(ded4a3e0a) v0.9.0.7
This commit is contained in:
@@ -0,0 +1,272 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>10.0.0</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{46474D32-2E58-6957-6E64-6F7773324D47}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>TwoMGFX</RootNamespace>
|
||||
<AssemblyName>2MGFX</AssemblyName>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<NoWarn>1591,0436</NoWarn>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<TargetFrameworkProfile />
|
||||
<LangVersion>Default</LangVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<Optimize>false</Optimize>
|
||||
<DebugType>full</DebugType>
|
||||
<EnableUnmanagedDebugging>true</EnableUnmanagedDebugging>
|
||||
<OutputPath>bin\Windows\AnyCPU\Debug</OutputPath>
|
||||
<IntermediateOutputPath>obj\Windows\AnyCPU\Debug</IntermediateOutputPath>
|
||||
<DocumentationFile>bin\Windows\AnyCPU\Debug\2MGFX.xml</DocumentationFile>
|
||||
<DefineConstants>DEBUG;TRACE;WINDOWS</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>none</DebugType>
|
||||
<OutputPath>bin\Windows\AnyCPU\Release</OutputPath>
|
||||
<IntermediateOutputPath>obj\Windows\AnyCPU\Release</IntermediateOutputPath>
|
||||
<DocumentationFile>bin\Windows\AnyCPU\Release\2MGFX.xml</DocumentationFile>
|
||||
<DefineConstants>TRACE;WINDOWS</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Runtime.Serialization" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="SharpDX">
|
||||
<HintPath>..\..\ThirdParty\Dependencies\SharpDX\net40\SharpDX.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SharpDX.D3DCompiler">
|
||||
<HintPath>..\..\ThirdParty\Dependencies\SharpDX\SharpDX.D3DCompiler.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="CppNet">
|
||||
<HintPath>..\..\ThirdParty\Dependencies\CppNet\CppNet.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="CommandLineParser.cs" />
|
||||
<Compile Include="Options.cs" />
|
||||
<Compile Include="..\..\MonoGame.Framework\BoundingBox.cs">
|
||||
<Link>MonoGame.Framework\BoundingBox.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\BoundingFrustum.cs">
|
||||
<Link>MonoGame.Framework\BoundingFrustum.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\BoundingSphere.cs">
|
||||
<Link>MonoGame.Framework\BoundingSphere.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\Color.cs">
|
||||
<Link>MonoGame.Framework\Color.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\ContainmentType.cs">
|
||||
<Link>MonoGame.Framework\ContainmentType.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\EventHelpers.cs">
|
||||
<Link>MonoGame.Framework\EventHelpers.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\Graphics\ColorWriteChannels.cs">
|
||||
<Link>MonoGame.Framework\ColorWriteChannels.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\Graphics\Effect\EffectParameterClass.cs">
|
||||
<Link>MonoGame.Framework\EffectParameterClass.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\Graphics\Effect\EffectParameterType.cs">
|
||||
<Link>MonoGame.Framework\EffectParameterType.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\Graphics\GraphicsResource.cs">
|
||||
<Link>MonoGame.Framework\GraphicsResource.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\Graphics\States\Blend.cs">
|
||||
<Link>MonoGame.Framework\Blend.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\Graphics\States\BlendFunction.cs">
|
||||
<Link>MonoGame.Framework\BlendFunction.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\Graphics\States\BlendState.cs">
|
||||
<Link>MonoGame.Framework\BlendState.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\Graphics\States\CompareFunction.cs">
|
||||
<Link>MonoGame.Framework\CompareFunction.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\Graphics\States\CullMode.cs">
|
||||
<Link>MonoGame.Framework\CullMode.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\Graphics\States\DepthStencilState.cs">
|
||||
<Link>MonoGame.Framework\DepthStencilState.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\Graphics\States\FillMode.cs">
|
||||
<Link>MonoGame.Framework\FillMode.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\Graphics\States\RasterizerState.cs">
|
||||
<Link>MonoGame.Framework\RasterizerState.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\Graphics\States\SamplerState.cs">
|
||||
<Link>MonoGame.Framework\SamplerState.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\Graphics\States\StencilOperation.cs">
|
||||
<Link>MonoGame.Framework\StencilOperation.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\Graphics\States\TargetBlendState.cs">
|
||||
<Link>MonoGame.Framework\TargetBlendState.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\Graphics\States\TextureAddressMode.cs">
|
||||
<Link>MonoGame.Framework\TextureAddressMode.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\Graphics\States\TextureFilter.cs">
|
||||
<Link>MonoGame.Framework\TextureFilter.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\Graphics\States\TextureFilterMode.cs">
|
||||
<Link>MonoGame.Framework\TextureFilterMode.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\Graphics\Vertices\VertexElementUsage.cs">
|
||||
<Link>MonoGame.Framework\VertexElementUsage.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\MathHelper.cs">
|
||||
<Link>MonoGame.Framework\MathHelper.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\Matrix.cs">
|
||||
<Link>MonoGame.Framework\Matrix.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\Plane.cs">
|
||||
<Link>MonoGame.Framework\Plane.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\Point.cs">
|
||||
<Link>MonoGame.Framework\Point.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\PlaneIntersectionType.cs">
|
||||
<Link>MonoGame.Framework\PlaneIntersectionType.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\Quaternion.cs">
|
||||
<Link>MonoGame.Framework\Quaternion.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\Ray.cs">
|
||||
<Link>MonoGame.Framework\Ray.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\Rectangle.cs">
|
||||
<Link>MonoGame.Framework\Rectangle.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\Vector2.cs">
|
||||
<Link>MonoGame.Framework\Vector2.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\Vector3.cs">
|
||||
<Link>MonoGame.Framework\Vector3.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\Vector4.cs">
|
||||
<Link>MonoGame.Framework\Vector4.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\Design\Vector2TypeConverter.cs">
|
||||
<Link>MonoGame.Framework\Design\Vector2TypeConverter.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\Design\Vector3TypeConverter.cs">
|
||||
<Link>MonoGame.Framework\Design\Vector3TypeConverter.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\Design\Vector4TypeConverter.cs">
|
||||
<Link>MonoGame.Framework\Design\Vector4TypeConverter.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\Design\VectorConversion.cs">
|
||||
<Link>MonoGame.Framework\Design\VectorConversion.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\Graphics\PackedVector\IPackedVector.cs">
|
||||
<Link>MonoGame.Framework\Graphics\PackedVector\IPackedVector.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\Utilities\Hash.cs">
|
||||
<Link>MonoGame.Framework\Utilities\Hash.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework\Utilities\CurrentPlatform.cs" />
|
||||
<Compile Include="..\..\MonoGame.Framework.Content.Pipeline\ExternalTool.cs">
|
||||
<Link>MonoGame.Framework.Content.Pipeline\ExternalTool.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\MonoGame.Framework.Content.Pipeline\LoadedTypeCollection.cs">
|
||||
<Link>MonoGame.Framework.Content.Pipeline\LoadedTypeCollection.c</Link>
|
||||
</Compile>
|
||||
<Compile Include="MonoGame.Framework\GraphicsDevice.cs" />
|
||||
<Compile Include="ConstantBufferData.cs" />
|
||||
<Compile Include="ConstantBufferData.mojo.cs" />
|
||||
<Compile Include="ConstantBufferData.sharpdx.cs" />
|
||||
<Compile Include="ConstantBufferData.writer.cs" />
|
||||
<Compile Include="EffectObject.cs" />
|
||||
<Compile Include="EffectObject.hlsl.cs" />
|
||||
<Compile Include="EffectObject.pssl.cs" />
|
||||
<Compile Include="EffectObject.writer.cs" />
|
||||
<Compile Include="IEffectCompilerOutput.cs" />
|
||||
<Compile Include="ShaderCompilerException.cs" />
|
||||
<Compile Include="ShaderData.cs" />
|
||||
<Compile Include="ShaderData.mojo.cs" />
|
||||
<Compile Include="ShaderData.pssl.cs" />
|
||||
<Compile Include="ShaderData.sharpdx.cs" />
|
||||
<Compile Include="ShaderData.writer.cs" />
|
||||
<Compile Include="ShaderProfile.cs" />
|
||||
<Compile Include="ShaderProfile.OpenGL.cs" />
|
||||
<Compile Include="ShaderProfile.DirectX.cs" />
|
||||
<Compile Include="ShaderResult.cs" />
|
||||
<Compile Include="TextureFilterType.cs" />
|
||||
<Compile Include="MarshalHelper.cs" />
|
||||
<Compile Include="MojoShader.cs" />
|
||||
<Compile Include="TPGParser\Parser.cs" />
|
||||
<Compile Include="TPGParser\ParseTree.cs" />
|
||||
<Compile Include="TPGParser\Scanner.cs" />
|
||||
<Compile Include="TPGParser\ParseTreeTools.cs" />
|
||||
<Compile Include="TPGParser\PassInfo.cs" />
|
||||
<Compile Include="TPGParser\SamplerStateInfo.cs" />
|
||||
<Compile Include="TPGParser\ShaderInfo.cs" />
|
||||
<Compile Include="TPGParser\TechniqueInfo.cs" />
|
||||
<Compile Include="Preprocessor.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<ItemGroup>
|
||||
<None Include="TPGParser\MGFX.tpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup>
|
||||
<None Include="..\..\ThirdParty\Dependencies\MojoShader\Windows\libmojoshader_64.dll">
|
||||
<Link>libmojoshader_64.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<NativeBinary>True</NativeBinary>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<_PostBuildHookTimestamp>@(IntermediateAssembly->'%(FullPath).timestamp')</_PostBuildHookTimestamp>
|
||||
<_PostBuildHookHostPlatform>$(Platform)</_PostBuildHookHostPlatform>
|
||||
</PropertyGroup>
|
||||
<Target Name="PostBuildHooks" Inputs="@(IntermediateAssembly);@(ReferencePath)" Outputs="@(IntermediateAssembly);$(_PostBuildHookTimestamp)" AfterTargets="CoreCompile" BeforeTargets="AfterCompile">
|
||||
<Touch Files="$(_PostBuildHookTimestamp)" AlwaysCreate="True" />
|
||||
</Target>
|
||||
<ItemGroup />
|
||||
<ProjectExtensions>
|
||||
<MonoDevelop>
|
||||
<Properties><Policies>
|
||||
<TextStylePolicy inheritsSet="VisualStudio" inheritsScope="text/plain" scope="text/x-csharp" />
|
||||
<CSharpFormattingPolicy IndentSwitchSection="True" NewLinesForBracesInProperties="True" NewLinesForBracesInAccessors="True" NewLinesForBracesInAnonymousMethods="True" NewLinesForBracesInControlBlocks="True" NewLinesForBracesInAnonymousTypes="True" NewLinesForBracesInObjectCollectionArrayInitializers="True" NewLinesForBracesInLambdaExpressionBody="True" NewLineForElse="True" NewLineForCatch="True" NewLineForFinally="True" NewLineForMembersInObjectInit="True" NewLineForMembersInAnonymousTypes="True" NewLineForClausesInQuery="True" SpacingAfterMethodDeclarationName="False" SpaceAfterMethodCallName="False" SpaceBeforeOpenSquareBracket="False" inheritsSet="Mono" inheritsScope="text/x-csharp" scope="text/x-csharp" />
|
||||
</Policies>
|
||||
</Properties>
|
||||
</MonoDevelop>
|
||||
</ProjectExtensions>
|
||||
</Project>
|
||||
@@ -0,0 +1,280 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using System.ComponentModel;
|
||||
|
||||
|
||||
namespace TwoMGFX
|
||||
{
|
||||
// Reusable, reflection based helper for parsing commandline options.
|
||||
//
|
||||
// From Shawn Hargreaves Blog:
|
||||
// http://blogs.msdn.com/b/shawnhar/archive/2012/04/20/a-reusable-reflection-based-command-line-parser.aspx
|
||||
//
|
||||
public class CommandLineParser
|
||||
{
|
||||
object _optionsObject;
|
||||
|
||||
Queue<FieldInfo> _requiredOptions = new Queue<FieldInfo>();
|
||||
Dictionary<string, FieldInfo> _optionalOptions = new Dictionary<string, FieldInfo>();
|
||||
|
||||
List<string> _requiredUsageHelp = new List<string>();
|
||||
List<string> _optionalUsageHelp = new List<string>();
|
||||
|
||||
|
||||
// Constructor.
|
||||
public CommandLineParser(object optionsObject)
|
||||
{
|
||||
this._optionsObject = optionsObject;
|
||||
|
||||
// Reflect to find what commandline options are available.
|
||||
foreach (var field in optionsObject.GetType().GetFields())
|
||||
{
|
||||
String description;
|
||||
var fieldName = GetOptionNameAndDescription(field, out description);
|
||||
|
||||
if (GetAttribute<RequiredAttribute>(field) != null)
|
||||
{
|
||||
// Record a required option.
|
||||
_requiredOptions.Enqueue(field);
|
||||
|
||||
_requiredUsageHelp.Add(string.Format("<{0}> {1}", fieldName, description));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Record an optional option.
|
||||
_optionalOptions.Add(fieldName.ToLowerInvariant(), field);
|
||||
|
||||
if (field.FieldType == typeof(bool))
|
||||
_optionalUsageHelp.Add(string.Format("/{0} {1}", fieldName, description));
|
||||
else
|
||||
_optionalUsageHelp.Add(string.Format("/{0}:value {1}", fieldName, description));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public bool ParseCommandLine(string[] args)
|
||||
{
|
||||
// Parse each argument in turn.
|
||||
foreach (var arg in args)
|
||||
{
|
||||
if (!ParseArgument(arg.Trim()))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure we got all the required options.
|
||||
var missingRequiredOption = _requiredOptions.FirstOrDefault(field => !IsList(field) || GetList(field).Count == 0);
|
||||
|
||||
if (missingRequiredOption != null)
|
||||
{
|
||||
ShowError("Missing argument '{0}'", GetOptionName(missingRequiredOption));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool ParseArgument(string arg)
|
||||
{
|
||||
if (arg.StartsWith("/"))
|
||||
{
|
||||
// After the first escaped argument we can no
|
||||
// longer read non-escaped arguments.
|
||||
_requiredOptions.Clear();
|
||||
|
||||
// Parse an optional argument.
|
||||
char[] separators = { ':' };
|
||||
|
||||
var split = arg.Substring(1).Split(separators, 2, StringSplitOptions.None);
|
||||
|
||||
var name = split[0];
|
||||
var value = (split.Length > 1) ? split[1] : "true";
|
||||
|
||||
FieldInfo field;
|
||||
|
||||
if (!_optionalOptions.TryGetValue(name.ToLowerInvariant(), out field))
|
||||
{
|
||||
ShowError("Unknown option '{0}'", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
return SetOption(field, value);
|
||||
}
|
||||
else if ( _requiredOptions.Count > 0 )
|
||||
{
|
||||
// Parse the next non escaped argument.
|
||||
var field = _requiredOptions.Peek();
|
||||
|
||||
if (!IsList(field))
|
||||
_requiredOptions.Dequeue();
|
||||
|
||||
return SetOption(field, arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowError("Too many arguments");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool SetOption(FieldInfo field, string value)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (IsList(field))
|
||||
{
|
||||
// Append this value to a list of options.
|
||||
GetList(field).Add(ChangeType(value, ListElementType(field)));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set the value of a single option.
|
||||
field.SetValue(_optionsObject, ChangeType(value, field.FieldType));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
ShowError("Invalid value '{0}' for option '{1}'", value, GetOptionName(field));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static object ChangeType(string value, Type type)
|
||||
{
|
||||
var converter = TypeDescriptor.GetConverter(type);
|
||||
|
||||
return converter.ConvertFromInvariantString(value);
|
||||
}
|
||||
|
||||
|
||||
static bool IsList(FieldInfo field)
|
||||
{
|
||||
return typeof(IList).IsAssignableFrom(field.FieldType);
|
||||
}
|
||||
|
||||
|
||||
IList GetList(FieldInfo field)
|
||||
{
|
||||
return (IList)field.GetValue(_optionsObject);
|
||||
}
|
||||
|
||||
|
||||
static Type ListElementType(FieldInfo field)
|
||||
{
|
||||
var interfaces = from i in field.FieldType.GetInterfaces()
|
||||
where i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>)
|
||||
select i;
|
||||
|
||||
return interfaces.First().GetGenericArguments()[0];
|
||||
}
|
||||
|
||||
|
||||
static string GetOptionName(FieldInfo field)
|
||||
{
|
||||
var nameAttribute = GetAttribute<NameAttribute>(field);
|
||||
if (nameAttribute != null)
|
||||
return nameAttribute.Name;
|
||||
else
|
||||
return field.Name;
|
||||
}
|
||||
|
||||
static string GetOptionNameAndDescription(FieldInfo field, out String description)
|
||||
{
|
||||
var nameAttribute = GetAttribute<NameAttribute>(field);
|
||||
|
||||
if (nameAttribute != null)
|
||||
{
|
||||
description = nameAttribute.Description;
|
||||
return nameAttribute.Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
description = null;
|
||||
return field.Name;
|
||||
}
|
||||
}
|
||||
|
||||
public string Title { get; set; }
|
||||
|
||||
void ShowError(string message, params object[] args)
|
||||
{
|
||||
var name = Path.GetFileNameWithoutExtension(Process.GetCurrentProcess().ProcessName);
|
||||
|
||||
if (!string.IsNullOrEmpty(Title))
|
||||
{
|
||||
Console.Error.WriteLine(Title);
|
||||
Console.Error.WriteLine();
|
||||
}
|
||||
Console.Error.WriteLine(message, args);
|
||||
Console.Error.WriteLine();
|
||||
Console.Error.WriteLine("Usage: {0} {1}", name, string.Join(" ", _requiredUsageHelp));
|
||||
|
||||
if (_optionalUsageHelp.Count > 0)
|
||||
{
|
||||
Console.Error.WriteLine();
|
||||
Console.Error.WriteLine("Options:");
|
||||
|
||||
foreach (string optional in _optionalUsageHelp)
|
||||
Console.Error.WriteLine(" {0}", optional);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static T GetAttribute<T>(ICustomAttributeProvider provider) where T : Attribute
|
||||
{
|
||||
return provider.GetCustomAttributes(typeof(T), false).OfType<T>().FirstOrDefault();
|
||||
}
|
||||
|
||||
|
||||
// Used on optionsObject fields to indicate which options are required.
|
||||
[AttributeUsage(AttributeTargets.Field)]
|
||||
public sealed class RequiredAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
// Used on an optionsObject field to rename the corresponding commandline option.
|
||||
[AttributeUsage(AttributeTargets.Field)]
|
||||
public class NameAttribute : Attribute
|
||||
{
|
||||
public NameAttribute(string name)
|
||||
{
|
||||
Name = name;
|
||||
Description = null;
|
||||
}
|
||||
|
||||
public NameAttribute(string name, string description)
|
||||
{
|
||||
Name = name;
|
||||
Description = description;
|
||||
}
|
||||
|
||||
public string Name { get; private set; }
|
||||
public string Description { get; protected set; }
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Field)]
|
||||
public sealed class ProfileNameAttribute : NameAttribute
|
||||
{
|
||||
public ProfileNameAttribute()
|
||||
: base("Profile")
|
||||
{
|
||||
var names = ShaderProfile.All.Select(p => p.Name);
|
||||
Description = "\t - Must be one of the following: " + string.Join(", ", names);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TwoMGFX
|
||||
{
|
||||
internal partial class ConstantBufferData
|
||||
{
|
||||
public string Name { get; private set; }
|
||||
|
||||
public int Size { get; private set; }
|
||||
|
||||
public List<int> ParameterIndex { get; private set; }
|
||||
|
||||
public List<int> ParameterOffset { get; private set; }
|
||||
|
||||
public List<EffectObject.d3dx_parameter> Parameters { get; private set; }
|
||||
|
||||
public ConstantBufferData(string name)
|
||||
{
|
||||
Name = name;
|
||||
|
||||
ParameterIndex = new List<int>();
|
||||
ParameterOffset = new List<int>();
|
||||
Parameters = new List<EffectObject.d3dx_parameter>();
|
||||
Size = 0;
|
||||
}
|
||||
|
||||
public bool SameAs(ConstantBufferData other)
|
||||
{
|
||||
// If the names of the constant buffers don't
|
||||
// match then consider them different right off
|
||||
// the bat... even if their parameters are the same.
|
||||
if (Name != other.Name)
|
||||
return false;
|
||||
|
||||
// Do we have the same count of parameters and size?
|
||||
if ( Size != other.Size ||
|
||||
Parameters.Count != other.Parameters.Count)
|
||||
return false;
|
||||
|
||||
// Compare the parameters themselves.
|
||||
for (var i = 0; i < Parameters.Count; i++)
|
||||
{
|
||||
var p1 = Parameters[i];
|
||||
var p2 = other.Parameters[i];
|
||||
|
||||
// Check the importaint bits.
|
||||
if ( p1.name != p2.name ||
|
||||
p1.rows != p2.rows ||
|
||||
p1.columns != p2.columns ||
|
||||
p1.class_ != p2.class_ ||
|
||||
p1.type != p2.type ||
|
||||
p1.bufferOffset != p2.bufferOffset)
|
||||
return false;
|
||||
}
|
||||
|
||||
// These are equal.
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TwoMGFX
|
||||
{
|
||||
internal partial class ConstantBufferData
|
||||
{
|
||||
public ConstantBufferData (string name,
|
||||
MojoShader.MOJOSHADER_symbolRegisterSet set,
|
||||
MojoShader.MOJOSHADER_symbol[] symbols)
|
||||
{
|
||||
Name = name ?? string.Empty;
|
||||
|
||||
ParameterIndex = new List<int> ();
|
||||
ParameterOffset = new List<int> ();
|
||||
Parameters = new List<EffectObject.d3dx_parameter> ();
|
||||
|
||||
int minRegister = short.MaxValue;
|
||||
int maxRegister = 0;
|
||||
|
||||
var registerSize = (set == MojoShader.MOJOSHADER_symbolRegisterSet.MOJOSHADER_SYMREGSET_BOOL ? 1 : 4) * 4;
|
||||
|
||||
foreach (var symbol in symbols) {
|
||||
if (symbol.register_set != set)
|
||||
continue;
|
||||
|
||||
// Create the parameter.
|
||||
var parm = GetParameterFromSymbol (symbol);
|
||||
|
||||
var offset = (int)symbol.register_index * registerSize;
|
||||
parm.bufferOffset = offset;
|
||||
|
||||
Parameters.Add (parm);
|
||||
ParameterOffset.Add(offset);
|
||||
|
||||
minRegister = Math.Min(minRegister, (int)symbol.register_index);
|
||||
maxRegister = Math.Max(maxRegister, (int)(symbol.register_index + symbol.register_count));
|
||||
}
|
||||
|
||||
Size = Math.Max(maxRegister - minRegister, 0) * registerSize;
|
||||
}
|
||||
|
||||
private static EffectObject.d3dx_parameter GetParameterFromSymbol(MojoShader.MOJOSHADER_symbol symbol)
|
||||
{
|
||||
var param = new EffectObject.d3dx_parameter();
|
||||
param.rows = symbol.info.rows;
|
||||
param.columns = symbol.info.columns;
|
||||
param.name = symbol.name ?? string.Empty;
|
||||
param.semantic = string.Empty; // TODO: How do i do this with only MojoShader?
|
||||
|
||||
var registerSize = (symbol.register_set == MojoShader.MOJOSHADER_symbolRegisterSet.MOJOSHADER_SYMREGSET_BOOL ? 1 : 4) * 4;
|
||||
var offset = (int)symbol.register_index * registerSize;
|
||||
param.bufferOffset = offset;
|
||||
|
||||
switch (symbol.info.parameter_class)
|
||||
{
|
||||
case MojoShader.MOJOSHADER_symbolClass.MOJOSHADER_SYMCLASS_SCALAR:
|
||||
param.class_ = EffectObject.D3DXPARAMETER_CLASS.SCALAR;
|
||||
break;
|
||||
|
||||
case MojoShader.MOJOSHADER_symbolClass.MOJOSHADER_SYMCLASS_VECTOR:
|
||||
param.class_ = EffectObject.D3DXPARAMETER_CLASS.VECTOR;
|
||||
break;
|
||||
|
||||
case MojoShader.MOJOSHADER_symbolClass.MOJOSHADER_SYMCLASS_MATRIX_COLUMNS:
|
||||
param.class_ = EffectObject.D3DXPARAMETER_CLASS.MATRIX_COLUMNS;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Exception("Unsupported parameter class!");
|
||||
}
|
||||
|
||||
switch (symbol.info.parameter_type)
|
||||
{
|
||||
case MojoShader.MOJOSHADER_symbolType.MOJOSHADER_SYMTYPE_BOOL:
|
||||
param.type = EffectObject.D3DXPARAMETER_TYPE.BOOL;
|
||||
break;
|
||||
|
||||
case MojoShader.MOJOSHADER_symbolType.MOJOSHADER_SYMTYPE_FLOAT:
|
||||
param.type = EffectObject.D3DXPARAMETER_TYPE.FLOAT;
|
||||
break;
|
||||
|
||||
case MojoShader.MOJOSHADER_symbolType.MOJOSHADER_SYMTYPE_INT:
|
||||
param.type = EffectObject.D3DXPARAMETER_TYPE.INT;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Exception("Unsupported parameter type!");
|
||||
}
|
||||
|
||||
// HACK: We don't have real default parameters from mojoshader!
|
||||
param.data = new byte[param.rows * param.columns * 4];
|
||||
|
||||
param.member_count = symbol.info.member_count;
|
||||
param.element_count = symbol.info.elements > 1 ? symbol.info.elements : 0;
|
||||
|
||||
if (param.member_count > 0)
|
||||
{
|
||||
param.member_handles = new EffectObject.d3dx_parameter[param.member_count];
|
||||
|
||||
var members = MarshalHelper.UnmarshalArray<MojoShader.MOJOSHADER_symbol>(
|
||||
symbol.info.members, (int)symbol.info.member_count);
|
||||
|
||||
for (var i = 0; i < param.member_count; i++)
|
||||
{
|
||||
var mparam = GetParameterFromSymbol(members[i]);
|
||||
param.member_handles[i] = mparam;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
param.member_handles = new EffectObject.d3dx_parameter[param.element_count];
|
||||
for (var i = 0; i < param.element_count; i++)
|
||||
{
|
||||
var mparam = new EffectObject.d3dx_parameter();
|
||||
|
||||
mparam.name = string.Empty;
|
||||
mparam.semantic = string.Empty;
|
||||
mparam.type = param.type;
|
||||
mparam.class_ = param.class_;
|
||||
mparam.rows = param.rows;
|
||||
mparam.columns = param.columns;
|
||||
mparam.data = new byte[param.columns * param.rows * 4];
|
||||
|
||||
param.member_handles[i] = mparam;
|
||||
}
|
||||
}
|
||||
|
||||
return param;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace TwoMGFX
|
||||
{
|
||||
internal partial class ConstantBufferData
|
||||
{
|
||||
public ConstantBufferData(SharpDX.D3DCompiler.ConstantBuffer cb)
|
||||
{
|
||||
Name = string.Empty;
|
||||
Size = cb.Description.Size;
|
||||
|
||||
ParameterIndex = new List<int>();
|
||||
|
||||
var parameters = new List<EffectObject.d3dx_parameter>();
|
||||
|
||||
// Gather all the parameters.
|
||||
for (var i = 0; i < cb.Description.VariableCount; i++)
|
||||
{
|
||||
var vdesc = cb.GetVariable(i);
|
||||
|
||||
var param = GetParameterFromType(vdesc.GetVariableType());
|
||||
|
||||
param.name = vdesc.Description.Name;
|
||||
param.semantic = string.Empty;
|
||||
param.bufferOffset = vdesc.Description.StartOffset;
|
||||
|
||||
var size = param.columns * param.rows * 4;
|
||||
var data = new byte[size];
|
||||
|
||||
if (vdesc.Description.DefaultValue != IntPtr.Zero)
|
||||
Marshal.Copy(vdesc.Description.DefaultValue, data, 0, (int)size);
|
||||
|
||||
param.data = data;
|
||||
|
||||
parameters.Add(param);
|
||||
}
|
||||
|
||||
// Sort them by the offset for some consistent results.
|
||||
Parameters = parameters.OrderBy(e => e.bufferOffset).ToList();
|
||||
|
||||
// Store the parameter offsets.
|
||||
ParameterOffset = new List<int>();
|
||||
foreach (var param in Parameters)
|
||||
ParameterOffset.Add(param.bufferOffset);
|
||||
}
|
||||
|
||||
private static EffectObject.d3dx_parameter GetParameterFromType(SharpDX.D3DCompiler.ShaderReflectionType type)
|
||||
{
|
||||
var param = new EffectObject.d3dx_parameter();
|
||||
param.rows = (uint)type.Description.RowCount;
|
||||
param.columns = (uint)type.Description.ColumnCount;
|
||||
param.name = type.Description.Name ?? string.Empty;
|
||||
param.semantic = string.Empty;
|
||||
param.bufferOffset = type.Description.Offset;
|
||||
|
||||
switch (type.Description.Class)
|
||||
{
|
||||
case SharpDX.D3DCompiler.ShaderVariableClass.Scalar:
|
||||
param.class_ = EffectObject.D3DXPARAMETER_CLASS.SCALAR;
|
||||
break;
|
||||
|
||||
case SharpDX.D3DCompiler.ShaderVariableClass.Vector:
|
||||
param.class_ = EffectObject.D3DXPARAMETER_CLASS.VECTOR;
|
||||
break;
|
||||
|
||||
case SharpDX.D3DCompiler.ShaderVariableClass.MatrixColumns:
|
||||
param.class_ = EffectObject.D3DXPARAMETER_CLASS.MATRIX_COLUMNS;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Exception("Unsupported parameter class!");
|
||||
}
|
||||
|
||||
switch (type.Description.Type)
|
||||
{
|
||||
case SharpDX.D3DCompiler.ShaderVariableType.Bool:
|
||||
param.type = EffectObject.D3DXPARAMETER_TYPE.BOOL;
|
||||
break;
|
||||
|
||||
case SharpDX.D3DCompiler.ShaderVariableType.Float:
|
||||
param.type = EffectObject.D3DXPARAMETER_TYPE.FLOAT;
|
||||
break;
|
||||
|
||||
case SharpDX.D3DCompiler.ShaderVariableType.Int:
|
||||
param.type = EffectObject.D3DXPARAMETER_TYPE.INT;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Exception("Unsupported parameter type!");
|
||||
}
|
||||
|
||||
param.member_count = (uint)type.Description.MemberCount;
|
||||
param.element_count = (uint)type.Description.ElementCount;
|
||||
|
||||
if (param.member_count > 0)
|
||||
{
|
||||
param.member_handles = new EffectObject.d3dx_parameter[param.member_count];
|
||||
for (var i = 0; i < param.member_count; i++)
|
||||
{
|
||||
var mparam = GetParameterFromType(type.GetMemberType(i));
|
||||
mparam.name = type.GetMemberTypeName(i) ?? string.Empty;
|
||||
param.member_handles[i] = mparam;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
param.member_handles = new EffectObject.d3dx_parameter[param.element_count];
|
||||
for (var i = 0; i < param.element_count; i++)
|
||||
{
|
||||
var mparam = new EffectObject.d3dx_parameter();
|
||||
|
||||
mparam.name = string.Empty;
|
||||
mparam.semantic = string.Empty;
|
||||
mparam.type = param.type;
|
||||
mparam.class_ = param.class_;
|
||||
mparam.rows = param.rows;
|
||||
mparam.columns = param.columns;
|
||||
mparam.data = new byte[param.columns * param.rows * 4];
|
||||
|
||||
param.member_handles[i] = mparam;
|
||||
}
|
||||
}
|
||||
|
||||
return param;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using System.IO;
|
||||
|
||||
namespace TwoMGFX
|
||||
{
|
||||
internal partial class ConstantBufferData
|
||||
{
|
||||
public void Write(BinaryWriter writer, Options options)
|
||||
{
|
||||
writer.Write(Name);
|
||||
|
||||
writer.Write((ushort)Size);
|
||||
|
||||
writer.Write((byte)ParameterIndex.Count);
|
||||
for (var i=0; i < ParameterIndex.Count; i++)
|
||||
{
|
||||
writer.Write((byte)ParameterIndex[i]);
|
||||
writer.Write((ushort)ParameterOffset[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,846 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace TwoMGFX
|
||||
{
|
||||
internal partial class EffectObject
|
||||
{
|
||||
private EffectObject()
|
||||
{
|
||||
}
|
||||
|
||||
public enum D3DRENDERSTATETYPE
|
||||
{
|
||||
ZENABLE = 7,
|
||||
FILLMODE = 8,
|
||||
SHADEMODE = 9,
|
||||
ZWRITEENABLE = 14,
|
||||
ALPHATESTENABLE = 15,
|
||||
LASTPIXEL = 16,
|
||||
SRCBLEND = 19,
|
||||
DESTBLEND = 20,
|
||||
CULLMODE = 22,
|
||||
ZFUNC = 23,
|
||||
ALPHAREF = 24,
|
||||
ALPHAFUNC = 25,
|
||||
DITHERENABLE = 26,
|
||||
ALPHABLENDENABLE = 27,
|
||||
FOGENABLE = 28,
|
||||
SPECULARENABLE = 29,
|
||||
FOGCOLOR = 34,
|
||||
FOGTABLEMODE = 35,
|
||||
FOGSTART = 36,
|
||||
FOGEND = 37,
|
||||
FOGDENSITY = 38,
|
||||
RANGEFOGENABLE = 48,
|
||||
STENCILENABLE = 52,
|
||||
STENCILFAIL = 53,
|
||||
STENCILZFAIL = 54,
|
||||
STENCILPASS = 55,
|
||||
STENCILFUNC = 56,
|
||||
STENCILREF = 57,
|
||||
STENCILMASK = 58,
|
||||
STENCILWRITEMASK = 59,
|
||||
TEXTUREFACTOR = 60,
|
||||
WRAP0 = 128,
|
||||
WRAP1 = 129,
|
||||
WRAP2 = 130,
|
||||
WRAP3 = 131,
|
||||
WRAP4 = 132,
|
||||
WRAP5 = 133,
|
||||
WRAP6 = 134,
|
||||
WRAP7 = 135,
|
||||
CLIPPING = 136,
|
||||
LIGHTING = 137,
|
||||
AMBIENT = 139,
|
||||
FOGVERTEXMODE = 140,
|
||||
COLORVERTEX = 141,
|
||||
LOCALVIEWER = 142,
|
||||
NORMALIZENORMALS = 143,
|
||||
DIFFUSEMATERIALSOURCE = 145,
|
||||
SPECULARMATERIALSOURCE = 146,
|
||||
AMBIENTMATERIALSOURCE = 147,
|
||||
EMISSIVEMATERIALSOURCE = 148,
|
||||
VERTEXBLEND = 151,
|
||||
CLIPPLANEENABLE = 152,
|
||||
POINTSIZE = 154,
|
||||
POINTSIZE_MIN = 155,
|
||||
POINTSPRITEENABLE = 156,
|
||||
POINTSCALEENABLE = 157,
|
||||
POINTSCALE_A = 158,
|
||||
POINTSCALE_B = 159,
|
||||
POINTSCALE_C = 160,
|
||||
MULTISAMPLEANTIALIAS = 161,
|
||||
MULTISAMPLEMASK = 162,
|
||||
PATCHEDGESTYLE = 163,
|
||||
DEBUGMONITORTOKEN = 165,
|
||||
POINTSIZE_MAX = 166,
|
||||
INDEXEDVERTEXBLENDENABLE = 167,
|
||||
COLORWRITEENABLE = 168,
|
||||
TWEENFACTOR = 170,
|
||||
BLENDOP = 171,
|
||||
POSITIONDEGREE = 172,
|
||||
NORMALDEGREE = 173,
|
||||
SCISSORTESTENABLE = 174,
|
||||
SLOPESCALEDEPTHBIAS = 175,
|
||||
ANTIALIASEDLINEENABLE = 176,
|
||||
MINTESSELLATIONLEVEL = 178,
|
||||
MAXTESSELLATIONLEVEL = 179,
|
||||
ADAPTIVETESS_X = 180,
|
||||
ADAPTIVETESS_Y = 181,
|
||||
ADAPTIVETESS_Z = 182,
|
||||
ADAPTIVETESS_W = 183,
|
||||
ENABLEADAPTIVETESSELLATION= 184,
|
||||
TWOSIDEDSTENCILMODE = 185,
|
||||
CCW_STENCILFAIL = 186,
|
||||
CCW_STENCILZFAIL = 187,
|
||||
CCW_STENCILPASS = 188,
|
||||
CCW_STENCILFUNC = 189,
|
||||
COLORWRITEENABLE1 = 190,
|
||||
COLORWRITEENABLE2 = 191,
|
||||
COLORWRITEENABLE3 = 192,
|
||||
BLENDFACTOR = 193,
|
||||
SRGBWRITEENABLE = 194,
|
||||
DEPTHBIAS = 195,
|
||||
WRAP8 = 198,
|
||||
WRAP9 = 199,
|
||||
WRAP10 = 200,
|
||||
WRAP11 = 201,
|
||||
WRAP12 = 202,
|
||||
WRAP13 = 203,
|
||||
WRAP14 = 204,
|
||||
WRAP15 = 205,
|
||||
SEPARATEALPHABLENDENABLE = 206,
|
||||
SRCBLENDALPHA = 207,
|
||||
DESTBLENDALPHA = 208,
|
||||
BLENDOPALPHA = 209,
|
||||
|
||||
FORCE_DWORD = 0x7fffffff
|
||||
}
|
||||
|
||||
public enum D3DTEXTURESTAGESTATETYPE
|
||||
{
|
||||
COLOROP = 1,
|
||||
COLORARG1 = 2,
|
||||
COLORARG2 = 3,
|
||||
ALPHAOP = 4,
|
||||
ALPHAARG1 = 5,
|
||||
ALPHAARG2 = 6,
|
||||
BUMPENVMAT00 = 7,
|
||||
BUMPENVMAT01 = 8,
|
||||
BUMPENVMAT10 = 9,
|
||||
BUMPENVMAT11 = 10,
|
||||
TEXCOORDINDEX = 11,
|
||||
BUMPENVLSCALE = 22,
|
||||
BUMPENVLOFFSET = 23,
|
||||
TEXTURETRANSFORMFLAGS = 24,
|
||||
COLORARG0 = 26,
|
||||
ALPHAARG0 = 27,
|
||||
RESULTARG = 28,
|
||||
CONSTANT = 32,
|
||||
|
||||
FORCE_DWORD = 0x7fffffff
|
||||
}
|
||||
|
||||
public enum D3DTRANSFORMSTATETYPE
|
||||
{
|
||||
VIEW = 2,
|
||||
PROJECTION = 3,
|
||||
TEXTURE0 = 16,
|
||||
TEXTURE1 = 17,
|
||||
TEXTURE2 = 18,
|
||||
TEXTURE3 = 19,
|
||||
TEXTURE4 = 20,
|
||||
TEXTURE5 = 21,
|
||||
TEXTURE6 = 22,
|
||||
TEXTURE7 = 23,
|
||||
WORLD = 256,
|
||||
FORCE_DWORD = 0x7fffffff
|
||||
}
|
||||
|
||||
public const int D3DX_PARAMETER_SHARED = 1;
|
||||
public const int D3DX_PARAMETER_LITERAL = 2;
|
||||
public const int D3DX_PARAMETER_ANNOTATION = 4;
|
||||
|
||||
public enum D3DXPARAMETER_CLASS
|
||||
{
|
||||
SCALAR,
|
||||
VECTOR,
|
||||
MATRIX_ROWS,
|
||||
MATRIX_COLUMNS,
|
||||
OBJECT,
|
||||
STRUCT,
|
||||
FORCE_DWORD = 0x7fffffff,
|
||||
}
|
||||
|
||||
public enum D3DXPARAMETER_TYPE
|
||||
{
|
||||
VOID,
|
||||
BOOL,
|
||||
INT,
|
||||
FLOAT,
|
||||
STRING,
|
||||
TEXTURE,
|
||||
TEXTURE1D,
|
||||
TEXTURE2D,
|
||||
TEXTURE3D,
|
||||
TEXTURECUBE,
|
||||
SAMPLER,
|
||||
SAMPLER1D,
|
||||
SAMPLER2D,
|
||||
SAMPLER3D,
|
||||
SAMPLERCUBE,
|
||||
PIXELSHADER,
|
||||
VERTEXSHADER,
|
||||
PIXELFRAGMENT,
|
||||
VERTEXFRAGMENT,
|
||||
UNSUPPORTED,
|
||||
FORCE_DWORD = 0x7fffffff,
|
||||
}
|
||||
|
||||
enum D3DSAMPLERSTATETYPE
|
||||
{
|
||||
ADDRESSU = 1,
|
||||
ADDRESSV = 2,
|
||||
ADDRESSW = 3,
|
||||
BORDERCOLOR = 4,
|
||||
MAGFILTER = 5,
|
||||
MINFILTER = 6,
|
||||
MIPFILTER = 7,
|
||||
MIPMAPLODBIAS = 8,
|
||||
MAXMIPLEVEL = 9,
|
||||
MAXANISOTROPY = 10,
|
||||
SRGBTEXTURE = 11,
|
||||
ELEMENTINDEX = 12,
|
||||
DMAPOFFSET = 13,
|
||||
|
||||
FORCE_DWORD = 0x7fffffff,
|
||||
};
|
||||
|
||||
public enum STATE_CLASS
|
||||
{
|
||||
LIGHTENABLE,
|
||||
FVF,
|
||||
LIGHT,
|
||||
MATERIAL,
|
||||
NPATCHMODE,
|
||||
PIXELSHADER,
|
||||
RENDERSTATE,
|
||||
SETSAMPLER,
|
||||
SAMPLERSTATE,
|
||||
TEXTURE,
|
||||
TEXTURESTAGE,
|
||||
TRANSFORM,
|
||||
VERTEXSHADER,
|
||||
SHADERCONST,
|
||||
UNKNOWN,
|
||||
};
|
||||
|
||||
public enum MATERIAL_TYPE
|
||||
{
|
||||
DIFFUSE,
|
||||
AMBIENT,
|
||||
SPECULAR,
|
||||
EMISSIVE,
|
||||
POWER,
|
||||
};
|
||||
|
||||
public enum LIGHT_TYPE
|
||||
{
|
||||
TYPE,
|
||||
DIFFUSE,
|
||||
SPECULAR,
|
||||
AMBIENT,
|
||||
POSITION,
|
||||
DIRECTION,
|
||||
RANGE,
|
||||
FALLOFF,
|
||||
ATTENUATION0,
|
||||
ATTENUATION1,
|
||||
ATTENUATION2,
|
||||
THETA,
|
||||
PHI,
|
||||
};
|
||||
|
||||
public enum SHADER_CONSTANT_TYPE
|
||||
{
|
||||
VSFLOAT,
|
||||
VSBOOL,
|
||||
VSINT,
|
||||
PSFLOAT,
|
||||
PSBOOL,
|
||||
PSINT,
|
||||
}
|
||||
|
||||
public enum STATE_TYPE
|
||||
{
|
||||
CONSTANT,
|
||||
PARAMETER,
|
||||
EXPRESSION,
|
||||
EXPRESSIONINDEX,
|
||||
}
|
||||
|
||||
public class d3dx_parameter
|
||||
{
|
||||
public string name;
|
||||
public string semantic;
|
||||
public object data;
|
||||
public D3DXPARAMETER_CLASS class_;
|
||||
public D3DXPARAMETER_TYPE type;
|
||||
public uint rows;
|
||||
public uint columns;
|
||||
public uint element_count;
|
||||
public uint annotation_count = 0;
|
||||
public uint member_count;
|
||||
public uint flags = 0;
|
||||
public uint bytes = 0;
|
||||
|
||||
public int bufferIndex = -1;
|
||||
public int bufferOffset = -1;
|
||||
|
||||
public d3dx_parameter[] annotation_handles = null;
|
||||
public d3dx_parameter[] member_handles;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (rows > 0 || columns > 0)
|
||||
return string.Format("{0} {1}{2}x{3} {4} : cb{5},{6}", class_, type, rows, columns, name, bufferIndex, bufferOffset);
|
||||
else
|
||||
return string.Format("{0} {1} {2}", class_, type, name);
|
||||
}
|
||||
}
|
||||
|
||||
public class d3dx_state
|
||||
{
|
||||
public uint operation;
|
||||
public uint index;
|
||||
public STATE_TYPE type;
|
||||
public d3dx_parameter parameter;
|
||||
}
|
||||
|
||||
public class d3dx_sampler
|
||||
{
|
||||
public uint state_count = 0;
|
||||
public d3dx_state[] states = null;
|
||||
}
|
||||
|
||||
public class d3dx_pass
|
||||
{
|
||||
public string name;
|
||||
public uint state_count;
|
||||
public uint annotation_count = 0;
|
||||
|
||||
public BlendState blendState;
|
||||
public DepthStencilState depthStencilState;
|
||||
public RasterizerState rasterizerState;
|
||||
|
||||
public d3dx_state[] states;
|
||||
public d3dx_parameter[] annotation_handles = null;
|
||||
}
|
||||
|
||||
public class d3dx_technique
|
||||
{
|
||||
public string name;
|
||||
public uint pass_count;
|
||||
public uint annotation_count = 0;
|
||||
|
||||
public d3dx_parameter[] annotation_handles = null;
|
||||
public d3dx_pass[] pass_handles;
|
||||
}
|
||||
|
||||
public class state_info
|
||||
{
|
||||
public STATE_CLASS class_ { get; private set; }
|
||||
public uint op { get; private set; }
|
||||
public string name { get; private set; }
|
||||
|
||||
public state_info(STATE_CLASS class_, uint op, string name)
|
||||
{
|
||||
this.class_ = class_;
|
||||
this.op = op;
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The shared state definition table.
|
||||
/// </summary>
|
||||
public static readonly state_info[] state_table =
|
||||
{
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.ZENABLE, "ZENABLE"), /* 0x0 */
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.FILLMODE, "FILLMODE"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.SHADEMODE, "SHADEMODE"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.ZWRITEENABLE, "ZWRITEENABLE"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.ALPHATESTENABLE, "ALPHATESTENABLE"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.LASTPIXEL, "LASTPIXEL"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.SRCBLEND, "SRCBLEND"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.DESTBLEND, "DESTBLEND"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.CULLMODE, "CULLMODE"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.ZFUNC, "ZFUNC"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.ALPHAREF, "ALPHAREF"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.ALPHAFUNC, "ALPHAFUNC"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.DITHERENABLE, "DITHERENABLE"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.ALPHABLENDENABLE, "ALPHABLENDENABLE"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.FOGENABLE, "FOGENABLE"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.SPECULARENABLE, "SPECULARENABLE"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.FOGCOLOR, "FOGCOLOR"), /* 0x10 */
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.FOGTABLEMODE, "FOGTABLEMODE"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.FOGSTART, "FOGSTART"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.FOGEND, "FOGEND"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.FOGDENSITY, "FOGDENSITY"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.RANGEFOGENABLE, "RANGEFOGENABLE"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.STENCILENABLE, "STENCILENABLE"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.STENCILFAIL, "STENCILFAIL"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.STENCILZFAIL, "STENCILZFAIL"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.STENCILPASS, "STENCILPASS"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.STENCILFUNC, "STENCILFUNC"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.STENCILREF, "STENCILREF"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.STENCILMASK, "STENCILMASK"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.STENCILWRITEMASK, "STENCILWRITEMASK"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.TEXTUREFACTOR, "TEXTUREFACTOR"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.WRAP0, "WRAP0"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.WRAP1, "WRAP1"), /* 0x20 */
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.WRAP2, "WRAP2"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.WRAP3, "WRAP3"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.WRAP4, "WRAP4"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.WRAP5, "WRAP5"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.WRAP6, "WRAP6"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.WRAP7, "WRAP7"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.WRAP8, "WRAP8"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.WRAP9, "WRAP9"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.WRAP10, "WRAP10"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.WRAP11, "WRAP11"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.WRAP12, "WRAP12"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.WRAP13, "WRAP13"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.WRAP14, "WRAP14"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.WRAP15, "WRAP15"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.CLIPPING, "CLIPPING"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.LIGHTING, "LIGHTING"), /* 0x30 */
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.AMBIENT, "AMBIENT"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.FOGVERTEXMODE, "FOGVERTEXMODE"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.COLORVERTEX, "COLORVERTEX"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.LOCALVIEWER, "LOCALVIEWER"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.NORMALIZENORMALS, "NORMALIZENORMALS"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.DIFFUSEMATERIALSOURCE, "DIFFUSEMATERIALSOURCE"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.SPECULARMATERIALSOURCE, "SPECULARMATERIALSOURCE"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.AMBIENTMATERIALSOURCE, "AMBIENTMATERIALSOURCE"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.EMISSIVEMATERIALSOURCE, "EMISSIVEMATERIALSOURCE"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.VERTEXBLEND, "VERTEXBLEND"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.CLIPPLANEENABLE, "CLIPPLANEENABLE"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.POINTSIZE, "POINTSIZE"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.POINTSIZE_MIN, "POINTSIZE_MIN"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.POINTSIZE_MAX, "POINTSIZE_MAX"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.POINTSPRITEENABLE, "POINTSPRITEENABLE"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.POINTSCALEENABLE, "POINTSCALEENABLE"), /* 0x40 */
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.POINTSCALE_A, "POINTSCALE_A"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.POINTSCALE_B, "POINTSCALE_B"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.POINTSCALE_C, "POINTSCALE_C"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.MULTISAMPLEANTIALIAS, "MULTISAMPLEANTIALIAS"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.MULTISAMPLEMASK, "MULTISAMPLEMASK"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.PATCHEDGESTYLE, "PATCHEDGESTYLE"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.DEBUGMONITORTOKEN, "DEBUGMONITORTOKEN"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.INDEXEDVERTEXBLENDENABLE, "INDEXEDVERTEXBLENDENABLE"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.COLORWRITEENABLE, "COLORWRITEENABLE"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.TWEENFACTOR, "TWEENFACTOR"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.BLENDOP, "BLENDOP"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.POSITIONDEGREE, "POSITIONDEGREE"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.NORMALDEGREE, "NORMALDEGREE"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.SCISSORTESTENABLE, "SCISSORTESTENABLE"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.SLOPESCALEDEPTHBIAS, "SLOPESCALEDEPTHBIAS"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.ANTIALIASEDLINEENABLE, "ANTIALIASEDLINEENABLE"), /* 0x50 */
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.MINTESSELLATIONLEVEL, "MINTESSELLATIONLEVEL"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.MAXTESSELLATIONLEVEL, "MAXTESSELLATIONLEVEL"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.ADAPTIVETESS_X, "ADAPTIVETESS_X"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.ADAPTIVETESS_Y, "ADAPTIVETESS_Y"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.ADAPTIVETESS_Z, "ADAPTIVETESS_Z"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.ADAPTIVETESS_W, "ADAPTIVETESS_W"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.ENABLEADAPTIVETESSELLATION, "ENABLEADAPTIVETESSELLATION"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.TWOSIDEDSTENCILMODE, "TWOSIDEDSTENCILMODE"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.CCW_STENCILFAIL, "CCW_STENCILFAIL"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.CCW_STENCILZFAIL, "CCW_STENCILZFAIL"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.CCW_STENCILPASS, "CCW_STENCILPASS"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.CCW_STENCILFUNC, "CCW_STENCILFUNC"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.COLORWRITEENABLE1, "COLORWRITEENABLE1"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.COLORWRITEENABLE2, "COLORWRITEENABLE2"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.COLORWRITEENABLE3, "COLORWRITEENABLE3"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.BLENDFACTOR, "BLENDFACTOR"), /* 0x60 */
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.SRGBWRITEENABLE, "SRGBWRITEENABLE"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.DEPTHBIAS, "DEPTHBIAS"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.SEPARATEALPHABLENDENABLE, "SEPARATEALPHABLENDENABLE"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.SRCBLENDALPHA, "SRCBLENDALPHA"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.DESTBLENDALPHA, "DESTBLENDALPHA"),
|
||||
new state_info(STATE_CLASS.RENDERSTATE, (uint)D3DRENDERSTATETYPE.BLENDOPALPHA, "BLENDOPALPHA"),
|
||||
/* Texture stages */
|
||||
new state_info(STATE_CLASS.TEXTURESTAGE, (uint)D3DTEXTURESTAGESTATETYPE.COLOROP, "COLOROP"),
|
||||
new state_info(STATE_CLASS.TEXTURESTAGE, (uint)D3DTEXTURESTAGESTATETYPE.COLORARG0, "COLORARG0"),
|
||||
new state_info(STATE_CLASS.TEXTURESTAGE, (uint)D3DTEXTURESTAGESTATETYPE.COLORARG1, "COLORARG1"),
|
||||
new state_info(STATE_CLASS.TEXTURESTAGE, (uint)D3DTEXTURESTAGESTATETYPE.COLORARG2, "COLORARG2"),
|
||||
new state_info(STATE_CLASS.TEXTURESTAGE, (uint)D3DTEXTURESTAGESTATETYPE.ALPHAOP, "ALPHAOP"),
|
||||
new state_info(STATE_CLASS.TEXTURESTAGE, (uint)D3DTEXTURESTAGESTATETYPE.ALPHAARG0, "ALPHAARG0"),
|
||||
new state_info(STATE_CLASS.TEXTURESTAGE, (uint)D3DTEXTURESTAGESTATETYPE.ALPHAARG1, "ALPHAARG1"),
|
||||
new state_info(STATE_CLASS.TEXTURESTAGE, (uint)D3DTEXTURESTAGESTATETYPE.ALPHAARG2, "ALPHAARG2"),
|
||||
new state_info(STATE_CLASS.TEXTURESTAGE, (uint)D3DTEXTURESTAGESTATETYPE.RESULTARG, "RESULTARG"),
|
||||
new state_info(STATE_CLASS.TEXTURESTAGE, (uint)D3DTEXTURESTAGESTATETYPE.BUMPENVMAT00, "BUMPENVMAT00"), /* 0x70 */
|
||||
new state_info(STATE_CLASS.TEXTURESTAGE, (uint)D3DTEXTURESTAGESTATETYPE.BUMPENVMAT01, "BUMPENVMAT01"),
|
||||
new state_info(STATE_CLASS.TEXTURESTAGE, (uint)D3DTEXTURESTAGESTATETYPE.BUMPENVMAT10, "BUMPENVMAT10"),
|
||||
new state_info(STATE_CLASS.TEXTURESTAGE, (uint)D3DTEXTURESTAGESTATETYPE.BUMPENVMAT11, "BUMPENVMAT11"),
|
||||
new state_info(STATE_CLASS.TEXTURESTAGE, (uint)D3DTEXTURESTAGESTATETYPE.TEXCOORDINDEX, "TEXCOORDINDEX"),
|
||||
new state_info(STATE_CLASS.TEXTURESTAGE, (uint)D3DTEXTURESTAGESTATETYPE.BUMPENVLSCALE, "BUMPENVLSCALE"),
|
||||
new state_info(STATE_CLASS.TEXTURESTAGE, (uint)D3DTEXTURESTAGESTATETYPE.BUMPENVLOFFSET, "BUMPENVLOFFSET"),
|
||||
new state_info(STATE_CLASS.TEXTURESTAGE, (uint)D3DTEXTURESTAGESTATETYPE.TEXTURETRANSFORMFLAGS, "TEXTURETRANSFORMFLAGS"),
|
||||
/* */
|
||||
new state_info(STATE_CLASS.UNKNOWN, 0, "UNKNOWN"),
|
||||
/* NPatchMode */
|
||||
new state_info(STATE_CLASS.NPATCHMODE, 0, "NPatchMode"),
|
||||
/* */
|
||||
new state_info(STATE_CLASS.UNKNOWN, 0, "UNKNOWN"),
|
||||
/* Transform */
|
||||
new state_info(STATE_CLASS.TRANSFORM, (uint)D3DTRANSFORMSTATETYPE.PROJECTION, "PROJECTION"),
|
||||
new state_info(STATE_CLASS.TRANSFORM, (uint)D3DTRANSFORMSTATETYPE.VIEW, "VIEW"),
|
||||
new state_info(STATE_CLASS.TRANSFORM, (uint)D3DTRANSFORMSTATETYPE.WORLD, "WORLD"),
|
||||
new state_info(STATE_CLASS.TRANSFORM, (uint)D3DTRANSFORMSTATETYPE.TEXTURE0, "TEXTURE0"),
|
||||
/* Material */
|
||||
new state_info(STATE_CLASS.MATERIAL, (uint)MATERIAL_TYPE.DIFFUSE, "MaterialDiffuse"),
|
||||
new state_info(STATE_CLASS.MATERIAL, (uint)MATERIAL_TYPE.AMBIENT, "MaterialAmbient"), /* 0x80 */
|
||||
new state_info(STATE_CLASS.MATERIAL, (uint)MATERIAL_TYPE.SPECULAR, "MaterialSpecular"),
|
||||
new state_info(STATE_CLASS.MATERIAL, (uint)MATERIAL_TYPE.EMISSIVE, "MaterialEmissive"),
|
||||
new state_info(STATE_CLASS.MATERIAL, (uint)MATERIAL_TYPE.POWER, "MaterialPower"),
|
||||
/* Light */
|
||||
new state_info(STATE_CLASS.LIGHT, (uint)LIGHT_TYPE.TYPE, "LightType"),
|
||||
new state_info(STATE_CLASS.LIGHT, (uint)LIGHT_TYPE.DIFFUSE, "LightDiffuse"),
|
||||
new state_info(STATE_CLASS.LIGHT, (uint)LIGHT_TYPE.SPECULAR, "LightSpecular"),
|
||||
new state_info(STATE_CLASS.LIGHT, (uint)LIGHT_TYPE.AMBIENT, "LightAmbient"),
|
||||
new state_info(STATE_CLASS.LIGHT, (uint)LIGHT_TYPE.POSITION, "LightPosition"),
|
||||
new state_info(STATE_CLASS.LIGHT, (uint)LIGHT_TYPE.DIRECTION, "LightDirection"),
|
||||
new state_info(STATE_CLASS.LIGHT, (uint)LIGHT_TYPE.RANGE, "LightRange"),
|
||||
new state_info(STATE_CLASS.LIGHT, (uint)LIGHT_TYPE.FALLOFF, "LightFallOff"),
|
||||
new state_info(STATE_CLASS.LIGHT, (uint)LIGHT_TYPE.ATTENUATION0, "LightAttenuation0"),
|
||||
new state_info(STATE_CLASS.LIGHT, (uint)LIGHT_TYPE.ATTENUATION1, "LightAttenuation1"),
|
||||
new state_info(STATE_CLASS.LIGHT, (uint)LIGHT_TYPE.ATTENUATION2, "LightAttenuation2"),
|
||||
new state_info(STATE_CLASS.LIGHT, (uint)LIGHT_TYPE.THETA, "LightTheta"),
|
||||
new state_info(STATE_CLASS.LIGHT, (uint)LIGHT_TYPE.PHI, "LightPhi"), /* 0x90 */
|
||||
/* Ligthenable */
|
||||
new state_info(STATE_CLASS.LIGHTENABLE, 0, "LightEnable"),
|
||||
/* Vertexshader */
|
||||
new state_info(STATE_CLASS.VERTEXSHADER, 0, "Vertexshader"),
|
||||
/* Pixelshader */
|
||||
new state_info(STATE_CLASS.PIXELSHADER, 0, "Pixelshader"),
|
||||
/* Shader constants */
|
||||
new state_info(STATE_CLASS.SHADERCONST, (uint)SHADER_CONSTANT_TYPE.VSFLOAT, "VertexShaderConstantF"),
|
||||
new state_info(STATE_CLASS.SHADERCONST, (uint)SHADER_CONSTANT_TYPE.VSBOOL, "VertexShaderConstantB"),
|
||||
new state_info(STATE_CLASS.SHADERCONST, (uint)SHADER_CONSTANT_TYPE.VSINT, "VertexShaderConstantI"),
|
||||
new state_info(STATE_CLASS.SHADERCONST, (uint)SHADER_CONSTANT_TYPE.VSFLOAT, "VertexShaderConstant"),
|
||||
new state_info(STATE_CLASS.SHADERCONST, (uint)SHADER_CONSTANT_TYPE.VSFLOAT, "VertexShaderConstant1"),
|
||||
new state_info(STATE_CLASS.SHADERCONST, (uint)SHADER_CONSTANT_TYPE.VSFLOAT, "VertexShaderConstant2"),
|
||||
new state_info(STATE_CLASS.SHADERCONST, (uint)SHADER_CONSTANT_TYPE.VSFLOAT, "VertexShaderConstant3"),
|
||||
new state_info(STATE_CLASS.SHADERCONST, (uint)SHADER_CONSTANT_TYPE.VSFLOAT, "VertexShaderConstant4"),
|
||||
new state_info(STATE_CLASS.SHADERCONST, (uint)SHADER_CONSTANT_TYPE.PSFLOAT, "PixelShaderConstantF"),
|
||||
new state_info(STATE_CLASS.SHADERCONST, (uint)SHADER_CONSTANT_TYPE.PSBOOL, "PixelShaderConstantB"),
|
||||
new state_info(STATE_CLASS.SHADERCONST, (uint)SHADER_CONSTANT_TYPE.PSINT, "PixelShaderConstantI"),
|
||||
new state_info(STATE_CLASS.SHADERCONST, (uint)SHADER_CONSTANT_TYPE.PSFLOAT, "PixelShaderConstant"),
|
||||
new state_info(STATE_CLASS.SHADERCONST, (uint)SHADER_CONSTANT_TYPE.PSFLOAT, "PixelShaderConstant1"), /* 0xa0 */
|
||||
new state_info(STATE_CLASS.SHADERCONST, (uint)SHADER_CONSTANT_TYPE.PSFLOAT, "PixelShaderConstant2"),
|
||||
new state_info(STATE_CLASS.SHADERCONST, (uint)SHADER_CONSTANT_TYPE.PSFLOAT, "PixelShaderConstant3"),
|
||||
new state_info(STATE_CLASS.SHADERCONST, (uint)SHADER_CONSTANT_TYPE.PSFLOAT, "PixelShaderConstant4"),
|
||||
/* Texture */
|
||||
new state_info(STATE_CLASS.TEXTURE, 0, "Texture"),
|
||||
/* Sampler states */
|
||||
new state_info(STATE_CLASS.SAMPLERSTATE, (uint)D3DSAMPLERSTATETYPE.ADDRESSU, "AddressU"),
|
||||
new state_info(STATE_CLASS.SAMPLERSTATE, (uint)D3DSAMPLERSTATETYPE.ADDRESSV, "AddressV"),
|
||||
new state_info(STATE_CLASS.SAMPLERSTATE, (uint)D3DSAMPLERSTATETYPE.ADDRESSW, "AddressW"),
|
||||
new state_info(STATE_CLASS.SAMPLERSTATE, (uint)D3DSAMPLERSTATETYPE.BORDERCOLOR, "BorderColor"),
|
||||
new state_info(STATE_CLASS.SAMPLERSTATE, (uint)D3DSAMPLERSTATETYPE.MAGFILTER, "MagFilter"),
|
||||
new state_info(STATE_CLASS.SAMPLERSTATE, (uint)D3DSAMPLERSTATETYPE.MINFILTER, "MinFilter"),
|
||||
new state_info(STATE_CLASS.SAMPLERSTATE, (uint)D3DSAMPLERSTATETYPE.MIPFILTER, "MipFilter"),
|
||||
new state_info(STATE_CLASS.SAMPLERSTATE, (uint)D3DSAMPLERSTATETYPE.MIPMAPLODBIAS, "MipMapLodBias"),
|
||||
new state_info(STATE_CLASS.SAMPLERSTATE, (uint)D3DSAMPLERSTATETYPE.MAXMIPLEVEL, "MaxMipLevel"),
|
||||
new state_info(STATE_CLASS.SAMPLERSTATE, (uint)D3DSAMPLERSTATETYPE.MAXANISOTROPY, "MaxAnisotropy"),
|
||||
new state_info(STATE_CLASS.SAMPLERSTATE, (uint)D3DSAMPLERSTATETYPE.SRGBTEXTURE, "SRGBTexture"),
|
||||
new state_info(STATE_CLASS.SAMPLERSTATE, (uint)D3DSAMPLERSTATETYPE.ELEMENTINDEX, "ElementIndex"), /* 0xb0 */
|
||||
new state_info(STATE_CLASS.SAMPLERSTATE, (uint)D3DSAMPLERSTATETYPE.DMAPOFFSET, "DMAPOffset"),
|
||||
/* Set sampler */
|
||||
new state_info(STATE_CLASS.SETSAMPLER, 0, "Sampler"),
|
||||
};
|
||||
|
||||
static public EffectParameterClass ToXNAParameterClass( D3DXPARAMETER_CLASS class_ )
|
||||
{
|
||||
switch (class_)
|
||||
{
|
||||
case D3DXPARAMETER_CLASS.SCALAR:
|
||||
return EffectParameterClass.Scalar;
|
||||
case D3DXPARAMETER_CLASS.VECTOR:
|
||||
return EffectParameterClass.Vector;
|
||||
case D3DXPARAMETER_CLASS.MATRIX_ROWS:
|
||||
case D3DXPARAMETER_CLASS.MATRIX_COLUMNS:
|
||||
return EffectParameterClass.Matrix;
|
||||
case D3DXPARAMETER_CLASS.OBJECT:
|
||||
return EffectParameterClass.Object;
|
||||
case D3DXPARAMETER_CLASS.STRUCT:
|
||||
return EffectParameterClass.Struct;
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
static public EffectParameterType ToXNAParameterType(D3DXPARAMETER_TYPE type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case D3DXPARAMETER_TYPE.BOOL:
|
||||
return EffectParameterType.Bool;
|
||||
case D3DXPARAMETER_TYPE.INT:
|
||||
return EffectParameterType.Int32;
|
||||
case D3DXPARAMETER_TYPE.FLOAT:
|
||||
return EffectParameterType.Single;
|
||||
case D3DXPARAMETER_TYPE.STRING:
|
||||
return EffectParameterType.String;
|
||||
case D3DXPARAMETER_TYPE.TEXTURE:
|
||||
return EffectParameterType.Texture;
|
||||
case D3DXPARAMETER_TYPE.TEXTURE1D:
|
||||
return EffectParameterType.Texture1D;
|
||||
case D3DXPARAMETER_TYPE.TEXTURE2D:
|
||||
return EffectParameterType.Texture2D;
|
||||
case D3DXPARAMETER_TYPE.TEXTURE3D:
|
||||
return EffectParameterType.Texture3D;
|
||||
case D3DXPARAMETER_TYPE.TEXTURECUBE:
|
||||
return EffectParameterType.TextureCube;
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
static internal VertexElementUsage ToXNAVertexElementUsage(MojoShader.MOJOSHADER_usage usage)
|
||||
{
|
||||
switch (usage)
|
||||
{
|
||||
case MojoShader.MOJOSHADER_usage.MOJOSHADER_USAGE_POSITION:
|
||||
return VertexElementUsage.Position;
|
||||
case MojoShader.MOJOSHADER_usage.MOJOSHADER_USAGE_BLENDWEIGHT:
|
||||
return VertexElementUsage.BlendWeight;
|
||||
case MojoShader.MOJOSHADER_usage.MOJOSHADER_USAGE_BLENDINDICES:
|
||||
return VertexElementUsage.BlendIndices;
|
||||
case MojoShader.MOJOSHADER_usage.MOJOSHADER_USAGE_NORMAL:
|
||||
return VertexElementUsage.Normal;
|
||||
case MojoShader.MOJOSHADER_usage.MOJOSHADER_USAGE_POINTSIZE:
|
||||
return VertexElementUsage.PointSize;
|
||||
case MojoShader.MOJOSHADER_usage.MOJOSHADER_USAGE_TEXCOORD:
|
||||
return VertexElementUsage.TextureCoordinate;
|
||||
case MojoShader.MOJOSHADER_usage.MOJOSHADER_USAGE_TANGENT:
|
||||
return VertexElementUsage.Tangent;
|
||||
case MojoShader.MOJOSHADER_usage.MOJOSHADER_USAGE_BINORMAL:
|
||||
return VertexElementUsage.Binormal;
|
||||
case MojoShader.MOJOSHADER_usage.MOJOSHADER_USAGE_TESSFACTOR:
|
||||
return VertexElementUsage.TessellateFactor;
|
||||
case MojoShader.MOJOSHADER_usage.MOJOSHADER_USAGE_COLOR:
|
||||
return VertexElementUsage.Color;
|
||||
case MojoShader.MOJOSHADER_usage.MOJOSHADER_USAGE_FOG:
|
||||
return VertexElementUsage.Fog;
|
||||
case MojoShader.MOJOSHADER_usage.MOJOSHADER_USAGE_DEPTH:
|
||||
return VertexElementUsage.Depth;
|
||||
case MojoShader.MOJOSHADER_usage.MOJOSHADER_USAGE_SAMPLE:
|
||||
return VertexElementUsage.Sample;
|
||||
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static public EffectObject CompileEffect(ShaderResult shaderResult, out string errorsAndWarnings)
|
||||
{
|
||||
var effect = new EffectObject();
|
||||
errorsAndWarnings = string.Empty;
|
||||
|
||||
// These are filled out as we process stuff.
|
||||
effect.ConstantBuffers = new List<ConstantBufferData>();
|
||||
effect.Shaders = new List<ShaderData>();
|
||||
|
||||
// Go thru the techniques and that will find all the
|
||||
// shaders and constant buffers.
|
||||
var shaderInfo = shaderResult.ShaderInfo;
|
||||
effect.Techniques = new d3dx_technique[shaderInfo.Techniques.Count];
|
||||
for (var t = 0; t < shaderInfo.Techniques.Count; t++)
|
||||
{
|
||||
var tinfo = shaderInfo.Techniques[t]; ;
|
||||
|
||||
var technique = new d3dx_technique();
|
||||
technique.name = tinfo.name;
|
||||
technique.pass_count = (uint)tinfo.Passes.Count;
|
||||
technique.pass_handles = new d3dx_pass[tinfo.Passes.Count];
|
||||
|
||||
for (var p = 0; p < tinfo.Passes.Count; p++)
|
||||
{
|
||||
var pinfo = tinfo.Passes[p];
|
||||
|
||||
var pass = new d3dx_pass();
|
||||
pass.name = pinfo.name ?? string.Empty;
|
||||
|
||||
pass.blendState = pinfo.blendState;
|
||||
pass.depthStencilState = pinfo.depthStencilState;
|
||||
pass.rasterizerState = pinfo.rasterizerState;
|
||||
|
||||
pass.state_count = 0;
|
||||
var tempstate = new d3dx_state[2];
|
||||
|
||||
shaderResult.Profile.ValidateShaderModels(pinfo);
|
||||
|
||||
if (!string.IsNullOrEmpty(pinfo.psFunction))
|
||||
{
|
||||
pass.state_count += 1;
|
||||
tempstate[pass.state_count - 1] = effect.CreateShader(shaderResult, pinfo.psFunction, pinfo.psModel, false, ref errorsAndWarnings);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(pinfo.vsFunction))
|
||||
{
|
||||
pass.state_count += 1;
|
||||
tempstate[pass.state_count - 1] = effect.CreateShader(shaderResult, pinfo.vsFunction, pinfo.vsModel, true, ref errorsAndWarnings);
|
||||
}
|
||||
|
||||
pass.states = new d3dx_state[pass.state_count];
|
||||
for (var s = 0; s < pass.state_count; s++)
|
||||
pass.states[s] = tempstate[s];
|
||||
|
||||
technique.pass_handles[p] = pass;
|
||||
}
|
||||
|
||||
effect.Techniques[t] = technique;
|
||||
}
|
||||
|
||||
// Make the list of parameters by combining all the
|
||||
// constant buffers ignoring the buffer offsets.
|
||||
var parameters = new List<d3dx_parameter>();
|
||||
for (var c = 0; c < effect.ConstantBuffers.Count; c++)
|
||||
{
|
||||
var cb = effect.ConstantBuffers[c];
|
||||
|
||||
for (var i = 0; i < cb.Parameters.Count; i++)
|
||||
{
|
||||
var param = cb.Parameters[i];
|
||||
|
||||
var match = parameters.FindIndex(e => e.name == param.name);
|
||||
if (match == -1)
|
||||
{
|
||||
cb.ParameterIndex.Add(parameters.Count);
|
||||
parameters.Add(param);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Make sure the type and size of
|
||||
// the parameter match up!
|
||||
cb.ParameterIndex.Add(match);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add the texture parameters from the samplers.
|
||||
foreach (var shader in effect.Shaders)
|
||||
{
|
||||
for (var s = 0; s < shader._samplers.Length; s++)
|
||||
{
|
||||
var sampler = shader._samplers[s];
|
||||
|
||||
var match = parameters.FindIndex(e => e.name == sampler.parameterName);
|
||||
if (match == -1)
|
||||
{
|
||||
// Store the index for runtime lookup.
|
||||
shader._samplers[s].parameter = parameters.Count;
|
||||
|
||||
var param = new d3dx_parameter();
|
||||
param.class_ = D3DXPARAMETER_CLASS.OBJECT;
|
||||
param.name = sampler.parameterName;
|
||||
param.semantic = string.Empty;
|
||||
|
||||
switch (sampler.type)
|
||||
{
|
||||
case MojoShader.MOJOSHADER_samplerType.MOJOSHADER_SAMPLER_1D:
|
||||
param.type = D3DXPARAMETER_TYPE.TEXTURE1D;
|
||||
break;
|
||||
|
||||
case MojoShader.MOJOSHADER_samplerType.MOJOSHADER_SAMPLER_2D:
|
||||
param.type = D3DXPARAMETER_TYPE.TEXTURE2D;
|
||||
break;
|
||||
|
||||
case MojoShader.MOJOSHADER_samplerType.MOJOSHADER_SAMPLER_VOLUME:
|
||||
param.type = D3DXPARAMETER_TYPE.TEXTURE3D;
|
||||
break;
|
||||
|
||||
case MojoShader.MOJOSHADER_samplerType.MOJOSHADER_SAMPLER_CUBE:
|
||||
param.type = D3DXPARAMETER_TYPE.TEXTURECUBE;
|
||||
break;
|
||||
}
|
||||
|
||||
parameters.Add(param);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Make sure the type and size of
|
||||
// the parameter match up!
|
||||
|
||||
shader._samplers[s].parameter = match;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Annotations are part of the .FX format and
|
||||
// not a part of shaders... we need to implement them
|
||||
// in our mgfx parser if we want them back.
|
||||
|
||||
effect.Parameters = parameters.ToArray();
|
||||
|
||||
return effect;
|
||||
}
|
||||
|
||||
|
||||
private d3dx_state CreateShader(ShaderResult shaderResult, string shaderFunction, string shaderProfile, bool isVertexShader, ref string errorsAndWarnings)
|
||||
{
|
||||
// Compile and create the shader.
|
||||
var shaderData = shaderResult.Profile.CreateShader(shaderResult, shaderFunction, shaderProfile, isVertexShader, this, ref errorsAndWarnings);
|
||||
|
||||
var state = new d3dx_state();
|
||||
state.index = 0;
|
||||
state.type = STATE_TYPE.CONSTANT;
|
||||
state.operation = isVertexShader ? (uint)146 : (uint)147;
|
||||
|
||||
state.parameter = new d3dx_parameter();
|
||||
state.parameter.name = string.Empty;
|
||||
state.parameter.semantic = string.Empty;
|
||||
state.parameter.class_ = D3DXPARAMETER_CLASS.OBJECT;
|
||||
state.parameter.type = isVertexShader ? D3DXPARAMETER_TYPE.VERTEXSHADER : D3DXPARAMETER_TYPE.PIXELSHADER;
|
||||
state.parameter.rows = 0;
|
||||
state.parameter.columns = 0;
|
||||
state.parameter.data = shaderData.SharedIndex;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
internal static int GetShaderIndex(STATE_CLASS type, d3dx_state[] states)
|
||||
{
|
||||
foreach (var state in states)
|
||||
{
|
||||
var operation = state_table[state.operation];
|
||||
if (operation.class_ != type)
|
||||
continue;
|
||||
|
||||
if (state.type != STATE_TYPE.CONSTANT)
|
||||
throw new NotSupportedException("We do not support shader expressions!");
|
||||
|
||||
return (int)state.parameter.data;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public d3dx_parameter[] Objects { get; private set; }
|
||||
|
||||
public d3dx_parameter[] Parameters { get; private set; }
|
||||
|
||||
public d3dx_technique[] Techniques { get; private set; }
|
||||
|
||||
public List<ShaderData> Shaders { get; private set; }
|
||||
|
||||
public List<ConstantBufferData> ConstantBuffers { get; private set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace TwoMGFX
|
||||
{
|
||||
partial class EffectObject
|
||||
{
|
||||
public static byte[] CompileHLSL(ShaderResult shaderResult, string shaderFunction, string shaderProfile, ref string errorsAndWarnings)
|
||||
{
|
||||
SharpDX.D3DCompiler.ShaderBytecode shaderByteCode;
|
||||
try
|
||||
{
|
||||
SharpDX.D3DCompiler.ShaderFlags shaderFlags = 0;
|
||||
|
||||
// While we never allow preshaders, this flag is invalid for
|
||||
// the DX11 shader compiler which doesn't allow preshaders
|
||||
// in the first place.
|
||||
//shaderFlags |= SharpDX.D3DCompiler.ShaderFlags.NoPreshader;
|
||||
|
||||
if (shaderResult.Profile == ShaderProfile.DirectX_11)
|
||||
shaderFlags |= SharpDX.D3DCompiler.ShaderFlags.EnableBackwardsCompatibility;
|
||||
|
||||
if (shaderResult.Debug)
|
||||
{
|
||||
shaderFlags |= SharpDX.D3DCompiler.ShaderFlags.SkipOptimization;
|
||||
shaderFlags |= SharpDX.D3DCompiler.ShaderFlags.Debug;
|
||||
}
|
||||
else
|
||||
{
|
||||
shaderFlags |= SharpDX.D3DCompiler.ShaderFlags.OptimizationLevel3;
|
||||
}
|
||||
|
||||
// Compile the shader into bytecode.
|
||||
var result = SharpDX.D3DCompiler.ShaderBytecode.Compile(
|
||||
shaderResult.FileContent,
|
||||
shaderFunction,
|
||||
shaderProfile,
|
||||
shaderFlags,
|
||||
0,
|
||||
null,
|
||||
null,
|
||||
shaderResult.FilePath);
|
||||
|
||||
// Store all the errors and warnings to log out later.
|
||||
errorsAndWarnings += result.Message;
|
||||
|
||||
if (result.Bytecode == null)
|
||||
throw new ShaderCompilerException();
|
||||
|
||||
shaderByteCode = result.Bytecode;
|
||||
//var source = shaderByteCode.Disassemble();
|
||||
}
|
||||
catch (SharpDX.CompilationException ex)
|
||||
{
|
||||
errorsAndWarnings += ex.Message;
|
||||
throw new ShaderCompilerException();
|
||||
}
|
||||
|
||||
// Return a copy of the shader bytecode.
|
||||
return shaderByteCode.Data.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
|
||||
namespace TwoMGFX
|
||||
{
|
||||
partial class EffectObject
|
||||
{
|
||||
private static byte[] CompilePSSL(ShaderResult shaderResult, string shaderFunction, string shaderProfile, ref string errorsAndWarnings)
|
||||
{
|
||||
// This is only part of the private PS4 repository.
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System.IO;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
|
||||
namespace TwoMGFX
|
||||
{
|
||||
internal partial class EffectObject
|
||||
{
|
||||
|
||||
private const string Header = "MGFX";
|
||||
private const int Version = 8;
|
||||
|
||||
/// <summary>
|
||||
/// Writes the effect for loading later.
|
||||
/// </summary>
|
||||
public void Write(BinaryWriter writer, Options options)
|
||||
{
|
||||
// Write a very simple header for identification and versioning.
|
||||
writer.Write(Header.ToCharArray());
|
||||
writer.Write((byte)Version);
|
||||
|
||||
// Write an simple identifier for DX11 vs GLSL
|
||||
// so we can easily detect the correct shader type.
|
||||
var profile = (byte)options.Profile.FormatId;
|
||||
writer.Write(profile);
|
||||
|
||||
// Write the rest to a memory stream.
|
||||
using(MemoryStream memStream = new MemoryStream())
|
||||
using(BinaryWriter memWriter = new BinaryWriter(memStream))
|
||||
{
|
||||
// Write all the constant buffers.
|
||||
memWriter.Write((byte)ConstantBuffers.Count);
|
||||
foreach (var cbuffer in ConstantBuffers)
|
||||
cbuffer.Write(memWriter, options);
|
||||
|
||||
// Write all the shaders.
|
||||
memWriter.Write((byte)Shaders.Count);
|
||||
foreach (var shader in Shaders)
|
||||
shader.Write(memWriter, options);
|
||||
|
||||
// Write the parameters.
|
||||
WriteParameters(memWriter, Parameters, Parameters.Length);
|
||||
|
||||
// Write the techniques.
|
||||
memWriter.Write((byte)Techniques.Length);
|
||||
foreach (var technique in Techniques)
|
||||
{
|
||||
memWriter.Write(technique.name);
|
||||
WriteAnnotations(memWriter, technique.annotation_handles);
|
||||
|
||||
// Write the passes.
|
||||
memWriter.Write((byte)technique.pass_count);
|
||||
for (var p = 0; p < technique.pass_count; p++)
|
||||
{
|
||||
var pass = technique.pass_handles[p];
|
||||
|
||||
memWriter.Write(pass.name);
|
||||
WriteAnnotations(memWriter, pass.annotation_handles);
|
||||
|
||||
// Write the index for the vertex and pixel shaders.
|
||||
var vertexShader = GetShaderIndex(STATE_CLASS.VERTEXSHADER, pass.states);
|
||||
var pixelShader = GetShaderIndex(STATE_CLASS.PIXELSHADER, pass.states);
|
||||
memWriter.Write((byte)vertexShader);
|
||||
memWriter.Write((byte)pixelShader);
|
||||
|
||||
// Write the state objects too!
|
||||
if (pass.blendState != null)
|
||||
{
|
||||
memWriter.Write(true);
|
||||
memWriter.Write((byte)pass.blendState.AlphaBlendFunction);
|
||||
memWriter.Write((byte)pass.blendState.AlphaDestinationBlend);
|
||||
memWriter.Write((byte)pass.blendState.AlphaSourceBlend);
|
||||
memWriter.Write(pass.blendState.BlendFactor.R);
|
||||
memWriter.Write(pass.blendState.BlendFactor.G);
|
||||
memWriter.Write(pass.blendState.BlendFactor.B);
|
||||
memWriter.Write(pass.blendState.BlendFactor.A);
|
||||
memWriter.Write((byte)pass.blendState.ColorBlendFunction);
|
||||
memWriter.Write((byte)pass.blendState.ColorDestinationBlend);
|
||||
memWriter.Write((byte)pass.blendState.ColorSourceBlend);
|
||||
memWriter.Write((byte)pass.blendState.ColorWriteChannels);
|
||||
memWriter.Write((byte)pass.blendState.ColorWriteChannels1);
|
||||
memWriter.Write((byte)pass.blendState.ColorWriteChannels2);
|
||||
memWriter.Write((byte)pass.blendState.ColorWriteChannels3);
|
||||
memWriter.Write(pass.blendState.MultiSampleMask);
|
||||
}
|
||||
else
|
||||
memWriter.Write(false);
|
||||
|
||||
if (pass.depthStencilState != null)
|
||||
{
|
||||
memWriter.Write(true);
|
||||
memWriter.Write((byte)pass.depthStencilState.CounterClockwiseStencilDepthBufferFail);
|
||||
memWriter.Write((byte)pass.depthStencilState.CounterClockwiseStencilFail);
|
||||
memWriter.Write((byte)pass.depthStencilState.CounterClockwiseStencilFunction);
|
||||
memWriter.Write((byte)pass.depthStencilState.CounterClockwiseStencilPass);
|
||||
memWriter.Write(pass.depthStencilState.DepthBufferEnable);
|
||||
memWriter.Write((byte)pass.depthStencilState.DepthBufferFunction);
|
||||
memWriter.Write(pass.depthStencilState.DepthBufferWriteEnable);
|
||||
memWriter.Write(pass.depthStencilState.ReferenceStencil);
|
||||
memWriter.Write((byte)pass.depthStencilState.StencilDepthBufferFail);
|
||||
memWriter.Write(pass.depthStencilState.StencilEnable);
|
||||
memWriter.Write((byte)pass.depthStencilState.StencilFail);
|
||||
memWriter.Write((byte)pass.depthStencilState.StencilFunction);
|
||||
memWriter.Write(pass.depthStencilState.StencilMask);
|
||||
memWriter.Write((byte)pass.depthStencilState.StencilPass);
|
||||
memWriter.Write(pass.depthStencilState.StencilWriteMask);
|
||||
memWriter.Write(pass.depthStencilState.TwoSidedStencilMode);
|
||||
}
|
||||
else
|
||||
memWriter.Write(false);
|
||||
|
||||
if (pass.rasterizerState != null)
|
||||
{
|
||||
memWriter.Write(true);
|
||||
memWriter.Write((byte)pass.rasterizerState.CullMode);
|
||||
memWriter.Write(pass.rasterizerState.DepthBias);
|
||||
memWriter.Write((byte)pass.rasterizerState.FillMode);
|
||||
memWriter.Write(pass.rasterizerState.MultiSampleAntiAlias);
|
||||
memWriter.Write(pass.rasterizerState.ScissorTestEnable);
|
||||
memWriter.Write(pass.rasterizerState.SlopeScaleDepthBias);
|
||||
}
|
||||
else
|
||||
memWriter.Write(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate a hash code from memory stream
|
||||
// and write it to the header.
|
||||
var effectKey = MonoGame.Utilities.Hash.ComputeHash(memStream);
|
||||
writer.Write((Int32)effectKey);
|
||||
|
||||
//write content from memory stream to final stream.
|
||||
memStream.WriteTo(writer.BaseStream);
|
||||
}
|
||||
}
|
||||
|
||||
private static void WriteParameters(BinaryWriter writer, d3dx_parameter[] parameters, int count)
|
||||
{
|
||||
writer.Write((byte)count);
|
||||
for (var i = 0; i < count; i++)
|
||||
WriteParameter(writer, parameters[i]);
|
||||
}
|
||||
|
||||
private static void WriteParameter(BinaryWriter writer, d3dx_parameter param)
|
||||
{
|
||||
var class_ = ToXNAParameterClass(param.class_);
|
||||
var type = ToXNAParameterType(param.type);
|
||||
writer.Write((byte)class_);
|
||||
writer.Write((byte)type);
|
||||
|
||||
writer.Write(param.name);
|
||||
writer.Write(param.semantic);
|
||||
WriteAnnotations(writer, param.annotation_handles);
|
||||
|
||||
writer.Write((byte)param.rows);
|
||||
writer.Write((byte)param.columns);
|
||||
|
||||
// Write the elements or struct members.
|
||||
WriteParameters(writer, param.member_handles, (int)param.element_count);
|
||||
WriteParameters(writer, param.member_handles, (int)param.member_count);
|
||||
|
||||
if (param.element_count == 0 && param.member_count == 0)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case EffectParameterType.Bool:
|
||||
case EffectParameterType.Int32:
|
||||
case EffectParameterType.Single:
|
||||
writer.Write((byte[])param.data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void WriteAnnotations(BinaryWriter writer, d3dx_parameter[] annotations)
|
||||
{
|
||||
var count = annotations == null ? 0 : annotations.Length;
|
||||
writer.Write((byte)count);
|
||||
for (var i = 0; i < count; i++)
|
||||
WriteParameter(writer, annotations[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace TwoMGFX
|
||||
{
|
||||
public interface IEffectCompilerOutput
|
||||
{
|
||||
void WriteWarning(string file, int line, int column, string message);
|
||||
void WriteError(string file, int line, int column, string message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace TwoMGFX
|
||||
{
|
||||
internal class MarshalHelper
|
||||
{
|
||||
public static T Unmarshal<T>(IntPtr ptr)
|
||||
{
|
||||
var type = typeof(T);
|
||||
var result = (T)Marshal.PtrToStructure(ptr, type);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static T[] UnmarshalArray<T>(IntPtr ptr, int count)
|
||||
{
|
||||
var type = typeof(T);
|
||||
var size = Marshal.SizeOf(type);
|
||||
var ret = new T[count];
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var offset = i * size;
|
||||
var structPtr = new IntPtr(ptr.ToInt64() + offset);
|
||||
ret[i] = (T)Marshal.PtrToStructure(structPtr, type);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static byte[] UnmarshalArray(IntPtr ptr, int count)
|
||||
{
|
||||
var result = new byte[count];
|
||||
Marshal.Copy(ptr, result, 0, count);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Graphics
|
||||
{
|
||||
// Dummy class for 2MGFX to compile.
|
||||
public class GraphicsDevice
|
||||
{
|
||||
internal void AddResourceReference(WeakReference resourceReference)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
internal void RemoveResourceReference(WeakReference resourceReference)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
namespace TwoMGFX
|
||||
{
|
||||
public class Options
|
||||
{
|
||||
[CommandLineParser.Required]
|
||||
public string SourceFile;
|
||||
|
||||
[CommandLineParser.Required]
|
||||
public string OutputFile = string.Empty;
|
||||
|
||||
[CommandLineParser.ProfileName]
|
||||
public ShaderProfile Profile = ShaderProfile.OpenGL;
|
||||
|
||||
[CommandLineParser.Name("Debug", "\t\t - Include extra debug information in the compiled effect.")]
|
||||
public bool Debug;
|
||||
|
||||
[CommandLineParser.Name("Defines", "\t - Semicolon-delimited define assignments")]
|
||||
public string Defines;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using CppNet;
|
||||
|
||||
namespace TwoMGFX
|
||||
{
|
||||
public static class Preprocessor
|
||||
{
|
||||
public static string Preprocess(
|
||||
string effectCode, string filePath, IDictionary<string, string> defines, List<string> dependencies,
|
||||
IEffectCompilerOutput output)
|
||||
{
|
||||
var fullPath = Path.GetFullPath(filePath);
|
||||
|
||||
var pp = new CppNet.Preprocessor();
|
||||
|
||||
pp.EmitExtraLineInfo = false;
|
||||
pp.addFeature(Feature.LINEMARKERS);
|
||||
pp.setListener(new MGErrorListener(output));
|
||||
pp.setFileSystem(new MGFileSystem(dependencies));
|
||||
pp.setQuoteIncludePath(new List<string> { Path.GetDirectoryName(fullPath) });
|
||||
|
||||
foreach (var define in defines)
|
||||
pp.addMacro(define.Key, define.Value);
|
||||
|
||||
effectCode = effectCode.Replace("#line", "//--WORKAROUND#line");
|
||||
|
||||
pp.addInput(new MGStringLexerSource(effectCode, true, fullPath));
|
||||
|
||||
var result = new StringBuilder();
|
||||
|
||||
var endOfStream = false;
|
||||
while (!endOfStream)
|
||||
{
|
||||
var token = pp.token();
|
||||
switch (token.getType())
|
||||
{
|
||||
case CppNet.Token.EOF:
|
||||
endOfStream = true;
|
||||
break;
|
||||
case CppNet.Token.CPPCOMMENT:
|
||||
if (token.getText().StartsWith("//--WORKAROUND#line"))
|
||||
{
|
||||
result.Append(token.getText().Replace("//--WORKAROUND#line", "#line"));
|
||||
}
|
||||
break;
|
||||
case CppNet.Token.CCOMMENT:
|
||||
{
|
||||
var tokenText = token.getText();
|
||||
if (tokenText != null)
|
||||
{
|
||||
// Need to preserve line breaks so that line numbers are correct.
|
||||
foreach (var c in tokenText)
|
||||
if (c == '\n')
|
||||
result.Append(c);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
var tokenText = token.getText();
|
||||
if (tokenText != null)
|
||||
result.Append(tokenText);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result.ToString();
|
||||
}
|
||||
|
||||
private class MGFileSystem : VirtualFileSystem
|
||||
{
|
||||
private readonly List<string> _dependencies;
|
||||
|
||||
public MGFileSystem(List<string> dependencies)
|
||||
{
|
||||
_dependencies = dependencies;
|
||||
}
|
||||
|
||||
public VirtualFile getFile(string path)
|
||||
{
|
||||
return new MGFile(path, _dependencies);
|
||||
}
|
||||
|
||||
public VirtualFile getFile(string dir, string name)
|
||||
{
|
||||
return new MGFile(Path.Combine(dir, name), _dependencies);
|
||||
}
|
||||
}
|
||||
|
||||
private class MGFile : VirtualFile
|
||||
{
|
||||
private readonly List<string> _dependencies;
|
||||
private readonly string _path;
|
||||
|
||||
public MGFile(string path, List<string> dependencies)
|
||||
{
|
||||
_dependencies = dependencies;
|
||||
_path = Path.GetFullPath(path);
|
||||
}
|
||||
|
||||
public bool isFile()
|
||||
{
|
||||
return File.Exists(_path) && !File.GetAttributes(_path).HasFlag(FileAttributes.Directory);
|
||||
}
|
||||
|
||||
public string getPath()
|
||||
{
|
||||
return _path;
|
||||
}
|
||||
|
||||
public string getName()
|
||||
{
|
||||
return Path.GetFileName(_path);
|
||||
}
|
||||
|
||||
public VirtualFile getParentFile()
|
||||
{
|
||||
return new MGFile(Path.GetDirectoryName(_path), _dependencies);
|
||||
}
|
||||
|
||||
public VirtualFile getChildFile(string name)
|
||||
{
|
||||
return new MGFile(Path.Combine(_path, name), _dependencies);
|
||||
}
|
||||
|
||||
public Source getSource()
|
||||
{
|
||||
if (!_dependencies.Contains(_path))
|
||||
_dependencies.Add(_path);
|
||||
return new MGStringLexerSource(AppendNewlineIfNonePresent(File.ReadAllText(_path)), true, _path);
|
||||
}
|
||||
|
||||
private static string AppendNewlineIfNonePresent(string text)
|
||||
{
|
||||
if (!text.EndsWith("\n"))
|
||||
return text + "\n";
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
private class MGStringLexerSource : StringLexerSource
|
||||
{
|
||||
public string Path { get; private set; }
|
||||
|
||||
public MGStringLexerSource(string str, bool ppvalid, string fileName)
|
||||
: base(str.Replace("\r\n", "\n"), ppvalid, fileName)
|
||||
{
|
||||
Path = fileName;
|
||||
}
|
||||
}
|
||||
|
||||
private class MGErrorListener : PreprocessorListener
|
||||
{
|
||||
private readonly IEffectCompilerOutput _output;
|
||||
|
||||
public MGErrorListener(IEffectCompilerOutput output)
|
||||
{
|
||||
_output = output;
|
||||
}
|
||||
|
||||
public void handleWarning(Source source, int line, int column, string msg)
|
||||
{
|
||||
_output.WriteWarning(GetPath(source), line, column, msg);
|
||||
}
|
||||
|
||||
public void handleError(Source source, int line, int column, string msg)
|
||||
{
|
||||
_output.WriteError(GetPath(source), line, column, msg);
|
||||
}
|
||||
|
||||
private string GetPath(Source source)
|
||||
{
|
||||
return ((MGStringLexerSource) source).Path;
|
||||
}
|
||||
|
||||
public void handleSourceChange(Source source, string ev)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace TwoMGFX
|
||||
{
|
||||
public static class Program
|
||||
{
|
||||
public static int Main(string[] args)
|
||||
{
|
||||
if (!Environment.Is64BitProcess && Environment.OSVersion.Platform != PlatformID.Unix)
|
||||
{
|
||||
Console.Error.WriteLine("The MonoGame content tools only work on a 64bit OS.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
var options = new Options();
|
||||
var parser = new CommandLineParser(options);
|
||||
parser.Title = "2MGFX - The MonoGame Effect compiler.";
|
||||
|
||||
if (!parser.ParseCommandLine(args))
|
||||
return 1;
|
||||
|
||||
// Validate the input file exits.
|
||||
if (!File.Exists(options.SourceFile))
|
||||
{
|
||||
Console.Error.WriteLine("The input file '{0}' was not found!", options.SourceFile);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// TODO: This would be where we would decide the user
|
||||
// is trying to convert an FX file to a MGFX glsl file.
|
||||
//
|
||||
// For now we assume we're going right to a compiled MGFXO file.
|
||||
|
||||
// Parse the MGFX file expanding includes, macros, and returning the techniques.
|
||||
ShaderResult shaderResult;
|
||||
try
|
||||
{
|
||||
shaderResult = ShaderResult.FromFile(options.SourceFile, options, new ConsoleEffectCompilerOutput());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.Error.WriteLine(ex.Message);
|
||||
Console.Error.WriteLine("Failed to parse '{0}'!", options.SourceFile);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Create the effect object.
|
||||
EffectObject effect;
|
||||
var shaderErrorsAndWarnings = string.Empty;
|
||||
try
|
||||
{
|
||||
effect = EffectObject.CompileEffect(shaderResult, out shaderErrorsAndWarnings);
|
||||
|
||||
if (!string.IsNullOrEmpty(shaderErrorsAndWarnings))
|
||||
Console.Error.WriteLine(shaderErrorsAndWarnings);
|
||||
}
|
||||
catch (ShaderCompilerException)
|
||||
{
|
||||
// Write the compiler errors and warnings and let the user know what happened.
|
||||
Console.Error.WriteLine(shaderErrorsAndWarnings);
|
||||
Console.Error.WriteLine("Failed to compile '{0}'!", options.SourceFile);
|
||||
return 1;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// First write all the compiler errors and warnings.
|
||||
if (!string.IsNullOrEmpty(shaderErrorsAndWarnings))
|
||||
Console.Error.WriteLine(shaderErrorsAndWarnings);
|
||||
|
||||
// If we have an exception message then write that.
|
||||
if (!string.IsNullOrEmpty(ex.Message))
|
||||
Console.Error.WriteLine(ex.Message);
|
||||
|
||||
// Let the user know what happened.
|
||||
Console.Error.WriteLine("Unexpected error compiling '{0}'!", options.SourceFile);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Get the output file path.
|
||||
if (options.OutputFile == string.Empty)
|
||||
options.OutputFile = Path.GetFileNameWithoutExtension(options.SourceFile) + ".mgfxo";
|
||||
|
||||
// Write out the effect to a runtime format.
|
||||
try
|
||||
{
|
||||
using (var stream = new FileStream(options.OutputFile, FileMode.Create, FileAccess.Write))
|
||||
using (var writer = new BinaryWriter(stream))
|
||||
effect.Write(writer, options);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.Error.WriteLine(ex.Message);
|
||||
Console.Error.WriteLine("Failed to write '{0}'!", options.OutputFile);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// We finished succesfully.
|
||||
Console.WriteLine("Compiled '{0}' to '{1}'.", options.SourceFile, options.OutputFile);
|
||||
return 0;
|
||||
}
|
||||
|
||||
private class ConsoleEffectCompilerOutput : IEffectCompilerOutput
|
||||
{
|
||||
public void WriteWarning(string file, int line, int column, string message)
|
||||
{
|
||||
Console.WriteLine("Warning: {0}({1},{2}): {3}" , file, line, column, message);
|
||||
}
|
||||
|
||||
public void WriteError(string file, int line, int column, string message)
|
||||
{
|
||||
throw new Exception(string.Format("Error: {0}({1},{2}): {3}", file, line, column, message));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("2MGFX")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("The MonoGame Team")]
|
||||
[assembly: AssemblyProduct("2MGFX")]
|
||||
[assembly: AssemblyCopyright("Copyright (C) The MonoGame Team")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Mark the assembly as CLS compliant so it can be safely used in other .NET languages
|
||||
[assembly: CLSCompliant(true)]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("91c6a368-4017-4be4-babb-39cca4870312")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
@@ -0,0 +1,17 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
namespace TwoMGFX
|
||||
{
|
||||
public class ShaderCompilerException : Exception
|
||||
{
|
||||
public ShaderCompilerException()
|
||||
: base("A shader failed to compile!")
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace TwoMGFX
|
||||
{
|
||||
internal partial class ShaderData
|
||||
{
|
||||
public ShaderData(bool isVertexShader, int sharedIndex, byte[] bytecode)
|
||||
{
|
||||
IsVertexShader = isVertexShader;
|
||||
SharedIndex = sharedIndex;
|
||||
Bytecode = (byte[])bytecode.Clone();
|
||||
}
|
||||
|
||||
public bool IsVertexShader { get; private set; }
|
||||
|
||||
public struct Sampler
|
||||
{
|
||||
public MojoShader.MOJOSHADER_samplerType type;
|
||||
public int textureSlot;
|
||||
public int samplerSlot;
|
||||
public string samplerName;
|
||||
public string parameterName;
|
||||
public int parameter;
|
||||
public SamplerState state;
|
||||
}
|
||||
|
||||
public struct Attribute
|
||||
{
|
||||
public string name;
|
||||
public VertexElementUsage usage;
|
||||
public int index;
|
||||
#pragma warning disable 649
|
||||
public int location;
|
||||
#pragma warning restore 649
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The index to the constant buffers which are
|
||||
/// required by this shader at runtime.
|
||||
/// </summary>
|
||||
public int[] _cbuffers;
|
||||
|
||||
public Sampler[] _samplers;
|
||||
|
||||
public Attribute[] _attributes;
|
||||
|
||||
public byte[] ShaderCode { get; set; }
|
||||
|
||||
|
||||
#region Non-Serialized Stuff
|
||||
|
||||
public byte[] Bytecode { get; private set; }
|
||||
|
||||
// The index of the shader in the shared list.
|
||||
public int SharedIndex { get; private set; }
|
||||
|
||||
#endregion // Non-Serialized Stuff
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
using TwoMGFX.TPGParser;
|
||||
|
||||
namespace TwoMGFX
|
||||
{
|
||||
internal partial class ShaderData
|
||||
{
|
||||
public static ShaderData CreateGLSL(byte[] byteCode, bool isVertexShader, List<ConstantBufferData> cbuffers, int sharedIndex, Dictionary<string, SamplerStateInfo> samplerStates, bool debug)
|
||||
{
|
||||
var dxshader = new ShaderData(isVertexShader, sharedIndex, byteCode);
|
||||
|
||||
// Use MojoShader to convert the HLSL bytecode to GLSL.
|
||||
|
||||
var parseDataPtr = MojoShader.NativeMethods.MOJOSHADER_parse (
|
||||
"glsl",
|
||||
byteCode,
|
||||
byteCode.Length,
|
||||
IntPtr.Zero,
|
||||
0,
|
||||
IntPtr.Zero,
|
||||
0,
|
||||
IntPtr.Zero,
|
||||
IntPtr.Zero,
|
||||
IntPtr.Zero);
|
||||
|
||||
var parseData = MarshalHelper.Unmarshal<MojoShader.MOJOSHADER_parseData> (parseDataPtr);
|
||||
if (parseData.error_count > 0) {
|
||||
var errors = MarshalHelper.UnmarshalArray<MojoShader.MOJOSHADER_error> (
|
||||
parseData.errors,
|
||||
parseData.error_count
|
||||
);
|
||||
throw new Exception (errors [0].error);
|
||||
}
|
||||
|
||||
// Conver the attributes.
|
||||
//
|
||||
// TODO: Could this be done using DX shader reflection?
|
||||
//
|
||||
{
|
||||
var attributes = MarshalHelper.UnmarshalArray<MojoShader.MOJOSHADER_attribute> (
|
||||
parseData.attributes, parseData.attribute_count);
|
||||
|
||||
dxshader._attributes = new Attribute[attributes.Length];
|
||||
for (var i = 0; i < attributes.Length; i++) {
|
||||
dxshader._attributes [i].name = attributes [i].name;
|
||||
dxshader._attributes [i].index = attributes [i].index;
|
||||
dxshader._attributes [i].usage = EffectObject.ToXNAVertexElementUsage (attributes [i].usage);
|
||||
}
|
||||
}
|
||||
|
||||
var symbols = MarshalHelper.UnmarshalArray<MojoShader.MOJOSHADER_symbol> (
|
||||
parseData.symbols, parseData.symbol_count);
|
||||
|
||||
//try to put the symbols in the order they are eventually packed into the uniform arrays
|
||||
//this /should/ be done by pulling the info from mojoshader
|
||||
Array.Sort (symbols, delegate(MojoShader.MOJOSHADER_symbol a, MojoShader.MOJOSHADER_symbol b) {
|
||||
uint va = a.register_index;
|
||||
if (a.info.elements == 1)
|
||||
va += 1024; //hax. mojoshader puts array objects first
|
||||
uint vb = b.register_index;
|
||||
if (b.info.elements == 1)
|
||||
vb += 1024;
|
||||
return va.CompareTo (vb);
|
||||
}
|
||||
);//(a, b) => ((int)(a.info.elements > 1))a.register_index.CompareTo(b.register_index));
|
||||
|
||||
// NOTE: It seems the latest versions of MojoShader only
|
||||
// output vec4 register sets. We leave the code below, but
|
||||
// the runtime has been optimized for this case.
|
||||
|
||||
// For whatever reason the register indexing is
|
||||
// incorrect from MojoShader.
|
||||
{
|
||||
uint bool_index = 0;
|
||||
uint float4_index = 0;
|
||||
uint int4_index = 0;
|
||||
|
||||
for (var i = 0; i < symbols.Length; i++) {
|
||||
switch (symbols [i].register_set) {
|
||||
case MojoShader.MOJOSHADER_symbolRegisterSet.MOJOSHADER_SYMREGSET_BOOL:
|
||||
symbols [i].register_index = bool_index;
|
||||
bool_index += symbols [i].register_count;
|
||||
break;
|
||||
|
||||
case MojoShader.MOJOSHADER_symbolRegisterSet.MOJOSHADER_SYMREGSET_FLOAT4:
|
||||
symbols [i].register_index = float4_index;
|
||||
float4_index += symbols[i].register_count;
|
||||
break;
|
||||
|
||||
case MojoShader.MOJOSHADER_symbolRegisterSet.MOJOSHADER_SYMREGSET_INT4:
|
||||
symbols [i].register_index = int4_index;
|
||||
int4_index += symbols [i].register_count;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the samplers.
|
||||
var samplers = MarshalHelper.UnmarshalArray<MojoShader.MOJOSHADER_sampler> (
|
||||
parseData.samplers, parseData.sampler_count);
|
||||
dxshader._samplers = new Sampler[samplers.Length];
|
||||
for (var i = 0; i < samplers.Length; i++)
|
||||
{
|
||||
// We need the original sampler name... look for that in the symbols.
|
||||
var originalSamplerName =
|
||||
symbols.First(e => e.register_set == MojoShader.MOJOSHADER_symbolRegisterSet.MOJOSHADER_SYMREGSET_SAMPLER &&
|
||||
e.register_index == samplers[i].index
|
||||
).name;
|
||||
|
||||
var sampler = new Sampler
|
||||
{
|
||||
//sampler mapping to parameter is unknown atm
|
||||
parameter = -1,
|
||||
|
||||
// GLSL needs the MojoShader mangled sampler name.
|
||||
samplerName = samplers[i].name,
|
||||
|
||||
// By default use the original sampler name for the parameter name.
|
||||
parameterName = originalSamplerName,
|
||||
|
||||
textureSlot = samplers[i].index,
|
||||
samplerSlot = samplers[i].index,
|
||||
type = samplers[i].type,
|
||||
};
|
||||
|
||||
SamplerStateInfo state;
|
||||
if (samplerStates.TryGetValue(originalSamplerName, out state))
|
||||
{
|
||||
sampler.state = state.State;
|
||||
sampler.parameterName = state.TextureName ?? originalSamplerName;
|
||||
}
|
||||
|
||||
// Store the sampler.
|
||||
dxshader._samplers[i] = sampler;
|
||||
}
|
||||
|
||||
// Gather all the parameters used by this shader.
|
||||
var symbol_types = new [] {
|
||||
new { name = dxshader.IsVertexShader ? "vs_uniforms_bool" : "ps_uniforms_bool", set = MojoShader.MOJOSHADER_symbolRegisterSet.MOJOSHADER_SYMREGSET_BOOL, },
|
||||
new { name = dxshader.IsVertexShader ? "vs_uniforms_ivec4" : "ps_uniforms_ivec4", set = MojoShader.MOJOSHADER_symbolRegisterSet.MOJOSHADER_SYMREGSET_INT4, },
|
||||
new { name = dxshader.IsVertexShader ? "vs_uniforms_vec4" : "ps_uniforms_vec4", set = MojoShader.MOJOSHADER_symbolRegisterSet.MOJOSHADER_SYMREGSET_FLOAT4, },
|
||||
};
|
||||
|
||||
var cbuffer_index = new List<int> ();
|
||||
for (var i = 0; i < symbol_types.Length; i++) {
|
||||
var cbuffer = new ConstantBufferData (symbol_types [i].name,
|
||||
symbol_types [i].set,
|
||||
symbols);
|
||||
if (cbuffer.Size == 0)
|
||||
continue;
|
||||
|
||||
var match = cbuffers.FindIndex (e => e.SameAs (cbuffer));
|
||||
if (match == -1) {
|
||||
cbuffer_index.Add (cbuffers.Count);
|
||||
cbuffers.Add (cbuffer);
|
||||
} else
|
||||
cbuffer_index.Add (match);
|
||||
}
|
||||
dxshader._cbuffers = cbuffer_index.ToArray ();
|
||||
|
||||
var glslCode = parseData.output;
|
||||
|
||||
// TODO: This sort of sucks... why does MojoShader not produce
|
||||
// code valid for GLES out of the box?
|
||||
|
||||
// GLES platforms do not like this.
|
||||
glslCode = glslCode.Replace ("#version 110", "");
|
||||
|
||||
// Add the required precision specifiers for GLES.
|
||||
|
||||
var floatPrecision = dxshader.IsVertexShader ? "precision highp float;\r\n" : "precision mediump float;\r\n";
|
||||
|
||||
glslCode = "#ifdef GL_ES\r\n" +
|
||||
floatPrecision +
|
||||
"precision mediump int;\r\n" +
|
||||
"#endif\r\n" +
|
||||
glslCode;
|
||||
|
||||
// Enable standard derivatives extension as necessary
|
||||
if ((glslCode.IndexOf("dFdx", StringComparison.InvariantCulture) >= 0)
|
||||
|| (glslCode.IndexOf("dFdy", StringComparison.InvariantCulture) >= 0))
|
||||
{
|
||||
glslCode = "#extension GL_OES_standard_derivatives : enable\r\n" + glslCode;
|
||||
}
|
||||
|
||||
// Store the code for serialization.
|
||||
dxshader.ShaderCode = Encoding.ASCII.GetBytes (glslCode);
|
||||
|
||||
return dxshader;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using TwoMGFX.TPGParser;
|
||||
|
||||
namespace TwoMGFX
|
||||
{
|
||||
internal partial class ShaderData
|
||||
{
|
||||
public static ShaderData CreatePSSL(byte[] byteCode, bool isVertexShader, List<ConstantBufferData> cbuffers, int sharedIndex, Dictionary<string, SamplerStateInfo> samplerStates, bool debug)
|
||||
{
|
||||
// This is only part of the private PS4 repository.
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
using System.Collections.Generic;
|
||||
using SharpDX.Direct3D;
|
||||
using TwoMGFX.TPGParser;
|
||||
|
||||
namespace TwoMGFX
|
||||
{
|
||||
internal partial class ShaderData
|
||||
{
|
||||
public static ShaderData CreateHLSL(byte[] byteCode, bool isVertexShader, List<ConstantBufferData> cbuffers, int sharedIndex, Dictionary<string, SamplerStateInfo> samplerStates, bool debug)
|
||||
{
|
||||
var dxshader = new ShaderData(isVertexShader, sharedIndex, byteCode);
|
||||
dxshader._attributes = new Attribute[0];
|
||||
|
||||
// Strip the bytecode we're gonna save!
|
||||
var stripFlags = SharpDX.D3DCompiler.StripFlags.CompilerStripReflectionData |
|
||||
SharpDX.D3DCompiler.StripFlags.CompilerStripTestBlobs;
|
||||
|
||||
if (!debug)
|
||||
stripFlags |= SharpDX.D3DCompiler.StripFlags.CompilerStripDebugInformation;
|
||||
|
||||
using (var original = new SharpDX.D3DCompiler.ShaderBytecode(byteCode))
|
||||
{
|
||||
// Strip the bytecode for saving to disk.
|
||||
var stripped = original.Strip(stripFlags);
|
||||
{
|
||||
// Only SM4 and above works with strip... so this can return null!
|
||||
if (stripped != null)
|
||||
{
|
||||
dxshader.ShaderCode = stripped;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: There is a way to strip SM3 and below
|
||||
// but we have to write the method ourselves.
|
||||
//
|
||||
// If we need to support it then consider porting
|
||||
// this code over...
|
||||
//
|
||||
// http://entland.homelinux.com/blog/2009/01/15/stripping-comments-from-shader-bytecodes/
|
||||
//
|
||||
dxshader.ShaderCode = (byte[])dxshader.Bytecode.Clone();
|
||||
}
|
||||
}
|
||||
|
||||
// Use reflection to get details of the shader.
|
||||
using (var refelect = new SharpDX.D3DCompiler.ShaderReflection(byteCode))
|
||||
{
|
||||
// Get the samplers.
|
||||
var samplers = new List<Sampler>();
|
||||
for (var i = 0; i < refelect.Description.BoundResources; i++)
|
||||
{
|
||||
var rdesc = refelect.GetResourceBindingDescription(i);
|
||||
if (rdesc.Type == SharpDX.D3DCompiler.ShaderInputType.Texture)
|
||||
{
|
||||
var samplerName = rdesc.Name;
|
||||
|
||||
var sampler = new Sampler
|
||||
{
|
||||
samplerName = string.Empty,
|
||||
textureSlot = rdesc.BindPoint,
|
||||
samplerSlot = rdesc.BindPoint,
|
||||
parameterName = samplerName
|
||||
};
|
||||
|
||||
SamplerStateInfo state;
|
||||
if (samplerStates.TryGetValue(samplerName, out state))
|
||||
{
|
||||
sampler.parameterName = state.TextureName ?? samplerName;
|
||||
sampler.state = state.State;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var s in samplerStates.Values)
|
||||
{
|
||||
if (samplerName == s.TextureName)
|
||||
{
|
||||
sampler.state = s.State;
|
||||
samplerName = s.Name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find sampler slot, which can be different from the texture slot.
|
||||
for (int j = 0; j < refelect.Description.BoundResources; j++)
|
||||
{
|
||||
var samplerrdesc = refelect.GetResourceBindingDescription(j);
|
||||
|
||||
if (samplerrdesc.Type == SharpDX.D3DCompiler.ShaderInputType.Sampler &&
|
||||
samplerrdesc.Name == samplerName)
|
||||
{
|
||||
sampler.samplerSlot = samplerrdesc.BindPoint;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (rdesc.Dimension)
|
||||
{
|
||||
case ShaderResourceViewDimension.Texture1D:
|
||||
case ShaderResourceViewDimension.Texture1DArray:
|
||||
sampler.type = MojoShader.MOJOSHADER_samplerType.MOJOSHADER_SAMPLER_1D;
|
||||
break;
|
||||
|
||||
case ShaderResourceViewDimension.Texture2D:
|
||||
case ShaderResourceViewDimension.Texture2DArray:
|
||||
case ShaderResourceViewDimension.Texture2DMultisampled:
|
||||
case ShaderResourceViewDimension.Texture2DMultisampledArray:
|
||||
sampler.type = MojoShader.MOJOSHADER_samplerType.MOJOSHADER_SAMPLER_2D;
|
||||
break;
|
||||
|
||||
case ShaderResourceViewDimension.Texture3D:
|
||||
sampler.type = MojoShader.MOJOSHADER_samplerType.MOJOSHADER_SAMPLER_VOLUME;
|
||||
break;
|
||||
|
||||
case ShaderResourceViewDimension.TextureCube:
|
||||
case ShaderResourceViewDimension.TextureCubeArray:
|
||||
sampler.type = MojoShader.MOJOSHADER_samplerType.MOJOSHADER_SAMPLER_CUBE;
|
||||
break;
|
||||
}
|
||||
|
||||
samplers.Add(sampler);
|
||||
}
|
||||
}
|
||||
dxshader._samplers = samplers.ToArray();
|
||||
|
||||
// Gather all the constant buffers used by this shader.
|
||||
dxshader._cbuffers = new int[refelect.Description.ConstantBuffers];
|
||||
for (var i = 0; i < refelect.Description.ConstantBuffers; i++)
|
||||
{
|
||||
var cb = new ConstantBufferData(refelect.GetConstantBuffer(i));
|
||||
|
||||
// Look for a duplicate cbuffer in the list.
|
||||
for (var c = 0; c < cbuffers.Count; c++)
|
||||
{
|
||||
if (cb.SameAs(cbuffers[c]))
|
||||
{
|
||||
cb = null;
|
||||
dxshader._cbuffers[i] = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Add a new cbuffer.
|
||||
if (cb != null)
|
||||
{
|
||||
dxshader._cbuffers[i] = cbuffers.Count;
|
||||
cbuffers.Add(cb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dxshader;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
using System.IO;
|
||||
|
||||
namespace TwoMGFX
|
||||
{
|
||||
internal partial class ShaderData
|
||||
{
|
||||
public void Write(BinaryWriter writer, Options options)
|
||||
{
|
||||
writer.Write(IsVertexShader);
|
||||
|
||||
writer.Write(ShaderCode.Length);
|
||||
writer.Write(ShaderCode);
|
||||
|
||||
writer.Write((byte)_samplers.Length);
|
||||
foreach (var sampler in _samplers)
|
||||
{
|
||||
writer.Write((byte)sampler.type);
|
||||
writer.Write((byte)sampler.textureSlot);
|
||||
writer.Write((byte)sampler.samplerSlot);
|
||||
|
||||
if (sampler.state != null)
|
||||
{
|
||||
writer.Write(true);
|
||||
writer.Write((byte)sampler.state.AddressU);
|
||||
writer.Write((byte)sampler.state.AddressV);
|
||||
writer.Write((byte)sampler.state.AddressW);
|
||||
writer.Write(sampler.state.BorderColor.R);
|
||||
writer.Write(sampler.state.BorderColor.G);
|
||||
writer.Write(sampler.state.BorderColor.B);
|
||||
writer.Write(sampler.state.BorderColor.A);
|
||||
writer.Write((byte)sampler.state.Filter);
|
||||
writer.Write(sampler.state.MaxAnisotropy);
|
||||
writer.Write(sampler.state.MaxMipLevel);
|
||||
writer.Write(sampler.state.MipMapLevelOfDetailBias);
|
||||
}
|
||||
else
|
||||
writer.Write(false);
|
||||
|
||||
writer.Write(sampler.samplerName);
|
||||
|
||||
writer.Write((byte)sampler.parameter);
|
||||
}
|
||||
|
||||
writer.Write((byte)_cbuffers.Length);
|
||||
foreach (var cb in _cbuffers)
|
||||
writer.Write((byte)cb);
|
||||
|
||||
writer.Write((byte)_attributes.Length);
|
||||
foreach (var attrib in _attributes)
|
||||
{
|
||||
writer.Write(attrib.name);
|
||||
writer.Write((byte)attrib.usage);
|
||||
writer.Write((byte)attrib.index);
|
||||
writer.Write((short)attrib.location);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using TwoMGFX.TPGParser;
|
||||
|
||||
namespace TwoMGFX
|
||||
{
|
||||
class DirectX11ShaderProfile : ShaderProfile
|
||||
{
|
||||
private static readonly Regex HlslPixelShaderRegex = new Regex(@"^ps_(?<major>1|2|3|4|5)_(?<minor>0|1|)(_level_(9_1|9_2|9_3))?$", RegexOptions.Compiled);
|
||||
private static readonly Regex HlslVertexShaderRegex = new Regex(@"^vs_(?<major>1|2|3|4|5)_(?<minor>0|1|)(_level_(9_1|9_2|9_3))?$", RegexOptions.Compiled);
|
||||
|
||||
public DirectX11ShaderProfile()
|
||||
: base("DirectX_11", 1)
|
||||
{
|
||||
}
|
||||
|
||||
internal override void AddMacros(Dictionary<string, string> macros)
|
||||
{
|
||||
macros.Add("HLSL", "1");
|
||||
macros.Add("SM4", "1");
|
||||
}
|
||||
|
||||
internal override void ValidateShaderModels(PassInfo pass)
|
||||
{
|
||||
int major, minor;
|
||||
|
||||
if (!string.IsNullOrEmpty(pass.vsFunction))
|
||||
{
|
||||
ParseShaderModel(pass.vsModel, HlslVertexShaderRegex, out major, out minor);
|
||||
if (major <= 3)
|
||||
throw new Exception(String.Format("Invalid profile '{0}'. Vertex shader '{1}' must be SM 4.0 level 9.1 or higher!", pass.vsModel, pass.vsFunction));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(pass.psFunction))
|
||||
{
|
||||
ParseShaderModel(pass.psModel, HlslPixelShaderRegex, out major, out minor);
|
||||
if (major <= 3)
|
||||
throw new Exception(String.Format("Invalid profile '{0}'. Pixel shader '{1}' must be SM 4.0 level 9.1 or higher!", pass.vsModel, pass.psFunction));
|
||||
}
|
||||
}
|
||||
|
||||
internal override ShaderData CreateShader(ShaderResult shaderResult, string shaderFunction, string shaderProfile, bool isVertexShader, EffectObject effect, ref string errorsAndWarnings)
|
||||
{
|
||||
var bytecode = EffectObject.CompileHLSL(shaderResult, shaderFunction, shaderProfile, ref errorsAndWarnings);
|
||||
|
||||
// First look to see if we already created this same shader.
|
||||
foreach (var shader in effect.Shaders)
|
||||
{
|
||||
if (bytecode.SequenceEqual(shader.Bytecode))
|
||||
return shader;
|
||||
}
|
||||
|
||||
var shaderInfo = shaderResult.ShaderInfo;
|
||||
var shaderData = ShaderData.CreateHLSL(bytecode, isVertexShader, effect.ConstantBuffers, effect.Shaders.Count, shaderInfo.SamplerStates, shaderResult.Debug);
|
||||
effect.Shaders.Add(shaderData);
|
||||
return shaderData;
|
||||
}
|
||||
|
||||
internal override bool Supports(string platform)
|
||||
{
|
||||
if (platform == "Windows" ||
|
||||
platform == "WindowsPhone8" ||
|
||||
platform == "WindowsStoreApp")
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using TwoMGFX.TPGParser;
|
||||
|
||||
namespace TwoMGFX
|
||||
{
|
||||
class OpenGLShaderProfile : ShaderProfile
|
||||
{
|
||||
private static readonly Regex GlslPixelShaderRegex = new Regex(@"^ps_(?<major>1|2|3|4|5)_(?<minor>0|1|)$", RegexOptions.Compiled);
|
||||
private static readonly Regex GlslVertexShaderRegex = new Regex(@"^vs_(?<major>1|2|3|4|5)_(?<minor>0|1|)$", RegexOptions.Compiled);
|
||||
|
||||
public OpenGLShaderProfile()
|
||||
: base("OpenGL", 0)
|
||||
{
|
||||
}
|
||||
|
||||
internal override void AddMacros(Dictionary<string, string> macros)
|
||||
{
|
||||
macros.Add("GLSL", "1");
|
||||
macros.Add("OPENGL", "1");
|
||||
}
|
||||
|
||||
internal override void ValidateShaderModels(PassInfo pass)
|
||||
{
|
||||
int major, minor;
|
||||
|
||||
if (!string.IsNullOrEmpty(pass.vsFunction))
|
||||
{
|
||||
ParseShaderModel(pass.vsModel, GlslVertexShaderRegex, out major, out minor);
|
||||
if (major > 3)
|
||||
throw new Exception(String.Format("Invalid profile '{0}'. Vertex shader '{1}' must be SM 3.0 or lower!", pass.vsModel, pass.vsFunction));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(pass.psFunction))
|
||||
{
|
||||
ParseShaderModel(pass.psModel, GlslPixelShaderRegex, out major, out minor);
|
||||
if (major > 3)
|
||||
throw new Exception(String.Format("Invalid profile '{0}'. Pixel shader '{1}' must be SM 3.0 or lower!", pass.vsModel, pass.psFunction));
|
||||
}
|
||||
}
|
||||
|
||||
internal override ShaderData CreateShader(ShaderResult shaderResult, string shaderFunction, string shaderProfile, bool isVertexShader, EffectObject effect, ref string errorsAndWarnings)
|
||||
{
|
||||
// For now GLSL is only supported via translation
|
||||
// using MojoShader which works from HLSL bytecode.
|
||||
var bytecode = EffectObject.CompileHLSL(shaderResult, shaderFunction, shaderProfile, ref errorsAndWarnings);
|
||||
|
||||
// First look to see if we already created this same shader.
|
||||
foreach (var shader in effect.Shaders)
|
||||
{
|
||||
if (bytecode.SequenceEqual(shader.Bytecode))
|
||||
return shader;
|
||||
}
|
||||
|
||||
var shaderInfo = shaderResult.ShaderInfo;
|
||||
var shaderData = ShaderData.CreateGLSL(bytecode, isVertexShader, effect.ConstantBuffers, effect.Shaders.Count, shaderInfo.SamplerStates, shaderResult.Debug);
|
||||
effect.Shaders.Add(shaderData);
|
||||
|
||||
return shaderData;
|
||||
}
|
||||
|
||||
internal override bool Supports(string platform)
|
||||
{
|
||||
if (platform == "iOS" ||
|
||||
platform == "Android" ||
|
||||
platform == "DesktopGL" ||
|
||||
platform == "MacOSX" ||
|
||||
platform == "RaspberryPi")
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.Xna.Framework.Content.Pipeline;
|
||||
using TwoMGFX.TPGParser;
|
||||
|
||||
namespace TwoMGFX
|
||||
{
|
||||
[TypeConverter(typeof(StringConverter))]
|
||||
public abstract class ShaderProfile
|
||||
{
|
||||
private static readonly LoadedTypeCollection<ShaderProfile> _profiles = new LoadedTypeCollection<ShaderProfile>();
|
||||
|
||||
protected ShaderProfile(string name, byte formatId)
|
||||
{
|
||||
Name = name;
|
||||
FormatId = formatId;
|
||||
}
|
||||
|
||||
public static readonly ShaderProfile OpenGL = FromName("OpenGL");
|
||||
|
||||
public static readonly ShaderProfile DirectX_11 = FromName("DirectX_11");
|
||||
|
||||
/// <summary>
|
||||
/// Returns all the loaded shader profiles.
|
||||
/// </summary>
|
||||
public static IEnumerable<ShaderProfile> All
|
||||
{
|
||||
get { return _profiles; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the name of the shader profile.
|
||||
/// </summary>
|
||||
public string Name { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the format identifier used in the MGFX file format.
|
||||
/// </summary>
|
||||
public byte FormatId { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the correct profile for the named platform or
|
||||
/// null if no supporting profile is found.
|
||||
/// </summary>
|
||||
public static ShaderProfile ForPlatform(string platform)
|
||||
{
|
||||
return _profiles.FirstOrDefault(p => p.Supports(platform));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the profile by name or null if no match is found.
|
||||
/// </summary>
|
||||
public static ShaderProfile FromName(string name)
|
||||
{
|
||||
return _profiles.FirstOrDefault(p => p.Name == name);
|
||||
}
|
||||
|
||||
internal abstract void AddMacros(Dictionary<string, string> macros);
|
||||
|
||||
internal abstract void ValidateShaderModels(PassInfo pass);
|
||||
|
||||
internal abstract ShaderData CreateShader(ShaderResult shaderResult, string shaderFunction, string shaderProfile, bool isVertexShader, EffectObject effect, ref string errorsAndWarnings);
|
||||
|
||||
internal abstract bool Supports(string platform);
|
||||
|
||||
protected static void ParseShaderModel(string text, Regex regex, out int major, out int minor)
|
||||
{
|
||||
var match = regex.Match(text);
|
||||
if (!match.Success)
|
||||
{
|
||||
major = 0;
|
||||
minor = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
major = int.Parse(match.Groups["major"].Value, NumberStyles.Integer, CultureInfo.InvariantCulture);
|
||||
minor = int.Parse(match.Groups["minor"].Value, NumberStyles.Integer, CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
private class StringConverter : TypeConverter
|
||||
{
|
||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||
{
|
||||
if (value is string)
|
||||
{
|
||||
var name = value as string;
|
||||
|
||||
foreach (var e in All)
|
||||
{
|
||||
if (e.Name == name)
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
return base.ConvertFrom(context, culture, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using TwoMGFX.TPGParser;
|
||||
|
||||
namespace TwoMGFX
|
||||
{
|
||||
public class ShaderResult
|
||||
{
|
||||
public ShaderInfo ShaderInfo { get; private set; }
|
||||
|
||||
public string FilePath { get; private set; }
|
||||
|
||||
public string FileContent { get; private set; }
|
||||
|
||||
public string OutputFilePath { get; private set; }
|
||||
|
||||
public List<string> Dependencies { get; private set; }
|
||||
|
||||
public List<string> AdditionalOutputFiles { get; private set; }
|
||||
|
||||
public ShaderProfile Profile { get; private set; }
|
||||
|
||||
public bool Debug { get; private set; }
|
||||
|
||||
|
||||
static public ShaderResult FromFile(string path, Options options, IEffectCompilerOutput output)
|
||||
{
|
||||
var effectSource = File.ReadAllText(path);
|
||||
return FromString(effectSource, path, options, output);
|
||||
}
|
||||
|
||||
static public ShaderResult FromString(string effectSource, string filePath, Options options, IEffectCompilerOutput output)
|
||||
{
|
||||
var macros = new Dictionary<string, string>();
|
||||
macros.Add("MGFX", "1");
|
||||
|
||||
options.Profile.AddMacros(macros);
|
||||
|
||||
// If we're building shaders for debug set that flag too.
|
||||
if (options.Debug)
|
||||
macros.Add("DEBUG", "1");
|
||||
|
||||
if (!string.IsNullOrEmpty(options.Defines))
|
||||
{
|
||||
var defines = options.Defines.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (var define in defines)
|
||||
{
|
||||
var name = define;
|
||||
var value = "1";
|
||||
if (define.Contains("="))
|
||||
{
|
||||
var parts = define.Split('=');
|
||||
|
||||
if (parts.Length > 0)
|
||||
name = parts[0].Trim();
|
||||
|
||||
if (parts.Length > 1)
|
||||
value = parts[1].Trim();
|
||||
}
|
||||
|
||||
macros.Add(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
// Use the D3DCompiler to pre-process the file resolving
|
||||
// all #includes and macros.... this even works for GLSL.
|
||||
string newFile;
|
||||
var fullPath = Path.GetFullPath(filePath);
|
||||
var dependencies = new List<string>();
|
||||
newFile = Preprocessor.Preprocess(effectSource, fullPath, macros, dependencies, output);
|
||||
|
||||
// Parse the resulting file for techniques and passes.
|
||||
var tree = new Parser(new Scanner()).Parse(newFile, fullPath);
|
||||
if (tree.Errors.Count > 0)
|
||||
{
|
||||
var errors = String.Empty;
|
||||
foreach (var error in tree.Errors)
|
||||
errors += string.Format("{0}({1},{2}) : {3}\r\n", error.File, error.Line, error.Column, error.Message);
|
||||
|
||||
throw new Exception(errors);
|
||||
}
|
||||
|
||||
// Evaluate the results of the parse tree.
|
||||
var shaderInfo = tree.Eval() as ShaderInfo;
|
||||
|
||||
// Remove the samplers and techniques so that the shader compiler
|
||||
// gets a clean file without any FX file syntax in it.
|
||||
var cleanFile = newFile;
|
||||
WhitespaceNodes(TokenType.Technique_Declaration, tree.Nodes, ref cleanFile);
|
||||
WhitespaceNodes(TokenType.Sampler_Declaration_States, tree.Nodes, ref cleanFile);
|
||||
|
||||
// Setup the rest of the shader info.
|
||||
ShaderResult result = new ShaderResult();
|
||||
result.ShaderInfo = shaderInfo;
|
||||
result.Dependencies = dependencies;
|
||||
result.FilePath = fullPath;
|
||||
result.FileContent = cleanFile;
|
||||
if (!string.IsNullOrEmpty(options.OutputFile))
|
||||
result.OutputFilePath = Path.GetFullPath(options.OutputFile);
|
||||
result.AdditionalOutputFiles = new List<string>();
|
||||
|
||||
// Remove empty techniques.
|
||||
for (var i = 0; i < shaderInfo.Techniques.Count; i++)
|
||||
{
|
||||
var tech = shaderInfo.Techniques[i];
|
||||
if (tech.Passes.Count <= 0)
|
||||
{
|
||||
shaderInfo.Techniques.RemoveAt(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
// We must have at least one technique.
|
||||
if (shaderInfo.Techniques.Count <= 0)
|
||||
throw new Exception("The effect must contain at least one technique and pass!");
|
||||
|
||||
result.Profile = options.Profile;
|
||||
result.Debug = options.Debug;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void WhitespaceNodes(TokenType type, List<ParseNode> nodes, ref string sourceFile)
|
||||
{
|
||||
for (var i = 0; i < nodes.Count; i++)
|
||||
{
|
||||
var n = nodes[i];
|
||||
if (n.Token.Type != type)
|
||||
{
|
||||
WhitespaceNodes(type, n.Nodes, ref sourceFile);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the full content of this node.
|
||||
var start = n.Token.StartPos;
|
||||
var end = n.Token.EndPos;
|
||||
var length = end - n.Token.StartPos;
|
||||
var content = sourceFile.Substring(start, length);
|
||||
|
||||
// Replace the content of this node with whitespace.
|
||||
for (var c = 0; c < length; c++)
|
||||
{
|
||||
if (!char.IsWhiteSpace(content[c]))
|
||||
content = content.Replace(content[c], ' ');
|
||||
}
|
||||
|
||||
// Add the whitespace back to the source file.
|
||||
var newfile = sourceFile.Substring(0, start);
|
||||
newfile += content;
|
||||
newfile += sourceFile.Substring(end);
|
||||
sourceFile = newfile;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,428 @@
|
||||
// MonoGame Effect Parser
|
||||
//
|
||||
// For use with our fork of the "Tiny Parser Generator"
|
||||
// https://github.com/SickheadGames/TinyPG
|
||||
//
|
||||
|
||||
<% @TinyPG Namespace="TwoMGFX.TPGParser" Language="C#"%>
|
||||
|
||||
[Skip] BlockComment -> @"/\*([^*]|\*[^/])*\*/";
|
||||
[Skip] Comment -> @"//[^\n\r]*";
|
||||
[Skip] Whitespace -> @"[ \t\n\r]+";
|
||||
[FileAndLine] LinePragma -> @"^[ \t]*#line[ \t]*(?<Line>\d*)[ \t]*(\""(?<File>[^\""\\]*(?:\\.[^\""\\]*)*)\"")?\n";
|
||||
|
||||
// TOKENS
|
||||
[IgnoreCase] Pass -> @"pass";
|
||||
[IgnoreCase] Technique -> @"technique";
|
||||
[IgnoreCase] Sampler -> @"sampler1D|sampler2D|sampler3D|samplerCUBE|SamplerState|sampler";
|
||||
[IgnoreCase] SamplerState -> @"sampler_state";
|
||||
[IgnoreCase] VertexShader -> @"VertexShader";
|
||||
[IgnoreCase] PixelShader -> @"PixelShader";
|
||||
[IgnoreCase] Register -> @"register";
|
||||
[IgnoreCase] Boolean -> @"true|false|0|1";
|
||||
Number -> @"[+-]? ?[0-9]?\.?[0-9]+[fF]?";
|
||||
[IgnoreCase] HexColor -> @"0x[0-9a-f]{6}([0-9a-f][0-9a-f])?";
|
||||
Identifier -> @"[A-Za-z_][A-Za-z0-9_]*";
|
||||
OpenBracket -> @"{";
|
||||
CloseBracket -> @"}";
|
||||
Equals -> @"=";
|
||||
Colon -> @":";
|
||||
Comma -> @",";
|
||||
Semicolon -> @";";
|
||||
Or -> @"\|";
|
||||
OpenParenthesis -> @"\(";
|
||||
CloseParenthesis -> @"\)";
|
||||
OpenSquareBracket -> @"\[";
|
||||
CloseSquareBracket -> @"\]";
|
||||
LessThan -> @"<";
|
||||
GreaterThan -> @">";
|
||||
[IgnoreCase] Compile -> @"compile";
|
||||
ShaderModel -> @"[A-Za-z_][A-Za-z0-9_]*";
|
||||
Code -> @"[\S]+";
|
||||
EndOfFile -> @"^$";
|
||||
|
||||
// Sampler states
|
||||
[IgnoreCase] MinFilter -> @"MinFilter";
|
||||
[IgnoreCase] MagFilter -> @"MagFilter";
|
||||
[IgnoreCase] MipFilter -> @"MipFilter";
|
||||
[IgnoreCase] Filter -> @"Filter";
|
||||
[IgnoreCase] Texture -> @"Texture";
|
||||
[IgnoreCase] AddressU -> @"AddressU";
|
||||
[IgnoreCase] AddressV -> @"AddressV";
|
||||
[IgnoreCase] AddressW -> @"AddressW";
|
||||
[IgnoreCase] BorderColor -> @"BorderColor";
|
||||
[IgnoreCase] MaxAnisotropy -> @"MaxAnisotropy";
|
||||
[IgnoreCase] MaxMipLevel -> @"MaxMipLevel|MaxLod";
|
||||
[IgnoreCase] MipLodBias -> @"MipLodBias";
|
||||
|
||||
// Address Mode
|
||||
[IgnoreCase] Clamp -> @"Clamp";
|
||||
[IgnoreCase] Wrap -> @"Wrap";
|
||||
[IgnoreCase] Mirror -> @"Mirror";
|
||||
[IgnoreCase] Border -> @"Border";
|
||||
|
||||
// Texture Filters
|
||||
[IgnoreCase] None -> @"None";
|
||||
[IgnoreCase] Linear -> @"Linear";
|
||||
[IgnoreCase] Point -> @"Point";
|
||||
[IgnoreCase] Anisotropic -> @"Anisotropic";
|
||||
|
||||
// Render states
|
||||
[IgnoreCase] AlphaBlendEnable -> @"AlphaBlendEnable";
|
||||
[IgnoreCase] SrcBlend -> @"SrcBlend";
|
||||
[IgnoreCase] DestBlend -> @"DestBlend";
|
||||
[IgnoreCase] BlendOp -> @"BlendOp";
|
||||
[IgnoreCase] ColorWriteEnable -> @"ColorWriteEnable";
|
||||
[IgnoreCase] ZEnable -> @"ZEnable";
|
||||
[IgnoreCase] ZWriteEnable -> @"ZWriteEnable";
|
||||
[IgnoreCase] ZFunc-> @"ZFunc";
|
||||
[IgnoreCase] DepthBias -> @"DepthBias";
|
||||
[IgnoreCase] CullMode -> @"CullMode";
|
||||
[IgnoreCase] FillMode -> @"FillMode";
|
||||
[IgnoreCase] MultiSampleAntiAlias -> @"MultiSampleAntiAlias";
|
||||
[IgnoreCase] ScissorTestEnable -> @"ScissorTestEnable";
|
||||
[IgnoreCase] SlopeScaleDepthBias -> @"SlopeScaleDepthBias";
|
||||
[IgnoreCase] StencilEnable -> @"StencilEnable";
|
||||
[IgnoreCase] StencilFail -> @"StencilFail";
|
||||
[IgnoreCase] StencilFunc -> @"StencilFunc";
|
||||
[IgnoreCase] StencilMask -> @"StencilMask";
|
||||
[IgnoreCase] StencilPass -> @"StencilPass";
|
||||
[IgnoreCase] StencilRef -> @"StencilRef";
|
||||
[IgnoreCase] StencilWriteMask -> @"StencilWriteMask";
|
||||
[IgnoreCase] StencilZFail -> @"StencilZFail";
|
||||
|
||||
|
||||
// Compare function
|
||||
[IgnoreCase] Never -> @"Never";
|
||||
[IgnoreCase] Less -> @"Less";
|
||||
[IgnoreCase] Equal -> @"Equal";
|
||||
[IgnoreCase] LessEqual -> @"LessEqual";
|
||||
[IgnoreCase] Greater -> @"Greater";
|
||||
[IgnoreCase] NotEqual -> @"NotEqual";
|
||||
[IgnoreCase] GreaterEqual -> @"GreaterEqual";
|
||||
[IgnoreCase] Always -> @"Always";
|
||||
|
||||
// Stencil operation
|
||||
[IgnoreCase] Keep -> @"Keep";
|
||||
[IgnoreCase] Zero -> @"Zero";
|
||||
[IgnoreCase] Replace -> @"Replace";
|
||||
[IgnoreCase] IncrSat -> @"IncrSat";
|
||||
[IgnoreCase] DecrSat -> @"DecrSat";
|
||||
[IgnoreCase] Invert -> @"Invert";
|
||||
[IgnoreCase] Incr -> @"Incr";
|
||||
[IgnoreCase] Decr -> @"Decr";
|
||||
|
||||
// Colors
|
||||
[IgnoreCase] Red -> @"Red";
|
||||
[IgnoreCase] Green -> @"Green";
|
||||
[IgnoreCase] Blue -> @"Blue";
|
||||
[IgnoreCase] Alpha -> @"Alpha";
|
||||
[IgnoreCase] All -> @"All";
|
||||
|
||||
// Cull mode
|
||||
[IgnoreCase] Cw -> @"Cw";
|
||||
[IgnoreCase] Ccw -> @"Ccw";
|
||||
|
||||
// Fill mode
|
||||
[IgnoreCase] Solid -> @"Solid";
|
||||
[IgnoreCase] WireFrame -> @"WireFrame";
|
||||
|
||||
// Blend function
|
||||
[IgnoreCase] Add -> @"Add";
|
||||
[IgnoreCase] Subtract -> @"Subtract";
|
||||
[IgnoreCase] RevSubtract -> @"RevSubtract";
|
||||
[IgnoreCase] Min -> @"Min";
|
||||
[IgnoreCase] Max -> @"Max";
|
||||
|
||||
// Blend
|
||||
[IgnoreCase] Zero -> @"Zero";
|
||||
[IgnoreCase] One -> @"One";
|
||||
[IgnoreCase] SrcColor -> @"SrcColor";
|
||||
[IgnoreCase] InvSrcColor -> @"InvSrcColor";
|
||||
[IgnoreCase] SrcAlpha -> @"SrcAlpha";
|
||||
[IgnoreCase] InvSrcAlpha -> @"InvSrcAlpha";
|
||||
[IgnoreCase] DestAlpha -> @"DestAlpha";
|
||||
[IgnoreCase] InvDestAlpha -> @"InvDestAlpha";
|
||||
[IgnoreCase] DestColor -> @"DestColor";
|
||||
[IgnoreCase] InvDestColor -> @"InvDestColor";
|
||||
[IgnoreCase] SrcAlphaSat -> @"SrcAlphaSat";
|
||||
[IgnoreCase] BlendFactor -> @"BlendFactor";
|
||||
[IgnoreCase] InvBlendFactor -> @"InvBlendFactor";
|
||||
|
||||
|
||||
// Productions
|
||||
Start -> (Code | Technique_Declaration | Sampler_Declaration)* EndOfFile
|
||||
{
|
||||
var shader = new ShaderInfo();
|
||||
|
||||
foreach (var node in Nodes)
|
||||
node.Eval(tree, shader);
|
||||
|
||||
return shader;
|
||||
};
|
||||
|
||||
Technique_Declaration -> Technique Identifier? OpenBracket Pass_Declaration+ CloseBracket
|
||||
{
|
||||
var technique = new TechniqueInfo();
|
||||
technique.name = $Identifier as string ?? string.Empty;
|
||||
technique.startPos = Token.StartPos;
|
||||
technique.length = Token.Length;
|
||||
|
||||
foreach (var node in Nodes)
|
||||
node.Eval(tree, technique);
|
||||
|
||||
// Make sure we have at least one pass.
|
||||
if (technique.Passes.Count > 0)
|
||||
{
|
||||
var shaderInfo = paramlist[0] as ShaderInfo;
|
||||
shaderInfo.Techniques.Add(technique);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
FillMode_Solid -> Solid { return FillMode.Solid; };
|
||||
FillMode_WireFrame -> WireFrame { return FillMode.WireFrame; };
|
||||
FillModes -> (FillMode_Solid|FillMode_WireFrame)
|
||||
{
|
||||
return $FillMode_Solid ?? $FillMode_WireFrame;
|
||||
};
|
||||
|
||||
CullMode_None -> None { return CullMode.None; };
|
||||
CullMode_Cw -> Cw { return CullMode.CullClockwiseFace; };
|
||||
CullMode_Ccw -> Ccw { return CullMode.CullCounterClockwiseFace; };
|
||||
CullModes -> (CullMode_None|CullMode_Cw|CullMode_Ccw)
|
||||
{
|
||||
return $CullMode_None ?? $CullMode_Cw ?? $CullMode_Ccw;
|
||||
};
|
||||
|
||||
Colors_None -> None { return ColorWriteChannels.None; };
|
||||
Colors_Red -> Red { return ColorWriteChannels.Red; };
|
||||
Colors_Green -> Green { return ColorWriteChannels.Green; };
|
||||
Colors_Blue -> Blue { return ColorWriteChannels.Blue; };
|
||||
Colors_Alpha -> Alpha { return ColorWriteChannels.Alpha; };
|
||||
Colors_All -> All { return ColorWriteChannels.All; };
|
||||
Colors_Boolean -> Boolean { return ParseTreeTools.ParseBool((string)$Boolean) ? ColorWriteChannels.All : ColorWriteChannels.None; };
|
||||
Colors -> (Colors_Red|Colors_Green|Colors_Blue|Colors_Alpha|Colors_None|Colors_All|Colors_Boolean)
|
||||
{
|
||||
return $Colors_Red ?? $Colors_Green ?? $Colors_Blue ?? $Colors_Alpha ?? $Colors_None ?? $Colors_All ?? $Colors_Boolean;
|
||||
};
|
||||
ColorsMasks -> Colors (Or Colors)? (Or Colors)? (Or Colors)?
|
||||
{
|
||||
return (ColorWriteChannels)($Colors[0] ?? 0) |
|
||||
(ColorWriteChannels)($Colors[1] ?? 0) |
|
||||
(ColorWriteChannels)($Colors[2] ?? 0) |
|
||||
(ColorWriteChannels)($Colors[3] ?? 0);
|
||||
};
|
||||
|
||||
Blend_Zero -> Zero { return Blend.Zero; };
|
||||
Blend_One -> One { return Blend.One; };
|
||||
Blend_SrcColor -> SrcColor { return Blend.SourceColor; };
|
||||
Blend_InvSrcColor -> InvSrcColor { return Blend.InverseSourceColor; };
|
||||
Blend_SrcAlpha -> SrcAlpha { return Blend.SourceAlpha; };
|
||||
Blend_InvSrcAlpha -> InvSrcAlpha { return Blend.InverseSourceAlpha; };
|
||||
Blend_DestAlpha -> DestAlpha { return Blend.DestinationAlpha; };
|
||||
Blend_InvDestAlpha -> InvDestAlpha { return Blend.InverseDestinationAlpha; };
|
||||
Blend_DestColor -> DestColor { return Blend.DestinationColor; };
|
||||
Blend_InvDestColor -> InvDestColor { return Blend.InverseDestinationColor; };
|
||||
Blend_SrcAlphaSat -> SrcAlphaSat { return Blend.SourceAlphaSaturation; };
|
||||
Blend_BlendFactor -> BlendFactor { return Blend.BlendFactor; };
|
||||
Blend_InvBlendFactor -> InvBlendFactor { return Blend.InverseBlendFactor; };
|
||||
Blends -> ( Blend_Zero|Blend_One|Blend_SrcColor|Blend_InvSrcColor|Blend_SrcAlpha|Blend_InvSrcAlpha|
|
||||
Blend_DestAlpha|Blend_InvDestAlpha|Blend_DestColor|Blend_InvDestColor|Blend_SrcAlphaSat|
|
||||
Blend_BlendFactor|Blend_InvBlendFactor)
|
||||
{
|
||||
return $Blend_Zero ?? $Blend_One ?? $Blend_SrcColor ?? $Blend_InvSrcColor ?? $Blend_SrcAlpha ?? $Blend_InvSrcAlpha ??
|
||||
$Blend_DestAlpha ?? $Blend_InvDestAlpha ?? $Blend_DestColor ?? $Blend_InvDestColor ?? $Blend_SrcAlphaSat ??
|
||||
$Blend_BlendFactor ?? $Blend_InvBlendFactor;
|
||||
};
|
||||
|
||||
BlendOp_Add -> Add { return BlendFunction.Add; };
|
||||
BlendOp_Subtract -> Subtract { return BlendFunction.Subtract; };
|
||||
BlendOp_RevSubtract -> RevSubtract { return BlendFunction.ReverseSubtract; };
|
||||
BlendOp_Min -> Min { return BlendFunction.Min; };
|
||||
BlendOp_Max -> Max { return BlendFunction.Max; };
|
||||
BlendOps -> (BlendOp_Add|BlendOp_Subtract|BlendOp_RevSubtract|BlendOp_Min|BlendOp_Max)
|
||||
{
|
||||
return $BlendOp_Add ?? $BlendOp_Subtract ?? $BlendOp_RevSubtract ?? $BlendOp_Min ?? $BlendOp_Max;
|
||||
};
|
||||
|
||||
CmpFunc_Never -> Never { return CompareFunction.Never; };
|
||||
CmpFunc_Less -> Less { return CompareFunction.Less; };
|
||||
CmpFunc_Equal -> Equal { return CompareFunction.Equal; };
|
||||
CmpFunc_LessEqual -> LessEqual { return CompareFunction.LessEqual; };
|
||||
CmpFunc_Greater -> Greater { return CompareFunction.Greater; };
|
||||
CmpFunc_NotEqual -> NotEqual { return CompareFunction.NotEqual; };
|
||||
CmpFunc_GreaterEqual -> GreaterEqual { return CompareFunction.GreaterEqual; };
|
||||
CmpFunc_Always -> Always { return CompareFunction.Always; };
|
||||
CmpFunc -> (CmpFunc_Never|CmpFunc_Less|CmpFunc_Equal|CmpFunc_LessEqual|CmpFunc_Greater|CmpFunc_NotEqual|CmpFunc_GreaterEqual|CmpFunc_Always)
|
||||
{
|
||||
return $CmpFunc_Never ?? $CmpFunc_Less ?? $CmpFunc_Equal ?? $CmpFunc_LessEqual ?? $CmpFunc_Greater ?? $CmpFunc_NotEqual ?? $CmpFunc_GreaterEqual ?? $CmpFunc_Always;
|
||||
};
|
||||
|
||||
StencilOp_Keep -> Keep { return StencilOperation.Keep; };
|
||||
StencilOp_Zero -> Zero { return StencilOperation.Zero; };
|
||||
StencilOp_Replace -> Replace { return StencilOperation.Replace; };
|
||||
StencilOp_IncrSat -> IncrSat { return StencilOperation.IncrementSaturation; };
|
||||
StencilOp_DecrSat -> DecrSat { return StencilOperation.DecrementSaturation; };
|
||||
StencilOp_Invert -> Invert { return StencilOperation.Invert; };
|
||||
StencilOp_Incr -> Incr { return StencilOperation.Increment; };
|
||||
StencilOp_Decr -> Decr { return StencilOperation.Decrement; };
|
||||
StencilOp -> (StencilOp_Keep|StencilOp_Zero|StencilOp_Replace|StencilOp_IncrSat|StencilOp_DecrSat|StencilOp_Invert|StencilOp_Incr|StencilOp_Decr)
|
||||
{
|
||||
return $StencilOp_Keep ?? $StencilOp_Zero ?? $StencilOp_Replace ?? $StencilOp_IncrSat ?? $StencilOp_DecrSat ?? $StencilOp_Invert ?? $StencilOp_Incr ?? $StencilOp_Decr;
|
||||
};
|
||||
|
||||
// Render states
|
||||
Render_State_CullMode -> CullMode Equals CullModes Semicolon { (paramlist[0] as PassInfo).CullMode = (CullMode)$CullModes; return null; };
|
||||
Render_State_FillMode -> FillMode Equals FillModes Semicolon { (paramlist[0] as PassInfo).FillMode = (FillMode)$FillModes; return null; };
|
||||
Render_State_AlphaBlendEnable -> AlphaBlendEnable Equals Boolean Semicolon { (paramlist[0] as PassInfo).AlphaBlendEnable = ParseTreeTools.ParseBool((string)$Boolean); return null; };
|
||||
Render_State_SrcBlend -> SrcBlend Equals Blends Semicolon { (paramlist[0] as PassInfo).SrcBlend = (Blend)$Blends; return null; };
|
||||
Render_State_DestBlend -> DestBlend Equals Blends Semicolon { (paramlist[0] as PassInfo).DestBlend = (Blend)$Blends; return null; };
|
||||
Render_State_BlendOp -> BlendOp Equals BlendOps Semicolon { (paramlist[0] as PassInfo).BlendOp = (BlendFunction)$BlendOps; return null; };
|
||||
Render_State_ColorWriteEnable -> ColorWriteEnable Equals ColorsMasks Semicolon { (paramlist[0] as PassInfo).ColorWriteEnable = (ColorWriteChannels)$ColorsMasks; return null; };
|
||||
Render_State_DepthBias -> DepthBias Equals Number Semicolon { (paramlist[0] as PassInfo).DepthBias = ParseTreeTools.ParseFloat((string)$Number); return null; };
|
||||
Render_State_SlopeScaleDepthBias -> SlopeScaleDepthBias Equals Number Semicolon { (paramlist[0] as PassInfo).SlopeScaleDepthBias = ParseTreeTools.ParseFloat((string)$Number); return null; };
|
||||
Render_State_ZEnable -> ZEnable Equals Boolean Semicolon { (paramlist[0] as PassInfo).ZEnable = ParseTreeTools.ParseBool((string)$Boolean); return null; };
|
||||
Render_State_ZWriteEnable -> ZWriteEnable Equals Boolean Semicolon { (paramlist[0] as PassInfo).ZWriteEnable = ParseTreeTools.ParseBool((string)$Boolean); return null; };
|
||||
Render_State_ZFunc -> ZFunc Equals CmpFunc Semicolon { (paramlist[0] as PassInfo).DepthBufferFunction = (CompareFunction)$CmpFunc; return null; };
|
||||
Render_State_MultiSampleAntiAlias -> MultiSampleAntiAlias Equals Boolean Semicolon { (paramlist[0] as PassInfo).MultiSampleAntiAlias = ParseTreeTools.ParseBool((string)$Boolean); return null; };
|
||||
Render_State_ScissorTestEnable -> ScissorTestEnable Equals Boolean Semicolon { (paramlist[0] as PassInfo).ScissorTestEnable = ParseTreeTools.ParseBool((string)$Boolean); return null; };
|
||||
Render_State_StencilEnable -> StencilEnable Equals Boolean Semicolon { (paramlist[0] as PassInfo).StencilEnable = ParseTreeTools.ParseBool((string)$Boolean); return null; };
|
||||
Render_State_StencilFail -> StencilFail Equals StencilOp Semicolon { (paramlist[0] as PassInfo).StencilFail = (StencilOperation)$StencilOp; return null; };
|
||||
Render_State_StencilFunc -> StencilFunc Equals CmpFunc Semicolon { (paramlist[0] as PassInfo).StencilFunc = (CompareFunction)$CmpFunc; return null; };
|
||||
Render_State_StencilMask -> StencilMask Equals Number Semicolon { (paramlist[0] as PassInfo).StencilMask = ParseTreeTools.ParseInt((string)$Number); return null; };
|
||||
Render_State_StencilPass -> StencilPass Equals StencilOp Semicolon { (paramlist[0] as PassInfo).StencilPass = (StencilOperation)$StencilOp; return null; };
|
||||
Render_State_StencilRef -> StencilRef Equals Number Semicolon { (paramlist[0] as PassInfo).StencilRef = ParseTreeTools.ParseInt((string)$Number); return null; };
|
||||
Render_State_StencilWriteMask -> StencilWriteMask Equals Number Semicolon { (paramlist[0] as PassInfo).StencilWriteMask = ParseTreeTools.ParseInt((string)$Number); return null; };
|
||||
Render_State_StencilZFail -> StencilZFail Equals StencilOp Semicolon { (paramlist[0] as PassInfo).StencilZFail = (StencilOperation)$StencilOp; return null; };
|
||||
|
||||
|
||||
Render_State_Expression ->
|
||||
Render_State_CullMode |
|
||||
Render_State_FillMode |
|
||||
Render_State_AlphaBlendEnable |
|
||||
Render_State_SrcBlend |
|
||||
Render_State_DestBlend |
|
||||
Render_State_BlendOp |
|
||||
Render_State_ColorWriteEnable |
|
||||
Render_State_DepthBias |
|
||||
Render_State_SlopeScaleDepthBias |
|
||||
Render_State_ZEnable |
|
||||
Render_State_ZWriteEnable |
|
||||
Render_State_ZFunc |
|
||||
Render_State_MultiSampleAntiAlias |
|
||||
Render_State_ScissorTestEnable |
|
||||
Render_State_StencilEnable |
|
||||
Render_State_StencilFail |
|
||||
Render_State_StencilFunc |
|
||||
Render_State_StencilMask |
|
||||
Render_State_StencilPass |
|
||||
Render_State_StencilRef |
|
||||
Render_State_StencilWriteMask |
|
||||
Render_State_StencilZFail;
|
||||
|
||||
Pass_Declaration -> Pass Identifier? OpenBracket (VertexShader_Pass_Expression | PixelShader_Pass_Expression | Render_State_Expression)* CloseBracket
|
||||
{
|
||||
var pass = new PassInfo();
|
||||
pass.name = $Identifier as string ?? string.Empty;
|
||||
|
||||
foreach (var node in Nodes)
|
||||
node.Eval(tree, pass);
|
||||
|
||||
// We need to have a pixel or vertex shader to keep this pass.
|
||||
if (!string.IsNullOrEmpty(pass.psFunction) || !string.IsNullOrEmpty(pass.vsFunction))
|
||||
{
|
||||
var technique = paramlist[0] as TechniqueInfo;
|
||||
technique.Passes.Add(pass);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
VertexShader_Pass_Expression -> VertexShader Equals Compile ShaderModel Identifier OpenParenthesis CloseParenthesis Semicolon
|
||||
{
|
||||
var pass = paramlist[0] as PassInfo;
|
||||
pass.vsModel = $ShaderModel as string;
|
||||
pass.vsFunction = $Identifier as string;
|
||||
return null;
|
||||
};
|
||||
|
||||
PixelShader_Pass_Expression -> PixelShader Equals Compile ShaderModel Identifier OpenParenthesis CloseParenthesis Semicolon
|
||||
{
|
||||
var pass = paramlist[0] as PassInfo;
|
||||
pass.psModel = $ShaderModel as string;
|
||||
pass.psFunction = $Identifier as string;
|
||||
return null;
|
||||
};
|
||||
|
||||
AddressMode_Clamp -> Clamp { return TextureAddressMode.Clamp; };
|
||||
AddressMode_Wrap -> Wrap { return TextureAddressMode.Wrap; };
|
||||
AddressMode_Mirror -> Mirror { return TextureAddressMode.Mirror; };
|
||||
AddressMode_Border -> Border { return TextureAddressMode.Border; };
|
||||
AddressMode -> (AddressMode_Clamp|AddressMode_Wrap|AddressMode_Mirror|AddressMode_Border)
|
||||
{
|
||||
return $AddressMode_Clamp ?? $AddressMode_Wrap ?? $AddressMode_Mirror ?? $AddressMode_Border;
|
||||
};
|
||||
|
||||
TextureFilter_None -> None { return TextureFilterType.None; };
|
||||
TextureFilter_Linear -> Linear { return TextureFilterType.Linear; };
|
||||
TextureFilter_Point -> Point { return TextureFilterType.Point; };
|
||||
TextureFilter_Anisotropic -> Anisotropic { return TextureFilterType.Anisotropic; };
|
||||
TextureFilter -> (TextureFilter_None|TextureFilter_Linear|TextureFilter_Point|TextureFilter_Anisotropic)
|
||||
{
|
||||
return $TextureFilter_None ?? $TextureFilter_Linear ?? $TextureFilter_Point ?? $TextureFilter_Anisotropic;
|
||||
};
|
||||
|
||||
// Sampler States
|
||||
Sampler_State_Texture -> Texture Equals (LessThan|OpenParenthesis) Identifier (GreaterThan|CloseParenthesis) Semicolon { (paramlist[0] as SamplerStateInfo).TextureName = (string)$Identifier; return null; };
|
||||
Sampler_State_MinFilter -> MinFilter Equals TextureFilter Semicolon { (paramlist[0] as SamplerStateInfo).MinFilter = (TextureFilterType)$TextureFilter; return null; };
|
||||
Sampler_State_MagFilter -> MagFilter Equals TextureFilter Semicolon { (paramlist[0] as SamplerStateInfo).MagFilter = (TextureFilterType)$TextureFilter; return null; };
|
||||
Sampler_State_MipFilter -> MipFilter Equals TextureFilter Semicolon { (paramlist[0] as SamplerStateInfo).MipFilter = (TextureFilterType)$TextureFilter; return null; };
|
||||
Sampler_State_Filter -> Filter Equals TextureFilter Semicolon { (paramlist[0] as SamplerStateInfo).Filter = (TextureFilterType)$TextureFilter; return null; };
|
||||
Sampler_State_AddressU -> AddressU Equals AddressMode Semicolon { (paramlist[0] as SamplerStateInfo).AddressU = (TextureAddressMode)$AddressMode; return null; };
|
||||
Sampler_State_AddressV -> AddressV Equals AddressMode Semicolon { (paramlist[0] as SamplerStateInfo).AddressV = (TextureAddressMode)$AddressMode; return null; };
|
||||
Sampler_State_AddressW -> AddressW Equals AddressMode Semicolon { (paramlist[0] as SamplerStateInfo).AddressW = (TextureAddressMode)$AddressMode; return null; };
|
||||
Sampler_State_BorderColor -> BorderColor Equals HexColor Semicolon { (paramlist[0] as SamplerStateInfo).BorderColor = ParseTreeTools.ParseColor((string)$HexColor); return null; };
|
||||
Sampler_State_MaxMipLevel -> MaxMipLevel Equals Number Semicolon { (paramlist[0] as SamplerStateInfo).MaxMipLevel = ParseTreeTools.ParseInt((string)$Number); return null; };
|
||||
Sampler_State_MaxAnisotropy -> MaxAnisotropy Equals Number Semicolon { (paramlist[0] as SamplerStateInfo).MaxAnisotropy = ParseTreeTools.ParseInt((string)$Number); return null; };
|
||||
Sampler_State_MipLodBias -> MipLodBias Equals Number Semicolon { (paramlist[0] as SamplerStateInfo).MipMapLevelOfDetailBias = ParseTreeTools.ParseFloat((string)$Number); return null; };
|
||||
|
||||
|
||||
Sampler_State_Expression ->
|
||||
Sampler_State_Texture |
|
||||
Sampler_State_MinFilter |
|
||||
Sampler_State_MagFilter |
|
||||
Sampler_State_MipFilter |
|
||||
Sampler_State_Filter |
|
||||
Sampler_State_AddressU |
|
||||
Sampler_State_AddressV |
|
||||
Sampler_State_AddressW |
|
||||
Sampler_State_BorderColor |
|
||||
Sampler_State_MaxMipLevel |
|
||||
Sampler_State_MaxAnisotropy |
|
||||
Sampler_State_MipLodBias;
|
||||
|
||||
Sampler_Register_Expression -> Colon Register OpenParenthesis Identifier (Comma Identifier (OpenSquareBracket Number CloseSquareBracket)?)? CloseParenthesis
|
||||
{
|
||||
return null;
|
||||
};
|
||||
|
||||
Sampler_Declaration_States -> (Equals SamplerState)? OpenBracket Sampler_State_Expression* CloseBracket;
|
||||
|
||||
Sampler_Declaration -> Sampler Identifier Sampler_Register_Expression* Sampler_Declaration_States? (Semicolon | Comma | CloseParenthesis)
|
||||
{
|
||||
// if there is a comma or closing paren at the end this is a sampler as a parameter of a function
|
||||
if ($Semicolon == null) return null;
|
||||
|
||||
var sampler = new SamplerStateInfo();
|
||||
sampler.Name = $Identifier[0] as string;
|
||||
|
||||
foreach (ParseNode node in Nodes)
|
||||
node.Eval(tree, sampler);
|
||||
|
||||
var shaderInfo = paramlist[0] as ShaderInfo;
|
||||
shaderInfo.SamplerStates.Add(sampler.Name, sampler);
|
||||
|
||||
return null;
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace TwoMGFX.TPGParser
|
||||
{
|
||||
public static class ParseTreeTools
|
||||
{
|
||||
public static float ParseFloat(string value)
|
||||
{
|
||||
// Remove all whitespace and trailing F or f.
|
||||
value = value.Replace(" ", "");
|
||||
value = value.TrimEnd('f', 'F');
|
||||
return float.Parse(value, NumberStyles.Float, CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
public static int ParseInt(string value)
|
||||
{
|
||||
// We read it as a float and cast it down to
|
||||
// an integer to match Microsoft FX behavior.
|
||||
return (int)Math.Floor(ParseFloat(value));
|
||||
}
|
||||
|
||||
public static bool ParseBool(string value)
|
||||
{
|
||||
if (value.ToLowerInvariant() == "true" || value == "1")
|
||||
return true;
|
||||
if (value.ToLowerInvariant() == "false" || value == "0")
|
||||
return false;
|
||||
|
||||
throw new Exception("Invalid boolean value '" + value + "'");
|
||||
}
|
||||
|
||||
public static Color ParseColor(string value)
|
||||
{
|
||||
var hexValue = Convert.ToUInt32(value, 16);
|
||||
|
||||
byte r, g, b, a;
|
||||
if (value.Length == 8)
|
||||
{
|
||||
r = (byte) ((hexValue >> 16) & 0xFF);
|
||||
g = (byte) ((hexValue >> 8) & 0xFF);
|
||||
b = (byte) ((hexValue >> 0) & 0xFF);
|
||||
a = 255;
|
||||
}
|
||||
else if (value.Length == 10)
|
||||
{
|
||||
r = (byte) ((hexValue >> 24) & 0xFF);
|
||||
g = (byte) ((hexValue >> 16) & 0xFF);
|
||||
b = (byte) ((hexValue >> 8) & 0xFF);
|
||||
a = (byte) ((hexValue >> 0) & 0xFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
return new Color(r, g, b, a);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,277 @@
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System.Globalization;
|
||||
|
||||
namespace TwoMGFX.TPGParser
|
||||
{
|
||||
public class PassInfo
|
||||
{
|
||||
public string name;
|
||||
|
||||
public string vsModel;
|
||||
public string vsFunction;
|
||||
|
||||
public string psModel;
|
||||
public string psFunction;
|
||||
|
||||
public BlendState blendState;
|
||||
public RasterizerState rasterizerState;
|
||||
public DepthStencilState depthStencilState;
|
||||
|
||||
private static Blend ToAlphaBlend(Blend blend)
|
||||
{
|
||||
switch (blend)
|
||||
{
|
||||
case Blend.SourceColor:
|
||||
return Blend.SourceAlpha;
|
||||
case Blend.InverseSourceColor:
|
||||
return Blend.InverseSourceAlpha;
|
||||
case Blend.DestinationColor:
|
||||
return Blend.DestinationAlpha;
|
||||
case Blend.InverseDestinationColor:
|
||||
return Blend.InverseDestinationAlpha;
|
||||
}
|
||||
return blend;
|
||||
}
|
||||
|
||||
public bool AlphaBlendEnable
|
||||
{
|
||||
set
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
if (blendState == null)
|
||||
{
|
||||
blendState = new BlendState();
|
||||
blendState.ColorSourceBlend = Blend.One;
|
||||
blendState.AlphaSourceBlend = Blend.One;
|
||||
blendState.ColorDestinationBlend = Blend.InverseSourceAlpha;
|
||||
blendState.AlphaDestinationBlend = Blend.InverseSourceAlpha;
|
||||
}
|
||||
}
|
||||
else if (!value)
|
||||
{
|
||||
if (blendState == null)
|
||||
blendState = new BlendState();
|
||||
blendState.ColorSourceBlend = Blend.One;
|
||||
blendState.AlphaSourceBlend = Blend.One;
|
||||
blendState.ColorDestinationBlend = Blend.Zero;
|
||||
blendState.AlphaDestinationBlend = Blend.Zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public FillMode FillMode
|
||||
{
|
||||
set
|
||||
{
|
||||
if (rasterizerState == null)
|
||||
rasterizerState = new RasterizerState();
|
||||
rasterizerState.FillMode = value;
|
||||
}
|
||||
}
|
||||
|
||||
public CullMode CullMode
|
||||
{
|
||||
set
|
||||
{
|
||||
if (rasterizerState == null)
|
||||
rasterizerState = new RasterizerState();
|
||||
rasterizerState.CullMode = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool ZEnable
|
||||
{
|
||||
set
|
||||
{
|
||||
if (depthStencilState == null)
|
||||
depthStencilState = new DepthStencilState();
|
||||
depthStencilState.DepthBufferEnable = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool ZWriteEnable
|
||||
{
|
||||
set
|
||||
{
|
||||
if (depthStencilState == null)
|
||||
depthStencilState = new DepthStencilState();
|
||||
depthStencilState.DepthBufferWriteEnable = value;
|
||||
}
|
||||
}
|
||||
|
||||
public CompareFunction DepthBufferFunction
|
||||
{
|
||||
set
|
||||
{
|
||||
if (depthStencilState == null)
|
||||
depthStencilState = new DepthStencilState();
|
||||
depthStencilState.DepthBufferFunction = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool MultiSampleAntiAlias
|
||||
{
|
||||
set
|
||||
{
|
||||
if (rasterizerState == null)
|
||||
rasterizerState = new RasterizerState();
|
||||
rasterizerState.MultiSampleAntiAlias = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool ScissorTestEnable
|
||||
{
|
||||
set
|
||||
{
|
||||
if (rasterizerState == null)
|
||||
rasterizerState = new RasterizerState();
|
||||
rasterizerState.ScissorTestEnable = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool StencilEnable
|
||||
{
|
||||
set
|
||||
{
|
||||
if (depthStencilState == null)
|
||||
depthStencilState = new DepthStencilState();
|
||||
depthStencilState.StencilEnable = value;
|
||||
}
|
||||
}
|
||||
|
||||
public StencilOperation StencilFail
|
||||
{
|
||||
set
|
||||
{
|
||||
if (depthStencilState == null)
|
||||
depthStencilState = new DepthStencilState();
|
||||
depthStencilState.StencilFail = value;
|
||||
}
|
||||
}
|
||||
|
||||
public CompareFunction StencilFunc
|
||||
{
|
||||
set
|
||||
{
|
||||
if (depthStencilState == null)
|
||||
depthStencilState = new DepthStencilState();
|
||||
depthStencilState.StencilFunction = value;
|
||||
}
|
||||
}
|
||||
|
||||
public int StencilMask
|
||||
{
|
||||
set
|
||||
{
|
||||
if (depthStencilState == null)
|
||||
depthStencilState = new DepthStencilState();
|
||||
depthStencilState.StencilMask = value;
|
||||
}
|
||||
}
|
||||
|
||||
public StencilOperation StencilPass
|
||||
{
|
||||
set
|
||||
{
|
||||
if (depthStencilState == null)
|
||||
depthStencilState = new DepthStencilState();
|
||||
depthStencilState.StencilPass = value;
|
||||
}
|
||||
}
|
||||
|
||||
public int StencilRef
|
||||
{
|
||||
set
|
||||
{
|
||||
if (depthStencilState == null)
|
||||
depthStencilState = new DepthStencilState();
|
||||
depthStencilState.ReferenceStencil = value;
|
||||
}
|
||||
}
|
||||
|
||||
public int StencilWriteMask
|
||||
{
|
||||
set
|
||||
{
|
||||
if (depthStencilState == null)
|
||||
depthStencilState = new DepthStencilState();
|
||||
depthStencilState.StencilWriteMask = value;
|
||||
}
|
||||
}
|
||||
|
||||
public StencilOperation StencilZFail
|
||||
{
|
||||
set
|
||||
{
|
||||
if (depthStencilState == null)
|
||||
depthStencilState = new DepthStencilState();
|
||||
depthStencilState.StencilDepthBufferFail = value;
|
||||
}
|
||||
}
|
||||
|
||||
public Blend SrcBlend
|
||||
{
|
||||
set
|
||||
{
|
||||
if (blendState == null)
|
||||
blendState = new BlendState();
|
||||
blendState.ColorSourceBlend = value;
|
||||
blendState.AlphaSourceBlend = ToAlphaBlend(value);
|
||||
}
|
||||
}
|
||||
|
||||
public Blend DestBlend
|
||||
{
|
||||
set
|
||||
{
|
||||
if (blendState == null)
|
||||
blendState = new BlendState();
|
||||
blendState.ColorDestinationBlend = value;
|
||||
blendState.AlphaDestinationBlend = ToAlphaBlend(value);
|
||||
}
|
||||
}
|
||||
|
||||
public BlendFunction BlendOp
|
||||
{
|
||||
set
|
||||
{
|
||||
if (blendState == null)
|
||||
blendState = new BlendState();
|
||||
blendState.AlphaBlendFunction = value;
|
||||
}
|
||||
}
|
||||
|
||||
public ColorWriteChannels ColorWriteEnable
|
||||
{
|
||||
set
|
||||
{
|
||||
if (blendState == null)
|
||||
blendState = new BlendState();
|
||||
blendState.ColorWriteChannels = value;
|
||||
}
|
||||
}
|
||||
|
||||
public float DepthBias
|
||||
{
|
||||
set
|
||||
{
|
||||
if (rasterizerState == null)
|
||||
rasterizerState = new RasterizerState();
|
||||
rasterizerState.DepthBias = value;
|
||||
}
|
||||
}
|
||||
|
||||
public float SlopeScaleDepthBias
|
||||
{
|
||||
set
|
||||
{
|
||||
if (rasterizerState == null)
|
||||
rasterizerState = new RasterizerState();
|
||||
rasterizerState.SlopeScaleDepthBias = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
using System;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace TwoMGFX.TPGParser
|
||||
{
|
||||
public class SamplerStateInfo
|
||||
{
|
||||
private SamplerState _state;
|
||||
|
||||
private bool _dirty;
|
||||
|
||||
private TextureFilterType _minFilter;
|
||||
private TextureFilterType _magFilter;
|
||||
private TextureFilterType _mipFilter;
|
||||
|
||||
private TextureAddressMode _addressU;
|
||||
private TextureAddressMode _addressV;
|
||||
private TextureAddressMode _addressW;
|
||||
|
||||
private Color _borderColor;
|
||||
|
||||
private int _maxAnisotropy;
|
||||
private int _maxMipLevel;
|
||||
private float _mipMapLevelOfDetailBias;
|
||||
|
||||
public SamplerStateInfo()
|
||||
{
|
||||
// NOTE: These match the defaults of SamplerState.
|
||||
_minFilter = TextureFilterType.Linear;
|
||||
_magFilter = TextureFilterType.Linear;
|
||||
_mipFilter = TextureFilterType.Linear;
|
||||
_addressU = TextureAddressMode.Wrap;
|
||||
_addressV = TextureAddressMode.Wrap;
|
||||
_addressW = TextureAddressMode.Wrap;
|
||||
_borderColor = Color.White;
|
||||
_maxAnisotropy = 4;
|
||||
_maxMipLevel = 0;
|
||||
_mipMapLevelOfDetailBias = 0.0f;
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public string TextureName { get; set; }
|
||||
|
||||
public TextureFilterType MinFilter
|
||||
{
|
||||
set
|
||||
{
|
||||
_minFilter = value;
|
||||
_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
public TextureFilterType MagFilter
|
||||
{
|
||||
set
|
||||
{
|
||||
_magFilter = value;
|
||||
_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
public TextureFilterType MipFilter
|
||||
{
|
||||
set
|
||||
{
|
||||
_mipFilter = value;
|
||||
_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
public TextureFilterType Filter
|
||||
{
|
||||
set
|
||||
{
|
||||
_minFilter = _magFilter = _mipFilter = value;
|
||||
_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
public TextureAddressMode AddressU
|
||||
{
|
||||
set
|
||||
{
|
||||
_addressU = value;
|
||||
_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
public TextureAddressMode AddressV
|
||||
{
|
||||
set
|
||||
{
|
||||
_addressV = value;
|
||||
_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
public TextureAddressMode AddressW
|
||||
{
|
||||
set
|
||||
{
|
||||
_addressW = value;
|
||||
_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
public Color BorderColor
|
||||
{
|
||||
set
|
||||
{
|
||||
_borderColor = value;
|
||||
_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
public int MaxAnisotropy
|
||||
{
|
||||
set
|
||||
{
|
||||
_maxAnisotropy = value;
|
||||
_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
public int MaxMipLevel
|
||||
{
|
||||
set
|
||||
{
|
||||
_maxMipLevel = value;
|
||||
_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
public float MipMapLevelOfDetailBias
|
||||
{
|
||||
set
|
||||
{
|
||||
_mipMapLevelOfDetailBias = value;
|
||||
_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateSamplerState()
|
||||
{
|
||||
// Get the existing state or create it.
|
||||
if (_state == null)
|
||||
_state = new SamplerState();
|
||||
|
||||
_state.AddressU = _addressU;
|
||||
_state.AddressV = _addressV;
|
||||
_state.AddressW = _addressW;
|
||||
|
||||
_state.BorderColor = _borderColor;
|
||||
|
||||
_state.MaxAnisotropy = _maxAnisotropy;
|
||||
_state.MaxMipLevel = _maxMipLevel;
|
||||
_state.MipMapLevelOfDetailBias = _mipMapLevelOfDetailBias;
|
||||
|
||||
// Figure out what kind of filter to set based on each
|
||||
// individual min, mag, and mip filter settings.
|
||||
//
|
||||
// NOTE: We're treating "None" and "Point" the same here
|
||||
// and disabling mipmapping further below.
|
||||
//
|
||||
if (_minFilter == TextureFilterType.Anisotropic)
|
||||
_state.Filter = TextureFilter.Anisotropic;
|
||||
else if (_minFilter == TextureFilterType.Linear && _magFilter == TextureFilterType.Linear && _mipFilter == TextureFilterType.Linear)
|
||||
_state.Filter = TextureFilter.Linear;
|
||||
else if (_minFilter == TextureFilterType.Linear && _magFilter == TextureFilterType.Linear && _mipFilter <= TextureFilterType.Point)
|
||||
_state.Filter = TextureFilter.LinearMipPoint;
|
||||
else if (_minFilter == TextureFilterType.Linear && _magFilter <= TextureFilterType.Point && _mipFilter == TextureFilterType.Linear)
|
||||
_state.Filter = TextureFilter.MinLinearMagPointMipLinear;
|
||||
else if (_minFilter == TextureFilterType.Linear && _magFilter <= TextureFilterType.Point && _mipFilter <= TextureFilterType.Point)
|
||||
_state.Filter = TextureFilter.MinLinearMagPointMipPoint;
|
||||
else if (_minFilter <= TextureFilterType.Point && _magFilter == TextureFilterType.Linear && _mipFilter == TextureFilterType.Linear)
|
||||
_state.Filter = TextureFilter.MinPointMagLinearMipLinear;
|
||||
else if (_minFilter <= TextureFilterType.Point && _magFilter == TextureFilterType.Linear && _mipFilter <= TextureFilterType.Point)
|
||||
_state.Filter = TextureFilter.MinPointMagLinearMipPoint;
|
||||
else if (_minFilter <= TextureFilterType.Point && _magFilter <= TextureFilterType.Point && _mipFilter <= TextureFilterType.Point)
|
||||
_state.Filter = TextureFilter.Point;
|
||||
else if (_minFilter <= TextureFilterType.Point && _magFilter <= TextureFilterType.Point && _mipFilter == TextureFilterType.Linear)
|
||||
_state.Filter = TextureFilter.PointMipLinear;
|
||||
|
||||
// Do we need to disable mipmapping?
|
||||
if (_mipFilter == TextureFilterType.None)
|
||||
{
|
||||
// TODO: This is the only option we have right now for
|
||||
// disabling mipmapping. We should add support for MinLod
|
||||
// and MaxLod which potentially does a better job at this.
|
||||
_state.MipMapLevelOfDetailBias = -16.0f;
|
||||
_state.MaxMipLevel = 0;
|
||||
}
|
||||
|
||||
_dirty = false;
|
||||
}
|
||||
|
||||
public SamplerState State
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_dirty)
|
||||
UpdateSamplerState();
|
||||
|
||||
return _state;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,986 @@
|
||||
// Generated by TinyPG v1.3 available at www.codeproject.com
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace TwoMGFX.TPGParser
|
||||
{
|
||||
#region Scanner
|
||||
|
||||
public partial class Scanner
|
||||
{
|
||||
public string Input;
|
||||
public int StartPos = 0;
|
||||
public int EndPos = 0;
|
||||
public string CurrentFile;
|
||||
public int CurrentLine;
|
||||
public int CurrentColumn;
|
||||
public int CurrentPosition;
|
||||
public List<Token> Skipped; // tokens that were skipped
|
||||
public Dictionary<TokenType, Regex> Patterns;
|
||||
|
||||
private Token LookAheadToken;
|
||||
private List<TokenType> Tokens;
|
||||
private List<TokenType> SkipList; // tokens to be skipped
|
||||
private readonly TokenType FileAndLine;
|
||||
|
||||
public Scanner()
|
||||
{
|
||||
Regex regex;
|
||||
Patterns = new Dictionary<TokenType, Regex>();
|
||||
Tokens = new List<TokenType>();
|
||||
LookAheadToken = null;
|
||||
Skipped = new List<Token>();
|
||||
|
||||
SkipList = new List<TokenType>();
|
||||
SkipList.Add(TokenType.BlockComment);
|
||||
SkipList.Add(TokenType.Comment);
|
||||
SkipList.Add(TokenType.Whitespace);
|
||||
SkipList.Add(TokenType.LinePragma);
|
||||
FileAndLine = TokenType.LinePragma;
|
||||
|
||||
regex = new Regex(@"/\*([^*]|\*[^/])*\*/", RegexOptions.Compiled);
|
||||
Patterns.Add(TokenType.BlockComment, regex);
|
||||
Tokens.Add(TokenType.BlockComment);
|
||||
|
||||
regex = new Regex(@"//[^\n\r]*", RegexOptions.Compiled);
|
||||
Patterns.Add(TokenType.Comment, regex);
|
||||
Tokens.Add(TokenType.Comment);
|
||||
|
||||
regex = new Regex(@"[ \t\n\r]+", RegexOptions.Compiled);
|
||||
Patterns.Add(TokenType.Whitespace, regex);
|
||||
Tokens.Add(TokenType.Whitespace);
|
||||
|
||||
regex = new Regex(@"^[ \t]*#line[ \t]*(?<Line>\d*)[ \t]*(\""(?<File>[^\""\\]*(?:\\.[^\""\\]*)*)\"")?\n", RegexOptions.Compiled);
|
||||
Patterns.Add(TokenType.LinePragma, regex);
|
||||
Tokens.Add(TokenType.LinePragma);
|
||||
|
||||
regex = new Regex(@"pass", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.Pass, regex);
|
||||
Tokens.Add(TokenType.Pass);
|
||||
|
||||
regex = new Regex(@"technique", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.Technique, regex);
|
||||
Tokens.Add(TokenType.Technique);
|
||||
|
||||
regex = new Regex(@"sampler1D|sampler2D|sampler3D|samplerCUBE|SamplerState|sampler", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.Sampler, regex);
|
||||
Tokens.Add(TokenType.Sampler);
|
||||
|
||||
regex = new Regex(@"sampler_state", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.SamplerState, regex);
|
||||
Tokens.Add(TokenType.SamplerState);
|
||||
|
||||
regex = new Regex(@"VertexShader", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.VertexShader, regex);
|
||||
Tokens.Add(TokenType.VertexShader);
|
||||
|
||||
regex = new Regex(@"PixelShader", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.PixelShader, regex);
|
||||
Tokens.Add(TokenType.PixelShader);
|
||||
|
||||
regex = new Regex(@"register", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.Register, regex);
|
||||
Tokens.Add(TokenType.Register);
|
||||
|
||||
regex = new Regex(@"true|false|0|1", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.Boolean, regex);
|
||||
Tokens.Add(TokenType.Boolean);
|
||||
|
||||
regex = new Regex(@"[+-]? ?[0-9]?\.?[0-9]+[fF]?", RegexOptions.Compiled);
|
||||
Patterns.Add(TokenType.Number, regex);
|
||||
Tokens.Add(TokenType.Number);
|
||||
|
||||
regex = new Regex(@"0x[0-9a-f]{6}([0-9a-f][0-9a-f])?", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.HexColor, regex);
|
||||
Tokens.Add(TokenType.HexColor);
|
||||
|
||||
regex = new Regex(@"[A-Za-z_][A-Za-z0-9_]*", RegexOptions.Compiled);
|
||||
Patterns.Add(TokenType.Identifier, regex);
|
||||
Tokens.Add(TokenType.Identifier);
|
||||
|
||||
regex = new Regex(@"{", RegexOptions.Compiled);
|
||||
Patterns.Add(TokenType.OpenBracket, regex);
|
||||
Tokens.Add(TokenType.OpenBracket);
|
||||
|
||||
regex = new Regex(@"}", RegexOptions.Compiled);
|
||||
Patterns.Add(TokenType.CloseBracket, regex);
|
||||
Tokens.Add(TokenType.CloseBracket);
|
||||
|
||||
regex = new Regex(@"=", RegexOptions.Compiled);
|
||||
Patterns.Add(TokenType.Equals, regex);
|
||||
Tokens.Add(TokenType.Equals);
|
||||
|
||||
regex = new Regex(@":", RegexOptions.Compiled);
|
||||
Patterns.Add(TokenType.Colon, regex);
|
||||
Tokens.Add(TokenType.Colon);
|
||||
|
||||
regex = new Regex(@",", RegexOptions.Compiled);
|
||||
Patterns.Add(TokenType.Comma, regex);
|
||||
Tokens.Add(TokenType.Comma);
|
||||
|
||||
regex = new Regex(@";", RegexOptions.Compiled);
|
||||
Patterns.Add(TokenType.Semicolon, regex);
|
||||
Tokens.Add(TokenType.Semicolon);
|
||||
|
||||
regex = new Regex(@"\|", RegexOptions.Compiled);
|
||||
Patterns.Add(TokenType.Or, regex);
|
||||
Tokens.Add(TokenType.Or);
|
||||
|
||||
regex = new Regex(@"\(", RegexOptions.Compiled);
|
||||
Patterns.Add(TokenType.OpenParenthesis, regex);
|
||||
Tokens.Add(TokenType.OpenParenthesis);
|
||||
|
||||
regex = new Regex(@"\)", RegexOptions.Compiled);
|
||||
Patterns.Add(TokenType.CloseParenthesis, regex);
|
||||
Tokens.Add(TokenType.CloseParenthesis);
|
||||
|
||||
regex = new Regex(@"\[", RegexOptions.Compiled);
|
||||
Patterns.Add(TokenType.OpenSquareBracket, regex);
|
||||
Tokens.Add(TokenType.OpenSquareBracket);
|
||||
|
||||
regex = new Regex(@"\]", RegexOptions.Compiled);
|
||||
Patterns.Add(TokenType.CloseSquareBracket, regex);
|
||||
Tokens.Add(TokenType.CloseSquareBracket);
|
||||
|
||||
regex = new Regex(@"<", RegexOptions.Compiled);
|
||||
Patterns.Add(TokenType.LessThan, regex);
|
||||
Tokens.Add(TokenType.LessThan);
|
||||
|
||||
regex = new Regex(@">", RegexOptions.Compiled);
|
||||
Patterns.Add(TokenType.GreaterThan, regex);
|
||||
Tokens.Add(TokenType.GreaterThan);
|
||||
|
||||
regex = new Regex(@"compile", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.Compile, regex);
|
||||
Tokens.Add(TokenType.Compile);
|
||||
|
||||
regex = new Regex(@"[A-Za-z_][A-Za-z0-9_]*", RegexOptions.Compiled);
|
||||
Patterns.Add(TokenType.ShaderModel, regex);
|
||||
Tokens.Add(TokenType.ShaderModel);
|
||||
|
||||
regex = new Regex(@"[\S]+", RegexOptions.Compiled);
|
||||
Patterns.Add(TokenType.Code, regex);
|
||||
Tokens.Add(TokenType.Code);
|
||||
|
||||
regex = new Regex(@"^$", RegexOptions.Compiled);
|
||||
Patterns.Add(TokenType.EndOfFile, regex);
|
||||
Tokens.Add(TokenType.EndOfFile);
|
||||
|
||||
regex = new Regex(@"MinFilter", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.MinFilter, regex);
|
||||
Tokens.Add(TokenType.MinFilter);
|
||||
|
||||
regex = new Regex(@"MagFilter", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.MagFilter, regex);
|
||||
Tokens.Add(TokenType.MagFilter);
|
||||
|
||||
regex = new Regex(@"MipFilter", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.MipFilter, regex);
|
||||
Tokens.Add(TokenType.MipFilter);
|
||||
|
||||
regex = new Regex(@"Filter", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.Filter, regex);
|
||||
Tokens.Add(TokenType.Filter);
|
||||
|
||||
regex = new Regex(@"Texture", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.Texture, regex);
|
||||
Tokens.Add(TokenType.Texture);
|
||||
|
||||
regex = new Regex(@"AddressU", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.AddressU, regex);
|
||||
Tokens.Add(TokenType.AddressU);
|
||||
|
||||
regex = new Regex(@"AddressV", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.AddressV, regex);
|
||||
Tokens.Add(TokenType.AddressV);
|
||||
|
||||
regex = new Regex(@"AddressW", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.AddressW, regex);
|
||||
Tokens.Add(TokenType.AddressW);
|
||||
|
||||
regex = new Regex(@"BorderColor", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.BorderColor, regex);
|
||||
Tokens.Add(TokenType.BorderColor);
|
||||
|
||||
regex = new Regex(@"MaxAnisotropy", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.MaxAnisotropy, regex);
|
||||
Tokens.Add(TokenType.MaxAnisotropy);
|
||||
|
||||
regex = new Regex(@"MaxMipLevel|MaxLod", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.MaxMipLevel, regex);
|
||||
Tokens.Add(TokenType.MaxMipLevel);
|
||||
|
||||
regex = new Regex(@"MipLodBias", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.MipLodBias, regex);
|
||||
Tokens.Add(TokenType.MipLodBias);
|
||||
|
||||
regex = new Regex(@"Clamp", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.Clamp, regex);
|
||||
Tokens.Add(TokenType.Clamp);
|
||||
|
||||
regex = new Regex(@"Wrap", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.Wrap, regex);
|
||||
Tokens.Add(TokenType.Wrap);
|
||||
|
||||
regex = new Regex(@"Mirror", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.Mirror, regex);
|
||||
Tokens.Add(TokenType.Mirror);
|
||||
|
||||
regex = new Regex(@"Border", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.Border, regex);
|
||||
Tokens.Add(TokenType.Border);
|
||||
|
||||
regex = new Regex(@"None", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.None, regex);
|
||||
Tokens.Add(TokenType.None);
|
||||
|
||||
regex = new Regex(@"Linear", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.Linear, regex);
|
||||
Tokens.Add(TokenType.Linear);
|
||||
|
||||
regex = new Regex(@"Point", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.Point, regex);
|
||||
Tokens.Add(TokenType.Point);
|
||||
|
||||
regex = new Regex(@"Anisotropic", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.Anisotropic, regex);
|
||||
Tokens.Add(TokenType.Anisotropic);
|
||||
|
||||
regex = new Regex(@"AlphaBlendEnable", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.AlphaBlendEnable, regex);
|
||||
Tokens.Add(TokenType.AlphaBlendEnable);
|
||||
|
||||
regex = new Regex(@"SrcBlend", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.SrcBlend, regex);
|
||||
Tokens.Add(TokenType.SrcBlend);
|
||||
|
||||
regex = new Regex(@"DestBlend", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.DestBlend, regex);
|
||||
Tokens.Add(TokenType.DestBlend);
|
||||
|
||||
regex = new Regex(@"BlendOp", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.BlendOp, regex);
|
||||
Tokens.Add(TokenType.BlendOp);
|
||||
|
||||
regex = new Regex(@"ColorWriteEnable", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.ColorWriteEnable, regex);
|
||||
Tokens.Add(TokenType.ColorWriteEnable);
|
||||
|
||||
regex = new Regex(@"ZEnable", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.ZEnable, regex);
|
||||
Tokens.Add(TokenType.ZEnable);
|
||||
|
||||
regex = new Regex(@"ZWriteEnable", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.ZWriteEnable, regex);
|
||||
Tokens.Add(TokenType.ZWriteEnable);
|
||||
|
||||
regex = new Regex(@"ZFunc", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.ZFunc, regex);
|
||||
Tokens.Add(TokenType.ZFunc);
|
||||
|
||||
regex = new Regex(@"DepthBias", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.DepthBias, regex);
|
||||
Tokens.Add(TokenType.DepthBias);
|
||||
|
||||
regex = new Regex(@"CullMode", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.CullMode, regex);
|
||||
Tokens.Add(TokenType.CullMode);
|
||||
|
||||
regex = new Regex(@"FillMode", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.FillMode, regex);
|
||||
Tokens.Add(TokenType.FillMode);
|
||||
|
||||
regex = new Regex(@"MultiSampleAntiAlias", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.MultiSampleAntiAlias, regex);
|
||||
Tokens.Add(TokenType.MultiSampleAntiAlias);
|
||||
|
||||
regex = new Regex(@"ScissorTestEnable", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.ScissorTestEnable, regex);
|
||||
Tokens.Add(TokenType.ScissorTestEnable);
|
||||
|
||||
regex = new Regex(@"SlopeScaleDepthBias", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.SlopeScaleDepthBias, regex);
|
||||
Tokens.Add(TokenType.SlopeScaleDepthBias);
|
||||
|
||||
regex = new Regex(@"StencilEnable", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.StencilEnable, regex);
|
||||
Tokens.Add(TokenType.StencilEnable);
|
||||
|
||||
regex = new Regex(@"StencilFail", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.StencilFail, regex);
|
||||
Tokens.Add(TokenType.StencilFail);
|
||||
|
||||
regex = new Regex(@"StencilFunc", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.StencilFunc, regex);
|
||||
Tokens.Add(TokenType.StencilFunc);
|
||||
|
||||
regex = new Regex(@"StencilMask", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.StencilMask, regex);
|
||||
Tokens.Add(TokenType.StencilMask);
|
||||
|
||||
regex = new Regex(@"StencilPass", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.StencilPass, regex);
|
||||
Tokens.Add(TokenType.StencilPass);
|
||||
|
||||
regex = new Regex(@"StencilRef", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.StencilRef, regex);
|
||||
Tokens.Add(TokenType.StencilRef);
|
||||
|
||||
regex = new Regex(@"StencilWriteMask", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.StencilWriteMask, regex);
|
||||
Tokens.Add(TokenType.StencilWriteMask);
|
||||
|
||||
regex = new Regex(@"StencilZFail", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.StencilZFail, regex);
|
||||
Tokens.Add(TokenType.StencilZFail);
|
||||
|
||||
regex = new Regex(@"Never", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.Never, regex);
|
||||
Tokens.Add(TokenType.Never);
|
||||
|
||||
regex = new Regex(@"Less", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.Less, regex);
|
||||
Tokens.Add(TokenType.Less);
|
||||
|
||||
regex = new Regex(@"Equal", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.Equal, regex);
|
||||
Tokens.Add(TokenType.Equal);
|
||||
|
||||
regex = new Regex(@"LessEqual", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.LessEqual, regex);
|
||||
Tokens.Add(TokenType.LessEqual);
|
||||
|
||||
regex = new Regex(@"Greater", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.Greater, regex);
|
||||
Tokens.Add(TokenType.Greater);
|
||||
|
||||
regex = new Regex(@"NotEqual", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.NotEqual, regex);
|
||||
Tokens.Add(TokenType.NotEqual);
|
||||
|
||||
regex = new Regex(@"GreaterEqual", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.GreaterEqual, regex);
|
||||
Tokens.Add(TokenType.GreaterEqual);
|
||||
|
||||
regex = new Regex(@"Always", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.Always, regex);
|
||||
Tokens.Add(TokenType.Always);
|
||||
|
||||
regex = new Regex(@"Keep", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.Keep, regex);
|
||||
Tokens.Add(TokenType.Keep);
|
||||
|
||||
regex = new Regex(@"Zero", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.Zero, regex);
|
||||
Tokens.Add(TokenType.Zero);
|
||||
|
||||
regex = new Regex(@"Replace", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.Replace, regex);
|
||||
Tokens.Add(TokenType.Replace);
|
||||
|
||||
regex = new Regex(@"IncrSat", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.IncrSat, regex);
|
||||
Tokens.Add(TokenType.IncrSat);
|
||||
|
||||
regex = new Regex(@"DecrSat", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.DecrSat, regex);
|
||||
Tokens.Add(TokenType.DecrSat);
|
||||
|
||||
regex = new Regex(@"Invert", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.Invert, regex);
|
||||
Tokens.Add(TokenType.Invert);
|
||||
|
||||
regex = new Regex(@"Incr", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.Incr, regex);
|
||||
Tokens.Add(TokenType.Incr);
|
||||
|
||||
regex = new Regex(@"Decr", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.Decr, regex);
|
||||
Tokens.Add(TokenType.Decr);
|
||||
|
||||
regex = new Regex(@"Red", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.Red, regex);
|
||||
Tokens.Add(TokenType.Red);
|
||||
|
||||
regex = new Regex(@"Green", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.Green, regex);
|
||||
Tokens.Add(TokenType.Green);
|
||||
|
||||
regex = new Regex(@"Blue", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.Blue, regex);
|
||||
Tokens.Add(TokenType.Blue);
|
||||
|
||||
regex = new Regex(@"Alpha", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.Alpha, regex);
|
||||
Tokens.Add(TokenType.Alpha);
|
||||
|
||||
regex = new Regex(@"All", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.All, regex);
|
||||
Tokens.Add(TokenType.All);
|
||||
|
||||
regex = new Regex(@"Cw", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.Cw, regex);
|
||||
Tokens.Add(TokenType.Cw);
|
||||
|
||||
regex = new Regex(@"Ccw", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.Ccw, regex);
|
||||
Tokens.Add(TokenType.Ccw);
|
||||
|
||||
regex = new Regex(@"Solid", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.Solid, regex);
|
||||
Tokens.Add(TokenType.Solid);
|
||||
|
||||
regex = new Regex(@"WireFrame", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.WireFrame, regex);
|
||||
Tokens.Add(TokenType.WireFrame);
|
||||
|
||||
regex = new Regex(@"Add", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.Add, regex);
|
||||
Tokens.Add(TokenType.Add);
|
||||
|
||||
regex = new Regex(@"Subtract", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.Subtract, regex);
|
||||
Tokens.Add(TokenType.Subtract);
|
||||
|
||||
regex = new Regex(@"RevSubtract", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.RevSubtract, regex);
|
||||
Tokens.Add(TokenType.RevSubtract);
|
||||
|
||||
regex = new Regex(@"Min", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.Min, regex);
|
||||
Tokens.Add(TokenType.Min);
|
||||
|
||||
regex = new Regex(@"Max", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.Max, regex);
|
||||
Tokens.Add(TokenType.Max);
|
||||
|
||||
regex = new Regex(@"One", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.One, regex);
|
||||
Tokens.Add(TokenType.One);
|
||||
|
||||
regex = new Regex(@"SrcColor", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.SrcColor, regex);
|
||||
Tokens.Add(TokenType.SrcColor);
|
||||
|
||||
regex = new Regex(@"InvSrcColor", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.InvSrcColor, regex);
|
||||
Tokens.Add(TokenType.InvSrcColor);
|
||||
|
||||
regex = new Regex(@"SrcAlpha", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.SrcAlpha, regex);
|
||||
Tokens.Add(TokenType.SrcAlpha);
|
||||
|
||||
regex = new Regex(@"InvSrcAlpha", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.InvSrcAlpha, regex);
|
||||
Tokens.Add(TokenType.InvSrcAlpha);
|
||||
|
||||
regex = new Regex(@"DestAlpha", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.DestAlpha, regex);
|
||||
Tokens.Add(TokenType.DestAlpha);
|
||||
|
||||
regex = new Regex(@"InvDestAlpha", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.InvDestAlpha, regex);
|
||||
Tokens.Add(TokenType.InvDestAlpha);
|
||||
|
||||
regex = new Regex(@"DestColor", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.DestColor, regex);
|
||||
Tokens.Add(TokenType.DestColor);
|
||||
|
||||
regex = new Regex(@"InvDestColor", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.InvDestColor, regex);
|
||||
Tokens.Add(TokenType.InvDestColor);
|
||||
|
||||
regex = new Regex(@"SrcAlphaSat", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.SrcAlphaSat, regex);
|
||||
Tokens.Add(TokenType.SrcAlphaSat);
|
||||
|
||||
regex = new Regex(@"BlendFactor", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.BlendFactor, regex);
|
||||
Tokens.Add(TokenType.BlendFactor);
|
||||
|
||||
regex = new Regex(@"InvBlendFactor", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Patterns.Add(TokenType.InvBlendFactor, regex);
|
||||
Tokens.Add(TokenType.InvBlendFactor);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void Init(string input)
|
||||
{
|
||||
Init(input, "");
|
||||
}
|
||||
|
||||
public void Init(string input, string fileName)
|
||||
{
|
||||
this.Input = input;
|
||||
StartPos = 0;
|
||||
EndPos = 0;
|
||||
CurrentFile = fileName;
|
||||
CurrentLine = 1;
|
||||
CurrentColumn = 1;
|
||||
CurrentPosition = 0;
|
||||
LookAheadToken = null;
|
||||
}
|
||||
|
||||
public Token GetToken(TokenType type)
|
||||
{
|
||||
Token t = new Token(this.StartPos, this.EndPos);
|
||||
t.Type = type;
|
||||
return t;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// executes a lookahead of the next token
|
||||
/// and will advance the scan on the input string
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Token Scan(params TokenType[] expectedtokens)
|
||||
{
|
||||
Token tok = LookAhead(expectedtokens); // temporarely retrieve the lookahead
|
||||
LookAheadToken = null; // reset lookahead token, so scanning will continue
|
||||
StartPos = tok.EndPos;
|
||||
EndPos = tok.EndPos; // set the tokenizer to the new scan position
|
||||
CurrentLine = tok.Line + (tok.Text.Length - tok.Text.Replace("\n", "").Length);
|
||||
CurrentFile = tok.File;
|
||||
return tok;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// returns token with longest best match
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Token LookAhead(params TokenType[] expectedtokens)
|
||||
{
|
||||
int i;
|
||||
int startpos = StartPos;
|
||||
int endpos = EndPos;
|
||||
int currentline = CurrentLine;
|
||||
string currentFile = CurrentFile;
|
||||
Token tok = null;
|
||||
List<TokenType> scantokens;
|
||||
|
||||
|
||||
// this prevents double scanning and matching
|
||||
// increased performance
|
||||
if (LookAheadToken != null
|
||||
&& LookAheadToken.Type != TokenType._UNDETERMINED_
|
||||
&& LookAheadToken.Type != TokenType._NONE_) return LookAheadToken;
|
||||
|
||||
// if no scantokens specified, then scan for all of them (= backward compatible)
|
||||
if (expectedtokens.Length == 0)
|
||||
scantokens = Tokens;
|
||||
else
|
||||
{
|
||||
scantokens = new List<TokenType>(expectedtokens);
|
||||
scantokens.AddRange(SkipList);
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
|
||||
int len = -1;
|
||||
TokenType index = (TokenType)int.MaxValue;
|
||||
string input = Input.Substring(startpos);
|
||||
|
||||
tok = new Token(startpos, endpos);
|
||||
|
||||
for (i = 0; i < scantokens.Count; i++)
|
||||
{
|
||||
Regex r = Patterns[scantokens[i]];
|
||||
Match m = r.Match(input);
|
||||
if (m.Success && m.Index == 0 && ((m.Length > len) || (scantokens[i] < index && m.Length == len )))
|
||||
{
|
||||
len = m.Length;
|
||||
index = scantokens[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (index >= 0 && len >= 0)
|
||||
{
|
||||
tok.EndPos = startpos + len;
|
||||
tok.Text = Input.Substring(tok.StartPos, len);
|
||||
tok.Type = index;
|
||||
}
|
||||
else if (tok.StartPos == tok.EndPos)
|
||||
{
|
||||
if (tok.StartPos < Input.Length)
|
||||
tok.Text = Input.Substring(tok.StartPos, 1);
|
||||
else
|
||||
tok.Text = "EOF";
|
||||
}
|
||||
|
||||
// Update the line and column count for error reporting.
|
||||
tok.File = currentFile;
|
||||
tok.Line = currentline;
|
||||
if (tok.StartPos < Input.Length)
|
||||
tok.Column = tok.StartPos - Input.LastIndexOf('\n', tok.StartPos);
|
||||
|
||||
if (SkipList.Contains(tok.Type))
|
||||
{
|
||||
startpos = tok.EndPos;
|
||||
endpos = tok.EndPos;
|
||||
currentline = tok.Line + (tok.Text.Length - tok.Text.Replace("\n", "").Length);
|
||||
currentFile = tok.File;
|
||||
Skipped.Add(tok);
|
||||
}
|
||||
else
|
||||
{
|
||||
// only assign to non-skipped tokens
|
||||
tok.Skipped = Skipped; // assign prior skips to this token
|
||||
Skipped = new List<Token>(); //reset skips
|
||||
}
|
||||
|
||||
// Check to see if the parsed token wants to
|
||||
// alter the file and line number.
|
||||
if (tok.Type == FileAndLine)
|
||||
{
|
||||
var match = Patterns[tok.Type].Match(tok.Text);
|
||||
var fileMatch = match.Groups["File"];
|
||||
if (fileMatch.Success)
|
||||
currentFile = fileMatch.Value.Replace("\\\\", "\\");
|
||||
var lineMatch = match.Groups["Line"];
|
||||
if (lineMatch.Success)
|
||||
currentline = int.Parse(lineMatch.Value, NumberStyles.Integer, CultureInfo.InvariantCulture);
|
||||
}
|
||||
}
|
||||
while (SkipList.Contains(tok.Type));
|
||||
|
||||
LookAheadToken = tok;
|
||||
return tok;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Token
|
||||
|
||||
public enum TokenType
|
||||
{
|
||||
|
||||
//Non terminal tokens:
|
||||
_NONE_ = 0,
|
||||
_UNDETERMINED_= 1,
|
||||
|
||||
//Non terminal tokens:
|
||||
Start = 2,
|
||||
Technique_Declaration= 3,
|
||||
FillMode_Solid= 4,
|
||||
FillMode_WireFrame= 5,
|
||||
FillModes= 6,
|
||||
CullMode_None= 7,
|
||||
CullMode_Cw= 8,
|
||||
CullMode_Ccw= 9,
|
||||
CullModes= 10,
|
||||
Colors_None= 11,
|
||||
Colors_Red= 12,
|
||||
Colors_Green= 13,
|
||||
Colors_Blue= 14,
|
||||
Colors_Alpha= 15,
|
||||
Colors_All= 16,
|
||||
Colors_Boolean= 17,
|
||||
Colors = 18,
|
||||
ColorsMasks= 19,
|
||||
Blend_Zero= 20,
|
||||
Blend_One= 21,
|
||||
Blend_SrcColor= 22,
|
||||
Blend_InvSrcColor= 23,
|
||||
Blend_SrcAlpha= 24,
|
||||
Blend_InvSrcAlpha= 25,
|
||||
Blend_DestAlpha= 26,
|
||||
Blend_InvDestAlpha= 27,
|
||||
Blend_DestColor= 28,
|
||||
Blend_InvDestColor= 29,
|
||||
Blend_SrcAlphaSat= 30,
|
||||
Blend_BlendFactor= 31,
|
||||
Blend_InvBlendFactor= 32,
|
||||
Blends = 33,
|
||||
BlendOp_Add= 34,
|
||||
BlendOp_Subtract= 35,
|
||||
BlendOp_RevSubtract= 36,
|
||||
BlendOp_Min= 37,
|
||||
BlendOp_Max= 38,
|
||||
BlendOps= 39,
|
||||
CmpFunc_Never= 40,
|
||||
CmpFunc_Less= 41,
|
||||
CmpFunc_Equal= 42,
|
||||
CmpFunc_LessEqual= 43,
|
||||
CmpFunc_Greater= 44,
|
||||
CmpFunc_NotEqual= 45,
|
||||
CmpFunc_GreaterEqual= 46,
|
||||
CmpFunc_Always= 47,
|
||||
CmpFunc = 48,
|
||||
StencilOp_Keep= 49,
|
||||
StencilOp_Zero= 50,
|
||||
StencilOp_Replace= 51,
|
||||
StencilOp_IncrSat= 52,
|
||||
StencilOp_DecrSat= 53,
|
||||
StencilOp_Invert= 54,
|
||||
StencilOp_Incr= 55,
|
||||
StencilOp_Decr= 56,
|
||||
StencilOp= 57,
|
||||
Render_State_CullMode= 58,
|
||||
Render_State_FillMode= 59,
|
||||
Render_State_AlphaBlendEnable= 60,
|
||||
Render_State_SrcBlend= 61,
|
||||
Render_State_DestBlend= 62,
|
||||
Render_State_BlendOp= 63,
|
||||
Render_State_ColorWriteEnable= 64,
|
||||
Render_State_DepthBias= 65,
|
||||
Render_State_SlopeScaleDepthBias= 66,
|
||||
Render_State_ZEnable= 67,
|
||||
Render_State_ZWriteEnable= 68,
|
||||
Render_State_ZFunc= 69,
|
||||
Render_State_MultiSampleAntiAlias= 70,
|
||||
Render_State_ScissorTestEnable= 71,
|
||||
Render_State_StencilEnable= 72,
|
||||
Render_State_StencilFail= 73,
|
||||
Render_State_StencilFunc= 74,
|
||||
Render_State_StencilMask= 75,
|
||||
Render_State_StencilPass= 76,
|
||||
Render_State_StencilRef= 77,
|
||||
Render_State_StencilWriteMask= 78,
|
||||
Render_State_StencilZFail= 79,
|
||||
Render_State_Expression= 80,
|
||||
Pass_Declaration= 81,
|
||||
VertexShader_Pass_Expression= 82,
|
||||
PixelShader_Pass_Expression= 83,
|
||||
AddressMode_Clamp= 84,
|
||||
AddressMode_Wrap= 85,
|
||||
AddressMode_Mirror= 86,
|
||||
AddressMode_Border= 87,
|
||||
AddressMode= 88,
|
||||
TextureFilter_None= 89,
|
||||
TextureFilter_Linear= 90,
|
||||
TextureFilter_Point= 91,
|
||||
TextureFilter_Anisotropic= 92,
|
||||
TextureFilter= 93,
|
||||
Sampler_State_Texture= 94,
|
||||
Sampler_State_MinFilter= 95,
|
||||
Sampler_State_MagFilter= 96,
|
||||
Sampler_State_MipFilter= 97,
|
||||
Sampler_State_Filter= 98,
|
||||
Sampler_State_AddressU= 99,
|
||||
Sampler_State_AddressV= 100,
|
||||
Sampler_State_AddressW= 101,
|
||||
Sampler_State_BorderColor= 102,
|
||||
Sampler_State_MaxMipLevel= 103,
|
||||
Sampler_State_MaxAnisotropy= 104,
|
||||
Sampler_State_MipLodBias= 105,
|
||||
Sampler_State_Expression= 106,
|
||||
Sampler_Register_Expression= 107,
|
||||
Sampler_Declaration_States= 108,
|
||||
Sampler_Declaration= 109,
|
||||
|
||||
//Terminal tokens:
|
||||
BlockComment= 110,
|
||||
Comment = 111,
|
||||
Whitespace= 112,
|
||||
LinePragma= 113,
|
||||
Pass = 114,
|
||||
Technique= 115,
|
||||
Sampler = 116,
|
||||
SamplerState= 117,
|
||||
VertexShader= 118,
|
||||
PixelShader= 119,
|
||||
Register= 120,
|
||||
Boolean = 121,
|
||||
Number = 122,
|
||||
HexColor= 123,
|
||||
Identifier= 124,
|
||||
OpenBracket= 125,
|
||||
CloseBracket= 126,
|
||||
Equals = 127,
|
||||
Colon = 128,
|
||||
Comma = 129,
|
||||
Semicolon= 130,
|
||||
Or = 131,
|
||||
OpenParenthesis= 132,
|
||||
CloseParenthesis= 133,
|
||||
OpenSquareBracket= 134,
|
||||
CloseSquareBracket= 135,
|
||||
LessThan= 136,
|
||||
GreaterThan= 137,
|
||||
Compile = 138,
|
||||
ShaderModel= 139,
|
||||
Code = 140,
|
||||
EndOfFile= 141,
|
||||
MinFilter= 142,
|
||||
MagFilter= 143,
|
||||
MipFilter= 144,
|
||||
Filter = 145,
|
||||
Texture = 146,
|
||||
AddressU= 147,
|
||||
AddressV= 148,
|
||||
AddressW= 149,
|
||||
BorderColor= 150,
|
||||
MaxAnisotropy= 151,
|
||||
MaxMipLevel= 152,
|
||||
MipLodBias= 153,
|
||||
Clamp = 154,
|
||||
Wrap = 155,
|
||||
Mirror = 156,
|
||||
Border = 157,
|
||||
None = 158,
|
||||
Linear = 159,
|
||||
Point = 160,
|
||||
Anisotropic= 161,
|
||||
AlphaBlendEnable= 162,
|
||||
SrcBlend= 163,
|
||||
DestBlend= 164,
|
||||
BlendOp = 165,
|
||||
ColorWriteEnable= 166,
|
||||
ZEnable = 167,
|
||||
ZWriteEnable= 168,
|
||||
ZFunc = 169,
|
||||
DepthBias= 170,
|
||||
CullMode= 171,
|
||||
FillMode= 172,
|
||||
MultiSampleAntiAlias= 173,
|
||||
ScissorTestEnable= 174,
|
||||
SlopeScaleDepthBias= 175,
|
||||
StencilEnable= 176,
|
||||
StencilFail= 177,
|
||||
StencilFunc= 178,
|
||||
StencilMask= 179,
|
||||
StencilPass= 180,
|
||||
StencilRef= 181,
|
||||
StencilWriteMask= 182,
|
||||
StencilZFail= 183,
|
||||
Never = 184,
|
||||
Less = 185,
|
||||
Equal = 186,
|
||||
LessEqual= 187,
|
||||
Greater = 188,
|
||||
NotEqual= 189,
|
||||
GreaterEqual= 190,
|
||||
Always = 191,
|
||||
Keep = 192,
|
||||
Zero = 193,
|
||||
Replace = 194,
|
||||
IncrSat = 195,
|
||||
DecrSat = 196,
|
||||
Invert = 197,
|
||||
Incr = 198,
|
||||
Decr = 199,
|
||||
Red = 200,
|
||||
Green = 201,
|
||||
Blue = 202,
|
||||
Alpha = 203,
|
||||
All = 204,
|
||||
Cw = 205,
|
||||
Ccw = 206,
|
||||
Solid = 207,
|
||||
WireFrame= 208,
|
||||
Add = 209,
|
||||
Subtract= 210,
|
||||
RevSubtract= 211,
|
||||
Min = 212,
|
||||
Max = 213,
|
||||
One = 214,
|
||||
SrcColor= 215,
|
||||
InvSrcColor= 216,
|
||||
SrcAlpha= 217,
|
||||
InvSrcAlpha= 218,
|
||||
DestAlpha= 219,
|
||||
InvDestAlpha= 220,
|
||||
DestColor= 221,
|
||||
InvDestColor= 222,
|
||||
SrcAlphaSat= 223,
|
||||
BlendFactor= 224,
|
||||
InvBlendFactor= 225
|
||||
}
|
||||
|
||||
public class Token
|
||||
{
|
||||
private string file;
|
||||
private int line;
|
||||
private int column;
|
||||
private int startpos;
|
||||
private int endpos;
|
||||
private string text;
|
||||
private object value;
|
||||
|
||||
// contains all prior skipped symbols
|
||||
private List<Token> skipped;
|
||||
|
||||
public string File {
|
||||
get { return file; }
|
||||
set { file = value; }
|
||||
}
|
||||
|
||||
public int Line {
|
||||
get { return line; }
|
||||
set { line = value; }
|
||||
}
|
||||
|
||||
public int Column {
|
||||
get { return column; }
|
||||
set { column = value; }
|
||||
}
|
||||
|
||||
public int StartPos {
|
||||
get { return startpos;}
|
||||
set { startpos = value; }
|
||||
}
|
||||
|
||||
public int Length {
|
||||
get { return endpos - startpos;}
|
||||
}
|
||||
|
||||
public int EndPos {
|
||||
get { return endpos;}
|
||||
set { endpos = value; }
|
||||
}
|
||||
|
||||
public string Text {
|
||||
get { return text;}
|
||||
set { text = value; }
|
||||
}
|
||||
|
||||
public List<Token> Skipped {
|
||||
get { return skipped;}
|
||||
set { skipped = value; }
|
||||
}
|
||||
public object Value {
|
||||
get { return value;}
|
||||
set { this.value = value; }
|
||||
}
|
||||
|
||||
[XmlAttribute]
|
||||
public TokenType Type;
|
||||
|
||||
public Token()
|
||||
: this(0, 0)
|
||||
{
|
||||
}
|
||||
|
||||
public Token(int start, int end)
|
||||
{
|
||||
Type = TokenType._UNDETERMINED_;
|
||||
startpos = start;
|
||||
endpos = end;
|
||||
Text = ""; // must initialize with empty string, may cause null reference exceptions otherwise
|
||||
Value = null;
|
||||
}
|
||||
|
||||
public void UpdateRange(Token token)
|
||||
{
|
||||
if (token.StartPos < startpos) startpos = token.StartPos;
|
||||
if (token.EndPos > endpos) endpos = token.EndPos;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (Text != null)
|
||||
return Type.ToString() + " '" + Text + "'";
|
||||
else
|
||||
return Type.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace TwoMGFX.TPGParser
|
||||
{
|
||||
public class ShaderInfo
|
||||
{
|
||||
public List<TechniqueInfo> Techniques = new List<TechniqueInfo>();
|
||||
|
||||
public Dictionary<string, SamplerStateInfo> SamplerStates = new Dictionary<string, SamplerStateInfo>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TwoMGFX.TPGParser
|
||||
{
|
||||
public class TechniqueInfo
|
||||
{
|
||||
public int startPos;
|
||||
public int length;
|
||||
|
||||
public string name;
|
||||
public List<PassInfo> Passes = new List<PassInfo>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace TwoMGFX
|
||||
{
|
||||
public enum TextureFilterType
|
||||
{
|
||||
None,
|
||||
Point,
|
||||
Linear,
|
||||
Anisotropic,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,504 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.Xna.Framework.Content.Pipeline;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using MonoGame.Framework.Content.Pipeline.Builder;
|
||||
|
||||
|
||||
namespace MGCB
|
||||
{
|
||||
class BuildContent
|
||||
{
|
||||
[CommandLineParameter(
|
||||
Name = "launchdebugger",
|
||||
Flag = "d",
|
||||
Description = "Wait for debugger to attach before building content.")]
|
||||
public bool LaunchDebugger = false;
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "quiet",
|
||||
Flag = "q",
|
||||
Description = "Only output content build errors.")]
|
||||
public bool Quiet = false;
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "@",
|
||||
Flag = "@",
|
||||
ValueName = "responseFile",
|
||||
Description = "Read a text response file with additional command line options and switches.")]
|
||||
// This property only exists for documentation.
|
||||
// The actual handling of '/@' is done in the preprocess step.
|
||||
public List<string> ResponseFiles
|
||||
{
|
||||
get { throw new InvalidOperationException(); }
|
||||
set { throw new InvalidOperationException(); }
|
||||
}
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "workingDir",
|
||||
Flag = "w",
|
||||
ValueName = "directoryPath",
|
||||
Description = "The working directory where all source content is located.")]
|
||||
public void SetWorkingDir(string path)
|
||||
{
|
||||
Directory.SetCurrentDirectory(path);
|
||||
}
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "outputDir",
|
||||
Flag = "o",
|
||||
ValueName = "path",
|
||||
Description = "The directory where all content is written.")]
|
||||
public string OutputDir = string.Empty;
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "intermediateDir",
|
||||
Flag = "n",
|
||||
ValueName = "path",
|
||||
Description = "The directory where all intermediate files are written.")]
|
||||
public string IntermediateDir = string.Empty;
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "rebuild",
|
||||
Flag = "r",
|
||||
Description = "Forces a full rebuild of all content.")]
|
||||
public bool Rebuild = false;
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "clean",
|
||||
Flag = "c",
|
||||
Description = "Delete all previously built content and intermediate files.")]
|
||||
public bool Clean = false;
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "incremental",
|
||||
Flag = "I",
|
||||
Description = "Skip cleaning files not included in the current build.")]
|
||||
public bool Incremental = false;
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "reference",
|
||||
Flag = "f",
|
||||
ValueName = "assembly",
|
||||
Description = "Adds an assembly reference for resolving content importers, processors, and writers.")]
|
||||
public readonly List<string> References = new List<string>();
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "platform",
|
||||
Flag = "t",
|
||||
ValueName = "targetPlatform",
|
||||
Description = "Set the target platform for this build. Defaults to Windows desktop DirectX.")]
|
||||
public TargetPlatform Platform = TargetPlatform.Windows;
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "profile",
|
||||
Flag = "g",
|
||||
ValueName = "graphicsProfile",
|
||||
Description = "Set the target graphics profile for this build. Defaults to HiDef.")]
|
||||
public GraphicsProfile Profile = GraphicsProfile.HiDef;
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "config",
|
||||
ValueName = "string",
|
||||
Description = "The optional build config string from the build system.")]
|
||||
public string Config = string.Empty;
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "importer",
|
||||
Flag = "i",
|
||||
ValueName = "className",
|
||||
Description = "Defines the class name of the content importer for reading source content.")]
|
||||
public string Importer = null;
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "processor",
|
||||
Flag = "p",
|
||||
ValueName = "className",
|
||||
Description = "Defines the class name of the content processor for processing imported content.")]
|
||||
public void SetProcessor(string processor)
|
||||
{
|
||||
_processor = processor;
|
||||
|
||||
// If you are changing the processor then reset all
|
||||
// the processor parameters.
|
||||
_processorParams.Clear();
|
||||
}
|
||||
|
||||
private string _processor = null;
|
||||
private readonly OpaqueDataDictionary _processorParams = new OpaqueDataDictionary();
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "processorParam",
|
||||
Flag = "P",
|
||||
ValueName = "name=value",
|
||||
Description = "Defines a parameter name and value to set on a content processor.")]
|
||||
public void AddProcessorParam(string nameAndValue)
|
||||
{
|
||||
var keyAndValue = nameAndValue.Split('=', ':');
|
||||
if (keyAndValue.Length != 2)
|
||||
{
|
||||
// Do we error out or something?
|
||||
return;
|
||||
}
|
||||
|
||||
_processorParams.Remove(keyAndValue[0]);
|
||||
_processorParams.Add(keyAndValue[0], keyAndValue[1]);
|
||||
}
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "build",
|
||||
Flag = "b",
|
||||
ValueName = "sourceFile",
|
||||
Description = "Build the content source file using the previously set switches and options. Optional destination path may be specified with \"sourceFile;destFile\" if you wish to change the output filepath.")]
|
||||
public void OnBuild(string sourceFile)
|
||||
{
|
||||
string link = null;
|
||||
if (sourceFile.Contains(";"))
|
||||
{
|
||||
var split = sourceFile.Split(';');
|
||||
sourceFile = split[0];
|
||||
|
||||
if(split.Length > 0)
|
||||
link = split[1];
|
||||
}
|
||||
|
||||
// Make sure the source file is absolute.
|
||||
if (!Path.IsPathRooted(sourceFile))
|
||||
sourceFile = Path.Combine(Directory.GetCurrentDirectory(), sourceFile);
|
||||
|
||||
// link should remain relative, absolute path will get set later when the build occurs
|
||||
|
||||
sourceFile = PathHelper.Normalize(sourceFile);
|
||||
|
||||
// Remove duplicates... keep this new one.
|
||||
var previous = _content.FindIndex(e => string.Equals(e.SourceFile, sourceFile, StringComparison.InvariantCultureIgnoreCase));
|
||||
if (previous != -1)
|
||||
_content.RemoveAt(previous);
|
||||
|
||||
// Create the item for processing later.
|
||||
var item = new ContentItem
|
||||
{
|
||||
SourceFile = sourceFile,
|
||||
OutputFile = link,
|
||||
Importer = Importer,
|
||||
Processor = _processor,
|
||||
ProcessorParams = new OpaqueDataDictionary()
|
||||
};
|
||||
_content.Add(item);
|
||||
|
||||
// Copy the current processor parameters blind as we
|
||||
// will validate and remove invalid parameters during
|
||||
// the build process later.
|
||||
foreach (var pair in _processorParams)
|
||||
item.ProcessorParams.Add(pair.Key, pair.Value);
|
||||
}
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "copy",
|
||||
ValueName = "sourceFile",
|
||||
Description = "Copy the content source file verbatim to the output directory.")]
|
||||
public void OnCopy(string sourceFile)
|
||||
{
|
||||
string link = null;
|
||||
if (sourceFile.Contains(";"))
|
||||
{
|
||||
var split = sourceFile.Split(';');
|
||||
sourceFile = split[0];
|
||||
|
||||
if (split.Length > 0)
|
||||
link = split[1];
|
||||
}
|
||||
|
||||
if (!Path.IsPathRooted(sourceFile))
|
||||
sourceFile = Path.Combine(Directory.GetCurrentDirectory(), sourceFile);
|
||||
|
||||
sourceFile = PathHelper.Normalize(sourceFile);
|
||||
|
||||
// Remove duplicates... keep this new one.
|
||||
var previous = _copyItems.FindIndex(e => string.Equals(e.SourceFile, sourceFile, StringComparison.InvariantCultureIgnoreCase));
|
||||
if (previous != -1)
|
||||
_copyItems.RemoveAt(previous);
|
||||
|
||||
_copyItems.Add(new CopyItem { SourceFile = sourceFile, Link = link });
|
||||
}
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "compress",
|
||||
Description = "Compress the XNB files for smaller file sizes.")]
|
||||
public bool CompressContent = false;
|
||||
|
||||
public class ContentItem
|
||||
{
|
||||
public string SourceFile;
|
||||
|
||||
// This refers to the "Link" which can override the default output location
|
||||
public string OutputFile;
|
||||
public string Importer;
|
||||
public string Processor;
|
||||
public OpaqueDataDictionary ProcessorParams;
|
||||
}
|
||||
|
||||
public class CopyItem
|
||||
{
|
||||
public string SourceFile;
|
||||
public string Link;
|
||||
}
|
||||
|
||||
private readonly List<ContentItem> _content = new List<ContentItem>();
|
||||
|
||||
private readonly List<CopyItem> _copyItems = new List<CopyItem>();
|
||||
|
||||
private PipelineManager _manager;
|
||||
|
||||
public bool HasWork
|
||||
{
|
||||
get { return _content.Count > 0 || _copyItems.Count > 0 || Clean; }
|
||||
}
|
||||
|
||||
string ReplaceSymbols(string parameter)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(parameter))
|
||||
return parameter;
|
||||
return parameter
|
||||
.Replace("$(Platform)", Platform.ToString())
|
||||
.Replace("$(Configuration)", Config)
|
||||
.Replace("$(Config)", Config)
|
||||
.Replace("$(Profile)", this.Profile.ToString());
|
||||
}
|
||||
|
||||
public void Build(out int successCount, out int errorCount)
|
||||
{
|
||||
var projectDirectory = PathHelper.Normalize(Directory.GetCurrentDirectory());
|
||||
|
||||
var outputPath = ReplaceSymbols (OutputDir);
|
||||
if (!Path.IsPathRooted(outputPath))
|
||||
outputPath = PathHelper.Normalize(Path.GetFullPath(Path.Combine(projectDirectory, outputPath)));
|
||||
|
||||
var intermediatePath = ReplaceSymbols (IntermediateDir);
|
||||
if (!Path.IsPathRooted(intermediatePath))
|
||||
intermediatePath = PathHelper.Normalize(Path.GetFullPath(Path.Combine(projectDirectory, intermediatePath)));
|
||||
|
||||
_manager = new PipelineManager(projectDirectory, outputPath, intermediatePath);
|
||||
_manager.Logger = new ConsoleLogger();
|
||||
_manager.CompressContent = CompressContent;
|
||||
|
||||
// If the intent is to debug build, break at the original location
|
||||
// of any exception, eg, within the actual importer/processor.
|
||||
if (LaunchDebugger)
|
||||
_manager.RethrowExceptions = false;
|
||||
|
||||
// Feed all the assembly references to the pipeline manager
|
||||
// so it can resolve importers, processors, writers, and types.
|
||||
foreach (var r in References)
|
||||
{
|
||||
var assembly = r;
|
||||
if (!Path.IsPathRooted(assembly))
|
||||
assembly = Path.GetFullPath(Path.Combine(projectDirectory, assembly));
|
||||
_manager.AddAssembly(assembly);
|
||||
}
|
||||
|
||||
// Load the previously serialized list of built content.
|
||||
var contentFile = Path.Combine(intermediatePath, PipelineBuildEvent.Extension);
|
||||
var previousContent = SourceFileCollection.Read(contentFile);
|
||||
|
||||
// If the target changed in any way then we need to force
|
||||
// a full rebuild even under incremental builds.
|
||||
var targetChanged = previousContent.Config != Config ||
|
||||
previousContent.Platform != Platform ||
|
||||
previousContent.Profile != Profile;
|
||||
|
||||
// First clean previously built content.
|
||||
for(int i = 0; i < previousContent.SourceFiles.Count; i++)
|
||||
{
|
||||
var sourceFile = previousContent.SourceFiles[i];
|
||||
|
||||
// This may be an old file (prior to MG 3.7) which doesn't have destination files:
|
||||
string destFile = null;
|
||||
if(i < previousContent.DestFiles.Count)
|
||||
{
|
||||
destFile = previousContent.DestFiles[i];
|
||||
}
|
||||
|
||||
var inContent = _content.Any(e => string.Equals(e.SourceFile, sourceFile, StringComparison.InvariantCultureIgnoreCase));
|
||||
var cleanOldContent = !inContent && !Incremental;
|
||||
var cleanRebuiltContent = inContent && (Rebuild || Clean);
|
||||
if (cleanRebuiltContent || cleanOldContent || targetChanged)
|
||||
_manager.CleanContent(sourceFile, destFile);
|
||||
}
|
||||
|
||||
// TODO: Should we be cleaning copy items? I think maybe we should.
|
||||
|
||||
var newContent = new SourceFileCollection
|
||||
{
|
||||
Profile = _manager.Profile = Profile,
|
||||
Platform = _manager.Platform = Platform,
|
||||
Config = _manager.Config = Config
|
||||
};
|
||||
errorCount = 0;
|
||||
successCount = 0;
|
||||
|
||||
// Before building the content, register all files to be built. (Necessary to
|
||||
// correctly resolve external references.)
|
||||
foreach (var c in _content)
|
||||
{
|
||||
try
|
||||
{
|
||||
_manager.RegisterContent(c.SourceFile, c.OutputFile, c.Importer, c.Processor, c.ProcessorParams);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore exception. Exception will be handled below.
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var c in _content)
|
||||
{
|
||||
try
|
||||
{
|
||||
_manager.BuildContent(c.SourceFile,
|
||||
c.OutputFile,
|
||||
c.Importer,
|
||||
c.Processor,
|
||||
c.ProcessorParams);
|
||||
|
||||
newContent.SourceFiles.Add(c.SourceFile);
|
||||
newContent.DestFiles.Add(c.OutputFile);
|
||||
|
||||
++successCount;
|
||||
}
|
||||
catch (InvalidContentException ex)
|
||||
{
|
||||
var message = string.Empty;
|
||||
if (ex.ContentIdentity != null && !string.IsNullOrEmpty(ex.ContentIdentity.SourceFilename))
|
||||
{
|
||||
message = ex.ContentIdentity.SourceFilename;
|
||||
if (!string.IsNullOrEmpty(ex.ContentIdentity.FragmentIdentifier))
|
||||
message += "(" + ex.ContentIdentity.FragmentIdentifier + ")";
|
||||
message += ": ";
|
||||
}
|
||||
message += ex.Message;
|
||||
Console.WriteLine(message);
|
||||
++errorCount;
|
||||
}
|
||||
catch (PipelineException ex)
|
||||
{
|
||||
Console.Error.WriteLine("{0}: error: {1}", c.SourceFile, ex.Message);
|
||||
if (ex.InnerException != null)
|
||||
Console.Error.WriteLine(ex.InnerException.ToString());
|
||||
++errorCount;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.Error.WriteLine("{0}: error: {1}", c.SourceFile, ex.Message);
|
||||
if (ex.InnerException != null)
|
||||
Console.Error.WriteLine(ex.InnerException.ToString());
|
||||
++errorCount;
|
||||
}
|
||||
}
|
||||
|
||||
// If this is an incremental build we merge the list
|
||||
// of previous content with the new list.
|
||||
if (Incremental && !targetChanged)
|
||||
{
|
||||
newContent.Merge(previousContent);
|
||||
_manager.ContentStats.MergePreviousStats();
|
||||
}
|
||||
|
||||
// Delete the old file and write the new content
|
||||
// list if we have any to serialize.
|
||||
FileHelper.DeleteIfExists(contentFile);
|
||||
if (newContent.SourceFiles.Count > 0)
|
||||
newContent.Write(contentFile);
|
||||
|
||||
// Process copy items (files that bypass the content pipeline)
|
||||
foreach (var c in _copyItems)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Figure out an asset name relative to the project directory,
|
||||
// retaining the file extension.
|
||||
// Note that replacing a sub-path like this requires consistent
|
||||
// directory separator characters.
|
||||
var relativeName = c.Link;
|
||||
if (string.IsNullOrWhiteSpace(relativeName))
|
||||
relativeName = c.SourceFile.Replace(projectDirectory, string.Empty)
|
||||
.TrimStart(Path.DirectorySeparatorChar)
|
||||
.TrimStart(Path.AltDirectorySeparatorChar);
|
||||
var dest = Path.Combine(outputPath, relativeName);
|
||||
|
||||
// Only copy if the source file is newer than the destination.
|
||||
// We may want to provide an option for overriding this, but for
|
||||
// nearly all cases this is the desired behavior.
|
||||
if (File.Exists(dest) && !Rebuild)
|
||||
{
|
||||
var srcTime = File.GetLastWriteTimeUtc(c.SourceFile);
|
||||
var dstTime = File.GetLastWriteTimeUtc(dest);
|
||||
if (srcTime <= dstTime)
|
||||
{
|
||||
if (string.IsNullOrEmpty(c.Link))
|
||||
Console.WriteLine("Skipping {0}", c.SourceFile);
|
||||
else
|
||||
Console.WriteLine("Skipping {0} => {1}", c.SourceFile, c.Link);
|
||||
|
||||
// Copy the stats from the previous stats collection.
|
||||
_manager.ContentStats.CopyPreviousStats(c.SourceFile);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
var startTime = DateTime.UtcNow;
|
||||
|
||||
// Create the destination directory if it doesn't already exist.
|
||||
var destPath = Path.GetDirectoryName(dest);
|
||||
if (!Directory.Exists(destPath))
|
||||
Directory.CreateDirectory(destPath);
|
||||
|
||||
File.Copy(c.SourceFile, dest, true);
|
||||
|
||||
// Destination file should not be read-only even if original was.
|
||||
var fileAttr = File.GetAttributes(dest);
|
||||
fileAttr = fileAttr & (~FileAttributes.ReadOnly);
|
||||
File.SetAttributes(dest, fileAttr);
|
||||
|
||||
var buildTime = DateTime.UtcNow - startTime;
|
||||
|
||||
if (string.IsNullOrEmpty(c.Link))
|
||||
Console.WriteLine("{0}", c.SourceFile);
|
||||
else
|
||||
Console.WriteLine("{0} => {1}", c.SourceFile, c.Link);
|
||||
|
||||
// Record content stats on the copy.
|
||||
_manager.ContentStats.RecordStats(c.SourceFile, dest, "CopyItem", typeof(File), (float)buildTime.TotalSeconds);
|
||||
|
||||
++successCount;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.Error.WriteLine("{0}: error: {1}", c, ex.Message);
|
||||
if (ex.InnerException != null)
|
||||
Console.Error.WriteLine(ex.InnerException.ToString());
|
||||
|
||||
++errorCount;
|
||||
}
|
||||
}
|
||||
|
||||
// Dump the content build stats.
|
||||
_manager.ContentStats.Write(intermediatePath);
|
||||
}
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "help",
|
||||
Flag = "h",
|
||||
Description = "Displays this help.")]
|
||||
public void Help()
|
||||
{
|
||||
MGBuildParser.Instance.ShowError(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,680 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace MGCB
|
||||
{
|
||||
/// <summary>
|
||||
/// Adapted from this generic command line argument parser:
|
||||
/// http://blogs.msdn.com/b/shawnhar/archive/2012/04/20/a-reusable-reflection-based-command-line-parser.aspx
|
||||
/// </summary>
|
||||
public class MGBuildParser
|
||||
{
|
||||
public static MGBuildParser Instance;
|
||||
|
||||
#region Supporting Types
|
||||
|
||||
public class PreprocessorProperty
|
||||
{
|
||||
public string Name;
|
||||
public string CurrentValue;
|
||||
|
||||
public PreprocessorProperty()
|
||||
{
|
||||
Name = string.Empty;
|
||||
CurrentValue = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public class PreprocessorPropertyCollection
|
||||
{
|
||||
private readonly List<PreprocessorProperty> _properties;
|
||||
|
||||
public PreprocessorPropertyCollection()
|
||||
{
|
||||
_properties = new List<PreprocessorProperty>();
|
||||
}
|
||||
|
||||
public string this[string name]
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (var i in _properties)
|
||||
{
|
||||
if (i.Name.Equals(name))
|
||||
return i.CurrentValue;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
foreach (var i in _properties)
|
||||
{
|
||||
if (i.Name.Equals(name))
|
||||
{
|
||||
i.CurrentValue = value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var prop = new PreprocessorProperty()
|
||||
{
|
||||
Name = name,
|
||||
CurrentValue = value,
|
||||
};
|
||||
_properties.Add(prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private readonly object _optionsObject;
|
||||
private readonly Queue<MemberInfo> _requiredOptions;
|
||||
private readonly Dictionary<string, MemberInfo> _optionalOptions;
|
||||
private readonly Dictionary<string, string> _flags;
|
||||
private readonly List<string> _requiredUsageHelp;
|
||||
|
||||
public readonly PreprocessorPropertyCollection _properties;
|
||||
|
||||
public delegate void ErrorCallback(string msg, object[] args);
|
||||
public event ErrorCallback OnError;
|
||||
|
||||
public MGBuildParser(object optionsObject)
|
||||
{
|
||||
Instance = this;
|
||||
|
||||
_optionsObject = optionsObject;
|
||||
_requiredOptions = new Queue<MemberInfo>();
|
||||
_optionalOptions = new Dictionary<string, MemberInfo>();
|
||||
_requiredUsageHelp = new List<string>();
|
||||
|
||||
_properties = new PreprocessorPropertyCollection();
|
||||
|
||||
// Reflect to find what commandline options are available...
|
||||
|
||||
// Fields
|
||||
foreach (var field in optionsObject.GetType().GetFields())
|
||||
{
|
||||
var param = GetAttribute<CommandLineParameterAttribute>(field);
|
||||
if (param == null)
|
||||
continue;
|
||||
|
||||
CheckReservedPrefixes(param.Name);
|
||||
|
||||
if (param.Required)
|
||||
{
|
||||
// Record a required option.
|
||||
_requiredOptions.Enqueue(field);
|
||||
|
||||
_requiredUsageHelp.Add(string.Format("<{0}>", param.Name));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Record an optional option.
|
||||
_optionalOptions.Add(param.Name.ToLowerInvariant(), field);
|
||||
}
|
||||
}
|
||||
|
||||
// Properties
|
||||
foreach (var property in optionsObject.GetType().GetProperties())
|
||||
{
|
||||
var param = GetAttribute<CommandLineParameterAttribute>(property);
|
||||
if (param == null)
|
||||
continue;
|
||||
|
||||
CheckReservedPrefixes(param.Name);
|
||||
|
||||
if (param.Required)
|
||||
{
|
||||
// Record a required option.
|
||||
_requiredOptions.Enqueue(property);
|
||||
|
||||
_requiredUsageHelp.Add(string.Format("<{0}>", param.Name));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Record an optional option.
|
||||
_optionalOptions.Add(param.Name.ToLowerInvariant(), property);
|
||||
}
|
||||
}
|
||||
|
||||
// Methods
|
||||
foreach (var method in optionsObject.GetType().GetMethods())
|
||||
{
|
||||
var param = GetAttribute<CommandLineParameterAttribute>(method);
|
||||
if (param == null)
|
||||
continue;
|
||||
|
||||
CheckReservedPrefixes(param.Name);
|
||||
|
||||
// Only accept methods that take less than 1 parameter.
|
||||
if (method.GetParameters().Length > 1)
|
||||
throw new NotSupportedException("Methods must have one or zero parameters.");
|
||||
|
||||
if (param.Required)
|
||||
{
|
||||
// Record a required option.
|
||||
_requiredOptions.Enqueue(method);
|
||||
|
||||
_requiredUsageHelp.Add(string.Format("<{0}>", param.Name));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Record an optional option.
|
||||
_optionalOptions.Add(param.Name.ToLowerInvariant(), method);
|
||||
}
|
||||
}
|
||||
|
||||
_flags = new Dictionary<string, string>();
|
||||
foreach(var pair in _optionalOptions)
|
||||
{
|
||||
var fi = GetAttribute<CommandLineParameterAttribute>(pair.Value);
|
||||
if(!string.IsNullOrEmpty(fi.Flag))
|
||||
_flags.Add(fi.Flag, fi.Name);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Parse(IEnumerable<string> args)
|
||||
{
|
||||
args = Preprocess(args);
|
||||
|
||||
var showUsage = true;
|
||||
var success = true;
|
||||
foreach (var arg in args)
|
||||
{
|
||||
showUsage = false;
|
||||
|
||||
if (!ParseFlags(arg))
|
||||
{
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var missingRequiredOption = _requiredOptions.FirstOrDefault(field => !IsList(field) || GetList(field).Count == 0);
|
||||
if (missingRequiredOption != null)
|
||||
{
|
||||
ShowError("Missing argument '{0}'", GetAttribute<CommandLineParameterAttribute>(missingRequiredOption).Name);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (showUsage)
|
||||
ShowError(null);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
private IEnumerable<string> Preprocess(IEnumerable<string> args)
|
||||
{
|
||||
var output = new List<string>();
|
||||
var lines = new List<string>(args);
|
||||
var ifstack = new Stack<Tuple<string, string>>();
|
||||
var fileStack = new Stack<string>();
|
||||
|
||||
while (lines.Count > 0)
|
||||
{
|
||||
var arg = lines[0];
|
||||
lines.RemoveAt(0);
|
||||
|
||||
if (arg.StartsWith("# Begin:"))
|
||||
{
|
||||
var file = arg.Substring(8);
|
||||
fileStack.Push(file);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg.StartsWith("# End:"))
|
||||
{
|
||||
fileStack.Pop();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg.StartsWith("$endif"))
|
||||
{
|
||||
ifstack.Pop();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ifstack.Count > 0)
|
||||
{
|
||||
var skip = false;
|
||||
foreach (var i in ifstack)
|
||||
{
|
||||
var val = _properties[i.Item1];
|
||||
if (!(i.Item2).Equals(val))
|
||||
{
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (skip)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg.StartsWith("$set"))
|
||||
{
|
||||
var words = arg.Substring(5).Split('=');
|
||||
var name = words[0];
|
||||
var value = words[1];
|
||||
|
||||
_properties[name] = value;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg.StartsWith("$if"))
|
||||
{
|
||||
if (fileStack.Count == 0)
|
||||
throw new Exception("$if is invalid outside of a response file.");
|
||||
|
||||
var words = arg.Substring(4).Split('=');
|
||||
var name = words[0];
|
||||
var value = words[1];
|
||||
|
||||
var condition = new Tuple<string, string>(name, value);
|
||||
ifstack.Push(condition);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg.StartsWith("/define:") || arg.StartsWith("--define:"))
|
||||
{
|
||||
var words = arg.Substring(8).Split('=');
|
||||
var name = words[0];
|
||||
var value = words[1];
|
||||
|
||||
_properties[name] = value;
|
||||
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
if (arg.StartsWith("/@") || arg.StartsWith("--@") || arg.StartsWith("-@")
|
||||
|| (arg.EndsWith(".mgcb") && File.Exists(arg)))
|
||||
{
|
||||
var file = arg;
|
||||
if (!File.Exists(arg))
|
||||
file = arg.Substring(arg.StartsWith("--@") ? 4 : 3);
|
||||
|
||||
var commands = File.ReadAllLines(file);
|
||||
var offset = 0;
|
||||
lines.Insert(0, string.Format("# Begin:{0} ", file));
|
||||
offset++;
|
||||
|
||||
for (var j = 0; j < commands.Length; j++)
|
||||
{
|
||||
var line = commands[j];
|
||||
if (string.IsNullOrEmpty(line))
|
||||
continue;
|
||||
if (line.StartsWith("#"))
|
||||
continue;
|
||||
|
||||
lines.Insert(offset, line);
|
||||
offset++;
|
||||
}
|
||||
|
||||
lines.Insert(offset, string.Format("# End:{0}", file));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
output.Add(arg);
|
||||
}
|
||||
|
||||
return output.ToArray();
|
||||
}
|
||||
|
||||
private bool ParseFlags(string arg)
|
||||
{
|
||||
// Filename detected, redo with a build command
|
||||
if (File.Exists(arg))
|
||||
return ParseFlags("/build=" + arg);
|
||||
|
||||
// Only one flag
|
||||
if (arg.Length >= 3 &&
|
||||
(arg[0] == '-' || arg[0] == '/') &&
|
||||
(arg[2] == '=' || arg[2] == ':'))
|
||||
{
|
||||
string name;
|
||||
if (!_flags.TryGetValue(arg[1].ToString(), out name))
|
||||
{
|
||||
ShowError("Unknown option '{0}'", arg[1].ToString());
|
||||
return false;
|
||||
}
|
||||
|
||||
ParseArgument("/" + name + arg.Substring(2));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Multiple flags
|
||||
if (arg.Length >= 2 &&
|
||||
((arg[0] == '-' && arg[1] != '-') || arg[0] == '/') &&
|
||||
!arg.Contains(":") && !arg.Contains("=") &&
|
||||
!_optionalOptions.ContainsKey(arg.Substring(1)))
|
||||
{
|
||||
for (int i = 1; i < arg.Length; i++)
|
||||
{
|
||||
string name;
|
||||
if (!_flags.TryGetValue(arg[i].ToString(), out name))
|
||||
{
|
||||
ShowError("Unknown option '{0}'", arg[i].ToString());
|
||||
break;
|
||||
}
|
||||
|
||||
ParseArgument("/" + name);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Not a flag, parse argument
|
||||
return ParseArgument(arg);
|
||||
}
|
||||
|
||||
private bool ParseArgument(string arg)
|
||||
{
|
||||
if (arg.StartsWith("/") || arg.StartsWith("--"))
|
||||
{
|
||||
// After the first escaped argument we can no
|
||||
// longer read non-escaped arguments.
|
||||
if (_requiredOptions.Count > 0)
|
||||
return false;
|
||||
|
||||
// Parse an optional argument.
|
||||
char[] separators = { ':', '=' };
|
||||
|
||||
var split = arg.Substring(arg.StartsWith("/") ? 1 : 2).Split(separators, 2, StringSplitOptions.None);
|
||||
|
||||
var name = split[0];
|
||||
var value = (split.Length > 1) ? split[1] : "true";
|
||||
|
||||
MemberInfo member;
|
||||
|
||||
if (!_optionalOptions.TryGetValue(name.ToLowerInvariant(), out member))
|
||||
{
|
||||
ShowError("Unknown option '{0}'", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
return SetOption(member, value);
|
||||
}
|
||||
|
||||
if (_requiredOptions.Count > 0)
|
||||
{
|
||||
// Parse the next non escaped argument.
|
||||
var field = _requiredOptions.Peek();
|
||||
|
||||
if (!IsList(field))
|
||||
_requiredOptions.Dequeue();
|
||||
|
||||
return SetOption(field, arg);
|
||||
}
|
||||
|
||||
ShowError("Too many arguments");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SetOption(MemberInfo member, string value)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (IsList(member))
|
||||
{
|
||||
// Append this value to a list of options.
|
||||
GetList(member).Add(ChangeType(value, ListElementType(member)));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set the value of a single option.
|
||||
if (member is MethodInfo)
|
||||
{
|
||||
var method = member as MethodInfo;
|
||||
var parameters = method.GetParameters();
|
||||
if (parameters.Length == 0)
|
||||
method.Invoke(_optionsObject, null);
|
||||
else
|
||||
method.Invoke(_optionsObject, new[] { ChangeType(value, parameters[0].ParameterType) });
|
||||
}
|
||||
else if (member is FieldInfo)
|
||||
{
|
||||
var field = member as FieldInfo;
|
||||
field.SetValue(_optionsObject, ChangeType(value, field.FieldType));
|
||||
}
|
||||
else
|
||||
{
|
||||
var property = member as PropertyInfo;
|
||||
property.SetValue(_optionsObject, ChangeType(value, property.PropertyType), null);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
ShowError("Invalid value '{0}' for option '{1}'", value, GetAttribute<CommandLineParameterAttribute>(member).Name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static readonly string[] ReservedPrefixes = new[]
|
||||
{
|
||||
"$",
|
||||
"/",
|
||||
"#",
|
||||
"--",
|
||||
"-"
|
||||
};
|
||||
|
||||
static void CheckReservedPrefixes(string str)
|
||||
{
|
||||
foreach (var i in ReservedPrefixes)
|
||||
{
|
||||
if (str.StartsWith(i))
|
||||
throw new Exception(string.Format("'{0}' is a reserved prefix and cannot be used at the start of an argument name.", i));
|
||||
}
|
||||
}
|
||||
|
||||
static object ChangeType(string value, Type type)
|
||||
{
|
||||
var converter = TypeDescriptor.GetConverter(type);
|
||||
|
||||
return converter.ConvertFromInvariantString(value);
|
||||
}
|
||||
|
||||
|
||||
static bool IsList(MemberInfo member)
|
||||
{
|
||||
if (member is MethodInfo)
|
||||
return false;
|
||||
|
||||
if (member is FieldInfo)
|
||||
return typeof(IList).IsAssignableFrom((member as FieldInfo).FieldType);
|
||||
|
||||
return typeof(IList).IsAssignableFrom((member as PropertyInfo).PropertyType);
|
||||
}
|
||||
|
||||
|
||||
IList GetList(MemberInfo member)
|
||||
{
|
||||
if (member is PropertyInfo)
|
||||
return (IList)(member as PropertyInfo).GetValue(_optionsObject, null);
|
||||
|
||||
if (member is FieldInfo)
|
||||
return (IList)(member as FieldInfo).GetValue(_optionsObject);
|
||||
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
|
||||
static Type ListElementType(MemberInfo member)
|
||||
{
|
||||
if (member is FieldInfo)
|
||||
{
|
||||
var field = member as FieldInfo;
|
||||
var interfaces = from i in field.FieldType.GetInterfaces()
|
||||
where i.IsGenericType && i.GetGenericTypeDefinition() == typeof (IEnumerable<>)
|
||||
select i;
|
||||
|
||||
return interfaces.First().GetGenericArguments()[0];
|
||||
}
|
||||
|
||||
if (member is PropertyInfo)
|
||||
{
|
||||
var property = member as PropertyInfo;
|
||||
var interfaces = from i in property.PropertyType.GetInterfaces()
|
||||
where i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>)
|
||||
select i;
|
||||
|
||||
return interfaces.First().GetGenericArguments()[0];
|
||||
}
|
||||
|
||||
throw new ArgumentException("Only FieldInfo and PropertyInfo are valid arguments.", "member");
|
||||
}
|
||||
|
||||
public string Title { get; set; }
|
||||
|
||||
bool IsWindows()
|
||||
{
|
||||
switch (Environment.OSVersion.Platform)
|
||||
{
|
||||
case PlatformID.Win32NT:
|
||||
case PlatformID.Win32S:
|
||||
case PlatformID.Win32Windows:
|
||||
case PlatformID.WinCE:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void ShowError(string message, params object[] args)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(message) && OnError != null)
|
||||
{
|
||||
OnError(message, args);
|
||||
return;
|
||||
}
|
||||
|
||||
var name = Path.GetFileNameWithoutExtension(Process.GetCurrentProcess().ProcessName);
|
||||
|
||||
if (!string.IsNullOrEmpty(Title))
|
||||
{
|
||||
Console.Error.WriteLine(Title);
|
||||
Console.Error.WriteLine();
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(message))
|
||||
{
|
||||
Console.Error.WriteLine(message, args);
|
||||
Console.Error.WriteLine();
|
||||
}
|
||||
|
||||
var defaultParamPrefix = IsWindows() ? "/" : "--";
|
||||
Console.Error.WriteLine("Usage: {0} {1}{2}",
|
||||
name,
|
||||
_requiredUsageHelp.Count > 0 ? string.Join(" ", _requiredUsageHelp) + " " : string.Empty,
|
||||
_optionalOptions.Count > 0 ? "<Options>" : string.Empty);
|
||||
|
||||
if (_optionalOptions.Count > 0)
|
||||
{
|
||||
Console.Error.WriteLine();
|
||||
Console.Error.WriteLine("Options:");
|
||||
|
||||
var data = _optionalOptions.Values.ToList();
|
||||
data.Sort((x, y) => {
|
||||
var px = GetAttribute<CommandLineParameterAttribute>(x);
|
||||
var py = GetAttribute<CommandLineParameterAttribute>(y);
|
||||
|
||||
return px.Name.CompareTo(py.Name);
|
||||
});
|
||||
|
||||
foreach(var d in data)
|
||||
{
|
||||
var attr = GetAttribute<CommandLineParameterAttribute>(d);
|
||||
var field = d as FieldInfo;
|
||||
var prop = d as PropertyInfo;
|
||||
var method = d as MethodInfo;
|
||||
var hasValue = false;
|
||||
|
||||
if (field != null && field.FieldType != typeof (bool))
|
||||
hasValue = true;
|
||||
if (prop != null && prop.PropertyType != typeof (bool))
|
||||
hasValue = true;
|
||||
if (method != null && method.GetParameters().Length != 0)
|
||||
hasValue = true;
|
||||
|
||||
var s = " ";
|
||||
|
||||
s += (!string.IsNullOrEmpty(attr.Flag)) ? (IsWindows() ? "/" : "-") + attr.Flag + "," : " ";
|
||||
s += " " + defaultParamPrefix + attr.Name;
|
||||
|
||||
if (hasValue)
|
||||
{
|
||||
if (IsWindows())
|
||||
s += ":<" + attr.ValueName + ">";
|
||||
else
|
||||
s += "=" + attr.ValueName.Replace("=", ":").ToUpper();
|
||||
}
|
||||
|
||||
s = s.PadRight(35, ' ');
|
||||
|
||||
// Wrap text description
|
||||
var bw = Math.Max(60, Console.BufferWidth);
|
||||
var desc = attr.Description.Split(' ');
|
||||
|
||||
foreach(var dw in desc)
|
||||
{
|
||||
if (s.Length + dw.Length >= bw)
|
||||
{
|
||||
Console.WriteLine(s);
|
||||
s = string.Empty.PadRight(37, ' ');
|
||||
}
|
||||
|
||||
s += " " + dw;
|
||||
}
|
||||
|
||||
Console.WriteLine(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static T GetAttribute<T>(ICustomAttributeProvider provider) where T : Attribute
|
||||
{
|
||||
return provider.GetCustomAttributes(typeof(T), false).OfType<T>().FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
// Used on an optionsObject field or method to rename the corresponding commandline option.
|
||||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Property)]
|
||||
public sealed class CommandLineParameterAttribute : Attribute
|
||||
{
|
||||
public CommandLineParameterAttribute()
|
||||
{
|
||||
ValueName = "value";
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public string Flag { get; set; }
|
||||
|
||||
public bool Required { get; set; }
|
||||
|
||||
public string ValueName { get; set; }
|
||||
|
||||
public string Description { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using Microsoft.Xna.Framework.Content.Pipeline;
|
||||
|
||||
namespace MonoGame.Framework.Content.Pipeline.Builder
|
||||
{
|
||||
public class ConsoleLogger : ContentBuildLogger
|
||||
{
|
||||
public override void LogMessage(string message, params object[] messageArgs)
|
||||
{
|
||||
Console.WriteLine(IndentString + message, messageArgs);
|
||||
}
|
||||
|
||||
public override void LogImportantMessage(string message, params object[] messageArgs)
|
||||
{
|
||||
// TODO: How do i make it high importance?
|
||||
Console.WriteLine(IndentString + message, messageArgs);
|
||||
}
|
||||
|
||||
public override void LogWarning(string helpLink, ContentIdentity contentIdentity, string message, params object[] messageArgs)
|
||||
{
|
||||
var warning = string.Empty;
|
||||
if (contentIdentity != null && !string.IsNullOrEmpty(contentIdentity.SourceFilename))
|
||||
{
|
||||
warning = contentIdentity.SourceFilename;
|
||||
if (!string.IsNullOrEmpty(contentIdentity.FragmentIdentifier))
|
||||
warning += "(" + contentIdentity.FragmentIdentifier + ")";
|
||||
warning += ": ";
|
||||
}
|
||||
|
||||
if (messageArgs != null && messageArgs.Length != 0)
|
||||
warning += string.Format(message, messageArgs);
|
||||
else if (!string.IsNullOrEmpty(message))
|
||||
warning += message;
|
||||
|
||||
Console.WriteLine(warning);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.monogame.mgcb</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,103 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>10.0.0</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{4243474D-4C2E-6E69-7578-4D4743422E4C}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>MGCB</RootNamespace>
|
||||
<AssemblyName>MGCB</AssemblyName>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<NoWarn>1591,0436</NoWarn>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<TargetFrameworkProfile />
|
||||
<LangVersion>Default</LangVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<Optimize>false</Optimize>
|
||||
<DebugType>full</DebugType>
|
||||
<EnableUnmanagedDebugging>true</EnableUnmanagedDebugging>
|
||||
<OutputPath>bin\Linux\AnyCPU\Debug</OutputPath>
|
||||
<IntermediateOutputPath>obj\Linux\AnyCPU\Debug</IntermediateOutputPath>
|
||||
<DocumentationFile>bin\Linux\AnyCPU\Debug\MGCB.xml</DocumentationFile>
|
||||
<DefineConstants>DEBUG;TRACE;LINUX</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>none</DebugType>
|
||||
<OutputPath>bin\Linux\AnyCPU\Release</OutputPath>
|
||||
<IntermediateOutputPath>obj\Linux\AnyCPU\Release</IntermediateOutputPath>
|
||||
<DocumentationFile>bin\Linux\AnyCPU\Release\MGCB.xml</DocumentationFile>
|
||||
<DefineConstants>TRACE;LINUX</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="CommandLineParser.cs" />
|
||||
<Compile Include="BuildContent.cs" />
|
||||
<Compile Include="ConsoleLogger.cs" />
|
||||
<Compile Include="SourceFileCollection.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<_PostBuildHookTimestamp>@(IntermediateAssembly->'%(FullPath).timestamp')</_PostBuildHookTimestamp>
|
||||
<_PostBuildHookHostPlatform>$(Platform)</_PostBuildHookHostPlatform>
|
||||
</PropertyGroup>
|
||||
<Target Name="PostBuildHooks" Inputs="@(IntermediateAssembly);@(ReferencePath)" Outputs="@(IntermediateAssembly);$(_PostBuildHookTimestamp)" AfterTargets="CoreCompile" BeforeTargets="AfterCompile">
|
||||
<Touch Files="$(_PostBuildHookTimestamp)" AlwaysCreate="True" />
|
||||
</Target>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\MonoGame.Framework\MonoGame.Framework.Linux.csproj">
|
||||
<Project>{35253CE1-C864-4CD3-8249-4D1319748E8F}</Project>
|
||||
<Name>MonoGame.Framework.Linux</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\MonoGame.Framework.Content.Pipeline\MonoGame.Framework.Content.Pipeline.Linux.csproj">
|
||||
<Project>{57696462-CE5E-4BC5-80AB-1B959E2420EA}</Project>
|
||||
<Name>MonoGame.Framework.Content.Pipeline.Linux</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ProjectExtensions>
|
||||
<MonoDevelop>
|
||||
<Properties><Policies>
|
||||
<TextStylePolicy inheritsSet="VisualStudio" inheritsScope="text/plain" scope="text/x-csharp" />
|
||||
<CSharpFormattingPolicy IndentSwitchSection="True" NewLinesForBracesInProperties="True" NewLinesForBracesInAccessors="True" NewLinesForBracesInAnonymousMethods="True" NewLinesForBracesInControlBlocks="True" NewLinesForBracesInAnonymousTypes="True" NewLinesForBracesInObjectCollectionArrayInitializers="True" NewLinesForBracesInLambdaExpressionBody="True" NewLineForElse="True" NewLineForCatch="True" NewLineForFinally="True" NewLineForMembersInObjectInit="True" NewLineForMembersInAnonymousTypes="True" NewLineForClausesInQuery="True" SpacingAfterMethodDeclarationName="False" SpaceAfterMethodCallName="False" SpaceBeforeOpenSquareBracket="False" inheritsSet="Mono" inheritsScope="text/x-csharp" scope="text/x-csharp" />
|
||||
</Policies>
|
||||
</Properties>
|
||||
</MonoDevelop>
|
||||
</ProjectExtensions>
|
||||
</Project>
|
||||
@@ -0,0 +1,103 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>10.0.0</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{4243474D-572E-6E69-646F-77734D474342}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>MGCB</RootNamespace>
|
||||
<AssemblyName>MGCB</AssemblyName>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<NoWarn>1591,0436</NoWarn>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<TargetFrameworkProfile />
|
||||
<LangVersion>Default</LangVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<Optimize>false</Optimize>
|
||||
<DebugType>full</DebugType>
|
||||
<EnableUnmanagedDebugging>true</EnableUnmanagedDebugging>
|
||||
<OutputPath>bin\Windows\AnyCPU\Debug</OutputPath>
|
||||
<IntermediateOutputPath>obj\Windows\AnyCPU\Debug</IntermediateOutputPath>
|
||||
<DocumentationFile>bin\Windows\AnyCPU\Debug\MGCB.xml</DocumentationFile>
|
||||
<DefineConstants>DEBUG;TRACE;WINDOWS</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>none</DebugType>
|
||||
<OutputPath>bin\Windows\AnyCPU\Release</OutputPath>
|
||||
<IntermediateOutputPath>obj\Windows\AnyCPU\Release</IntermediateOutputPath>
|
||||
<DocumentationFile>bin\Windows\AnyCPU\Release\MGCB.xml</DocumentationFile>
|
||||
<DefineConstants>TRACE;WINDOWS</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="CommandLineParser.cs" />
|
||||
<Compile Include="BuildContent.cs" />
|
||||
<Compile Include="ConsoleLogger.cs" />
|
||||
<Compile Include="SourceFileCollection.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<_PostBuildHookTimestamp>@(IntermediateAssembly->'%(FullPath).timestamp')</_PostBuildHookTimestamp>
|
||||
<_PostBuildHookHostPlatform>$(Platform)</_PostBuildHookHostPlatform>
|
||||
</PropertyGroup>
|
||||
<Target Name="PostBuildHooks" Inputs="@(IntermediateAssembly);@(ReferencePath)" Outputs="@(IntermediateAssembly);$(_PostBuildHookTimestamp)" AfterTargets="CoreCompile" BeforeTargets="AfterCompile">
|
||||
<Touch Files="$(_PostBuildHookTimestamp)" AlwaysCreate="True" />
|
||||
</Target>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\MonoGame.Framework\MonoGame.Framework.Windows.csproj">
|
||||
<Project>{7DE47032-A904-4C29-BD22-2D235E8D91BA}</Project>
|
||||
<Name>MonoGame.Framework.Windows</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\MonoGame.Framework.Content.Pipeline\MonoGame.Framework.Content.Pipeline.Windows.csproj">
|
||||
<Project>{B950DE10-AC5D-4BD9-B817-51247C4A732D}</Project>
|
||||
<Name>MonoGame.Framework.Content.Pipeline.Windows</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ProjectExtensions>
|
||||
<MonoDevelop>
|
||||
<Properties><Policies>
|
||||
<TextStylePolicy inheritsSet="VisualStudio" inheritsScope="text/plain" scope="text/x-csharp" />
|
||||
<CSharpFormattingPolicy IndentSwitchSection="True" NewLinesForBracesInProperties="True" NewLinesForBracesInAccessors="True" NewLinesForBracesInAnonymousMethods="True" NewLinesForBracesInControlBlocks="True" NewLinesForBracesInAnonymousTypes="True" NewLinesForBracesInObjectCollectionArrayInitializers="True" NewLinesForBracesInLambdaExpressionBody="True" NewLineForElse="True" NewLineForCatch="True" NewLineForFinally="True" NewLineForMembersInObjectInit="True" NewLineForMembersInAnonymousTypes="True" NewLineForClausesInQuery="True" SpacingAfterMethodDeclarationName="False" SpaceAfterMethodCallName="False" SpaceBeforeOpenSquareBracket="False" inheritsSet="Mono" inheritsScope="text/x-csharp" scope="text/x-csharp" />
|
||||
</Policies>
|
||||
</Properties>
|
||||
</MonoDevelop>
|
||||
</ProjectExtensions>
|
||||
</Project>
|
||||
@@ -0,0 +1,73 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace MGCB
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static int Main(string[] args)
|
||||
{
|
||||
// We force all stderr to redirect to stdout
|
||||
// to avoid any out of order console output.
|
||||
Console.SetError(Console.Out);
|
||||
|
||||
if (!Environment.Is64BitProcess && Environment.OSVersion.Platform != PlatformID.Unix)
|
||||
{
|
||||
Console.Error.WriteLine("The MonoGame content tools only work on a 64bit OS.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
var content = new BuildContent();
|
||||
|
||||
// Parse the command line.
|
||||
var parser = new MGBuildParser(content)
|
||||
{
|
||||
Title = "MonoGame Content Builder\n" +
|
||||
"Builds optimized game content for MonoGame projects."
|
||||
};
|
||||
|
||||
if (!parser.Parse(args))
|
||||
return -1;
|
||||
|
||||
// Launch debugger if requested.
|
||||
if (content.LaunchDebugger)
|
||||
{
|
||||
try {
|
||||
System.Diagnostics.Debugger.Launch();
|
||||
} catch (NotImplementedException) {
|
||||
// not implemented under Mono
|
||||
}
|
||||
}
|
||||
|
||||
if (content.HasWork)
|
||||
{
|
||||
// Print a startup message.
|
||||
var buildStarted = DateTime.Now;
|
||||
if (!content.Quiet)
|
||||
Console.WriteLine("Build started {0}\n", buildStarted);
|
||||
|
||||
// Let the content build.
|
||||
int successCount, errorCount;
|
||||
content.Build(out successCount, out errorCount);
|
||||
|
||||
// Print the finishing info.
|
||||
if (!content.Quiet)
|
||||
{
|
||||
Console.WriteLine("\nBuild {0} succeeded, {1} failed.\n", successCount, errorCount);
|
||||
Console.WriteLine("Time elapsed {0:hh\\:mm\\:ss\\.ff}.", DateTime.Now - buildStarted);
|
||||
}
|
||||
|
||||
// Return the error count.
|
||||
return errorCount;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("MGCB")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("MGCB")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2016")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("b64484a5-f0ca-47cb-8149-59272a68966d")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
@@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Serialization;
|
||||
using Microsoft.Xna.Framework.Content.Pipeline;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace MGCB
|
||||
{
|
||||
[XmlRoot(ElementName = "SourceFileCollection")]
|
||||
public sealed class SourceFileCollection
|
||||
{
|
||||
public GraphicsProfile Profile { get; set; }
|
||||
|
||||
public TargetPlatform Platform { get; set; }
|
||||
|
||||
public string Config { get; set; }
|
||||
|
||||
[XmlArrayItem("File")]
|
||||
public List<string> SourceFiles { get; set; }
|
||||
|
||||
[XmlArrayItem("File")]
|
||||
public List<string> DestFiles { get; set; }
|
||||
|
||||
|
||||
public SourceFileCollection()
|
||||
{
|
||||
SourceFiles = new List<string>();
|
||||
DestFiles = new List<string>();
|
||||
Config = string.Empty;
|
||||
}
|
||||
|
||||
static public SourceFileCollection Read(string filePath)
|
||||
{
|
||||
var deserializer = new XmlSerializer(typeof(SourceFileCollection));
|
||||
try
|
||||
{
|
||||
using (var textReader = new StreamReader(filePath))
|
||||
return (SourceFileCollection)deserializer.Deserialize(textReader);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
|
||||
return new SourceFileCollection();
|
||||
}
|
||||
|
||||
public void Write(string filePath)
|
||||
{
|
||||
var serializer = new XmlSerializer(typeof(SourceFileCollection));
|
||||
using (var textWriter = new StreamWriter(filePath, false, new UTF8Encoding(false)))
|
||||
serializer.Serialize(textWriter, this);
|
||||
}
|
||||
|
||||
public void Merge(SourceFileCollection other)
|
||||
{
|
||||
foreach (var sourceFile in other.SourceFiles)
|
||||
{
|
||||
var inContent = SourceFiles.Any(e => string.Equals(e, sourceFile, StringComparison.InvariantCultureIgnoreCase));
|
||||
if (!inContent)
|
||||
SourceFiles.Add(sourceFile);
|
||||
}
|
||||
|
||||
foreach (var destFile in other.DestFiles)
|
||||
{
|
||||
var inContent = DestFiles.Any(e => string.Equals(e, destFile, StringComparison.InvariantCultureIgnoreCase));
|
||||
if (!inContent)
|
||||
DestFiles.Add(destFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0"?>
|
||||
<configuration>
|
||||
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/></startup></configuration>
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>10.0.0</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{E2D9E2AE-AD75-D3D6-A3BA-75696C642E54}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>MonoGame.Build.Tasks</RootNamespace>
|
||||
<AssemblyName>MonoGame.Build.Tasks</AssemblyName>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<NoWarn>1591,0436</NoWarn>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<TargetFrameworkProfile />
|
||||
<LangVersion>Default</LangVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<Optimize>false</Optimize>
|
||||
<DebugType>full</DebugType>
|
||||
<EnableUnmanagedDebugging>true</EnableUnmanagedDebugging>
|
||||
<OutputPath>bin\Linux\AnyCPU\Debug</OutputPath>
|
||||
<IntermediateOutputPath>obj\Linux\AnyCPU\Debug</IntermediateOutputPath>
|
||||
<DocumentationFile>bin\Linux\AnyCPU\Debug\MonoGame.Build.Tasks.xml</DocumentationFile>
|
||||
<DefineConstants>DEBUG;PLATFORM_LINUX</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>none</DebugType>
|
||||
<OutputPath>bin\Linux\AnyCPU\Release</OutputPath>
|
||||
<IntermediateOutputPath>obj\Linux\AnyCPU\Release</IntermediateOutputPath>
|
||||
<DocumentationFile>bin\Linux\AnyCPU\Release\MonoGame.Build.Tasks.xml</DocumentationFile>
|
||||
<DefineConstants>PLATFORM_LINUX</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="Microsoft.Build" />
|
||||
<Reference Include="Microsoft.Build.Framework" />
|
||||
<Reference Include="Microsoft.Build.Tasks.v4.0" />
|
||||
<Reference Include="Microsoft.Build.Utilities.v4.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Tasks\CollectContentReferences.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<_PostBuildHookTimestamp>@(IntermediateAssembly->'%(FullPath).timestamp')</_PostBuildHookTimestamp>
|
||||
<_PostBuildHookHostPlatform>$(Platform)</_PostBuildHookHostPlatform>
|
||||
</PropertyGroup>
|
||||
<Target Name="PostBuildHooks" Inputs="@(IntermediateAssembly);@(ReferencePath)" Outputs="@(IntermediateAssembly);$(_PostBuildHookTimestamp)" AfterTargets="CoreCompile" BeforeTargets="AfterCompile">
|
||||
<Touch Files="$(_PostBuildHookTimestamp)" AlwaysCreate="True" />
|
||||
</Target>
|
||||
<ItemGroup />
|
||||
<ProjectExtensions>
|
||||
<MonoDevelop>
|
||||
<Properties><Policies>
|
||||
<TextStylePolicy inheritsSet="VisualStudio" inheritsScope="text/plain" scope="text/x-csharp" />
|
||||
<CSharpFormattingPolicy IndentSwitchSection="True" NewLinesForBracesInProperties="True" NewLinesForBracesInAccessors="True" NewLinesForBracesInAnonymousMethods="True" NewLinesForBracesInControlBlocks="True" NewLinesForBracesInAnonymousTypes="True" NewLinesForBracesInObjectCollectionArrayInitializers="True" NewLinesForBracesInLambdaExpressionBody="True" NewLineForElse="True" NewLineForCatch="True" NewLineForFinally="True" NewLineForMembersInObjectInit="True" NewLineForMembersInAnonymousTypes="True" NewLineForClausesInQuery="True" SpacingAfterMethodDeclarationName="False" SpaceAfterMethodCallName="False" SpaceBeforeOpenSquareBracket="False" inheritsSet="Mono" inheritsScope="text/x-csharp" scope="text/x-csharp" />
|
||||
</Policies>
|
||||
</Properties>
|
||||
</MonoDevelop>
|
||||
</ProjectExtensions>
|
||||
</Project>
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>10.0.0</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{E2D9E2AE-B875-D3D6-92B1-ECDC6C642E54}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>MonoGame.Build.Tasks</RootNamespace>
|
||||
<AssemblyName>MonoGame.Build.Tasks</AssemblyName>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<NoWarn>1591,0436</NoWarn>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<TargetFrameworkProfile />
|
||||
<LangVersion>Default</LangVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<Optimize>false</Optimize>
|
||||
<DebugType>full</DebugType>
|
||||
<EnableUnmanagedDebugging>true</EnableUnmanagedDebugging>
|
||||
<OutputPath>bin\Windows\AnyCPU\Debug</OutputPath>
|
||||
<IntermediateOutputPath>obj\Windows\AnyCPU\Debug</IntermediateOutputPath>
|
||||
<DocumentationFile>bin\Windows\AnyCPU\Debug\MonoGame.Build.Tasks.xml</DocumentationFile>
|
||||
<DefineConstants>DEBUG;PLATFORM_WINDOWS</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>none</DebugType>
|
||||
<OutputPath>bin\Windows\AnyCPU\Release</OutputPath>
|
||||
<IntermediateOutputPath>obj\Windows\AnyCPU\Release</IntermediateOutputPath>
|
||||
<DocumentationFile>bin\Windows\AnyCPU\Release\MonoGame.Build.Tasks.xml</DocumentationFile>
|
||||
<DefineConstants>PLATFORM_WINDOWS</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="Microsoft.Build" />
|
||||
<Reference Include="Microsoft.Build.Framework" />
|
||||
<Reference Include="Microsoft.Build.Tasks.v4.0" />
|
||||
<Reference Include="Microsoft.Build.Utilities.v4.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Tasks\CollectContentReferences.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<_PostBuildHookTimestamp>@(IntermediateAssembly->'%(FullPath).timestamp')</_PostBuildHookTimestamp>
|
||||
<_PostBuildHookHostPlatform>$(Platform)</_PostBuildHookHostPlatform>
|
||||
</PropertyGroup>
|
||||
<Target Name="PostBuildHooks" Inputs="@(IntermediateAssembly);@(ReferencePath)" Outputs="@(IntermediateAssembly);$(_PostBuildHookTimestamp)" AfterTargets="CoreCompile" BeforeTargets="AfterCompile">
|
||||
<Touch Files="$(_PostBuildHookTimestamp)" AlwaysCreate="True" />
|
||||
</Target>
|
||||
<ItemGroup />
|
||||
<ProjectExtensions>
|
||||
<MonoDevelop>
|
||||
<Properties><Policies>
|
||||
<TextStylePolicy inheritsSet="VisualStudio" inheritsScope="text/plain" scope="text/x-csharp" />
|
||||
<CSharpFormattingPolicy IndentSwitchSection="True" NewLinesForBracesInProperties="True" NewLinesForBracesInAccessors="True" NewLinesForBracesInAnonymousMethods="True" NewLinesForBracesInControlBlocks="True" NewLinesForBracesInAnonymousTypes="True" NewLinesForBracesInObjectCollectionArrayInitializers="True" NewLinesForBracesInLambdaExpressionBody="True" NewLineForElse="True" NewLineForCatch="True" NewLineForFinally="True" NewLineForMembersInObjectInit="True" NewLineForMembersInAnonymousTypes="True" NewLineForClausesInQuery="True" SpacingAfterMethodDeclarationName="False" SpaceAfterMethodCallName="False" SpaceBeforeOpenSquareBracket="False" inheritsSet="Mono" inheritsScope="text/x-csharp" scope="text/x-csharp" />
|
||||
</Policies>
|
||||
</Properties>
|
||||
</MonoDevelop>
|
||||
</ProjectExtensions>
|
||||
</Project>
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: AssemblyTitle("MonoGame.Build.Tasks")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("MonoGame Team")]
|
||||
[assembly: AssemblyProduct("MonoGame.Framework")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2009-2017 MonoGame Team")]
|
||||
[assembly: AssemblyTrademark("MonoGame® is a registered trademark of the MonoGame Team")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
|
||||
[assembly: AssemblyVersion("0.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("0.0.0.0")]
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
// MIT License - Copyright (C) The Mono.Xna Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Utilities;
|
||||
|
||||
namespace MonoGame.Build.Tasks
|
||||
{
|
||||
public static class StringExt
|
||||
{
|
||||
public static string NormalisePath(this string path)
|
||||
{
|
||||
return path.Replace('\\', Path.DirectorySeparatorChar).Replace('/', Path.DirectorySeparatorChar);
|
||||
}
|
||||
}
|
||||
|
||||
public class CollectContentReferences : Task
|
||||
{
|
||||
[Required]
|
||||
public ITaskItem[] ContentReferences { get; set; }
|
||||
|
||||
[Required]
|
||||
public string MonoGamePlatform { get; set; }
|
||||
|
||||
[Output]
|
||||
public ITaskItem[] Output { get; set; }
|
||||
|
||||
public override bool Execute()
|
||||
{
|
||||
var output = new List<ITaskItem>();
|
||||
foreach (var content in ContentReferences)
|
||||
{
|
||||
var relative = content.GetMetadata("RelativeDir").NormalisePath();
|
||||
var fp = content.GetMetadata("FullPath").NormalisePath();
|
||||
var link = content.GetMetadata("Link").NormalisePath();
|
||||
var metaData = new Dictionary<string, string>();
|
||||
var contentFolder = String.Empty;
|
||||
if (!string.IsNullOrEmpty(link))
|
||||
{
|
||||
contentFolder = Path.GetFileName(Path.GetDirectoryName(link));
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(relative))
|
||||
{
|
||||
contentFolder = Path.GetFileName(Path.GetDirectoryName(relative));
|
||||
}
|
||||
var outputPath = Path.GetFileNameWithoutExtension(fp);
|
||||
if (!outputPath.EndsWith(contentFolder, StringComparison.OrdinalIgnoreCase))
|
||||
outputPath = Path.Combine(outputPath, contentFolder);
|
||||
metaData.Add("ContentDirectory", !string.IsNullOrEmpty(contentFolder) ? contentFolder + Path.DirectorySeparatorChar : "");
|
||||
metaData.Add("RelativeFullPath", !string.IsNullOrEmpty(relative) ? Path.GetFullPath(relative) : "");
|
||||
metaData.Add("ContentOutputDir", Path.Combine("bin", MonoGamePlatform, outputPath));
|
||||
metaData.Add("ContentIntermediateOutputDir", Path.Combine("obj", MonoGamePlatform, outputPath));
|
||||
output.Add(new TaskItem(fp, metaData));
|
||||
}
|
||||
Output = output.ToArray();
|
||||
return !Log.HasLoggedErrors;
|
||||
}
|
||||
}
|
||||
}
|
||||
+191
@@ -0,0 +1,191 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Utilities;
|
||||
|
||||
namespace MonoGame.Packaging
|
||||
{
|
||||
public class BuildFlatpakTask : Task
|
||||
{
|
||||
[Required]
|
||||
public string IntermediateDir { get; set; }
|
||||
|
||||
[Required]
|
||||
public string OutputPath { get; set; }
|
||||
|
||||
[Required]
|
||||
public string ProjectDir { get; set; }
|
||||
|
||||
[Required]
|
||||
public string PublishDir { get; set; }
|
||||
|
||||
[Required]
|
||||
public string AssemblyName { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Title { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Id { get; set; }
|
||||
|
||||
[Required]
|
||||
public string IconPath { get; set; }
|
||||
|
||||
public override bool Execute()
|
||||
{
|
||||
try
|
||||
{
|
||||
Log.LogMessage(MessageImportance.Normal, "BuildFlatpakTask: Starting...");
|
||||
|
||||
// Ensure that flatpak command is installed
|
||||
if (!IsFlatpakInstalled())
|
||||
{
|
||||
Log.LogMessage(MessageImportance.High, "Flatpak command not found :(");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ensure that flatpak runtimes are installed
|
||||
if (!AreFlatpakRuntimesInstalled())
|
||||
{
|
||||
Log.LogMessage(MessageImportance.High, "Error, the requred flatpak runtime components were not found:");
|
||||
Log.LogMessage(MessageImportance.High, " - org.freedesktop.Platform/x86_64/1.6");
|
||||
Log.LogMessage(MessageImportance.High, " - org.freedesktop.Sdk/x86_64/1.6");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Setup intermediate directory
|
||||
var objpath = Path.Combine(ProjectDir, IntermediateDir, "Flatpak");
|
||||
if (Directory.Exists(objpath))
|
||||
Directory.Delete(objpath, true);
|
||||
Directory.CreateDirectory(objpath);
|
||||
|
||||
// Generate metadata
|
||||
Log.LogMessage(MessageImportance.Normal, "BuildFlatpakTask: Generating metadata");
|
||||
var metadatalines = new[] {
|
||||
"[Application]",
|
||||
"name=" + Id,
|
||||
"runtime=org.freedesktop.Platform/x86_64/1.6",
|
||||
"command=/app/opt/" + AssemblyName + "/" + AssemblyName,
|
||||
"",
|
||||
"[Context]",
|
||||
"shared=ipc;network;",
|
||||
"sockets=x11;wayland;pulseaudio;",
|
||||
"devices=all;"
|
||||
};
|
||||
File.WriteAllLines(Path.Combine(objpath, "metadata"), metadatalines);
|
||||
|
||||
// Copy over icon
|
||||
Log.LogMessage(MessageImportance.Normal, "BuildFlatpakTask: Copying over icon");
|
||||
var icondir = Path.Combine(objpath, "export/share/icons");
|
||||
Directory.CreateDirectory(icondir);
|
||||
File.Copy(Path.Combine(ProjectDir, IconPath), Path.Combine(icondir, Id + ".png"));
|
||||
|
||||
// Generate .desktop launcher file
|
||||
Log.LogMessage(MessageImportance.Normal, "BuildFlatpakTask: Generating launcher file");
|
||||
var desktopdir = Path.Combine(objpath, "export/share/applications");
|
||||
Directory.CreateDirectory(desktopdir);
|
||||
var desktoplines = new[] {
|
||||
"[Desktop Entry]",
|
||||
"Name=" + Title,
|
||||
"Exec=/app/opt/" + AssemblyName + "/" + AssemblyName,
|
||||
"Type=Application",
|
||||
"Icon=" + Id,
|
||||
"Categories=Game;"
|
||||
};
|
||||
File.WriteAllLines(Path.Combine(desktopdir, Id + ".desktop"), desktoplines);
|
||||
|
||||
// Copy over game
|
||||
Log.LogMessage(MessageImportance.Normal, "BuildFlatpakTask: Copying over game data");
|
||||
var sourcegamedir = Path.Combine(ProjectDir, PublishDir);
|
||||
var gamedir = Path.Combine(objpath, "files/opt/" + AssemblyName + "/");
|
||||
Directory.CreateDirectory(gamedir);
|
||||
foreach (var dirpath in Directory.GetDirectories(sourcegamedir, "*", SearchOption.AllDirectories))
|
||||
Directory.CreateDirectory(dirpath.Replace(sourcegamedir, gamedir));
|
||||
foreach (var filepath in Directory.GetFiles(sourcegamedir, "*.*", SearchOption.AllDirectories))
|
||||
File.Copy(filepath, filepath.Replace(sourcegamedir, gamedir));
|
||||
|
||||
// Copy over suplementary libraries
|
||||
var libdir = Path.Combine(Path.GetDirectoryName((new Uri(typeof(BuildFlatpakTask).Assembly.CodeBase)).LocalPath), "../../extra");
|
||||
Directory.CreateDirectory(Path.Combine(objpath, "files/lib"));
|
||||
File.Copy(Path.Combine(libdir, "libunwind-x86_64.so.8"), Path.Combine(objpath, "files/lib/libunwind-x86_64.so.8"));
|
||||
File.Copy(Path.Combine(libdir, "libunwind.so.8"), Path.Combine(objpath, "files/lib/libunwind.so.8"));
|
||||
File.Copy(Path.Combine(libdir, "libSDL2-2.0.so.0.8.0"), Path.Combine(objpath, "files/opt/" + AssemblyName + "/libSDL2-2.so"), true);
|
||||
|
||||
// Generate flatpak
|
||||
Log.LogMessage(MessageImportance.Normal, "BuildFlatpakTask: Generating flatpak");
|
||||
var repodir = Path.Combine(ProjectDir, IntermediateDir, "FlatpakRepo");
|
||||
if (Directory.Exists(repodir))
|
||||
Directory.Delete(repodir, true);
|
||||
Directory.CreateDirectory(repodir);
|
||||
var flatpak = Path.Combine(ProjectDir, OutputPath, AssemblyName + ".flatpak");
|
||||
CallFlatpak("build-export " + repodir + " " + objpath);
|
||||
CallFlatpak("build-bundle " + repodir + " " + flatpak + " " + Id);
|
||||
|
||||
Log.LogMessage(MessageImportance.High, "BuildFlatpakTask: Flatpak generated at: " + flatpak);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.LogMessage(MessageImportance.High, "An error occured while trying to package the project into a flatpak.");
|
||||
Log.LogMessage(MessageImportance.High, "Error Info: " + e.ToString());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool IsFlatpakInstalled()
|
||||
{
|
||||
var proc = new Process();
|
||||
proc.StartInfo.FileName = "which";
|
||||
proc.StartInfo.Arguments = "flatpak";
|
||||
proc.StartInfo.UseShellExecute = false;
|
||||
proc.StartInfo.RedirectStandardOutput = true;
|
||||
proc.Start();
|
||||
proc.StandardOutput.ReadToEnd();
|
||||
|
||||
return proc.ExitCode == 0;
|
||||
}
|
||||
|
||||
private bool AreFlatpakRuntimesInstalled()
|
||||
{
|
||||
var rt = false;
|
||||
var rtsdk = false;
|
||||
var proc = new Process();
|
||||
proc.StartInfo.FileName = "flatpak";
|
||||
proc.StartInfo.Arguments = "list";
|
||||
proc.StartInfo.UseShellExecute = false;
|
||||
proc.StartInfo.RedirectStandardOutput = true;
|
||||
proc.Start();
|
||||
|
||||
while (!proc.StandardOutput.EndOfStream)
|
||||
{
|
||||
var line = proc.StandardOutput.ReadLine();
|
||||
if (line.Contains("org.freedesktop.Platform/x86_64/1.6"))
|
||||
rt = true;
|
||||
else if (line.Contains("org.freedesktop.Sdk/x86_64/1.6"))
|
||||
rtsdk = true;
|
||||
}
|
||||
|
||||
return rt && rtsdk;
|
||||
}
|
||||
|
||||
private void CallFlatpak(string args)
|
||||
{
|
||||
var proc = new Process();
|
||||
proc.StartInfo.FileName = "flatpak";
|
||||
proc.StartInfo.Arguments = args;
|
||||
proc.StartInfo.UseShellExecute = false;
|
||||
proc.StartInfo.RedirectStandardOutput = true;
|
||||
proc.Start();
|
||||
|
||||
while (!proc.StandardOutput.EndOfStream)
|
||||
Log.LogMessage(MessageImportance.Normal, proc.StandardOutput.ReadLine());
|
||||
}
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard2.0;net46</TargetFrameworks>
|
||||
<BuildOutputTargetFolder>tasks</BuildOutputTargetFolder>
|
||||
<PackageIconUrl>https://pbs.twimg.com/profile_images/487954549441691649/O3KsHAsb_400x400.png</PackageIconUrl>
|
||||
<PackageProjectUrl>http://monogame.net</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/MonoGame/MonoGame.git</RepositoryUrl>
|
||||
<Description>This package allows you to package up your MonoGame game into a flatpak installer for Linux.</Description>
|
||||
<PackageTags>monogame;.net core;core;packaging;flatpak</PackageTags>
|
||||
<Version>3.7.0.18</Version>
|
||||
<Authors>MonoGame Team</Authors>
|
||||
<PackageId>MonoGame.Packaging.Flatpak</PackageId>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="MonoGame.Packaging.Flatpak.targets" PackagePath="build\MonoGame.Packaging.Flatpak.targets" />
|
||||
<Content Include="..\..\ThirdParty\Dependencies\FlatpakLibs\*" PackagePath="extra\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Build.Framework" Version="15.1.1012" />
|
||||
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="15.1.1012" />
|
||||
|
||||
<PackageReference Update="@(PackageReference)" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
**This package only works if you are targeting .NET Core.** This package allows you to package up your MonoGame game into a flatpak installer for Linux.
|
||||
|
||||
## Requirements:
|
||||
- netcoreapp as the target
|
||||
- flatpak
|
||||
- org.freedesktop.Platform/x86_64/1.6
|
||||
- org.freedesktop.Sdk/x86_64/1.6
|
||||
|
||||
Flatpak install instructions: [https://flatpak.org/setup/](https://flatpak.org/setup/)
|
||||
|
||||
To install the required runtimes, simply do:
|
||||
```sh
|
||||
flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
|
||||
flatpak install flathub org.freedesktop.Platform/x86_64/1.6
|
||||
flatpak install flathub org.freedesktop.Sdk/x86_64/1.6
|
||||
```
|
||||
|
||||
## Usage:
|
||||
Call the publish command as you normally would: `dotnet publish -r linux-x64`, the resulting flatpak should get generated in the output directory.
|
||||
|
||||
## Customization:
|
||||
This nuget package offers the following properties for customizing the build of the flatpak. Simply set them in the csproj or pass them to msbuild to change their values:
|
||||
|
||||
```
|
||||
| Variable Name | Description / Default value |
|
||||
| ------------------------ | -------------------------------------- |
|
||||
| MGFlatpakIntermediateDir | Folder for temporary files. |
|
||||
| | $(IntermediateOutputPath) |
|
||||
| ------------------------ | -------------------------------------- |
|
||||
| MGFlatpakOutputPath | The output folder for the flatpak. |
|
||||
| | $(OutputPath) |
|
||||
| ------------------------ | -------------------------------------- |
|
||||
| MGFlatpakProjectDir | The current project directory. |
|
||||
| | $(ProjectDir) |
|
||||
| ------------------------ | -------------------------------------- |
|
||||
| MGFlatpakPublishDir | The publish output folder. |
|
||||
| | $(PublishDir) |
|
||||
| ------------------------ | -------------------------------------- |
|
||||
| MGFlatpakAssemblyName | The output assembly to run. |
|
||||
| | $(AssemblyName) |
|
||||
| ------------------------ | -------------------------------------- |
|
||||
| MGFlatpakTitle | The game title. |
|
||||
| | $(AssemblyTitle) |
|
||||
| ------------------------ | -------------------------------------- |
|
||||
| MGFlatpakId | The game id. |
|
||||
| | com.$(Company).$(AssemblyName) |
|
||||
| ------------------------ | -------------------------------------- |
|
||||
| MGFlatpakIcon | The icon file, needs to be png format. |
|
||||
| | Icon.png |
|
||||
```
|
||||
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- Select correct MSBuild task assembly. -->
|
||||
<MGFlatpakFoler Condition=" '$(MSBuildRuntimeType)' == 'Core' ">netstandard2.0</MGFlatpakFoler>
|
||||
<MGFlatpakFoler Condition=" '$(MSBuildRuntimeType)' != 'Core' ">net46</MGFlatpakFoler>
|
||||
<MGFlatpakTaskAssembly>$(MSBuildThisFileDirectory)..\tasks\$(MGFlatpakFoler)\MonoGame.Packaging.Flatpak.dll</MGFlatpakTaskAssembly>
|
||||
|
||||
<!-- Init task properties -->
|
||||
<MGFlatpakIntermediateDir Condition=" '$(MGFlatpakIntermediateDir)' == '' ">$(IntermediateOutputPath)</MGFlatpakIntermediateDir>
|
||||
<MGFlatpakOutputPath Condition=" '$(MGFlatpakOutputPath)' == '' ">$(OutputPath)</MGFlatpakOutputPath>
|
||||
<MGFlatpakProjectDir Condition=" '$(MGFlatpakProjectDir)' == '' ">$(ProjectDir)</MGFlatpakProjectDir>
|
||||
<MGFlatpakPublishDir Condition=" '$(MGFlatpakPublishDir)' == '' ">$(PublishDir)</MGFlatpakPublishDir>
|
||||
<MGFlatpakAssemblyName Condition=" '$(MGFlatpakAssemblyName)' == '' ">$(AssemblyName)</MGFlatpakAssemblyName>
|
||||
<MGFlatpakTitle Condition=" '$(MGFlatpakTitle)' == '' ">$(AssemblyTitle)</MGFlatpakTitle>
|
||||
<MGFlatpakId Condition=" '$(MGFlatpakId)' == '' ">com.$(Company).$(AssemblyName)</MGFlatpakId>
|
||||
<MGFlatpakIcon Condition=" '$(MGFlatpakIcon)' == '' ">Icon.png</MGFlatpakIcon>
|
||||
</PropertyGroup>
|
||||
|
||||
<UsingTask TaskName="MonoGame.Packaging.BuildFlatpakTask" AssemblyFile="$(MGFlatpakTaskAssembly)" />
|
||||
|
||||
<Target Name="PackageFlatpak" AfterTargets="Publish" Condition=" '$(RuntimeIdentifier)'=='linux-x64' ">
|
||||
<BuildFlatpakTask IntermediateDir="$(MGFlatpakIntermediateDir)"
|
||||
OutputPath="$(MGFlatpakOutputPath)"
|
||||
ProjectDir="$(MGFlatpakProjectDir)"
|
||||
PublishDir="$(MGFlatpakPublishDir)"
|
||||
AssemblyName="$(MGFlatpakAssemblyName)"
|
||||
Title="$(MGFlatpakTitle)"
|
||||
Id="$(MGFlatpakId)"
|
||||
IconPath="$(MGFlatpakIcon)" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
|
||||
</startup>
|
||||
</configuration>
|
||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 144 KiB |
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.18.1 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.16"/>
|
||||
<menu id="appmenu">
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">_Help</attribute>
|
||||
<attribute name="action">app.help</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">_About</attribute>
|
||||
<attribute name="action">app.about</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">_Quit</attribute>
|
||||
<attribute name="action">app.quit</attribute>
|
||||
</item>
|
||||
</section>
|
||||
</menu>
|
||||
</interface>
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a stack of undo/redo-able actions.
|
||||
/// </summary>
|
||||
public class ActionStack
|
||||
{
|
||||
private readonly PipelineController _controller;
|
||||
private readonly List<IProjectAction> _undoStack;
|
||||
private readonly List<IProjectAction> _redoStack;
|
||||
|
||||
public bool CanUndo { get; private set; }
|
||||
public bool CanRedo { get; private set; }
|
||||
|
||||
public ActionStack(PipelineController controller)
|
||||
{
|
||||
_controller = controller;
|
||||
_undoStack = new List<IProjectAction>();
|
||||
_redoStack = new List<IProjectAction>();
|
||||
}
|
||||
|
||||
public void Add(IProjectAction action)
|
||||
{
|
||||
_undoStack.Add(action);
|
||||
|
||||
if (_redoStack.Count > 0)
|
||||
_redoStack.Clear();
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
public void Undo()
|
||||
{
|
||||
if (!_undoStack.Any())
|
||||
return;
|
||||
|
||||
var action = _undoStack.Last();
|
||||
if (action.Undo())
|
||||
{
|
||||
_undoStack.Remove(action);
|
||||
_redoStack.Add(action);
|
||||
}
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
public void Redo()
|
||||
{
|
||||
if (!_redoStack.Any())
|
||||
return;
|
||||
|
||||
var action = _redoStack.Last();
|
||||
if (action.Do())
|
||||
{
|
||||
_redoStack.Remove(action);
|
||||
_undoStack.Add(action);
|
||||
}
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_undoStack.Clear();
|
||||
_redoStack.Clear();
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
CanUndo = _undoStack.Any();
|
||||
CanRedo = _redoStack.Any();
|
||||
_controller.UpdateMenu();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom converter for the Processor property of a ContentItem.
|
||||
/// </summary>
|
||||
public class ImporterConverter : TypeConverter
|
||||
{
|
||||
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
|
||||
{
|
||||
if (context.Instance is Array)
|
||||
{
|
||||
var array = context.Instance as Array;
|
||||
foreach (var obj in array)
|
||||
{
|
||||
var item = obj as ContentItem;
|
||||
if (item.BuildAction == BuildAction.Copy)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var contentItem = (context.Instance as ContentItem);
|
||||
if (contentItem.BuildAction == BuildAction.Copy)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
|
||||
{
|
||||
return PipelineTypes.ImportersStandardValuesCollection;
|
||||
}
|
||||
|
||||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
|
||||
{
|
||||
if (sourceType == typeof (string))
|
||||
return true;
|
||||
|
||||
return base.CanConvertFrom(context, sourceType);
|
||||
}
|
||||
|
||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||
{
|
||||
if (value is string)
|
||||
{
|
||||
var str = value as string;
|
||||
|
||||
foreach (var i in PipelineTypes.Importers)
|
||||
{
|
||||
if (i.DisplayName.Equals(str))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(str))
|
||||
return PipelineTypes.NullImporter;
|
||||
else
|
||||
return PipelineTypes.MissingImporter;
|
||||
}
|
||||
|
||||
return base.ConvertFrom(context, culture, value);
|
||||
}
|
||||
|
||||
|
||||
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
|
||||
{
|
||||
var importer = (ImporterTypeDescription)value;// contentItem.Importer;
|
||||
//System.Diagnostics.Debug.Assert(importer == value);
|
||||
|
||||
if (destinationType == typeof (string))
|
||||
{
|
||||
if (importer == PipelineTypes.MissingImporter)
|
||||
{
|
||||
var contentItem = (ContentItem)context.Instance;
|
||||
return string.Format("[missing] {0}", contentItem.ImporterName ?? "[null]");
|
||||
}
|
||||
|
||||
return ((ImporterTypeDescription)value).DisplayName;
|
||||
}
|
||||
|
||||
return base.ConvertTo(context, culture, value, destinationType);
|
||||
}
|
||||
|
||||
public override bool GetPropertiesSupported(ITypeDescriptorContext context)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Microsoft.Xna.Framework.Content.Pipeline;
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom converter for the Processor property of a ContentItem.
|
||||
/// </summary>
|
||||
public class ProcessorConverter : TypeConverter
|
||||
{
|
||||
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
|
||||
{
|
||||
if (context.Instance is Array)
|
||||
{
|
||||
var array = context.Instance as Array;
|
||||
foreach (var obj in array)
|
||||
{
|
||||
var item = obj as ContentItem;
|
||||
if (item.BuildAction == BuildAction.Copy)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var contentItem = (context.Instance as ContentItem);
|
||||
if (contentItem.BuildAction == BuildAction.Copy)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
|
||||
{
|
||||
return PipelineTypes.ProcessorsStandardValuesCollection;
|
||||
}
|
||||
|
||||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
|
||||
{
|
||||
if (sourceType == typeof (string))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return base.CanConvertFrom(context, sourceType);
|
||||
}
|
||||
|
||||
|
||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||
{
|
||||
if (value is string)
|
||||
{
|
||||
foreach (var i in PipelineTypes.Processors)
|
||||
{
|
||||
if (i.DisplayName.Equals(value))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return base.ConvertFrom(context, culture, value);
|
||||
}
|
||||
|
||||
|
||||
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
|
||||
{
|
||||
if (destinationType == typeof (string))
|
||||
{
|
||||
var processor = (ProcessorTypeDescription)value;
|
||||
|
||||
if (processor == PipelineTypes.MissingProcessor)
|
||||
{
|
||||
var contentItem = context.Instance as ContentItem;
|
||||
return string.Format("[missing] {0}", contentItem.ProcessorName);
|
||||
}
|
||||
|
||||
return ((ProcessorTypeDescription)value).DisplayName;
|
||||
}
|
||||
|
||||
return base.ConvertTo(context, culture, value, destinationType);
|
||||
}
|
||||
|
||||
public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
|
||||
{
|
||||
var props = new PropertyDescriptorCollection(null);
|
||||
|
||||
var processor = value as ProcessorTypeDescription;
|
||||
|
||||
if (context.Instance is Array)
|
||||
{
|
||||
var array = context.Instance as object[];
|
||||
|
||||
foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(value, attributes, true))
|
||||
props.Add(new MultiTargetPropertyDescriptor(prop.Name, prop.PropertyType, prop.ComponentType, prop, array));
|
||||
|
||||
var paramArray = array.Select(e => ((ContentItem)e).ProcessorParams).ToArray();
|
||||
|
||||
foreach (var p in processor.Properties)
|
||||
{
|
||||
var prop = new OpaqueDataDictionaryElementPropertyDescriptor(p.Name,
|
||||
p.Type,
|
||||
null);
|
||||
var prop2 = new MultiTargetPropertyDescriptor(prop.Name,
|
||||
prop.PropertyType,
|
||||
prop.ComponentType,
|
||||
prop,
|
||||
paramArray);
|
||||
props.Add(prop2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var contentItem = context.Instance as ContentItem;
|
||||
|
||||
if (value == PipelineTypes.MissingProcessor)
|
||||
{
|
||||
|
||||
props.Add(new ReadonlyPropertyDescriptor("Name", typeof (string), typeof (ProcessorTypeDescription), contentItem.ProcessorName));
|
||||
|
||||
foreach (var p in contentItem.ProcessorParams)
|
||||
{
|
||||
var desc = new OpaqueDataDictionaryElementPropertyDescriptor(p.Key,
|
||||
p.Value.GetType(),
|
||||
contentItem.ProcessorParams);
|
||||
|
||||
|
||||
props.Add(desc);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Emit regular properties.
|
||||
foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(value, attributes, true))
|
||||
props.Add(prop);
|
||||
|
||||
// Emit processor parameters.
|
||||
foreach (var p in processor.Properties)
|
||||
{
|
||||
var desc = new OpaqueDataDictionaryElementPropertyDescriptor(p.Name,
|
||||
p.Type,
|
||||
contentItem.ProcessorParams);
|
||||
|
||||
props.Add(desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return props;
|
||||
}
|
||||
|
||||
public override bool GetPropertiesSupported(ITypeDescriptorContext context)
|
||||
{
|
||||
if (!GetStandardValuesSupported(context))
|
||||
return false;
|
||||
|
||||
if (context.Instance is Array)
|
||||
{
|
||||
var array = (context.Instance as Array);
|
||||
var first = array.GetValue(0) as ContentItem;
|
||||
|
||||
if (!first.Processor.Properties.Any())
|
||||
return false;
|
||||
|
||||
if (first.Processor == PipelineTypes.MissingProcessor)
|
||||
return false;
|
||||
|
||||
for (var i = 1; i < array.Length; i++)
|
||||
{
|
||||
var item = array.GetValue(i) as ContentItem;
|
||||
if (item.Processor != first.Processor)
|
||||
return false;
|
||||
|
||||
if (!item.Processor.Properties.Any())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var item = context.Instance as ContentItem;
|
||||
if (item.BuildAction == BuildAction.Copy)
|
||||
return false;
|
||||
|
||||
if (!item.Processor.Properties.Any())
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using Microsoft.Xna.Framework.Content.Pipeline;
|
||||
using Microsoft.Xna.Framework.Content.Pipeline.Builder.Convertors;
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
public enum BuildAction
|
||||
{
|
||||
Build,
|
||||
Copy,
|
||||
}
|
||||
|
||||
public class ContentItem : IProjectItem
|
||||
{
|
||||
public IContentItemObserver Observer;
|
||||
|
||||
public string ImporterName;
|
||||
public string ProcessorName;
|
||||
public OpaqueDataDictionary ProcessorParams;
|
||||
|
||||
private ImporterTypeDescription _importer;
|
||||
private ProcessorTypeDescription _processor;
|
||||
private BuildAction _buildAction;
|
||||
|
||||
#region IProjectItem
|
||||
|
||||
[Browsable(false)]
|
||||
public string OriginalPath { get; set; }
|
||||
|
||||
[Browsable(false)]
|
||||
public string DestinationPath { get; set; }
|
||||
|
||||
[Category("Common")]
|
||||
[Description("The file name of this item.")]
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return System.IO.Path.GetFileName(OriginalPath);
|
||||
}
|
||||
}
|
||||
|
||||
[Category("Common")]
|
||||
[Description("The folder where this item is located.")]
|
||||
public string Location
|
||||
{
|
||||
get
|
||||
{
|
||||
return System.IO.Path.GetDirectoryName(OriginalPath);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
[Category("Settings")]
|
||||
[DisplayName("Build Action")]
|
||||
[Description("The way to process this content item.")]
|
||||
public BuildAction BuildAction
|
||||
{
|
||||
get { return _buildAction; }
|
||||
set
|
||||
{
|
||||
if (_buildAction == value)
|
||||
return;
|
||||
|
||||
_buildAction = value;
|
||||
|
||||
if (Observer != null)
|
||||
Observer.OnItemModified(this);
|
||||
}
|
||||
}
|
||||
|
||||
[Category("Settings")]
|
||||
[Description("The importer used to load the content file.")]
|
||||
[TypeConverter(typeof(ImporterConverter))]
|
||||
public ImporterTypeDescription Importer
|
||||
{
|
||||
get { return _importer; }
|
||||
|
||||
set
|
||||
{
|
||||
if (_importer == value)
|
||||
return;
|
||||
|
||||
_importer = value;
|
||||
ImporterName = _importer.TypeName;
|
||||
|
||||
// Validate that our processor can accept input content of the type output by the new importer.
|
||||
if ((_processor == null || _processor.InputType != _importer.OutputType) && _processor != PipelineTypes.MissingProcessor)
|
||||
{
|
||||
// If it cannot, set the default processor.
|
||||
Processor = PipelineTypes.FindProcessor(_importer.DefaultProcessor, _importer);
|
||||
}
|
||||
|
||||
if (Observer != null)
|
||||
Observer.OnItemModified(this);
|
||||
}
|
||||
}
|
||||
|
||||
[Category("Settings")]
|
||||
[Description("The processor used to transform the content for runtime use.")]
|
||||
[TypeConverter(typeof(ProcessorConverter))]
|
||||
public ProcessorTypeDescription Processor
|
||||
{
|
||||
get { return _processor; }
|
||||
|
||||
set
|
||||
{
|
||||
if (_processor == value)
|
||||
return;
|
||||
|
||||
_processor = value;
|
||||
ProcessorName = _processor.TypeName;
|
||||
|
||||
// When the processor changes reset our parameters
|
||||
// to the default for the processor type.
|
||||
ProcessorParams.Clear();
|
||||
foreach (var p in _processor.Properties)
|
||||
{
|
||||
ProcessorParams.Add(p.Name, p.DefaultValue);
|
||||
}
|
||||
|
||||
if (Observer != null)
|
||||
Observer.OnItemModified(this);
|
||||
|
||||
// Note:
|
||||
// There is no need to validate that the new processor can accept input
|
||||
// of the type output by our importer, because that should be handled by
|
||||
// only showing valid processors in the drop-down (eg, within ProcessConverter).
|
||||
}
|
||||
}
|
||||
|
||||
public void ResolveTypes()
|
||||
{
|
||||
if (BuildAction == BuildAction.Copy)
|
||||
{
|
||||
// Copy items do not have importers or processors.
|
||||
_importer = PipelineTypes.NullImporter;
|
||||
_processor = PipelineTypes.NullProcessor;
|
||||
}
|
||||
else
|
||||
{
|
||||
_importer = PipelineTypes.FindImporter(ImporterName, System.IO.Path.GetExtension(OriginalPath));
|
||||
if (_importer != null && (string.IsNullOrEmpty(ImporterName) || ImporterName != _importer.TypeName))
|
||||
ImporterName = _importer.TypeName;
|
||||
|
||||
if (_importer == null)
|
||||
_importer = PipelineTypes.MissingImporter;
|
||||
|
||||
_processor = PipelineTypes.FindProcessor(ProcessorName, _importer);
|
||||
if (_processor != null && (string.IsNullOrEmpty(ProcessorName) || ProcessorName != _processor.TypeName))
|
||||
ProcessorName = _processor.TypeName;
|
||||
|
||||
if (_processor == null)
|
||||
_processor = PipelineTypes.MissingProcessor;
|
||||
|
||||
// ProcessorParams get deserialized as strings
|
||||
// this code converts them to object(s) of their actual type
|
||||
// so that the correct editor appears within the property grid.
|
||||
foreach (var p in _processor.Properties)
|
||||
{
|
||||
if (!ProcessorParams.ContainsKey(p.Name))
|
||||
{
|
||||
ProcessorParams[p.Name] = p.DefaultValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
var src = ProcessorParams[p.Name];
|
||||
if (src != null)
|
||||
{
|
||||
var srcType = src.GetType();
|
||||
|
||||
var converter = PipelineTypes.FindConverter(p.Type);
|
||||
|
||||
// Should we throw an exception here?
|
||||
// This property will actually not be editable in the property grid
|
||||
// since we do not have a type converter for it.
|
||||
if (converter.CanConvertFrom(srcType))
|
||||
{
|
||||
var dst = converter.ConvertFrom(null, CultureInfo.InvariantCulture, src);
|
||||
ProcessorParams[p.Name] = dst;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return System.IO.Path.GetFileName(OriginalPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
public class ContentItemTemplate
|
||||
{
|
||||
public string Label;
|
||||
public string Icon;
|
||||
public string ImporterName;
|
||||
public string ProcessorName;
|
||||
public string TemplateFile;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Label;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using Microsoft.Xna.Framework.Content.Pipeline;
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
/// <summary>
|
||||
/// PropertyDescriptor for delegating get/set calls to more than one component (object).
|
||||
/// </summary>
|
||||
public class MultiTargetPropertyDescriptor : PropertyDescriptor
|
||||
{
|
||||
private readonly Type _propertyType;
|
||||
private readonly Type _componentType;
|
||||
private readonly object[] _targets;
|
||||
private readonly PropertyDescriptor _property;
|
||||
|
||||
public MultiTargetPropertyDescriptor(string propertyName, Type propertyType, Type componentType, PropertyDescriptor property, object[] targets)
|
||||
: base(propertyName, new Attribute[] { })
|
||||
{
|
||||
_propertyType = propertyType;
|
||||
_componentType = componentType;
|
||||
_targets = targets;
|
||||
_property = property;
|
||||
}
|
||||
|
||||
public override object GetValue(object component)
|
||||
{
|
||||
var val = _property.GetValue(_targets[0]);
|
||||
for (var i = 1; i < _targets.Length; i++)
|
||||
{
|
||||
var v = _property.GetValue(_targets[i]);
|
||||
if (!v.Equals(val))
|
||||
return null;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
public override void SetValue(object component, object value)
|
||||
{
|
||||
for (var i = 0; i < _targets.Length; i++)
|
||||
_property.SetValue(_targets[i], value);
|
||||
}
|
||||
|
||||
public override bool CanResetValue(object component) { return true; }
|
||||
public override Type ComponentType { get { return _componentType; } }
|
||||
public override bool IsReadOnly { get { return false; } }
|
||||
public override Type PropertyType { get { return _propertyType; } }
|
||||
public override void ResetValue(object component) { SetValue(component, null); }
|
||||
public override bool ShouldSerializeValue(object component) { return true; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PropertyDescriptor for a named item within an OpaqueDataDictionary.
|
||||
/// </summary>
|
||||
public class OpaqueDataDictionaryElementPropertyDescriptor : PropertyDescriptor
|
||||
{
|
||||
private readonly Type _propertyType;
|
||||
private readonly Type _componentType;
|
||||
private readonly string _propertyName;
|
||||
private readonly OpaqueDataDictionary _target;
|
||||
|
||||
public OpaqueDataDictionaryElementPropertyDescriptor(string propertyName, Type propertyType, OpaqueDataDictionary target)
|
||||
: base(propertyName, new Attribute[] { })
|
||||
{
|
||||
_propertyType = propertyType;
|
||||
_propertyName = propertyName;
|
||||
_componentType = typeof(OpaqueDataDictionary);
|
||||
_target = target;
|
||||
}
|
||||
|
||||
public override object GetValue(object component)
|
||||
{
|
||||
var data = _target ?? (component as OpaqueDataDictionary);
|
||||
if (!data.ContainsKey(_propertyName))
|
||||
return string.Empty;
|
||||
|
||||
return data[_propertyName];
|
||||
}
|
||||
|
||||
public override void SetValue(object component, object value)
|
||||
{
|
||||
var data = _target ?? (component as OpaqueDataDictionary);
|
||||
data[_propertyName] = value;
|
||||
}
|
||||
|
||||
public override bool CanResetValue(object component) { return true; }
|
||||
public override Type ComponentType { get { return _componentType; } }
|
||||
public override bool IsReadOnly { get { return false; } }
|
||||
public override Type PropertyType { get { return _propertyType; } }
|
||||
public override void ResetValue(object component) { SetValue(component, null); }
|
||||
public override bool ShouldSerializeValue(object component) { return true; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PropertyDescriptor which has a fixed value.
|
||||
/// </summary>
|
||||
public class ReadonlyPropertyDescriptor : PropertyDescriptor
|
||||
{
|
||||
private readonly Type _propertyType;
|
||||
private readonly Type _componentType;
|
||||
private readonly object _value;
|
||||
|
||||
public ReadonlyPropertyDescriptor(string propertyName, Type propertyType, Type componentType, object value)
|
||||
: base(propertyName, new Attribute[] {})
|
||||
{
|
||||
_propertyType = propertyType;
|
||||
_componentType = componentType;
|
||||
_value = value;
|
||||
}
|
||||
|
||||
public override object GetValue(object component)
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
|
||||
public override bool CanResetValue(object component)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public override Type ComponentType
|
||||
{
|
||||
get { return _componentType; }
|
||||
}
|
||||
|
||||
public override bool IsReadOnly
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public override Type PropertyType
|
||||
{
|
||||
get { return _propertyType; }
|
||||
}
|
||||
|
||||
public override void ResetValue(object component)
|
||||
{
|
||||
}
|
||||
|
||||
public override void SetValue(object component, object value)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool ShouldSerializeValue(object component)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
public class DirectoryItem : IProjectItem
|
||||
{
|
||||
public DirectoryItem(string name, string location) : this(location + Path.DirectorySeparatorChar + name)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public DirectoryItem(string path)
|
||||
{
|
||||
OriginalPath = path.Trim(Path.DirectorySeparatorChar).Replace(Path.DirectorySeparatorChar, '/');
|
||||
Exists = true;
|
||||
}
|
||||
|
||||
#region IProjectItem
|
||||
|
||||
[Browsable(false)]
|
||||
public string OriginalPath { get; set; }
|
||||
|
||||
[Category("Common")]
|
||||
[Description("The file name of this item.")]
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.GetFileName(OriginalPath);
|
||||
}
|
||||
}
|
||||
|
||||
[Category("Common")]
|
||||
[Description("The folder where this item is located.")]
|
||||
public string Location
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.GetDirectoryName(OriginalPath);
|
||||
}
|
||||
}
|
||||
|
||||
[Browsable(false)]
|
||||
public bool Exists { get; set; }
|
||||
|
||||
[Browsable(false)]
|
||||
public bool ExpandToThis { get; set; }
|
||||
|
||||
[Browsable(false)]
|
||||
public bool SelectThis { get; set; }
|
||||
|
||||
[Browsable(false)]
|
||||
public string DestinationPath
|
||||
{
|
||||
get { return OriginalPath; }
|
||||
set { OriginalPath = value; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
public static class Extensions
|
||||
{
|
||||
public static bool NullOrEmpty(this IList list)
|
||||
{
|
||||
if (list == null || list.Count == 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
public enum FileType
|
||||
{
|
||||
Base,
|
||||
File,
|
||||
Folder
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
public interface IContentItemObserver
|
||||
{
|
||||
void OnItemModified(ContentItem item);
|
||||
}
|
||||
|
||||
public interface IController : IContentItemObserver
|
||||
{
|
||||
/// <summary>
|
||||
/// Types of content which can be created and added to a project.
|
||||
/// </summary>
|
||||
IEnumerable<ContentItemTemplate> Templates { get; }
|
||||
|
||||
List<IProjectItem> SelectedItems { get; }
|
||||
|
||||
IProjectItem SelectedItem { get; }
|
||||
|
||||
PipelineProject ProjectItem { get; }
|
||||
|
||||
/// <summary>
|
||||
/// True if there is a project.
|
||||
/// </summary>
|
||||
bool ProjectOpen { get; }
|
||||
|
||||
/// <summary>
|
||||
/// True if the project has unsaved changes.
|
||||
/// </summary>
|
||||
bool ProjectDirty { get; }
|
||||
|
||||
/// <summary>
|
||||
/// True if the project is actively building.
|
||||
/// </summary>
|
||||
bool ProjectBuilding { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The view this controller is attached to.
|
||||
/// </summary>
|
||||
IView View { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Triggered when the project starts loading.
|
||||
/// </summary>
|
||||
event Action OnProjectLoading;
|
||||
|
||||
/// <summary>
|
||||
/// Triggered when the project finishes loading.
|
||||
/// </summary>
|
||||
event Action OnProjectLoaded;
|
||||
|
||||
/// <summary>
|
||||
/// Notify controller that a property of Project or its contents has been modified.
|
||||
/// </summary>
|
||||
void OnProjectModified();
|
||||
|
||||
/// <summary>
|
||||
/// Notify controller that Project.References has been modified.
|
||||
/// </summary>
|
||||
void OnReferencesModified();
|
||||
|
||||
void NewProject();
|
||||
|
||||
void ImportProject();
|
||||
|
||||
void OpenProject();
|
||||
|
||||
void OpenProject(string projectFilePath);
|
||||
|
||||
void ClearRecentList();
|
||||
|
||||
void CloseProject();
|
||||
|
||||
bool SaveProject(bool saveAs);
|
||||
|
||||
void Build(bool rebuild);
|
||||
|
||||
void RebuildItems();
|
||||
|
||||
void Clean();
|
||||
|
||||
void CancelBuild();
|
||||
|
||||
bool Exit();
|
||||
|
||||
#region ContentItem
|
||||
|
||||
void DragDrop(string initialDirectory, string[] folders, string[] files);
|
||||
|
||||
void Include();
|
||||
|
||||
void IncludeFolder();
|
||||
|
||||
void Exclude(bool delete);
|
||||
|
||||
void NewItem();
|
||||
|
||||
void NewFolder();
|
||||
|
||||
void Rename();
|
||||
|
||||
void AddAction(IProjectAction action);
|
||||
|
||||
void SelectionChanged(List<IProjectItem> items);
|
||||
|
||||
IProjectItem GetItem(string originalPath);
|
||||
|
||||
void CopyAssetPath();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Undo, Redo
|
||||
|
||||
bool CanRedo { get; }
|
||||
|
||||
bool CanUndo { get; }
|
||||
|
||||
void Undo();
|
||||
|
||||
void Redo();
|
||||
|
||||
#endregion
|
||||
|
||||
string GetFullPath(string filePath);
|
||||
|
||||
string GetRelativePath(string filePath);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
public interface IProjectAction
|
||||
{
|
||||
bool Do();
|
||||
bool Undo();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
public interface IProjectItem
|
||||
{
|
||||
string OriginalPath { get; set; }
|
||||
string Name { get; }
|
||||
string Location { get; }
|
||||
string DestinationPath { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
public interface IProjectObserver
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
public enum AskResult
|
||||
{
|
||||
Yes,
|
||||
No,
|
||||
Cancel
|
||||
}
|
||||
|
||||
public interface IView
|
||||
{
|
||||
void Attach(IController controller);
|
||||
|
||||
void Invoke(Action action);
|
||||
|
||||
AskResult AskSaveOrCancel();
|
||||
|
||||
bool AskSaveName(ref string filePath, string title);
|
||||
|
||||
bool AskOpenProject(out string projectFilePath);
|
||||
|
||||
bool AskImportProject(out string projectFilePath);
|
||||
|
||||
void ShowError(string title, string message);
|
||||
|
||||
void ShowMessage(string message);
|
||||
|
||||
bool ShowDeleteDialog(List<IProjectItem> items);
|
||||
|
||||
bool ShowEditDialog(string title, string text, string oldname, bool file, out string newname);
|
||||
|
||||
void BeginTreeUpdate();
|
||||
|
||||
void SetTreeRoot(IProjectItem item);
|
||||
|
||||
void AddTreeItem(IProjectItem item);
|
||||
|
||||
void RemoveTreeItem(IProjectItem item);
|
||||
|
||||
void UpdateTreeItem(IProjectItem item);
|
||||
|
||||
void EndTreeUpdate();
|
||||
|
||||
void UpdateProperties();
|
||||
|
||||
void OutputAppend(string text);
|
||||
|
||||
void OutputClear();
|
||||
|
||||
bool ChooseContentFile(string initialDirectory, out List<string> files);
|
||||
|
||||
bool ChooseContentFolder(string initialDirectory, out string folder);
|
||||
|
||||
bool ChooseItemTemplate(string folder, out ContentItemTemplate template, out string name);
|
||||
|
||||
bool CopyOrLinkFile(string file, bool exists, out IncludeType action, out bool applyforall);
|
||||
|
||||
bool CopyOrLinkFolder(string folder, bool exists, out IncludeType action, out bool applyforall);
|
||||
|
||||
Process CreateProcess(string exe, string commands);
|
||||
|
||||
void UpdateCommands(MenuInfo info);
|
||||
|
||||
void UpdateRecentList(List<string> recentList);
|
||||
|
||||
void SetClipboard(string text);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
public enum IncludeType
|
||||
{
|
||||
Skip,
|
||||
Copy,
|
||||
Link,
|
||||
Create
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This class is used for IncludeAction file handling.
|
||||
/// </summary>
|
||||
public class IncludeItem
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the source path.
|
||||
/// </summary>
|
||||
/// <value>The source path, should be an absolute path.</value>
|
||||
public string SourcePath { get; set; }
|
||||
|
||||
public IncludeType IncludeType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the relative destination path.
|
||||
/// </summary>
|
||||
/// <value>The relative destination path.</value>
|
||||
public string RelativeDestPath { get; set; }
|
||||
|
||||
public bool IsDirectory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the item template.
|
||||
///
|
||||
/// Only usefull if the action is create and the item is not a directory.
|
||||
/// </summary>
|
||||
/// <value>The item template.</value>
|
||||
public ContentItemTemplate ItemTemplate { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
public class MenuInfo
|
||||
{
|
||||
public bool New { get; set; }
|
||||
|
||||
public bool Open { get; set; }
|
||||
|
||||
public bool Close { get; set; }
|
||||
|
||||
public bool Import { get; set; }
|
||||
|
||||
public bool Save { get; set; }
|
||||
|
||||
public bool SaveAs { get; set; }
|
||||
|
||||
public bool Exit { get; set; }
|
||||
|
||||
public bool Undo { get; set; }
|
||||
|
||||
public bool Redo { get; set; }
|
||||
|
||||
public bool Add { get; set; }
|
||||
|
||||
public bool Exclude { get; set; }
|
||||
|
||||
public bool Rename { get; set; }
|
||||
|
||||
public bool Delete { get; set; }
|
||||
|
||||
public bool BuildMenu { get; set; }
|
||||
|
||||
public bool Build { get; set; }
|
||||
|
||||
public bool Rebuild { get; set; }
|
||||
|
||||
public bool Clean { get; set; }
|
||||
|
||||
public bool Cancel { get; set; }
|
||||
|
||||
public bool Debug { get; set; }
|
||||
|
||||
public bool OpenItem { get; set; }
|
||||
|
||||
public bool OpenItemWith { get; set; }
|
||||
|
||||
public bool OpenItemLocation { get; set; }
|
||||
|
||||
public bool OpenOutputItemLocation { get; set; }
|
||||
|
||||
public bool CopyAssetPath { get; set; }
|
||||
|
||||
public bool RebuildItem { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
public enum OutputState
|
||||
{
|
||||
Initialized,
|
||||
BuildBegin,
|
||||
Cleaning,
|
||||
Skipping,
|
||||
BuildAsset,
|
||||
BuildError,
|
||||
BuildWarning,
|
||||
BuildErrorContinue,
|
||||
BuildEnd,
|
||||
BuildTime,
|
||||
BuildTerminated,
|
||||
|
||||
Unknown
|
||||
}
|
||||
|
||||
public class OutputParser
|
||||
{
|
||||
internal OutputState State { get; private set; }
|
||||
internal String Filename { get; private set; }
|
||||
internal String ErrorMessage { get; private set; }
|
||||
internal String BuildBeginTime { get; private set; }
|
||||
internal String BuildInfo { get; private set; }
|
||||
internal String BuildElapsedTime { get; private set; }
|
||||
|
||||
|
||||
Regex _reBuildBegin = new Regex(@"^(Build started)\W+(?<buildBeginTime>.*?)\r?$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Regex _reCleaning = new Regex(@"^(Cleaning)\W(?<filename>.*?)\r?$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Regex _reSkipping = new Regex(@"^(Skipping)\W(?<filename>.*?)\r?$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Regex _reBuildAsset = new Regex(@"^(?<filename>([a-zA-Z]:)?/.+?)\r?$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Regex _reBuildError = new Regex(@"^(?<filename>([a-zA-Z]:)?/.+?)\W*?:\W*?error\W*?:\W*(?<errorMessage>.*?)\r?$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Regex _reFileErrorWithLineNum = new Regex(@"^(?<filename>.+?)(\((?<line>[0-9]+),(?<column>[0-9]+)(-(?<columnEnd>[0-9]+))?\))?:\W*?(error)\W*(?<errorCode>[A-Z][0-9]+):\W*(?<errorMessage>.*?)\r?$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Regex _reFileWarningWithLineNum = new Regex(@"^(?<filename>.+?)(\((?<line>[0-9]+),(?<column>[0-9]+)(-(?<columnEnd>[0-9]+))?\))?:\W*?(warning)\W*(?<warningCode>[A-Z][0-9]+):\W*(?<warningMessage>.*?)\r?$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Regex _reFileError = new Regex(@"^(?<filename>([a-zA-Z]:)?/.+?)\W*?: (?<errorMessage>.*?)\r?$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Regex _reBuildEnd = new Regex(@"^(Build)\W+(?<buildInfo>.*?)\r?$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
Regex _reBuildTime = new Regex(@"^(Time elapsed)\W+(?<buildElapsedTime>.*?)\.\r?$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
|
||||
public OutputParser()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
internal void Reset()
|
||||
{
|
||||
State = OutputState.Initialized;
|
||||
Filename = null;
|
||||
BuildBeginTime = null;
|
||||
BuildInfo = null;
|
||||
BuildElapsedTime = null;
|
||||
ErrorMessage = null;
|
||||
}
|
||||
|
||||
internal void Parse(string text)
|
||||
{
|
||||
ParseLine(text);
|
||||
}
|
||||
|
||||
|
||||
private void ParseLine(string line)
|
||||
{
|
||||
/*
|
||||
* Line <-- BuildBegin
|
||||
* Line <-- BuildEnd
|
||||
* Line <-- BuildTime
|
||||
* Line <-- Cleaning
|
||||
* Line <-- Skipping
|
||||
* Line <-- BuildError (BuildErrorContinue)+
|
||||
* Line <-- BuildAsset
|
||||
* BuildBegin <-- "Build" "started" buildBeginTime
|
||||
* Cleaning <-- "Cleaning" filenane
|
||||
* Skipping <-- "Skipping" filenane
|
||||
* BuildAsset <-- filename
|
||||
* BuildError <-- filename ':' "Error" ':' errorMessage
|
||||
* BuildErrorContinue <-- errorMessage
|
||||
* BuildEnd <-- "Build" buildInfo
|
||||
* BuildTime <-- "Time" "elapsed" buildElapsedTime
|
||||
*/
|
||||
|
||||
var prevState = State;
|
||||
var prevFilename = Filename;
|
||||
|
||||
State = OutputState.Unknown;
|
||||
Filename = null;
|
||||
BuildBeginTime = null;
|
||||
BuildInfo = null;
|
||||
BuildElapsedTime = null;
|
||||
ErrorMessage = null;
|
||||
|
||||
if (line == "Build terminated!")
|
||||
{
|
||||
State = OutputState.BuildTerminated;
|
||||
}
|
||||
else if (_reBuildBegin.IsMatch(line))
|
||||
{
|
||||
State = OutputState.BuildBegin;
|
||||
var m = _reBuildBegin.Match(line);
|
||||
BuildBeginTime = m.Groups["buildBeginTime"].Value;
|
||||
}
|
||||
else if (_reBuildEnd.IsMatch(line))
|
||||
{
|
||||
State = OutputState.BuildEnd;
|
||||
var m = _reBuildEnd.Match(line);
|
||||
BuildInfo = m.Groups["buildInfo"].Value;
|
||||
}
|
||||
else if (_reBuildTime.IsMatch(line))
|
||||
{
|
||||
State = OutputState.BuildTime;
|
||||
var m = _reBuildTime.Match(line);
|
||||
BuildElapsedTime = m.Groups["buildElapsedTime"].Value;
|
||||
}
|
||||
else if (_reCleaning.IsMatch(line))
|
||||
{
|
||||
State = OutputState.Cleaning;
|
||||
var m = _reCleaning.Match(line);
|
||||
Filename = m.Groups["filename"].Value;
|
||||
}
|
||||
else if (_reSkipping.IsMatch(line))
|
||||
{
|
||||
State = OutputState.Skipping;
|
||||
var m = _reSkipping.Match(line);
|
||||
Filename = m.Groups["filename"].Value;
|
||||
}
|
||||
else if (_reBuildError.IsMatch(line))
|
||||
{
|
||||
State = OutputState.BuildError;
|
||||
var m = _reBuildError.Match(line);
|
||||
Filename = m.Groups["filename"].Value;
|
||||
ErrorMessage = m.Groups["errorMessage"].Value;
|
||||
}
|
||||
else if (_reFileErrorWithLineNum.IsMatch(line))
|
||||
{
|
||||
State = OutputState.BuildError;
|
||||
var m = _reFileErrorWithLineNum.Match(line);
|
||||
var lineNum = m.Groups["line"];
|
||||
var columnBegin = m.Groups["column"];
|
||||
var columnEnd = m.Groups["columnEnd"];
|
||||
var column = columnBegin.Value;
|
||||
if(columnEnd.Success)
|
||||
column += "-" + columnEnd.Value;
|
||||
var errorCode = m.Groups["errorCode"];
|
||||
Filename = m.Groups["filename"].Value.Replace("\\\\","/").Replace("\\", "/");
|
||||
ErrorMessage = string.Format("{0} ({1},{2}): {3}", errorCode, lineNum, column, m.Groups["errorMessage"].Value);
|
||||
}
|
||||
else if (_reFileWarningWithLineNum.IsMatch(line))
|
||||
{
|
||||
State = OutputState.BuildWarning;
|
||||
var m = _reFileWarningWithLineNum.Match(line);
|
||||
var lineNum = m.Groups["line"];
|
||||
var columnBegin = m.Groups["column"];
|
||||
var columnEnd = m.Groups["columnEnd"];
|
||||
var column = columnBegin.Value;
|
||||
if(columnEnd.Success)
|
||||
column += "-" + columnEnd.Value;
|
||||
var errorCode = m.Groups["warningCode"];
|
||||
Filename = m.Groups["filename"].Value.Replace("\\\\", "/").Replace("\\", "/");
|
||||
ErrorMessage = string.Format("{0} ({1},{2}): {3}", errorCode, lineNum, column, m.Groups["warningMessage"].Value);
|
||||
}
|
||||
else if (_reFileError.IsMatch(line))
|
||||
{
|
||||
State = OutputState.BuildError;
|
||||
var m = _reFileError.Match(line);
|
||||
Filename = m.Groups["filename"].Value;
|
||||
ErrorMessage = m.Groups["errorMessage"].Value;
|
||||
}
|
||||
else if (_reBuildAsset.IsMatch(line))
|
||||
{
|
||||
State = OutputState.BuildAsset;
|
||||
var m = _reBuildAsset.Match(line);
|
||||
Filename = m.Groups["filename"].Value;
|
||||
}
|
||||
else if (prevState == OutputState.BuildError || prevState == OutputState.BuildErrorContinue)
|
||||
{
|
||||
State = OutputState.BuildErrorContinue;
|
||||
Filename = prevFilename;
|
||||
ErrorMessage = line.TrimEnd();
|
||||
}
|
||||
else
|
||||
{
|
||||
State = OutputState.Unknown;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
public partial class PipelineController
|
||||
{
|
||||
private class ExcludeAction : IProjectAction
|
||||
{
|
||||
private readonly PipelineController _con;
|
||||
private readonly List<IProjectItem> _items;
|
||||
private readonly List<ContentItem> _subitems;
|
||||
private readonly bool _delete;
|
||||
|
||||
public ExcludeAction(PipelineController controller, List<IProjectItem> items, bool delete)
|
||||
{
|
||||
_items = new List<IProjectItem>();
|
||||
_subitems = new List<ContentItem>();
|
||||
|
||||
_con = controller;
|
||||
_items.AddRange(items);
|
||||
_delete = delete;
|
||||
|
||||
foreach (var item in items)
|
||||
if (item is DirectoryItem)
|
||||
foreach (var citem in _con._project.ContentItems)
|
||||
if (citem.OriginalPath.StartsWith(item.OriginalPath))
|
||||
_subitems.Add(citem);
|
||||
}
|
||||
|
||||
public bool Do()
|
||||
{
|
||||
_con.View.BeginTreeUpdate();
|
||||
|
||||
foreach (var item in _items)
|
||||
{
|
||||
if (item is ContentItem)
|
||||
_con._project.ContentItems.Remove(item as ContentItem);
|
||||
_con.View.RemoveTreeItem(item);
|
||||
|
||||
if (_delete)
|
||||
{
|
||||
// Only delete if the item is in the project folder, otherwise we may (and have done!) delete files/folders outside of the project
|
||||
if (!item.OriginalPath.Contains(".."))
|
||||
{
|
||||
var fullItemPath = _con.GetFullPath(item.OriginalPath);
|
||||
try
|
||||
{
|
||||
if (item is DirectoryItem)
|
||||
Directory.Delete(_con.GetFullPath(item.OriginalPath), true);
|
||||
else
|
||||
File.Delete(_con.GetFullPath(item.OriginalPath));
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
// No error needed in case file is not found
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_con.View.ShowError("Error while trying to delete the file", ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var sitem in _subitems)
|
||||
_con._project.ContentItems.Remove(sitem);
|
||||
|
||||
//Since these items are removed from the project, manually clear the selection
|
||||
_con.SelectedItems.Clear();
|
||||
_con.SelectionChanged(_con.SelectedItems);
|
||||
|
||||
_con.View.EndTreeUpdate();
|
||||
_con.ProjectDirty = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Undo()
|
||||
{
|
||||
if (_delete)
|
||||
return false;
|
||||
|
||||
_con.View.BeginTreeUpdate();
|
||||
|
||||
foreach (var item in _items)
|
||||
{
|
||||
if(item is ContentItem)
|
||||
_con._project.ContentItems.Add(item as ContentItem);
|
||||
_con.View.AddTreeItem(item);
|
||||
}
|
||||
|
||||
foreach (var item in _subitems)
|
||||
{
|
||||
_con._project.ContentItems.Add(item);
|
||||
_con.View.AddTreeItem(item);
|
||||
}
|
||||
|
||||
_con.View.EndTreeUpdate();
|
||||
_con.ProjectDirty = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System;
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
public partial class PipelineController
|
||||
{
|
||||
private class IncludeAction : IProjectAction
|
||||
{
|
||||
private readonly PipelineController _con;
|
||||
private readonly List<IncludeItem> _includes;
|
||||
private readonly List<IProjectItem> _items;
|
||||
private bool _firsttime;
|
||||
|
||||
public IncludeAction(List<IncludeItem> includes)
|
||||
{
|
||||
_items = new List<IProjectItem>();
|
||||
_con = Instance;
|
||||
_includes = includes;
|
||||
_firsttime = true;
|
||||
}
|
||||
|
||||
public IncludeAction(IncludeItem item) : this(new List<IncludeItem> { item })
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prepares the item list and creates all the neccecary files.
|
||||
/// </summary>
|
||||
public void FirstDo()
|
||||
{
|
||||
var parser = new PipelineProjectParser(_con, _con._project);
|
||||
|
||||
for (int i = 0; i < _includes.Count; i++)
|
||||
{
|
||||
var item = _includes[i].IsDirectory ?
|
||||
(IProjectItem)new DirectoryItem("") : new ContentItem();
|
||||
|
||||
if (_includes[i].IncludeType == IncludeType.Create ||
|
||||
_includes[i].IncludeType == IncludeType.Link)
|
||||
{
|
||||
item.OriginalPath = Util.GetRelativePath(_includes[i].SourcePath, _con.ProjectLocation);
|
||||
item.DestinationPath = _includes[i].RelativeDestPath;
|
||||
|
||||
if (_includes[i].IncludeType == IncludeType.Create)
|
||||
{
|
||||
if (_includes[i].IsDirectory)
|
||||
Directory.CreateDirectory(_includes[i].SourcePath);
|
||||
else
|
||||
{
|
||||
var conitem = item as ContentItem;
|
||||
var template = _includes[i].ItemTemplate;
|
||||
|
||||
conitem.ImporterName = template.ImporterName;
|
||||
conitem.ProcessorName = template.ProcessorName;
|
||||
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(_includes[i].SourcePath));
|
||||
File.Copy(template.TemplateFile, _includes[i].SourcePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!_includes[i].IsDirectory) // This is only a valid action for files
|
||||
{
|
||||
var sourcePath = _includes[i].SourcePath;
|
||||
var destPath = Path.Combine(_con.ProjectLocation, _includes[i].RelativeDestPath);
|
||||
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(destPath));
|
||||
File.Copy(sourcePath, destPath);
|
||||
|
||||
item.OriginalPath = item.DestinationPath = _includes[i].RelativeDestPath;
|
||||
}
|
||||
|
||||
var citem = item as ContentItem;
|
||||
if (citem != null)
|
||||
{
|
||||
citem.ProcessorParams = new Microsoft.Xna.Framework.Content.Pipeline.OpaqueDataDictionary();
|
||||
citem.Observer = _con;
|
||||
|
||||
citem.ResolveTypes();
|
||||
}
|
||||
|
||||
// Always keep Unix slashes in the .mgcb files for cross platform compatibility
|
||||
item.OriginalPath = item.OriginalPath.Replace('\\', '/');
|
||||
item.DestinationPath = item.DestinationPath.Replace('\\', '/');
|
||||
|
||||
_items.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Do()
|
||||
{
|
||||
if (_firsttime)
|
||||
{
|
||||
// Generate file list and populate item list
|
||||
_firsttime = false;
|
||||
|
||||
try
|
||||
{
|
||||
FirstDo();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_con.View.ShowError(
|
||||
"Include Action Error",
|
||||
"The include action has failed for the following reason: " +
|
||||
Environment.NewLine + ex
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
_con.View.BeginTreeUpdate();
|
||||
|
||||
foreach (var item in _items)
|
||||
{
|
||||
if (item is ContentItem)
|
||||
_con._project.ContentItems.Add(item as ContentItem);
|
||||
|
||||
_con.View.AddTreeItem(item);
|
||||
}
|
||||
|
||||
_con.View.EndTreeUpdate();
|
||||
_con.ProjectDirty = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Undo()
|
||||
{
|
||||
_con.View.BeginTreeUpdate();
|
||||
|
||||
foreach (var item in _items)
|
||||
{
|
||||
if (item is ContentItem)
|
||||
_con._project.ContentItems.Remove(item as ContentItem);
|
||||
|
||||
_con.View.RemoveTreeItem(item);
|
||||
}
|
||||
|
||||
_con.View.EndTreeUpdate();
|
||||
_con.ProjectDirty = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System.IO;
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
public partial class PipelineController
|
||||
{
|
||||
private class MoveAction : IProjectAction
|
||||
{
|
||||
private IProjectItem _item;
|
||||
private readonly PipelineController _con;
|
||||
private string _oldname, _newname;
|
||||
|
||||
public MoveAction(IProjectItem item, string newname)
|
||||
{
|
||||
_con = PipelineController.Instance;
|
||||
_oldname = Path.GetFileName(item.OriginalPath);
|
||||
_newname = newname;
|
||||
_item = item;
|
||||
}
|
||||
|
||||
public bool Do()
|
||||
{
|
||||
_con.View.RemoveTreeItem(_item);
|
||||
var folder = Path.GetDirectoryName(_item.DestinationPath);
|
||||
_item.DestinationPath = Path.Combine(folder, _newname).Replace('\\', '/');
|
||||
_con.View.AddTreeItem(_item);
|
||||
_con.ProjectDirty = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Undo()
|
||||
{
|
||||
_con.View.RemoveTreeItem(_item);
|
||||
var folder = Path.GetDirectoryName(_item.DestinationPath);
|
||||
_item.DestinationPath = Path.Combine(folder, _oldname).Replace('\\', '/');
|
||||
_con.View.AddTreeItem(_item);
|
||||
_con.ProjectDirty = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
public class UpdateProcessorAction : IProjectAction
|
||||
{
|
||||
private readonly IView _view;
|
||||
private readonly List<ContentItem> _objects;
|
||||
private readonly string _property;
|
||||
|
||||
private List<object> _values;
|
||||
|
||||
public UpdateProcessorAction(IView view, List<ContentItem> objects, string property, object value)
|
||||
{
|
||||
_view = view;
|
||||
_objects = objects;
|
||||
_property = property;
|
||||
|
||||
_values = new List<object>();
|
||||
for (int i = 0; i < _objects.Count; i++)
|
||||
_values.Add(value);
|
||||
}
|
||||
|
||||
public bool Do()
|
||||
{
|
||||
Toggle();
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Undo()
|
||||
{
|
||||
Toggle();
|
||||
return true;
|
||||
}
|
||||
|
||||
private void Toggle()
|
||||
{
|
||||
var oldValues = new List<object>();
|
||||
|
||||
for (int i = 0; i < _objects.Count; i++)
|
||||
{
|
||||
var obj = _objects[i];
|
||||
|
||||
oldValues.Add(obj.ProcessorParams[_property]);
|
||||
obj.ProcessorParams[_property] = _values[i];
|
||||
}
|
||||
|
||||
_view.UpdateProperties();
|
||||
_values = oldValues;
|
||||
}
|
||||
}
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
public class UpdatePropertyAction : IProjectAction
|
||||
{
|
||||
private readonly IView _view;
|
||||
private readonly List<object> _objects;
|
||||
private readonly PropertyInfo _property;
|
||||
|
||||
private List<object> _values;
|
||||
|
||||
public UpdatePropertyAction(IView view, List<object> objects, PropertyInfo property, object value)
|
||||
{
|
||||
_view = view;
|
||||
_objects = objects;
|
||||
_property = property;
|
||||
|
||||
_values = new List<object>();
|
||||
for (int i = 0; i < _objects.Count; i++)
|
||||
_values.Add(value);
|
||||
}
|
||||
|
||||
public bool Do()
|
||||
{
|
||||
Toggle();
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Undo()
|
||||
{
|
||||
Toggle();
|
||||
return true;
|
||||
}
|
||||
|
||||
private void Toggle()
|
||||
{
|
||||
var oldValues = new List<object>();
|
||||
|
||||
for (int i = 0; i < _objects.Count; i++)
|
||||
{
|
||||
var obj = _objects[i];
|
||||
|
||||
oldValues.Add(_property.GetValue(obj, null));
|
||||
_property.SetValue(obj, _values[i], null);
|
||||
}
|
||||
|
||||
_view.UpdateProperties();
|
||||
_values = oldValues;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,89 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using Microsoft.Xna.Framework.Content.Pipeline;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
public class PipelineProject : IProjectItem
|
||||
{
|
||||
[Browsable(false)]
|
||||
public string OriginalPath { get; set; }
|
||||
|
||||
[Browsable(false)]
|
||||
public string DestinationPath { get; set; }
|
||||
|
||||
[Browsable(false)]
|
||||
public List<ContentItem> ContentItems { get; private set; }
|
||||
|
||||
[Browsable(false)]
|
||||
public bool LaunchDebugger { get; set; }
|
||||
|
||||
public string OutputDir { get; set; }
|
||||
|
||||
public string IntermediateDir { get; set; }
|
||||
|
||||
public List<string> References { get; set; }
|
||||
|
||||
public TargetPlatform Platform { get; set; }
|
||||
|
||||
public GraphicsProfile Profile { get; set; }
|
||||
|
||||
public string Config { get; set; }
|
||||
|
||||
public bool Compress { get; set; }
|
||||
|
||||
#region IPipelineItem
|
||||
|
||||
[Category("Common")]
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(OriginalPath))
|
||||
return "";
|
||||
|
||||
return System.IO.Path.GetFileNameWithoutExtension(OriginalPath);
|
||||
}
|
||||
}
|
||||
|
||||
[Category("Common")]
|
||||
public string Location
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(OriginalPath))
|
||||
return "";
|
||||
|
||||
var idx = OriginalPath.LastIndexOfAny(new char[] {Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar}, OriginalPath.Length - 1);
|
||||
return OriginalPath.Remove(idx);
|
||||
}
|
||||
}
|
||||
|
||||
[Browsable(false)]
|
||||
public bool Exists { get; set; }
|
||||
|
||||
[Browsable(false)]
|
||||
public bool ExpandToThis { get; set; }
|
||||
|
||||
[Browsable(false)]
|
||||
public bool SelectThis { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
public PipelineProject()
|
||||
{
|
||||
ContentItems = new List<ContentItem>();
|
||||
References = new List<string>();
|
||||
OutputDir = "bin";
|
||||
IntermediateDir = "obj";
|
||||
Exists = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,586 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using MGCB;
|
||||
using Microsoft.Xna.Framework.Content.Pipeline;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using PathHelper = MonoGame.Framework.Content.Pipeline.Builder.PathHelper;
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
public class PipelineProjectParser
|
||||
{
|
||||
#region Other Data
|
||||
|
||||
private readonly PipelineProject _project;
|
||||
private readonly IContentItemObserver _observer;
|
||||
private readonly OpaqueDataDictionary _processorParams = new OpaqueDataDictionary();
|
||||
|
||||
private string _processor;
|
||||
|
||||
#endregion
|
||||
|
||||
#region CommandLineParameters
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "outputDir",
|
||||
ValueName = "directoryPath",
|
||||
Description = "The directory where all content is written.")]
|
||||
public string OutputDir { set { _project.OutputDir = value; } }
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "intermediateDir",
|
||||
ValueName = "directoryPath",
|
||||
Description = "The directory where all intermediate files are written.")]
|
||||
public string IntermediateDir { set { _project.IntermediateDir = value; } }
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "reference",
|
||||
ValueName = "assemblyNameOrFile",
|
||||
Description = "Adds an assembly reference for resolving content importers, processors, and writers.")]
|
||||
public List<string> References
|
||||
{
|
||||
set { _project.References = value; }
|
||||
get { return _project.References; }
|
||||
}
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "platform",
|
||||
ValueName = "targetPlatform",
|
||||
Description = "Set the target platform for this build. Defaults to Windows.")]
|
||||
public TargetPlatform Platform { set { _project.Platform = value; } }
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "profile",
|
||||
ValueName = "graphicsProfile",
|
||||
Description = "Set the target graphics profile for this build. Defaults to HiDef.")]
|
||||
public GraphicsProfile Profile { set { _project.Profile = value; } }
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "config",
|
||||
ValueName = "string",
|
||||
Description = "The optional build config string from the build system.")]
|
||||
public string Config { set { _project.Config = value; } }
|
||||
|
||||
#pragma warning disable 414
|
||||
|
||||
// Allow a MGCB file containing the /rebuild parameter to be imported without error
|
||||
[CommandLineParameter(
|
||||
Name = "rebuild",
|
||||
ValueName = "bool",
|
||||
Description = "Forces a rebuild of the project.")]
|
||||
public bool Rebuild { set { _rebuild = value; } }
|
||||
private bool _rebuild;
|
||||
|
||||
// Allow a MGCB file containing the /clean parameter to be imported without error
|
||||
[CommandLineParameter(
|
||||
Name = "clean",
|
||||
ValueName = "bool",
|
||||
Description = "Removes intermediate and output files.")]
|
||||
public bool Clean { set { _clean = value; } }
|
||||
private bool _clean;
|
||||
|
||||
#pragma warning restore 414
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "compress",
|
||||
ValueName = "bool",
|
||||
Description = "Content files can be compressed for smaller file sizes.")]
|
||||
public bool Compress { set { _project.Compress = value; } }
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "importer",
|
||||
ValueName = "className",
|
||||
Description = "Defines the class name of the content importer for reading source content.")]
|
||||
public string Importer;
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "processor",
|
||||
ValueName = "className",
|
||||
Description = "Defines the class name of the content processor for processing imported content.")]
|
||||
public string Processor
|
||||
{
|
||||
get { return _processor; }
|
||||
set
|
||||
{
|
||||
_processor = value;
|
||||
_processorParams.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "processorParam",
|
||||
ValueName = "name=value",
|
||||
Description = "Defines a parameter name and value to set on a content processor.")]
|
||||
public void AddProcessorParam(string nameAndValue)
|
||||
{
|
||||
var keyAndValue = nameAndValue.Split('=');
|
||||
if (keyAndValue.Length != 2)
|
||||
{
|
||||
// Do we error out or something?
|
||||
return;
|
||||
}
|
||||
|
||||
_processorParams.Remove(keyAndValue[0]);
|
||||
_processorParams.Add(keyAndValue[0], keyAndValue[1]);
|
||||
}
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "build",
|
||||
ValueName = "sourceFile",
|
||||
Description = "Build the content source file using the previously set switches and options.")]
|
||||
public void OnBuild(string sourceFile)
|
||||
{
|
||||
AddContent(sourceFile, false);
|
||||
}
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "launchDebugger",
|
||||
ValueName = "sourceFile")]
|
||||
public void OnDebug()
|
||||
{
|
||||
_project.LaunchDebugger = true;
|
||||
}
|
||||
|
||||
public bool AddContent(string sourceFile, bool skipDuplicates)
|
||||
{
|
||||
string link = null;
|
||||
|
||||
if (sourceFile.Contains(";"))
|
||||
{
|
||||
var split = sourceFile.Split(';');
|
||||
sourceFile = split[0];
|
||||
|
||||
if (split.Length > 0)
|
||||
link = split[1];
|
||||
}
|
||||
|
||||
// Make sure the source file is relative to the project.
|
||||
var projectDir = ProjectDirectory + Path.DirectorySeparatorChar;
|
||||
|
||||
sourceFile = PathHelper.GetRelativePath(projectDir, sourceFile);
|
||||
|
||||
// Do we have a duplicate?
|
||||
var previous = _project.ContentItems.FindIndex(e => string.Equals(e.OriginalPath, sourceFile, StringComparison.InvariantCultureIgnoreCase));
|
||||
if (previous != -1)
|
||||
{
|
||||
if (skipDuplicates)
|
||||
return false;
|
||||
|
||||
// Replace the duplicate.
|
||||
_project.ContentItems.RemoveAt(previous);
|
||||
}
|
||||
|
||||
// Create the item for processing later.
|
||||
var item = new ContentItem
|
||||
{
|
||||
Observer = _observer,
|
||||
BuildAction = BuildAction.Build,
|
||||
OriginalPath = sourceFile,
|
||||
DestinationPath = string.IsNullOrEmpty(link) ? sourceFile : link,
|
||||
ImporterName = Importer,
|
||||
ProcessorName = Processor,
|
||||
ProcessorParams = new OpaqueDataDictionary()
|
||||
};
|
||||
_project.ContentItems.Add(item);
|
||||
|
||||
// Copy the current processor parameters blind as we
|
||||
// will validate and remove invalid parameters during
|
||||
// the build process later.
|
||||
foreach (var pair in _processorParams)
|
||||
item.ProcessorParams.Add(pair.Key, pair.Value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[CommandLineParameter(
|
||||
Name = "copy",
|
||||
ValueName = "sourceFile",
|
||||
Description = "Copy the content source file verbatim to the output directory.")]
|
||||
public void OnCopy(string sourceFile)
|
||||
{
|
||||
string link = null;
|
||||
|
||||
if (sourceFile.Contains(";"))
|
||||
{
|
||||
var split = sourceFile.Split(';');
|
||||
sourceFile = split[0];
|
||||
|
||||
if (split.Length > 0)
|
||||
link = split[1];
|
||||
}
|
||||
|
||||
// Make sure the source file is relative to the project.
|
||||
var projectDir = ProjectDirectory + Path.DirectorySeparatorChar;
|
||||
|
||||
sourceFile = PathHelper.GetRelativePath(projectDir, sourceFile);
|
||||
|
||||
// Remove duplicates... keep this new one.
|
||||
var previous = _project.ContentItems.FirstOrDefault(e => e.OriginalPath.Equals(sourceFile));
|
||||
if (previous != null)
|
||||
_project.ContentItems.Remove(previous);
|
||||
|
||||
// Create the item for processing later.
|
||||
var item = new ContentItem
|
||||
{
|
||||
BuildAction = BuildAction.Copy,
|
||||
OriginalPath = sourceFile,
|
||||
DestinationPath = string.IsNullOrEmpty(link) ? sourceFile : link,
|
||||
ProcessorParams = new OpaqueDataDictionary()
|
||||
};
|
||||
_project.ContentItems.Add(item);
|
||||
|
||||
// Copy the current processor parameters blind as we
|
||||
// will validate and remove invalid parameters during
|
||||
// the build process later.
|
||||
foreach (var pair in _processorParams)
|
||||
item.ProcessorParams.Add(pair.Key, pair.Value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public PipelineProjectParser(IContentItemObserver observer, PipelineProject project)
|
||||
{
|
||||
_observer = observer;
|
||||
_project = project;
|
||||
}
|
||||
|
||||
public void OpenProject(string projectFilePath, MGBuildParser.ErrorCallback errorCallback)
|
||||
{
|
||||
_project.ContentItems.Clear();
|
||||
|
||||
// Store the file name for saving later.
|
||||
_project.OriginalPath = projectFilePath;
|
||||
|
||||
var parser = new MGBuildParser(this);
|
||||
parser.Title = "Pipeline";
|
||||
|
||||
if (errorCallback != null)
|
||||
parser.OnError += errorCallback;
|
||||
|
||||
var commands = new string[]
|
||||
{
|
||||
string.Format("/@:{0}", projectFilePath),
|
||||
};
|
||||
parser.Parse(commands);
|
||||
}
|
||||
|
||||
public void SaveProject()
|
||||
{
|
||||
using (var io = File.CreateText(_project.OriginalPath))
|
||||
SaveProject(io, null);
|
||||
}
|
||||
|
||||
public void SaveProject(TextWriter io, Func<ContentItem, bool> filterItem)
|
||||
{
|
||||
const string lineFormat = "/{0}:{1}";
|
||||
const string processorParamFormat = "{0}={1}";
|
||||
string line;
|
||||
|
||||
line = FormatDivider("Global Properties");
|
||||
io.WriteLine(line);
|
||||
|
||||
line = string.Format(lineFormat, "outputDir", _project.OutputDir);
|
||||
io.WriteLine(line);
|
||||
|
||||
line = string.Format(lineFormat, "intermediateDir", _project.IntermediateDir);
|
||||
io.WriteLine(line);
|
||||
|
||||
line = string.Format(lineFormat, "platform", _project.Platform);
|
||||
io.WriteLine(line);
|
||||
|
||||
line = string.Format(lineFormat, "config", _project.Config);
|
||||
io.WriteLine(line);
|
||||
|
||||
line = string.Format(lineFormat, "profile", _project.Profile);
|
||||
io.WriteLine(line);
|
||||
|
||||
line = string.Format(lineFormat, "compress", _project.Compress);
|
||||
io.WriteLine(line);
|
||||
|
||||
if (_project.LaunchDebugger)
|
||||
io.WriteLine("/launchdebugger");
|
||||
|
||||
line = FormatDivider("References");
|
||||
io.WriteLine(line);
|
||||
|
||||
foreach (var i in _project.References)
|
||||
{
|
||||
line = string.Format(lineFormat, "reference", i);
|
||||
io.WriteLine(line);
|
||||
}
|
||||
|
||||
line = FormatDivider("Content");
|
||||
io.WriteLine(line);
|
||||
|
||||
// Sort the items alphabetically to ensure a consistent output
|
||||
// and better mergability of the resulting MGCB file.
|
||||
var sortedItems = _project.ContentItems.OrderBy(c => c.OriginalPath, StringComparer.InvariantCulture);
|
||||
|
||||
foreach (var i in sortedItems)
|
||||
{
|
||||
// Reject any items that don't pass the filter.
|
||||
if (filterItem != null && filterItem(i))
|
||||
continue;
|
||||
|
||||
// Wrap content item lines with a begin comment line
|
||||
// to make them more cohesive (for version control).
|
||||
line = string.Format("#begin {0}", i.OriginalPath);
|
||||
io.WriteLine(line);
|
||||
|
||||
if (i.BuildAction == BuildAction.Copy)
|
||||
{
|
||||
string path = i.OriginalPath;
|
||||
if (i.OriginalPath != i.DestinationPath)
|
||||
path += ";" + i.DestinationPath;
|
||||
line = string.Format(lineFormat, "copy", path);
|
||||
io.WriteLine(line);
|
||||
io.WriteLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// Write importer.
|
||||
{
|
||||
line = string.Format(lineFormat, "importer", i.ImporterName);
|
||||
io.WriteLine(line);
|
||||
}
|
||||
|
||||
// Write processor.
|
||||
{
|
||||
line = string.Format(lineFormat, "processor", i.ProcessorName);
|
||||
io.WriteLine(line);
|
||||
}
|
||||
|
||||
// Write processor parameters.
|
||||
{
|
||||
if (i.Processor == PipelineTypes.MissingProcessor)
|
||||
{
|
||||
// Could still be missing the real processor.
|
||||
// If so, write the string parameters from import.
|
||||
foreach (var j in i.ProcessorParams)
|
||||
{
|
||||
line = string.Format(lineFormat, "processorParam", string.Format(processorParamFormat, j.Key, j.Value));
|
||||
io.WriteLine(line);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise, write only values which are defined by the real processor.
|
||||
foreach (var j in i.Processor.Properties)
|
||||
{
|
||||
object value = null;
|
||||
if (i.ProcessorParams.ContainsKey(j.Name))
|
||||
value = i.ProcessorParams[j.Name];
|
||||
|
||||
// JCF: I 'think' writting an empty string for null would be appropriate but to be on the safe side
|
||||
// im just not writting the value at all.
|
||||
if (value != null)
|
||||
{
|
||||
var converter = PipelineTypes.FindConverter(value.GetType());
|
||||
var valueStr = converter.ConvertTo(null, CultureInfo.InvariantCulture, value, typeof(string));
|
||||
line = string.Format(lineFormat, "processorParam", string.Format(processorParamFormat, j.Name, valueStr));
|
||||
io.WriteLine(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string buildValue = i.OriginalPath;
|
||||
if (i.OriginalPath != i.DestinationPath)
|
||||
buildValue += ";" + i.DestinationPath;
|
||||
line = string.Format(lineFormat, "build", buildValue);
|
||||
io.WriteLine(line);
|
||||
io.WriteLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ImportProject(string projectFilePath)
|
||||
{
|
||||
_project.OriginalPath = projectFilePath.Remove(projectFilePath.LastIndexOf('.')) + ".mgcb";
|
||||
|
||||
using (var io = XmlReader.Create(File.OpenText(projectFilePath)))
|
||||
{
|
||||
while (io.Read())
|
||||
{
|
||||
if (io.NodeType == XmlNodeType.Element)
|
||||
{
|
||||
var buildAction = io.LocalName;
|
||||
if (buildAction.Equals("Reference"))
|
||||
{
|
||||
string include, hintPath;
|
||||
ReadIncludeReference(io, out include, out hintPath);
|
||||
|
||||
if (!string.IsNullOrEmpty(hintPath) &&
|
||||
hintPath.IndexOf("microsoft", StringComparison.CurrentCultureIgnoreCase) == -1 &&
|
||||
hintPath.IndexOf("monogamecontentprocessors", StringComparison.CurrentCultureIgnoreCase) == -1)
|
||||
{
|
||||
_project.References.Add(hintPath);
|
||||
}
|
||||
}
|
||||
else if (buildAction.Equals("Content") || buildAction.Equals("None"))
|
||||
{
|
||||
string include, copyToOutputDirectory;
|
||||
ReadIncludeContent(io, out include, out copyToOutputDirectory);
|
||||
|
||||
if (!string.IsNullOrEmpty(copyToOutputDirectory) && !copyToOutputDirectory.Equals("Never"))
|
||||
{
|
||||
var sourceFilePath = Path.GetDirectoryName(projectFilePath);
|
||||
sourceFilePath += "\\" + include;
|
||||
|
||||
OnCopy(sourceFilePath);
|
||||
}
|
||||
}
|
||||
else if (buildAction.Equals("Compile"))
|
||||
{
|
||||
string include, name, importer, processor;
|
||||
string[] processorParams;
|
||||
ReadIncludeCompile(io, out include, out name, out importer, out processor, out processorParams);
|
||||
|
||||
Importer = importer;
|
||||
Processor = processor;
|
||||
if (processorParams != null)
|
||||
{
|
||||
foreach (var i in processorParams)
|
||||
AddProcessorParam(i);
|
||||
}
|
||||
|
||||
var sourceFilePath = Path.GetDirectoryName(projectFilePath);
|
||||
sourceFilePath += "\\" + include;
|
||||
|
||||
OnBuild(sourceFilePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string ProjectDirectory
|
||||
{
|
||||
get
|
||||
{
|
||||
return _project.Location;
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadIncludeReference(XmlReader io, out string include, out string hintPath)
|
||||
{
|
||||
include = io.GetAttribute("Include").Unescape();
|
||||
hintPath = null;
|
||||
|
||||
if (!io.IsEmptyElement)
|
||||
{
|
||||
var depth = io.Depth;
|
||||
for (io.Read(); io.Depth != depth; io.Read())
|
||||
{
|
||||
// process sub nodes
|
||||
if (io.IsStartElement("HintPath"))
|
||||
{
|
||||
io.Read();
|
||||
hintPath = io.Value.Unescape();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadIncludeContent(XmlReader io, out string include, out string copyToOutputDirectory)
|
||||
{
|
||||
copyToOutputDirectory = null;
|
||||
include = io.GetAttribute("Include").Unescape();
|
||||
|
||||
if (!io.IsEmptyElement)
|
||||
{
|
||||
var depth = io.Depth;
|
||||
for (io.Read(); io.Depth != depth; io.Read())
|
||||
{
|
||||
// process sub nodes here.
|
||||
|
||||
if (io.IsStartElement())
|
||||
{
|
||||
switch (io.LocalName)
|
||||
{
|
||||
case "CopyToOutputDirectory":
|
||||
io.Read();
|
||||
copyToOutputDirectory = io.Value.Unescape();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadIncludeCompile(XmlReader io,
|
||||
out string include,
|
||||
out string name,
|
||||
out string importer,
|
||||
out string processor,
|
||||
out string[] processorParams)
|
||||
{
|
||||
name = null;
|
||||
importer = null;
|
||||
processor = null;
|
||||
|
||||
include = io.GetAttribute("Include").Unescape();
|
||||
var parameters = new List<string>();
|
||||
|
||||
if (!io.IsEmptyElement)
|
||||
{
|
||||
var depth = io.Depth;
|
||||
for (io.Read(); io.Depth != depth; io.Read())
|
||||
{
|
||||
// process sub nodes here.
|
||||
|
||||
if (io.IsStartElement())
|
||||
{
|
||||
switch (io.LocalName)
|
||||
{
|
||||
case "Name":
|
||||
io.Read();
|
||||
name = io.Value.Unescape();
|
||||
break;
|
||||
case "Importer":
|
||||
io.Read();
|
||||
importer = io.Value.Unescape();
|
||||
break;
|
||||
case "Processor":
|
||||
io.Read();
|
||||
processor = io.Value.Unescape();
|
||||
break;
|
||||
default:
|
||||
if (io.LocalName.Contains("ProcessorParameters_"))
|
||||
{
|
||||
var line = io.LocalName.Replace("ProcessorParameters_", "");
|
||||
line += "=";
|
||||
io.Read();
|
||||
line += io.Value;
|
||||
parameters.Add(line.Unescape());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
processorParams = parameters.ToArray();
|
||||
}
|
||||
|
||||
private string FormatDivider(string label)
|
||||
{
|
||||
var commentFormat = Environment.NewLine + "#----------------------------------------------------------------------------#" + Environment.NewLine;
|
||||
|
||||
label = " " + label + " ";
|
||||
var src = commentFormat.Length / 2 - label.Length / 2;
|
||||
var dst = src + label.Length;
|
||||
|
||||
return commentFormat.Substring(0, src) + label + commentFormat.Substring(dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.IsolatedStorage;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
public class PipelineSettings
|
||||
{
|
||||
private const string SettingsPath = "Settings.xml";
|
||||
private IsolatedStorageFile _isoStore;
|
||||
private bool _isoStoreInit;
|
||||
|
||||
public static PipelineSettings Default { get; private set; }
|
||||
|
||||
public List<string> ProjectHistory;
|
||||
public string StartupProject;
|
||||
public Microsoft.Xna.Framework.Point Size;
|
||||
public int HSeparator, VSeparator;
|
||||
public bool Maximized, DebugMode, PropertyGroupSort;
|
||||
public bool FilterOutput, FilterShowSkipped, FilterShowSuccessful, FilterShowCleaned, AutoScrollBuildOutput;
|
||||
public string ErrorMessage;
|
||||
|
||||
static PipelineSettings()
|
||||
{
|
||||
Default = new PipelineSettings();
|
||||
}
|
||||
|
||||
public PipelineSettings()
|
||||
{
|
||||
ProjectHistory = new List<string>();
|
||||
|
||||
PropertyGroupSort = true;
|
||||
FilterOutput = true;
|
||||
FilterShowSkipped = true;
|
||||
FilterShowSuccessful = true;
|
||||
FilterShowCleaned = true;
|
||||
AutoScrollBuildOutput = true;
|
||||
|
||||
try
|
||||
{
|
||||
_isoStore = IsolatedStorageFile.GetStore(IsolatedStorageScope.User | IsolatedStorageScope.Assembly, null, null);
|
||||
_isoStoreInit = true;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If the project already exists in history, it will be moved to the end.
|
||||
/// </summary>
|
||||
public void AddProjectHistory(string file)
|
||||
{
|
||||
var cleanFile = file.Trim();
|
||||
ProjectHistory.Remove(cleanFile);
|
||||
ProjectHistory.Add(cleanFile);
|
||||
}
|
||||
|
||||
public void RemoveProjectHistory(string file)
|
||||
{
|
||||
var cleanFile = file.Trim();
|
||||
ProjectHistory.Remove(cleanFile);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
ProjectHistory.Clear();
|
||||
StartupProject = null;
|
||||
Save();
|
||||
}
|
||||
|
||||
public void Save()
|
||||
{
|
||||
if (!_isoStoreInit)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
var mode = FileMode.CreateNew;
|
||||
if (_isoStore.FileExists(SettingsPath))
|
||||
mode = FileMode.Truncate;
|
||||
|
||||
using (var isoStream = new IsolatedStorageFileStream(SettingsPath, mode, _isoStore))
|
||||
{
|
||||
using (var writer = new StreamWriter(isoStream))
|
||||
{
|
||||
var serializer = new XmlSerializer(typeof(PipelineSettings));
|
||||
serializer.Serialize(writer, this);
|
||||
}
|
||||
}
|
||||
} catch { }
|
||||
}
|
||||
|
||||
public void Load()
|
||||
{
|
||||
if (!_isoStoreInit)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
if (_isoStore.FileExists(SettingsPath))
|
||||
{
|
||||
using (var isoStream = new IsolatedStorageFileStream(SettingsPath, FileMode.Open, _isoStore))
|
||||
{
|
||||
using (var reader = new StreamReader(isoStream))
|
||||
{
|
||||
var serializer = new XmlSerializer(typeof(PipelineSettings));
|
||||
Default = (PipelineSettings)serializer.Deserialize(reader);
|
||||
|
||||
var history = Default.ProjectHistory.ToArray();
|
||||
foreach (var h in history)
|
||||
if (!File.Exists(h))
|
||||
Default.ProjectHistory.Remove(h);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
Save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,548 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Content.Pipeline;
|
||||
using Microsoft.Xna.Framework.Content.Pipeline.Builder.Convertors;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System.Diagnostics;
|
||||
using MonoGame.Framework.Content.Pipeline.Builder;
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
public class ImporterTypeDescription
|
||||
{
|
||||
public string TypeName;
|
||||
public string DisplayName;
|
||||
public string DefaultProcessor;
|
||||
public IEnumerable<string> FileExtensions;
|
||||
public Type OutputType;
|
||||
|
||||
public ImporterTypeDescription()
|
||||
{
|
||||
TypeName = "Invalid / Missing Importer";
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return TypeName;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return TypeName == null ? 0 : TypeName.GetHashCode();
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
var other = obj as ImporterTypeDescription;
|
||||
if (other == null)
|
||||
return false;
|
||||
|
||||
if (string.IsNullOrEmpty(other.TypeName) != string.IsNullOrEmpty(TypeName))
|
||||
return false;
|
||||
|
||||
return TypeName.Equals(other.TypeName);
|
||||
}
|
||||
};
|
||||
|
||||
public class ProcessorTypeDescription
|
||||
{
|
||||
#region Supporting Types
|
||||
|
||||
public struct Property
|
||||
{
|
||||
public string Name;
|
||||
public string DisplayName;
|
||||
public Type Type;
|
||||
public object DefaultValue;
|
||||
public bool Browsable;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
|
||||
public class ProcessorPropertyCollection : IEnumerable<Property>
|
||||
{
|
||||
private readonly Property[] _properties;
|
||||
|
||||
public ProcessorPropertyCollection(IEnumerable<Property> properties)
|
||||
{
|
||||
_properties = properties.ToArray();
|
||||
}
|
||||
|
||||
public Property this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
return _properties[index];
|
||||
}
|
||||
set
|
||||
{
|
||||
_properties[index] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public Property this[string name]
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (var p in _properties)
|
||||
{
|
||||
if (p.Name.Equals(name))
|
||||
return p;
|
||||
}
|
||||
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
for (var i = 0; i < _properties.Length; i++)
|
||||
{
|
||||
var p = _properties[i];
|
||||
if (p.Name.Equals(name))
|
||||
{
|
||||
_properties[i] = value;
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
public bool Contains(string name)
|
||||
{
|
||||
return _properties.Any(e => e.Name == name);
|
||||
}
|
||||
|
||||
public IEnumerator<Property> GetEnumerator()
|
||||
{
|
||||
return _properties.AsEnumerable().GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return _properties.GetEnumerator();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public string TypeName;
|
||||
public string DisplayName;
|
||||
public ProcessorPropertyCollection Properties;
|
||||
public Type InputType;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return TypeName;
|
||||
}
|
||||
};
|
||||
|
||||
internal class PipelineTypes
|
||||
{
|
||||
[DebuggerDisplay("ImporterInfo: {Type.Name}")]
|
||||
private struct ImporterInfo
|
||||
{
|
||||
public ContentImporterAttribute Attribute;
|
||||
public Type Type;
|
||||
}
|
||||
|
||||
[DebuggerDisplay("ProcessorInfo: {Type.Name}")]
|
||||
private struct ProcessorInfo
|
||||
{
|
||||
public ContentProcessorAttribute Attribute;
|
||||
public Type Type;
|
||||
}
|
||||
|
||||
private static List<ImporterInfo> _importers;
|
||||
private static List<ProcessorInfo> _processors;
|
||||
private static List<FileSystemWatcher> _watchers;
|
||||
private static string _currentAssemblyDirectory;
|
||||
|
||||
public static ImporterTypeDescription[] Importers { get; private set; }
|
||||
public static ProcessorTypeDescription[] Processors { get; private set; }
|
||||
|
||||
public static ImporterTypeDescription NullImporter { get; private set; }
|
||||
public static ProcessorTypeDescription NullProcessor { get; private set; }
|
||||
|
||||
public static ImporterTypeDescription MissingImporter { get; private set; }
|
||||
public static ProcessorTypeDescription MissingProcessor { get; private set; }
|
||||
|
||||
public static TypeConverter.StandardValuesCollection ImportersStandardValuesCollection { get; private set; }
|
||||
public static TypeConverter.StandardValuesCollection ProcessorsStandardValuesCollection { get; private set; }
|
||||
|
||||
private static readonly Dictionary<string, string> _oldNameRemap = new Dictionary<string, string>()
|
||||
{
|
||||
{ "MGMaterialProcessor", "MaterialProcessor" },
|
||||
{ "MGSongProcessor", "SongProcessor" },
|
||||
{ "MGSoundEffectProcessor", "SoundEffectProcessor" },
|
||||
{ "MGSpriteFontDescriptionProcessor", "FontDescriptionProcessor" },
|
||||
{ "MGSpriteFontTextureProcessor", "FontTextureProcessor" },
|
||||
{ "MGTextureProcessor", "TextureProcessor" },
|
||||
{ "MGEffectProcessor", "EffectProcessor" },
|
||||
};
|
||||
|
||||
private static string RemapOldNames(string name)
|
||||
{
|
||||
if (_oldNameRemap.ContainsKey(name))
|
||||
return _oldNameRemap[name];
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
static PipelineTypes()
|
||||
{
|
||||
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
|
||||
|
||||
MissingImporter = new ImporterTypeDescription()
|
||||
{
|
||||
DisplayName = "Invalid / Missing Importer",
|
||||
};
|
||||
|
||||
MissingProcessor = new ProcessorTypeDescription()
|
||||
{
|
||||
DisplayName = "Invalid / Missing Processor",
|
||||
Properties = new ProcessorTypeDescription.ProcessorPropertyCollection(new ProcessorTypeDescription.Property[0]),
|
||||
};
|
||||
|
||||
NullImporter = new ImporterTypeDescription()
|
||||
{
|
||||
DisplayName = "",
|
||||
};
|
||||
|
||||
NullProcessor = new ProcessorTypeDescription()
|
||||
{
|
||||
DisplayName = "",
|
||||
Properties = new ProcessorTypeDescription.ProcessorPropertyCollection(new ProcessorTypeDescription.Property[0]),
|
||||
};
|
||||
|
||||
_watchers = new List<FileSystemWatcher>();
|
||||
}
|
||||
|
||||
private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
|
||||
{
|
||||
if (string.IsNullOrEmpty(_currentAssemblyDirectory))
|
||||
return null;
|
||||
|
||||
var path = Path.Combine(_currentAssemblyDirectory, (new AssemblyName(args.Name).Name) + ".dll");
|
||||
if (!File.Exists(path))
|
||||
return null;
|
||||
|
||||
return Assembly.Load(File.ReadAllBytes(path));
|
||||
}
|
||||
|
||||
public static void Load(PipelineProject project)
|
||||
{
|
||||
Unload();
|
||||
|
||||
var assemblyPaths = new List<string>();
|
||||
|
||||
var projectRoot = project.Location;
|
||||
|
||||
foreach (var i in project.References)
|
||||
{
|
||||
var path = Path.Combine(projectRoot, i);
|
||||
|
||||
if (string.IsNullOrEmpty(path))
|
||||
throw new ArgumentException("assemblyFilePath cannot be null!");
|
||||
if (!Path.IsPathRooted(path))
|
||||
throw new ArgumentException("assemblyFilePath must be absolute!");
|
||||
|
||||
// Make sure we're not adding the same assembly twice.
|
||||
path = PathHelper.Normalize(path);
|
||||
if (!assemblyPaths.Contains(path))
|
||||
assemblyPaths.Add(path);
|
||||
}
|
||||
|
||||
ResolveAssemblies(assemblyPaths);
|
||||
|
||||
var importerDescriptions = new ImporterTypeDescription[_importers.Count];
|
||||
var cur = 0;
|
||||
foreach (var item in _importers)
|
||||
{
|
||||
// Find the abstract base class ContentImporter<T>.
|
||||
var baseType = item.Type.BaseType;
|
||||
while (!baseType.IsAbstract)
|
||||
baseType = baseType.BaseType;
|
||||
|
||||
var outputType = baseType.GetGenericArguments()[0];
|
||||
var name = item.Attribute.DisplayName;
|
||||
if (string.IsNullOrEmpty(name))
|
||||
name = item.GetType().Name;
|
||||
var desc = new ImporterTypeDescription()
|
||||
{
|
||||
TypeName = item.Type.Name,
|
||||
DisplayName = name,
|
||||
DefaultProcessor = item.Attribute.DefaultProcessor,
|
||||
FileExtensions = item.Attribute.FileExtensions,
|
||||
OutputType = outputType,
|
||||
};
|
||||
importerDescriptions[cur] = desc;
|
||||
cur++;
|
||||
}
|
||||
|
||||
Importers = importerDescriptions;
|
||||
ImportersStandardValuesCollection = new TypeConverter.StandardValuesCollection(Importers);
|
||||
|
||||
var processorDescriptions = new ProcessorTypeDescription[_processors.Count];
|
||||
|
||||
const BindingFlags bindings = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
|
||||
|
||||
cur = 0;
|
||||
foreach (var item in _processors)
|
||||
{
|
||||
var obj = Activator.CreateInstance(item.Type);
|
||||
var typeProperties = item.Type.GetProperties(bindings);
|
||||
var properties = new List<ProcessorTypeDescription.Property>();
|
||||
foreach (var i in typeProperties)
|
||||
{
|
||||
var attrs = i.GetCustomAttributes(true);
|
||||
var name = i.Name;
|
||||
var browsable = true;
|
||||
var defvalue = i.GetValue(obj, null);
|
||||
|
||||
foreach (var a in attrs)
|
||||
{
|
||||
if (a is BrowsableAttribute)
|
||||
browsable = (a as BrowsableAttribute).Browsable;
|
||||
else if (a is DisplayNameAttribute)
|
||||
name = (a as DisplayNameAttribute).DisplayName;
|
||||
}
|
||||
|
||||
var p = new ProcessorTypeDescription.Property()
|
||||
{
|
||||
Name = i.Name,
|
||||
DisplayName = name,
|
||||
Type = i.PropertyType,
|
||||
DefaultValue = defvalue,
|
||||
Browsable = browsable
|
||||
};
|
||||
properties.Add(p);
|
||||
}
|
||||
|
||||
var inputType = (obj as IContentProcessor).InputType;
|
||||
var desc = new ProcessorTypeDescription()
|
||||
{
|
||||
TypeName = item.Type.Name,
|
||||
DisplayName = item.Attribute.DisplayName,
|
||||
Properties = new ProcessorTypeDescription.ProcessorPropertyCollection(properties),
|
||||
InputType = inputType,
|
||||
};
|
||||
if (string.IsNullOrEmpty(desc.DisplayName))
|
||||
desc.DisplayName = desc.TypeName;
|
||||
|
||||
processorDescriptions[cur] = desc;
|
||||
cur++;
|
||||
}
|
||||
|
||||
Processors = processorDescriptions;
|
||||
ProcessorsStandardValuesCollection = new TypeConverter.StandardValuesCollection(Processors);
|
||||
}
|
||||
|
||||
public static void Unload()
|
||||
{
|
||||
foreach (var watch in _watchers)
|
||||
watch.Dispose();
|
||||
_watchers.Clear();
|
||||
|
||||
_importers = null;
|
||||
Importers = null;
|
||||
|
||||
_processors = null;
|
||||
Processors = null;
|
||||
|
||||
ImportersStandardValuesCollection = null;
|
||||
ProcessorsStandardValuesCollection = null;
|
||||
}
|
||||
|
||||
public static TypeConverter FindConverter(Type type)
|
||||
{
|
||||
if (type == typeof(Color))
|
||||
return new StringToColorConverter();
|
||||
|
||||
return TypeDescriptor.GetConverter(type);
|
||||
}
|
||||
|
||||
public static ImporterTypeDescription FindImporter(string name, string fileExtension)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(name))
|
||||
{
|
||||
name = RemapOldNames(name);
|
||||
|
||||
foreach (var i in Importers)
|
||||
{
|
||||
if (i.TypeName.Equals(name))
|
||||
return i;
|
||||
}
|
||||
|
||||
foreach (var i in Importers)
|
||||
{
|
||||
if (i.DisplayName.Equals(name))
|
||||
return i;
|
||||
}
|
||||
|
||||
//Debug.Fail(string.Format("Importer not found! name={0}, ext={1}", name, fileExtension));
|
||||
return null;
|
||||
}
|
||||
|
||||
var lowerFileExt = fileExtension.ToLowerInvariant();
|
||||
foreach (var i in Importers)
|
||||
{
|
||||
if (i.FileExtensions.Any(e => e.ToLowerInvariant() == lowerFileExt))
|
||||
return i;
|
||||
}
|
||||
|
||||
//Debug.Fail(string.Format("Importer not found! name={0}, ext={1}", name, fileExtension));
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ProcessorTypeDescription FindProcessor(string name, ImporterTypeDescription importer)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(name))
|
||||
{
|
||||
name = RemapOldNames(name);
|
||||
|
||||
foreach (var i in Processors)
|
||||
{
|
||||
if (i.TypeName.Equals(name))
|
||||
return i;
|
||||
}
|
||||
|
||||
//Debug.Fail(string.Format("Processor not found! name={0}, importer={1}", name, importer));
|
||||
return null;
|
||||
}
|
||||
|
||||
if (importer != null)
|
||||
{
|
||||
foreach (var i in Processors)
|
||||
{
|
||||
if (i.TypeName.Equals(importer.DefaultProcessor))
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
//Debug.Fail(string.Format("Processor not found! name={0}, importer={1}", name, importer));
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void ResolveAssemblies(IEnumerable<string> assemblyPaths)
|
||||
{
|
||||
_importers = new List<ImporterInfo>();
|
||||
_processors = new List<ProcessorInfo>();
|
||||
|
||||
var assemblies = new List<Assembly>(AppDomain.CurrentDomain.GetAssemblies());
|
||||
|
||||
foreach (var asm in assemblies)
|
||||
{
|
||||
#if SHIPPING
|
||||
try
|
||||
#endif
|
||||
{
|
||||
if (!asm.ToString().Contains("MonoGame"))
|
||||
continue;
|
||||
|
||||
var types = asm.GetTypes();
|
||||
ProcessTypes(types);
|
||||
}
|
||||
#if SHIPPING
|
||||
catch (Exception e)
|
||||
{
|
||||
// ??
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
foreach (var watch in _watchers)
|
||||
watch.Dispose();
|
||||
_watchers.Clear();
|
||||
|
||||
foreach (var path in assemblyPaths)
|
||||
{
|
||||
try
|
||||
{
|
||||
_currentAssemblyDirectory = Path.GetDirectoryName(path);
|
||||
|
||||
var a = Assembly.Load(File.ReadAllBytes(path));
|
||||
var types = a.GetTypes();
|
||||
ProcessTypes(types);
|
||||
|
||||
var watch = new FileSystemWatcher();
|
||||
watch.Path = Path.GetDirectoryName(path);
|
||||
watch.EnableRaisingEvents = true;
|
||||
watch.Filter = Path.GetFileName(path);
|
||||
watch.Changed += (sender, e) =>
|
||||
{
|
||||
if (Path.GetFileName(path) == e.Name)
|
||||
PipelineController.Instance.OnReferencesModified();
|
||||
};
|
||||
watch.Created += (sender, e) =>
|
||||
{
|
||||
if (Path.GetFileName(path) == e.Name)
|
||||
PipelineController.Instance.OnReferencesModified();
|
||||
};
|
||||
|
||||
_watchers.Add(watch);
|
||||
}
|
||||
catch
|
||||
{
|
||||
//Logger.LogWarning(null, null, "Failed to load assembly '{0}': {1}", assemblyPath, e.Message);
|
||||
// The assembly failed to load... nothing
|
||||
// we can do but ignore it.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
_currentAssemblyDirectory = null;
|
||||
}
|
||||
|
||||
private static void ProcessTypes(IEnumerable<Type> types)
|
||||
{
|
||||
foreach (var t in types)
|
||||
{
|
||||
if (t.IsAbstract)
|
||||
continue;
|
||||
|
||||
if (t.GetInterface(@"IContentImporter") == typeof(IContentImporter))
|
||||
{
|
||||
var attributes = t.GetCustomAttributes(typeof(ContentImporterAttribute), false);
|
||||
if (attributes.Length != 0)
|
||||
{
|
||||
var importerAttribute = attributes[0] as ContentImporterAttribute;
|
||||
_importers.Add(new ImporterInfo { Attribute = importerAttribute, Type = t });
|
||||
}
|
||||
else
|
||||
{
|
||||
// If no attribute specify default one
|
||||
var importerAttribute = new ContentImporterAttribute(".*");
|
||||
importerAttribute.DefaultProcessor = "";
|
||||
importerAttribute.DisplayName = t.Name;
|
||||
_importers.Add(new ImporterInfo { Attribute = importerAttribute, Type = t });
|
||||
}
|
||||
}
|
||||
else if (t.GetInterface(@"IContentProcessor") == typeof(IContentProcessor))
|
||||
{
|
||||
var attributes = t.GetCustomAttributes(typeof(ContentProcessorAttribute), false);
|
||||
if (attributes.Length != 0)
|
||||
{
|
||||
var processorAttribute = attributes[0] as ContentProcessorAttribute;
|
||||
_processors.Add(new ProcessorInfo { Attribute = processorAttribute, Type = t });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Xna.Framework.Content.Pipeline;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
/// <summary>
|
||||
/// Snapshot of a PipelineProject's state, used for undo/redo.
|
||||
/// </summary>
|
||||
internal class ProjectState
|
||||
{
|
||||
public string OutputDir;
|
||||
public string IntermediateDir;
|
||||
public List<string> References;
|
||||
public TargetPlatform Platform;
|
||||
public GraphicsProfile Profile;
|
||||
public string Config;
|
||||
public string OriginalPath;
|
||||
|
||||
/// <summary>
|
||||
/// Create a ProjectState storing member values of the passed PipelineProject.
|
||||
/// </summary>
|
||||
public static ProjectState Get(PipelineProject proj)
|
||||
{
|
||||
var state = new ProjectState()
|
||||
{
|
||||
OriginalPath = proj.OriginalPath,
|
||||
OutputDir = proj.OutputDir,
|
||||
IntermediateDir = proj.IntermediateDir,
|
||||
References = new List<string>(proj.References),
|
||||
Platform = proj.Platform,
|
||||
Profile = proj.Profile,
|
||||
Config = proj.Config,
|
||||
};
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set a PipelineProject's member values from this state object.
|
||||
/// </summary>
|
||||
public void Apply(PipelineProject proj)
|
||||
{
|
||||
proj.OutputDir = OutputDir;
|
||||
proj.IntermediateDir = IntermediateDir;
|
||||
proj.References = new List<string>(References);
|
||||
proj.Platform = Platform;
|
||||
proj.Profile = Profile;
|
||||
proj.Config = Config;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Security;
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
public static class StringExtensions
|
||||
{
|
||||
public static string Unescape(this string text)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text))
|
||||
return text;
|
||||
|
||||
var result = Uri.UnescapeDataString(text);
|
||||
|
||||
// JCF: XmlReader already does this.
|
||||
/*
|
||||
result = result.Replace("'", "'");
|
||||
result = result.Replace(""", "\"");
|
||||
result = result.Replace(">", ">");
|
||||
result = result.Replace("&", "&");
|
||||
*/
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
public static class Util
|
||||
{
|
||||
[DllImport("libc")]
|
||||
private static extern string realpath(string path, IntPtr resolved_path);
|
||||
|
||||
public static string GetRealPath(string path)
|
||||
{
|
||||
// resolve symlinks on Unix systems
|
||||
if (Environment.OSVersion.Platform == PlatformID.Unix)
|
||||
return realpath(path, IntPtr.Zero);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the path 'filspec' made relative path 'folder'.
|
||||
///
|
||||
/// If 'folder' is not an absolute path, throws ArgumentException.
|
||||
/// If 'filespec' is not an absolute path, returns 'filespec' unmodified.
|
||||
/// </summary>
|
||||
public static string GetRelativePath(string filespec, string folder)
|
||||
{
|
||||
if (!Path.IsPathRooted(filespec))
|
||||
return filespec;
|
||||
|
||||
if (!Path.IsPathRooted(folder))
|
||||
throw new ArgumentException("Must be an absolute path.", "folder");
|
||||
|
||||
filespec = Path.GetFullPath(filespec).TrimEnd(new[] { '/', '\\' });
|
||||
folder = Path.GetFullPath(folder).TrimEnd(new[] { '/', '\\' });
|
||||
|
||||
if (filespec == folder)
|
||||
return string.Empty;
|
||||
|
||||
var pathUri = new Uri(filespec);
|
||||
var folderUri = new Uri(folder + Path.DirectorySeparatorChar);
|
||||
var result = folderUri.MakeRelativeUri(pathUri).ToString();
|
||||
result = result.Replace('/', Path.DirectorySeparatorChar);
|
||||
result = Uri.UnescapeDataString(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Eto.Drawing;
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
class BuildItem
|
||||
{
|
||||
private const int CellHeight = 32;
|
||||
private const int Spacing = 10;
|
||||
private const int Margin = 10;
|
||||
private const string ArrowCollapse = "▲";
|
||||
private const string ArrowExpand = "▼";
|
||||
private const int ButtonSpacing = 3;
|
||||
|
||||
public string Text { get; set; }
|
||||
public Image Icon { get; set; }
|
||||
public int Height { get; set; }
|
||||
public int RequestedWidth { get; set; }
|
||||
|
||||
public string Description
|
||||
{
|
||||
set
|
||||
{
|
||||
_description.Clear();
|
||||
_description.Add(value);
|
||||
}
|
||||
}
|
||||
|
||||
private readonly float _arrowWidth;
|
||||
private readonly float _textOffset;
|
||||
private readonly float _imageOffset;
|
||||
private readonly float _descSize;
|
||||
|
||||
private List<string> _description;
|
||||
private float _descriptionOffset;
|
||||
private bool _expanded;
|
||||
private bool _selected;
|
||||
|
||||
public BuildItem()
|
||||
{
|
||||
_arrowWidth = SystemFonts.Default().MeasureString(ArrowExpand).Width;
|
||||
_textOffset = (CellHeight - DrawInfo.TextHeight) / 2;
|
||||
_imageOffset = (CellHeight - 16) / 2;
|
||||
_descSize = SystemFonts.Default().LineHeight + 4;
|
||||
|
||||
_description = new List<string>();
|
||||
|
||||
Height = CellHeight;
|
||||
RequestedWidth = 0;
|
||||
}
|
||||
|
||||
public void AddDescription(string text)
|
||||
{
|
||||
_description.Add(text);
|
||||
}
|
||||
|
||||
public void OnClick()
|
||||
{
|
||||
if (_selected && _description.Count != 0)
|
||||
{
|
||||
_expanded = !_expanded;
|
||||
|
||||
if (_expanded)
|
||||
{
|
||||
_descriptionOffset = (_descSize - DrawInfo.TextHeight) / 2;
|
||||
Height = (int)(CellHeight + _descSize * _description.Count);
|
||||
|
||||
foreach (var des in _description)
|
||||
{
|
||||
var width = SystemFonts.Default().MeasureString(des).Width + 4 * Spacing + 16;
|
||||
if (width > RequestedWidth)
|
||||
RequestedWidth = (int)width;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Height = CellHeight;
|
||||
RequestedWidth = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Draw(Graphics g, int y, int width)
|
||||
{
|
||||
var x = Margin;
|
||||
_selected = BuildOutput.MouseLocation.Y > y && BuildOutput.MouseLocation.Y < y + CellHeight;
|
||||
|
||||
// Draw Background
|
||||
g.FillRectangle(DrawInfo.BorderColor, 0, y, width, Height);
|
||||
g.FillRectangle(_selected ? DrawInfo.HoverBackColor : DrawInfo.BorderColor, 0, y, width, CellHeight);
|
||||
|
||||
// Draw Icon
|
||||
g.DrawImage(Icon, x, y + _imageOffset);
|
||||
x += 16 + Spacing;
|
||||
|
||||
// Draw Text
|
||||
g.DrawText(SystemFonts.Default(), DrawInfo.GetTextColor(_selected, false), x, y + _textOffset, Text);
|
||||
|
||||
// Draw Expander
|
||||
if (_description.Count != 0)
|
||||
{
|
||||
//g.FillRectangle(_expandSelected ? DrawInfo.HoverBackColor : DrawInfo.BorderColor, rectangle);
|
||||
g.DrawText(SystemFonts.Default(), DrawInfo.GetTextColor(_selected, false), width - Margin - _arrowWidth, y + _textOffset, _expanded ? ArrowCollapse : ArrowExpand);
|
||||
}
|
||||
|
||||
// Draw Description
|
||||
if (_expanded)
|
||||
{
|
||||
for (int i = 0; i < _description.Count; i++)
|
||||
g.DrawText(SystemFonts.Default(), DrawInfo.DisabledTextColor, x + Spacing, y + CellHeight + _descriptionOffset + _descSize * i, _description[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,308 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Eto.Drawing;
|
||||
using Eto.Forms;
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
public partial class BuildOutput
|
||||
{
|
||||
public static Point MouseLocation;
|
||||
public static int Count;
|
||||
|
||||
private bool _tryScroll, _setHeight;
|
||||
private int _reqWidth = 0;
|
||||
private OutputParser _output;
|
||||
private List<BuildItem> _items;
|
||||
private CheckCommand _cmdFilterOutput, _cmdAutoScroll, _cmdShowSkipped, _cmdShowSuccessful, _cmdShowCleaned;
|
||||
private Image _iconInformation, _iconFail, _iconProcessing, _iconSkip, _iconSucceed, _iconSucceedWithWarnings, _iconStart, _iconEndSucceed, _iconEndFailed;
|
||||
private BuildItem _selectedItem;
|
||||
private Eto.Drawing.Point _scrollPosition;
|
||||
|
||||
public BuildOutput()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
_output = new OutputParser();
|
||||
|
||||
_iconInformation = Global.GetEtoIcon("Build.Information.png");
|
||||
_iconFail = Global.GetEtoIcon("Build.Fail.png");
|
||||
_iconProcessing = Global.GetEtoIcon("Build.Processing.png");
|
||||
_iconSkip = Global.GetEtoIcon("Build.Skip.png");
|
||||
_iconStart = Global.GetEtoIcon("Build.Start.png");
|
||||
_iconEndSucceed = Global.GetEtoIcon("Build.EndSucceed.png");
|
||||
_iconEndFailed = Global.GetEtoIcon("Build.EndFailed.png");
|
||||
_iconSucceed = Global.GetEtoIcon("Build.Succeed.png");
|
||||
_iconSucceedWithWarnings = Global.GetEtoIcon("Build.SucceedWithWarnings.png");
|
||||
|
||||
_items = new List<BuildItem>();
|
||||
|
||||
_cmdFilterOutput = new CheckCommand();
|
||||
_cmdFilterOutput.MenuText = "Filter Output";
|
||||
_cmdFilterOutput.CheckedChanged += CmdFilterOutput_CheckedChanged;
|
||||
AddCommand(_cmdFilterOutput);
|
||||
|
||||
_cmdShowSkipped = new CheckCommand();
|
||||
_cmdShowSkipped.MenuText = "Show Skipped Files";
|
||||
_cmdShowSkipped.CheckedChanged += CmdShowSkipped_CheckedChanged;
|
||||
AddCommand(_cmdShowSkipped);
|
||||
|
||||
_cmdShowSuccessful = new CheckCommand();
|
||||
_cmdShowSuccessful.MenuText = "Show Successfully Built Files";
|
||||
_cmdShowSuccessful.CheckedChanged += CmdShowSuccessful_CheckedChanged;
|
||||
AddCommand(_cmdShowSuccessful);
|
||||
|
||||
_cmdShowCleaned = new CheckCommand();
|
||||
_cmdShowCleaned.MenuText = "Show Cleaned Files";
|
||||
_cmdShowCleaned.CheckedChanged += CmdShowCleaned_CheckedChanged;
|
||||
AddCommand(_cmdShowCleaned);
|
||||
|
||||
_cmdAutoScroll = new CheckCommand();
|
||||
_cmdAutoScroll.MenuText = "Auto Scroll";
|
||||
_cmdAutoScroll.CheckedChanged += CmdAutoScroll_CheckedChanged;
|
||||
AddCommand(_cmdAutoScroll);
|
||||
|
||||
MouseLocation = new Point(-1, -1);
|
||||
}
|
||||
|
||||
public override void LoadSettings()
|
||||
{
|
||||
_cmdFilterOutput.Checked = PipelineSettings.Default.FilterOutput;
|
||||
_cmdShowSkipped.Checked = PipelineSettings.Default.FilterShowSkipped;
|
||||
_cmdShowSuccessful.Checked = PipelineSettings.Default.FilterShowSuccessful;
|
||||
_cmdShowCleaned.Checked = PipelineSettings.Default.FilterShowCleaned;
|
||||
_cmdAutoScroll.Checked = PipelineSettings.Default.AutoScrollBuildOutput;
|
||||
}
|
||||
|
||||
private void CmdFilterOutput_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (_cmdFilterOutput.Checked)
|
||||
drawable.Paint -= Drawable_Paint;
|
||||
|
||||
panel.Content = _cmdFilterOutput.Checked ? (Control)scrollable : textArea;
|
||||
PipelineSettings.Default.FilterOutput = _cmdFilterOutput.Checked;
|
||||
|
||||
if (_cmdFilterOutput.Checked)
|
||||
drawable.Paint += Drawable_Paint;
|
||||
|
||||
drawable.Invalidate();
|
||||
}
|
||||
|
||||
private void CmdShowSkipped_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
PipelineSettings.Default.FilterShowSkipped = _cmdShowSkipped.Checked;
|
||||
drawable.Invalidate();
|
||||
}
|
||||
|
||||
private void CmdShowSuccessful_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
PipelineSettings.Default.FilterShowSuccessful = _cmdShowSuccessful.Checked;
|
||||
drawable.Invalidate();
|
||||
}
|
||||
|
||||
private void CmdShowCleaned_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
PipelineSettings.Default.FilterShowCleaned = _cmdShowCleaned.Checked;
|
||||
drawable.Invalidate();
|
||||
}
|
||||
|
||||
private void CmdAutoScroll_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
PipelineSettings.Default.AutoScrollBuildOutput = _cmdAutoScroll.Checked;
|
||||
}
|
||||
|
||||
public void ClearOutput()
|
||||
{
|
||||
drawable.Width = _reqWidth = 0;
|
||||
scrollable.ScrollPosition = new Point(0, 0);
|
||||
textArea.Text = "";
|
||||
_items.Clear();
|
||||
drawable.Invalidate();
|
||||
}
|
||||
|
||||
public void WriteLine(string line)
|
||||
{
|
||||
textArea.Append(line + Environment.NewLine, _cmdAutoScroll.Checked);
|
||||
|
||||
if (string.IsNullOrEmpty(line))
|
||||
return;
|
||||
|
||||
_output.Parse(line);
|
||||
line = line.Trim(new[] { ' ', '\n', '\r', '\t' });
|
||||
|
||||
switch (_output.State)
|
||||
{
|
||||
case OutputState.BuildBegin:
|
||||
_items.Add(new BuildItem { Text = line, Icon = _iconStart });
|
||||
Count = -1;
|
||||
break;
|
||||
case OutputState.Cleaning:
|
||||
_items.Add(new BuildItem
|
||||
{
|
||||
Text = "Cleaning " + PipelineController.Instance.GetRelativePath(_output.Filename),
|
||||
Icon = _iconInformation,
|
||||
Description = line
|
||||
});
|
||||
break;
|
||||
case OutputState.Skipping:
|
||||
if (_items[_items.Count - 1].Icon == _iconProcessing)
|
||||
_items[_items.Count - 1].Icon = _iconSucceed;
|
||||
|
||||
_items.Add(new BuildItem
|
||||
{
|
||||
Text = "Skipping " + PipelineController.Instance.GetRelativePath(_output.Filename),
|
||||
Icon = _iconSkip,
|
||||
Description = _output.Filename
|
||||
});
|
||||
break;
|
||||
case OutputState.BuildAsset:
|
||||
if (_items[_items.Count - 1].Icon == _iconProcessing)
|
||||
_items[_items.Count - 1].Icon = _iconSucceed;
|
||||
|
||||
_items.Add(new BuildItem
|
||||
{
|
||||
Text = "Building " + PipelineController.Instance.GetRelativePath(_output.Filename),
|
||||
Icon = _iconProcessing,
|
||||
Description = _output.Filename
|
||||
});
|
||||
break;
|
||||
case OutputState.BuildError:
|
||||
_items[_items.Count - 1].Icon = _iconFail;
|
||||
_items[_items.Count - 1].AddDescription(_output.ErrorMessage);
|
||||
break;
|
||||
case OutputState.BuildErrorContinue:
|
||||
_items[_items.Count - 1].AddDescription(_output.ErrorMessage);
|
||||
break;
|
||||
case OutputState.BuildWarning:
|
||||
if (_items[_items.Count - 1].Icon == _iconProcessing)
|
||||
_items[_items.Count - 1].Icon = _iconSucceedWithWarnings;
|
||||
_items[_items.Count - 1].AddDescription(_output.ErrorMessage);
|
||||
break;
|
||||
case OutputState.BuildEnd:
|
||||
if (_items.Count > 0 && _items[_items.Count - 1].Icon == _iconProcessing)
|
||||
_items[_items.Count - 1].Icon = _iconSucceed;
|
||||
|
||||
_items.Add(new BuildItem
|
||||
{
|
||||
Text = line,
|
||||
Icon = line.Contains("0 failed") ? _iconEndSucceed : _iconEndFailed
|
||||
});
|
||||
break;
|
||||
case OutputState.BuildTime:
|
||||
var text = _items[_items.Count - 1].Text.TrimEnd(new[] { '.', ' ' }) + ", " + line;
|
||||
_items[_items.Count - 1].Text = text;
|
||||
Count = _items.Count * 35 - 3;
|
||||
break;
|
||||
case OutputState.BuildTerminated:
|
||||
_items.Add(new BuildItem { Text = line, Icon = _iconEndFailed });
|
||||
break;
|
||||
}
|
||||
|
||||
_setHeight = true;
|
||||
drawable.Invalidate();
|
||||
}
|
||||
|
||||
private void Drawable_MouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
MouseLocation = new Point((int)e.Location.X, (int)e.Location.Y);
|
||||
drawable.Invalidate();
|
||||
}
|
||||
|
||||
private void Drawable_MouseLeave(object sender, MouseEventArgs e)
|
||||
{
|
||||
_selectedItem = null;
|
||||
MouseLocation = new Point(-1, -1);
|
||||
drawable.Invalidate();
|
||||
}
|
||||
|
||||
private void Drawable_MouseDown(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (_selectedItem != null)
|
||||
_selectedItem.OnClick();
|
||||
|
||||
_reqWidth = 0;
|
||||
foreach (var item in _items)
|
||||
if (item.RequestedWidth > _reqWidth)
|
||||
_reqWidth = item.RequestedWidth;
|
||||
|
||||
drawable.Width = _reqWidth;
|
||||
_setHeight = true;
|
||||
drawable.Invalidate();
|
||||
}
|
||||
|
||||
private void Drawable_SizeChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (_tryScroll)
|
||||
{
|
||||
_tryScroll = false;
|
||||
|
||||
if (PipelineSettings.Default.AutoScrollBuildOutput)
|
||||
scrollable.ScrollPosition = new Point(0, drawable.Height + 10 - scrollable.Height);
|
||||
}
|
||||
}
|
||||
|
||||
private void Scrollable1_SizeChanged(object sender, EventArgs e)
|
||||
{
|
||||
drawable.Invalidate();
|
||||
}
|
||||
|
||||
private void Scrollable1_Scroll(object sender, EventArgs e)
|
||||
{
|
||||
_scrollPosition = scrollable.ScrollPosition;
|
||||
drawable.Invalidate();
|
||||
}
|
||||
|
||||
private void Drawable_Paint(object sender, PaintEventArgs e)
|
||||
{
|
||||
var g = e.Graphics;
|
||||
var count = _items.Count;
|
||||
var y = 0;
|
||||
|
||||
g.Clear(DrawInfo.BackColor);
|
||||
|
||||
for (int i = 0; i < _items.Count; i++)
|
||||
{
|
||||
var item = _items[i];
|
||||
|
||||
// Skip Skipped items
|
||||
if (!PipelineSettings.Default.FilterShowSkipped && item.Icon == _iconSkip)
|
||||
continue;
|
||||
|
||||
// Skip Successful items
|
||||
if (!PipelineSettings.Default.FilterShowSuccessful && item.Icon == _iconSucceed)
|
||||
continue;
|
||||
|
||||
// Skip Cleaned items
|
||||
if (!PipelineSettings.Default.FilterShowCleaned && item.Icon == _iconInformation)
|
||||
continue;
|
||||
|
||||
// Check if the item is in the visible rectangle
|
||||
if (y + item.Height >= _scrollPosition.Y && y < _scrollPosition.Y + scrollable.Height)
|
||||
{
|
||||
// Check if the item is selected
|
||||
if (MouseLocation.Y > y && MouseLocation.Y < y + item.Height)
|
||||
_selectedItem = item;
|
||||
|
||||
// Draw item
|
||||
item.Draw(g, y, drawable.Width);
|
||||
}
|
||||
|
||||
// Add border
|
||||
y += item.Height + 3;
|
||||
}
|
||||
|
||||
if (_setHeight)
|
||||
{
|
||||
_setHeight = false;
|
||||
drawable.Size = new Size(_reqWidth, Math.Max(y - 3, 1));
|
||||
}
|
||||
|
||||
if (Count == -1)
|
||||
_tryScroll = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using Eto.Forms;
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
public partial class BuildOutput : Pad
|
||||
{
|
||||
Panel panel;
|
||||
TextArea textArea;
|
||||
Scrollable scrollable;
|
||||
Drawable drawable;
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
Title = "Build Output";
|
||||
|
||||
panel = new Panel();
|
||||
|
||||
textArea = new TextArea();
|
||||
textArea.Wrap = false;
|
||||
textArea.ReadOnly = true;
|
||||
|
||||
scrollable = new Scrollable();
|
||||
scrollable.BackgroundColor = DrawInfo.BackColor;
|
||||
scrollable.ExpandContentWidth = true;
|
||||
scrollable.ExpandContentHeight = true;
|
||||
drawable = new Drawable();
|
||||
scrollable.Content = drawable;
|
||||
|
||||
panel.Content = textArea;
|
||||
CreateContent(panel);
|
||||
|
||||
drawable.MouseDown += Drawable_MouseDown;
|
||||
drawable.MouseMove += Drawable_MouseMove;
|
||||
drawable.MouseLeave += Drawable_MouseLeave;
|
||||
drawable.SizeChanged += Drawable_SizeChanged;
|
||||
drawable.Paint += Drawable_Paint;
|
||||
scrollable.SizeChanged += Scrollable1_SizeChanged;
|
||||
scrollable.Scroll += Scrollable1_Scroll;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using Eto.Drawing;
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
static class DrawInfo
|
||||
{
|
||||
private static bool once;
|
||||
|
||||
public static int TextHeight;
|
||||
public static Color TextColor, BackColor, HoverTextColor, HoverBackColor, DisabledTextColor, BorderColor;
|
||||
|
||||
static DrawInfo()
|
||||
{
|
||||
TextHeight = (int)SystemFonts.Default().LineHeight;
|
||||
TextColor = SystemColors.ControlText;
|
||||
BackColor = SystemColors.ControlBackground;
|
||||
HoverTextColor = SystemColors.HighlightText;
|
||||
HoverBackColor = SystemColors.Highlight;
|
||||
DisabledTextColor = SystemColors.ControlText;
|
||||
DisabledTextColor.A = 0.4f;
|
||||
BorderColor = Global.Unix ? SystemColors.WindowBackground : SystemColors.Control;
|
||||
}
|
||||
|
||||
public static void SetPixelsPerPoint(Graphics g)
|
||||
{
|
||||
if (!once && !Global.Unix)
|
||||
{
|
||||
once = true;
|
||||
TextHeight = (int)(SystemFonts.Default().LineHeight * g.PixelsPerPoint + 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
public static Color GetTextColor(bool selected, bool disabled)
|
||||
{
|
||||
if (disabled)
|
||||
return DisabledTextColor;
|
||||
|
||||
return selected ? HoverTextColor : TextColor;
|
||||
}
|
||||
|
||||
public static Color GetBackgroundColor(bool selected)
|
||||
{
|
||||
return selected ? HoverBackColor : BackColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Eto.Forms;
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
public partial class Pad
|
||||
{
|
||||
public string Title
|
||||
{
|
||||
get { return label.Text; }
|
||||
set { label.Text = value; }
|
||||
}
|
||||
|
||||
public List<Command> Commands;
|
||||
private ContextMenu _contextMenu;
|
||||
|
||||
public Pad()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
Commands = new List<Command>();
|
||||
_contextMenu = new ContextMenu();
|
||||
}
|
||||
|
||||
public virtual void LoadSettings()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void ImageSettings_MouseDown(object sender, MouseEventArgs e)
|
||||
{
|
||||
_contextMenu.Show(imageSettings);
|
||||
}
|
||||
|
||||
public void CreateContent(Control control)
|
||||
{
|
||||
layout.AddRow(control);
|
||||
}
|
||||
|
||||
public void AddCommand(Command com)
|
||||
{
|
||||
imageSettings.Visible = true;
|
||||
|
||||
Commands.Add(com);
|
||||
_contextMenu.Items.Add(com.CreateMenuItem());
|
||||
}
|
||||
|
||||
public void AddCommand(RadioCommand com)
|
||||
{
|
||||
imageSettings.Visible = true;
|
||||
|
||||
Commands.Add(com);
|
||||
_contextMenu.Items.Add(com);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using Eto.Drawing;
|
||||
using Eto.Forms;
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
#if LINUX
|
||||
public partial class Pad : GroupBox
|
||||
#else
|
||||
public partial class Pad : Panel
|
||||
#endif
|
||||
{
|
||||
private DynamicLayout layout;
|
||||
private StackLayout stack;
|
||||
private ImageView imageSettings;
|
||||
private Panel panelLabel;
|
||||
private Label label;
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
layout = new DynamicLayout();
|
||||
|
||||
panelLabel = new Panel();
|
||||
panelLabel.Padding = new Padding(5);
|
||||
|
||||
if (!Global.Unix)
|
||||
panelLabel.Height = 25;
|
||||
|
||||
stack = new StackLayout();
|
||||
stack.Orientation = Orientation.Horizontal;
|
||||
|
||||
label = new Label();
|
||||
label.Font = new Font(label.Font.Family, label.Font.Size - 1, FontStyle.Bold);
|
||||
stack.Items.Add(new StackLayoutItem(label, true));
|
||||
|
||||
imageSettings = new ImageView();
|
||||
imageSettings.Image = Global.GetEtoIcon("Icons.Settings.png");
|
||||
imageSettings.Visible = false;
|
||||
stack.Items.Add(new StackLayoutItem(imageSettings, false));
|
||||
|
||||
panelLabel.Content = stack;
|
||||
|
||||
layout.AddRow(panelLabel);
|
||||
|
||||
Content = layout;
|
||||
|
||||
imageSettings.MouseDown += ImageSettings_MouseDown;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,197 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Eto.Drawing;
|
||||
using Eto.Forms;
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
public partial class ProjectControl : Pad
|
||||
{
|
||||
private TreeGridView _treeView;
|
||||
private Image _iconRoot;
|
||||
private TreeGridItem _treeBase, _treeRoot;
|
||||
private bool _rootExists;
|
||||
private ContextMenu _contextMenu;
|
||||
|
||||
public ProjectControl()
|
||||
{
|
||||
Title = "Project";
|
||||
_treeView = new TreeGridView();
|
||||
_treeView.ShowHeader = false;
|
||||
_treeView.AllowMultipleSelection = true;
|
||||
_treeView.Columns.Add(new GridColumn { DataCell = new ImageTextCell(0, 1), AutoSize = true });
|
||||
_treeView.DataStore = _treeBase = new TreeGridItem();
|
||||
CreateContent(_treeView);
|
||||
|
||||
_iconRoot = Bitmap.FromResource("TreeView.Root.png").WithSize(16, 16);
|
||||
|
||||
_treeView.SelectionChanged += TreeView_SelectedItemChanged;
|
||||
}
|
||||
|
||||
private void TreeView_SelectedItemChanged(object sender, EventArgs e)
|
||||
{
|
||||
var items = new List<IProjectItem>();
|
||||
|
||||
foreach (TreeGridItem selected in _treeView.SelectedItems)
|
||||
if (selected.Tag is IProjectItem)
|
||||
items.Add(selected.Tag as IProjectItem);
|
||||
|
||||
PipelineController.Instance.SelectionChanged(items);
|
||||
}
|
||||
|
||||
public void SetContextMenu(ContextMenu contextMenu)
|
||||
{
|
||||
_contextMenu = contextMenu;
|
||||
}
|
||||
|
||||
public void ExpandBase()
|
||||
{
|
||||
_treeRoot.Expanded = true;
|
||||
}
|
||||
|
||||
public void SetRoot(IProjectItem item)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
_treeView.DataStore = _treeBase = new TreeGridItem();
|
||||
_rootExists = false;
|
||||
_treeView.ContextMenu = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_rootExists)
|
||||
{
|
||||
_treeRoot = new TreeGridItem();
|
||||
_treeBase.Children.Add(_treeRoot);
|
||||
|
||||
_rootExists = true;
|
||||
}
|
||||
|
||||
_treeRoot.SetValue(0, _iconRoot);
|
||||
_treeRoot.SetValue(1, item.Name);
|
||||
_treeRoot.Tag = item;
|
||||
_treeRoot.Expanded = true;
|
||||
|
||||
_treeView.ReloadItem(_treeRoot);
|
||||
_treeView.ContextMenu = _contextMenu;
|
||||
}
|
||||
|
||||
public void AddItem(IProjectItem citem)
|
||||
{
|
||||
AddItem(_treeRoot, citem, citem.DestinationPath, "");
|
||||
}
|
||||
|
||||
public void AddItem(TreeGridItem root, IProjectItem citem, string path, string currentPath)
|
||||
{
|
||||
var split = path.Split('/');
|
||||
var item = GetorAddItem(root, split.Length > 1 ? new DirectoryItem(split[0], currentPath) : citem);
|
||||
|
||||
if (path.Contains("/"))
|
||||
AddItem(item, citem, string.Join("/", split, 1, split.Length - 1), (currentPath + Path.DirectorySeparatorChar + split[0]));
|
||||
}
|
||||
|
||||
public void RemoveItem(IProjectItem item)
|
||||
{
|
||||
TreeGridItem titem;
|
||||
if (FindItem(_treeRoot, item.DestinationPath, out titem))
|
||||
{
|
||||
var parrent = titem.Parent as TreeGridItem;
|
||||
parrent.Children.Remove(titem);
|
||||
_treeView.ReloadItem(parrent);
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateItem(IProjectItem item)
|
||||
{
|
||||
// Does nothing right now
|
||||
}
|
||||
|
||||
private bool FindItem(TreeGridItem root, string path, out TreeGridItem item)
|
||||
{
|
||||
var split = path.Split('/');
|
||||
|
||||
if (GetItem(root, split[0], out item))
|
||||
{
|
||||
if (split.Length != 1)
|
||||
return FindItem(item, string.Join("/", split, 1, split.Length - 1), out item);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool GetItem(TreeGridItem root, string text, out TreeGridItem item)
|
||||
{
|
||||
var enumerator = root.Children.GetEnumerator();
|
||||
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
var citem = enumerator.Current as TreeGridItem;
|
||||
|
||||
if (citem.GetValue(1).ToString() == text)
|
||||
{
|
||||
item = citem;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
item = _treeRoot;
|
||||
return false;
|
||||
}
|
||||
|
||||
private TreeGridItem GetorAddItem(TreeGridItem root, IProjectItem item)
|
||||
{
|
||||
var enumerator = root.Children.GetEnumerator();
|
||||
var folder = item is DirectoryItem;
|
||||
|
||||
var items = new List<string>();
|
||||
int pos = 0;
|
||||
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
var citem = enumerator.Current as TreeGridItem;
|
||||
|
||||
if (citem.GetValue(1).ToString() == Path.GetFileName(item.DestinationPath))
|
||||
return citem;
|
||||
|
||||
if (folder)
|
||||
{
|
||||
if (citem.Tag is DirectoryItem)
|
||||
items.Add(citem.GetValue(1).ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (citem.Tag is DirectoryItem)
|
||||
pos++;
|
||||
else
|
||||
items.Add(citem.GetValue(1).ToString());
|
||||
}
|
||||
}
|
||||
|
||||
items.Add(Path.GetFileName(item.DestinationPath));
|
||||
items.Sort();
|
||||
pos += items.IndexOf(Path.GetFileName(item.DestinationPath));
|
||||
|
||||
var ret = new TreeGridItem();
|
||||
|
||||
if (item is DirectoryItem)
|
||||
ret.SetValue(0, Global.GetEtoDirectoryIcon());
|
||||
else
|
||||
ret.SetValue(0, Global.GetEtoFileIcon(PipelineController.Instance.GetFullPath(item.OriginalPath), item.OriginalPath != item.DestinationPath));
|
||||
|
||||
ret.SetValue(1, Path.GetFileName(item.DestinationPath));
|
||||
ret.Tag = item;
|
||||
|
||||
root.Children.Insert(pos, ret);
|
||||
_treeView.ReloadItem(root);
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using Eto.Drawing;
|
||||
using Eto.Forms;
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true)]
|
||||
public class CellAttribute : Attribute
|
||||
{
|
||||
public string Name;
|
||||
public Type Type;
|
||||
|
||||
public CellAttribute(Type type)
|
||||
{
|
||||
Type = type;
|
||||
}
|
||||
}
|
||||
|
||||
public class CellBase
|
||||
{
|
||||
public string Category { get; set; }
|
||||
public object Value { get; set; }
|
||||
public string DisplayValue { get; set; }
|
||||
public string Text { get; set; }
|
||||
public bool Editable { get; set; }
|
||||
public int Height { get; set; }
|
||||
public Action OnKill;
|
||||
|
||||
protected EventHandler _eventHandler;
|
||||
protected Rectangle _lastRec;
|
||||
protected Type _type;
|
||||
|
||||
public void Create(string category, string name, object value, Type type, EventHandler eventHandler = null)
|
||||
{
|
||||
Category = category;
|
||||
Value = value;
|
||||
DisplayValue = (value == null) ? "" : value.ToString();
|
||||
Text = name;
|
||||
Editable = true;
|
||||
Height = DrawInfo.TextHeight;
|
||||
|
||||
_eventHandler = eventHandler;
|
||||
_type = type;
|
||||
|
||||
OnCreate();
|
||||
}
|
||||
|
||||
public virtual void OnCreate()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public virtual void Edit(PixelLayout control)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public virtual void Draw(Graphics g, Rectangle rec, int separatorPos, bool selected)
|
||||
{
|
||||
if (selected)
|
||||
g.FillRectangle(SystemColors.Highlight, rec);
|
||||
|
||||
g.DrawText(SystemFonts.Default(), DrawInfo.GetTextColor(selected, false), rec.X + 5, rec.Y + (rec.Height - Height) / 2, Text);
|
||||
g.FillRectangle(DrawInfo.GetBackgroundColor(selected), separatorPos - 6, rec.Y, rec.Width, rec.Height);
|
||||
DrawCell(g, rec, separatorPos, selected);
|
||||
}
|
||||
|
||||
public virtual void DrawCell(Graphics g, Rectangle rec, int separatorPos, bool selected)
|
||||
{
|
||||
_lastRec = rec;
|
||||
_lastRec.X += separatorPos;
|
||||
_lastRec.Width -= separatorPos - 1;
|
||||
|
||||
g.DrawText(SystemFonts.Default(), DrawInfo.GetTextColor(selected, !Editable), separatorPos + 5, rec.Y + (rec.Height - Height) / 2, DisplayValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using Eto.Drawing;
|
||||
using Eto.Forms;
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
[CellAttribute(typeof(bool))]
|
||||
public class CellBool : CellBase
|
||||
{
|
||||
private bool _draw;
|
||||
|
||||
public CellBool()
|
||||
{
|
||||
_draw = true;
|
||||
}
|
||||
|
||||
public override void Edit(PixelLayout control)
|
||||
{
|
||||
_draw = false;
|
||||
|
||||
var checkbox = new CheckBox();
|
||||
checkbox.Tag = this;
|
||||
checkbox.Checked = (bool?)Value;
|
||||
checkbox.ThreeState = (Value == null);
|
||||
checkbox.Text = (checkbox.Checked == null) ? "Not Set" : checkbox.Checked.ToString();
|
||||
checkbox.Width = _lastRec.Width - 10;
|
||||
checkbox.Height = _lastRec.Height;
|
||||
control.Add(checkbox, _lastRec.X + 10, _lastRec.Y);
|
||||
|
||||
checkbox.CheckedChanged += (sender, e) => checkbox.Text = (checkbox.Checked == null) ? "Not Set" : checkbox.Checked.ToString();
|
||||
|
||||
OnKill += delegate
|
||||
{
|
||||
OnKill = null;
|
||||
|
||||
if (_eventHandler == null || checkbox.Checked == null)
|
||||
return;
|
||||
|
||||
_draw = true;
|
||||
Value = checkbox.Checked;
|
||||
_eventHandler(Value, EventArgs.Empty);
|
||||
};
|
||||
}
|
||||
|
||||
public override void DrawCell(Graphics g, Rectangle rec, int separatorPos, bool selected)
|
||||
{
|
||||
if (_draw)
|
||||
base.DrawCell(g, rec, separatorPos, selected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using Eto.Forms;
|
||||
|
||||
namespace MonoGame.Tools.Pipeline
|
||||
{
|
||||
[CellAttribute(typeof(char))]
|
||||
public class CellChar : CellBase
|
||||
{
|
||||
public override void OnCreate()
|
||||
{
|
||||
DisplayValue = ((int)(char)Value) + " (" + Value + ")";
|
||||
}
|
||||
|
||||
public override void Edit(PixelLayout control)
|
||||
{
|
||||
var editText = new TextBox();
|
||||
editText.Tag = this;
|
||||
editText.Style = "OverrideSize";
|
||||
editText.Width = _lastRec.Width;
|
||||
editText.Height = _lastRec.Height;
|
||||
|
||||
char value;
|
||||
char.TryParse(Value.ToString(), out value);
|
||||
|
||||
editText.Text = ((int)value).ToString();
|
||||
|
||||
control.Add(editText, _lastRec.X, _lastRec.Y);
|
||||
|
||||
editText.Focus();
|
||||
editText.CaretIndex = editText.Text.Length;
|
||||
|
||||
OnKill += delegate
|
||||
{
|
||||
OnKill = null;
|
||||
|
||||
if (_eventHandler == null)
|
||||
return;
|
||||
|
||||
int num;
|
||||
if (!int.TryParse(editText.Text, out num))
|
||||
return;
|
||||
|
||||
_eventHandler((char)num, EventArgs.Empty);
|
||||
};
|
||||
|
||||
editText.KeyDown += (sender, e) =>
|
||||
{
|
||||
if (e.Key == Keys.Enter)
|
||||
OnKill.Invoke();
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user