diff --git a/Engine.Integration/Engine.Integration.MonoGame/Abstract/IDrawableSprite.cs b/Engine.Integration/Engine.Integration.MonoGame/Abstract/IDrawableSprite.cs new file mode 100644 index 0000000..9d24079 --- /dev/null +++ b/Engine.Integration/Engine.Integration.MonoGame/Abstract/IDrawableSprite.cs @@ -0,0 +1,10 @@ +using Microsoft.Xna.Framework.Graphics; + +using Syntriax.Engine.Core; + +namespace Syntriax.Engine.Integration.MonoGame; + +public interface IDrawableSprite : IBehaviour +{ + void Draw(SpriteBatch spriteBatch); +} diff --git a/Engine.Integration/Engine.Integration.MonoGame/Abstract/IDrawableTriangle.cs b/Engine.Integration/Engine.Integration.MonoGame/Abstract/IDrawableTriangle.cs new file mode 100644 index 0000000..937d559 --- /dev/null +++ b/Engine.Integration/Engine.Integration.MonoGame/Abstract/IDrawableTriangle.cs @@ -0,0 +1,8 @@ +using Syntriax.Engine.Core; + +namespace Syntriax.Engine.Integration.MonoGame; + +public interface IDrawableTriangle : IBehaviour +{ + void Draw(ITriangleBatch triangleBatch); +} diff --git a/Engine.Integration/Engine.Integration.MonoGame/Abstract/ITriangleBatch.cs b/Engine.Integration/Engine.Integration.MonoGame/Abstract/ITriangleBatch.cs new file mode 100644 index 0000000..08f190a --- /dev/null +++ b/Engine.Integration/Engine.Integration.MonoGame/Abstract/ITriangleBatch.cs @@ -0,0 +1,12 @@ +using Microsoft.Xna.Framework; + +using Syntriax.Engine.Core; + +namespace Syntriax.Engine.Integration.MonoGame; + +public interface ITriangleBatch +{ + void Begin(Matrix? view = null, Matrix? projection = null); + void Draw(Triangle triangle, ColorRGBA colorRGBA); + void End(); +} diff --git a/Engine.Integration/Engine.Integration.MonoGame/Behaviours/DrawableShapeBehaviour.cs b/Engine.Integration/Engine.Integration.MonoGame/Behaviours/DrawableShapeBehaviour.cs new file mode 100644 index 0000000..dbfef7e --- /dev/null +++ b/Engine.Integration/Engine.Integration.MonoGame/Behaviours/DrawableShapeBehaviour.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; + +using Syntriax.Engine.Core; + +namespace Syntriax.Engine.Integration.MonoGame; + +public class DrawableShapeBehaviour : Behaviour2D, IDrawableTriangle, IPreDraw +{ + private readonly Shape2D shape = new([]); + private readonly List worldTriangles = []; + private readonly Shape2D worldShape = new([]); + protected ColorRGB color = new(255, 255, 255); + + public void PreDraw() => UpdateWorldShape(); + + public void Draw(ITriangleBatch triangleBatch) + { + worldShape.ToTrianglesConvex(worldTriangles); + + foreach (Triangle triangle in worldTriangles) + triangleBatch.Draw(new(triangle.C, triangle.B, triangle.A), color); + } + + protected void UpdateWorldShape() => shape.Transform(Transform, worldShape); + + public DrawableShapeBehaviour() => shape = Shape2D.Triangle; + public DrawableShapeBehaviour(Shape2D shape) => this.shape = shape; + public DrawableShapeBehaviour(Shape2D shape, ColorRGB color) { this.shape = shape; this.color = color; } +} diff --git a/Engine.Integration/Engine.Integration.MonoGame/Behaviours/KeyboardInputsBehaviour.cs b/Engine.Integration/Engine.Integration.MonoGame/Behaviours/KeyboardInputsBehaviour.cs new file mode 100644 index 0000000..944fcc1 --- /dev/null +++ b/Engine.Integration/Engine.Integration.MonoGame/Behaviours/KeyboardInputsBehaviour.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections.Generic; + +using Microsoft.Xna.Framework.Input; + +using Syntriax.Engine.Core; +using Syntriax.Engine.Systems.Input; + +namespace Syntriax.Engine.Integration.MonoGame; + +public class KeyboardInputsBehaviour : Behaviour, IButtonInputs, IUpdate +{ + public Event, IButtonInputs.ButtonCallbackArguments> OnAnyButtonPressed { get; } = new(); + public Event, IButtonInputs.ButtonCallbackArguments> OnAnyButtonReleased { get; } = new(); + + private readonly Dictionary, IButtonInputs.ButtonCallbackArguments>> OnPressed = new(256); + private readonly Dictionary, IButtonInputs.ButtonCallbackArguments>> OnReleased = new(256); + + private int cachePressedCurrentlyCount = 0; + private readonly Keys[] cachePressedCurrently = new Keys[256]; + + private int cachePressedPreviouslyCount = 0; + private readonly Keys[] cachePressedPreviously = new Keys[256]; + + public void RegisterOnPress(Keys key, Event, IButtonInputs.ButtonCallbackArguments>.EventHandler callback) + { + if (!OnPressed.TryGetValue(key, out Event, IButtonInputs.ButtonCallbackArguments>? delegateCallback)) + { + delegateCallback = new(); + OnPressed.Add(key, delegateCallback); + } + + delegateCallback.AddListener(callback); + } + + public void UnregisterOnPress(Keys key, Event, IButtonInputs.ButtonCallbackArguments>.EventHandler callback) + { + if (OnPressed.TryGetValue(key, out Event, IButtonInputs.ButtonCallbackArguments>? delegateCallback)) + delegateCallback.RemoveListener(callback); + } + + public void RegisterOnRelease(Keys key, Event, IButtonInputs.ButtonCallbackArguments>.EventHandler callback) + { + if (!OnReleased.TryGetValue(key, out Event, IButtonInputs.ButtonCallbackArguments>? delegateCallback)) + { + delegateCallback = new(); + OnReleased.Add(key, delegateCallback); + } + + delegateCallback.AddListener(callback); + } + + public void UnregisterOnRelease(Keys key, Event, IButtonInputs.ButtonCallbackArguments>.EventHandler callback) + { + if (OnReleased.TryGetValue(key, out Event, IButtonInputs.ButtonCallbackArguments>? delegateCallback)) + delegateCallback.RemoveListener(callback); + } + + public void Update() + { + KeyboardState keyboardState = Keyboard.GetState(); + keyboardState.GetPressedKeys(cachePressedCurrently); + cachePressedCurrentlyCount = keyboardState.GetPressedKeyCount(); + + for (int i = 0; i < cachePressedCurrentlyCount; i++) + { + Keys currentlyPressedKey = cachePressedCurrently[i]; + + if (WasPressed(currentlyPressedKey)) + continue; + + if (OnPressed.TryGetValue(currentlyPressedKey, out Event, IButtonInputs.ButtonCallbackArguments>? callback)) + callback?.Invoke(this, new(currentlyPressedKey)); + + OnAnyButtonPressed?.Invoke(this, new(currentlyPressedKey)); + } + + for (int i = 0; i < cachePressedPreviouslyCount; i++) + { + Keys previouslyPressedKey = cachePressedPreviously[i]; + + if (IsPressed(previouslyPressedKey)) + continue; + + if (OnReleased.TryGetValue(previouslyPressedKey, out Event, IButtonInputs.ButtonCallbackArguments>? callback)) + callback?.Invoke(this, new(previouslyPressedKey)); + + OnAnyButtonReleased?.Invoke(this, new(previouslyPressedKey)); + } + + Array.Copy(cachePressedCurrently, cachePressedPreviously, cachePressedCurrentlyCount); + cachePressedPreviouslyCount = cachePressedCurrentlyCount; + } + + public bool IsPressed(Keys key) + { + for (int i = 0; i < cachePressedCurrentlyCount; i++) + if (cachePressedCurrently[i] == key) + return true; + return false; + } + + private bool WasPressed(Keys key) + { + for (int i = 0; i < cachePressedPreviouslyCount; i++) + if (cachePressedPreviously[i] == key) + return true; + return false; + } +} diff --git a/Engine.Integration/Engine.Integration.MonoGame/Behaviours/MonoGameCamera2DBehaviour.cs b/Engine.Integration/Engine.Integration.MonoGame/Behaviours/MonoGameCamera2DBehaviour.cs new file mode 100644 index 0000000..553c843 --- /dev/null +++ b/Engine.Integration/Engine.Integration.MonoGame/Behaviours/MonoGameCamera2DBehaviour.cs @@ -0,0 +1,109 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +using Syntriax.Engine.Core; + +namespace Syntriax.Engine.Integration.MonoGame; + +public class MonoGameCamera2DBehaviour : BehaviourBase, ICamera2D, IFirstFrameUpdate, IPreDraw +{ + public event MatrixTransformChangedArguments? OnMatrixTransformChanged = null; + public event ViewportChangedArguments? OnViewportChanged = null; + public event ZoomChangedArguments? OnZoomChanged = null; + + private Matrix _matrixTransform = Matrix.Identity; + + private Viewport _viewport = default; + private float _zoom = 1f; + + public GraphicsDeviceManager Graphics { get; private set; } = null!; + public ITransform2D Transform { get; private set; } = null!; + + public Matrix MatrixTransform + { + get => _matrixTransform; + set + { + if (_matrixTransform == value) + return; + + _matrixTransform = value; + OnMatrixTransformChanged?.Invoke(this); + } + } + + public Vector2D Position + { + get => Transform.Position; + set => Transform.Position = value; + } + + public Viewport Viewport + { + get => _viewport; + set + { + if (_viewport.Equals(value)) + return; + + _viewport = value; + OnViewportChanged?.Invoke(this); + } + } + + public float Zoom + { + get => _zoom; + set + { + float newValue = Syntriax.Engine.Core.Math.Max(0.1f, value); + + if (_zoom == newValue) + return; + + _zoom = newValue; + OnZoomChanged?.Invoke(this); + } + } + + public float Rotation + { + get => Transform.Rotation; + set => Transform.Rotation = value; + } + + // TODO This causes delay since OnPreDraw calls assuming this is called in in Update + public Vector2D ScreenToWorldPosition(Vector2D screenPosition) + { + Vector2D worldPosition = Vector2.Transform(screenPosition.ToVector2(), Matrix.Invert(MatrixTransform)).ToVector2D(); + return worldPosition.Scale(EngineConverterExtensions.screenScale); + } + public Vector2D WorldToScreenPosition(Vector2D worldPosition) + { + Vector2D screenPosition = Vector2.Transform(worldPosition.ToVector2(), MatrixTransform).ToVector2D(); + return screenPosition.Scale(EngineConverterExtensions.screenScale); + } + + public void FirstActiveFrame() + { + Graphics = BehaviourController.UniverseObject.Universe.FindRequiredBehaviour().Window.Graphics; + Viewport = Graphics.GraphicsDevice.Viewport; + } + + public void PreDraw() + { + MatrixTransform = + Matrix.CreateTranslation(new Vector3(-Position.X, Position.Y, 0f)) * + Matrix.CreateRotationZ(Rotation * Syntriax.Engine.Core.Math.DegreeToRadian) * + Matrix.CreateScale(Transform.Scale.X.Max(Transform.Scale.Y)) * + Matrix.CreateScale(Zoom) * + Matrix.CreateTranslation(new Vector3(_viewport.Width * .5f, _viewport.Height * .5f, 0f)); + } + + protected sealed override void InitializeInternal() => Transform = BehaviourController.GetRequiredBehaviour(); + protected sealed override void FinalizeInternal() => Transform = null!; + + public delegate void MatrixTransformChangedArguments(MonoGameCamera2DBehaviour sender); + public delegate void ViewportChangedArguments(MonoGameCamera2DBehaviour sender); + public delegate void ZoomChangedArguments(MonoGameCamera2DBehaviour sender); +} diff --git a/Engine.Integration/Engine.Integration.MonoGame/Behaviours/SpriteBatcher.cs b/Engine.Integration/Engine.Integration.MonoGame/Behaviours/SpriteBatcher.cs new file mode 100644 index 0000000..7876bcc --- /dev/null +++ b/Engine.Integration/Engine.Integration.MonoGame/Behaviours/SpriteBatcher.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; + +using Microsoft.Xna.Framework.Graphics; + +using Syntriax.Engine.Core; + +namespace Syntriax.Engine.Integration.MonoGame; + +public class SpriteBatcher : BehaviourBase, IFirstFrameUpdate, IDraw +{ + private static Comparer SortByPriority() => Comparer.Create((x, y) => y.Priority.CompareTo(x.Priority)); + private SpriteBatch spriteBatch = null!; + private MonoGameCamera2DBehaviour camera2D = null!; + private readonly ActiveBehaviourCollectorSorted drawableSprites = new() { SortBy = SortByPriority() }; + + public void FirstActiveFrame() + { + MonoGameWindowContainer windowContainer = BehaviourController.UniverseObject.Universe.FindRequiredBehaviour(); + camera2D = BehaviourController.UniverseObject.Universe.FindRequiredBehaviour(); + + spriteBatch = new(windowContainer.Window.GraphicsDevice); + } + + public void Draw() + { + spriteBatch.Begin(transformMatrix: camera2D.MatrixTransform); + for (int i = 0; i < drawableSprites.Count; i++) + drawableSprites[i].Draw(spriteBatch); + spriteBatch.End(); + } +} diff --git a/Engine.Integration/Engine.Integration.MonoGame/Behaviours/TriangleBatcher.cs b/Engine.Integration/Engine.Integration.MonoGame/Behaviours/TriangleBatcher.cs new file mode 100644 index 0000000..4215384 --- /dev/null +++ b/Engine.Integration/Engine.Integration.MonoGame/Behaviours/TriangleBatcher.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; + +using Microsoft.Xna.Framework; + +using Syntriax.Engine.Core; + +namespace Syntriax.Engine.Integration.MonoGame; + +public class TriangleBatcher : BehaviourBase, ITriangleBatch, IFirstFrameUpdate, IDraw +{ + private static Comparer SortByAscendingPriority() => Comparer.Create((x, y) => x.Priority.CompareTo(y.Priority)); + + private TriangleBatch triangleBatch = null!; + private MonoGameCamera2DBehaviour camera2D = null!; + private readonly ActiveBehaviourCollectorSorted drawableShapes = new() { SortBy = SortByAscendingPriority() }; + + public void FirstActiveFrame() + { + MonoGameWindowContainer windowContainer = BehaviourController.UniverseObject.Universe.FindRequiredBehaviour(); + camera2D = BehaviourController.UniverseObject.Universe.FindRequiredBehaviour(); + + triangleBatch = new(windowContainer.Window.GraphicsDevice); + drawableShapes.Unassign(); + drawableShapes.Assign(BehaviourController.UniverseObject.Universe); + } + + public void Draw() + { + triangleBatch.Begin(camera2D.MatrixTransform); + for (int i = 0; i < drawableShapes.Count; i++) + drawableShapes[i].Draw(triangleBatch); + triangleBatch.End(); + } + + public void Begin(Matrix? view = null, Matrix? projection = null) => triangleBatch.Begin(view, projection); + public void Draw(Triangle triangle, ColorRGBA colorRGBA) => triangleBatch.Draw(triangle, colorRGBA); + public void End() => triangleBatch.End(); +} diff --git a/Engine.Integration/Engine.Integration.MonoGame/Engine.Integration.MonoGame.csproj b/Engine.Integration/Engine.Integration.MonoGame/Engine.Integration.MonoGame.csproj new file mode 100644 index 0000000..cd49b65 --- /dev/null +++ b/Engine.Integration/Engine.Integration.MonoGame/Engine.Integration.MonoGame.csproj @@ -0,0 +1,16 @@ + + + net9.0 + disable + enable + Syntriax.Engine.Integration.MonoGame + + + + All + + + + + + diff --git a/Engine.Integration/Engine.Integration.MonoGame/EngineConverter.cs b/Engine.Integration/Engine.Integration.MonoGame/EngineConverter.cs new file mode 100644 index 0000000..e1a7020 --- /dev/null +++ b/Engine.Integration/Engine.Integration.MonoGame/EngineConverter.cs @@ -0,0 +1,36 @@ +using System.Runtime.CompilerServices; + +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +using Syntriax.Engine.Core; + +namespace Syntriax.Engine.Integration.MonoGame; + +public static class EngineConverterExtensions +{ + public readonly static Vector2D screenScale = Vector2D.Down + Vector2D.Right; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static UniverseTime ToEngineTime(this GameTime gameTime) => new(gameTime.TotalGameTime, gameTime.ElapsedGameTime); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2D ToVector2D(this Vector2 vector) => new(vector.X, vector.Y); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Color ToColor(this ColorRGBA rgba) => new(rgba.R, rgba.G, rgba.B, rgba.A); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2D ToVector2D(this Point point) => new(point.X, point.Y); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 ToVector2(this Vector2D vector) => new(vector.X, vector.Y); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 ToDisplayVector2(this Vector2D vector) => vector.Scale(screenScale).ToVector2(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2D ApplyDisplayScale(this Vector2D vector) => vector.Scale(screenScale); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rectangle ToDisplayRectangle(this Rectangle rectangle, DisplayMode displayMode) => new() + { + X = rectangle.X, + Y = displayMode.Height - rectangle.Y - rectangle.Height, + Width = rectangle.Width, + Height = rectangle.Height + }; +} diff --git a/Engine.Integration/Engine.Integration.MonoGame/MonoGameWindow.cs b/Engine.Integration/Engine.Integration.MonoGame/MonoGameWindow.cs new file mode 100644 index 0000000..77715d1 --- /dev/null +++ b/Engine.Integration/Engine.Integration.MonoGame/MonoGameWindow.cs @@ -0,0 +1,55 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +using Syntriax.Engine.Core; + +namespace Syntriax.Engine.Integration.MonoGame; + +public abstract class MonoGameWindow : Game +{ + public GraphicsDeviceManager Graphics { get; protected set; } = null!; + public IUniverse Universe { get; protected set; } = null!; + public ColorRGB BackgroundColor { get; set; } = new ColorRGB(35, 20, 35); + + public MonoGameWindow() + { + Preserver.Preserve(); + Graphics = new GraphicsDeviceManager(this); + Content.RootDirectory = "Content"; + IsMouseVisible = true; + Universe = new Universe(); + } + + protected abstract void PopulateUniverse(IUniverse universe); + protected override void Initialize() + { + Universe.Initialize(); + Universe.InstantiateUniverseObject().SetUniverseObject("Window Container") + .BehaviourController.AddBehaviour(this); + + PopulateUniverse(Universe); + + base.Initialize(); + } + + protected override void LoadContent() + { + // TODO: use this.Content to load your game content here + } + + protected override void Update(GameTime gameTime) + { + Universe.Update(gameTime.ToEngineTime()); + + base.Update(gameTime); + } + + protected override void Draw(GameTime gameTime) + { + GraphicsDevice.Clear(((ColorRGBA)BackgroundColor).ToColor()); + + Universe.Draw(); + + base.Draw(gameTime); + } +} diff --git a/Engine.Integration/Engine.Integration.MonoGame/TriangleBatch.cs b/Engine.Integration/Engine.Integration.MonoGame/TriangleBatch.cs new file mode 100644 index 0000000..a03c852 --- /dev/null +++ b/Engine.Integration/Engine.Integration.MonoGame/TriangleBatch.cs @@ -0,0 +1,74 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +using Syntriax.Engine.Core; + +namespace Syntriax.Engine.Integration.MonoGame; + +public class TriangleBatch : ITriangleBatch +{ + private readonly GraphicsDevice graphicsDevice; + private VertexBuffer vertexBuffer = default!; + private readonly VertexPositionColor[] vertices = new VertexPositionColor[1024]; + private int verticesIndex = 0; + private Matrix _view; + private Matrix _projection; + private readonly BasicEffect basicEffect; + + public TriangleBatch(GraphicsDevice graphicsDevice) + { + this.graphicsDevice = graphicsDevice; + this.graphicsDevice.RasterizerState = new RasterizerState() { CullMode = CullMode.None }; + basicEffect = new(graphicsDevice); + basicEffect.VertexColorEnabled = true; + } + + public void Draw(Triangle triangle, ColorRGBA colorRGBA) + { + if (verticesIndex + 3 >= vertices.Length) + Flush(); + + Vector2 A = triangle.A.ToDisplayVector2(); + Vector2 B = triangle.B.ToDisplayVector2(); + Vector2 C = triangle.C.ToDisplayVector2(); + Color color = colorRGBA.ToColor(); + + vertices[verticesIndex++] = new(new(A.X, A.Y, 0f), color); + vertices[verticesIndex++] = new(new(B.X, B.Y, 0f), color); + vertices[verticesIndex++] = new(new(C.X, C.Y, 0f), color); + } + + public void Begin(Matrix? view = null, Matrix? projection = null) + { + if (view != null) + _view = view.Value; + else + _view = Matrix.Identity; + + if (projection != null) + _projection = projection.Value; + else + { + Viewport viewport = graphicsDevice.Viewport; + _projection = Matrix.CreateOrthographicOffCenter(viewport.X, viewport.Width, viewport.Height, viewport.Y, 0, 1); + } + } + + public void End() => Flush(); + + private void Flush() + { + basicEffect.Projection = _projection; + basicEffect.View = _view; + vertexBuffer = new VertexBuffer(graphicsDevice, typeof(VertexPositionColor), 1024, BufferUsage.WriteOnly); + vertexBuffer.SetData(vertices); + + graphicsDevice.SetVertexBuffer(vertexBuffer); + + foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes) + pass.Apply(); + graphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, verticesIndex / 3); + + verticesIndex = 0; + } +} diff --git a/Engine.Integration/Engine.Integration.MonoGame/UniverseObjects/MonoGameWindowContainer.cs b/Engine.Integration/Engine.Integration.MonoGame/UniverseObjects/MonoGameWindowContainer.cs new file mode 100644 index 0000000..eba7e18 --- /dev/null +++ b/Engine.Integration/Engine.Integration.MonoGame/UniverseObjects/MonoGameWindowContainer.cs @@ -0,0 +1,10 @@ +using Syntriax.Engine.Core; +using Syntriax.Engine.Core.Serialization; + +namespace Syntriax.Engine.Integration.MonoGame; + +[IgnoreSerialization] +public class MonoGameWindowContainer(MonoGameWindow GameWindow) : BehaviourBase +{ + public MonoGameWindow Window { get; } = GameWindow; +} diff --git a/Engine.sln b/Engine.sln index ca5e093..4f5da96 100644 --- a/Engine.sln +++ b/Engine.sln @@ -17,36 +17,104 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Serializers.Yaml", " EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YamlDotNet", "Engine.Serializers\YamlDotNet\YamlDotNet\YamlDotNet.csproj", "{3D852C92-BC14-4893-AEF2-50612DAFCD8F}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Integration", "Integration", "{823D4020-332D-2C13-F261-6F510F11A57E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoGame", "Engine.Integration\Engine.Integration.MonoGame\Engine.Integration.MonoGame.csproj", "{C3438D33-0879-44E4-9DF0-D29F5621C44C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {71719EAD-1B6B-4229-B39E-E53A2E8BFAB1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {71719EAD-1B6B-4229-B39E-E53A2E8BFAB1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {71719EAD-1B6B-4229-B39E-E53A2E8BFAB1}.Debug|x64.ActiveCfg = Debug|Any CPU + {71719EAD-1B6B-4229-B39E-E53A2E8BFAB1}.Debug|x64.Build.0 = Debug|Any CPU + {71719EAD-1B6B-4229-B39E-E53A2E8BFAB1}.Debug|x86.ActiveCfg = Debug|Any CPU + {71719EAD-1B6B-4229-B39E-E53A2E8BFAB1}.Debug|x86.Build.0 = Debug|Any CPU {71719EAD-1B6B-4229-B39E-E53A2E8BFAB1}.Release|Any CPU.ActiveCfg = Release|Any CPU {71719EAD-1B6B-4229-B39E-E53A2E8BFAB1}.Release|Any CPU.Build.0 = Release|Any CPU + {71719EAD-1B6B-4229-B39E-E53A2E8BFAB1}.Release|x64.ActiveCfg = Release|Any CPU + {71719EAD-1B6B-4229-B39E-E53A2E8BFAB1}.Release|x64.Build.0 = Release|Any CPU + {71719EAD-1B6B-4229-B39E-E53A2E8BFAB1}.Release|x86.ActiveCfg = Release|Any CPU + {71719EAD-1B6B-4229-B39E-E53A2E8BFAB1}.Release|x86.Build.0 = Release|Any CPU {3B3C3332-07E3-4A00-9898-0A5410BCB08C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3B3C3332-07E3-4A00-9898-0A5410BCB08C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3B3C3332-07E3-4A00-9898-0A5410BCB08C}.Debug|x64.ActiveCfg = Debug|Any CPU + {3B3C3332-07E3-4A00-9898-0A5410BCB08C}.Debug|x64.Build.0 = Debug|Any CPU + {3B3C3332-07E3-4A00-9898-0A5410BCB08C}.Debug|x86.ActiveCfg = Debug|Any CPU + {3B3C3332-07E3-4A00-9898-0A5410BCB08C}.Debug|x86.Build.0 = Debug|Any CPU {3B3C3332-07E3-4A00-9898-0A5410BCB08C}.Release|Any CPU.ActiveCfg = Release|Any CPU {3B3C3332-07E3-4A00-9898-0A5410BCB08C}.Release|Any CPU.Build.0 = Release|Any CPU + {3B3C3332-07E3-4A00-9898-0A5410BCB08C}.Release|x64.ActiveCfg = Release|Any CPU + {3B3C3332-07E3-4A00-9898-0A5410BCB08C}.Release|x64.Build.0 = Release|Any CPU + {3B3C3332-07E3-4A00-9898-0A5410BCB08C}.Release|x86.ActiveCfg = Release|Any CPU + {3B3C3332-07E3-4A00-9898-0A5410BCB08C}.Release|x86.Build.0 = Release|Any CPU {8452323D-99EF-43B1-8E7B-123E02279674}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8452323D-99EF-43B1-8E7B-123E02279674}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8452323D-99EF-43B1-8E7B-123E02279674}.Debug|x64.ActiveCfg = Debug|Any CPU + {8452323D-99EF-43B1-8E7B-123E02279674}.Debug|x64.Build.0 = Debug|Any CPU + {8452323D-99EF-43B1-8E7B-123E02279674}.Debug|x86.ActiveCfg = Debug|Any CPU + {8452323D-99EF-43B1-8E7B-123E02279674}.Debug|x86.Build.0 = Debug|Any CPU {8452323D-99EF-43B1-8E7B-123E02279674}.Release|Any CPU.ActiveCfg = Release|Any CPU {8452323D-99EF-43B1-8E7B-123E02279674}.Release|Any CPU.Build.0 = Release|Any CPU + {8452323D-99EF-43B1-8E7B-123E02279674}.Release|x64.ActiveCfg = Release|Any CPU + {8452323D-99EF-43B1-8E7B-123E02279674}.Release|x64.Build.0 = Release|Any CPU + {8452323D-99EF-43B1-8E7B-123E02279674}.Release|x86.ActiveCfg = Release|Any CPU + {8452323D-99EF-43B1-8E7B-123E02279674}.Release|x86.Build.0 = Release|Any CPU {58AE79C1-9203-44AE-8022-AA180F0A71DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {58AE79C1-9203-44AE-8022-AA180F0A71DC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {58AE79C1-9203-44AE-8022-AA180F0A71DC}.Debug|x64.ActiveCfg = Debug|Any CPU + {58AE79C1-9203-44AE-8022-AA180F0A71DC}.Debug|x64.Build.0 = Debug|Any CPU + {58AE79C1-9203-44AE-8022-AA180F0A71DC}.Debug|x86.ActiveCfg = Debug|Any CPU + {58AE79C1-9203-44AE-8022-AA180F0A71DC}.Debug|x86.Build.0 = Debug|Any CPU {58AE79C1-9203-44AE-8022-AA180F0A71DC}.Release|Any CPU.ActiveCfg = Release|Any CPU {58AE79C1-9203-44AE-8022-AA180F0A71DC}.Release|Any CPU.Build.0 = Release|Any CPU + {58AE79C1-9203-44AE-8022-AA180F0A71DC}.Release|x64.ActiveCfg = Release|Any CPU + {58AE79C1-9203-44AE-8022-AA180F0A71DC}.Release|x64.Build.0 = Release|Any CPU + {58AE79C1-9203-44AE-8022-AA180F0A71DC}.Release|x86.ActiveCfg = Release|Any CPU + {58AE79C1-9203-44AE-8022-AA180F0A71DC}.Release|x86.Build.0 = Release|Any CPU {E9D1CDC3-5BFF-4C87-AFEB-6CE372709176}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E9D1CDC3-5BFF-4C87-AFEB-6CE372709176}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E9D1CDC3-5BFF-4C87-AFEB-6CE372709176}.Debug|x64.ActiveCfg = Debug|Any CPU + {E9D1CDC3-5BFF-4C87-AFEB-6CE372709176}.Debug|x64.Build.0 = Debug|Any CPU + {E9D1CDC3-5BFF-4C87-AFEB-6CE372709176}.Debug|x86.ActiveCfg = Debug|Any CPU + {E9D1CDC3-5BFF-4C87-AFEB-6CE372709176}.Debug|x86.Build.0 = Debug|Any CPU {E9D1CDC3-5BFF-4C87-AFEB-6CE372709176}.Release|Any CPU.ActiveCfg = Release|Any CPU {E9D1CDC3-5BFF-4C87-AFEB-6CE372709176}.Release|Any CPU.Build.0 = Release|Any CPU + {E9D1CDC3-5BFF-4C87-AFEB-6CE372709176}.Release|x64.ActiveCfg = Release|Any CPU + {E9D1CDC3-5BFF-4C87-AFEB-6CE372709176}.Release|x64.Build.0 = Release|Any CPU + {E9D1CDC3-5BFF-4C87-AFEB-6CE372709176}.Release|x86.ActiveCfg = Release|Any CPU + {E9D1CDC3-5BFF-4C87-AFEB-6CE372709176}.Release|x86.Build.0 = Release|Any CPU {3D852C92-BC14-4893-AEF2-50612DAFCD8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3D852C92-BC14-4893-AEF2-50612DAFCD8F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3D852C92-BC14-4893-AEF2-50612DAFCD8F}.Debug|x64.ActiveCfg = Debug|Any CPU + {3D852C92-BC14-4893-AEF2-50612DAFCD8F}.Debug|x64.Build.0 = Debug|Any CPU + {3D852C92-BC14-4893-AEF2-50612DAFCD8F}.Debug|x86.ActiveCfg = Debug|Any CPU + {3D852C92-BC14-4893-AEF2-50612DAFCD8F}.Debug|x86.Build.0 = Debug|Any CPU {3D852C92-BC14-4893-AEF2-50612DAFCD8F}.Release|Any CPU.ActiveCfg = Release|Any CPU {3D852C92-BC14-4893-AEF2-50612DAFCD8F}.Release|Any CPU.Build.0 = Release|Any CPU + {3D852C92-BC14-4893-AEF2-50612DAFCD8F}.Release|x64.ActiveCfg = Release|Any CPU + {3D852C92-BC14-4893-AEF2-50612DAFCD8F}.Release|x64.Build.0 = Release|Any CPU + {3D852C92-BC14-4893-AEF2-50612DAFCD8F}.Release|x86.ActiveCfg = Release|Any CPU + {3D852C92-BC14-4893-AEF2-50612DAFCD8F}.Release|x86.Build.0 = Release|Any CPU + {C3438D33-0879-44E4-9DF0-D29F5621C44C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C3438D33-0879-44E4-9DF0-D29F5621C44C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C3438D33-0879-44E4-9DF0-D29F5621C44C}.Debug|x64.ActiveCfg = Debug|Any CPU + {C3438D33-0879-44E4-9DF0-D29F5621C44C}.Debug|x64.Build.0 = Debug|Any CPU + {C3438D33-0879-44E4-9DF0-D29F5621C44C}.Debug|x86.ActiveCfg = Debug|Any CPU + {C3438D33-0879-44E4-9DF0-D29F5621C44C}.Debug|x86.Build.0 = Debug|Any CPU + {C3438D33-0879-44E4-9DF0-D29F5621C44C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C3438D33-0879-44E4-9DF0-D29F5621C44C}.Release|Any CPU.Build.0 = Release|Any CPU + {C3438D33-0879-44E4-9DF0-D29F5621C44C}.Release|x64.ActiveCfg = Release|Any CPU + {C3438D33-0879-44E4-9DF0-D29F5621C44C}.Release|x64.Build.0 = Release|Any CPU + {C3438D33-0879-44E4-9DF0-D29F5621C44C}.Release|x86.ActiveCfg = Release|Any CPU + {C3438D33-0879-44E4-9DF0-D29F5621C44C}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -54,5 +122,6 @@ Global GlobalSection(NestedProjects) = preSolution {E9D1CDC3-5BFF-4C87-AFEB-6CE372709176} = {F88E129A-9A47-4D27-96EE-6EC02F79594B} {3D852C92-BC14-4893-AEF2-50612DAFCD8F} = {F88E129A-9A47-4D27-96EE-6EC02F79594B} + {C3438D33-0879-44E4-9DF0-D29F5621C44C} = {823D4020-332D-2C13-F261-6F510F11A57E} EndGlobalSection EndGlobal