diff --git a/.github/workflows/build_test_and_publish.yml b/.github/workflows/build_test_and_publish.yml
index 956ce7d4..30dfa352 100644
--- a/.github/workflows/build_test_and_publish.yml
+++ b/.github/workflows/build_test_and_publish.yml
@@ -52,7 +52,7 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: extract tag version
- run: echo ::set-env name=TAG_VERSION::${GITHUB_REF#refs/tags/v*}
+ run: echo "TAG_VERSION=${GITHUB_REF#refs/tags/v*}" >> $GITHUB_ENV
shell: bash
- uses: actions/setup-dotnet@v1
with:
@@ -78,7 +78,7 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: extract tag version
- run: echo ::set-env name=TAG_VERSION::${GITHUB_REF#refs/tags/v*}
+ run: echo "TAG_VERSION=${GITHUB_REF#refs/tags/v*}" >> $GITHUB_ENV
shell: bash
- uses: actions/setup-dotnet@v1
with:
diff --git a/Exomia.Framework.sln b/Exomia.Framework.sln
index ec18fa6a..bebcb7c0 100644
--- a/Exomia.Framework.sln
+++ b/Exomia.Framework.sln
@@ -26,6 +26,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Exomia.Framework.Example.Ju
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Exomia.Framework.BasicSetup", "examples\Exomia.Framework.BasicSetup\Exomia.Framework.BasicSetup.csproj", "{8329DE95-55FA-4176-91BF-BBC793B9EBE2}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Exomia.Framework.Example.Canvas", "examples\Exomia.Framework.Example.Canvas\Exomia.Framework.Example.Canvas.csproj", "{BEB473A8-DF7F-4402-97C2-0344308EE17F}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -108,6 +110,18 @@ Global
{8329DE95-55FA-4176-91BF-BBC793B9EBE2}.Release|x64.Build.0 = Release|x64
{8329DE95-55FA-4176-91BF-BBC793B9EBE2}.Release|x86.ActiveCfg = Release|x86
{8329DE95-55FA-4176-91BF-BBC793B9EBE2}.Release|x86.Build.0 = Release|x86
+ {BEB473A8-DF7F-4402-97C2-0344308EE17F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BEB473A8-DF7F-4402-97C2-0344308EE17F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BEB473A8-DF7F-4402-97C2-0344308EE17F}.Debug|x64.ActiveCfg = Debug|x64
+ {BEB473A8-DF7F-4402-97C2-0344308EE17F}.Debug|x64.Build.0 = Debug|x64
+ {BEB473A8-DF7F-4402-97C2-0344308EE17F}.Debug|x86.ActiveCfg = Debug|x86
+ {BEB473A8-DF7F-4402-97C2-0344308EE17F}.Debug|x86.Build.0 = Debug|x86
+ {BEB473A8-DF7F-4402-97C2-0344308EE17F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BEB473A8-DF7F-4402-97C2-0344308EE17F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BEB473A8-DF7F-4402-97C2-0344308EE17F}.Release|x64.ActiveCfg = Release|x64
+ {BEB473A8-DF7F-4402-97C2-0344308EE17F}.Release|x64.Build.0 = Release|x64
+ {BEB473A8-DF7F-4402-97C2-0344308EE17F}.Release|x86.ActiveCfg = Release|x86
+ {BEB473A8-DF7F-4402-97C2-0344308EE17F}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -118,6 +132,7 @@ Global
{E86DC9EB-8FC0-4C5D-95F2-206C67A069C2} = {65A2B0A0-B984-4A33-AFA5-A5E70862A10A}
{22EC1807-99FD-4EC1-8A86-9553CD743498} = {9D20989E-7C37-42F4-AE05-19CED958EA7A}
{8329DE95-55FA-4176-91BF-BBC793B9EBE2} = {9D20989E-7C37-42F4-AE05-19CED958EA7A}
+ {BEB473A8-DF7F-4402-97C2-0344308EE17F} = {9D20989E-7C37-42F4-AE05-19CED958EA7A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3E4E52C8-D1D4-488D-8700-A3E45E8968BE}
diff --git a/examples/Exomia.Framework.BasicSetup/MyGame.cs b/examples/Exomia.Framework.BasicSetup/MyGame.cs
index aa962c4d..d89e4868 100644
--- a/examples/Exomia.Framework.BasicSetup/MyGame.cs
+++ b/examples/Exomia.Framework.BasicSetup/MyGame.cs
@@ -57,6 +57,7 @@ protected override void OnInitializeGameGraphicsParameters(ref GameGraphicsParam
protected override void OnInitialize()
{
Content.RootDirectory = "Content";
+ _spriteBatch = ToDispose(new SpriteBatch(GraphicsDevice));
/*
* TODO: Add your initialization logic here
@@ -67,8 +68,6 @@ protected override void OnInitialize()
/// OnLoadContent will be called once per game and is the place to load all of your content.
protected override void OnLoadContent()
{
- _spriteBatch = ToDispose(new SpriteBatch(GraphicsDevice));
-
/*
* TODO: use base.Content to load your game content here
*/
diff --git a/examples/Exomia.Framework.Example.Canvas/Content/logo1.jpg b/examples/Exomia.Framework.Example.Canvas/Content/logo1.jpg
new file mode 100644
index 00000000..45dde99b
Binary files /dev/null and b/examples/Exomia.Framework.Example.Canvas/Content/logo1.jpg differ
diff --git a/examples/Exomia.Framework.Example.Canvas/Content/logo2.png b/examples/Exomia.Framework.Example.Canvas/Content/logo2.png
new file mode 100644
index 00000000..e0d843a7
Binary files /dev/null and b/examples/Exomia.Framework.Example.Canvas/Content/logo2.png differ
diff --git a/examples/Exomia.Framework.Example.Canvas/Exomia.Framework.Example.Canvas.csproj b/examples/Exomia.Framework.Example.Canvas/Exomia.Framework.Example.Canvas.csproj
new file mode 100644
index 00000000..633e5ff7
--- /dev/null
+++ b/examples/Exomia.Framework.Example.Canvas/Exomia.Framework.Example.Canvas.csproj
@@ -0,0 +1,61 @@
+
+
+ Exe
+ netcoreapp3.1
+ AnyCPU;x64;x86
+ 8.0
+ enable
+ true
+
+
+
+ 1.0.0
+ baetz
+
+ Copyright © $([System.DateTime]::Now.Year) baetz
+
+
+
+ portable
+ true
+ DEBUG;TRACE;x86
+ DEBUG;TRACE;$(Platform)
+ true
+
+
+
+ none
+ false
+ TRACE;x86
+ TRACE;$(Platform)
+
+
+
+ 1701;1702;IDE0063
+ NU1605
+ false
+
+
+
+ $(MSBuildProjectName)
+ $(MSBuildProjectName)
+
+
+
+ $(MSBuildProjectName).$(Platform)
+ $(MSBuildProjectName).$(Platform)
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+
\ No newline at end of file
diff --git a/examples/Exomia.Framework.Example.Canvas/MyGame.cs b/examples/Exomia.Framework.Example.Canvas/MyGame.cs
new file mode 100644
index 00000000..4e718373
--- /dev/null
+++ b/examples/Exomia.Framework.Example.Canvas/MyGame.cs
@@ -0,0 +1,281 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using Exomia.Framework.Components;
+using Exomia.Framework.Game;
+using Exomia.Framework.Graphics;
+using Exomia.Framework.Mathematics;
+using Exomia.Framework.Resources;
+using SharpDX;
+
+namespace Exomia.Framework.Example.Canvas
+{
+ ///
+ /// my game. This class cannot be inherited.
+ ///
+ sealed class MyGame : Game.Game
+ {
+#pragma warning disable IDE0052 // Remove unread private members
+ private SpriteBatch _spriteBatch = null!;
+#pragma warning restore IDE0052 // Remove unread private members
+
+ private Graphics.Canvas _canvas = null!;
+
+ private Texture _texture = null!;
+ private Texture _texture2 = null!;
+ private SpriteFont _spriteFont1_12Px = null!;
+ private SpriteFont _spriteFont1_24Px = null!;
+
+ private float k;
+
+ private readonly Vector2[] polyA =
+ {
+ new Vector2(550, 250), new Vector2(550, 120), new Vector2(650, 320), new Vector2(520, 250)
+ };
+
+ private readonly Vector2[] polyB =
+ {
+ new Vector2(450, 400), new Vector2(700, 420), new Vector2(700, 450), new Vector2(600, 480),
+ new Vector2(600, 600)
+ };
+
+ private readonly Vector2[] polyC =
+ {
+ new Vector2(400, 600), new Vector2(550, 620), new Vector2(650, 820), new Vector2(520, 750)
+ };
+
+ private readonly Vector2[] polyD =
+ {
+ new Vector2(600, 600), new Vector2(650, 610), new Vector2(650, 720), new Vector2(450, 750),
+ new Vector2(400, 630)
+ };
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public MyGame()
+ : base("MyGame")
+ {
+ Add(
+ new DebugComponent
+ {
+ Enabled = true,
+ Visible = true,
+ UpdateOrder = 0,
+ DrawOrder = 0,
+ EnableTitleInformation = false,
+ });
+
+ IsFixedTimeStep = false;
+ TargetElapsedTime = 1000f / 144f; //144fps
+ }
+
+ ///
+ protected override void OnInitializeGameGraphicsParameters(ref GameGraphicsParameters parameters)
+ {
+ parameters.IsMouseVisible = true;
+ parameters.Width = 1600;
+ parameters.Height = 1024;
+ parameters.EnableMultiSampling = true;
+ parameters.MultiSampleCount = MultiSampleCount.MsaaX8;
+ }
+
+ ///
+ /// This is where you can query for any required services and load any non-graphic related content.
+ protected override void OnInitialize()
+ {
+ Content.RootDirectory = "Content";
+ _spriteBatch = ToDispose(new SpriteBatch(GraphicsDevice));
+ _canvas = ToDispose(new Graphics.Canvas(GraphicsDevice));
+
+ /*
+ * TODO: Add your initialization logic here
+ */
+ }
+
+ ///
+ /// OnLoadContent will be called once per game and is the place to load all of your content.
+ protected override void OnLoadContent()
+ {
+ /*
+ * TODO: use base.Content to load your game content here
+ */
+
+ _texture = Content.Load("logo1.jpg");
+ _texture2 = Content.Load("logo2.png");
+
+ _spriteFont1_12Px = Content.Load(Fonts.ARIAL_12_PX, true);
+ _spriteFont1_24Px = Content.Load(Fonts.ARIAL_24_PX, true);
+ }
+
+ ///
+ /// OnUnloadContent will be called once per game and is the place to unload all content
+ protected override void OnUnloadContent()
+ {
+ /*
+ * TODO: Unload any non ContentManager content here
+ */
+ }
+
+ ///
+ /// Allows the game to run logic such as updating the world, checking for collisions, gathering input, and playing audio.
+ protected override void Update(GameTime gameTime)
+ {
+ /*
+ * TODO: Add your update logic here
+ */
+
+ base.Update(gameTime);
+ }
+
+ ///
+ /// This is called when the game should draw itself.
+ protected override void Draw(GameTime gameTime)
+ {
+ GraphicsDevice.Clear(Color.CornflowerBlue);
+
+ _canvas.Begin(rasterizerState: GraphicsDevice.RasterizerStates.CullBackDepthClipOffMultiSampleOn);
+
+ k += gameTime.DeltaTimeS / 2;
+
+ _canvas.DrawFillTriangle(new Triangle2(100, 250, 150, 300, 50, 300), Color.Red, 0, Vector2.Zero, 1.0f);
+ _canvas.DrawTriangle(new Triangle2(100, 250, 150, 300, 50, 300), Color.Green, 5.0f, 0, Vector2.Zero, 1.0f);
+
+ _canvas.DrawFillTriangle(
+ new Triangle2(100, 250, 150, 300, 50, 300), Color.Yellow, k, new Vector2(100, 250), 1.0f);
+ _canvas.DrawTriangle(
+ new Triangle2(100, 250, 150, 300, 50, 300), Color.Green, 5.0f, k, new Vector2(100, 250), 1.0f);
+
+ _canvas.DrawFillRectangle(new RectangleF(200, 200, 100, 50), Color.Red, 0, Vector2.Zero, 1.0f);
+ _canvas.DrawRectangle(new RectangleF(200, 200, 100, 50), Color.Green, 5.0f, 0, Vector2.Zero, 1.0f);
+
+ _canvas.DrawFillRectangle(new RectangleF(200, 200, 100, 50), Color.Yellow, k, new Vector2(200, 200), 1.0f);
+ _canvas.DrawRectangle(new RectangleF(200, 200, 100, 50), Color.Green, 5.0f, k, new Vector2(200, 200), 1.0f);
+
+ _canvas.DrawLine(new Line2(300, 400, 345, 400), Color.Red, 5.0f, 1.0f, 0, Vector2.Zero);
+ _canvas.DrawLine(new Line2(400, 400, 450, 450), Color.Red, 5.0f, 1.0f, k, new Vector2(425, 425));
+
+ _canvas.DrawLine(new Line2(300, 450, 345, 450), Color.Yellow, 5.0f, 1.0f, 0, Vector2.Zero);
+ _canvas.DrawLine(new Line2(400, 450, 450, 400), Color.Yellow, 5.0f, 1.0f, k, new Vector2(425, 425));
+
+ _canvas.DrawFillPolygon(polyA, Color.Red, 0.0f, Vector2.Zero, 1.0f);
+ _canvas.DrawPolygon(polyA, Color.Green, 5.0f, 0.0f, Vector2.Zero, 1.0f);
+
+ _canvas.DrawFillPolygon(polyB, Color.Red, 0.0f, Vector2.Zero, 1.0f);
+ _canvas.DrawPolygon(polyB, Color.Green, 5.0f, 0.0f, Vector2.Zero, 1.0f);
+
+ _canvas.DrawFillPolygon(polyC, Color.Yellow, k, new Vector2(400, 600), 1.0f);
+ _canvas.DrawPolygon(polyC, Color.Green, 5.0f, k, new Vector2(400, 600), 1.0f);
+
+ _canvas.DrawFillPolygon(polyD, Color.Red, 0.0f, Vector2.Zero, 1.0f);
+ _canvas.DrawPolygon(polyD, Color.Yellow, 5.0f, 0.0f, Vector2.Zero, 1.0f);
+
+ Vector2 center = new Vector2(800, 400);
+
+ _canvas.DrawRectangle(
+ new RectangleF(center.X - 100, center.Y - 100, 200, 200), Color.Green, 2, 0, Vector2.Zero, 1.0f);
+ _canvas.DrawFillArc(new Arc2(center, 100f), Color.Black, 0, center, 1.0f);
+
+ float l = 20;
+ float r = 100;
+ _canvas.DrawArc(
+ new Arc2(center, r, MathUtil.DegreesToRadians(90), MathUtil.DegreesToRadians(-45)), Color.Yellow, l,
+ 0, Vector2.Zero, 1.0f);
+
+ float rr = (r - l) * 0.685f;
+ _canvas.DrawRectangle(
+ new RectangleF(center.X - rr, center.Y - rr, rr * 2, rr * 2), Color.Green, 2, 0, Vector2.Zero, 1.0f);
+
+ Vector2 center2 = new Vector2(1200, 400);
+ _canvas.DrawRectangle(
+ new RectangleF(center2.X - 50f, center2.Y - 50f, 100, 100), Color.Green, 2.0f, 0, Vector2.Zero, 1.0f);
+ _canvas.DrawFillArc(
+ new Arc2(center2, 50f, MathUtil.DegreesToRadians(80), MathUtil.DegreesToRadians(200)), Color.Blue,
+ 0.0f, Vector2.Zero, 1.0f);
+
+ Vector2 center21 = new Vector2(1300, 400);
+ _canvas.DrawRectangle(
+ new RectangleF(center21.X - 50f, center21.Y - 50f, 100, 100), Color.Green, 2.0f, 0, Vector2.Zero, 1.0f);
+ _canvas.DrawFillArc(
+ new Arc2(center21, 50f, MathUtil.DegreesToRadians(80), MathUtil.DegreesToRadians(-10)), Color.Blue,
+ 0.0f, Vector2.Zero, 1.0f);
+
+ Vector2 center3 = new Vector2(1200, 500);
+ _canvas.DrawRectangle(
+ new RectangleF(center3.X - 50f, center3.Y - 50f, 100, 100), Color.Green, 2.0f, 0, Vector2.Zero, 1.0f);
+ _canvas.DrawFillArc(
+ new Arc2(center3, 50f, MathUtil.DegreesToRadians(80), 0), Color.Blue, 0.0f, Vector2.Zero, 1.0f);
+
+ Vector2 center31 = new Vector2(1300, 500);
+ _canvas.DrawRectangle(
+ new RectangleF(center31.X - 50f, center31.Y - 50f, 100, 100), Color.Green, 2.0f, 0, Vector2.Zero, 1.0f);
+ _canvas.DrawFillArc(
+ new Arc2(center31, 50f, MathUtil.DegreesToRadians(-80), MathUtil.DegreesToRadians(200)), Color.Blue,
+ 0.0f, Vector2.Zero, 1.0f);
+
+ Vector2 center4 = new Vector2(1200, 600);
+ _canvas.DrawRectangle(
+ new RectangleF(center4.X - 50f, center4.Y - 50f, 100, 100), Color.Green, 2.0f, 0, Vector2.Zero, 1.0f);
+ _canvas.DrawFillArc(
+ new Arc2(center4, 50f, MathUtil.DegreesToRadians(-80), MathUtil.DegreesToRadians(-200)), Color.Blue,
+ 0.0f, Vector2.Zero, 1.0f);
+
+ Vector2 center41 = new Vector2(1300, 600);
+ _canvas.DrawRectangle(
+ new RectangleF(center41.X - 50f, center41.Y - 50f, 100, 100), Color.Green, 2.0f, 0, Vector2.Zero, 1.0f);
+ _canvas.DrawFillArc(
+ new Arc2(center41, 50f, MathUtil.DegreesToRadians(-80), MathUtil.DegreesToRadians(0)), Color.Blue,
+ 0.0f, Vector2.Zero, 1.0f);
+
+ Vector2 center5 = new Vector2(1200, 700);
+ _canvas.DrawRectangle(
+ new RectangleF(center5.X - 50f, center5.Y - 50f, 100, 100), Color.Green, 2.0f, 0, Vector2.Zero, 1.0f);
+ _canvas.DrawFillArc(
+ new Arc2(center5, 50f, MathUtil.DegreesToRadians(0), MathUtil.DegreesToRadians(200)), Color.Blue, 0.0f,
+ Vector2.Zero, 1.0f);
+
+ Vector2 center51 = new Vector2(1300, 700);
+ _canvas.DrawRectangle(
+ new RectangleF(center51.X - 50f, center51.Y - 50f, 100, 100), Color.Green, 2.0f, 0, Vector2.Zero, 1.0f);
+ _canvas.DrawFillArc(
+ new Arc2(center51, 50f, MathUtil.DegreesToRadians(0), MathUtil.DegreesToRadians(-200)), Color.Blue,
+ 0.0f, Vector2.Zero, 1.0f);
+
+ Vector2 center200 = new Vector2(1400, 400);
+ _canvas.DrawRectangle(
+ new RectangleF(center200.X - 50f, center200.Y - 50f, 100, 100), Color.Green, 2.0f, 0, Vector2.Zero,
+ 1.0f);
+ _canvas.DrawFillArc(
+ new Arc2(center200, 50f, MathUtil.DegreesToRadians(80), MathUtil.DegreesToRadians(10)), Color.Blue,
+ 0.0f, Vector2.Zero, 1.0f);
+ _canvas.DrawFillArc(
+ new Arc2(center200, 50f, MathUtil.DegreesToRadians(80) + k, MathUtil.DegreesToRadians(10) + k),
+ Color.DeepPink, 0.0f, center200, 1.0f);
+
+ Vector2 center400 = new Vector2(1400, 500);
+ _canvas.DrawRectangle(
+ new RectangleF(center400.X - 50f, center400.Y - 50f, 100, 100), Color.Green, 2.0f, 0, Vector2.Zero,
+ 1.0f);
+ _canvas.DrawFillArc(
+ new Arc2(center400, 50f, MathUtil.DegreesToRadians(-200), MathUtil.DegreesToRadians(-80)), Color.Blue,
+ 0.0f, Vector2.Zero, 1.0f);
+
+ _canvas.Draw(_texture, new RectangleF(1100, 50, 200, 200), Color.White);
+ _canvas.Draw(_texture2, new RectangleF(1350, 50, 200, 200), Color.White);
+
+ _canvas.DrawText(_spriteFont1_12Px, "This is the canvas example.", new Vector2(450, 50), Color.Black, 0);
+ _canvas.DrawText(_spriteFont1_24Px, "This is the canvas example.", new Vector2(450, 65), Color.Black, k, new Vector2(450, 65), 1.0f, TextureEffects.None);
+
+ _canvas.End();
+
+ base.Draw(gameTime);
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/Exomia.Framework.Example.Canvas/Program.cs b/examples/Exomia.Framework.Example.Canvas/Program.cs
new file mode 100644
index 00000000..cb968fc4
--- /dev/null
+++ b/examples/Exomia.Framework.Example.Canvas/Program.cs
@@ -0,0 +1,29 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+namespace Exomia.Framework.Example.Canvas
+{
+ ///
+ /// A program. This class cannot be inherited.
+ ///
+ sealed class Program
+ {
+ ///
+ /// Main entry-point for this application.
+ ///
+ private static void Main()
+ {
+ using (MyGame game = new MyGame())
+ {
+ game.Run();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/Exomia.Framework.Example.JumpAndRun/Components/InputComponent.cs b/examples/Exomia.Framework.Example.JumpAndRun/Components/InputComponent.cs
index 38f2ca92..a0503c12 100644
--- a/examples/Exomia.Framework.Example.JumpAndRun/Components/InputComponent.cs
+++ b/examples/Exomia.Framework.Example.JumpAndRun/Components/InputComponent.cs
@@ -1,12 +1,22 @@
-using Exomia.ECS.Attributes;
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using Exomia.ECS.Attributes;
namespace Exomia.Framework.Example.JumpAndRun.Components
{
[EntityComponentConfiguration(PoolSize = 8)]
sealed class InputComponent
{
- public bool Left { get; set; }
+ public bool Left { get; set; }
public bool Right { get; set; }
- public bool Jump { get; set; }
+ public bool Jump { get; set; }
}
-}
+}
\ No newline at end of file
diff --git a/examples/Exomia.Framework.Example.JumpAndRun/Scenes/GameScene.cs b/examples/Exomia.Framework.Example.JumpAndRun/Scenes/GameScene.cs
index ab86f9d1..87007be1 100644
--- a/examples/Exomia.Framework.Example.JumpAndRun/Scenes/GameScene.cs
+++ b/examples/Exomia.Framework.Example.JumpAndRun/Scenes/GameScene.cs
@@ -28,7 +28,7 @@ sealed class GameScene : SceneBase, IInputHandler
private EntityManager _entityManager = null!;
// ReSharper disable once NotAccessedField.Local
- private Entity _player = null!;
+ private Entity _player = null!;
private InputComponent _inputComponent = null!;
///
@@ -38,7 +38,21 @@ public GameScene(string key)
_mapRenderer = Add(
new MapRenderer("mapRenderer") { DrawOrder = 1, Visible = true });
}
-
+
+ ///
+ public void RegisterInput(IInputDevice device)
+ {
+ device.RegisterKeyDown(OnKeyDown);
+ device.RegisterKeyUp(OnKeyUp);
+ }
+
+ ///
+ public void UnregisterInput(IInputDevice device)
+ {
+ device.UnregisterKeyUp(OnKeyDown);
+ device.UnregisterKeyUp(OnKeyUp);
+ }
+
///
protected override void OnInitialize(IServiceRegistry registry)
{
@@ -156,20 +170,6 @@ protected override void OnLoadContent(IServiceRegistry registry)
});
}
- ///
- public void RegisterInput(IInputDevice device)
- {
- device.RegisterKeyDown(OnKeyDown);
- device.RegisterKeyUp(OnKeyUp);
- }
-
- ///
- public void UnregisterInput(IInputDevice device)
- {
- device.UnregisterKeyUp(OnKeyDown);
- device.UnregisterKeyUp(OnKeyUp);
- }
-
private bool OnKeyDown(int keyValue, KeyModifier modifiers)
{
switch (keyValue)
diff --git a/examples/Exomia.Framework.Example.JumpAndRun/Systems/CollisionSystem.cs b/examples/Exomia.Framework.Example.JumpAndRun/Systems/CollisionSystem.cs
index 17061738..1a492f53 100644
--- a/examples/Exomia.Framework.Example.JumpAndRun/Systems/CollisionSystem.cs
+++ b/examples/Exomia.Framework.Example.JumpAndRun/Systems/CollisionSystem.cs
@@ -22,24 +22,24 @@ interface ICollisionSystem
{
MapRenderer MapRenderer { get; set; }
}
-
+
[EntitySystemConfiguration(
nameof(CollisionSystem), EntitySystemType.Update, After = new[] { nameof(PhysicSystem) })]
sealed class CollisionSystem : EntitySystemBaseR2, ICollisionSystem
{
private MapRenderer _mapRenderer = null!;
-
+
///
public MapRenderer MapRenderer
{
get { return _mapRenderer; }
set { _mapRenderer = value; }
}
-
+
///
public CollisionSystem(EntityManager manager)
: base(manager) { }
-
+
///
protected override void Tick(GameTime gameTime, Entity entity, PositionComponent c1, VelocityComponent c2)
{
diff --git a/examples/Exomia.Framework.Example.JumpAndRun/Systems/InputSystem.cs b/examples/Exomia.Framework.Example.JumpAndRun/Systems/InputSystem.cs
index b9cb821e..4d640a44 100644
--- a/examples/Exomia.Framework.Example.JumpAndRun/Systems/InputSystem.cs
+++ b/examples/Exomia.Framework.Example.JumpAndRun/Systems/InputSystem.cs
@@ -1,4 +1,14 @@
-using Exomia.ECS;
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using Exomia.ECS;
using Exomia.ECS.Attributes;
using Exomia.ECS.Systems;
using Exomia.Framework.Example.JumpAndRun.Components;
@@ -19,7 +29,7 @@ protected override void Tick(GameTime gameTime, Entity entity, InputComponent c1
{
if (c1.Jump)
{
- c1.Jump = false;
+ c1.Jump = false;
c2.Velocity.Y -= 600;
}
diff --git a/framework.wiki b/framework.wiki
index ed40697d..89bb7be5 160000
--- a/framework.wiki
+++ b/framework.wiki
@@ -1 +1 @@
-Subproject commit ed40697d3ea5107efe55efd3599d2f5749ea0838
+Subproject commit 89bb7be513e702d434f66ae6236a47694d3df750
diff --git a/src/Exomia.Framework/Collections/LinkedList.cs b/src/Exomia.Framework/Collections/LinkedList.cs
index 16506264..189807be 100644
--- a/src/Exomia.Framework/Collections/LinkedList.cs
+++ b/src/Exomia.Framework/Collections/LinkedList.cs
@@ -276,6 +276,15 @@ internal LinkedListNode(in T value)
Item = value;
}
+ ///
+ /// Invalidates this object.
+ ///
+ internal void Invalidate()
+ {
+ Next = null;
+ Previous = null;
+ }
+
///
/// Implicit cast that converts the given LinkedListNode to a T.
///
@@ -287,15 +296,6 @@ public static implicit operator T(LinkedListNode node)
{
return node.Item;
}
-
- ///
- /// Invalidates this object.
- ///
- internal void Invalidate()
- {
- Next = null;
- Previous = null;
- }
}
///
diff --git a/src/Exomia.Framework/Components/DebugComponent.cs b/src/Exomia.Framework/Components/DebugComponent.cs
index 8e67a159..a34e5c90 100644
--- a/src/Exomia.Framework/Components/DebugComponent.cs
+++ b/src/Exomia.Framework/Components/DebugComponent.cs
@@ -38,7 +38,6 @@ public class DebugComponent : DrawableComponent
_sampleBuffer;
private IGameWindow? _gameWindow;
- private Vector2 _position1;
private int _sampleCount, _totalFrames;
private SpriteBatch? _spriteBatch;
private string _title = string.Empty;
@@ -71,13 +70,18 @@ public override void Draw(GameTime gameTime)
if (EnableTitleInformation)
{
- _gameWindow!.Title = _title + " " + _fpsInfo;
+ _gameWindow!.Title = $"{_title} {_fpsInfo}";
}
_spriteBatch!.Begin();
_spriteBatch.DrawText(
- _arial12Px!, _fpsInfo, _position1, _fpsCurrent <= FRAME_DANGER_THRESHOLD ? Color.Red : Color.White,
+ _arial12Px!,
+ _fpsInfo,
+ Vector2.Zero,
+ _fpsCurrent <= FRAME_DANGER_THRESHOLD
+ ? Color.Red
+ : Color.White,
0.0f);
_spriteBatch.End();
@@ -136,9 +140,7 @@ protected override void OnInitialize(IServiceRegistry registry)
IGraphicsDevice graphicsDevice = registry.GetService();
_spriteBatch = new SpriteBatch(graphicsDevice);
- _position1 = new Vector2(0, 0);
-
- _gpuName = graphicsDevice.Adapter.Desc3.Description;
+ _gpuName = graphicsDevice.Adapter?.Desc3.Description ?? "";
}
///
diff --git a/src/Exomia.Framework/Content/ContentManager.cs b/src/Exomia.Framework/Content/ContentManager.cs
index 0d7c156e..b4fc52d3 100644
--- a/src/Exomia.Framework/Content/ContentManager.cs
+++ b/src/Exomia.Framework/Content/ContentManager.cs
@@ -257,24 +257,12 @@ public object Load(Type assetType, string assetName, bool fromEmbeddedResource =
}
}
- ///
- public object Load(Type assetType, FileInfo assetFileInfo)
- {
- return Load(assetType, assetFileInfo.FullName);
- }
-
///
public T Load(string assetName, bool fromEmbeddedResource = false)
{
return (T)Load(typeof(T), assetName, fromEmbeddedResource);
}
- ///
- public T Load(FileInfo assetFileInfo)
- {
- return (T)Load(typeof(T), assetFileInfo.FullName);
- }
-
///
public void Unload()
{
@@ -344,12 +332,6 @@ public bool Unload(string assetName)
return Unload(typeof(T), assetName);
}
- ///
- public bool Unload(FileInfo assetFileInfo)
- {
- return Unload(typeof(T), assetFileInfo.FullName);
- }
-
///
/// Resolve stream.
///
@@ -479,6 +461,7 @@ private object LoadAssetWithDynamicContentReader(Type assetType, string assetNam
{
lock (_registeredContentReaderFactories)
{
+ // ReSharper disable once ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator
foreach (IContentReaderFactory factory in _registeredContentReaderFactories)
{
if (factory.TryCreate(assetType, out contentReader))
@@ -512,10 +495,7 @@ private object LoadAssetWithDynamicContentReader(Type assetType, string assetNam
}
}
- ///
- /// An asset key.
- ///
- private struct AssetKey : IEquatable
+ private readonly struct AssetKey : IEquatable
{
///
/// Initializes a new instance of the class.
@@ -528,14 +508,7 @@ public AssetKey(Type assetType, string assetName)
_assetName = assetName;
}
- ///
- /// Type of the asset.
- ///
- private readonly Type _assetType;
-
- ///
- /// Name of the asset.
- ///
+ private readonly Type _assetType;
private readonly string _assetName;
///
@@ -548,7 +521,6 @@ public bool Equals(AssetKey other)
///
public override bool Equals(object obj)
{
- if (obj is null) { return false; }
return obj is AssetKey key && Equals(key);
}
diff --git a/src/Exomia.Framework/Content/ContentReaderParameters.cs b/src/Exomia.Framework/Content/ContentReaderParameters.cs
index efae4863..bfb41fb2 100644
--- a/src/Exomia.Framework/Content/ContentReaderParameters.cs
+++ b/src/Exomia.Framework/Content/ContentReaderParameters.cs
@@ -14,17 +14,19 @@
namespace Exomia.Framework.Content
{
///
- /// A content reader parameters.
+ /// The content reader parameters.
///
public struct ContentReaderParameters
{
///
- /// Name of the asset currently loaded when using .
+ /// Name of the asset currently loaded when using
+ /// .
///
public string AssetName { get; }
///
- /// Type of the asset currently loaded when using .
+ /// Type of the asset currently loaded when using
+ /// .
///
public Type AssetType { get; }
diff --git a/src/Exomia.Framework/Content/IContentManager.cs b/src/Exomia.Framework/Content/IContentManager.cs
index ab73c456..a514cf85 100644
--- a/src/Exomia.Framework/Content/IContentManager.cs
+++ b/src/Exomia.Framework/Content/IContentManager.cs
@@ -9,7 +9,6 @@
#endregion
using System;
-using System.IO;
using Exomia.Framework.Content.Resolver;
using Exomia.Framework.Content.Resolver.EmbeddedResource;
@@ -107,24 +106,6 @@ public interface IContentManager : IDisposable
///
T Load(string assetName, bool fromEmbeddedResource = false);
- ///
- /// Loads an asset that has been processed by the content pipeline.
- ///
- /// Generic type parameter.
- /// Information describing the asset file.
- ///
- /// A asset of type .
- ///
- ///
- /// If the asset was not found from all
- /// .
- ///
- ///
- /// If no content reader was suitable to
- /// decode the asset.
- ///
- T Load(FileInfo assetFileInfo);
-
///
/// Loads an asset that has been processed by the Content Pipeline.
///
@@ -149,16 +130,6 @@ public interface IContentManager : IDisposable
///
object Load(Type assetType, string assetName, bool fromEmbeddedResource = false);
- ///
- /// Loads an asset that has been processed by the Content Pipeline.
- ///
- /// Asset Type.
- /// Information describing the asset file.
- ///
- /// An asset of type .
- ///
- object Load(Type assetType, FileInfo assetFileInfo);
-
///
/// Unloads all data that was loaded by this ContentManager. All data will be disposed.
///
@@ -178,16 +149,6 @@ public interface IContentManager : IDisposable
///
bool Unload(string assetName);
- ///
- /// Unloads and disposes an asset.
- ///
- /// Generic type parameter.
- /// Information describing the asset file.
- ///
- /// true if the asset exists and was unloaded, false otherwise.
- ///
- bool Unload(FileInfo assetFileInfo);
-
///
/// Unloads and disposes an asset.
///
diff --git a/src/Exomia.Framework/Content/Loader/ObjFileLoader.cs b/src/Exomia.Framework/Content/Loader/ObjFileLoader.cs
index bc698a4e..7ec110b2 100644
--- a/src/Exomia.Framework/Content/Loader/ObjFileLoader.cs
+++ b/src/Exomia.Framework/Content/Loader/ObjFileLoader.cs
@@ -49,7 +49,7 @@ public Obj Load(Stream stream)
{
while (!sr.EndOfStream)
{
- string currentLine = sr.ReadLine();
+ string? currentLine = sr.ReadLine();
if (string.IsNullOrWhiteSpace(currentLine) || currentLine[0] == '#')
{
diff --git a/src/Exomia.Framework/ContentSerialization/Compression/CompressMode.cs b/src/Exomia.Framework/ContentSerialization/Compression/CompressMode.cs
index 277c8db9..eed2361b 100644
--- a/src/Exomia.Framework/ContentSerialization/Compression/CompressMode.cs
+++ b/src/Exomia.Framework/ContentSerialization/Compression/CompressMode.cs
@@ -11,12 +11,12 @@
namespace Exomia.Framework.ContentSerialization.Compression
{
///
- /// CompressMode.
+ /// Values that represent CompressMode.
///
public enum CompressMode : byte
{
///
- /// gzip (default)
+ /// An enum constant representing the gzip option (default).
///
Gzip = 1
}
diff --git a/src/Exomia.Framework/ContentSerialization/Compression/ContentCompressor.cs b/src/Exomia.Framework/ContentSerialization/Compression/ContentCompressor.cs
index 2856cf9a..79f9c2de 100644
--- a/src/Exomia.Framework/ContentSerialization/Compression/ContentCompressor.cs
+++ b/src/Exomia.Framework/ContentSerialization/Compression/ContentCompressor.cs
@@ -16,12 +16,12 @@
namespace Exomia.Framework.ContentSerialization.Compression
{
///
- /// ContentCompressor class.
+ /// A content compressor.
///
public static class ContentCompressor
{
///
- /// the default compressed e1 extension.
+ /// The default compressed e1 extension.
///
public const string DEFAULT_COMPRESSED_EXTENSION = ".e1";
@@ -29,7 +29,7 @@ public static class ContentCompressor
private static readonly byte[] s_magicHeader = { 64, 101, 120, 49 };
///
- /// compress a given stream with the given compression mode.
+ /// Compress a given stream with the given compression mode.
///
/// the stream to compress.
/// [out] than finished the compressed out stream.
@@ -71,7 +71,7 @@ public static bool CompressStream(Stream stream,
}
///
- /// decompress a given stream with the given compression mode.
+ /// Decompress a given stream with the given compression mode.
///
/// the stream to compress.
/// [out] than finished the decompressed out stream.
@@ -115,11 +115,6 @@ public static bool DecompressStream(Stream stream, out Stream streamOut)
#region GZIP
- ///
- /// Gzip compress.
- ///
- /// the stream to compress.
- /// [out] than finished the compressed out stream.
private static void GzipCompress(Stream stream, Stream streamOut)
{
using (GZipStream gs = new GZipStream(streamOut, CompressionLevel.Optimal, true))
@@ -134,11 +129,6 @@ private static void GzipCompress(Stream stream, Stream streamOut)
streamOut.Position = 0;
}
- ///
- /// Gzip decompress.
- ///
- /// the stream to compress.
- /// [out] than finished the compressed out stream.
private static void GzipDecompress(Stream stream, out Stream streamOut)
{
streamOut = new MemoryStream();
diff --git a/src/Exomia.Framework/ContentSerialization/ContentSerializableAttribute.cs b/src/Exomia.Framework/ContentSerialization/ContentSerializableAttribute.cs
index 210331c5..8115289a 100644
--- a/src/Exomia.Framework/ContentSerialization/ContentSerializableAttribute.cs
+++ b/src/Exomia.Framework/ContentSerialization/ContentSerializableAttribute.cs
@@ -13,7 +13,7 @@
namespace Exomia.Framework.ContentSerialization
{
///
- /// used to mark a content serializable class.
+ /// Used to mark a content serializable class.
///
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
public sealed class ContentSerializableAttribute : Attribute
@@ -34,9 +34,8 @@ public sealed class ContentSerializableAttribute : Attribute
///
internal IContentSerializationWriter Writer { get; }
- ///
///
- /// ContentSerializableAttribute constructor.
+ /// Initializes a new instance of the class.
///
///
/// the content reader type
@@ -46,6 +45,7 @@ public sealed class ContentSerializableAttribute : Attribute
/// the content writer type
///
///
+ /// Thrown when a Type Load error condition occurs.
public ContentSerializableAttribute(Type reader, Type writer)
{
Reader = System.Activator.CreateInstance(reader) as IContentSerializationReader ??
diff --git a/src/Exomia.Framework/ContentSerialization/ContentSerializationContext.cs b/src/Exomia.Framework/ContentSerialization/ContentSerializationContext.cs
index 3686277c..bb3d9478 100644
--- a/src/Exomia.Framework/ContentSerialization/ContentSerializationContext.cs
+++ b/src/Exomia.Framework/ContentSerialization/ContentSerializationContext.cs
@@ -15,9 +15,9 @@
namespace Exomia.Framework.ContentSerialization
{
///
- /// ContentSerializationContext class
+ /// A content serialization context. This class cannot be inherited.
///
- public class ContentSerializationContext
+ public sealed class ContentSerializationContext
{
internal Dictionary Content { get; } =
new Dictionary();
@@ -72,24 +72,13 @@ internal void Set(string key, object obj, Type type)
}
}
- ///
- /// A content serialization context value.
- ///
struct ContentSerializationContextValue
{
- ///
- /// The type.
- ///
- public Type Type;
-
- ///
- /// The object.
- ///
+ public Type Type;
public object Object;
///
- /// Initializes a new instance of the
- /// struct.
+ /// Initializes a new instance of the struct.
///
/// The type.
/// The object.
diff --git a/src/Exomia.Framework/ContentSerialization/ContentSerializer.cs b/src/Exomia.Framework/ContentSerialization/ContentSerializer.cs
index 2b915c7f..16954bbc 100644
--- a/src/Exomia.Framework/ContentSerialization/ContentSerializer.cs
+++ b/src/Exomia.Framework/ContentSerialization/ContentSerializer.cs
@@ -18,6 +18,10 @@
using Exomia.Framework.ContentSerialization.Writers;
using SharpDX;
+#if NETSTANDARD2_0
+using Exomia.Framework.Extensions;
+#endif
+
namespace Exomia.Framework.ContentSerialization
{
///
@@ -117,8 +121,7 @@ static ContentSerializer()
{
if (a.FullName.StartsWith("System") ||
a.FullName.StartsWith("SharpDX") ||
- a.FullName.StartsWith("ms") ||
- a.FullName.StartsWith("Xilium.CefGlue")) { continue; }
+ a.FullName.StartsWith("ms")) { continue; }
foreach (Type t in a.GetTypes())
{
@@ -135,28 +138,28 @@ static ContentSerializer()
#region SharpDX
- AddWriter(new Vector3CW());
- AddWriter(new Vector2CW());
- AddWriter(new ColorCW());
- AddWriter(new RectangleCW());
- AddWriter(new RectangleFCW());
+ AddWriter(new Vector3ContentSerializationWriter());
+ AddWriter(new Vector2ContentSerializationWriter());
+ AddWriter(new ColorContentSerializationWriter());
+ AddWriter(new RectangleContentSerializationWriter());
+ AddWriter(new RectangleFContentSerializationWriter());
- AddReader(new Vector3CR());
- AddReader(new Vector2CR());
- AddReader(new ColorCR());
- AddReader(new RectangleCR());
- AddReader(new RectangleFCR());
+ AddReader(new Vector3ContentSerializationReader());
+ AddReader(new Vector2ContentSerializationReader());
+ AddReader(new ColorContentSerializationReader());
+ AddReader(new RectangleContentSerializationReader());
+ AddReader(new RectangleFContentSerializationReader());
#endregion
}
///
- /// Adds a new content pipeline reader to the content pipeline.
+ /// Adds a new to the content pipeline.
///
- /// the type the reader can read.
- /// IContentSerializationReader.
- /// ArgumentNullException.
- /// CSReaderException.
+ /// The type the reader can read.
+ /// The .
+ /// Thrown when one or more required arguments are null.
+ /// Thrown when a Create struct Reader error condition occurs.
public static void AddReader(Type type, IContentSerializationReader reader)
{
if (reader == null) { throw new ArgumentNullException(nameof(reader)); }
@@ -173,20 +176,20 @@ public static void AddReader(Type type, IContentSerializationReader reader)
///
/// Adds a new content pipeline reader to the content pipeline.
///
- /// the type the reader can read.
- /// IContentSerializationReader.
+ /// Generic type parameter.
+ /// The .
public static void AddReader(IContentSerializationReader reader)
{
AddReader(typeof(T), reader);
}
///
- /// Adds a new content pipeline writer to the content pipeline.
+ /// Adds a new to the content pipeline.
///
- /// the type the writer can write.
- /// IContentSerializationWriter.
- /// ArgumentNullException.
- /// CSWriterException.
+ /// The type the writer can write.
+ /// The .
+ /// Thrown when one or more required arguments are null.
+ /// Thrown when a Create struct Writer error condition occurs.
public static void AddWriter(Type type, IContentSerializationWriter writer)
{
if (writer == null) { throw new ArgumentNullException(nameof(writer)); }
@@ -202,17 +205,13 @@ public static void AddWriter(Type type, IContentSerializationWriter writer)
///
/// Adds a new content pipeline writer to the content pipeline.
///
- /// the type the writer can write.
- /// IContentSerializationWriter.
+ /// Generic type parameter.
+ /// The .
public static void AddWriter(IContentSerializationWriter writer)
{
AddWriter(typeof(T), writer);
}
- ///
- /// Adds an assembly.
- ///
- /// The assembly.
private static void AddAssembly(Assembly assembly)
{
string assemblyName = assembly.GetName().Name;
@@ -229,7 +228,7 @@ private static void AddAssembly(Assembly assembly)
///
/// Generic type parameter.
/// Name of the asset.
- /// Object.
+ /// The object.
/// (Optional) True to minify.
/// Thrown when one or more required arguments are null.
public static void Write(string assetName, T obj, bool minify = false) where T : class
@@ -265,13 +264,13 @@ public static void Write(string assetName, T obj, bool minify = false) where
///
/// The write handler.
/// The tab space.
- /// Object.
- /// the type the reader can read.
+ /// The Object.
+ /// The type the reader can read.
///
/// Thrown when a Create struct Writer error condition
/// occurs.
///
- internal static void Write(Action writeHandler, string tabSpace, object obj, Type type)
+ internal static void Write(Action writeHandler, string tabSpace, object? obj, Type type)
{
if (obj == null) { return; }
@@ -283,20 +282,20 @@ internal static void Write(Action writeHandler, string tabSpace,
ContentSerializationContext context = new ContentSerializationContext();
writer.Write(context, obj);
- foreach (KeyValuePair ctxt in context.Content)
+ foreach ((var key, ContentSerializationContextValue value) in context.Content)
{
- if (ctxt.Value.Object == null) { continue; }
+ if (value.Object == null) { continue; }
- if (s_types.TryGetValue(ctxt.Value.Type.Name.ToUpper(), out IType it) ||
- s_types.TryGetValue(ctxt.Value.Type.BaseType.Name.ToUpper(), out it))
+ if (s_types.TryGetValue(value.Type.Name.ToUpper(), out IType it) ||
+ s_types.TryGetValue(value.Type.BaseType!.Name.ToUpper(), out it))
{
- it.Write(writeHandler, tabSpace, ctxt.Key, ctxt.Value.Object);
+ it.Write(writeHandler, tabSpace, key, value.Object);
}
else
{
- writeHandler(tabSpace, $"[{ctxt.Key}:{ctxt.Value.Type}]");
- Write(writeHandler, tabSpace + TABSPACE, ctxt.Value.Object, ctxt.Value.Type);
- writeHandler(tabSpace, $"[/{ctxt.Key}]");
+ writeHandler(tabSpace, $"[{key}:{value.Type}]");
+ Write(writeHandler, tabSpace + TABSPACE, value.Object, value.Type);
+ writeHandler(tabSpace, $"[/{key}]");
}
}
}
@@ -306,10 +305,10 @@ internal static void Write(Action writeHandler, string tabSpace,
#region ContentReader
///
- /// Reads a object from the given stream.
+ /// Reads an object from the given stream.
///
/// Generic type parameter.
- /// Stream.
+ /// The stream.
/// (Optional) True to keep open.
///
/// A T.
@@ -347,11 +346,11 @@ public static T Read(Stream stream, bool keepOpen = false) where T : class
///
/// Reads a object from the given stream.
///
- /// Stream.
- /// the type the reader can read.
+ /// The stream.
+ /// The type the reader can read.
/// The object key.
///
- /// T Object.
+ /// An object.
///
///
/// Thrown when a Create struct Reader error condition
@@ -365,9 +364,7 @@ internal static object Read(CSStreamReader stream, Type type, string objKey)
}
ContentSerializationContext context = new ContentSerializationContext();
-
Read(stream, ref context, objKey);
-
return reader.Read(context);
}
@@ -404,7 +401,7 @@ private static void Read(CSStreamReader stream, ref ContentSerializationContext
if (string.IsNullOrEmpty(genericTypeInfo))
{
throw new CSReaderException(
- $"ERROR: NO GENERIC TYPE INFO DEFINED -> {baseTypeInfo}");
+ $"ERROR: No generic type info defined -> {baseTypeInfo}");
}
context.Set(
key, it.Read(stream, key, genericTypeInfo, dimensionInfo), it.BaseType);
@@ -422,14 +419,15 @@ private static void Read(CSStreamReader stream, ref ContentSerializationContext
if ($"/{objKey}" != key)
{
throw new CSReaderException(
- $"ERROR: INVALID ENDTAG DEFINITION! -> {objKey} != {key}");
+ $"ERROR: Invalid end tag definition! -> {objKey} != {key}");
}
return;
}
}
break;
case '/':
- throw new CSReaderException($"ERROR: INVALID FILE CONTENT! -> invalid char '{c}'!");
+ throw new CSReaderException(
+ $"ERROR: Invalid file content char '{c}' at ({stream.Line}:{stream.Index})!");
case '\n':
case '\r':
case '\t':
@@ -437,7 +435,7 @@ private static void Read(CSStreamReader stream, ref ContentSerializationContext
break;
default:
Console.WriteLine(
- $"WARNING: invalid char '{c}' found near line {stream.Line} -> index {stream.Index}!");
+ $"WARNING: invalid char '{c}' found near ({stream.Line}:{stream.Index})!");
break;
}
}
diff --git a/src/Exomia.Framework/ContentSerialization/Readers/ColorCR.cs b/src/Exomia.Framework/ContentSerialization/Readers/ColorContentSerializationReader.cs
similarity index 81%
rename from src/Exomia.Framework/ContentSerialization/Readers/ColorCR.cs
rename to src/Exomia.Framework/ContentSerialization/Readers/ColorContentSerializationReader.cs
index 28a1b21f..807719e9 100644
--- a/src/Exomia.Framework/ContentSerialization/Readers/ColorCR.cs
+++ b/src/Exomia.Framework/ContentSerialization/Readers/ColorContentSerializationReader.cs
@@ -12,10 +12,7 @@
namespace Exomia.Framework.ContentSerialization.Readers
{
- ///
- /// A color carriage return. This class cannot be inherited.
- ///
- sealed class ColorCR : ContentSerializationReader
+ sealed class ColorContentSerializationReader : ContentSerializationReader
{
///
public override Color ReadContext(ContentSerializationContext context)
diff --git a/src/Exomia.Framework/ContentSerialization/Readers/RectangleContentSerializationReader.cs b/src/Exomia.Framework/ContentSerialization/Readers/RectangleContentSerializationReader.cs
new file mode 100644
index 00000000..7a434a2d
--- /dev/null
+++ b/src/Exomia.Framework/ContentSerialization/Readers/RectangleContentSerializationReader.cs
@@ -0,0 +1,29 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using SharpDX;
+
+namespace Exomia.Framework.ContentSerialization.Readers
+{
+ sealed class RectangleContentSerializationReader : ContentSerializationReader
+ {
+ ///
+ public override Rectangle ReadContext(ContentSerializationContext context)
+ {
+ return new Rectangle
+ {
+ X = context.Get(nameof(Rectangle.X)),
+ Y = context.Get(nameof(Rectangle.Y)),
+ Width = context.Get(nameof(Rectangle.Width)),
+ Height = context.Get(nameof(Rectangle.Height))
+ };
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Exomia.Framework/ContentSerialization/Readers/RectangleFCR.cs b/src/Exomia.Framework/ContentSerialization/Readers/RectangleFCR.cs
deleted file mode 100644
index 9ef0ec16..00000000
--- a/src/Exomia.Framework/ContentSerialization/Readers/RectangleFCR.cs
+++ /dev/null
@@ -1,50 +0,0 @@
-#region License
-
-// Copyright (c) 2018-2020, exomia
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree.
-
-#endregion
-
-using SharpDX;
-
-namespace Exomia.Framework.ContentSerialization.Readers
-{
- ///
- /// A rectangle fcr. This class cannot be inherited.
- ///
- sealed class RectangleFCR : ContentSerializationReader
- {
- ///
- public override RectangleF ReadContext(ContentSerializationContext context)
- {
- return new RectangleF
- {
- X = context.Get(nameof(RectangleF.X)),
- Y = context.Get(nameof(RectangleF.Y)),
- Width = context.Get(nameof(RectangleF.Width)),
- Height = context.Get(nameof(RectangleF.Height))
- };
- }
- }
-
- ///
- /// A rectangle carriage return. This class cannot be inherited.
- ///
- sealed class RectangleCR : ContentSerializationReader
- {
- ///
- public override Rectangle ReadContext(ContentSerializationContext context)
- {
- return new Rectangle
- {
- X = context.Get(nameof(Rectangle.X)),
- Y = context.Get(nameof(Rectangle.Y)),
- Width = context.Get(nameof(Rectangle.Width)),
- Height = context.Get(nameof(Rectangle.Height))
- };
- }
- }
-}
\ No newline at end of file
diff --git a/src/Exomia.Framework/ContentSerialization/Readers/RectangleFContentSerializationReader.cs b/src/Exomia.Framework/ContentSerialization/Readers/RectangleFContentSerializationReader.cs
new file mode 100644
index 00000000..b06cb526
--- /dev/null
+++ b/src/Exomia.Framework/ContentSerialization/Readers/RectangleFContentSerializationReader.cs
@@ -0,0 +1,29 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using SharpDX;
+
+namespace Exomia.Framework.ContentSerialization.Readers
+{
+ sealed class RectangleFContentSerializationReader : ContentSerializationReader
+ {
+ ///
+ public override RectangleF ReadContext(ContentSerializationContext context)
+ {
+ return new RectangleF
+ {
+ X = context.Get(nameof(RectangleF.X)),
+ Y = context.Get(nameof(RectangleF.Y)),
+ Width = context.Get(nameof(RectangleF.Width)),
+ Height = context.Get(nameof(RectangleF.Height))
+ };
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Exomia.Framework/ContentSerialization/Readers/Vector2CR.cs b/src/Exomia.Framework/ContentSerialization/Readers/Vector2ContentSerializationReader.cs
similarity index 76%
rename from src/Exomia.Framework/ContentSerialization/Readers/Vector2CR.cs
rename to src/Exomia.Framework/ContentSerialization/Readers/Vector2ContentSerializationReader.cs
index 888231d3..13179d1a 100644
--- a/src/Exomia.Framework/ContentSerialization/Readers/Vector2CR.cs
+++ b/src/Exomia.Framework/ContentSerialization/Readers/Vector2ContentSerializationReader.cs
@@ -12,10 +12,7 @@
namespace Exomia.Framework.ContentSerialization.Readers
{
- ///
- /// A vector 2 carriage return. This class cannot be inherited.
- ///
- sealed class Vector2CR : ContentSerializationReader
+ sealed class Vector2ContentSerializationReader : ContentSerializationReader
{
///
public override Vector2 ReadContext(ContentSerializationContext context)
diff --git a/src/Exomia.Framework/ContentSerialization/Readers/Vector3CR.cs b/src/Exomia.Framework/ContentSerialization/Readers/Vector3ContentSerializationReader.cs
similarity index 79%
rename from src/Exomia.Framework/ContentSerialization/Readers/Vector3CR.cs
rename to src/Exomia.Framework/ContentSerialization/Readers/Vector3ContentSerializationReader.cs
index 3511e85f..a07eda88 100644
--- a/src/Exomia.Framework/ContentSerialization/Readers/Vector3CR.cs
+++ b/src/Exomia.Framework/ContentSerialization/Readers/Vector3ContentSerializationReader.cs
@@ -12,10 +12,7 @@
namespace Exomia.Framework.ContentSerialization.Readers
{
- ///
- /// A vector 3 carriage return. This class cannot be inherited.
- ///
- sealed class Vector3CR : ContentSerializationReader
+ sealed class Vector3ContentSerializationReader : ContentSerializationReader
{
///
public override Vector3 ReadContext(ContentSerializationContext context)
diff --git a/src/Exomia.Framework/ContentSerialization/Types/DictionaryType.cs b/src/Exomia.Framework/ContentSerialization/Types/DictionaryType.cs
index 91cd9a7f..a04c4be7 100644
--- a/src/Exomia.Framework/ContentSerialization/Types/DictionaryType.cs
+++ b/src/Exomia.Framework/ContentSerialization/Types/DictionaryType.cs
@@ -142,6 +142,29 @@ public void Write(Action writeHandler,
Write(writeHandler, tabSpace, key, (dynamic)content, useTypeInfo);
}
+ ///
+ ///
+ ///
+ /// Type of the key.
+ /// Type of the value.
+ /// The write handler.
+ /// The tab space.
+ /// The key.
+ /// The content.
+ /// (Optional) True to use type information.
+ private void Write(Action writeHandler,
+ string tabSpace,
+ string key,
+ Dictionary content,
+ bool useTypeInfo = true)
+ {
+ writeHandler(
+ tabSpace,
+ $"[{key}:{(useTypeInfo ? CreateTypeInfo(content.GetType()) : string.Empty)}({content.Count})]");
+ ForeachDictionaryDimension(writeHandler, tabSpace + ContentSerializer.TABSPACE, content);
+ writeHandler(tabSpace, $"[/{(useTypeInfo ? key : string.Empty)}]");
+ }
+
#region WriteHelper
///
@@ -179,29 +202,6 @@ private static void ForeachDictionaryDimension(Action
- ///
- ///
- /// Type of the key.
- /// Type of the value.
- /// The write handler.
- /// The tab space.
- /// The key.
- /// The content.
- /// (Optional) True to use type information.
- private void Write(Action writeHandler,
- string tabSpace,
- string key,
- Dictionary content,
- bool useTypeInfo = true)
- {
- writeHandler(
- tabSpace,
- $"[{key}:{(useTypeInfo ? CreateTypeInfo(content.GetType()) : string.Empty)}({content.Count})]");
- ForeachDictionaryDimension(writeHandler, tabSpace + ContentSerializer.TABSPACE, content);
- writeHandler(tabSpace, $"[/{(useTypeInfo ? key : string.Empty)}]");
- }
-
#region ReaderHelper
///
diff --git a/src/Exomia.Framework/ContentSerialization/Types/ListType.cs b/src/Exomia.Framework/ContentSerialization/Types/ListType.cs
index 7d5ecc13..5e2ba99f 100644
--- a/src/Exomia.Framework/ContentSerialization/Types/ListType.cs
+++ b/src/Exomia.Framework/ContentSerialization/Types/ListType.cs
@@ -125,6 +125,28 @@ public void Write(Action writeHandler,
Write(writeHandler, tabSpace, key, (dynamic)content, useTypeInfo);
}
+ ///
+ /// Writes.
+ ///
+ /// Generic type parameter.
+ /// The write handler.
+ /// The tab space.
+ /// The key.
+ /// The content.
+ /// (Optional) True to use type information.
+ private void Write(Action writeHandler,
+ string tabSpace,
+ string key,
+ List content,
+ bool useTypeInfo = true)
+ {
+ writeHandler(
+ tabSpace,
+ $"[{key}:{(useTypeInfo ? CreateTypeInfo(content.GetType()) : string.Empty)}({content.Count})]");
+ ForeachListDimension(writeHandler, tabSpace + ContentSerializer.TABSPACE, content);
+ writeHandler(tabSpace, $"[/{(useTypeInfo ? key : string.Empty)}]");
+ }
+
#region WriteHelper
///
@@ -155,28 +177,6 @@ private static void ForeachListDimension(Action writeHandler,
#endregion
- ///
- /// Writes.
- ///
- /// Generic type parameter.
- /// The write handler.
- /// The tab space.
- /// The key.
- /// The content.
- /// (Optional) True to use type information.
- private void Write(Action writeHandler,
- string tabSpace,
- string key,
- List content,
- bool useTypeInfo = true)
- {
- writeHandler(
- tabSpace,
- $"[{key}:{(useTypeInfo ? CreateTypeInfo(content.GetType()) : string.Empty)}({content.Count})]");
- ForeachListDimension(writeHandler, tabSpace + ContentSerializer.TABSPACE, content);
- writeHandler(tabSpace, $"[/{(useTypeInfo ? key : string.Empty)}]");
- }
-
#region ReaderHelper
///
diff --git a/src/Exomia.Framework/ContentSerialization/Writers/ColorCW.cs b/src/Exomia.Framework/ContentSerialization/Writers/ColorContentSerializationWriter.cs
similarity index 80%
rename from src/Exomia.Framework/ContentSerialization/Writers/ColorCW.cs
rename to src/Exomia.Framework/ContentSerialization/Writers/ColorContentSerializationWriter.cs
index be18a7c7..8d2df092 100644
--- a/src/Exomia.Framework/ContentSerialization/Writers/ColorCW.cs
+++ b/src/Exomia.Framework/ContentSerialization/Writers/ColorContentSerializationWriter.cs
@@ -12,10 +12,7 @@
namespace Exomia.Framework.ContentSerialization.Writers
{
- ///
- /// A color cw. This class cannot be inherited.
- ///
- sealed class ColorCW : ContentSerializationWriter
+ sealed class ColorContentSerializationWriter : ContentSerializationWriter
{
///
public override void WriteContext(ContentSerializationContext context, Color obj)
diff --git a/src/Exomia.Framework/ContentSerialization/Writers/RectangleContentSerializationWriter.cs b/src/Exomia.Framework/ContentSerialization/Writers/RectangleContentSerializationWriter.cs
new file mode 100644
index 00000000..45f6b66f
--- /dev/null
+++ b/src/Exomia.Framework/ContentSerialization/Writers/RectangleContentSerializationWriter.cs
@@ -0,0 +1,26 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using SharpDX;
+
+namespace Exomia.Framework.ContentSerialization.Writers
+{
+ sealed class RectangleContentSerializationWriter : ContentSerializationWriter
+ {
+ ///
+ public override void WriteContext(ContentSerializationContext context, Rectangle obj)
+ {
+ context.Set(nameof(Rectangle.X), obj.X);
+ context.Set(nameof(Rectangle.Y), obj.Y);
+ context.Set(nameof(Rectangle.Width), obj.Width);
+ context.Set(nameof(Rectangle.Height), obj.Height);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Exomia.Framework/ContentSerialization/Writers/RectangleFCW.cs b/src/Exomia.Framework/ContentSerialization/Writers/RectangleFCW.cs
deleted file mode 100644
index 461cf87d..00000000
--- a/src/Exomia.Framework/ContentSerialization/Writers/RectangleFCW.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-#region License
-
-// Copyright (c) 2018-2020, exomia
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree.
-
-#endregion
-
-using SharpDX;
-
-namespace Exomia.Framework.ContentSerialization.Writers
-{
- ///
- /// A rectangle fcw. This class cannot be inherited.
- ///
- sealed class RectangleFCW : ContentSerializationWriter
- {
- ///
- public override void WriteContext(ContentSerializationContext context, RectangleF obj)
- {
- context.Set(nameof(RectangleF.X), obj.X);
- context.Set(nameof(RectangleF.Y), obj.Y);
- context.Set(nameof(RectangleF.Width), obj.Width);
- context.Set(nameof(RectangleF.Height), obj.Height);
- }
- }
-
- ///
- /// A rectangle cw. This class cannot be inherited.
- ///
- sealed class RectangleCW : ContentSerializationWriter
- {
- ///
- public override void WriteContext(ContentSerializationContext context, Rectangle obj)
- {
- context.Set(nameof(Rectangle.X), obj.X);
- context.Set(nameof(Rectangle.Y), obj.Y);
- context.Set(nameof(Rectangle.Width), obj.Width);
- context.Set(nameof(Rectangle.Height), obj.Height);
- }
- }
-}
\ No newline at end of file
diff --git a/src/Exomia.Framework/ContentSerialization/Writers/RectangleFContentSerializationWriter.cs b/src/Exomia.Framework/ContentSerialization/Writers/RectangleFContentSerializationWriter.cs
new file mode 100644
index 00000000..4bca32a3
--- /dev/null
+++ b/src/Exomia.Framework/ContentSerialization/Writers/RectangleFContentSerializationWriter.cs
@@ -0,0 +1,26 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using SharpDX;
+
+namespace Exomia.Framework.ContentSerialization.Writers
+{
+ sealed class RectangleFContentSerializationWriter : ContentSerializationWriter
+ {
+ ///
+ public override void WriteContext(ContentSerializationContext context, RectangleF obj)
+ {
+ context.Set(nameof(RectangleF.X), obj.X);
+ context.Set(nameof(RectangleF.Y), obj.Y);
+ context.Set(nameof(RectangleF.Width), obj.Width);
+ context.Set(nameof(RectangleF.Height), obj.Height);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Exomia.Framework/ContentSerialization/Writers/Vector2CW.cs b/src/Exomia.Framework/ContentSerialization/Writers/Vector2ContentSerializationWriter.cs
similarity index 77%
rename from src/Exomia.Framework/ContentSerialization/Writers/Vector2CW.cs
rename to src/Exomia.Framework/ContentSerialization/Writers/Vector2ContentSerializationWriter.cs
index 040c151e..748ea654 100644
--- a/src/Exomia.Framework/ContentSerialization/Writers/Vector2CW.cs
+++ b/src/Exomia.Framework/ContentSerialization/Writers/Vector2ContentSerializationWriter.cs
@@ -12,10 +12,7 @@
namespace Exomia.Framework.ContentSerialization.Writers
{
- ///
- /// A vector 2 cw. This class cannot be inherited.
- ///
- sealed class Vector2CW : ContentSerializationWriter
+ sealed class Vector2ContentSerializationWriter : ContentSerializationWriter
{
///
public override void WriteContext(ContentSerializationContext context, Vector2 obj)
diff --git a/src/Exomia.Framework/ContentSerialization/Writers/Vector3CW.cs b/src/Exomia.Framework/ContentSerialization/Writers/Vector3ContentSerializationWriter.cs
similarity index 79%
rename from src/Exomia.Framework/ContentSerialization/Writers/Vector3CW.cs
rename to src/Exomia.Framework/ContentSerialization/Writers/Vector3ContentSerializationWriter.cs
index 214e2cc9..1c20f06c 100644
--- a/src/Exomia.Framework/ContentSerialization/Writers/Vector3CW.cs
+++ b/src/Exomia.Framework/ContentSerialization/Writers/Vector3ContentSerializationWriter.cs
@@ -12,10 +12,7 @@
namespace Exomia.Framework.ContentSerialization.Writers
{
- ///
- /// A vector 3 cw. This class cannot be inherited.
- ///
- sealed class Vector3CW : ContentSerializationWriter
+ sealed class Vector3ContentSerializationWriter : ContentSerializationWriter
{
///
public override void WriteContext(ContentSerializationContext context, Vector3 obj)
diff --git a/src/Exomia.Framework/DrawableComparer.cs b/src/Exomia.Framework/DrawableComparer.cs
index 1e6d1dcd..82420035 100644
--- a/src/Exomia.Framework/DrawableComparer.cs
+++ b/src/Exomia.Framework/DrawableComparer.cs
@@ -30,16 +30,6 @@ public int Compare(IDrawable left, IDrawable right)
return 0;
}
- if (left == null)
- {
- return 1;
- }
-
- if (right == null)
- {
- return -1;
- }
-
return left.DrawOrder < right.DrawOrder ? 1 : -1;
}
}
diff --git a/src/Exomia.Framework/Exomia.Framework.csproj b/src/Exomia.Framework/Exomia.Framework.csproj
index dd0dc96a..94b6dfea 100644
--- a/src/Exomia.Framework/Exomia.Framework.csproj
+++ b/src/Exomia.Framework/Exomia.Framework.csproj
@@ -8,10 +8,10 @@
true
enable
true
+ TRACE;$(Platform)
- 1.4.1
exomia
exomia;saika01
a framework for building 2D and 3D games and more inspired by the XNA/Mono framework
@@ -42,16 +42,13 @@
portable
true
- DEBUG;TRACE;x86
- DEBUG;TRACE;$(Platform)
true
+ $(DefineConstants);DEBUG
none
false
- TRACE;x86
- TRACE;$(Platform)
@@ -65,7 +62,7 @@
- 1701;1702;IDE0063
+ 1701;1702;IDE0063;IDE0079
NU1605
false
logo_x192_Hcn_icon.ico
@@ -103,6 +100,7 @@
+
@@ -151,6 +149,7 @@
$(MSBuildProjectName).Resources.fonts.arial.arial_38px.e1
+
@@ -162,25 +161,53 @@
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
+
RenderForm.cs
+
+
+
+
+ Math2.cs
+
+
+
+
+
+
+ SpriteBatch.cs
+
+
+
+
+
+
+ Canvas.cs
+
+
+
+
+
+
+ SpriteFont.cs
+
+
diff --git a/src/Exomia.Framework/Extensions/DeconstructExtensions.cs b/src/Exomia.Framework/Extensions/DeconstructExtensions.cs
new file mode 100644
index 00000000..1bd06e80
--- /dev/null
+++ b/src/Exomia.Framework/Extensions/DeconstructExtensions.cs
@@ -0,0 +1,37 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+#if NETSTANDARD2_0
+using System.Collections.Generic;
+
+namespace Exomia.Framework.Extensions
+{
+
+ ///
+ /// A deconstruct extensions.
+ ///
+ public static class DeconstructExtensions
+ {
+ ///
+ /// A type deconstruct-or that extracts the individual members from this object.
+ ///
+ /// Type of the key.
+ /// Type of the value.
+ /// The kvp.
+ /// [out] The key.
+ /// [out] The value.
+ public static void Deconstruct(this KeyValuePair kvp, out TKey key, out TValue value)
+ {
+ key = kvp.Key;
+ value = kvp.Value;
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/Exomia.Framework/Graphics/Camera/Camera3D.cs b/src/Exomia.Framework/Game/Camera/Camera3D.cs
similarity index 99%
rename from src/Exomia.Framework/Graphics/Camera/Camera3D.cs
rename to src/Exomia.Framework/Game/Camera/Camera3D.cs
index 198c97c1..86abbc5b 100644
--- a/src/Exomia.Framework/Graphics/Camera/Camera3D.cs
+++ b/src/Exomia.Framework/Game/Camera/Camera3D.cs
@@ -10,11 +10,10 @@
using System;
using System.Collections.Generic;
-using Exomia.Framework.Game;
using Exomia.Framework.Input;
using SharpDX;
-namespace Exomia.Framework.Graphics.Camera
+namespace Exomia.Framework.Game.Camera
{
///
/// A camera base.
diff --git a/src/Exomia.Framework/Graphics/Camera/Controller/RotationController.cs b/src/Exomia.Framework/Game/Camera/Controller/RotationController.cs
similarity index 95%
rename from src/Exomia.Framework/Graphics/Camera/Controller/RotationController.cs
rename to src/Exomia.Framework/Game/Camera/Controller/RotationController.cs
index fd40f04b..7a05858d 100644
--- a/src/Exomia.Framework/Graphics/Camera/Controller/RotationController.cs
+++ b/src/Exomia.Framework/Game/Camera/Controller/RotationController.cs
@@ -10,12 +10,11 @@
using System;
using System.Threading;
-using Exomia.Framework.Game;
using Exomia.Framework.Input;
using Exomia.Framework.Mathematics;
using SharpDX;
-namespace Exomia.Framework.Graphics.Camera.Controller
+namespace Exomia.Framework.Game.Camera.Controller
{
///
/// A controller for handling rotations. This class cannot be inherited.
@@ -100,14 +99,14 @@ void IInputHandler.UnregisterInput(IInputDevice device)
device.RegisterRawMouseInput(CameraOnRawMouseInput);
}
- private bool CameraOnRawMouseInput(in MouseEventArgs mouseEventArgs)
+ private EventAction CameraOnRawMouseInput(in MouseEventArgs mouseEventArgs)
{
if (mouseEventArgs.X != 0 || mouseEventArgs.Y != 0)
{
Interlocked.Add(ref _x, mouseEventArgs.X);
Interlocked.Add(ref _y, mouseEventArgs.Y);
}
- return false;
+ return EventAction.Continue;
}
}
}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Graphics/Camera/Controller/TranslationKeyboardController.cs b/src/Exomia.Framework/Game/Camera/Controller/TranslationKeyboardController.cs
similarity index 91%
rename from src/Exomia.Framework/Graphics/Camera/Controller/TranslationKeyboardController.cs
rename to src/Exomia.Framework/Game/Camera/Controller/TranslationKeyboardController.cs
index 1731984a..70c4b04d 100644
--- a/src/Exomia.Framework/Graphics/Camera/Controller/TranslationKeyboardController.cs
+++ b/src/Exomia.Framework/Game/Camera/Controller/TranslationKeyboardController.cs
@@ -9,11 +9,10 @@
#endregion
using System.Collections.Generic;
-using Exomia.Framework.Game;
using Exomia.Framework.Input;
using SharpDX;
-namespace Exomia.Framework.Graphics.Camera.Controller
+namespace Exomia.Framework.Game.Camera.Controller
{
///
/// A controller for handling translation keyboards. This class cannot be inherited.
@@ -100,16 +99,16 @@ void IUpdateableCameraComponent.Update(GameTime gameTime, ICamera camera)
}
}
- private bool CameraOnKeyDown(int keyValue, KeyModifier modifiers)
+ private EventAction CameraOnKeyDown(int keyValue, KeyModifier modifiers)
{
_keysDown.Add(keyValue);
- return false;
+ return EventAction.Continue;
}
- private bool CameraOnKeyUp(int keyValue, KeyModifier modifiers)
+ private EventAction CameraOnKeyUp(int keyValue, KeyModifier modifiers)
{
_keysDown.Remove(keyValue);
- return false;
+ return EventAction.Continue;
}
}
}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Graphics/Camera/ICamera.cs b/src/Exomia.Framework/Game/Camera/ICamera.cs
similarity index 98%
rename from src/Exomia.Framework/Graphics/Camera/ICamera.cs
rename to src/Exomia.Framework/Game/Camera/ICamera.cs
index af4ce15f..c3c0ca4f 100644
--- a/src/Exomia.Framework/Graphics/Camera/ICamera.cs
+++ b/src/Exomia.Framework/Game/Camera/ICamera.cs
@@ -11,7 +11,7 @@
using Exomia.Framework.Input;
using SharpDX;
-namespace Exomia.Framework.Graphics.Camera
+namespace Exomia.Framework.Game.Camera
{
///
/// Interface for a camera.
diff --git a/src/Exomia.Framework/Graphics/Camera/ICameraComponent.cs b/src/Exomia.Framework/Game/Camera/ICameraComponent.cs
similarity index 92%
rename from src/Exomia.Framework/Graphics/Camera/ICameraComponent.cs
rename to src/Exomia.Framework/Game/Camera/ICameraComponent.cs
index fc38f35d..9df7560a 100644
--- a/src/Exomia.Framework/Graphics/Camera/ICameraComponent.cs
+++ b/src/Exomia.Framework/Game/Camera/ICameraComponent.cs
@@ -8,7 +8,7 @@
#endregion
-namespace Exomia.Framework.Graphics.Camera
+namespace Exomia.Framework.Game.Camera
{
///
/// Interface for camera component.
diff --git a/src/Exomia.Framework/Graphics/Camera/IDisposableCameraComponent.cs b/src/Exomia.Framework/Game/Camera/IDisposableCameraComponent.cs
similarity index 93%
rename from src/Exomia.Framework/Graphics/Camera/IDisposableCameraComponent.cs
rename to src/Exomia.Framework/Game/Camera/IDisposableCameraComponent.cs
index ba602ef3..af411193 100644
--- a/src/Exomia.Framework/Graphics/Camera/IDisposableCameraComponent.cs
+++ b/src/Exomia.Framework/Game/Camera/IDisposableCameraComponent.cs
@@ -6,7 +6,7 @@
// LICENSE file in the root directory of this source tree.
#endregion
-namespace Exomia.Framework.Graphics.Camera {
+namespace Exomia.Framework.Game.Camera {
///
/// Interface for disposable camera component.
///
diff --git a/src/Exomia.Framework/Graphics/Camera/IInitializableCameraComponent.cs b/src/Exomia.Framework/Game/Camera/IInitializableCameraComponent.cs
similarity index 93%
rename from src/Exomia.Framework/Graphics/Camera/IInitializableCameraComponent.cs
rename to src/Exomia.Framework/Game/Camera/IInitializableCameraComponent.cs
index 4298dba2..6f513c98 100644
--- a/src/Exomia.Framework/Graphics/Camera/IInitializableCameraComponent.cs
+++ b/src/Exomia.Framework/Game/Camera/IInitializableCameraComponent.cs
@@ -8,7 +8,7 @@
#endregion
-namespace Exomia.Framework.Graphics.Camera
+namespace Exomia.Framework.Game.Camera
{
///
/// Interface for initializable camera component.
diff --git a/src/Exomia.Framework/Graphics/Camera/IUpdateableCameraComponent.cs b/src/Exomia.Framework/Game/Camera/IUpdateableCameraComponent.cs
similarity index 89%
rename from src/Exomia.Framework/Graphics/Camera/IUpdateableCameraComponent.cs
rename to src/Exomia.Framework/Game/Camera/IUpdateableCameraComponent.cs
index d811f666..ad71bbdf 100644
--- a/src/Exomia.Framework/Graphics/Camera/IUpdateableCameraComponent.cs
+++ b/src/Exomia.Framework/Game/Camera/IUpdateableCameraComponent.cs
@@ -8,9 +8,7 @@
#endregion
-using Exomia.Framework.Game;
-
-namespace Exomia.Framework.Graphics.Camera
+namespace Exomia.Framework.Game.Camera
{
///
/// Interface for updateable camera component.
diff --git a/src/Exomia.Framework/Game/Desktop/GamePlatformWindows.cs b/src/Exomia.Framework/Game/Desktop/GamePlatformWindows.cs
new file mode 100644
index 00000000..15d6cd4c
--- /dev/null
+++ b/src/Exomia.Framework/Game/Desktop/GamePlatformWindows.cs
@@ -0,0 +1,29 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using Exomia.Framework.Input;
+
+namespace Exomia.Framework.Game.Desktop
+{
+ sealed class GamePlatformWindows : GamePlatform
+ {
+ ///
+ public GamePlatformWindows(Game game, string title)
+ : base(game, title) { }
+
+ ///
+ private protected override IGameWindow CreateGameWindow(Game game, string title)
+ {
+ GameWindowWindows gameWindow = new GameWindowWindows(title);
+ game.Services.AddService(gameWindow.RenderForm);
+ return gameWindow;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Game/WinFormsGameWindow.cs b/src/Exomia.Framework/Game/Desktop/GameWindowWindows.cs
similarity index 73%
rename from src/Exomia.Framework/Game/WinFormsGameWindow.cs
rename to src/Exomia.Framework/Game/Desktop/GameWindowWindows.cs
index dd8f6145..8b989a2e 100644
--- a/src/Exomia.Framework/Game/WinFormsGameWindow.cs
+++ b/src/Exomia.Framework/Game/Desktop/GameWindowWindows.cs
@@ -11,59 +11,43 @@
using System;
using Exomia.Framework.Win32;
-namespace Exomia.Framework.Game
+namespace Exomia.Framework.Game.Desktop
{
///
/// Form for viewing the window forms game. This class cannot be inherited.
///
- sealed class WinFormsGameWindow : IWinFormsGameWindow, IGameWindowInitialize
+ sealed class GameWindowWindows : IGameWindow
{
- ///
- /// Occurs when the form is about to close.
- ///
+ ///
public event RefEventHandler FormClosing
{
add { _renderForm.FormClosing += value; }
remove { _renderForm.FormClosing -= value; }
}
+ ///
+ public event EventHandler FormClosed
+ {
+ add { _renderForm.FormClosed += value; }
+ remove { _renderForm.FormClosed -= value; }
+ }
+
private readonly RenderForm _renderForm;
private bool _isInitialized;
- ///
- /// Gets the width.
- ///
- ///
- /// The width.
- ///
+ ///
public int Width
{
get { return _renderForm.Size.X; }
}
- ///
- /// Gets the height.
- ///
- ///
- /// The height.
- ///
+ ///
public int Height
{
get { return _renderForm.Size.Y; }
}
///
- public RenderForm RenderForm
- {
- get { return _renderForm; }
- }
-
- ///
- /// Gets or sets the title.
- ///
- ///
- /// The title.
- ///
public string Title
{
get { return _renderForm.WindowTitle; }
@@ -71,40 +55,33 @@ public string Title
}
///
- /// Gets a value indicating whether this object is initialized.
+ /// Gets the render form.
///
///
- /// True if this object is initialized, false if not.
+ /// The render form.
///
- bool IGameWindowInitialize.IsInitialized
+ public RenderForm RenderForm
{
- get { return _isInitialized; }
+ get { return _renderForm; }
}
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class.
///
/// The title.
- public WinFormsGameWindow(string title)
+ public GameWindowWindows(string title)
{
_renderForm = new RenderForm(title);
}
- ///
- /// Resizes.
- ///
- /// The width.
- /// The height.
+ ///
public void Resize(int width, int height)
{
_renderForm.Resize(width, height);
}
- ///
- /// Initializes this object.
- ///
- /// [in,out] Options for controlling the operation.
- void IGameWindowInitialize.Initialize(ref GameGraphicsParameters parameters)
+ ///
+ public void Initialize(ref GameGraphicsParameters parameters)
{
if (_isInitialized) { return; }
@@ -166,16 +143,14 @@ void IGameWindowInitialize.Initialize(ref GameGraphicsParameters parameters)
_isInitialized = true;
}
- void IGameWindowInitialize.Show()
+ ///
+ public void Show()
{
_renderForm.Show();
}
#region IDisposable Support
- ///
- /// True if disposed.
- ///
private bool _disposed;
///
@@ -199,9 +174,9 @@ private void Dispose(bool disposing)
}
///
- /// Finalizes an instance of the class.
+ /// Finalizes an instance of the class.
///
- ~WinFormsGameWindow()
+ ~GameWindowWindows()
{
Dispose(false);
}
diff --git a/src/Exomia.Framework/Game/Game.cs b/src/Exomia.Framework/Game/Game.cs
index dcd3270e..dc6d0996 100644
--- a/src/Exomia.Framework/Game/Game.cs
+++ b/src/Exomia.Framework/Game/Game.cs
@@ -19,9 +19,6 @@
using Exomia.Framework.Tools;
using Exomia.Framework.Win32;
using SharpDX;
-using SharpDX.Direct3D;
-using SharpDX.Direct3D11;
-using SharpDX.DXGI;
namespace Exomia.Framework.Game
{
@@ -44,10 +41,9 @@ public abstract class Game : IRunnable
private readonly List _updateableComponent;
private readonly IServiceRegistry _serviceRegistry;
private readonly DisposeCollector _collector;
- private readonly IGameWindowInitialize _gameWindowInitialize;
private readonly IInputDevice _inputDevice;
private readonly IContentManager _contentManager;
- private readonly IGameWindow _gameWindow;
+ private readonly GamePlatform _platform;
private readonly GraphicsDevice _graphicsDevice;
private bool _isRunning, _isInitialized, _isContentLoaded, _shutdown;
@@ -81,7 +77,7 @@ public IContentManager Content
///
public IGameWindow GameWindow
{
- get { return _gameWindow; }
+ get { return _platform.MainWindow; }
}
///
@@ -126,10 +122,10 @@ public bool IsRunning
}
///
- /// Gets or sets the target elapsed time.
+ /// Gets or sets the target elapsed time in ms.
///
///
- /// The target elapsed time.
+ /// The target elapsed time in ms.
///
public double TargetElapsedTime { get; set; } = 1000.0 / 60.0;
@@ -157,16 +153,14 @@ protected Game(string title = "Exomia.Framework",
_collector = new DisposeCollector();
_serviceRegistry = new ServiceRegistry();
- // TODO: use a factory?
- WinFormsGameWindow gameWindow = new WinFormsGameWindow(title);
- gameWindow.FormClosing += (ref bool cancel) => { Shutdown(); };
-
- _gameWindowInitialize = gameWindow;
- _serviceRegistry.AddService(_gameWindow = gameWindow);
-
_serviceRegistry.AddService(_graphicsDevice = new GraphicsDevice());
_serviceRegistry.AddService(_contentManager = new ContentManager(_serviceRegistry));
- _serviceRegistry.AddService(_inputDevice = gameWindow.RenderForm);
+
+ _platform = GamePlatform.Create(this, title);
+ _serviceRegistry.AddService(_platform.MainWindow);
+
+ // NOTE: The input device should be registered during the platform creation!
+ _inputDevice = _serviceRegistry.GetService();
}
///
@@ -178,12 +172,12 @@ protected Game(string title = "Exomia.Framework",
}
///
- /// add a new game system.
+ /// Adds an item to the game.
///
/// T.
/// item.
///
- /// true if successfully added; false otherwise.
+ /// The item.
///
public T Add(T item)
{
@@ -281,12 +275,12 @@ public T Add(T item)
}
///
- /// add a new game system.
+ /// Remove an item from the game.
///
- /// T.
+ /// Generic type parameter.
/// item.
///
- /// true if successfully added; false otherwise.
+ /// The item.
///
public T Remove(T item)
{
@@ -343,7 +337,7 @@ public T Remove(T item)
}
///
- /// get a game system by name.
+ /// Get a game component by its name.
///
/// the game system name.
/// [out] out found game system.
@@ -364,7 +358,7 @@ public void Run()
{
if (_isRunning)
{
- throw new InvalidOperationException("Can't run this instance while it is already running.");
+ throw new InvalidOperationException("The instance is already running!");
}
_isRunning = true;
@@ -373,6 +367,9 @@ public void Run()
{
Initialize();
LoadContent();
+
+ _platform.ShowMainWindow();
+
Renderloop();
UnloadContent();
}
@@ -425,6 +422,7 @@ void OnIsRunningChanged(Game s, bool v)
}
Update(gameTime);
+
if (BeginFrame())
{
Draw(gameTime);
@@ -434,9 +432,9 @@ void OnIsRunningChanged(Game s, bool v)
if (IsFixedTimeStep)
{
//SLEEP
- while (TargetElapsedTime - stopwatch.Elapsed.TotalMilliseconds > FIXED_TIMESTAMP_THRESHOLD)
+ while (TargetElapsedTime - FIXED_TIMESTAMP_THRESHOLD > stopwatch.Elapsed.TotalMilliseconds)
{
- Thread.Sleep(1);
+ Thread.Yield();
}
//IDLE
@@ -482,39 +480,11 @@ protected virtual void OnAfterInitialize() { }
///
private void InitializeGameGraphicsParameters()
{
- GameGraphicsParameters parameters = new GameGraphicsParameters
- {
- BufferCount = 1,
-#if DEBUG
- DeviceCreationFlags =
- DeviceCreationFlags.BgraSupport |
- DeviceCreationFlags.Debug,
-#else
- DeviceCreationFlags =
- DeviceCreationFlags.BgraSupport,
-#endif
- DriverType = DriverType.Hardware,
- Format = Format.B8G8R8A8_UNorm,
- Width = 1024,
- Height = 768,
- DisplayType = DisplayType.Window,
- IsMouseVisible = false,
- Rational = new Rational(60, 1),
- SwapChainFlags = SwapChainFlags.AllowModeSwitch,
- SwapEffect = SwapEffect.Discard,
- Usage = Usage.RenderTargetOutput,
- UseVSync = false,
- WindowAssociationFlags = WindowAssociationFlags.IgnoreAll,
- EnableMultiSampling = false,
- MultiSampleCount = MultiSampleCount.None,
- AdapterLuid = -1,
- OutputIndex = -1,
- ClipCursor = false
- };
+ GameGraphicsParameters parameters = GameGraphicsParameters.Create(IntPtr.Zero);
OnInitializeGameGraphicsParameters(ref parameters);
- _gameWindowInitialize.Initialize(ref parameters);
+ _platform.Initialize(ref parameters);
_graphicsDevice.Initialize(ref parameters);
GameGraphicsParameters = parameters;
@@ -544,8 +514,8 @@ private void Initialize()
OnInitialize();
InitializePendingInitializations();
_isInitialized = true;
+
OnAfterInitialize();
- _gameWindowInitialize.Show();
}
}
@@ -570,7 +540,6 @@ private void LoadContent()
{
if (!_isContentLoaded)
{
- _isContentLoaded = true;
OnLoadContent();
lock (_contentableComponent)
@@ -584,6 +553,8 @@ private void LoadContent()
}
_currentlyContentableComponent.Clear();
+
+ _isContentLoaded = true;
}
}
@@ -607,11 +578,12 @@ private void UnloadContent()
_currentlyContentableComponent.Clear();
OnUnloadContent();
+
_isContentLoaded = false;
}
}
- #endregion Content
+ #endregion
#region Update
@@ -789,10 +761,10 @@ public Timer2 AddTimer(float tick,
#region IDisposable Support
///
- /// adds a IDisposable object to the dispose collector.
+ /// Adds a object to the dispose collector.
///
- /// .
- /// .
+ /// Generic type parameter.
+ /// The object.
///
/// Obj as a T.
///
@@ -801,9 +773,6 @@ public T ToDispose(T obj) where T : IDisposable
return _collector.Collect(obj);
}
- ///
- /// True if disposed.
- ///
private bool _disposed;
///
@@ -845,9 +814,10 @@ private void Dispose(bool disposing)
_gameComponents.Clear();
_pendingInitializables.Clear();
+ _platform.Dispose();
+
_contentManager.Dispose();
_graphicsDevice.Dispose();
- _gameWindow.Dispose();
}
_collector.DisposeAndClear(disposing);
diff --git a/src/Exomia.Framework/Game/GameGraphicsParameters.cs b/src/Exomia.Framework/Game/GameGraphicsParameters.cs
index 2ba51426..e0aadb7c 100644
--- a/src/Exomia.Framework/Game/GameGraphicsParameters.cs
+++ b/src/Exomia.Framework/Game/GameGraphicsParameters.cs
@@ -124,5 +124,54 @@ public struct GameGraphicsParameters
/// The output index.
///
public int OutputIndex;
+
+ ///
+ /// Creates a new object with default settings.
+ ///
+ /// The handle.
+ ///
+ /// (Optional)
+ /// Define the width of the .
+ ///
+ ///
+ /// (Optional)
+ /// Define the height of the .
+ ///
+ ///
+ /// The .
+ ///
+ public static GameGraphicsParameters Create(IntPtr handle, int width = 1024, int height = 768)
+ {
+ return new GameGraphicsParameters
+ {
+ Handle = handle,
+ BufferCount = 1,
+#if DEBUG
+ DeviceCreationFlags =
+ DeviceCreationFlags.BgraSupport |
+ DeviceCreationFlags.Debug,
+#else
+ DeviceCreationFlags =
+ DeviceCreationFlags.BgraSupport,
+#endif
+ DriverType = DriverType.Hardware,
+ Format = Format.B8G8R8A8_UNorm,
+ Width = width,
+ Height = height,
+ DisplayType = DisplayType.Window,
+ IsMouseVisible = false,
+ Rational = new Rational(60, 1),
+ SwapChainFlags = SwapChainFlags.AllowModeSwitch,
+ SwapEffect = SwapEffect.Discard,
+ Usage = Usage.RenderTargetOutput,
+ UseVSync = false,
+ WindowAssociationFlags = WindowAssociationFlags.IgnoreAll,
+ EnableMultiSampling = false,
+ MultiSampleCount = MultiSampleCount.None,
+ AdapterLuid = -1,
+ OutputIndex = -1,
+ ClipCursor = false
+ };
+ }
}
}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Game/GamePlatform.cs b/src/Exomia.Framework/Game/GamePlatform.cs
new file mode 100644
index 00000000..f2331233
--- /dev/null
+++ b/src/Exomia.Framework/Game/GamePlatform.cs
@@ -0,0 +1,104 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using System;
+using Exomia.Framework.Game.Desktop;
+
+namespace Exomia.Framework.Game
+{
+ abstract class GamePlatform : IDisposable
+ {
+ private readonly IGameWindow _mainWindow;
+
+ public IGameWindow MainWindow
+ {
+ get { return _mainWindow; }
+ }
+
+ protected GamePlatform(Game game, string title)
+ {
+ // ReSharper disable once VirtualMemberCallInConstructor
+ _mainWindow = CreateGameWindow(game, title);
+ _mainWindow.FormClosed += game.Shutdown;
+ }
+
+ ///
+ /// Initializes the .
+ ///
+ /// [in,out] Options for controlling the operation.
+ public void Initialize(ref GameGraphicsParameters parameters)
+ {
+ _mainWindow.Initialize(ref parameters);
+ }
+
+ ///
+ /// Shows the main window.
+ ///
+ public void ShowMainWindow()
+ {
+ _mainWindow.Show();
+ }
+
+ private protected abstract IGameWindow CreateGameWindow(Game game, string title);
+
+ ///
+ /// Creates a new .
+ ///
+ /// The game.
+ /// The title.
+ ///
+ /// A .
+ ///
+ public static GamePlatform Create(Game game, string title)
+ {
+ return new GamePlatformWindows(game, title);
+ }
+
+ #region IDisposable Support
+
+ private bool _disposed;
+
+ ///
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged/managed resources.
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ private void Dispose(bool disposing)
+ {
+ if (!_disposed)
+ {
+ OnDispose(disposing);
+ if (disposing)
+ {
+ _mainWindow.Dispose();
+ }
+ _disposed = true;
+ }
+ }
+
+ ///
+ ~GamePlatform()
+ {
+ Dispose(false);
+ }
+
+ ///
+ /// called then the instance is disposing
+ ///
+ /// true if user code; false called by finalizer
+ protected virtual void OnDispose(bool disposing) { }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Game/GameTime.cs b/src/Exomia.Framework/Game/GameTime.cs
index 4f42fc82..fa9f7655 100644
--- a/src/Exomia.Framework/Game/GameTime.cs
+++ b/src/Exomia.Framework/Game/GameTime.cs
@@ -99,17 +99,6 @@ private GameTime()
_prevTime = _baseTime = Stopwatch.GetTimestamp();
}
- ///
- /// Starts a new.
- ///
- ///
- /// A GameTime.
- ///
- public static GameTime StartNew()
- {
- return new GameTime();
- }
-
///
/// reset the game time.
///
@@ -172,5 +161,16 @@ public void Tick()
_prevTime = _currTime;
}
+
+ ///
+ /// Starts a new.
+ ///
+ ///
+ /// A GameTime.
+ ///
+ public static GameTime StartNew()
+ {
+ return new GameTime();
+ }
}
}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Game/IGameWindow.cs b/src/Exomia.Framework/Game/IGameWindow.cs
index 95ef3a4e..bad7fcb8 100644
--- a/src/Exomia.Framework/Game/IGameWindow.cs
+++ b/src/Exomia.Framework/Game/IGameWindow.cs
@@ -12,30 +12,8 @@
namespace Exomia.Framework.Game
{
- interface IGameWindowInitialize
- {
- ///
- /// Gets a value indicating whether this object is initialized.
- ///
- ///
- /// True if this object is initialized, false if not.
- ///
- bool IsInitialized { get; }
-
- ///
- /// Initializes this object.
- ///
- /// [in,out] Options for controlling the operation.
- void Initialize(ref GameGraphicsParameters parameters);
-
- ///
- /// Shows this object.
- ///
- void Show();
- }
-
///
- /// IGameWindow interface.
+ /// Interface for game window.
///
public interface IGameWindow : IDisposable
{
@@ -45,12 +23,9 @@ public interface IGameWindow : IDisposable
event RefEventHandler FormClosing;
///
- /// Gets the height.
+ /// Occurs when the form is closed.
///
- ///
- /// The height.
- ///
- int Height { get; }
+ event EventHandler FormClosed;
///
/// Gets or sets the title.
@@ -60,6 +35,14 @@ public interface IGameWindow : IDisposable
///
string Title { get; set; }
+ ///
+ /// Gets the height.
+ ///
+ ///
+ /// The height.
+ ///
+ int Height { get; }
+
///
/// Gets the width.
///
@@ -69,10 +52,21 @@ public interface IGameWindow : IDisposable
int Width { get; }
///
- /// Resizes.
+ /// Resizes the game window.
///
/// The width.
/// The height.
void Resize(int width, int height);
+
+ ///
+ /// Initializes this object.
+ ///
+ /// [in,out] Options for controlling the operation.
+ void Initialize(ref GameGraphicsParameters parameters);
+
+ ///
+ /// Shows the game window.
+ ///
+ void Show();
}
}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Game/IWinFormsGameWindow.cs b/src/Exomia.Framework/Game/IWinFormsGameWindow.cs
deleted file mode 100644
index 1e61703b..00000000
--- a/src/Exomia.Framework/Game/IWinFormsGameWindow.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-#region License
-
-// Copyright (c) 2018-2020, exomia
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree.
-
-#endregion
-
-namespace Exomia.Framework.Game
-{
- ///
- /// IWinFormsGameWindow interface.
- ///
- public interface IWinFormsGameWindow : IGameWindow
- {
- ///
- /// Gets the render form.
- ///
- ///
- /// The render form.
- ///
- RenderForm RenderForm { get; }
- }
-}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Game/RenderForm.Events.cs b/src/Exomia.Framework/Game/RenderForm.Events.cs
index 7ddcbd5c..ef7437dc 100644
--- a/src/Exomia.Framework/Game/RenderForm.Events.cs
+++ b/src/Exomia.Framework/Game/RenderForm.Events.cs
@@ -46,6 +46,11 @@ sealed partial class RenderForm
///
public event RefEventHandler? FormClosing;
+ ///
+ /// Occurs when the form is closed.
+ ///
+ public event EventHandler? FormClosed;
+
private unsafe IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
{
Message m;
@@ -96,6 +101,7 @@ private unsafe IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lPara
FormClosing?.Invoke(ref cancel);
if (!cancel)
{
+ FormClosed?.Invoke();
User32.DestroyWindow(_hWnd);
}
return IntPtr.Zero;
@@ -161,7 +167,11 @@ private unsafe IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lPara
MouseButtons mouseButtons = (MouseButtons)LowWord(m.wParam);
for (int i = 0; i < _mouseMovePipe.Count; i++)
{
- if (_mouseMovePipe[i].Invoke(new MouseEventArgs(x, y, mouseButtons, 0, 0))) { break; }
+ if (_mouseMovePipe[i].Invoke(new MouseEventArgs(x, y, mouseButtons, 0, 0)) ==
+ EventAction.StopPropagation)
+ {
+ break;
+ }
}
return IntPtr.Zero;
}
@@ -173,7 +183,8 @@ private unsafe IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lPara
int wheelDelta = HighWord(m.wParam);
for (int i = 0; i < _mouseWheelPipe.Count; i++)
{
- if (_mouseWheelPipe[i].Invoke(new MouseEventArgs(x, y, mouseButtons, 2, wheelDelta)))
+ if (_mouseWheelPipe[i].Invoke(new MouseEventArgs(x, y, mouseButtons, 2, wheelDelta)) ==
+ EventAction.StopPropagation)
{
break;
}
@@ -191,7 +202,11 @@ private unsafe IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lPara
MouseButtons mouseButtons = (MouseButtons)LowWord(m.wParam);
for (int i = 0; i < _mouseClickPipe.Count; i++)
{
- if (_mouseClickPipe[i].Invoke(new MouseEventArgs(x, y, mouseButtons, 2, 0))) { break; }
+ if (_mouseClickPipe[i].Invoke(new MouseEventArgs(x, y, mouseButtons, 2, 0)) ==
+ EventAction.StopPropagation)
+ {
+ break;
+ }
}
return IntPtr.Zero;
}
@@ -204,7 +219,7 @@ private void RawKeyMessage(ref Message m)
{
for (int i = 0; i < _rawKeyPipe.Count; i++)
{
- if (_rawKeyPipe[i].Invoke(m))
+ if (_rawKeyPipe[i].Invoke(m) == EventAction.StopPropagation)
{
break;
}
@@ -230,7 +245,7 @@ private void RawKeyMessage(ref Message m)
}
for (int i = 0; i < _keyDownPipe.Count; i++)
{
- if (_keyDownPipe[i].Invoke(vKey, _keyModifier))
+ if (_keyDownPipe[i].Invoke(vKey, _keyModifier) == EventAction.StopPropagation)
{
break;
}
@@ -252,7 +267,7 @@ private void RawKeyMessage(ref Message m)
}
for (int i = 0; i < _keyUpPipe.Count; i++)
{
- if (_keyUpPipe[i].Invoke(vKey, _keyModifier))
+ if (_keyUpPipe[i].Invoke(vKey, _keyModifier) == EventAction.StopPropagation)
{
break;
}
@@ -262,7 +277,7 @@ private void RawKeyMessage(ref Message m)
case WM.CHAR:
for (int i = 0; i < _keyPressPipe.Count; i++)
{
- if (_keyPressPipe[i].Invoke((char)vKey))
+ if (_keyPressPipe[i].Invoke((char)vKey) == EventAction.StopPropagation)
{
break;
}
@@ -279,7 +294,8 @@ private void RawMouseDown(ref Message m, MouseButtons buttons)
int high = HighWord(m.lParam);
for (int i = 0; i < _mouseDownPipe.Count; i++)
{
- if (_mouseDownPipe[i].Invoke(new MouseEventArgs(low, high, buttons, 1, 0)))
+ if (_mouseDownPipe[i].Invoke(new MouseEventArgs(low, high, buttons, 1, 0)) ==
+ EventAction.StopPropagation)
{
break;
}
@@ -296,7 +312,8 @@ private void RawMouseUp(ref Message m, MouseButtons buttons)
int clicks = (_state & 0x4000000) == 0x4000000 ? 2 : 1;
for (int i = 0; i < _mouseClickPipe.Count; i++)
{
- if (_mouseClickPipe[i].Invoke(new MouseEventArgs(low, high, buttons, clicks, 0)))
+ if (_mouseClickPipe[i].Invoke(new MouseEventArgs(low, high, buttons, clicks, 0)) ==
+ EventAction.StopPropagation)
{
break;
}
@@ -305,7 +322,10 @@ private void RawMouseUp(ref Message m, MouseButtons buttons)
_state &= ~0xC000000;
for (int i = 0; i < _mouseUpPipe.Count; i++)
{
- if (_mouseUpPipe[i].Invoke(new MouseEventArgs(low, high, buttons, 1, 0))) { break; }
+ if (_mouseUpPipe[i].Invoke(new MouseEventArgs(low, high, buttons, 1, 0)) == EventAction.StopPropagation)
+ {
+ break;
+ }
}
}
@@ -340,7 +360,8 @@ private void RawMouseInput(in RAWINPUTMOUSE e)
}
for (int i = 0; i < _mouseRawInputPipe.Count; i++)
{
- if (_mouseRawInputPipe[i].Invoke(new MouseEventArgs(e.LastX, e.LastY, buttons, clicks, e.ButtonData)))
+ if (_mouseRawInputPipe[i].Invoke(new MouseEventArgs(e.LastX, e.LastY, buttons, clicks, e.ButtonData)) ==
+ EventAction.StopPropagation)
{
break;
}
diff --git a/src/Exomia.Framework/Graphics/BlendStates.cs b/src/Exomia.Framework/Graphics/BlendStates.cs
new file mode 100644
index 00000000..f0a802d1
--- /dev/null
+++ b/src/Exomia.Framework/Graphics/BlendStates.cs
@@ -0,0 +1,137 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using System;
+using SharpDX.Direct3D11;
+
+namespace Exomia.Framework.Graphics
+{
+ ///
+ /// The built-in blend states. This class cannot be inherited.
+ ///
+ public sealed class BlendStates : IDisposable
+ {
+ ///
+ /// A built-in state object with settings for additive blend, that is adding the destination data to the source data
+ /// without using alpha.
+ ///
+ public readonly BlendState Additive;
+
+ ///
+ /// A built-in state object with settings for alpha blend, that is blending the source and destination data using
+ /// alpha.
+ ///
+ public readonly BlendState AlphaBlend;
+
+ ///
+ /// A built-in state object with settings for blending with non-premultiplied alpha, that is blending source and
+ /// destination data using alpha while assuming the color data contains no alpha information.
+ ///
+ public readonly BlendState NonPremultiplied;
+
+ ///
+ /// A built-in state object with settings for opaque blend, that is overwriting the source with the destination data.
+ ///
+ public readonly BlendState Opaque;
+
+ ///
+ /// A built-in default state object (no blending).
+ ///
+ public readonly BlendState Default;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The graphics device.
+ internal BlendStates(IGraphicsDevice graphicsDevice)
+ {
+ Additive = Create(graphicsDevice.Device, nameof(Additive), BlendOption.SourceAlpha, BlendOption.One, true);
+ AlphaBlend = Create(
+ graphicsDevice.Device, nameof(AlphaBlend), BlendOption.One, BlendOption.InverseSourceAlpha, true);
+ NonPremultiplied = Create(
+ graphicsDevice.Device, nameof(NonPremultiplied), BlendOption.SourceAlpha,
+ BlendOption.InverseSourceAlpha, true);
+ Opaque = Create(graphicsDevice.Device, nameof(Opaque), BlendOption.One, BlendOption.Zero, true);
+ Default = Create(graphicsDevice.Device, nameof(Default), BlendStateDescription.Default());
+ }
+
+ private static BlendState Create(Device5 device, string name, BlendStateDescription description)
+ {
+ return new BlendState(device, description) { DebugName = name };
+ }
+
+ private static BlendState Create(Device5 device,
+ string name,
+ BlendOption sourceBlend,
+ BlendOption destinationBlend,
+ bool blendEnabled)
+ {
+ return Create(
+ device,
+ name,
+ new BlendStateDescription
+ {
+ AlphaToCoverageEnable = false,
+ IndependentBlendEnable = false,
+ RenderTarget =
+ {
+ [0] = new RenderTargetBlendDescription
+ {
+ IsBlendEnabled = blendEnabled,
+ SourceBlend = sourceBlend,
+ DestinationBlend = destinationBlend,
+ SourceAlphaBlend = sourceBlend,
+ DestinationAlphaBlend = destinationBlend,
+ BlendOperation = BlendOperation.Add,
+ AlphaBlendOperation = BlendOperation.Add,
+ RenderTargetWriteMask = ColorWriteMaskFlags.All
+ }
+ }
+ });
+ }
+
+ #region IDisposable Support
+
+ private bool _disposed;
+
+ private void Dispose(bool disposing)
+ {
+ if (!_disposed)
+ {
+ if (disposing)
+ {
+ Additive.Dispose();
+ AlphaBlend.Dispose();
+ NonPremultiplied.Dispose();
+ Opaque.Dispose();
+ Default.Dispose();
+ }
+ _disposed = true;
+ }
+ }
+
+ ///
+ ~BlendStates()
+ {
+ Dispose(false);
+ }
+
+ ///
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged/managed resources.
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Graphics/Buffers/ConstantBuffer.cs b/src/Exomia.Framework/Graphics/Buffers/ConstantBuffer.cs
new file mode 100644
index 00000000..7bf4a03a
--- /dev/null
+++ b/src/Exomia.Framework/Graphics/Buffers/ConstantBuffer.cs
@@ -0,0 +1,130 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using System;
+using System.Runtime.CompilerServices;
+using Exomia.Framework.Mathematics;
+using SharpDX.Direct3D11;
+using Buffer = SharpDX.Direct3D11.Buffer;
+
+namespace Exomia.Framework.Graphics.Buffers
+{
+ ///
+ /// A constant buffer. This class cannot be inherited.
+ ///
+ public sealed class ConstantBuffer : IDisposable
+ {
+ private readonly Buffer _buffer;
+
+ private ConstantBuffer(Buffer buffer)
+ {
+ _buffer = buffer ?? throw new ArgumentNullException(nameof(buffer));
+ }
+
+ ///
+ /// Creates a new .
+ ///
+ /// Generic type parameter.
+ /// The graphics device.
+ /// (Optional) The resource usage.
+ /// (Optional) The CPU access flags.
+ ///
+ /// A .
+ ///
+ public static unsafe ConstantBuffer Create(IGraphicsDevice graphicsDevice,
+ ResourceUsage resourceUsage = ResourceUsage.Default,
+ CpuAccessFlags cpuAccessFlags = CpuAccessFlags.None)
+ where T : unmanaged
+ {
+ return Create(graphicsDevice, sizeof(T), resourceUsage, cpuAccessFlags);
+ }
+
+ ///
+ /// Creates a new with the specified size in bytes.
+ ///
+ /// The graphics device.
+ /// The size in bytes.
+ /// (Optional) The resource usage.
+ /// (Optional) The CPU access flags.
+ ///
+ /// A .
+ ///
+ ///
+ /// The must be a multiple of 16,
+ /// if not it will be calculated to the minimum multiple of 16 fitting it in.
+ /// e.g.
+ /// - a size in bytes of 11 will be 16.
+ /// - a size in bytes of 23 will be 32.
+ /// - a size in bytes of 80 will be 80.
+ /// > see https://docs.microsoft.com/de-de/windows/win32/api/d3d11/ns-d3d11-d3d11_buffer_desc#remarks
+ ///
+ public static ConstantBuffer Create(IGraphicsDevice graphicsDevice,
+ int sizeInBytes,
+ ResourceUsage resourceUsage = ResourceUsage.Default,
+ CpuAccessFlags cpuAccessFlags = CpuAccessFlags.None)
+ {
+ return new ConstantBuffer(
+ new Buffer(
+ graphicsDevice.Device,
+ Math2.Ceiling(sizeInBytes / 16.0f) * 16,
+ resourceUsage,
+ BindFlags.ConstantBuffer,
+ cpuAccessFlags,
+ ResourceOptionFlags.None,
+ 0));
+ }
+
+ ///
+ /// Implicit cast that converts the given to a .
+ ///
+ /// Buffer for constant data.
+ ///
+ /// The result of the operation.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Buffer(ConstantBuffer buffer)
+ {
+ return buffer._buffer;
+ }
+
+ #region IDisposable Support
+
+ private bool _disposed;
+
+ private void Dispose(bool disposing)
+ {
+ if (!_disposed)
+ {
+ if (disposing)
+ {
+ _buffer.Dispose();
+ }
+ _disposed = true;
+ }
+ }
+
+ ///
+ ~ConstantBuffer()
+ {
+ Dispose(false);
+ }
+
+ ///
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged/managed resources.
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Graphics/Buffers/IndexBuffer.cs b/src/Exomia.Framework/Graphics/Buffers/IndexBuffer.cs
new file mode 100644
index 00000000..cef484e1
--- /dev/null
+++ b/src/Exomia.Framework/Graphics/Buffers/IndexBuffer.cs
@@ -0,0 +1,129 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using System;
+using System.Runtime.CompilerServices;
+using SharpDX;
+using SharpDX.Direct3D11;
+using SharpDX.DXGI;
+using Buffer = SharpDX.Direct3D11.Buffer;
+
+namespace Exomia.Framework.Graphics.Buffers
+{
+ ///
+ /// A index buffer. This class cannot be inherited.
+ ///
+ public sealed class IndexBuffer : IDisposable
+ {
+ ///
+ /// Describes the format of the index buffer.
+ ///
+ public readonly Format Format;
+
+ private readonly Buffer _buffer;
+
+ private IndexBuffer(Buffer buffer, Format format)
+ {
+ _buffer = buffer ?? throw new ArgumentNullException(nameof(buffer));
+ Format = format;
+ }
+
+ ///
+ /// Creates a new .
+ ///
+ /// Generic type parameter.
+ /// The graphics device.
+ /// The data.
+ /// (Optional) The resource usage.
+ /// (Optional) The CPU access flags.
+ ///
+ /// A .
+ ///
+ public static unsafe IndexBuffer Create(IGraphicsDevice graphicsDevice,
+ in T[] data,
+ ResourceUsage resourceUsage = ResourceUsage.Immutable,
+ CpuAccessFlags cpuAccessFlags = CpuAccessFlags.None)
+ where T : unmanaged
+
+ {
+ using (DataStream dataStream = new DataStream(sizeof(T) * data.Length, true, true))
+ {
+ dataStream.WriteRange(data, 0, data.Length);
+ dataStream.Position = 0;
+
+ Buffer buffer = new Buffer(
+ graphicsDevice.Device,
+ dataStream,
+ sizeof(T) * data.Length,
+ resourceUsage,
+ BindFlags.IndexBuffer,
+ cpuAccessFlags,
+ ResourceOptionFlags.None,
+ 0);
+
+ return new IndexBuffer(
+ buffer, Type.GetTypeCode(typeof(T)) switch
+ {
+ TypeCode.Int16 => Format.R16_SInt,
+ TypeCode.Int32 => Format.R32_SInt,
+ TypeCode.UInt16 => Format.R16_UInt,
+ TypeCode.UInt32 => Format.R32_UInt,
+ _ => Format.Unknown
+ });
+ }
+ }
+
+ ///
+ /// Implicit cast that converts the given to a .
+ ///
+ /// Buffer for index data.
+ ///
+ /// The result of the operation.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Buffer(IndexBuffer buffer)
+ {
+ return buffer._buffer;
+ }
+
+ #region IDisposable Support
+
+ private bool _disposed;
+
+ private void Dispose(bool disposing)
+ {
+ if (!_disposed)
+ {
+ if (disposing)
+ {
+ _buffer.Dispose();
+ }
+ _disposed = true;
+ }
+ }
+
+ ///
+ ~IndexBuffer()
+ {
+ Dispose(false);
+ }
+
+ ///
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged/managed resources.
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Graphics/Buffers/VertexBuffer.cs b/src/Exomia.Framework/Graphics/Buffers/VertexBuffer.cs
new file mode 100644
index 00000000..60f85a4b
--- /dev/null
+++ b/src/Exomia.Framework/Graphics/Buffers/VertexBuffer.cs
@@ -0,0 +1,209 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using System;
+using System.Runtime.CompilerServices;
+using SharpDX;
+using SharpDX.Direct3D11;
+using Buffer = SharpDX.Direct3D11.Buffer;
+
+namespace Exomia.Framework.Graphics.Buffers
+{
+ ///
+ /// A vertex buffer. This class cannot be inherited.
+ ///
+ public sealed class VertexBuffer : IDisposable
+ {
+ private readonly Buffer _buffer;
+ private readonly VertexBufferBinding _vertexBufferBinding;
+
+ private VertexBuffer(Buffer buffer, int stride)
+ {
+ _buffer = buffer ?? throw new ArgumentNullException(nameof(buffer));
+ _vertexBufferBinding = new VertexBufferBinding(_buffer, stride, 0);
+ }
+
+ ///
+ /// Map the data.
+ ///
+ /// Generic type parameter.
+ /// The context4.
+ /// The data.
+ /// (Optional) The map mode.
+ /// (Optional) The map flags.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Map(DeviceContext4 context4,
+ T[] data,
+ MapMode mapMode = MapMode.WriteDiscard,
+ MapFlags mapFlags = MapFlags.None)
+ where T : unmanaged
+ {
+ Map(context4, 0, data, 0, data.Length, mapMode, mapFlags);
+ }
+
+ ///
+ /// Map the data.
+ ///
+ /// Generic type parameter.
+ /// The context4.
+ /// The offset.
+ /// The data.
+ /// (Optional) The map mode.
+ /// (Optional) The map flags.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Map(DeviceContext4 context4,
+ int offset,
+ T[] data,
+ MapMode mapMode = MapMode.WriteDiscard,
+ MapFlags mapFlags = MapFlags.None)
+ where T : unmanaged
+ {
+ Map(context4, offset, data, 0, data.Length, mapMode, mapFlags);
+ }
+
+ ///
+ /// Map the data.
+ ///
+ /// Generic type parameter.
+ /// The context4.
+ /// The data.
+ /// The data offset.
+ /// The data length.
+ /// (Optional) The map mode.
+ /// (Optional) The map flags.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Map(DeviceContext4 context4,
+ T[] data,
+ int dataOffset,
+ int dataLength,
+ MapMode mapMode = MapMode.WriteDiscard,
+ MapFlags mapFlags = MapFlags.None)
+ where T : unmanaged
+ {
+ Map(context4, 0, data, dataOffset, dataLength, mapMode, mapFlags);
+ }
+
+ ///
+ /// Map the data.
+ ///
+ /// Generic type parameter.
+ /// The context4.
+ /// The offset.
+ /// The data.
+ /// The data offset.
+ /// The data length.
+ /// (Optional) The map mode.
+ /// (Optional) The map flags.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public unsafe void Map(DeviceContext4 context4,
+ int offset,
+ T[] data,
+ int dataOffset,
+ int dataLength,
+ MapMode mapMode = MapMode.WriteDiscard,
+ MapFlags mapFlags = MapFlags.None)
+ where T : unmanaged
+ {
+ DataBox box = context4.MapSubresource(_buffer, 0, mapMode, mapFlags);
+ T* vpctPtr = (T*)box.DataPointer;
+ for (int i = 0; i < dataLength; i++)
+ {
+ *(vpctPtr + offset + i) = data[i + dataOffset];
+ }
+ context4.UnmapSubresource(_buffer, 0);
+ }
+
+ ///
+ /// Creates a new .
+ ///
+ /// Generic type parameter.
+ /// The graphics device.
+ /// The count of the vertices to store in this vertex buffer.
+ /// (Optional) The resource usage.
+ /// (Optional) The CPU access flags.
+ ///
+ /// A .
+ ///
+ public static unsafe VertexBuffer Create(IGraphicsDevice graphicsDevice,
+ int vertices,
+ ResourceUsage resourceUsage = ResourceUsage.Dynamic,
+ CpuAccessFlags cpuAccessFlags = CpuAccessFlags.Write)
+ where T : unmanaged
+ {
+ return new VertexBuffer(
+ new Buffer(
+ graphicsDevice.Device,
+ sizeof(T) * vertices,
+ resourceUsage,
+ BindFlags.VertexBuffer,
+ cpuAccessFlags,
+ ResourceOptionFlags.None,
+ 0),
+ sizeof(T));
+ }
+
+ ///
+ /// Implicit cast that converts the given to a .
+ ///
+ /// Buffer for vertex data.
+ ///
+ /// The result of the operation.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Buffer(VertexBuffer buffer)
+ {
+ return buffer._buffer;
+ }
+
+ ///
+ /// Implicit cast that converts the given to a .
+ ///
+ /// Buffer for vertex data.
+ ///
+ /// The result of the operation.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator VertexBufferBinding(VertexBuffer buffer)
+ {
+ return buffer._vertexBufferBinding;
+ }
+
+ #region IDisposable Support
+
+ private bool _disposed;
+
+ private void Dispose(bool disposing)
+ {
+ if (!_disposed)
+ {
+ if (disposing)
+ {
+ _buffer.Dispose();
+ }
+ _disposed = true;
+ }
+ }
+
+ ///
+ ~VertexBuffer()
+ {
+ Dispose(false);
+ }
+
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Graphics/Canvas.Arc.cs b/src/Exomia.Framework/Graphics/Canvas.Arc.cs
new file mode 100644
index 00000000..e0881c96
--- /dev/null
+++ b/src/Exomia.Framework/Graphics/Canvas.Arc.cs
@@ -0,0 +1,345 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using System;
+using System.Runtime.CompilerServices;
+using Exomia.Framework.Mathematics;
+using SharpDX;
+
+namespace Exomia.Framework.Graphics
+{
+ public sealed unsafe partial class Canvas
+ {
+ private static readonly Vector2[]
+ s_arcCornerOffsets = { new Vector2(-1, -1), new Vector2(1, -1), new Vector2(1, 1), new Vector2(-1, 1) };
+
+ ///
+ /// Draws an arc.
+ ///
+ /// The center.
+ /// The radius.
+ /// The start.
+ /// The end.
+ /// The color.
+ /// The width of the line.
+ /// The rotation.
+ /// The origin.
+ /// The opacity.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void DrawArc(in Vector2 center,
+ float radius,
+ float start,
+ float end,
+ in Color color,
+ float lineWidth,
+ float rotation,
+ in Vector2 origin,
+ float opacity)
+ {
+ DrawArc(new Arc2(center, radius, start, end), in color, lineWidth, rotation, in origin, opacity);
+ }
+
+ ///
+ /// Draws an arc.
+ ///
+ /// The arc.
+ /// The color.
+ /// The width of the line.
+ /// The rotation.
+ /// The origin.
+ /// The opacity.
+ public void DrawArc(in Arc2 arc,
+ in Color color,
+ float lineWidth,
+ float rotation,
+ in Vector2 origin,
+ float opacity)
+ {
+ // ReSharper disable once CompareOfFloatsByEqualityOperator
+ if (arc.Start == arc.End) { return; }
+
+ Vector4 scaledColor;
+ scaledColor.X = color.R * opacity;
+ scaledColor.Y = color.G * opacity;
+ scaledColor.Z = color.B * opacity;
+ scaledColor.W = color.A * opacity;
+
+ float r = arc.Radius;
+ float rh = (arc.Radius - lineWidth) * 0.685f;
+ float o = ((uint)(arc.Radius * 10.0f) << 16) | (uint)((arc.Radius - lineWidth) * 10.0f);
+
+ float u = arc.Start;
+ float v = arc.End;
+
+ if (u > MathUtil.TwoPi)
+ {
+ float times = (float)Math.Floor(u / MathUtil.TwoPi);
+ u -= times * MathUtil.TwoPi;
+ v -= times * MathUtil.TwoPi;
+ }
+ else if (u < -MathUtil.TwoPi)
+ {
+ float times = (float)Math.Floor((u + MathUtil.TwoPi) / MathUtil.TwoPi);
+ u -= times * MathUtil.TwoPi;
+ v -= times * MathUtil.TwoPi;
+ }
+
+ if (v > MathUtil.TwoPi)
+ {
+ float times = (float)Math.Floor(v / MathUtil.TwoPi);
+ u -= times * MathUtil.TwoPi;
+ v -= times * MathUtil.TwoPi;
+ }
+ else if (v < -MathUtil.TwoPi)
+ {
+ float times = (float)Math.Floor((v + MathUtil.TwoPi) / MathUtil.TwoPi);
+ u -= times * MathUtil.TwoPi;
+ v -= times * MathUtil.TwoPi;
+ }
+
+ if (v < u)
+ {
+ float t = u;
+ u = v;
+ v = t;
+ }
+
+ if (u < 0 && v < 0)
+ {
+ u += MathUtil.TwoPi;
+ v += MathUtil.TwoPi;
+ }
+
+ float x;
+ float y;
+ if (rotation == 0.0f)
+ {
+ x = arc.X;
+ y = arc.Y;
+ }
+ else
+ {
+ float cos = (float)Math.Cos(rotation);
+ float sin = (float)Math.Sin(rotation);
+ float dx = arc.X - origin.X;
+ float dy = arc.Y - origin.Y;
+ x = ((cos * dx) - (sin * dy)) + origin.X;
+ y = (sin * dx) + (cos * dy) + origin.Y;
+ }
+
+ Item* ptr = Reserve(4);
+ DrawArcRect(
+ ptr + 0,
+ new Line2(x - r, y - r, x + r, y - r),
+ new Line2(x - rh, y - rh, x + rh, y - rh),
+ scaledColor, x, y, u, v, o);
+
+ DrawArcRect(
+ ptr + 1,
+ new Line2(x + r, y - r, x + r, y + r),
+ new Line2(x + rh, y - rh, x + rh, y + rh),
+ scaledColor, x, y, u, v, o);
+
+ DrawArcRect(
+ ptr + 2,
+ new Line2(x + r, y + r, x - r, y + r),
+ new Line2(x + rh, y + rh, x - rh, y + rh),
+ scaledColor, x, y, u, v, o);
+
+ DrawArcRect(
+ ptr + 3,
+ new Line2(x - r, arc.Y + r, x - r, y - r),
+ new Line2(x - rh, arc.Y + rh, x - rh, y - rh),
+ scaledColor, x, y, u, v, o);
+ }
+
+ ///
+ /// Draws a filled arc.
+ ///
+ /// The center.
+ /// The radius.
+ /// The start.
+ /// The end.
+ /// The color.
+ /// The rotation.
+ /// The origin.
+ /// The opacity.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void DrawFillArc(in Vector2 center,
+ float radius,
+ float start,
+ float end,
+ in Color color,
+ float rotation,
+ in Vector2 origin,
+ float opacity)
+ {
+ DrawFillArc(new Arc2(center, radius, start, end), in color, rotation, in origin, opacity);
+ }
+
+ ///
+ /// Draws a filled arc.
+ ///
+ /// The arc.
+ /// The color.
+ /// The rotation.
+ /// The origin.
+ /// The opacity.
+ public void DrawFillArc(in Arc2 arc,
+ in Color color,
+ float rotation,
+ in Vector2 origin,
+ float opacity)
+ {
+ // ReSharper disable once CompareOfFloatsByEqualityOperator
+ if (arc.Start == arc.End) { return; }
+
+ Vector4 scaledColor;
+ scaledColor.X = color.R * opacity;
+ scaledColor.Y = color.G * opacity;
+ scaledColor.Z = color.B * opacity;
+ scaledColor.W = color.A * opacity;
+
+ float u = arc.Start;
+ float v = arc.End;
+
+ if (u > MathUtil.TwoPi)
+ {
+ float times = (float)Math.Floor(u / MathUtil.TwoPi);
+ u -= times * MathUtil.TwoPi;
+ v -= times * MathUtil.TwoPi;
+ }
+ else if (u < -MathUtil.TwoPi)
+ {
+ float times = (float)Math.Floor((u + MathUtil.TwoPi) / MathUtil.TwoPi);
+ u -= times * MathUtil.TwoPi;
+ v -= times * MathUtil.TwoPi;
+ }
+
+ if (v > MathUtil.TwoPi)
+ {
+ float times = (float)Math.Floor(v / MathUtil.TwoPi);
+ u -= times * MathUtil.TwoPi;
+ v -= times * MathUtil.TwoPi;
+ }
+ else if (v < -MathUtil.TwoPi)
+ {
+ float times = (float)Math.Floor((v + MathUtil.TwoPi) / MathUtil.TwoPi);
+ u -= times * MathUtil.TwoPi;
+ v -= times * MathUtil.TwoPi;
+ }
+
+ if (v < u)
+ {
+ float t = u;
+ u = v;
+ v = t;
+ }
+
+ if (u < 0 && v < 0)
+ {
+ u += MathUtil.TwoPi;
+ v += MathUtil.TwoPi;
+ }
+
+ float x;
+ float y;
+ if (rotation == 0.0f)
+ {
+ x = arc.X;
+ y = arc.Y;
+ }
+ else
+ {
+ float cos = (float)Math.Cos(rotation);
+ float sin = (float)Math.Sin(rotation);
+ float dx = arc.X - origin.X;
+ float dy = arc.Y - origin.Y;
+ x = ((cos * dx) - (sin * dy)) + origin.X;
+ y = (sin * dx) + (cos * dy) + origin.Y;
+ }
+
+ // ReSharper disable CompareOfFloatsByEqualityOperator
+ float m = u == 0.0f && v == MathUtil.TwoPi ? FILL_CIRCLE_MODE : FILL_CIRCLE_ARC_MODE;
+
+ // ReSharper enable CompareOfFloatsByEqualityOperator
+
+ Item* ptr = Reserve(1);
+ for (int i = 0; i < 4; i++)
+ {
+ VertexPositionColorTextureMode* vertex = (VertexPositionColorTextureMode*)ptr + i;
+
+ Vector2 corner = s_arcCornerOffsets[i];
+
+ vertex->X = x + (corner.X * arc.Radius);
+ vertex->Y = y + (corner.Y * arc.Radius);
+ vertex->Z = x;
+ vertex->W = y;
+ vertex->RGBA = scaledColor;
+ vertex->U = u;
+ vertex->V = v;
+ vertex->M = m;
+ vertex->O = arc.Radius;
+ }
+ }
+
+ private static void DrawArcRect(Item* ptr,
+ in Line2 lineA,
+ in Line2 lineB,
+ in Vector4 c,
+ float z,
+ float w,
+ float u,
+ float v,
+ float o)
+ {
+ // ReSharper disable CompareOfFloatsByEqualityOperator
+ float m = u == 0.0f && v == MathUtil.TwoPi ? BORDER_CIRCLE_MODE : BORDER_CIRCLE_ARC_MODE;
+
+ // ReSharper enable CompareOfFloatsByEqualityOperator
+
+ for (int i = 0; i < 2; i++)
+ {
+ VertexPositionColorTextureMode* vertex = (VertexPositionColorTextureMode*)ptr + i;
+ fixed (Line2* t = &lineA)
+ {
+ Vector2* lf = (Vector2*)t;
+ vertex->XY = *(lf + i);
+ }
+
+ vertex->Z = z;
+ vertex->W = w;
+ vertex->RGBA = c;
+ vertex->U = u;
+ vertex->V = v;
+ vertex->M = m;
+ vertex->O = o;
+ }
+
+ for (int i = 1; i >= 0; i--)
+ {
+ VertexPositionColorTextureMode* vertex = (VertexPositionColorTextureMode*)ptr + 2 + (1 - i);
+ fixed (Line2* t = &lineB)
+ {
+ Vector2* lf = (Vector2*)t;
+ vertex->XY = *(lf + i);
+ }
+
+ vertex->Z = z;
+ vertex->W = w;
+ vertex->RGBA = c;
+ vertex->U = u;
+ vertex->V = v;
+ vertex->M = m;
+ vertex->O = o;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Graphics/Canvas.Line.cs b/src/Exomia.Framework/Graphics/Canvas.Line.cs
new file mode 100644
index 00000000..5cd0e4bf
--- /dev/null
+++ b/src/Exomia.Framework/Graphics/Canvas.Line.cs
@@ -0,0 +1,105 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using System;
+using System.Runtime.CompilerServices;
+using Exomia.Framework.Mathematics;
+using SharpDX;
+
+namespace Exomia.Framework.Graphics
+{
+ public sealed unsafe partial class Canvas
+ {
+ ///
+ /// Draw a line from to .
+ ///
+ /// The first point.
+ /// The second point.
+ /// The color.
+ /// The width of the line.
+ /// The opacity.
+ /// The rotation.
+ /// The origin.
+ /// (Optional) The length factor.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void DrawLine(in Vector2 point1,
+ in Vector2 point2,
+ in Color color,
+ float lineWidth,
+ float opacity,
+ float rotation,
+ in Vector2 origin,
+ float lengthFactor = 1.0f)
+ {
+ DrawLine(new Line2(in point1, in point2), color, lineWidth, opacity, rotation, origin, lengthFactor);
+ }
+
+ ///
+ /// Draw a line.
+ ///
+ /// The line.
+ /// The color.
+ /// The width of the line.
+ /// The opacity.
+ /// The rotation.
+ /// The origin.
+ /// (Optional) The length factor.
+ public void DrawLine(in Line2 line,
+ in Color color,
+ float lineWidth,
+ float opacity,
+ float rotation,
+ in Vector2 origin,
+ float lengthFactor = 1.0f)
+ {
+ Line2 l = rotation == 0.0f ? line : Line2.RotateAround(in line, rotation, origin);
+
+ Vector4 scaledColor;
+ scaledColor.X = color.R * opacity;
+ scaledColor.Y = color.G * opacity;
+ scaledColor.Z = color.B * opacity;
+ scaledColor.W = color.A * opacity;
+
+ float dx = l.X2 - l.X1;
+ float dy = l.Y2 - l.Y1;
+
+ double dl = Math.Sqrt((dx * dx) + (dy * dy));
+ float nx = (float)((dy / dl) * lineWidth);
+ float ny = (float)((dx / dl) * lineWidth);
+
+ VertexPositionColorTextureMode* vertex = (VertexPositionColorTextureMode*)Reserve(1);
+
+ // p1
+ vertex->XY = l.XY1;
+ vertex->RGBA = scaledColor;
+ vertex->M = COLOR_MODE;
+ vertex++;
+
+ // p2
+ vertex->XY = l.XY2;
+ vertex->RGBA = scaledColor;
+ vertex->M = COLOR_MODE;
+ vertex++;
+
+ // p2'
+ vertex->X = l.X2 - nx;
+ vertex->Y = l.Y2 + ny;
+ vertex->RGBA = scaledColor;
+ vertex->M = COLOR_MODE;
+ vertex++;
+
+ // p1'
+ vertex->X = l.X1 - nx;
+ vertex->Y = l.Y1 + ny;
+ vertex->RGBA = scaledColor;
+ vertex->M = COLOR_MODE;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Graphics/Canvas.Polygon.cs b/src/Exomia.Framework/Graphics/Canvas.Polygon.cs
new file mode 100644
index 00000000..21857be5
--- /dev/null
+++ b/src/Exomia.Framework/Graphics/Canvas.Polygon.cs
@@ -0,0 +1,211 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using System;
+using Exomia.Framework.Mathematics;
+using SharpDX;
+
+namespace Exomia.Framework.Graphics
+{
+ public sealed unsafe partial class Canvas
+ {
+ ///
+ /// Draws a polygon.
+ ///
+ /// The vertices.
+ /// The color.
+ /// The width of the line.
+ /// The rotation.
+ /// The origin.
+ /// The opacity.
+ /// Thrown when one or more arguments are outside the required range.
+ public void DrawPolygon(Vector2[] vertices,
+ in Color color,
+ float lineWidth,
+ float rotation,
+ in Vector2 origin,
+ float opacity)
+ {
+ if (vertices.Length < 2) { throw new ArgumentOutOfRangeException(nameof(vertices.Length)); }
+
+ Vector4 scaledColor;
+ scaledColor.X = color.R * opacity;
+ scaledColor.Y = color.G * opacity;
+ scaledColor.Z = color.B * opacity;
+ scaledColor.W = color.A * opacity;
+
+ Item* ptr = Reserve(vertices.Length);
+
+ if (rotation != 0.0f)
+ {
+ Vector2[] vs = new Vector2[vertices.Length];
+ double cos = Math.Cos(rotation);
+ double sin = Math.Sin(rotation);
+ for (int i = 0; i < vertices.Length; i++)
+ {
+ ref Vector2 v = ref vertices[i];
+ float x = v.X - origin.X;
+ float y = v.Y - origin.Y;
+ vs[i] = new Vector2(
+ (float)(((cos * x) - (sin * y)) + origin.X), (float)((sin * x) + (cos * y) + origin.Y));
+ }
+ vertices = vs;
+ }
+
+ Line2 previous = Line2.CreateWithPerpendicular(
+ ref vertices[vertices.Length - 1], ref vertices[0], lineWidth, out Line2 perpendicularPrevious);
+
+ Line2 current = Line2.CreateWithPerpendicular(
+ ref vertices[0], ref vertices[1], lineWidth, out Line2 perpendicularCurrent);
+
+ if (!perpendicularPrevious.IntersectWith(perpendicularCurrent, out Vector2 ipE))
+ {
+ ipE = new Vector2(perpendicularCurrent.X1, perpendicularCurrent.Y1);
+ }
+
+ Vector2 ip1 = ipE;
+ for (int i = 1; i < vertices.Length - 1; i++)
+ {
+ Line2 next = Line2.CreateWithPerpendicular(
+ ref vertices[i], ref vertices[i + 1], lineWidth, out Line2 perpendicularNext);
+
+ if (!perpendicularCurrent.IntersectWith(perpendicularNext, out Vector2 ip2))
+ {
+ ip2 = new Vector2(perpendicularNext.X1, perpendicularNext.Y1);
+ }
+
+ DrawRect(ptr + i, current, new Line2(in ip1, in ip2), in scaledColor);
+
+ current = next;
+ perpendicularCurrent = perpendicularNext;
+ ip1 = ip2;
+ }
+
+ if (!perpendicularCurrent.IntersectWith(perpendicularPrevious, out Vector2 ip3))
+ {
+ ip3 = new Vector2(perpendicularPrevious.X1, perpendicularPrevious.Y1);
+ }
+
+ DrawRect(ptr, current, new Line2(in ip1, in ip3), in scaledColor);
+ DrawRect(ptr + (vertices.Length - 1), previous, new Line2(in ip3, in ipE), in scaledColor);
+ }
+
+ ///
+ /// Draws a filled polygon.
+ ///
+ /// The vertices.
+ /// The color.
+ /// The rotation.
+ /// The origin.
+ /// The opacity.
+ /// Thrown when one or more arguments are outside the required range.
+ ///
+ /// Attention:
+ /// - The must be declared in a clockwise orientation.
+ /// - The triangulation used to fill the polygon may not work for concave polygons at the moment!
+ /// - Complex polygons may not work at all!
+ ///
+ public void DrawFillPolygon(Vector2[] vertices,
+ in Color color,
+ float rotation,
+ in Vector2 origin,
+ float opacity)
+ {
+ if (vertices.Length < 3) { throw new ArgumentOutOfRangeException(nameof(vertices.Length)); }
+
+ Vector4 scaledColor;
+ scaledColor.X = color.R * opacity;
+ scaledColor.Y = color.G * opacity;
+ scaledColor.Z = color.B * opacity;
+ scaledColor.W = color.A * opacity;
+
+ VertexPositionColorTextureMode* vertex = (VertexPositionColorTextureMode*)Reserve(vertices.Length - 2);
+
+ if (rotation == 0.0f)
+ {
+ for (int i = 1; i < vertices.Length - 1; i += 2)
+ {
+ vertex->XY = vertices[0];
+ vertex->RGBA = scaledColor;
+ vertex->M = COLOR_MODE;
+ vertex++;
+
+ vertex->XY = vertices[i];
+ vertex->RGBA = scaledColor;
+ vertex->M = COLOR_MODE;
+ vertex++;
+
+ vertex->XY = vertices[i + 1];
+ vertex->RGBA = scaledColor;
+ vertex->M = COLOR_MODE;
+ vertex++;
+
+ if (i + 2 < vertices.Length)
+ {
+ vertex->XY = vertices[i + 2];
+ vertex->RGBA = scaledColor;
+ vertex->M = COLOR_MODE;
+ vertex++;
+ }
+ else
+ {
+ // INFO: currently we need 4 vertices (rectangle) and can't draw triangles directly so just use the first vertex as the last vertex too.
+ *vertex = *(vertex - 3);
+ }
+ }
+ }
+ else
+ {
+ Vector2* vs = stackalloc Vector2[vertices.Length];
+ double cos = Math.Cos(rotation);
+ double sin = Math.Sin(rotation);
+ for (int i = 0; i < vertices.Length; i++)
+ {
+ ref Vector2 v = ref vertices[i];
+ float x = v.X - origin.X;
+ float y = v.Y - origin.Y;
+ *(vs + i) = new Vector2(
+ (float)(((cos * x) - (sin * y)) + origin.X), (float)((sin * x) + (cos * y) + origin.Y));
+ }
+
+ for (int i = 1; i < vertices.Length - 1; i += 2)
+ {
+ vertex->XY = *vs;
+ vertex->RGBA = scaledColor;
+ vertex->M = COLOR_MODE;
+ vertex++;
+
+ vertex->XY = *(vs + i);
+ vertex->RGBA = scaledColor;
+ vertex->M = COLOR_MODE;
+ vertex++;
+
+ vertex->XY = *(vs + i + 1);
+ vertex->RGBA = scaledColor;
+ vertex->M = COLOR_MODE;
+ vertex++;
+
+ if (i + 2 < vertices.Length)
+ {
+ vertex->XY = *(vs + i + 2);
+ vertex->RGBA = scaledColor;
+ vertex->M = COLOR_MODE;
+ vertex++;
+ }
+ else
+ {
+ // INFO: currently we need 4 vertices (rectangle) and can't draw triangles directly so just use the first vertex as the last vertex too.
+ *vertex = *(vertex - 3);
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Graphics/Canvas.Rectangle.cs b/src/Exomia.Framework/Graphics/Canvas.Rectangle.cs
new file mode 100644
index 00000000..afca8d24
--- /dev/null
+++ b/src/Exomia.Framework/Graphics/Canvas.Rectangle.cs
@@ -0,0 +1,213 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using System;
+using Exomia.Framework.Mathematics;
+using SharpDX;
+
+namespace Exomia.Framework.Graphics
+{
+ public sealed unsafe partial class Canvas
+ {
+ private static readonly Vector2[]
+ s_rectangleCornerOffsets = { Vector2.Zero, Vector2.UnitX, Vector2.One, Vector2.UnitY };
+
+ ///
+ /// Draw rectangle.
+ ///
+ /// The destination rectangle.
+ /// The color.
+ /// The width of the line.
+ /// The rotation.
+ /// The origin.
+ /// The opacity.
+ public void DrawRectangle(in RectangleF destination,
+ in Color color,
+ float lineWidth,
+ float rotation,
+ in Vector2 origin,
+ float opacity)
+ {
+ Vector4 scaledColor;
+ scaledColor.X = color.R * opacity;
+ scaledColor.Y = color.G * opacity;
+ scaledColor.Z = color.B * opacity;
+ scaledColor.W = color.A * opacity;
+
+ Vector2 tl = new Vector2(destination.Left + lineWidth, destination.Top + lineWidth);
+ Vector2 tr = new Vector2(destination.Right - lineWidth, destination.Top + lineWidth);
+ Vector2 br = new Vector2(destination.Right - lineWidth, destination.Bottom - lineWidth);
+ Vector2 bl = new Vector2(destination.Left + lineWidth, destination.Bottom - lineWidth);
+
+ Item* ptr = Reserve(4);
+
+ if (rotation == 0f)
+ {
+ DrawRect(
+ ptr + 0,
+ new Line2(destination.TopLeft, destination.TopRight),
+ new Line2(in tl, in tr),
+ in scaledColor);
+
+ DrawRect(
+ ptr + 1,
+ new Line2(destination.TopRight, destination.BottomRight),
+ new Line2(in tr, in br),
+ in scaledColor);
+
+ DrawRect(
+ ptr + 2,
+ new Line2(destination.BottomRight, destination.BottomLeft),
+ new Line2(in br, in bl),
+ in scaledColor);
+
+ DrawRect(
+ ptr + 3,
+ new Line2(destination.BottomLeft, destination.TopLeft),
+ new Line2(in bl, in tl),
+ in scaledColor);
+ }
+ else
+ {
+ double cos = Math.Cos(rotation);
+ double sin = Math.Sin(rotation);
+
+ float tlx1 = destination.Left - origin.X;
+ float tly1 = destination.Top - origin.Y;
+
+ float tlx2 = tl.X - origin.X;
+ float tly2 = tl.Y - origin.Y;
+
+ float trx1 = destination.Right - origin.X;
+ float try1 = destination.Top - origin.Y;
+
+ float trx2 = tr.X - origin.X;
+ float try2 = tr.Y - origin.Y;
+
+ float brx1 = destination.Right - origin.X;
+ float bry1 = destination.Bottom - origin.Y;
+
+ float brx2 = br.X - origin.X;
+ float bry2 = br.Y - origin.Y;
+
+ float blx1 = destination.Left - origin.X;
+ float bly1 = destination.Bottom - origin.Y;
+
+ float blx2 = bl.X - origin.X;
+ float bly2 = bl.Y - origin.Y;
+
+ Vector2 tl1 = new Vector2(
+ (float)((tlx1 * cos) - (tly1 * sin)) + origin.X, (float)((tlx1 * sin) + (tly1 * cos)) + origin.Y);
+ Vector2 tl2 = new Vector2(
+ (float)((tlx2 * cos) - (tly2 * sin)) + origin.X, (float)((tlx2 * sin) + (tly2 * cos)) + origin.Y);
+
+ Vector2 tr1 = new Vector2(
+ (float)((trx1 * cos) - (try1 * sin)) + origin.X, (float)((trx1 * sin) + (try1 * cos)) + origin.Y);
+ Vector2 tr2 = new Vector2(
+ (float)((trx2 * cos) - (try2 * sin)) + origin.X, (float)((trx2 * sin) + (try2 * cos)) + origin.Y);
+
+ Vector2 br1 = new Vector2(
+ (float)((brx1 * cos) - (bry1 * sin)) + origin.X, (float)((brx1 * sin) + (bry1 * cos)) + origin.Y);
+ Vector2 br2 = new Vector2(
+ (float)((brx2 * cos) - (bry2 * sin)) + origin.X, (float)((brx2 * sin) + (bry2 * cos)) + origin.Y);
+
+ Vector2 bl1 = new Vector2(
+ (float)((blx1 * cos) - (bly1 * sin)) + origin.X, (float)((blx1 * sin) + (bly1 * cos)) + origin.Y);
+ Vector2 bl2 = new Vector2(
+ (float)((blx2 * cos) - (bly2 * sin)) + origin.X, (float)((blx2 * sin) + (bly2 * cos)) + origin.Y);
+
+ DrawRect(ptr + 0, new Line2(in tl1, in tr1), new Line2(in tl2, in tr2), in scaledColor);
+ DrawRect(ptr + 1, new Line2(in tr1, in br1), new Line2(in tr2, in br2), in scaledColor);
+ DrawRect(ptr + 2, new Line2(in br1, in bl1), new Line2(in br2, in bl2), in scaledColor);
+ DrawRect(ptr + 3, new Line2(in bl1, in tl1), new Line2(in bl2, in tl2), in scaledColor);
+ }
+ }
+
+ ///
+ /// Draw fill rectangle.
+ ///
+ /// The destination rectangle.
+ /// The color.
+ /// The rotation.
+ /// The origin.
+ /// The opacity.
+ public void DrawFillRectangle(in RectangleF destination,
+ in Color color,
+ float rotation,
+ in Vector2 origin,
+ float opacity)
+ {
+ Vector4 scaledColor;
+ scaledColor.X = color.R * opacity;
+ scaledColor.Y = color.G * opacity;
+ scaledColor.Z = color.B * opacity;
+ scaledColor.W = color.A * opacity;
+
+ Item* ptr = Reserve(1);
+
+ if (rotation == 0f)
+ {
+ for (int j = 0; j < 4; j++)
+ {
+ VertexPositionColorTextureMode* vertex = (VertexPositionColorTextureMode*)ptr + j;
+
+ Vector2 corner = s_rectangleCornerOffsets[j];
+
+ vertex->X = destination.X + (corner.X * destination.Width);
+ vertex->Y = destination.Y + (corner.Y * destination.Height);
+ vertex->RGBA = scaledColor;
+ vertex->M = COLOR_MODE;
+ }
+ }
+ else
+ {
+ double cos = Math.Cos(rotation);
+ double sin = Math.Sin(rotation);
+
+ for (int j = 0; j < 4; j++)
+ {
+ VertexPositionColorTextureMode* vertex = (VertexPositionColorTextureMode*)ptr + j;
+
+ Vector2 corner = s_rectangleCornerOffsets[j];
+ float posX = (destination.X - origin.X) + (corner.X * destination.Width);
+ float posY = (destination.Y - origin.Y) + (corner.Y * destination.Height);
+
+ vertex->X = (float)((origin.X + (posX * cos)) - (posY * sin));
+ vertex->Y = (float)(origin.Y + (posX * sin) + (posY * cos));
+ vertex->RGBA = scaledColor;
+ vertex->M = COLOR_MODE;
+ }
+ }
+ }
+
+ private static void DrawRect(Item* ptr, in Line2 lineA, in Line2 lineB, in Vector4 c)
+ {
+ // p1
+ ptr->V1.XY = lineA.XY1;
+ ptr->V1.RGBA = c;
+ ptr->V1.M = COLOR_MODE;
+
+ // p2
+ ptr->V2.XY = lineA.XY2;
+ ptr->V2.RGBA = c;
+ ptr->V2.M = COLOR_MODE;
+
+ // p2'
+ ptr->V3.XY = lineB.XY2;
+ ptr->V3.RGBA = c;
+ ptr->V3.M = COLOR_MODE;
+
+ // p1'
+ ptr->V4.XY = lineB.XY1;
+ ptr->V4.RGBA = c;
+ ptr->V4.M = COLOR_MODE;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Graphics/Canvas.SpriteFont.cs b/src/Exomia.Framework/Graphics/Canvas.SpriteFont.cs
new file mode 100644
index 00000000..abd398cf
--- /dev/null
+++ b/src/Exomia.Framework/Graphics/Canvas.SpriteFont.cs
@@ -0,0 +1,205 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using System.Runtime.CompilerServices;
+using SharpDX;
+
+#if NETSTANDARD2_1
+using System;
+
+#endif
+
+namespace Exomia.Framework.Graphics
+{
+ public sealed partial class Canvas
+ {
+ ///
+ /// Draw text.
+ ///
+ /// The font.
+ /// The text.
+ /// The position.
+ /// The color.
+#if NETSTANDARD2_1
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void DrawText(SpriteFont font, ReadOnlySpan text, in Vector2 position, in Color color)
+#else
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void DrawText(SpriteFont font, string text, in Vector2 position, in Color color)
+#endif
+ {
+ font.Draw(DrawTextInternal, text, position, color, 0f, Vector2.Zero, 1.0f, TextureEffects.None, 0f);
+ }
+
+ ///
+ /// Draw text.
+ ///
+ /// The font.
+ /// The text.
+ /// The position.
+ /// The color.
+ /// The rotation.
+#if NETSTANDARD2_1
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void DrawText(SpriteFont font,
+ ReadOnlySpan text,
+ in Vector2 position,
+ in Color color,
+ float rotation)
+#else
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void DrawText(SpriteFont font, string text, in Vector2 position, in Color color, float rotation)
+#endif
+ {
+ font.Draw(DrawTextInternal, text, position, color, rotation, Vector2.Zero, 1.0f, TextureEffects.None, 0f);
+ }
+
+ ///
+ /// Draw text.
+ ///
+ /// The font.
+ /// The text.
+ /// The position.
+ /// The color.
+ /// The rotation.
+ /// The origin.
+ /// The opacity.
+ /// The effects.
+#if NETSTANDARD2_1
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void DrawText(SpriteFont font,
+ ReadOnlySpan text,
+ in Vector2 position,
+ in Color color,
+ float rotation,
+ in Vector2 origin,
+ float opacity,
+ TextureEffects effects)
+#else
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void DrawText(SpriteFont font,
+ string text,
+ in Vector2 position,
+ in Color color,
+ float rotation,
+ in Vector2 origin,
+ float opacity,
+ TextureEffects effects)
+#endif
+ {
+ font.Draw(DrawTextInternal, text, position, color, rotation, origin, opacity, effects, 0f);
+ }
+
+ ///
+ /// Draw text.
+ ///
+ /// The font.
+ /// The text.
+ /// The start.
+ /// The end.
+ /// The position.
+ /// The color.
+ /// The rotation.
+ /// The origin.
+ /// The opacity.
+ /// The effects.
+#if NETSTANDARD2_1
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void DrawText(SpriteFont font,
+ ReadOnlySpan text,
+ int start,
+ int end,
+ in Vector2 position,
+ in Color color,
+ float rotation,
+ in Vector2 origin,
+ float opacity,
+ TextureEffects effects)
+#else
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void DrawText(SpriteFont font,
+ string text,
+ int start,
+ int end,
+ in Vector2 position,
+ in Color color,
+ float rotation,
+ in Vector2 origin,
+ float opacity,
+ TextureEffects effects)
+#endif
+ {
+ font.Draw(DrawTextInternal, text, start, end, position, color, rotation, origin, opacity, effects, 0f);
+ }
+
+ ///
+ /// Draw text.
+ ///
+ /// The font.
+ /// The text.
+ /// The start.
+ /// The end.
+ /// The position.
+ /// The dimension.
+ /// The color.
+ /// The rotation.
+ /// The origin.
+ /// The opacity.
+ /// The effects.
+#if NETSTANDARD2_1
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void DrawText(SpriteFont font,
+ ReadOnlySpan text,
+ int start,
+ int end,
+ in Vector2 position,
+ in Size2F dimension,
+ in Color color,
+ float rotation,
+ in Vector2 origin,
+ float opacity,
+ TextureEffects effects)
+#else
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void DrawText(SpriteFont font,
+ string text,
+ int start,
+ int end,
+ in Vector2 position,
+ in Size2F dimension,
+ in Color color,
+ float rotation,
+ in Vector2 origin,
+ float opacity,
+ TextureEffects effects)
+#endif
+ {
+ font.Draw(
+ DrawTextInternal, text, start, end, position, dimension, color, rotation, origin, opacity, effects, 0f);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal void DrawTextInternal(Texture texture,
+ in Vector2 position,
+ in Rectangle? sourceRectangle,
+ in Color color,
+ float rotation,
+ in Vector2 origin,
+ float scale,
+ float opacity,
+ TextureEffects effects,
+ float layerDepth)
+ {
+ DrawTexture(
+ texture, new RectangleF(position.X, position.Y, scale, scale), true, sourceRectangle, color,
+ rotation, origin, opacity, effects, FONT_TEXTURE_MODE);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Graphics/Canvas.Structs.cs b/src/Exomia.Framework/Graphics/Canvas.Structs.cs
new file mode 100644
index 00000000..1e795fd1
--- /dev/null
+++ b/src/Exomia.Framework/Graphics/Canvas.Structs.cs
@@ -0,0 +1,83 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using System.Runtime.InteropServices;
+using SharpDX;
+
+namespace Exomia.Framework.Graphics
+{
+ public sealed partial class Canvas
+ {
+ [StructLayout(LayoutKind.Explicit, Size = VERTEX_STRIDE * 4)]
+ private struct Item
+ {
+ [FieldOffset(VERTEX_STRIDE * 0)]
+ public VertexPositionColorTextureMode V1;
+
+ [FieldOffset(VERTEX_STRIDE * 1)]
+ public VertexPositionColorTextureMode V2;
+
+ [FieldOffset(VERTEX_STRIDE * 2)]
+ public VertexPositionColorTextureMode V3;
+
+ [FieldOffset(VERTEX_STRIDE * 3)]
+ public VertexPositionColorTextureMode V4;
+ }
+
+ [StructLayout(LayoutKind.Explicit, Size = VERTEX_STRIDE)]
+ private struct VertexPositionColorTextureMode
+ {
+ [FieldOffset(0)]
+ public float X;
+
+ [FieldOffset(4)]
+ public float Y;
+
+ [FieldOffset(0)]
+ public Vector2 XY;
+
+ [FieldOffset(8)]
+ public float Z;
+
+ [FieldOffset(12)]
+ public float W;
+
+ [FieldOffset(8)]
+ public long ZW;
+
+ [FieldOffset(16)]
+ public readonly float R;
+
+ [FieldOffset(20)]
+ public readonly float G;
+
+ [FieldOffset(24)]
+ public readonly float B;
+
+ [FieldOffset(28)]
+ public readonly float A;
+
+ [FieldOffset(16)]
+ public Vector4 RGBA;
+
+ [FieldOffset(32)]
+ public float U;
+
+ [FieldOffset(36)]
+ public float V;
+
+ [FieldOffset(40)]
+ public float M;
+
+ [FieldOffset(44)]
+ public float O;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Graphics/Canvas.Texture.cs b/src/Exomia.Framework/Graphics/Canvas.Texture.cs
new file mode 100644
index 00000000..6368ae73
--- /dev/null
+++ b/src/Exomia.Framework/Graphics/Canvas.Texture.cs
@@ -0,0 +1,270 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using System;
+using System.Runtime.CompilerServices;
+using SharpDX;
+
+namespace Exomia.Framework.Graphics
+{
+ public sealed unsafe partial class Canvas
+ {
+ ///
+ /// Draws a texture.
+ ///
+ /// The texture.
+ /// The position.
+ /// The color.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Draw(Texture texture, in Vector2 position, in Color color)
+ {
+ DrawTexture(
+ texture, new RectangleF(position.X, position.Y, 1f, 1f), true,
+ s_nullRectangle, color, 0f, s_vector2Zero, 1.0f, TextureEffects.None);
+ }
+
+ ///
+ /// Draws a texture.
+ ///
+ /// The texture.
+ /// The destination rectangle.
+ /// The color.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Draw(Texture texture, in RectangleF destinationRectangle, in Color color)
+ {
+ DrawTexture(
+ texture, destinationRectangle, false,
+ s_nullRectangle, color, 0f, s_vector2Zero, 1.0f, TextureEffects.None);
+ }
+
+ ///
+ /// Draws a texture.
+ ///
+ /// The texture.
+ /// The position.
+ /// The source rectangle.
+ /// The color.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Draw(Texture texture, in Vector2 position, in Rectangle? sourceRectangle, in Color color)
+ {
+ DrawTexture(
+ texture, new RectangleF(position.X, position.Y, 1f, 1f), true,
+ sourceRectangle, color, 0f, s_vector2Zero, 1.0f, TextureEffects.None);
+ }
+
+ ///
+ /// Draws a texture.
+ ///
+ /// The texture.
+ /// The destination rectangle.
+ /// The source rectangle.
+ /// The color.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Draw(Texture texture,
+ in RectangleF destinationRectangle,
+ in Rectangle? sourceRectangle,
+ in Color color)
+ {
+ DrawTexture(
+ texture, destinationRectangle, false,
+ sourceRectangle, color, 0f, s_vector2Zero, 1.0f, TextureEffects.None);
+ }
+
+ ///
+ /// Draws a texture.
+ ///
+ /// The texture.
+ /// The destination rectangle.
+ /// The source rectangle.
+ /// The color.
+ /// The rotation.
+ /// The origin.
+ /// The opacity.
+ /// The effects.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Draw(Texture texture,
+ in RectangleF destinationRectangle,
+ in Rectangle? sourceRectangle,
+ in Color color,
+ float rotation,
+ in Vector2 origin,
+ float opacity,
+ TextureEffects effects)
+ {
+ DrawTexture(
+ texture, destinationRectangle, false,
+ sourceRectangle, color, rotation, origin, opacity, effects);
+ }
+
+ ///
+ /// Draws a texture.
+ ///
+ /// The texture.
+ /// The position.
+ /// The source rectangle.
+ /// The color.
+ /// The rotation.
+ /// The origin.
+ /// The scale.
+ /// The opacity.
+ /// The effects.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Draw(Texture texture,
+ in Vector2 position,
+ in Rectangle? sourceRectangle,
+ in Color color,
+ float rotation,
+ in Vector2 origin,
+ float scale,
+ float opacity,
+ TextureEffects effects)
+ {
+ DrawTexture(
+ texture, new RectangleF(position.X, position.Y, scale, scale), true,
+ sourceRectangle, color, rotation, origin, opacity, effects);
+ }
+
+ ///
+ /// Draws a texture.
+ ///
+ /// The texture.
+ /// The position.
+ /// The source rectangle.
+ /// The color.
+ /// The rotation.
+ /// The origin.
+ /// The scale.
+ /// The opacity.
+ /// The effects.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Draw(Texture texture,
+ in Vector2 position,
+ in Rectangle? sourceRectangle,
+ in Color color,
+ float rotation,
+ in Vector2 origin,
+ in Vector2 scale,
+ float opacity,
+ TextureEffects effects)
+ {
+ DrawTexture(
+ texture, new RectangleF(position.X, position.Y, scale.X, scale.Y), true,
+ sourceRectangle, color, rotation, origin, opacity, effects);
+ }
+
+ private void DrawTexture(Texture texture,
+ in RectangleF destination,
+ bool scaleDestination,
+ in Rectangle? sourceRectangle,
+ in Color color,
+ float rotation,
+ in Vector2 origin,
+ float opacity,
+ TextureEffects effects,
+ float mode = TEXTURE_MODE)
+
+ {
+ long tp = texture.TexturePointer.ToInt64();
+ if (!_textures.ContainsKey(tp))
+ {
+ bool lockTaken = false;
+ try
+ {
+ _spinLock.Enter(ref lockTaken);
+ if (!_textures.ContainsKey(tp))
+ {
+ _textures.Add(tp, texture);
+ }
+ }
+ finally
+ {
+ if (lockTaken)
+ {
+ _spinLock.Exit(false);
+ }
+ }
+ }
+
+ Vector4 scaledColor;
+ scaledColor.X = color.R * opacity;
+ scaledColor.Y = color.G * opacity;
+ scaledColor.Z = color.B * opacity;
+ scaledColor.W = color.A * opacity;
+
+ Rectangle s = sourceRectangle ?? new Rectangle(0, 0, texture.Width, texture.Height);
+ RectangleF d = destination;
+ if (scaleDestination)
+ {
+ d.Width *= s.Width;
+ d.Height *= s.Height;
+ }
+
+ if (d.Width < 0)
+ {
+ d.X += d.Width;
+ d.Width = -d.Width;
+ }
+
+ if (d.Height < 0)
+ {
+ d.Y += d.Height;
+ d.Height = -d.Height;
+ }
+
+ float deltaX = 1.0f / texture.Width;
+ float deltaY = 1.0f / texture.Height;
+
+ Item* ptr = Reserve(1);
+ if (rotation == 0f)
+ {
+ for (int j = 0; j < 4; j++)
+ {
+ VertexPositionColorTextureMode* vertex = (VertexPositionColorTextureMode*)ptr + j;
+
+ Vector2 corner = s_rectangleCornerOffsets[j];
+
+ vertex->X = d.X + ((corner.X - origin.X) * d.Width);
+ vertex->Y = d.Y + ((corner.Y - origin.Y) * d.Height);
+ vertex->ZW = tp;
+ vertex->RGBA = scaledColor;
+ corner = s_rectangleCornerOffsets[j ^ (int)effects];
+ vertex->U = (s.X + (corner.X * s.Width)) * deltaX;
+ vertex->V = (s.Y + (corner.Y * s.Height)) * deltaY;
+
+ vertex->M = mode;
+ }
+ }
+ else
+ {
+ double cos = Math.Cos(rotation);
+ double sin = Math.Sin(rotation);
+
+ for (int j = 0; j < 4; j++)
+ {
+ VertexPositionColorTextureMode* vertex = (VertexPositionColorTextureMode*)ptr + j;
+
+ Vector2 corner = s_rectangleCornerOffsets[j];
+ float posX = (corner.X - origin.X) * d.Width;
+ float posY = (corner.Y - origin.Y) * d.Height;
+
+ vertex->X = (float)((d.X + (posX * cos)) - (posY * sin));
+ vertex->Y = (float)(d.Y + (posX * sin) + (posY * cos));
+ vertex->ZW = tp;
+ vertex->RGBA = scaledColor;
+ corner = s_rectangleCornerOffsets[j ^ (int)effects];
+ vertex->U = (s.X + (corner.X * s.Width)) * deltaX;
+ vertex->V = (s.Y + (corner.Y * s.Height)) * deltaY;
+
+ vertex->M = mode;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Graphics/Canvas.Triangle.cs b/src/Exomia.Framework/Graphics/Canvas.Triangle.cs
new file mode 100644
index 00000000..c5765ae0
--- /dev/null
+++ b/src/Exomia.Framework/Graphics/Canvas.Triangle.cs
@@ -0,0 +1,228 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using System;
+using System.Runtime.CompilerServices;
+using Exomia.Framework.Mathematics;
+using SharpDX;
+using SharpDX.Direct3D11;
+
+namespace Exomia.Framework.Graphics
+{
+ public sealed unsafe partial class Canvas
+ {
+ ///
+ /// Draws a triangle.
+ ///
+ /// The first point.
+ /// The second point.
+ /// The third point.
+ /// The color.
+ /// The width of the line.
+ /// The rotation.
+ /// The origin.
+ /// The opacity.
+ ///
+ /// The points 1 to 3 have to match the ,
+ /// so for default, with is set,
+ /// the points have to use one of the following winding order:
+ /// p1 p2 p3
+ /// /\ /\ /\
+ /// / \ / \ / \
+ /// /____\ /____\ /____\
+ /// p3 p2 p1 p3 p2 p1.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void DrawTriangle(in Vector2 point1,
+ in Vector2 point2,
+ in Vector2 point3,
+ in Color color,
+ float lineWidth,
+ float rotation,
+ in Vector2 origin,
+ float opacity)
+ {
+ DrawTriangle(
+ new Triangle2(in point1, in point2, in point3), color, lineWidth, rotation, in origin, opacity);
+ }
+
+ ///
+ /// Draws a triangle.
+ ///
+ /// The triangle.
+ /// The color.
+ /// The width of the line.
+ /// The rotation.
+ /// The origin.
+ /// The opacity.
+ /// Thrown when one or more arguments have unsupported or illegal values.
+ ///
+ /// The points 1 to 3 have to match the ,
+ /// so for default, with is set,
+ /// the points have to use one of the following winding order:
+ /// p1 p2 p3
+ /// /\ /\ /\
+ /// / \ / \ / \
+ /// /____\ /____\ /____\
+ /// p3 p2 p1 p3 p2 p1.
+ ///
+ public void DrawTriangle(in Triangle2 triangle,
+ in Color color,
+ float lineWidth,
+ float rotation,
+ in Vector2 origin,
+ float opacity)
+ {
+ Triangle2 t = rotation == 0.0 ? triangle : Triangle2.RotateAround(in triangle, rotation, in origin);
+
+ Vector4 scaledColor;
+ scaledColor.X = color.R * opacity;
+ scaledColor.Y = color.G * opacity;
+ scaledColor.Z = color.B * opacity;
+ scaledColor.W = color.A * opacity;
+
+ Line2 a = new Line2(in t.XY1, in t.XY2);
+ Line2 perpendicularA = a.GetPerpendicular(lineWidth);
+
+ Line2 b = new Line2(in t.XY2, in t.XY3);
+ Line2 perpendicularB = b.GetPerpendicular(lineWidth);
+
+ Line2 c = new Line2(in t.XY3, in t.XY1);
+ Line2 perpendicularC = c.GetPerpendicular(lineWidth);
+
+ if (!perpendicularA.IntersectWith(perpendicularB, out Vector2 ipAb))
+ {
+ throw new ArgumentException("The lines a and b are parallel to each other! Check the triangle points!");
+ }
+
+ if (!perpendicularB.IntersectWith(perpendicularC, out Vector2 ipBc))
+ {
+ throw new ArgumentException("The lines b and c are parallel to each other! Check the triangle points!");
+ }
+
+ if (!perpendicularC.IntersectWith(perpendicularA, out Vector2 ipCa))
+ {
+ throw new ArgumentException("The lines c and a are parallel to each other! Check the triangle points!");
+ }
+
+ Item* ptr = Reserve(3);
+ DrawRect(ptr + 0, a, new Line2(in ipCa, in ipAb), in scaledColor);
+ DrawRect(ptr + 1, b, new Line2(in ipAb, in ipBc), in scaledColor);
+ DrawRect(ptr + 2, c, new Line2(in ipBc, in ipCa), in scaledColor);
+ }
+
+ ///
+ /// Draws a filled triangle.
+ ///
+ /// The first point.
+ /// The second point.
+ /// The third point.
+ /// The color.
+ /// The rotation.
+ /// The origin.
+ /// The opacity.
+ ///
+ /// The points 1 to 3 have to match the ,
+ /// so for default, with is set,
+ /// the points have to use one of the following winding order:
+ /// p1 p2 p3
+ /// /\ /\ /\
+ /// / \ / \ / \
+ /// /____\ /____\ /____\
+ /// p3 p2 p1 p3 p2 p1.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void DrawFillTriangle(in Vector2 point1,
+ in Vector2 point2,
+ in Vector2 point3,
+ in Color color,
+ float rotation,
+ in Vector2 origin,
+ float opacity)
+ {
+ DrawFillTriangle(new Triangle2(in point1, in point2, in point3), color, rotation, origin, opacity);
+ }
+
+ ///
+ /// Draws a filled triangle.
+ ///
+ /// The triangle.
+ /// The color.
+ /// The rotation.
+ /// The origin.
+ /// The opacity.
+ ///
+ /// The points 1 to 3 from the have to match the
+ /// ,
+ /// so for default, with is set,
+ /// the points have to use one of the following winding order:
+ /// p1 p2 p3
+ /// /\ /\ /\
+ /// / \ / \ / \
+ /// /____\ /____\ /____\
+ /// p3 p2 p1 p3 p2 p1.
+ ///
+ public void DrawFillTriangle(in Triangle2 triangle,
+ in Color color,
+ float rotation,
+ in Vector2 origin,
+ float opacity)
+ {
+ Vector4 scaledColor;
+ scaledColor.X = color.R * opacity;
+ scaledColor.Y = color.G * opacity;
+ scaledColor.Z = color.B * opacity;
+ scaledColor.W = color.A * opacity;
+
+ Item* ptr = Reserve(1);
+
+ if (rotation == 0.0f)
+ {
+ for (int i = 0; i < 3; i++)
+ {
+ VertexPositionColorTextureMode* vertex = (VertexPositionColorTextureMode*)ptr + i;
+
+ fixed (Triangle2* t = &triangle)
+ {
+ Vector2* tf = (Vector2*)t;
+ vertex->XY = *(tf + i);
+ }
+
+ vertex->RGBA = scaledColor;
+ vertex->M = COLOR_MODE;
+ }
+ }
+ else
+ {
+ double cos = Math.Cos(rotation);
+ double sin = Math.Sin(rotation);
+
+ for (int i = 0; i < 3; i++)
+ {
+ VertexPositionColorTextureMode* vertex = (VertexPositionColorTextureMode*)ptr + i;
+
+ fixed (Triangle2* t = &triangle)
+ {
+ Vector2* tf = (Vector2*)t;
+ Vector2 v = *(tf + i) - origin;
+ vertex->X = (float)(((cos * v.X) - (sin * v.Y)) + origin.X);
+ vertex->Y = (float)((sin * v.X) + (cos * v.Y) + origin.Y);
+ }
+
+ vertex->RGBA = scaledColor;
+ vertex->M = COLOR_MODE;
+ }
+ }
+
+ // INFO: currently we need 4 vertices (rectangle) and can't draw triangles directly so just use the first vertex as the last vertex too.
+ *((VertexPositionColorTextureMode*)ptr + 3) = *(VertexPositionColorTextureMode*)ptr;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Graphics/Canvas.cs b/src/Exomia.Framework/Graphics/Canvas.cs
index 6d6a4912..d76ae830 100644
--- a/src/Exomia.Framework/Graphics/Canvas.cs
+++ b/src/Exomia.Framework/Graphics/Canvas.cs
@@ -9,8 +9,18 @@
#endregion
using System;
-using System.Text;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Threading;
+using Exomia.Framework.Graphics.Buffers;
+using Exomia.Framework.Graphics.Shader;
+using Exomia.Framework.Resources;
+using Exomia.Framework.Win32;
using SharpDX;
+using SharpDX.Direct3D;
using SharpDX.Direct3D11;
namespace Exomia.Framework.Graphics
@@ -18,615 +28,412 @@ namespace Exomia.Framework.Graphics
///
/// A canvas. This class cannot be inherited.
///
- public sealed class Canvas : IDisposable
+ public sealed unsafe partial class Canvas : IDisposable
{
- private static readonly Vector2 s_vector2Zero = Vector2.Zero;
- private static readonly Rectangle? s_nullRectangle = null;
- private readonly Device5 _device;
- private readonly DeviceContext4 _context;
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// Zero-based index of the device.
- public Canvas(IGraphicsDevice iDevice)
+ private const int MAX_BATCH_SIZE = 1 << 13;
+ private const int INITIAL_QUEUE_SIZE = 1 << 7;
+ private const int MAX_VERTEX_COUNT = MAX_BATCH_SIZE * 4;
+ private const int MAX_INDEX_COUNT = MAX_BATCH_SIZE * 6;
+ private const int BATCH_SEQUENTIAL_THRESHOLD = 1 << 9;
+ private const int VERTEX_STRIDE = sizeof(float) * 12;
+ private const int MAX_TEXTURE_SLOTS = 8;
+ private const int MAX_FONT_TEXTURE_SLOTS = 4;
+
+ private const float COLOR_MODE = 0.0f;
+ private const float TEXTURE_MODE = 1.0f;
+ private const float FONT_TEXTURE_MODE = 2.0f;
+ private const float FILL_CIRCLE_MODE = 3.0f;
+ private const float FILL_CIRCLE_ARC_MODE = 4.0f;
+ private const float BORDER_CIRCLE_MODE = 5.0f;
+ private const float BORDER_CIRCLE_ARC_MODE = 6.0f;
+
+ private static readonly ushort[] s_indices;
+ private static readonly Vector2 s_vector2Zero = Vector2.Zero;
+ private static readonly Rectangle? s_nullRectangle = null;
+
+ private readonly DeviceContext4 _context;
+
+ private readonly InputLayout _vertexInputLayout;
+
+ private readonly IndexBuffer _indexBuffer;
+ private readonly VertexBuffer _vertexBuffer;
+ private readonly ConstantBuffer _perFrameBuffer;
+
+ private readonly Shader.Shader _shader;
+ private readonly PixelShader _pixelShader;
+ private readonly VertexShader _vertexShader;
+
+ private readonly BlendState _defaultBlendState;
+ private readonly DepthStencilState _defaultDepthStencilState;
+ private readonly RasterizerState _defaultRasterizerState;
+ private readonly RasterizerState _defaultRasterizerScissorEnabledState;
+ private readonly SamplerState _defaultSamplerState;
+ private BlendState? _blendState;
+ private DepthStencilState? _depthStencilState;
+ private RasterizerState? _rasterizerState;
+ private SamplerState? _samplerState;
+
+ private bool _isBeginCalled, _isScissorEnabled;
+ private Rectangle _scissorRectangle;
+
+ private Matrix _projectionMatrix, _viewMatrix, _transformMatrix;
+
+ private Item* _itemQueue;
+ private int _itemQueueLength;
+ private int _itemQueueCount;
+
+ private SpinLock _spinLock = new SpinLock(Debugger.IsAttached);
+
+ private readonly Dictionary _textures = new Dictionary(INITIAL_QUEUE_SIZE);
+ private readonly Dictionary _textureSlotMap = new Dictionary(MAX_TEXTURE_SLOTS);
+ private readonly Dictionary _fontTextureSlotMap = new Dictionary(MAX_FONT_TEXTURE_SLOTS);
+
+ ///
+ /// Initializes static members of the class.
+ ///
+ ///
+ /// Thrown when one or more arguments are outside
+ /// the required range.
+ ///
+ static Canvas()
{
- _device = iDevice.Device;
- _context = iDevice.DeviceContext;
+ if (MAX_INDEX_COUNT > ushort.MaxValue)
+#pragma warning disable 162
+ {
+#pragma warning restore IDE0079 // Remove unnecessary suppression
- iDevice.ResizeFinished += IDevice_onResizeFinished;
+ // ReSharper disable once NotResolvedInText
+ throw new ArgumentOutOfRangeException("MAX_INDEX_COUNT->MAX_BATCH_SIZE");
+ }
+#pragma warning restore 162
+ s_indices = new ushort[MAX_INDEX_COUNT];
+ for (int i = 0, k = 0; i < MAX_INDEX_COUNT; i += 6, k += 4)
+ {
+ s_indices[i + 0] = (ushort)(k + 0);
+ s_indices[i + 1] = (ushort)(k + 1);
+ s_indices[i + 2] = (ushort)(k + 2);
+ s_indices[i + 3] = (ushort)(k + 0);
+ s_indices[i + 4] = (ushort)(k + 2);
+ s_indices[i + 5] = (ushort)(k + 3);
+ }
}
- #region Line
-
///
- /// Draw line.
+ /// Initializes a new instance of the class.
///
- /// The first point.
- /// The second point.
- /// The color.
- /// Width of the line.
- /// The opacity.
- /// (Optional) The length factor.
- public void DrawLine(in Vector2 point1,
- in Vector2 point2,
- in Color color,
- float lineWidth,
- float opacity,
- float lengthFactor = 1.0f)
+ /// The graphics device.
+ /// Thrown when a value was unexpectedly null.
+ public Canvas(IGraphicsDevice graphicsDevice)
{
- DrawFillRectangle(
- new RectangleF(point1.X, point1.Y, Vector2.Distance(point1, point2) * lengthFactor, lineWidth), color,
- (float)Math.Atan2(point2.Y - point1.Y, point2.X - point1.X), s_vector2Zero, opacity);
- }
+ _context = graphicsDevice.DeviceContext;
- #endregion
+ _defaultBlendState = graphicsDevice.BlendStates.AlphaBlend;
+ _defaultSamplerState = graphicsDevice.SamplerStates.LinearWrap;
+ _defaultDepthStencilState = graphicsDevice.DepthStencilStates.None;
- ///
- /// Device on resize finished.
- ///
- /// The viewport.
- private static void IDevice_onResizeFinished(ViewportF viewport) { }
+ _defaultRasterizerState = graphicsDevice.RasterizerStates.CullBackDepthClipOff;
+ _defaultRasterizerScissorEnabledState = graphicsDevice.RasterizerStates.CullBackDepthClipOffScissorEnabled;
- #region Triangle
+ _indexBuffer = IndexBuffer.Create(graphicsDevice, s_indices);
- ///
- /// Draw triangle.
- ///
- /// The first point.
- /// The second point.
- /// The third point.
- /// The color.
- /// Width of the line.
- /// The opacity.
- public void DrawTriangle(in Vector2 point1,
- in Vector2 point2,
- in Vector2 point3,
- in Color color,
- float lineWidth,
- float opacity) { }
-
- ///
- /// Draw fill triangle.
- ///
- /// The first point.
- /// The second point.
- /// The third point.
- /// The color.
- /// Width of the line.
- /// The opacity.
- public void DrawFillTriangle(in Vector2 point1,
- in Vector2 point2,
- in Vector2 point3,
- in Color color,
- float lineWidth,
- float opacity) { }
-
- #endregion
+ Assembly assembly = Assembly.GetExecutingAssembly();
+ using (Stream stream =
+ assembly.GetManifestResourceStream($"{assembly.GetName().Name}.{Shaders.CANVAS}") ??
+ throw new NullReferenceException($"{assembly.GetName().Name}.{Shaders.CANVAS}"))
+ {
+ Shader.Shader.Group group =
+ (_shader = ShaderFileLoader.FromStream(graphicsDevice, stream) ??
+ throw new NullReferenceException(nameof(ShaderFileLoader.FromStream)))["DEFAULT"];
- #region Rectangle
+ _vertexShader = group;
+ _pixelShader = group;
- ///
- /// Draw rectangle.
- ///
- /// Destination rectangle.
- /// The color.
- /// Width of the line.
- /// The rotation.
- /// The origin.
- /// The opacity.
- public void DrawRectangle(in RectangleF destinationRectangle,
- in Color color,
- float lineWidth,
- float rotation,
- in Vector2 origin,
- float opacity) { }
+ _vertexInputLayout = group.CreateInputLayout(graphicsDevice, Shader.Shader.Type.VertexShader);
+ }
- ///
- /// Draw fill rectangle.
- ///
- /// Destination rectangle.
- /// The color.
- /// The rotation.
- /// The origin.
- /// The opacity.
- public void DrawFillRectangle(in RectangleF destinationRectangle,
- in Color color,
- float rotation,
- in Vector2 origin,
- float opacity) { }
+ _vertexBuffer = VertexBuffer.Create(graphicsDevice, MAX_VERTEX_COUNT);
+ _perFrameBuffer = ConstantBuffer.Create(graphicsDevice);
- #endregion
+ _itemQueue = (Item*)Marshal.AllocHGlobal(sizeof(Item) * (_itemQueueLength = MAX_BATCH_SIZE));
- #region Arc
+ graphicsDevice.ResizeFinished += GraphicsDeviceOnResizeFinished;
+ Resize(graphicsDevice.Viewport);
+ }
///
- /// Draw arc.
+ /// Resizes.
///
- /// The center.
- /// The radius.
- /// The start.
- /// The end.
- /// The width.
- /// The height.
- /// The color.
- /// Width of the line.
- /// The opacity.
- /// The segments.
- public void DrawArc(in Vector2 center,
- float radius,
- float start,
- float end,
- float width,
- float height,
- in Color color,
- float lineWidth,
- float opacity,
- int segments) { }
+ /// The size.
+ public void Resize(Size2F size)
+ {
+ Resize(size.Width, size.Height);
+ }
///
- /// Draw fill arc.
+ /// Resizes.
///
- /// The center.
- /// The radius.
- /// The start.
- /// The end.
- /// The width.
- /// The height.
- /// The color.
- /// Width of the line.
- /// The opacity.
- /// The segments.
- public void DrawFillArc(in Vector2 center,
- float radius,
- float start,
- float end,
- float width,
- float height,
- in Color color,
- float lineWidth,
- float opacity,
- int segments) { }
-
- #endregion
-
- #region Polygon
+ /// The viewport.
+ public void Resize(ViewportF viewport)
+ {
+ Resize(viewport.Width, viewport.Height);
+ }
///
- /// Draw polygon.
+ /// Resizes.
///
- /// The vertex.
- /// The color.
- /// Width of the line.
- /// The opacity.
- public void DrawPolygon(Vector2[] vertex, in Color color, float lineWidth, float opacity)
+ /// The width.
+ /// The height.
+ public void Resize(float width, float height)
{
- if (vertex.Length > 1)
+ float xRatio = width > 0 ? 1f / width : 0f;
+ float yRatio = height > 0 ? -1f / height : 0f;
+
+ _projectionMatrix = new Matrix
{
- int l = vertex.Length - 1;
- for (int i = 0; i < l; i++)
- {
- DrawLine(vertex[i], vertex[i + 1], color, lineWidth, opacity);
- }
- DrawLine(vertex[l], vertex[0], color, lineWidth, opacity);
- }
+ M11 = xRatio * 2f,
+ M22 = yRatio * 2f,
+ M33 = 1f,
+ M44 = 1f,
+ M41 = -1f,
+ M42 = 1f
+ };
}
///
- /// Draw fill polygon.
- ///
- /// The vertex.
- /// The color.
- /// Width of the line.
- /// The opacity.
- public void DrawFillPolygon(Vector2[] vertex, in Color color, float lineWidth, float opacity) { }
+ /// Begins a new batch.
+ ///
+ /// Thrown when the requested operation is invalid.
+ /// (Optional) State of the blend.
+ /// (Optional) State of the sampler.
+ /// (Optional) State of the depth stencil.
+ /// (Optional) State of the rasterizer.
+ /// (Optional) The transform matrix.
+ /// (Optional) The view matrix.
+ /// (Optional) The scissor rectangle.
+ public void Begin(BlendState? blendState = null,
+ SamplerState? samplerState = null,
+ DepthStencilState? depthStencilState = null,
+ RasterizerState? rasterizerState = null,
+ Matrix? transformMatrix = null,
+ Matrix? viewMatrix = null,
+ Rectangle? scissorRectangle = null)
+ {
+ if (_isBeginCalled)
+ {
+ throw new InvalidOperationException("End must be called before begin");
+ }
- #endregion
+ _blendState = blendState;
+ _samplerState = samplerState;
+ _depthStencilState = depthStencilState;
+ _rasterizerState = rasterizerState;
+ _transformMatrix = transformMatrix ?? Matrix.Identity;
+ _viewMatrix = viewMatrix ?? Matrix.Identity;
- #region Texture
+ _isScissorEnabled = scissorRectangle.HasValue;
+ _scissorRectangle = scissorRectangle ?? Rectangle.Empty;
- ///
- /// Draws.
- ///
- /// The texture.
- /// The position.
- /// The color.
- public void Draw(Texture texture, in Vector2 position, in Color color)
- {
- DrawSprite(
- texture, new RectangleF(position.X, position.Y, 1f, 1f), true,
- s_nullRectangle, color, 0f, s_vector2Zero, 1.0f, SpriteEffects.None);
+ _isBeginCalled = true;
}
///
- /// Draws.
+ /// Ends the current batch.
///
- /// The texture.
- /// Destination rectangle.
- /// The color.
- public void Draw(Texture texture, in RectangleF destinationRectangle, in Color color)
+ /// Thrown when the requested operation is invalid.
+ public void End()
{
- DrawSprite(
- texture, destinationRectangle, false,
- s_nullRectangle, color, 0f, s_vector2Zero, 1.0f, SpriteEffects.None);
- }
+ if (!_isBeginCalled)
+ {
+ throw new InvalidOperationException("Begin must be called before End");
+ }
- ///
- /// Draws.
- ///
- /// The texture.
- /// The position.
- /// Source rectangle.
- /// The color.
- public void Draw(Texture texture, in Vector2 position, in Rectangle? sourceRectangle, in Color color)
- {
- DrawSprite(
- texture, new RectangleF(position.X, position.Y, 1f, 1f), true,
- sourceRectangle, color, 0f, s_vector2Zero, 1.0f, SpriteEffects.None);
- }
+ if (_itemQueueCount > 0)
+ {
+ PrepareForRendering();
+ FlushBatch();
+ }
- ///
- /// Draws.
- ///
- /// The texture.
- /// Destination rectangle.
- /// Source rectangle.
- /// The color.
- public void Draw(Texture texture,
- in RectangleF destinationRectangle,
- in Rectangle? sourceRectangle,
- in Color color)
- {
- DrawSprite(
- texture, destinationRectangle, false,
- sourceRectangle, color, 0f, s_vector2Zero, 1.0f, SpriteEffects.None);
+ _isBeginCalled = false;
}
- ///
- /// Draws.
- ///
- /// The texture.
- /// Destination rectangle.
- /// Source rectangle.
- /// The color.
- /// The rotation.
- /// The origin.
- /// The opacity.
- /// The effects.
- public void Draw(Texture texture,
- in RectangleF destinationRectangle,
- in Rectangle? sourceRectangle,
- in Color color,
- float rotation,
- in Vector2 origin,
- float opacity,
- SpriteEffects effects)
+ private void GraphicsDeviceOnResizeFinished(ViewportF viewport)
{
- DrawSprite(
- texture, destinationRectangle, false,
- sourceRectangle, color, rotation, origin, opacity, effects);
+ Resize(viewport);
}
- ///
- /// Draws.
- ///
- /// The texture.
- /// The position.
- /// Source rectangle.
- /// The color.
- /// The rotation.
- /// The origin.
- /// The scale.
- /// The opacity.
- /// The effects.
- public void Draw(Texture texture,
- in Vector2 position,
- in Rectangle? sourceRectangle,
- in Color color,
- float rotation,
- in Vector2 origin,
- float scale,
- float opacity,
- SpriteEffects effects)
+ private void PrepareForRendering()
{
- DrawSprite(
- texture, new RectangleF(position.X, position.Y, scale, scale), true,
- sourceRectangle, color, rotation, origin, opacity, effects);
- }
+ _context.VertexShader.Set(_vertexShader);
+ _context.PixelShader.Set(_pixelShader);
- ///
- /// Draws.
- ///
- /// The texture.
- /// The position.
- /// Source rectangle.
- /// The color.
- /// The rotation.
- /// The origin.
- /// The scale.
- /// The opacity.
- /// The effects.
- public void Draw(Texture texture,
- in Vector2 position,
- in Rectangle? sourceRectangle,
- in Color color,
- float rotation,
- in Vector2 origin,
- in Vector2 scale,
- float opacity,
- SpriteEffects effects)
- {
- DrawSprite(
- texture, new RectangleF(position.X, position.Y, scale.X, scale.Y), true,
- sourceRectangle, color, rotation, origin, opacity, effects);
- }
+ _context.OutputMerger.SetBlendState(_blendState ?? _defaultBlendState);
+ _context.OutputMerger.SetDepthStencilState(_depthStencilState ?? _defaultDepthStencilState);
- ///
- /// Draw sprite.
- ///
- /// The texture.
- /// Destination for the.
- /// True to scale destination.
- /// Source rectangle.
- /// The color.
- /// The rotation.
- /// The origin.
- /// The opacity.
- /// The effects.
- private void DrawSprite(Texture texture,
- in RectangleF destination,
- bool scaleDestination,
- in Rectangle? sourceRectangle,
- in Color color,
- float rotation,
- in Vector2 origin,
- float opacity,
- SpriteEffects effects) { }
+ _context.Rasterizer.State = _rasterizerState ?? _defaultRasterizerState;
- #endregion
+ if (_isScissorEnabled)
+ {
+ _context.Rasterizer.State = _rasterizerState ?? _defaultRasterizerScissorEnabledState;
+ _context.Rasterizer.SetScissorRectangle(
+ _scissorRectangle.Left, _scissorRectangle.Top,
+ _scissorRectangle.Right, _scissorRectangle.Bottom);
+ }
- #region SpiteFont
+ _context.PixelShader.SetSampler(0, _samplerState ?? _defaultSamplerState);
- ///
- /// Draw text.
- ///
- /// The font.
- /// The text.
- /// The position.
- /// The color.
- public void DrawText(SpriteFont font, string text, in Vector2 position, in Color color)
- {
- font.Draw(DrawTextInternal, text, position, color, 0f, Vector2.Zero, 1.0f, SpriteEffects.None, 0f);
- }
+ _context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;
+ _context.InputAssembler.InputLayout = _vertexInputLayout;
- ///
- /// Draw text.
- ///
- /// The font.
- /// The text.
- /// The position.
- /// The color.
- /// The rotation.
- public void DrawText(SpriteFont font, string text, in Vector2 position, in Color color, float rotation)
- {
- font.Draw(DrawTextInternal, text, position, color, rotation, Vector2.Zero, 1.0f, SpriteEffects.None, 0f);
- }
+ Matrix worldViewProjection = Matrix.Transpose(_transformMatrix * _viewMatrix * _projectionMatrix);
+ _context.UpdateSubresource(ref worldViewProjection, _perFrameBuffer);
+ _context.VertexShader.SetConstantBuffer(0, _perFrameBuffer);
+ _context.PixelShader.SetConstantBuffer(0, _perFrameBuffer);
- ///
- /// Draw text.
- ///
- /// The font.
- /// The text.
- /// The position.
- /// The color.
- /// The rotation.
- /// The origin.
- /// The opacity.
- /// The effects.
- public void DrawText(SpriteFont font,
- string text,
- in Vector2 position,
- in Color color,
- float rotation,
- in Vector2 origin,
- float opacity,
- SpriteEffects effects)
- {
- font.Draw(DrawTextInternal, text, position, color, rotation, origin, opacity, effects, 0f);
+ _context.InputAssembler.SetIndexBuffer(_indexBuffer, _indexBuffer.Format, 0);
+ _context.InputAssembler.SetVertexBuffers(0, _vertexBuffer);
}
- ///
- /// Draw text.
- ///
- /// The font.
- /// The text.
- /// The start.
- /// The end.
- /// The position.
- /// The color.
- /// The rotation.
- /// The origin.
- /// The opacity.
- /// The effects.
- public void DrawText(SpriteFont font,
- string text,
- int start,
- int end,
- in Vector2 position,
- in Color color,
- float rotation,
- in Vector2 origin,
- float opacity,
- SpriteEffects effects)
+ private void FlushBatch()
{
- font.Draw(DrawTextInternal, text, start, end, position, color, rotation, origin, opacity, effects, 0f);
- }
+ int offset = 0;
- ///
- /// Draw text.
- ///
- /// The font.
- /// The text.
- /// The start.
- /// The end.
- /// The position.
- /// The dimension.
- /// The color.
- /// The rotation.
- /// The origin.
- /// The opacity.
- /// The effects.
- public void DrawText(SpriteFont font,
- string text,
- int start,
- int end,
- in Vector2 position,
- in Size2F dimension,
- in Color color,
- float rotation,
- in Vector2 origin,
- float opacity,
- SpriteEffects effects)
- {
- font.Draw(
- DrawTextInternal, text, start, end, position, dimension, color, rotation, origin, opacity, effects, 0f);
- }
+ for (int i = 0; i < _itemQueueCount; i++)
+ {
+ ref Item item = ref _itemQueue[i];
- ///
- /// Draw text.
- ///
- /// The font.
- /// The text.
- /// The position.
- /// The color.
- public void DrawText(SpriteFont font, StringBuilder text, in Vector2 position, in Color color)
- {
- font.Draw(DrawTextInternal, text, position, color, 0f, Vector2.Zero, 1.0f, SpriteEffects.None, 0f);
- }
+ switch (item.V1.M)
+ {
+ case TEXTURE_MODE:
+ {
+ long tp = item.V1.ZW;
+ if (!_textures.TryGetValue(tp, out Texture texture))
+ {
+ throw new KeyNotFoundException("The looked up texture wasn't found!");
+ }
+
+ if (!_textureSlotMap.TryGetValue(tp, out int tSlot))
+ {
+ _context.PixelShader.SetShaderResource(_textureSlotMap.Count, texture.TextureView);
+ _textureSlotMap.Add(tp, tSlot = _textureSlotMap.Count);
+ }
+
+ item.V1.O = tSlot;
+ item.V2.O = tSlot;
+ item.V3.O = tSlot;
+ item.V4.O = tSlot;
+
+ if (_textureSlotMap.Count > MAX_TEXTURE_SLOTS)
+ {
+ if (i > offset)
+ {
+ DrawBatch(offset, i - offset);
+ }
+
+ offset = i;
+ _textureSlotMap.Clear();
+ _fontTextureSlotMap.Clear();
+ }
+ break;
+ }
+ case FONT_TEXTURE_MODE:
+ {
+ long tp = item.V1.ZW;
+ if (!_textures.TryGetValue(tp, out Texture texture))
+ {
+ throw new KeyNotFoundException("The looked up texture wasn't found!");
+ }
+
+ if (!_fontTextureSlotMap.TryGetValue(tp, out int tSlot))
+ {
+ _context.PixelShader.SetShaderResource(
+ MAX_TEXTURE_SLOTS + _fontTextureSlotMap.Count, texture.TextureView);
+ _fontTextureSlotMap.Add(tp, tSlot = _fontTextureSlotMap.Count);
+ }
+
+ item.V1.O = tSlot;
+ item.V2.O = tSlot;
+ item.V3.O = tSlot;
+ item.V4.O = tSlot;
+
+ if (_fontTextureSlotMap.Count > MAX_FONT_TEXTURE_SLOTS)
+ {
+ if (i > offset)
+ {
+ DrawBatch(offset, i - offset);
+ }
+
+ offset = i;
+ _fontTextureSlotMap.Clear();
+ _textureSlotMap.Clear();
+ }
+ break;
+ }
+ }
+ }
- ///
- /// Draw text.
- ///
- /// The font.
- /// The text.
- /// The position.
- /// The color.
- /// The rotation.
- public void DrawText(SpriteFont font, StringBuilder text, in Vector2 position, in Color color, float rotation)
- {
- font.Draw(DrawTextInternal, text, position, color, rotation, Vector2.Zero, 1.0f, SpriteEffects.None, 0f);
- }
+ DrawBatch(offset, _itemQueueCount - offset);
- ///
- /// Draw text.
- ///
- /// The font.
- /// The text.
- /// The position.
- /// The color.
- /// The rotation.
- /// The origin.
- /// The opacity.
- /// The effects.
- public void DrawText(SpriteFont font,
- StringBuilder text,
- in Vector2 position,
- in Color color,
- float rotation,
- in Vector2 origin,
- float opacity,
- SpriteEffects effects)
- {
- font.Draw(DrawTextInternal, text, position, color, rotation, origin, opacity, effects, 0f);
+ _itemQueueCount = 0;
+ _textureSlotMap.Clear();
+ _fontTextureSlotMap.Clear();
}
- ///
- /// Draw text.
- ///
- /// The font.
- /// The text.
- /// The start.
- /// The end.
- /// The position.
- /// The color.
- /// The rotation.
- /// The origin.
- /// The opacity.
- /// The effects.
- public void DrawText(SpriteFont font,
- StringBuilder text,
- int start,
- int end,
- in Vector2 position,
- in Color color,
- float rotation,
- in Vector2 origin,
- float opacity,
- SpriteEffects effects)
+ private void DrawBatch(int offset, int count)
{
- font.Draw(DrawTextInternal, text, start, end, position, color, rotation, origin, opacity, effects, 0f);
- }
+ while (count > 0)
+ {
+ int batchSize = count;
+ if (batchSize > MAX_BATCH_SIZE)
+ {
+ batchSize = MAX_BATCH_SIZE;
+ }
- ///
- /// Draw text.
- ///
- /// The font.
- /// The text.
- /// The start.
- /// The end.
- /// The position.
- /// The dimension.
- /// The color.
- /// The rotation.
- /// The origin.
- /// The opacity.
- /// The effects.
- public void DrawText(SpriteFont font,
- StringBuilder text,
- int start,
- int end,
- in Vector2 position,
- in Size2F dimension,
- in Color color,
- float rotation,
- in Vector2 origin,
- float opacity,
- SpriteEffects effects)
- {
- font.Draw(
- DrawTextInternal, text, start, end, position, dimension, color, rotation, origin, opacity, effects, 0f);
+ DataBox box = _context.MapSubresource(
+ _vertexBuffer, 0, MapMode.WriteDiscard, MapFlags.None);
+ VertexPositionColorTextureMode* vpctPtr = (VertexPositionColorTextureMode*)box.DataPointer;
+
+ for (int i = 0; i < batchSize; i++)
+ {
+ ref Item item = ref _itemQueue[i + offset];
+ VertexPositionColorTextureMode* v = vpctPtr + (i << 2);
+ *(v + 0) = item.V1;
+ *(v + 1) = item.V2;
+ *(v + 2) = item.V3;
+ *(v + 3) = item.V4;
+ }
+
+ _context.UnmapSubresource(_vertexBuffer, 0);
+ _context.DrawIndexed(6 * batchSize, 0, 0);
+
+ offset += batchSize;
+ count -= batchSize;
+ }
}
- ///
- /// Draw text internal.
- ///
- /// The texture.
- /// The position.
- /// Source rectangle.
- /// The color.
- /// The rotation.
- /// The origin.
- /// The scale.
- /// The opacity.
- /// The effects.
- /// Depth of the layer.
- internal void DrawTextInternal(Texture texture,
- in Vector2 position,
- in Rectangle? sourceRectangle,
- in Color color,
- float rotation,
- in Vector2 origin,
- float scale,
- float opacity,
- SpriteEffects effects,
- float layerDepth)
+ private Item* Reserve(int itemCount)
{
- DrawSprite(
- texture, new RectangleF(position.X, position.Y, scale, scale), true, sourceRectangle, color,
- rotation, origin, opacity, effects);
- }
+ if (_itemQueueCount >= _itemQueueLength)
+ {
+ bool lockTaken = false;
+ try
+ {
+ _spinLock.Enter(ref lockTaken);
+ if (_itemQueueCount >= _itemQueueLength)
+ {
+ Mem.Resize(ref _itemQueue, ref _itemQueueLength, _itemQueueLength * 2);
+ }
+ }
+ finally
+ {
+ if (lockTaken)
+ {
+ _spinLock.Exit(false);
+ }
+ }
+ }
- #endregion
+ return _itemQueue + (Interlocked.Add(ref _itemQueueCount, itemCount) - itemCount);
+ }
#region IDisposable Support
@@ -655,7 +462,22 @@ private void Dispose(bool disposing)
{
if (!_disposed)
{
- if (disposing) { }
+ if (disposing)
+ {
+ Utilities.Dispose(ref _blendState);
+ Utilities.Dispose(ref _rasterizerState);
+ Utilities.Dispose(ref _samplerState);
+ Utilities.Dispose(ref _depthStencilState);
+
+ _vertexBuffer.Dispose();
+ _indexBuffer.Dispose();
+ _perFrameBuffer.Dispose();
+
+ _shader.Dispose();
+ _vertexInputLayout.Dispose();
+ }
+
+ Marshal.FreeHGlobal(new IntPtr(_itemQueue));
_disposed = true;
}
diff --git a/src/Exomia.Framework/Graphics/DefaultTextures.cs b/src/Exomia.Framework/Graphics/DefaultTextures.cs
deleted file mode 100644
index 76ea0dcb..00000000
--- a/src/Exomia.Framework/Graphics/DefaultTextures.cs
+++ /dev/null
@@ -1,98 +0,0 @@
-#region License
-
-// Copyright (c) 2018-2020, exomia
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree.
-
-#endregion
-
-using System;
-using System.IO;
-using SharpDX;
-using SharpDX.Direct3D11;
-
-namespace Exomia.Framework.Graphics
-{
- ///
- /// A default textures.
- ///
- public static class DefaultTextures
- {
- private const string WHITE_TEXTURE_BASE64 =
- "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+ip1sAAAAASUVORK5CYII=";
-
- private static Texture? s_whiteTexture;
- private static bool s_isInitialized;
-
- ///
- /// Gets the white texture.
- ///
- ///
- /// The white texture.
- ///
- public static Texture WhiteTexture
- {
- get { return s_whiteTexture!; }
- }
-
- ///
- /// Initializes the textures.
- ///
- /// The device.
- internal static void InitializeTextures(Device5 device)
- {
- if (!s_isInitialized)
- {
- s_isInitialized = true;
- s_disposedValue = false;
-
- using (MemoryStream ms = new MemoryStream(Convert.FromBase64String(WHITE_TEXTURE_BASE64)))
- {
- s_whiteTexture = Texture.Load(device, ms) ??
- throw new NullReferenceException($"{nameof(WhiteTexture)}");
- }
- }
- }
-
- #region IDisposable Support
-
- ///
- /// True to disposed value.
- ///
- private static bool s_disposedValue;
-
- ///
- /// Performs application-defined tasks associated with freeing, releasing, or resetting
- /// unmanaged resources.
- ///
- ///
- /// True to release both managed and unmanaged resources; false to
- /// release only unmanaged resources.
- ///
- public static void Dispose(bool disposing)
- {
- if (!s_disposedValue)
- {
- if (disposing)
- {
- Utilities.Dispose(ref s_whiteTexture);
- }
- s_isInitialized = false;
- s_disposedValue = true;
- }
- }
-
- ///
- /// Performs application-defined tasks associated with freeing, releasing, or resetting
- /// unmanaged resources.
- ///
- public static void Dispose()
- {
- Dispose(true);
- }
-
- #endregion
- }
-}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Graphics/DepthStencilStates.cs b/src/Exomia.Framework/Graphics/DepthStencilStates.cs
new file mode 100644
index 00000000..93472f6c
--- /dev/null
+++ b/src/Exomia.Framework/Graphics/DepthStencilStates.cs
@@ -0,0 +1,122 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using System;
+using SharpDX.Direct3D11;
+
+namespace Exomia.Framework.Graphics
+{
+ ///
+ /// The built-in depth stencil states. This class cannot be inherited.
+ ///
+ public sealed class DepthStencilStates : IDisposable
+ {
+ ///
+ /// A built-in state object with default settings for using a depth stencil buffer.
+ ///
+ public readonly DepthStencilState Default;
+
+ ///
+ /// A built-in state object with settings for enabling a read-only depth stencil buffer.
+ ///
+ public readonly DepthStencilState DepthRead;
+
+ ///
+ /// A built-in state object with settings for not using a depth stencil buffer.
+ ///
+ public readonly DepthStencilState None;
+
+ ///
+ /// A built-in state object with default settings for using a depth stencil buffer with stencil enabled.
+ ///
+ public readonly DepthStencilState DefaultStencilEnabled;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The graphics device.
+ internal DepthStencilStates(IGraphicsDevice graphicsDevice)
+ {
+ Default = Create(graphicsDevice.Device, nameof(Default), true, true, false);
+ DepthRead = Create(graphicsDevice.Device, nameof(DepthRead), true, false, false);
+ None = Create(graphicsDevice.Device, nameof(None), false, false, false);
+ DefaultStencilEnabled = Create(graphicsDevice.Device, nameof(DefaultStencilEnabled), true, true, true);
+ }
+
+ private static DepthStencilState Create(Device5 device,
+ string name,
+ bool depthEnable,
+ bool depthWriteEnable,
+ bool stencilEnabled)
+ {
+ return new DepthStencilState(
+ device,
+ new DepthStencilStateDescription
+ {
+ IsDepthEnabled = depthEnable,
+ DepthWriteMask = depthWriteEnable ? DepthWriteMask.All : DepthWriteMask.Zero,
+ DepthComparison = Comparison.LessEqual,
+ IsStencilEnabled = stencilEnabled,
+ StencilReadMask = 0xFF,
+ StencilWriteMask = 0xFF,
+ FrontFace = new DepthStencilOperationDescription
+ {
+ FailOperation = StencilOperation.Keep,
+ DepthFailOperation = StencilOperation.Keep,
+ PassOperation = StencilOperation.Keep,
+ Comparison = Comparison.Always
+ },
+ BackFace = new DepthStencilOperationDescription
+ {
+ FailOperation = StencilOperation.Keep,
+ DepthFailOperation = StencilOperation.Keep,
+ PassOperation = StencilOperation.Keep,
+ Comparison = Comparison.Always
+ }
+ }) { DebugName = name };
+ }
+
+ #region IDisposable Support
+
+ private bool _disposed;
+
+ private void Dispose(bool disposing)
+ {
+ if (!_disposed)
+ {
+ if (disposing)
+ {
+ Default.Dispose();
+ DepthRead.Dispose();
+ None.Dispose();
+ DefaultStencilEnabled.Dispose();
+ }
+ _disposed = true;
+ }
+ }
+
+ ///
+ ~DepthStencilStates()
+ {
+ Dispose(false);
+ }
+
+ ///
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged/managed resources.
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Graphics/GraphicsDevice.cs b/src/Exomia.Framework/Graphics/GraphicsDevice.cs
index c1661523..63d721c0 100644
--- a/src/Exomia.Framework/Graphics/GraphicsDevice.cs
+++ b/src/Exomia.Framework/Graphics/GraphicsDevice.cs
@@ -41,47 +41,52 @@ public sealed class GraphicsDevice : IGraphicsDevice
public event EventHandler? ResizeFinished;
private Adapter4? _adapter4;
- private RenderTargetView1? _currentRenderView;
- private Device5? _d3DDevice5;
- private DeviceContext4? _d3DDeviceContext;
- private DepthStencilView? _depthStencilView;
- private Device4? _dxgiDevice4;
- private Factory5? _dxgiFactory;
- private bool _needResize;
- private Output6? _output6;
- private RenderTargetView1? _renderView1;
+ private RenderTargetView1 _currentRenderView = null!;
+ private Device5 _d3DDevice5 = null!;
+ private DeviceContext4 _d3DDeviceContext = null!;
+ private DepthStencilView _depthStencilView = null!;
+ private Device4 _dxgiDevice4 = null!;
+ private Factory5 _dxgiFactory = null!;
+ private Output6 _output6 = null!;
+ private RenderTargetView1 _renderView1 = null!;
+ private SwapChain4 _swapChain4 = null!;
+ private BlendStates _blendStates = null!;
+ private DepthStencilStates _depthStencilStates = null!;
+ private RasterizerStates _rasterizerStates = null!;
+ private SamplerStates _samplerStates = null!;
+ private Textures _textures = null!;
private ResizeParameters _resizeParameters;
- private SwapChain4? _swapChain4;
+ private bool _needResize;
private int _vSync;
///
- public Adapter4 Adapter
+ public Adapter4? Adapter
{
- get { return _adapter4!; }
+ get { return _adapter4; }
}
///
public Device5 Device
{
- get { return _d3DDevice5!; }
+ get { return _d3DDevice5; }
}
///
public DeviceContext4 DeviceContext
{
- get { return _d3DDeviceContext!; }
+ get { return _d3DDeviceContext; }
}
///
public Device4 DxgiDevice
{
- get { return _dxgiDevice4!; }
+ get { return _dxgiDevice4; }
}
///
public Factory5 Factory
{
- get { return _dxgiFactory!; }
+ get { return _dxgiFactory; }
}
///
@@ -90,13 +95,13 @@ public Factory5 Factory
///
public RenderTargetView1 RenderView
{
- get { return _renderView1!; }
+ get { return _renderView1; }
}
///
public SwapChain4 SwapChain
{
- get { return _swapChain4!; }
+ get { return _swapChain4; }
}
///
@@ -109,6 +114,36 @@ public bool VSync
set { _vSync = value ? 1 : 0; }
}
+ ///
+ public BlendStates BlendStates
+ {
+ get { return _blendStates; }
+ }
+
+ ///
+ public DepthStencilStates DepthStencilStates
+ {
+ get { return _depthStencilStates; }
+ }
+
+ ///
+ public RasterizerStates RasterizerStates
+ {
+ get { return _rasterizerStates; }
+ }
+
+ ///
+ public SamplerStates SamplerStates
+ {
+ get { return _samplerStates; }
+ }
+
+ ///
+ public Textures Textures
+ {
+ get { return _textures; }
+ }
+
///
public void Clear()
{
@@ -118,9 +153,9 @@ public void Clear()
///
public void Clear(Color color)
{
- _d3DDeviceContext!.ClearDepthStencilView(
- _depthStencilView!, DepthStencilClearFlags.Depth | DepthStencilClearFlags.Stencil, 1f, 0);
- _d3DDeviceContext!.ClearRenderTargetView(_currentRenderView!, color);
+ _d3DDeviceContext.ClearDepthStencilView(
+ _depthStencilView, DepthStencilClearFlags.Depth | DepthStencilClearFlags.Stencil, 1f, 0);
+ _d3DDeviceContext!.ClearRenderTargetView(_currentRenderView, color);
}
///
@@ -141,7 +176,7 @@ public void Resize(int width, int height)
{
_resizeParameters = new ResizeParameters
{
- BufferCount = _swapChain4!.Description1.BufferCount,
+ BufferCount = _swapChain4.Description1.BufferCount,
Width = width,
Height = height,
SwapChainFlags = _swapChain4.Description1.Flags
@@ -154,21 +189,21 @@ public void SetFullscreenState(bool state, Output? output = null)
{
if (GetFullscreenState() != state)
{
- _swapChain4!.SetFullscreenState(state, output);
+ _swapChain4.SetFullscreenState(state, output);
}
}
///
public bool GetFullscreenState()
{
- return _swapChain4!.IsFullScreen;
+ return _swapChain4.IsFullScreen;
}
///
public void SetRenderTarget(RenderTargetView1? target)
{
_currentRenderView = target ?? _renderView1;
- _d3DDeviceContext!.OutputMerger.SetRenderTargets(_depthStencilView, _currentRenderView);
+ _d3DDeviceContext.OutputMerger.SetRenderTargets(_depthStencilView, _currentRenderView);
}
///
@@ -192,11 +227,11 @@ public bool BeginFrame()
///
public void EndFrame()
{
- _swapChain4!.Present(_vSync, PresentFlags.None, s_defaultPresentParameters);
+ _swapChain4.Present(_vSync, PresentFlags.None, s_defaultPresentParameters);
}
///
- /// Initializes this object.
+ /// Initializes the .
///
/// [in,out] Options for controlling the operation.
public void Initialize(ref GameGraphicsParameters parameters)
@@ -242,10 +277,10 @@ public void Initialize(ref GameGraphicsParameters parameters)
featureLevel: SharpDX.Direct3D11.Device.GetSupportedFeatureLevel(a)))
.GroupBy(t => t.featureLevel)
.OrderByDescending(t => t.Key)
- .FirstOrDefault()
+ .First()
.Select(k => k.adapter);
- _adapter4 = null!;
+ _adapter4 = null;
foreach (Adapter adapter in adapters)
{
using (adapter)
@@ -299,7 +334,7 @@ Device CreateDevice(in GameGraphicsParameters parameters)
Console.WriteLine($"Scaling:\t\t{modeDescription.Scaling}");
Console.WriteLine($"ScanlineOrdering:\t{modeDescription.ScanlineOrdering}");
Console.WriteLine();
- Console.WriteLine($"DeviceName:\t\t{_output6!.Description.DeviceName}");
+ Console.WriteLine($"DeviceName:\t\t{_output6.Description.DeviceName}");
Console.WriteLine(
$"DesktopBounds:\t\t{_output6.Description.DesktopBounds.Left};{_output6.Description.DesktopBounds.Top};{_output6.Description.DesktopBounds.Right};{_output6.Description.DesktopBounds.Bottom}");
Console.WriteLine($"MonitorHandle:\t\t{_output6.Description.MonitorHandle}");
@@ -351,7 +386,7 @@ Device CreateDevice(in GameGraphicsParameters parameters)
_dxgiFactory.MakeWindowAssociation(parameters.Handle, parameters.WindowAssociationFlags);
- _swapChain4!.ResizeTarget(ref modeDescription);
+ _swapChain4.ResizeTarget(ref modeDescription);
SetFullscreenState(parameters.DisplayType == DisplayType.Fullscreen);
@@ -365,6 +400,12 @@ Device CreateDevice(in GameGraphicsParameters parameters)
Resize(_resizeParameters);
+ _blendStates = new BlendStates(this);
+ _depthStencilStates = new DepthStencilStates(this);
+ _rasterizerStates = new RasterizerStates(this);
+ _samplerStates = new SamplerStates(this);
+ _textures = new Textures(this);
+
IsInitialized = true;
}
@@ -373,9 +414,9 @@ private void Resize(ResizeParameters args)
Utilities.Dispose(ref _renderView1);
Utilities.Dispose(ref _depthStencilView);
- _d3DDeviceContext!.ClearState();
+ _d3DDeviceContext.ClearState();
- _swapChain4!.ResizeBuffers(
+ _swapChain4.ResizeBuffers(
args.BufferCount, args.Width, args.Height, Format.Unknown, args.SwapChainFlags);
using (Texture2D backBuffer = _swapChain4.GetBackBuffer(0))
@@ -410,7 +451,7 @@ private void Resize(ResizeParameters args)
});
}
- _d3DDeviceContext!.Rasterizer.SetViewport(Viewport = new Viewport(0, 0, args.Width, args.Height));
+ _d3DDeviceContext.Rasterizer.SetViewport(Viewport = new Viewport(0, 0, args.Width, args.Height));
SetRenderTarget(null);
@@ -453,6 +494,13 @@ private void Dispose(bool disposing)
{
if (disposing)
{
+ _blendStates.Dispose();
+ _depthStencilStates.Dispose();
+ _rasterizerStates.Dispose();
+ _samplerStates.Dispose();
+
+ _textures.Dispose();
+
Utilities.Dispose(ref _depthStencilView);
Utilities.Dispose(ref _renderView1);
Utilities.Dispose(ref _dxgiDevice4);
diff --git a/src/Exomia.Framework/Graphics/IGraphicsDevice.cs b/src/Exomia.Framework/Graphics/IGraphicsDevice.cs
index 0b71c9b5..618f274d 100644
--- a/src/Exomia.Framework/Graphics/IGraphicsDevice.cs
+++ b/src/Exomia.Framework/Graphics/IGraphicsDevice.cs
@@ -41,7 +41,7 @@ public interface IGraphicsDevice : IDisposable
///
/// The adapter.
///
- Adapter4 Adapter { get; }
+ Adapter4? Adapter { get; }
///
/// Gets the device.
@@ -107,6 +107,46 @@ public interface IGraphicsDevice : IDisposable
///
bool VSync { get; set; }
+ ///
+ /// Gets the for this graphics device.
+ ///
+ ///
+ /// The blend states.
+ ///
+ BlendStates BlendStates { get; }
+
+ ///
+ /// Gets the for this graphics device.
+ ///
+ ///
+ /// The depth stencil states.
+ ///
+ DepthStencilStates DepthStencilStates { get; }
+
+ ///
+ /// Gets the for this graphics device.
+ ///
+ ///
+ /// The rasterizer states.
+ ///
+ RasterizerStates RasterizerStates { get; }
+
+ ///
+ /// Gets the for this graphics device.
+ ///
+ ///
+ /// The sample states.
+ ///
+ SamplerStates SamplerStates { get; }
+
+ ///
+ /// Gets the for this graphics device.
+ ///
+ ///
+ /// The textures.
+ ///
+ Textures Textures { get; }
+
///
/// Clears this object to its blank/initial state.
///
diff --git a/src/Exomia.Framework/Graphics/RasterizerStates.cs b/src/Exomia.Framework/Graphics/RasterizerStates.cs
new file mode 100644
index 00000000..ad6899fc
--- /dev/null
+++ b/src/Exomia.Framework/Graphics/RasterizerStates.cs
@@ -0,0 +1,162 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using System;
+using SharpDX.Direct3D11;
+
+namespace Exomia.Framework.Graphics
+{
+ ///
+ /// The built-in rasterizer states. This class cannot be inherited.
+ ///
+ public sealed class RasterizerStates : IDisposable
+ {
+ ///
+ /// Built-in rasterizer state object with settings for wireframe rendering.
+ ///
+ public readonly RasterizerState WireFrame;
+
+ ///
+ /// Built-in rasterizer state object with settings for wireframe rendering.
+ ///
+ public readonly RasterizerState WireFrameCullNone;
+
+ ///
+ /// Built-in rasterizer state object with settings for culling primitives with clockwise winding order (front facing).
+ ///
+ public readonly RasterizerState CullFront;
+
+ ///
+ /// Built-in rasterizer state object with settings for culling primitives with counter-clockwise winding order (back
+ /// facing).
+ ///
+ public readonly RasterizerState CullBack;
+
+ ///
+ /// Built-in rasterizer state object with settings for not culling any primitives.
+ ///
+ public readonly RasterizerState CullNone;
+
+ ///
+ /// Built-in rasterizer state object with settings and depth clip off.
+ ///
+ public readonly RasterizerState CullBackDepthClipOff;
+
+ ///
+ /// Built-in rasterizer state object with settings and scissor enabled.
+ ///
+ public readonly RasterizerState CullBackScissorEnabled;
+
+ ///
+ /// Built-in rasterizer state object with settings and
+ /// .
+ ///
+ public readonly RasterizerState CullBackDepthClipOffScissorEnabled;
+
+ ///
+ /// Built-in rasterizer state object with settings and multi sample enabled.
+ ///
+ public readonly RasterizerState CullBackDepthClipOffMultiSampleOn;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The graphics device.
+ internal RasterizerStates(IGraphicsDevice graphicsDevice)
+ {
+ WireFrame = Create(
+ graphicsDevice.Device, nameof(WireFrame), FillMode.Wireframe, CullMode.Back, true, false, false);
+ WireFrameCullNone = Create(
+ graphicsDevice.Device, nameof(WireFrameCullNone), FillMode.Wireframe, CullMode.None, true, false,
+ false);
+ CullFront = Create(
+ graphicsDevice.Device, nameof(CullFront), FillMode.Solid, CullMode.Front, true, false, false);
+ CullBack = Create(
+ graphicsDevice.Device, nameof(CullBack), FillMode.Solid, CullMode.Back, true, false, false);
+ CullNone = Create(
+ graphicsDevice.Device, nameof(CullNone), FillMode.Solid, CullMode.None, true, false, false);
+ CullBackDepthClipOff = Create(
+ graphicsDevice.Device, nameof(CullBack), FillMode.Solid, CullMode.Back, false, false, false);
+ CullBackScissorEnabled = Create(
+ graphicsDevice.Device, nameof(CullBack), FillMode.Solid, CullMode.Back, true, true, false);
+ CullBackDepthClipOffScissorEnabled = Create(
+ graphicsDevice.Device, nameof(CullBack), FillMode.Solid, CullMode.Back, true, true, false);
+ CullBackDepthClipOffMultiSampleOn = Create(
+ graphicsDevice.Device, nameof(CullBack), FillMode.Solid, CullMode.Back, false, false, true);
+ }
+
+ private static RasterizerState Create(Device5 device,
+ string name,
+ FillMode fillMode,
+ CullMode cullMode,
+ bool depthClipEnabled,
+ bool scissorEnabled,
+ bool multiSampleEnabled)
+ {
+ return new RasterizerState(
+ device,
+ new RasterizerStateDescription
+ {
+ FillMode = fillMode,
+ CullMode = cullMode,
+ IsFrontCounterClockwise = false,
+ DepthBias = 0,
+ DepthBiasClamp = 0,
+ SlopeScaledDepthBias = 0,
+ IsDepthClipEnabled = depthClipEnabled,
+ IsScissorEnabled = scissorEnabled,
+ IsMultisampleEnabled = multiSampleEnabled,
+ IsAntialiasedLineEnabled = multiSampleEnabled
+ }) { DebugName = name };
+ }
+
+ #region IDisposable Support
+
+ private bool _disposed;
+
+ private void Dispose(bool disposing)
+ {
+ if (!_disposed)
+ {
+ if (disposing)
+ {
+ WireFrame.Dispose();
+ WireFrameCullNone.Dispose();
+ CullFront.Dispose();
+ CullBack.Dispose();
+ CullNone.Dispose();
+ CullBackDepthClipOff.Dispose();
+ CullBackScissorEnabled.Dispose();
+ CullBackDepthClipOffScissorEnabled.Dispose();
+ CullBackDepthClipOffMultiSampleOn.Dispose();
+ }
+
+ _disposed = true;
+ }
+ }
+
+ ///
+ ~RasterizerStates()
+ {
+ Dispose(false);
+ }
+
+ ///
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged/managed resources.
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Graphics/SamplerStates.cs b/src/Exomia.Framework/Graphics/SamplerStates.cs
new file mode 100644
index 00000000..b4bb3763
--- /dev/null
+++ b/src/Exomia.Framework/Graphics/SamplerStates.cs
@@ -0,0 +1,156 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using System;
+using SharpDX;
+using SharpDX.Direct3D11;
+
+namespace Exomia.Framework.Graphics
+{
+ ///
+ /// The built-in sampler states. This class cannot be inherited.
+ ///
+ public sealed class SamplerStates : IDisposable
+ {
+ ///
+ /// Point filtering with texture coordinate wrapping.
+ ///
+ public readonly SamplerState PointWrap;
+
+ ///
+ /// Point filtering with texture coordinate clamping.
+ ///
+ public readonly SamplerState PointClamp;
+
+ ///
+ /// Point filtering with texture coordinate mirroring.
+ ///
+ public readonly SamplerState PointMirror;
+
+ ///
+ /// Linear filtering with texture coordinate wrapping.
+ ///
+ public readonly SamplerState LinearWrap;
+
+ ///
+ /// Linear filtering with texture coordinate clamping.
+ ///
+ public readonly SamplerState LinearClamp;
+
+ ///
+ /// Linear filtering with texture coordinate mirroring.
+ ///
+ public readonly SamplerState LinearMirror;
+
+ ///
+ /// Anisotropic filtering with texture coordinate wrapping.
+ ///
+ public readonly SamplerState AnisotropicWrap;
+
+ ///
+ /// Anisotropic filtering with texture coordinate clamping.
+ ///
+ public readonly SamplerState AnisotropicClamp;
+
+ ///
+ /// Anisotropic filtering with texture coordinate mirroring.
+ ///
+ public readonly SamplerState AnisotropicMirror;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The graphics device.
+ internal SamplerStates(IGraphicsDevice graphicsDevice)
+ {
+ PointWrap = Create(
+ graphicsDevice.Device, nameof(PointWrap), Filter.MinMagMipPoint, TextureAddressMode.Wrap);
+ PointClamp = Create(
+ graphicsDevice.Device, nameof(PointClamp), Filter.MinMagMipPoint, TextureAddressMode.Clamp);
+ PointMirror = Create(
+ graphicsDevice.Device, nameof(PointMirror), Filter.MinMagMipPoint, TextureAddressMode.Mirror);
+ LinearWrap = Create(
+ graphicsDevice.Device, nameof(LinearWrap), Filter.MinMagMipLinear, TextureAddressMode.Wrap);
+ LinearClamp = Create(
+ graphicsDevice.Device, nameof(LinearClamp), Filter.MinMagMipLinear, TextureAddressMode.Clamp);
+ LinearMirror = Create(
+ graphicsDevice.Device, nameof(LinearMirror), Filter.MinMagMipLinear, TextureAddressMode.Mirror);
+ AnisotropicWrap = Create(
+ graphicsDevice.Device, nameof(AnisotropicWrap), Filter.Anisotropic, TextureAddressMode.Wrap);
+ AnisotropicClamp = Create(
+ graphicsDevice.Device, nameof(AnisotropicClamp), Filter.Anisotropic, TextureAddressMode.Clamp);
+ AnisotropicMirror = Create(
+ graphicsDevice.Device, nameof(AnisotropicMirror), Filter.Anisotropic, TextureAddressMode.Mirror);
+ }
+
+ private static SamplerState Create(Device5 device,
+ string name,
+ Filter filter,
+ TextureAddressMode textureAddressMode)
+ {
+ return new SamplerState(
+ device,
+ new SamplerStateDescription
+ {
+ AddressU = textureAddressMode,
+ AddressV = textureAddressMode,
+ AddressW = textureAddressMode,
+ BorderColor = Color.White,
+ ComparisonFunction = Comparison.Never,
+ Filter = filter,
+ MaximumAnisotropy = 16,
+ MaximumLod = float.MaxValue,
+ MinimumLod = float.MinValue,
+ MipLodBias = 0.0f
+ }) { DebugName = name };
+ }
+
+ #region IDisposable Support
+
+ private bool _disposed;
+
+ private void Dispose(bool disposing)
+ {
+ if (!_disposed)
+ {
+ if (disposing)
+ {
+ PointWrap.Dispose();
+ PointClamp.Dispose();
+ PointMirror.Dispose();
+ LinearWrap.Dispose();
+ LinearClamp.Dispose();
+ LinearMirror.Dispose();
+ AnisotropicWrap.Dispose();
+ AnisotropicClamp.Dispose();
+ AnisotropicMirror.Dispose();
+ }
+ _disposed = true;
+ }
+ }
+
+ ///
+ ~SamplerStates()
+ {
+ Dispose(false);
+ }
+
+ ///
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged/managed resources.
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Graphics/Shader/Shader.cs b/src/Exomia.Framework/Graphics/Shader/Shader.cs
index 09a7c58d..271a1b66 100644
--- a/src/Exomia.Framework/Graphics/Shader/Shader.cs
+++ b/src/Exomia.Framework/Graphics/Shader/Shader.cs
@@ -13,9 +13,11 @@
using System.Linq;
using System.Runtime.CompilerServices;
using Exomia.Framework.Content;
+using Exomia.Framework.Mathematics;
using SharpDX;
using SharpDX.D3DCompiler;
using SharpDX.Direct3D11;
+using SharpDX.DXGI;
namespace Exomia.Framework.Graphics.Shader
{
@@ -61,254 +63,354 @@ public enum Type
ComputeShader
}
- private readonly Dictionary _techniques;
+ private readonly Dictionary _groups;
///
- /// Specify the technique to get
+ /// Specify the group to get.
///
- /// The technique name.
+ /// The group name.
///
- /// The .
+ /// The .
///
- public Technique this[string name]
+ public Group this[string name]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- get { return GetTechnique(name); }
+ get { return GetGroup(name); }
}
///
/// Initializes a new instance of the class.
///
- /// The techniques.
- internal Shader(
- IEnumerable<(string technique, IEnumerable<(Type, ComObject, ShaderSignature)> passes)> techniques)
+ /// The shader groups.
+ internal Shader(IEnumerable<(string name, IEnumerable<(Type, ComObject, ShaderSignature, ShaderReflection)>)>
+ groups)
{
- _techniques = new Dictionary(StringComparer.InvariantCultureIgnoreCase);
- foreach ((string technique, IEnumerable<(Type, ComObject, ShaderSignature)> passes) in techniques)
+ _groups = new Dictionary(StringComparer.InvariantCultureIgnoreCase);
+ foreach ((string name,
+ IEnumerable<(Type, ComObject, ShaderSignature, ShaderReflection)> entries) in groups)
{
- _techniques.Add(technique, new Technique(passes));
+ _groups.Add(name, new Group(entries));
}
}
///
- /// Gets all technique names from this shader instance.
+ /// Gets all group names from this shader instance.
///
///
- /// An array of technique names.
+ /// An array of group names.
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public string[] GetTechniqueNames()
+ public string[] GetGroupNames()
{
- return _techniques.Keys.ToArray();
+ return _groups.Keys.ToArray();
}
///
- /// Attempts to get a from the given .
+ /// Attempts to get a from the given .
///
- /// The technique name.
- /// [out] The technique.
+ /// The group name.
+ /// [out] The .
///
/// True if it succeeds, false if it fails.
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public bool TryGetTechnique(string name, out Technique technique)
+ public bool TryGetGroup(string name, out Group group)
{
- return _techniques.TryGetValue(name, out technique);
+ return _groups.TryGetValue(name, out group);
}
///
- /// Attempts to get a from the given .
+ /// Attempts to get a from the given .
///
- /// The technique name.
+ /// The group name.
///
- /// The .
+ /// The .
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public Technique GetTechnique(string name)
+ public Group GetGroup(string name)
{
- return _techniques[name];
+ return _groups[name];
}
///
- /// A technique. This class cannot be inherited.
+ /// A shader group collection. This class cannot be inherited.
///
- public sealed class Technique
+ public sealed class Group
{
- private readonly Dictionary _passes;
+ private readonly
+ Dictionary _entries;
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class.
///
- /// The passes.
- internal Technique(IEnumerable<(Type type, ComObject comObject, ShaderSignature signature)> passes)
+ /// The entries.
+ internal Group(IEnumerable<(Type, ComObject, ShaderSignature, ShaderReflection)> entries)
{
- _passes = new Dictionary();
- foreach ((Type type, ComObject comObject, ShaderSignature signature) in passes)
+ _entries = new Dictionary();
+ foreach ((Type type, ComObject comObject, ShaderSignature signature,
+ ShaderReflection reflection) in entries)
{
- _passes.Add(type, (comObject, signature));
+ _entries.Add(type, (comObject, signature, reflection));
}
}
///
- /// Implicit converts the given Shader to a .
+ /// Gets a .
///
- /// The technique.
///
/// The .
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static implicit operator VertexShader(Technique technique)
+ public VertexShader GetVertexShader()
{
- return technique.GetVertexShader();
+ return (VertexShader)_entries[Type.VertexShader].shader;
}
///
- /// Implicit converts the given Shader to a .
+ /// Gets a .
///
- /// The technique.
///
/// The .
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static implicit operator PixelShader(Technique technique)
+ public PixelShader GetPixelShader()
{
- return technique.GetPixelShader();
+ return (PixelShader)_entries[Type.PixelShader].shader;
}
///
- /// Implicit converts the given Shader to a .
+ /// Gets a .
///
- /// The technique.
///
/// The .
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static implicit operator DomainShader(Technique technique)
+ public DomainShader GetDomainShader()
{
- return technique.GetDomainShader();
+ return (DomainShader)_entries[Type.DomainShader].shader;
}
///
- /// Implicit converts the given Shader to a .
+ /// Gets a .
///
- /// The technique.
///
/// The .
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static implicit operator GeometryShader(Technique technique)
+ public GeometryShader GetGeometryShader()
{
- return technique.GetGeometryShader();
+ return (GeometryShader)_entries[Type.GeometryShader].shader;
}
///
- /// Implicit converts the given Shader to a .
+ /// Gets a .
///
- /// The technique.
///
/// The .
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static implicit operator HullShader(Technique technique)
+ public HullShader GetHullShader()
{
- return technique.GetHullShader();
+ return (HullShader)_entries[Type.HullShader].shader;
}
///
- /// Implicit converts the given Shader to a .
+ /// Gets a .
///
- /// The technique.
///
/// The .
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static implicit operator ComputeShader(Technique technique)
+ public ComputeShader GetComputeShader()
{
- return technique.GetComputeShader();
+ return (ComputeShader)_entries[Type.ComputeShader].shader;
}
///
- /// Gets a .
+ /// Gets the .
///
+ /// The type.
///
- /// The .
+ /// The .
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public VertexShader GetVertexShader()
+ public ShaderSignature GetShaderSignature(Type type)
{
- return (VertexShader)_passes[Type.VertexShader].shader;
+ return _entries[type].signature;
}
///
- /// Gets a .
+ /// Gets the .
///
+ /// The type.
///
- /// The .
+ /// The .
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public PixelShader GetPixelShader()
+ public ShaderReflection GetShaderReflection(Type type)
{
- return (PixelShader)_passes[Type.PixelShader].shader;
+ return _entries[type].reflection;
}
///
- /// Gets a .
+ /// Creates input layout for the specified .
///
+ /// The graphics device.
+ /// The type.
///
- /// The .
+ /// The new input layout.
///
+ /// Thrown when one or more required arguments are null.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public DomainShader GetDomainShader()
+ public InputLayout CreateInputLayout(IGraphicsDevice graphicsDevice, Type type)
{
- return (DomainShader)_passes[Type.DomainShader].shader;
+ return new InputLayout(
+ (graphicsDevice ?? throw new ArgumentNullException(nameof(graphicsDevice))).Device,
+ GetShaderSignature(type),
+ CreateInputElements(type));
}
///
- /// Gets a .
+ /// Creates input elements for the specified .
///
+ /// The type.
///
- /// The .
+ /// A new array of input element.
+ ///
+ /// Thrown when one or more arguments are outside the required range.
+ public InputElement[] CreateInputElements(Type type)
+ {
+ ShaderReflection shaderReflection = GetShaderReflection(type);
+
+ InputElement[] elements = new InputElement[shaderReflection.Description.InputParameters];
+ for (int i = 0; i < shaderReflection.Description.InputParameters; i++)
+ {
+ ShaderParameterDescription description = shaderReflection.GetInputParameterDescription(i);
+
+ Format format = Math2.CountOnes((int)description.UsageMask) switch
+ {
+ // ReSharper disable once SwitchExpressionHandlesSomeKnownEnumValuesWithExceptionInDefault
+ 1 => description.ComponentType switch
+ {
+ RegisterComponentType.UInt32 => Format.R32_UInt,
+ RegisterComponentType.SInt32 => Format.R32_SInt,
+ RegisterComponentType.Float32 => Format.R32_Float,
+ _ => throw new ArgumentOutOfRangeException(nameof(description.ComponentType))
+ },
+
+ // ReSharper disable once SwitchExpressionHandlesSomeKnownEnumValuesWithExceptionInDefault
+ 2 => description.ComponentType switch
+ {
+ RegisterComponentType.UInt32 => Format.R32G32_UInt,
+ RegisterComponentType.SInt32 => Format.R32G32_SInt,
+ RegisterComponentType.Float32 => Format.R32G32_Float,
+ _ => throw new ArgumentOutOfRangeException(nameof(description.ComponentType))
+ },
+
+ // ReSharper disable once SwitchExpressionHandlesSomeKnownEnumValuesWithExceptionInDefault
+ 3 => description.ComponentType switch
+ {
+ RegisterComponentType.UInt32 => Format.R32G32B32_UInt,
+ RegisterComponentType.SInt32 => Format.R32G32B32_SInt,
+ RegisterComponentType.Float32 => Format.R32G32B32_Float,
+ _ => throw new ArgumentOutOfRangeException(nameof(description.ComponentType))
+ },
+
+ // ReSharper disable once SwitchExpressionHandlesSomeKnownEnumValuesWithExceptionInDefault
+ 4 => description.ComponentType switch
+ {
+ RegisterComponentType.UInt32 => Format.R32G32B32A32_UInt,
+ RegisterComponentType.SInt32 => Format.R32G32B32A32_SInt,
+ RegisterComponentType.Float32 => Format.R32G32B32A32_Float,
+ _ => throw new ArgumentOutOfRangeException(nameof(description.ComponentType))
+ },
+ _ => throw new ArgumentOutOfRangeException(nameof(description.UsageMask))
+ };
+
+ elements[i] = new InputElement(
+ description.SemanticName, description.SemanticIndex, format,
+ InputElement.AppendAligned, 0, InputClassification.PerVertexData, 0);
+ }
+
+ return elements;
+ }
+
+ ///
+ /// Implicit converts the given Shader to a .
+ ///
+ /// The .
+ ///
+ /// The .
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public GeometryShader GetGeometryShader()
+ public static implicit operator VertexShader(Group group)
{
- return (GeometryShader)_passes[Type.GeometryShader].shader;
+ return group.GetVertexShader();
}
///
- /// Gets a .
+ /// Implicit converts the given Shader to a .
///
+ /// The .
///
- /// The .
+ /// The .
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public HullShader GetHullShader()
+ public static implicit operator PixelShader(Group group)
{
- return (HullShader)_passes[Type.HullShader].shader;
+ return group.GetPixelShader();
}
///
- /// Gets a .
+ /// Implicit converts the given Shader to a .
///
+ /// The .
///
- /// The .
+ /// The .
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public ComputeShader GetComputeShader()
+ public static implicit operator DomainShader(Group group)
{
- return (ComputeShader)_passes[Type.ComputeShader].shader;
+ return group.GetDomainShader();
}
///
- /// Gets the .
+ /// Implicit converts the given Shader to a .
///
- /// The type.
+ /// The .
///
- /// The .
+ /// The .
///
- public ShaderSignature GetShaderSignature(Type type)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator GeometryShader(Group group)
{
- return _passes[type].signature;
+ return group.GetGeometryShader();
+ }
+
+ ///
+ /// Implicit converts the given Shader to a .
+ ///
+ /// The .
+ ///
+ /// The .
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator HullShader(Group group)
+ {
+ return group.GetHullShader();
+ }
+
+ ///
+ /// Implicit converts the given Shader to a .
+ ///
+ /// The .
+ ///
+ /// The .
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator ComputeShader(Group group)
+ {
+ return group.GetComputeShader();
}
#region IDisposable Support
@@ -319,21 +421,22 @@ private void Dispose(bool disposing)
{
if (!_disposed)
{
- foreach (KeyValuePair keyValuePair in _passes)
- {
- keyValuePair.Value.shader.Dispose();
- keyValuePair.Value.signature.Dispose();
- }
if (disposing)
{
- _passes.Clear();
+ foreach (var (shader, signature, reflection) in _entries.Values)
+ {
+ reflection.Dispose();
+ signature.Dispose();
+ shader.Dispose();
+ }
+ _entries.Clear();
}
_disposed = true;
}
}
///
- ~Technique()
+ ~Group()
{
Dispose(false);
}
@@ -358,13 +461,13 @@ private void Dispose(bool disposing)
{
if (!_disposed)
{
- foreach (KeyValuePair keyValuePair in _techniques)
- {
- keyValuePair.Value.Dispose();
- }
if (disposing)
{
- _techniques.Clear();
+ foreach (Group group in _groups.Values)
+ {
+ group.Dispose();
+ }
+ _groups.Clear();
}
_disposed = true;
}
diff --git a/src/Exomia.Framework/Graphics/Shader/ShaderFileLoader.cs b/src/Exomia.Framework/Graphics/Shader/ShaderFileLoader.cs
index f7af2147..5aab1a52 100644
--- a/src/Exomia.Framework/Graphics/Shader/ShaderFileLoader.cs
+++ b/src/Exomia.Framework/Graphics/Shader/ShaderFileLoader.cs
@@ -29,8 +29,8 @@ static class ShaderFileLoader
"^\\s*\\**\\s*$",
RegexOptions.Compiled | RegexOptions.Singleline);
- private static readonly Regex s_techniqueRegex = new Regex(
- "^\\s*\\*\\s*technique\\s*(.*)$",
+ private static readonly Regex s_groupRegex = new Regex(
+ "^\\s*\\*\\s*group\\s*(.*)$",
RegexOptions.Compiled | RegexOptions.Singleline);
private static readonly Regex s_shaderInfoRegex = new Regex(
@@ -45,10 +45,10 @@ static class ShaderFileLoader
return null;
}
- IList techniques = new List(1);
+ IList groups = new List(1);
- Technique? currentTechnique = null;
- string? line;
+ Group? currentGroup = null;
+ string? line;
while ((line = sr.ReadLine()?.Trim()) != null)
{
if (SHADER_DEFINITION_END.Equals(line, StringComparison.InvariantCultureIgnoreCase))
@@ -58,10 +58,10 @@ static class ShaderFileLoader
if (!s_emptyLineRegex.IsMatch(line))
{
- Match techniqueMatch = s_techniqueRegex.Match(line);
- if (techniqueMatch.Success)
+ Match groupMatch = s_groupRegex.Match(line);
+ if (groupMatch.Success)
{
- techniques.Add(currentTechnique = new Technique(techniqueMatch.Groups[1].Value));
+ groups.Add(currentGroup = new Group(groupMatch.Groups[1].Value));
continue;
}
@@ -71,9 +71,9 @@ static class ShaderFileLoader
if (!Enum.TryParse(shaderInfoMatch.Groups[4].Value, out ShaderFlags flags))
{
throw new InvalidDataException(
- $"pass shader flags '{shaderInfoMatch.Groups[4].Value}' one or more flags are invalid or unsupported.");
+ $"shader flags '{shaderInfoMatch.Groups[4].Value}' one or more flags are invalid or unsupported.");
}
- currentTechnique?.Add(
+ currentGroup?.Add(
new ShaderInfo(
shaderInfoMatch.Groups[1].Value,
shaderInfoMatch.Groups[2].Value,
@@ -86,7 +86,7 @@ static class ShaderFileLoader
string shaderSource = sr.ReadToEnd();
return new Shader(
- techniques.Select(
+ groups.Select(
t =>
{
return (t.Name,
@@ -103,24 +103,30 @@ static class ShaderFileLoader
{
"vs" => (Shader.Type.VertexShader,
(ComObject)new VertexShader(graphicsDevice.Device, cr),
- ShaderSignature.GetInputSignature(cr)),
+ ShaderSignature.GetInputSignature(cr),
+ new ShaderReflection(cr)),
"ps" => (Shader.Type.PixelShader,
(ComObject)new PixelShader(graphicsDevice.Device, cr),
- ShaderSignature.GetInputSignature(cr)),
+ ShaderSignature.GetInputSignature(cr),
+ new ShaderReflection(cr)),
"ds" => (Shader.Type.DomainShader,
(ComObject)new DomainShader(graphicsDevice.Device, cr),
- ShaderSignature.GetInputSignature(cr)),
+ ShaderSignature.GetInputSignature(cr),
+ new ShaderReflection(cr)),
"gs" => (Shader.Type.GeometryShader,
(ComObject)new GeometryShader(graphicsDevice.Device, cr),
- ShaderSignature.GetInputSignature(cr)),
+ ShaderSignature.GetInputSignature(cr),
+ new ShaderReflection(cr)),
"hs" => (Shader.Type.HullShader,
(ComObject)new HullShader(graphicsDevice.Device, cr),
- ShaderSignature.GetInputSignature(cr)),
+ ShaderSignature.GetInputSignature(cr),
+ new ShaderReflection(cr)),
"cs" => (Shader.Type.ComputeShader,
(ComObject)new ComputeShader(graphicsDevice.Device, cr),
- ShaderSignature.GetInputSignature(cr)),
+ ShaderSignature.GetInputSignature(cr),
+ new ShaderReflection(cr)),
_ => throw new InvalidDataException(
- $"pass shader type '{s.Type}' doesn't exists or is unsupported.")
+ $"shader type '{s.Type}' doesn't exists or is unsupported.")
};
})
);
@@ -128,9 +134,9 @@ static class ShaderFileLoader
}
///
- /// A technique. This class cannot be inherited.
+ /// A group. This class cannot be inherited.
///
- private sealed class Technique
+ private sealed class Group
{
///
/// Gets the name.
@@ -149,10 +155,10 @@ private sealed class Technique
public IList ShaderInfos { get; }
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class.
///
/// The name.
- public Technique(string name)
+ public Group(string name)
{
Name = name;
ShaderInfos = new List(2);
diff --git a/src/Exomia.Framework/Graphics/SpriteBatch.Arc.cs b/src/Exomia.Framework/Graphics/SpriteBatch.Arc.cs
new file mode 100644
index 00000000..3933d096
--- /dev/null
+++ b/src/Exomia.Framework/Graphics/SpriteBatch.Arc.cs
@@ -0,0 +1,119 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using System;
+using System.Runtime.CompilerServices;
+using Exomia.Framework.Mathematics;
+using SharpDX;
+
+namespace Exomia.Framework.Graphics
+{
+ public sealed partial class SpriteBatch
+ {
+ ///
+ /// Draws a circle.
+ ///
+ /// The center.
+ /// The radius.
+ /// The color.
+ /// The width of the line.
+ /// The opacity.
+ /// The segments.
+ /// The depth of the layer.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void DrawCircle(in Vector2 center,
+ float radius,
+ in Color color,
+ float lineWidth,
+ float opacity,
+ int segments,
+ float layerDepth)
+ {
+ DrawArc(new Arc2(center, radius), color, lineWidth, opacity, segments, layerDepth);
+ }
+
+ ///
+ /// Draws a circle.
+ ///
+ /// The circle.
+ /// The color.
+ /// The width of the line.
+ /// The opacity.
+ /// The segments.
+ /// The depth of the layer.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void DrawCircle(in Circle2 circle,
+ in Color color,
+ float lineWidth,
+ float opacity,
+ int segments,
+ float layerDepth)
+ {
+ DrawArc(new Arc2(circle.X, circle.Y, circle.Radius), color, lineWidth, opacity, segments, layerDepth);
+ }
+
+ ///
+ /// Draws a circle.
+ ///
+ /// The center.
+ /// The radius.
+ /// The start.
+ /// The end.
+ /// The color.
+ /// The width of the line.
+ /// The opacity.
+ /// The segments.
+ /// The depth of the layer.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void DrawArc(in Vector2 center,
+ float radius,
+ float start,
+ float end,
+ in Color color,
+ float lineWidth,
+ float opacity,
+ int segments,
+ float layerDepth)
+ {
+ DrawArc(new Arc2(center, radius, start, end), in color, lineWidth, opacity, segments, layerDepth);
+ }
+
+ ///
+ /// Draws a circle.
+ ///
+ /// The arc.
+ /// The color.
+ /// The width of the line.
+ /// The opacity.
+ /// The segments.
+ /// The depth of the layer.
+ public void DrawArc(in Arc2 arc,
+ in Color color,
+ float lineWidth,
+ float opacity,
+ int segments,
+ float layerDepth)
+ {
+ Vector2[] vertex = new Vector2[segments];
+
+ float increment = (arc.End - arc.Start) / segments;
+ float theta = arc.Start;
+
+ for (int i = 0; i < segments; i++)
+ {
+ vertex[i].X = arc.X + (arc.Radius * (float)Math.Cos(theta));
+ vertex[i].Y = arc.Y + (arc.Radius * (float)Math.Sin(theta));
+ theta += increment;
+ }
+
+ DrawPolygon(vertex, color, lineWidth, opacity, layerDepth);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Graphics/SpriteBatch.Line.cs b/src/Exomia.Framework/Graphics/SpriteBatch.Line.cs
new file mode 100644
index 00000000..a7e1128a
--- /dev/null
+++ b/src/Exomia.Framework/Graphics/SpriteBatch.Line.cs
@@ -0,0 +1,106 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using System;
+using System.Runtime.CompilerServices;
+using Exomia.Framework.Mathematics;
+using SharpDX;
+
+namespace Exomia.Framework.Graphics
+{
+ public sealed partial class SpriteBatch
+ {
+ ///
+ /// Draw line.
+ ///
+ /// The first point.
+ /// The second point.
+ /// The color.
+ /// The width of the line.
+ /// The opacity.
+ /// The depth of the layer.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void DrawLine(in Vector2 point1,
+ in Vector2 point2,
+ in Color color,
+ float lineWidth,
+ float opacity,
+ float layerDepth)
+ {
+ DrawLine(point1, point2, color, lineWidth, opacity, 1.0f, layerDepth);
+ }
+
+ ///
+ /// Draw line.
+ ///
+ /// The line.
+ /// The color.
+ /// The width of the line.
+ /// The opacity.
+ /// The depth of the layer.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void DrawLine(in Line2 line,
+ in Color color,
+ float lineWidth,
+ float opacity,
+ float layerDepth)
+ {
+ DrawLine(in line, color, lineWidth, opacity, 1.0f, layerDepth);
+ }
+
+ ///
+ /// Draw line.
+ ///
+ /// The first point.
+ /// The second point.
+ /// The color.
+ /// The width of the line.
+ /// The opacity.
+ /// The length factor.
+ /// The depth of the layer.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void DrawLine(in Vector2 point1,
+ in Vector2 point2,
+ in Color color,
+ float lineWidth,
+ float opacity,
+ float lengthFactor,
+ float layerDepth)
+ {
+ DrawLine(new Line2(in point1, in point2), color, lineWidth, opacity, lengthFactor, layerDepth);
+ }
+
+ ///
+ /// Draw line.
+ ///
+ /// The line.
+ /// The color.
+ /// The width of the line.
+ /// The opacity.
+ /// The length factor.
+ /// The depth of the layer.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void DrawLine(in Line2 line,
+ in Color color,
+ float lineWidth,
+ float opacity,
+ float lengthFactor,
+ float layerDepth)
+ {
+ float dx = line.X2 - line.X1;
+ float dy = line.Y2 - line.Y1;
+ DrawSprite(
+ _whiteTexture, new RectangleF(
+ line.X1, line.Y1, (float)Math.Sqrt((dx * dx) + (dy * dy)) * lengthFactor, lineWidth), false,
+ s_nullRectangle, color, (float)Math.Atan2(dy, dx),
+ s_vector2Zero, opacity, TextureEffects.None, layerDepth);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Graphics/SpriteBatch.Polygon.cs b/src/Exomia.Framework/Graphics/SpriteBatch.Polygon.cs
new file mode 100644
index 00000000..48ce9c1b
--- /dev/null
+++ b/src/Exomia.Framework/Graphics/SpriteBatch.Polygon.cs
@@ -0,0 +1,38 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using SharpDX;
+
+namespace Exomia.Framework.Graphics
+{
+ public sealed partial class SpriteBatch
+ {
+ ///
+ /// Draw polygon.
+ ///
+ /// The vertex.
+ /// The color.
+ /// The width of the line.
+ /// The opacity.
+ /// The depth of the layer.
+ public void DrawPolygon(Vector2[] vertex, in Color color, float lineWidth, float opacity, float layerDepth)
+ {
+ if (vertex.Length > 1)
+ {
+ int l = vertex.Length - 1;
+ for (int i = 0; i < l; i++)
+ {
+ DrawLine(vertex[i], vertex[i + 1], color, lineWidth, opacity, layerDepth);
+ }
+ DrawLine(vertex[l], vertex[0], color, lineWidth, opacity, layerDepth);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Graphics/SpriteBatch.Rectangle.cs b/src/Exomia.Framework/Graphics/SpriteBatch.Rectangle.cs
new file mode 100644
index 00000000..f3c6a70e
--- /dev/null
+++ b/src/Exomia.Framework/Graphics/SpriteBatch.Rectangle.cs
@@ -0,0 +1,157 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using System;
+using System.Runtime.CompilerServices;
+using SharpDX;
+
+namespace Exomia.Framework.Graphics
+{
+ public sealed partial class SpriteBatch
+ {
+ ///
+ /// Draw rectangle.
+ ///
+ /// The destination rectangle.
+ /// The color.
+ /// The width of the line.
+ /// The rotation.
+ /// The opacity.
+ /// The depth of the layer.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void DrawRectangle(in RectangleF destinationRectangle,
+ in Color color,
+ float lineWidth,
+ float rotation,
+ float opacity,
+ float layerDepth)
+ {
+ DrawRectangle(destinationRectangle, color, lineWidth, rotation, s_vector2Zero, opacity, layerDepth);
+ }
+
+ ///
+ /// Draw rectangle.
+ ///
+ /// The destination rectangle.
+ /// The color.
+ /// The width of the line.
+ /// The rotation.
+ /// The origin.
+ /// The opacity.
+ /// The depth of the layer.
+ public void DrawRectangle(in RectangleF destinationRectangle,
+ in Color color,
+ float lineWidth,
+ float rotation,
+ in Vector2 origin,
+ float opacity,
+ float layerDepth)
+ {
+ Vector2[] vertex;
+
+ // ReSharper disable once CompareOfFloatsByEqualityOperator
+ if (rotation == 0.0f)
+ {
+ vertex = new[]
+ {
+ destinationRectangle.TopLeft, destinationRectangle.TopRight, destinationRectangle.BottomRight,
+ destinationRectangle.BottomLeft
+ };
+ }
+ else
+ {
+ vertex = new Vector2[4];
+
+ Vector2 o = origin;
+
+ // ReSharper disable once CompareOfFloatsByEqualityOperator
+ if (destinationRectangle.Width != 0f)
+ {
+ o.X /= destinationRectangle.Width;
+ }
+
+ // ReSharper disable once CompareOfFloatsByEqualityOperator
+ if (destinationRectangle.Height != 0f)
+ {
+ o.Y /= destinationRectangle.Height;
+ }
+
+ float cos = (float)Math.Cos(rotation);
+ float sin = (float)Math.Sin(rotation);
+ for (int j = 0; j < VERTICES_PER_SPRITE; j++)
+ {
+ Vector2 corner = s_cornerOffsets[j];
+ float posX = (corner.X - o.X) * destinationRectangle.Width;
+ float posY = (corner.Y - o.Y) * destinationRectangle.Height;
+
+ vertex[j] = new Vector2(
+ (destinationRectangle.X + (posX * cos)) - (posY * sin),
+ destinationRectangle.Y + (posX * sin) + (posY * cos));
+ }
+ }
+
+ DrawPolygon(vertex, color, lineWidth, opacity, layerDepth);
+ }
+
+ ///
+ /// Draw fill rectangle.
+ ///
+ /// The destination rectangle.
+ /// The color.
+ /// The depth of the layer.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void DrawFillRectangle(in RectangleF destinationRectangle, in Color color, float layerDepth)
+ {
+ DrawSprite(
+ _whiteTexture, destinationRectangle, false, s_nullRectangle,
+ color, 0.0f, s_vector2Zero, 1.0f, TextureEffects.None, layerDepth);
+ }
+
+ ///
+ /// Draw fill rectangle.
+ ///
+ /// The destination rectangle.
+ /// The color.
+ /// The opacity.
+ /// The depth of the layer.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void DrawFillRectangle(in RectangleF destinationRectangle,
+ in Color color,
+ float opacity,
+ float layerDepth)
+ {
+ DrawSprite(
+ _whiteTexture, destinationRectangle, false, s_nullRectangle,
+ color, 0.0f, s_vector2Zero, opacity, TextureEffects.None, layerDepth);
+ }
+
+ ///
+ /// Draw fill rectangle.
+ ///
+ /// The destination rectangle.
+ /// The color.
+ /// The rotation.
+ /// The origin.
+ /// The opacity.
+ /// The depth of the layer.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void DrawFillRectangle(in RectangleF destinationRectangle,
+ in Color color,
+ float rotation,
+ in Vector2 origin,
+ float opacity,
+ float layerDepth)
+ {
+ DrawSprite(
+ _whiteTexture, destinationRectangle, false, s_nullRectangle,
+ color, rotation, origin, opacity, TextureEffects.None, layerDepth);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Graphics/SpriteBatch.SpriteFont.cs b/src/Exomia.Framework/Graphics/SpriteBatch.SpriteFont.cs
new file mode 100644
index 00000000..b407a234
--- /dev/null
+++ b/src/Exomia.Framework/Graphics/SpriteBatch.SpriteFont.cs
@@ -0,0 +1,229 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using System.Runtime.CompilerServices;
+using SharpDX;
+
+#if NETSTANDARD2_1
+using System;
+
+#endif
+
+namespace Exomia.Framework.Graphics
+{
+ public sealed partial class SpriteBatch
+ {
+ ///
+ /// Draw text.
+ ///
+ /// The font.
+ /// The text.
+ /// The position.
+ /// The color.
+ /// The depth of the layer.
+#if NETSTANDARD2_1
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void DrawText(SpriteFont font,
+ ReadOnlySpan text,
+ in Vector2 position,
+ in Color color,
+ float layerDepth = 1.0f)
+#else
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void DrawText(SpriteFont font, string text, in Vector2 position, in Color color, float layerDepth = 1.0f)
+#endif
+ {
+ font.Draw(DrawTextInternal, text, position, color, 0f, Vector2.Zero, 1.0f, TextureEffects.None, layerDepth);
+ }
+
+ ///
+ /// Draw text.
+ ///
+ /// The font.
+ /// The text.
+ /// The position.
+ /// The color.
+ /// The rotation.
+ /// The depth of the layer.
+#if NETSTANDARD2_1
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void DrawText(SpriteFont font,
+ ReadOnlySpan text,
+ in Vector2 position,
+ in Color color,
+ float rotation,
+ float layerDepth = 1.0f)
+#else
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void DrawText(SpriteFont font,
+ string text,
+ in Vector2 position,
+ in Color color,
+ float rotation,
+ float layerDepth = 1.0f)
+#endif
+ {
+ font.Draw(
+ DrawTextInternal, text, position, color, rotation, Vector2.Zero, 1.0f, TextureEffects.None, layerDepth);
+ }
+
+ ///
+ /// Draw text.
+ ///
+ /// The font.
+ /// The text.
+ /// The position.
+ /// The color.
+ /// The rotation.
+ /// The origin.
+ /// The opacity.
+ /// The effects.
+ /// The depth of the layer.
+#if NETSTANDARD2_1
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void DrawText(SpriteFont font,
+ ReadOnlySpan text,
+ in Vector2 position,
+ in Color color,
+ float rotation,
+ in Vector2 origin,
+ float opacity,
+ TextureEffects effects,
+ float layerDepth = 1.0f)
+#else
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void DrawText(SpriteFont font,
+ string text,
+ in Vector2 position,
+ in Color color,
+ float rotation,
+ in Vector2 origin,
+ float opacity,
+ TextureEffects effects,
+ float layerDepth = 1.0f)
+#endif
+ {
+ font.Draw(DrawTextInternal, text, position, color, rotation, origin, opacity, effects, layerDepth);
+ }
+
+ ///
+ /// Draw text.
+ ///
+ /// The font.
+ /// The text.
+ /// The start.
+ /// The end.
+ /// The position.
+ /// The color.
+ /// The rotation.
+ /// The origin.
+ /// The opacity.
+ /// The effects.
+ /// The depth of the layer.
+#if NETSTANDARD2_1
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void DrawText(SpriteFont font,
+ ReadOnlySpan text,
+ int start,
+ int end,
+ in Vector2 position,
+ in Color color,
+ float rotation,
+ in Vector2 origin,
+ float opacity,
+ TextureEffects effects,
+ float layerDepth = 1.0f)
+#else
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void DrawText(SpriteFont font,
+ string text,
+ int start,
+ int end,
+ in Vector2 position,
+ in Color color,
+ float rotation,
+ in Vector2 origin,
+ float opacity,
+ TextureEffects effects,
+ float layerDepth = 1.0f)
+#endif
+ {
+ font.Draw(
+ DrawTextInternal, text, start, end, position, color, rotation, origin, opacity, effects, layerDepth);
+ }
+
+ ///
+ /// Draw text.
+ ///
+ /// The font.
+ /// The text.
+ /// The start.
+ /// The end.
+ /// The position.
+ /// The dimension.
+ /// The color.
+ /// The rotation.
+ /// The origin.
+ /// The opacity.
+ /// The effects.
+ /// The depth of the layer.
+#if NETSTANDARD2_1
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void DrawText(SpriteFont font,
+ ReadOnlySpan text,
+ int start,
+ int end,
+ in Vector2 position,
+ in Size2F dimension,
+ in Color color,
+ float rotation,
+ in Vector2 origin,
+ float opacity,
+ TextureEffects effects,
+ float layerDepth = 1.0f)
+#else
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void DrawText(SpriteFont font,
+ string text,
+ int start,
+ int end,
+ in Vector2 position,
+ in Size2F dimension,
+ in Color color,
+ float rotation,
+ in Vector2 origin,
+ float opacity,
+ TextureEffects effects,
+ float layerDepth = 1.0f)
+#endif
+ {
+ font.Draw(
+ DrawTextInternal, text, start, end, position, dimension, color, rotation, origin, opacity, effects,
+ layerDepth);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal void DrawTextInternal(Texture texture,
+ in Vector2 position,
+ in Rectangle? sourceRectangle,
+ in Color color,
+ float rotation,
+ in Vector2 origin,
+ float scale,
+ float opacity,
+ TextureEffects effects,
+ float layerDepth)
+ {
+ DrawSprite(
+ texture, new RectangleF(position.X, position.Y, scale, scale), true, sourceRectangle,
+ color, rotation, origin, opacity, effects, layerDepth);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Graphics/SpriteBatch.Structs.cs b/src/Exomia.Framework/Graphics/SpriteBatch.Structs.cs
new file mode 100644
index 00000000..43f4c94a
--- /dev/null
+++ b/src/Exomia.Framework/Graphics/SpriteBatch.Structs.cs
@@ -0,0 +1,81 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using System.Runtime.InteropServices;
+using SharpDX;
+using SharpDX.Direct3D11;
+
+namespace Exomia.Framework.Graphics
+{
+ public sealed partial class SpriteBatch
+ {
+ internal struct SpriteInfo
+ {
+ public RectangleF Source;
+ public RectangleF Destination;
+ public Vector2 Origin;
+ public float Rotation;
+ public float Depth;
+ public TextureEffects SpriteEffects;
+ public Color Color;
+ public float Opacity;
+ }
+
+ internal readonly struct TextureInfo
+ {
+ public readonly ShaderResourceView View;
+ public readonly int Width;
+ public readonly int Height;
+ public readonly long Ptr64;
+
+ public TextureInfo(ShaderResourceView view, int width, int height)
+ {
+ View = view;
+ Width = width;
+ Height = height;
+ Ptr64 = view.NativePointer.ToInt64();
+ }
+ }
+
+ [StructLayout(LayoutKind.Explicit, Size = VERTEX_STRIDE)]
+ private struct VertexPositionColorTexture
+ {
+ [FieldOffset(0)]
+ public float X;
+
+ [FieldOffset(4)]
+ public float Y;
+
+ [FieldOffset(8)]
+ public float Z;
+
+ [FieldOffset(12)]
+ public float W;
+
+ [FieldOffset(16)]
+ public float R;
+
+ [FieldOffset(20)]
+ public float G;
+
+ [FieldOffset(24)]
+ public float B;
+
+ [FieldOffset(28)]
+ public float A;
+
+ [FieldOffset(32)]
+ public float U;
+
+ [FieldOffset(36)]
+ public float V;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Graphics/SpriteBatch.Texture.cs b/src/Exomia.Framework/Graphics/SpriteBatch.Texture.cs
new file mode 100644
index 00000000..dcb506a7
--- /dev/null
+++ b/src/Exomia.Framework/Graphics/SpriteBatch.Texture.cs
@@ -0,0 +1,338 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Threading;
+using SharpDX;
+
+namespace Exomia.Framework.Graphics
+{
+ public sealed partial class SpriteBatch
+ {
+ ///
+ /// Draws a texture to the screen.
+ ///
+ /// The texture.
+ /// The position.
+ /// The color.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Draw(Texture texture, in Vector2 position, in Color color)
+ {
+ DrawSprite(
+ texture, new RectangleF(position.X, position.Y, 1f, 1f), true, s_nullRectangle,
+ color, 0f, s_vector2Zero, 1.0f, TextureEffects.None, 0f);
+ }
+
+ ///
+ /// Draws a texture to the screen.
+ ///
+ /// The texture.
+ /// The destination rectangle.
+ /// The color.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Draw(Texture texture, in RectangleF destinationRectangle, in Color color)
+ {
+ DrawSprite(
+ texture, destinationRectangle, false, s_nullRectangle,
+ color, 0f, s_vector2Zero, 1.0f, TextureEffects.None, 0f);
+ }
+
+ ///
+ /// Draws a texture to the screen.
+ ///
+ /// The texture.
+ /// The position.
+ /// The source rectangle.
+ /// The color.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Draw(Texture texture, in Vector2 position, in Rectangle? sourceRectangle, in Color color)
+ {
+ DrawSprite(
+ texture, new RectangleF(position.X, position.Y, 1f, 1f), true, sourceRectangle,
+ color, 0f, s_vector2Zero, 1.0f, TextureEffects.None, 0f);
+ }
+
+ ///
+ /// Draws a texture to the screen.
+ ///
+ /// The texture.
+ /// The destination rectangle.
+ /// The source rectangle.
+ /// The color.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Draw(Texture texture,
+ in RectangleF destinationRectangle,
+ in Rectangle? sourceRectangle,
+ in Color color)
+ {
+ DrawSprite(
+ texture, destinationRectangle, false, sourceRectangle,
+ color, 0f, s_vector2Zero, 1.0f, TextureEffects.None, 0f);
+ }
+
+ ///
+ /// Draws a texture to the screen.
+ ///
+ /// The texture.
+ /// The position.
+ /// The color.
+ /// The rotation.
+ /// The origin.
+ /// (Optional) The depth of the layer.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Draw(Texture texture,
+ in Vector2 position,
+ in Color color,
+ float rotation,
+ in Vector2 origin,
+ float layerDepth = 0f)
+ {
+ DrawSprite(
+ texture, new RectangleF(position.X, position.Y, 1f, 1f), true, s_nullRectangle,
+ color, rotation, origin, 1.0f, TextureEffects.None, layerDepth);
+ }
+
+ ///
+ /// Draws a texture to the screen.
+ ///
+ /// The texture.
+ /// The destination rectangle.
+ /// The color.
+ /// The rotation.
+ /// The origin.
+ /// The depth of the layer.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Draw(Texture texture,
+ in RectangleF destinationRectangle,
+ in Color color,
+ float rotation,
+ in Vector2 origin,
+ float layerDepth = 0f)
+ {
+ DrawSprite(
+ texture, destinationRectangle, false, s_nullRectangle,
+ color, rotation, origin, 1.0f, TextureEffects.None, layerDepth);
+ }
+
+ ///
+ /// Draws a texture to the screen.
+ ///
+ /// The texture.
+ /// The destination rectangle.
+ /// The source rectangle.
+ /// The color.
+ /// The rotation.
+ /// The origin.
+ /// The opacity.
+ /// The effects.
+ /// The depth of the layer.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Draw(Texture texture,
+ in RectangleF destinationRectangle,
+ in Rectangle? sourceRectangle,
+ in Color color,
+ float rotation,
+ in Vector2 origin,
+ float opacity,
+ TextureEffects effects,
+ float layerDepth)
+ {
+ DrawSprite(
+ texture, destinationRectangle, false, sourceRectangle,
+ color, rotation, origin, opacity, effects, layerDepth);
+ }
+
+ ///
+ /// Draws a texture to the screen.
+ ///
+ /// The texture.
+ /// The position.
+ /// The source rectangle.
+ /// The color.
+ /// The rotation.
+ /// The origin.
+ /// The scale.
+ /// The opacity.
+ /// The effects.
+ /// The depth of the layer.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Draw(Texture texture,
+ in Vector2 position,
+ in Rectangle? sourceRectangle,
+ in Color color,
+ float rotation,
+ in Vector2 origin,
+ float scale,
+ float opacity,
+ TextureEffects effects,
+ float layerDepth)
+ {
+ DrawSprite(
+ texture, new RectangleF(position.X, position.Y, scale, scale), true, sourceRectangle,
+ color, rotation, origin, opacity, effects, layerDepth);
+ }
+
+ ///
+ /// Draws a texture to the screen.
+ ///
+ /// The texture.
+ /// The position.
+ /// The source rectangle.
+ /// The color.
+ /// The rotation.
+ /// The origin.
+ /// The scale.
+ /// The opacity.
+ /// The effects.
+ /// The depth of the layer.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Draw(Texture texture,
+ in Vector2 position,
+ in Rectangle? sourceRectangle,
+ in Color color,
+ float rotation,
+ in Vector2 origin,
+ in Vector2 scale,
+ float opacity,
+ TextureEffects effects,
+ float layerDepth)
+ {
+ DrawSprite(
+ texture, new RectangleF(position.X, position.Y, scale.X, scale.Y), true, sourceRectangle,
+ color, rotation, origin, opacity, effects, layerDepth);
+ }
+
+ private unsafe void DrawSprite(Texture texture,
+ in RectangleF destination,
+ bool scaleDestination,
+ in Rectangle? sourceRectangle,
+ in Color color,
+ float rotation,
+ in Vector2 origin,
+ float opacity,
+ TextureEffects effects,
+ float depth)
+ {
+ if (!_isBeginCalled)
+ {
+ throw new InvalidOperationException("Begin must be called before draw");
+ }
+
+ if (texture.TexturePointer == IntPtr.Zero)
+ {
+ throw new ArgumentNullException(nameof(texture));
+ }
+
+ if (_spriteQueueCount >= _spriteQueue.Length)
+ {
+ bool lockTaken = false;
+ try
+ {
+ _spinLock.Enter(ref lockTaken);
+
+ int size = _spriteQueue.Length * 2;
+ _sortIndices = new int[size];
+ _sortedSprites = new SpriteInfo[size];
+ Array.Resize(ref _spriteQueue, size);
+ Array.Resize(ref _spriteTextures, size);
+ }
+ finally
+ {
+ if (lockTaken)
+ {
+ _spinLock.Exit(false);
+ }
+ }
+ }
+
+ if (!_textureInfos.TryGetValue(texture.TexturePointer, out TextureInfo textureInfo))
+ {
+ bool lockTaken = false;
+ try
+ {
+ _spinLock.Enter(ref lockTaken);
+ if (!_textureInfos.TryGetValue(texture.TexturePointer, out textureInfo))
+ {
+ textureInfo = new TextureInfo(texture.TextureView, texture.Width, texture.Height);
+ _textureInfos.Add(texture.TexturePointer, textureInfo);
+ }
+ }
+ finally
+ {
+ if (lockTaken)
+ {
+ _spinLock.Exit(false);
+ }
+ }
+ }
+
+ int spriteQueueCount = Interlocked.Increment(ref _spriteQueueCount) - 1;
+ fixed (SpriteInfo* spriteInfo = &_spriteQueue[spriteQueueCount])
+ {
+ float width;
+ float height;
+ if (sourceRectangle.HasValue)
+ {
+ Rectangle rectangle = sourceRectangle.Value;
+ spriteInfo->Source.X = rectangle.X;
+ spriteInfo->Source.Y = rectangle.Y;
+ width = rectangle.Width;
+ height = rectangle.Height;
+ }
+ else
+ {
+ spriteInfo->Source.X = 0;
+ spriteInfo->Source.Y = 0;
+ width = texture.Width;
+ height = texture.Height;
+ }
+
+ spriteInfo->Source.Width = width;
+ spriteInfo->Source.Height = height;
+
+ spriteInfo->Destination.X = destination.X;
+ spriteInfo->Destination.Y = destination.Y;
+
+ if (scaleDestination)
+ {
+ spriteInfo->Destination.Width = destination.Width * width;
+ spriteInfo->Destination.Height = destination.Height * height;
+ }
+ else
+ {
+ spriteInfo->Destination.Width = destination.Width;
+ spriteInfo->Destination.Height = destination.Height;
+ }
+
+ if (spriteInfo->Destination.Width < 0)
+ {
+ spriteInfo->Destination.X += spriteInfo->Destination.Width;
+ spriteInfo->Destination.Width = -spriteInfo->Destination.Width;
+ }
+
+ if (spriteInfo->Destination.Height < 0)
+ {
+ spriteInfo->Destination.Y += spriteInfo->Destination.Height;
+ spriteInfo->Destination.Height = -spriteInfo->Destination.Height;
+ }
+
+ spriteInfo->Origin = origin;
+ spriteInfo->Rotation = rotation;
+ spriteInfo->Depth = depth;
+ spriteInfo->SpriteEffects = effects;
+ spriteInfo->Color = color;
+ spriteInfo->Opacity = opacity;
+ }
+
+ _spriteTextures[spriteQueueCount] = textureInfo;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Graphics/SpriteBatch.cs b/src/Exomia.Framework/Graphics/SpriteBatch.cs
index 1b95f6cc..35fa7e99 100644
--- a/src/Exomia.Framework/Graphics/SpriteBatch.cs
+++ b/src/Exomia.Framework/Graphics/SpriteBatch.cs
@@ -14,26 +14,22 @@
using System.Diagnostics;
using System.IO;
using System.Reflection;
-using System.Runtime.InteropServices;
-using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using Exomia.Framework.Graphics.Buffers;
using Exomia.Framework.Graphics.Shader;
using Exomia.Framework.Graphics.SpriteSort;
using Exomia.Framework.Resources;
using SharpDX;
using SharpDX.Direct3D;
using SharpDX.Direct3D11;
-using SharpDX.DXGI;
-using Buffer = SharpDX.Direct3D11.Buffer;
-using MapFlags = SharpDX.Direct3D11.MapFlags;
namespace Exomia.Framework.Graphics
{
///
/// A sprite batch. This class cannot be inherited.
///
- public sealed class SpriteBatch : IDisposable
+ public sealed partial class SpriteBatch : IDisposable
{
private const int MAX_BATCH_SIZE = 1 << 13;
private const int INITIAL_QUEUE_SIZE = 1 << 7;
@@ -58,24 +54,29 @@ private static readonly Vector2[]
private readonly Dictionary _textureInfos =
new Dictionary(INITIAL_QUEUE_SIZE);
- private readonly VertexBufferBinding _vertexBufferBinding;
- private readonly InputLayout _vertexInputLayout;
+ private readonly InputLayout _vertexInputLayout;
- private readonly Buffer _vertexBuffer, _indexBuffer, _perFrameBuffer;
+ private readonly IndexBuffer _indexBuffer;
+ private readonly VertexBuffer _vertexBuffer;
+ private readonly ConstantBuffer _perFrameBuffer;
private readonly Shader.Shader _shader;
private readonly PixelShader _pixelShader;
private readonly VertexShader _vertexShader;
-
- private BlendState? _defaultBlendState, _blendState;
- private DepthStencilState? _defaultDepthStencilState, _depthStencilState;
-
- private RasterizerState? _defaultRasterizerState,
- _defaultRasterizerScissorEnabledState,
- _rasterizerState;
-
- private SamplerState? _defaultSamplerState, _samplerState;
- private bool _isBeginCalled, _isScissorEnabled;
+ private readonly Texture _whiteTexture;
+ private readonly bool _center;
+
+ private readonly BlendState _defaultBlendState;
+ private readonly DepthStencilState _defaultDepthStencilState;
+ private readonly RasterizerState _defaultRasterizerState;
+ private readonly RasterizerState _defaultRasterizerScissorEnabledState;
+ private readonly SamplerState _defaultSamplerState;
+ private BlendState? _blendState;
+ private DepthStencilState? _depthStencilState;
+ private RasterizerState? _rasterizerState;
+ private SamplerState? _samplerState;
+
+ private bool _isBeginCalled, _isScissorEnabled;
private Rectangle _scissorRectangle;
private SpriteSortMode _spriteSortMode;
private int[] _sortIndices;
@@ -117,16 +118,22 @@ static SpriteBatch()
///
/// Initializes a new instance of the class.
///
+ /// The graphics device.
+ /// (Optional) True to center the coordinate system in the viewport.
+ /// (Optional) The sort algorithm.
///
/// Thrown when one or more arguments have unsupported or
/// illegal values.
///
- /// Zero-based index of the device.
- /// (Optional) The sort algorithm.
- public SpriteBatch(IGraphicsDevice iDevice, SpriteSortAlgorithm sortAlgorithm = SpriteSortAlgorithm.MergeSort)
+ /// Thrown when a value was unexpectedly null.
+ public SpriteBatch(IGraphicsDevice graphicsDevice,
+ bool center = false,
+ SpriteSortAlgorithm sortAlgorithm = SpriteSortAlgorithm.MergeSort)
{
- _device = iDevice.Device;
- _context = iDevice.DeviceContext;
+ _device = graphicsDevice.Device;
+ _context = graphicsDevice.DeviceContext;
+
+ _center = center;
_spriteSort = sortAlgorithm switch
{
@@ -134,41 +141,33 @@ public SpriteBatch(IGraphicsDevice iDevice, SpriteSortAlgorithm sortAlgorithm =
_ => throw new ArgumentException($"invalid sort algorithm ({sortAlgorithm})", nameof(sortAlgorithm))
};
- InitializeStates(iDevice.Device);
- DefaultTextures.InitializeTextures(iDevice.Device);
+ _defaultBlendState = graphicsDevice.BlendStates.AlphaBlend;
+ _defaultSamplerState = graphicsDevice.SamplerStates.LinearWrap;
+ _defaultDepthStencilState = graphicsDevice.DepthStencilStates.None;
+ _defaultRasterizerState = graphicsDevice.RasterizerStates.CullBackDepthClipOff;
+ _defaultRasterizerScissorEnabledState = graphicsDevice.RasterizerStates.CullBackDepthClipOffScissorEnabled;
- _indexBuffer = Buffer.Create(
- _device, BindFlags.IndexBuffer, s_indices, 0, ResourceUsage.Immutable);
+ _whiteTexture = graphicsDevice.Textures.White;
+
+ _indexBuffer = IndexBuffer.Create(graphicsDevice, s_indices);
Assembly assembly = Assembly.GetExecutingAssembly();
- using (Stream stream = assembly.GetManifestResourceStream(
- $"{assembly.GetName().Name}.{Shaders.POSITION_COLOR_TEXTURE}"))
+ using (Stream stream =
+ assembly.GetManifestResourceStream($"{assembly.GetName().Name}.{Shaders.POSITION_COLOR_TEXTURE}") ??
+ throw new NullReferenceException($"{assembly.GetName().Name}.{Shaders.POSITION_COLOR_TEXTURE}"))
{
- Shader.Shader.Technique technique =
- (_shader = ShaderFileLoader.FromStream(iDevice, stream) ??
+ Shader.Shader.Group group =
+ (_shader = ShaderFileLoader.FromStream(graphicsDevice, stream) ??
throw new NullReferenceException(nameof(ShaderFileLoader.FromStream)))["DEFAULT"];
- _vertexShader = technique;
- _pixelShader = technique;
+ _vertexShader = group;
+ _pixelShader = group;
- _vertexInputLayout = new InputLayout(
- _device, technique.GetShaderSignature(Shader.Shader.Type.VertexShader),
- new[]
- {
- new InputElement(
- "SV_POSITION", 0, Format.R32G32B32A32_Float, InputElement.AppendAligned, 0),
- new InputElement("COLOR", 0, Format.R32G32B32A32_Float, InputElement.AppendAligned, 0),
- new InputElement("TEXCOORD", 0, Format.R32G32_Float, InputElement.AppendAligned, 0)
- });
+ _vertexInputLayout = group.CreateInputLayout(graphicsDevice, Shader.Shader.Type.VertexShader);
}
- _vertexBuffer = new Buffer(
- _device, VERTEX_STRIDE * MAX_VERTEX_COUNT, ResourceUsage.Dynamic, BindFlags.VertexBuffer,
- CpuAccessFlags.Write, ResourceOptionFlags.None, 0);
- _vertexBufferBinding = new VertexBufferBinding(_vertexBuffer, VERTEX_STRIDE, 0);
- _perFrameBuffer = new Buffer(
- _device, sizeof(float) * 4 * 4 * 1, ResourceUsage.Default, BindFlags.ConstantBuffer,
- CpuAccessFlags.None, ResourceOptionFlags.None, 0);
+ _vertexBuffer = VertexBuffer.Create(graphicsDevice, MAX_VERTEX_COUNT);
+ _perFrameBuffer = ConstantBuffer.Create(graphicsDevice);
_sortIndices = new int[MAX_BATCH_SIZE];
_sortedSprites = new SpriteInfo[MAX_BATCH_SIZE];
@@ -176,21 +175,13 @@ public SpriteBatch(IGraphicsDevice iDevice, SpriteSortAlgorithm sortAlgorithm =
_spriteQueue = new SpriteInfo[MAX_BATCH_SIZE];
_spriteTextures = new TextureInfo[MAX_BATCH_SIZE];
- iDevice.ResizeFinished += IDevice_onResizeFinished;
-
- Resize(iDevice.Viewport);
- }
+ graphicsDevice.ResizeFinished += GraphicsDeviceOnResizeFinished;
- ///
- /// Finalizes an instance of the class.
- ///
- ~SpriteBatch()
- {
- Dispose(false);
+ Resize(graphicsDevice.Viewport);
}
///
- /// Begins.
+ /// Begins a new batch.
///
/// Thrown when the requested operation is invalid.
/// (Optional) The sort mode.
@@ -230,7 +221,7 @@ public void Begin(SpriteSortMode sortMode = SpriteSortMode.Deferred
}
///
- /// Ends this object.
+ /// Ends the current batch.
///
/// Thrown when the requested operation is invalid.
public void End()
@@ -239,6 +230,7 @@ public void End()
{
throw new InvalidOperationException("Begin must be called before End");
}
+
if (_spriteQueueCount > 0)
{
PrepareForRendering();
@@ -277,105 +269,23 @@ public void Resize(float width, float height)
{
float xRatio = width > 0 ? 1f / width : 0f;
float yRatio = height > 0 ? -1f / height : 0f;
+
_projectionMatrix = new Matrix
{
M11 = xRatio * 2f,
M22 = yRatio * 2f,
M33 = 1f,
M44 = 1f,
- M41 = -1f,
- M42 = 1f
+ M41 = -(_center ? 0f : 1f),
+ M42 = _center ? 0f : 1f
};
}
- ///
- /// Updates the vertex from sprite information.
- ///
- /// [in,out] Information describing the sprite.
- /// [in,out] If non-null, the vpct pointer.
- /// The delta x coordinate.
- /// The delta y coordinate.
- private static unsafe void UpdateVertexFromSpriteInfo(ref SpriteInfo spriteInfo,
- VertexPositionColorTexture* vpctPtr,
- float deltaX,
- float deltaY)
+ private void GraphicsDeviceOnResizeFinished(ViewportF viewport)
{
- Vector2 origin = spriteInfo.Origin;
-
- // ReSharper disable once CompareOfFloatsByEqualityOperator
- if (spriteInfo.Source.Width != 0f)
- {
- origin.X /= spriteInfo.Source.Width;
- }
-
- // ReSharper disable once CompareOfFloatsByEqualityOperator
- if (spriteInfo.Source.Height != 0f)
- {
- origin.Y /= spriteInfo.Source.Height;
- }
-
- // ReSharper disable once CompareOfFloatsByEqualityOperator
- if (spriteInfo.Rotation == 0f)
- {
- for (int j = 0; j < VERTICES_PER_SPRITE; j++)
- {
- VertexPositionColorTexture* vertex = vpctPtr + j;
-
- Vector2 corner = s_cornerOffsets[j];
- float posX = (corner.X - origin.X) * spriteInfo.Destination.Width;
- float posY = (corner.Y - origin.Y) * spriteInfo.Destination.Height;
-
- vertex->X = spriteInfo.Destination.X + posX;
- vertex->Y = spriteInfo.Destination.Y + posY;
- vertex->Z = spriteInfo.Depth;
- vertex->W = 1.0f;
-
- vertex->R = spriteInfo.Color.R * spriteInfo.Opacity;
- vertex->G = spriteInfo.Color.G * spriteInfo.Opacity;
- vertex->B = spriteInfo.Color.B * spriteInfo.Opacity;
- vertex->A = spriteInfo.Color.A * spriteInfo.Opacity;
-
- corner = s_cornerOffsets[j ^ (int)spriteInfo.SpriteEffects];
- vertex->U = (spriteInfo.Source.X + (corner.X * spriteInfo.Source.Width)) * deltaX;
- vertex->V = (spriteInfo.Source.Y + (corner.Y * spriteInfo.Source.Height)) * deltaY;
- }
- }
- else
- {
- float cos = (float)Math.Cos(spriteInfo.Rotation);
- float sin = (float)Math.Sin(spriteInfo.Rotation);
- for (int j = 0; j < VERTICES_PER_SPRITE; j++)
- {
- VertexPositionColorTexture* vertex = vpctPtr + j;
-
- Vector2 corner = s_cornerOffsets[j];
- float posX = (corner.X - origin.X) * spriteInfo.Destination.Width;
- float posY = (corner.Y - origin.Y) * spriteInfo.Destination.Height;
-
- vertex->X = (spriteInfo.Destination.X + (posX * cos)) - (posY * sin);
- vertex->Y = spriteInfo.Destination.Y + (posX * sin) + (posY * cos);
- vertex->Z = spriteInfo.Depth;
- vertex->W = 1.0f;
-
- vertex->R = spriteInfo.Color.R * spriteInfo.Opacity;
- vertex->G = spriteInfo.Color.G * spriteInfo.Opacity;
- vertex->B = spriteInfo.Color.B * spriteInfo.Opacity;
- vertex->A = spriteInfo.Color.A * spriteInfo.Opacity;
-
- corner = s_cornerOffsets[j ^ (int)spriteInfo.SpriteEffects];
- vertex->U = (spriteInfo.Source.X + (corner.X * spriteInfo.Source.Width)) * deltaX;
- vertex->V = (spriteInfo.Source.Y + (corner.Y * spriteInfo.Source.Height)) * deltaY;
- }
- }
+ Resize(viewport);
}
- ///
- /// Draw batch per texture.
- ///
- /// [in,out] The texture.
- /// The sprites.
- /// The offset.
- /// Number of.
private unsafe void DrawBatchPerTexture(ref TextureInfo texture, SpriteInfo[] sprites, int offset, int count)
{
_context.PixelShader.SetShaderResource(0, texture.View);
@@ -389,60 +299,52 @@ private unsafe void DrawBatchPerTexture(ref TextureInfo texture, SpriteInfo[] sp
{
batchSize = MAX_BATCH_SIZE;
}
- lock (_device)
- {
- DataBox box = _context.MapSubresource(
- _vertexBuffer, 0, MapMode.WriteDiscard, MapFlags.None);
- VertexPositionColorTexture* vpctPtr = (VertexPositionColorTexture*)box.DataPointer;
- if (batchSize > BATCH_SEQUENTIAL_THRESHOLD)
- {
- int middle = batchSize >> 1;
- Parallel.Invoke(
- () =>
+ DataBox box = _context.MapSubresource(
+ _vertexBuffer, 0, MapMode.WriteDiscard, MapFlags.None);
+ VertexPositionColorTexture* vpctPtr = (VertexPositionColorTexture*)box.DataPointer;
+
+ if (batchSize > BATCH_SEQUENTIAL_THRESHOLD)
+ {
+ int middle = batchSize >> 1;
+ Parallel.Invoke(
+ () =>
+ {
+ for (int i = 0; i < middle; i++)
{
- for (int i = 0; i < middle; i++)
- {
- UpdateVertexFromSpriteInfo(
-
- // ReSharper disable once AccessToModifiedClosure
- ref sprites[i + offset], vpctPtr + (i << 2), deltaX, deltaY);
- }
- },
- () =>
+ UpdateVertexFromSpriteInfo(
+
+ // ReSharper disable once AccessToModifiedClosure
+ ref sprites[i + offset], vpctPtr + (i << 2), deltaX, deltaY);
+ }
+ },
+ () =>
+ {
+ for (int i = middle; i < batchSize; i++)
{
- for (int i = middle; i < batchSize; i++)
- {
- UpdateVertexFromSpriteInfo(
-
- // ReSharper disable once AccessToModifiedClosure
- ref sprites[i + offset], vpctPtr + (i << 2), deltaX, deltaY);
- }
- });
- }
- else
+ UpdateVertexFromSpriteInfo(
+
+ // ReSharper disable once AccessToModifiedClosure
+ ref sprites[i + offset], vpctPtr + (i << 2), deltaX, deltaY);
+ }
+ });
+ }
+ else
+ {
+ for (int i = 0; i < batchSize; i++)
{
- for (int i = 0; i < batchSize; i++)
- {
- UpdateVertexFromSpriteInfo(
- ref sprites[i + offset], vpctPtr + (i << 2), deltaX, deltaY);
- }
+ UpdateVertexFromSpriteInfo(
+ ref sprites[i + offset], vpctPtr + (i << 2), deltaX, deltaY);
}
- _context.UnmapSubresource(_vertexBuffer, 0);
- _context.DrawIndexed(INDICES_PER_SPRITE * batchSize, 0, 0);
}
+ _context.UnmapSubresource(_vertexBuffer, 0);
+ _context.DrawIndexed(INDICES_PER_SPRITE * batchSize, 0, 0);
+
offset += batchSize;
count -= batchSize;
}
}
- ///
- /// Flushes the batch.
- ///
- ///
- /// Thrown when an Invalid Enum Argument error
- /// condition occurs.
- ///
private void FlushBatch()
{
SpriteInfo[] spriteQueueForBatch;
@@ -510,121 +412,6 @@ private void FlushBatch()
_spriteQueueCount = 0;
}
- ///
- /// Device on resize finished.
- ///
- /// The viewport.
- private void IDevice_onResizeFinished(ViewportF viewport)
- {
- Resize(viewport);
- }
-
- ///
- /// Initializes the states.
- ///
- /// The device.
- private void InitializeStates(Device5 device)
- {
- _defaultSamplerState = new SamplerState(
- device,
- new SamplerStateDescription
- {
- AddressU = TextureAddressMode.Wrap,
- AddressV = TextureAddressMode.Wrap,
- AddressW = TextureAddressMode.Wrap,
- BorderColor = Color.White,
- ComparisonFunction = Comparison.Always,
- Filter = Filter.ComparisonMinMagMipLinear,
- MaximumAnisotropy = 16,
- MaximumLod = float.MaxValue,
- MinimumLod = 0,
- MipLodBias = 0.0f
- });
-
- _defaultBlendState = new BlendState(
- device,
- new BlendStateDescription
- {
- AlphaToCoverageEnable = false,
- IndependentBlendEnable = false,
- RenderTarget =
- {
- [0] = new RenderTargetBlendDescription
- {
- IsBlendEnabled = true,
- SourceBlend = BlendOption.One,
- DestinationBlend = BlendOption.InverseSourceAlpha,
- BlendOperation = BlendOperation.Add,
- SourceAlphaBlend = BlendOption.Zero,
- DestinationAlphaBlend = BlendOption.Zero,
- AlphaBlendOperation = BlendOperation.Add,
- RenderTargetWriteMask = ColorWriteMaskFlags.All
- }
- }
- }) { DebugName = "AlphaBlend" };
-
- _defaultDepthStencilState = new DepthStencilState(
- device,
- new DepthStencilStateDescription
- {
- IsDepthEnabled = false,
- DepthWriteMask = DepthWriteMask.All,
- DepthComparison = Comparison.LessEqual,
- IsStencilEnabled = false,
- StencilReadMask = 0xFF,
- StencilWriteMask = 0xFF,
- FrontFace = new DepthStencilOperationDescription
- {
- FailOperation = StencilOperation.Keep,
- DepthFailOperation = StencilOperation.Increment,
- PassOperation = StencilOperation.Keep,
- Comparison = Comparison.Always
- },
- BackFace = new DepthStencilOperationDescription
- {
- FailOperation = StencilOperation.Keep,
- DepthFailOperation = StencilOperation.Decrement,
- PassOperation = StencilOperation.Keep,
- Comparison = Comparison.Always
- }
- });
-
- _defaultRasterizerState = new RasterizerState(
- device,
- new RasterizerStateDescription
- {
- FillMode = FillMode.Solid,
- CullMode = CullMode.Back,
- IsFrontCounterClockwise = false,
- DepthBias = 0,
- DepthBiasClamp = 0,
- SlopeScaledDepthBias = 0,
- IsDepthClipEnabled = false,
- IsScissorEnabled = false,
- IsMultisampleEnabled = true,
- IsAntialiasedLineEnabled = true
- });
-
- _defaultRasterizerScissorEnabledState = new RasterizerState(
- device,
- new RasterizerStateDescription
- {
- FillMode = FillMode.Solid,
- CullMode = CullMode.Back,
- IsFrontCounterClockwise = false,
- DepthBias = 0,
- DepthBiasClamp = 0,
- SlopeScaledDepthBias = 0,
- IsDepthClipEnabled = false,
- IsScissorEnabled = true,
- IsMultisampleEnabled = true,
- IsAntialiasedLineEnabled = true
- });
- }
-
- ///
- /// Prepare for rendering.
- ///
private void PrepareForRendering()
{
_context.VertexShader.Set(_vertexShader);
@@ -648,920 +435,88 @@ private void PrepareForRendering()
_context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;
_context.InputAssembler.InputLayout = _vertexInputLayout;
- _context.VertexShader.SetConstantBuffer(0, _perFrameBuffer);
-
- _context.InputAssembler.SetIndexBuffer(_indexBuffer, Format.R16_UInt, 0);
- _context.InputAssembler.SetVertexBuffers(0, _vertexBufferBinding);
-
- Matrix worldViewProjection = _transformMatrix * _viewMatrix * _projectionMatrix;
- worldViewProjection.Transpose();
-
+ Matrix worldViewProjection = Matrix.Transpose(_transformMatrix * _viewMatrix * _projectionMatrix);
_context.UpdateSubresource(ref worldViewProjection, _perFrameBuffer);
- }
+ _context.VertexShader.SetConstantBuffer(0, _perFrameBuffer);
- internal struct SpriteInfo
- {
- public RectangleF Source;
- public RectangleF Destination;
- public Vector2 Origin;
- public float Rotation;
- public float Depth;
- public SpriteEffects SpriteEffects;
- public Color Color;
- public float Opacity;
+ _context.InputAssembler.SetIndexBuffer(_indexBuffer, _indexBuffer.Format, 0);
+ _context.InputAssembler.SetVertexBuffers(0, _vertexBuffer);
}
- internal readonly struct TextureInfo
+ private static unsafe void UpdateVertexFromSpriteInfo(ref SpriteInfo spriteInfo,
+ VertexPositionColorTexture* vpctPtr,
+ float deltaX,
+ float deltaY)
{
- public readonly ShaderResourceView View;
- public readonly int Width;
- public readonly int Height;
- public readonly long Ptr64;
+ Vector2 origin = spriteInfo.Origin;
- public TextureInfo(ShaderResourceView view, int width, int height)
+ // ReSharper disable once CompareOfFloatsByEqualityOperator
+ if (spriteInfo.Source.Width != 0f)
{
- View = view;
- Width = width;
- Height = height;
- Ptr64 = view.NativePointer.ToInt64();
+ origin.X /= spriteInfo.Source.Width;
}
- }
-
- [StructLayout(LayoutKind.Explicit, Size = VERTEX_STRIDE)]
- private struct VertexPositionColorTexture
- {
- [FieldOffset(0)]
- public float X;
-
- [FieldOffset(4)]
- public float Y;
-
- [FieldOffset(8)]
- public float Z;
-
- [FieldOffset(12)]
- public float W;
-
- [FieldOffset(16)]
- public float R;
-
- [FieldOffset(20)]
- public float G;
-
- [FieldOffset(24)]
- public float B;
-
- [FieldOffset(28)]
- public float A;
-
- [FieldOffset(32)]
- public float U;
-
- [FieldOffset(36)]
- public float V;
- }
-
- #region Drawing
-
- #region Defaults
-
- ///
- /// Draw rectangle.
- ///
- /// Destination rectangle.
- /// The color.
- /// Width of the line.
- /// The rotation.
- /// The opacity.
- /// Depth of the layer.
- public void DrawRectangle(in RectangleF destinationRectangle,
- in Color color,
- float lineWidth,
- float rotation,
- float opacity,
- float layerDepth)
- {
- DrawRectangle(destinationRectangle, color, lineWidth, rotation, s_vector2Zero, opacity, layerDepth);
- }
-
- ///
- /// Draw rectangle.
- ///
- /// Destination rectangle.
- /// The color.
- /// Width of the line.
- /// The rotation.
- /// The origin.
- /// The opacity.
- /// Depth of the layer.
- public void DrawRectangle(in RectangleF destinationRectangle,
- in Color color,
- float lineWidth,
- float rotation,
- in Vector2 origin,
- float opacity,
- float layerDepth)
- {
- Vector2[] vertex;
// ReSharper disable once CompareOfFloatsByEqualityOperator
- if (rotation == 0.0f)
- {
- vertex = new[]
- {
- destinationRectangle.TopLeft, destinationRectangle.TopRight, destinationRectangle.BottomRight,
- destinationRectangle.BottomLeft
- };
- }
- else
+ if (spriteInfo.Source.Height != 0f)
{
- vertex = new Vector2[4];
-
- Vector2 o = origin;
-
- // ReSharper disable once CompareOfFloatsByEqualityOperator
- if (destinationRectangle.Width != 0f)
- {
- o.X /= destinationRectangle.Width;
- }
-
- // ReSharper disable once CompareOfFloatsByEqualityOperator
- if (destinationRectangle.Height != 0f)
- {
- o.Y /= destinationRectangle.Height;
- }
-
- float cos = (float)Math.Cos(rotation);
- float sin = (float)Math.Sin(rotation);
- for (int j = 0; j < VERTICES_PER_SPRITE; j++)
- {
- Vector2 corner = s_cornerOffsets[j];
- float posX = (corner.X - o.X) * destinationRectangle.Width;
- float posY = (corner.Y - o.Y) * destinationRectangle.Height;
-
- vertex[j] = new Vector2(
- (destinationRectangle.X + (posX * cos)) - (posY * sin),
- destinationRectangle.Y + (posX * sin) + (posY * cos));
- }
+ origin.Y /= spriteInfo.Source.Height;
}
- DrawPolygon(vertex, color, lineWidth, opacity, layerDepth);
- }
-
- ///
- /// Draw fill rectangle.
- ///
- /// Destination rectangle.
- /// The color.
- /// Depth of the layer.
- public void DrawFillRectangle(in RectangleF destinationRectangle, in Color color, float layerDepth)
- {
- DrawSprite(
- DefaultTextures.WhiteTexture, destinationRectangle, false, s_nullRectangle,
- color, 0.0f, s_vector2Zero, 1.0f, SpriteEffects.None, layerDepth);
- }
-
- ///
- /// Draw fill rectangle.
- ///
- /// Destination rectangle.
- /// The color.
- /// The opacity.
- /// Depth of the layer.
- public void DrawFillRectangle(in RectangleF destinationRectangle,
- in Color color,
- float opacity,
- float layerDepth)
- {
- DrawSprite(
- DefaultTextures.WhiteTexture, destinationRectangle, false, s_nullRectangle,
- color, 0.0f, s_vector2Zero, opacity, SpriteEffects.None, layerDepth);
- }
-
- ///
- /// Draw fill rectangle.
- ///
- /// Destination rectangle.
- /// The color.
- /// The rotation.
- /// The origin.
- /// The opacity.
- /// Depth of the layer.
- public void DrawFillRectangle(in RectangleF destinationRectangle,
- in Color color,
- float rotation,
- in Vector2 origin,
- float opacity,
- float layerDepth)
- {
- DrawSprite(
- DefaultTextures.WhiteTexture, destinationRectangle, false, s_nullRectangle,
- color, rotation, origin, opacity, SpriteEffects.None, layerDepth);
- }
-
- ///
- /// Draw line.
- ///
- /// The first point.
- /// The second point.
- /// The color.
- /// Width of the line.
- /// The opacity.
- /// Depth of the layer.
- public void DrawLine(in Vector2 point1,
- in Vector2 point2,
- in Color color,
- float lineWidth,
- float opacity,
- float layerDepth)
- {
- DrawLine(point1, point2, color, lineWidth, opacity, 1.0f, layerDepth);
- }
-
- ///
- /// Draw line.
- ///
- /// The first point.
- /// The second point.
- /// The color.
- /// Width of the line.
- /// The opacity.
- /// The length factor.
- /// Depth of the layer.
- public void DrawLine(in Vector2 point1,
- in Vector2 point2,
- in Color color,
- float lineWidth,
- float opacity,
- float lengthFactor,
- float layerDepth)
- {
- DrawSprite(
- DefaultTextures.WhiteTexture, new RectangleF(
- point1.X, point1.Y, Vector2.Distance(point1, point2) * lengthFactor, lineWidth), false,
- s_nullRectangle, color, (float)Math.Atan2(point2.Y - point1.Y, point2.X - point1.X),
- s_vector2Zero, opacity, SpriteEffects.None, layerDepth);
- }
-
- ///
- /// Draw polygon.
- ///
- /// The vertex.
- /// The color.
- /// Width of the line.
- /// The opacity.
- /// Depth of the layer.
- public void DrawPolygon(Vector2[] vertex, in Color color, float lineWidth, float opacity, float layerDepth)
- {
- if (vertex.Length > 1)
+ // ReSharper disable once CompareOfFloatsByEqualityOperator
+ if (spriteInfo.Rotation == 0f)
{
- int l = vertex.Length - 1;
- for (int i = 0; i < l; i++)
+ for (int j = 0; j < VERTICES_PER_SPRITE; j++)
{
- DrawLine(vertex[i], vertex[i + 1], color, lineWidth, opacity, layerDepth);
- }
- DrawLine(vertex[l], vertex[0], color, lineWidth, opacity, layerDepth);
- }
- }
-
- ///
- /// Draw circle.
- ///
- /// The center.
- /// The radius.
- /// The color.
- /// Width of the line.
- /// The opacity.
- /// The segments.
- /// Depth of the layer.
- public void DrawCircle(in Vector2 center,
- float radius,
- in Color color,
- float lineWidth,
- float opacity,
- int segments,
- float layerDepth)
- {
- DrawCircle(center, radius, 0, MathUtil.TwoPi, color, lineWidth, opacity, segments, layerDepth);
- }
-
- ///
- /// Draw circle.
- ///
- /// The center.
- /// The radius.
- /// The start.
- /// The end.
- /// The color.
- /// Width of the line.
- /// The opacity.
- /// The segments.
- /// Depth of the layer.
- public void DrawCircle(in Vector2 center,
- float radius,
- float start,
- float end,
- in Color color,
- float lineWidth,
- float opacity,
- int segments,
- float layerDepth)
- {
- Vector2[] vertex = new Vector2[segments];
-
- float increment = (end - start) / segments;
- float theta = start;
-
- for (int i = 0; i < segments; i++)
- {
- vertex[i].X = center.X + (radius * (float)Math.Cos(theta));
- vertex[i].Y = center.Y + (radius * (float)Math.Sin(theta));
- theta += increment;
- }
-
- DrawPolygon(vertex, color, lineWidth, opacity, layerDepth);
- }
-
- #endregion
-
- #region Texture
-
- ///
- /// Draws.
- ///
- /// The texture.
- /// The position.
- /// The color.
- public void Draw(Texture texture, in Vector2 position, in Color color)
- {
- DrawSprite(
- texture, new RectangleF(position.X, position.Y, 1f, 1f), true, s_nullRectangle,
- color, 0f, s_vector2Zero, 1.0f, SpriteEffects.None, 0f);
- }
-
- ///
- /// Draws.
- ///
- /// The texture.
- /// Destination rectangle.
- /// The color.
- public void Draw(Texture texture, in RectangleF destinationRectangle, in Color color)
- {
- DrawSprite(
- texture, destinationRectangle, false, s_nullRectangle,
- color, 0f, s_vector2Zero, 1.0f, SpriteEffects.None, 0f);
- }
-
- ///
- /// Draws.
- ///
- /// The texture.
- /// The position.
- /// Source rectangle.
- /// The color.
- public void Draw(Texture texture, in Vector2 position, in Rectangle? sourceRectangle, in Color color)
- {
- DrawSprite(
- texture, new RectangleF(position.X, position.Y, 1f, 1f), true, sourceRectangle,
- color, 0f, s_vector2Zero, 1.0f, SpriteEffects.None, 0f);
- }
-
- ///
- /// Draws.
- ///
- /// The texture.
- /// Destination rectangle.
- /// Source rectangle.
- /// The color.
- public void Draw(Texture texture,
- in RectangleF destinationRectangle,
- in Rectangle? sourceRectangle,
- in Color color)
- {
- DrawSprite(
- texture, destinationRectangle, false, sourceRectangle,
- color, 0f, s_vector2Zero, 1.0f, SpriteEffects.None, 0f);
- }
-
- ///
- /// Draws.
- ///
- /// The texture.
- /// Destination rectangle.
- /// Source rectangle.
- /// The color.
- /// The rotation.
- /// The origin.
- /// The opacity.
- /// The effects.
- /// Depth of the layer.
- public void Draw(Texture texture,
- in RectangleF destinationRectangle,
- in Rectangle? sourceRectangle,
- in Color color,
- float rotation,
- in Vector2 origin,
- float opacity,
- SpriteEffects effects,
- float layerDepth)
- {
- DrawSprite(
- texture, destinationRectangle, false, sourceRectangle,
- color, rotation, origin, opacity, effects, layerDepth);
- }
-
- ///
- /// Draws.
- ///
- /// The texture.
- /// The position.
- /// Source rectangle.
- /// The color.
- /// The rotation.
- /// The origin.
- /// The scale.
- /// The opacity.
- /// The effects.
- /// Depth of the layer.
- public void Draw(Texture texture,
- in Vector2 position,
- in Rectangle? sourceRectangle,
- in Color color,
- float rotation,
- in Vector2 origin,
- float scale,
- float opacity,
- SpriteEffects effects,
- float layerDepth)
- {
- DrawSprite(
- texture, new RectangleF(position.X, position.Y, scale, scale), true, sourceRectangle,
- color, rotation, origin, opacity, effects, layerDepth);
- }
-
- ///
- /// Draws.
- ///
- /// The texture.
- /// The position.
- /// Source rectangle.
- /// The color.
- /// The rotation.
- /// The origin.
- /// The scale.
- /// The opacity.
- /// The effects.
- /// Depth of the layer.
- public void Draw(Texture texture,
- in Vector2 position,
- in Rectangle? sourceRectangle,
- in Color color,
- float rotation,
- in Vector2 origin,
- in Vector2 scale,
- float opacity,
- SpriteEffects effects,
- float layerDepth)
- {
- DrawSprite(
- texture, new RectangleF(position.X, position.Y, scale.X, scale.Y), true, sourceRectangle,
- color, rotation, origin, opacity, effects, layerDepth);
- }
-
- ///
- /// Draw sprite.
- ///
- ///
- /// Thrown when one or more required arguments are
- /// null.
- ///
- /// Thrown when the requested operation is invalid.
- /// The texture.
- /// Destination for the.
- /// True to scale destination.
- /// Source rectangle.
- /// The color.
- /// The rotation.
- /// The origin.
- /// The opacity.
- /// The effects.
- /// The depth.
- private unsafe void DrawSprite(Texture texture,
- in RectangleF destination,
- bool scaleDestination,
- in Rectangle? sourceRectangle,
- in Color color,
- float rotation,
- in Vector2 origin,
- float opacity,
- SpriteEffects effects,
- float depth)
- {
- if (!_isBeginCalled)
- {
- throw new InvalidOperationException("Begin must be called before draw");
- }
+ VertexPositionColorTexture* vertex = vpctPtr + j;
- if (texture.TexturePointer == IntPtr.Zero)
- {
- throw new ArgumentNullException(nameof(texture));
- }
+ Vector2 corner = s_cornerOffsets[j];
+ float posX = (corner.X - origin.X) * spriteInfo.Destination.Width;
+ float posY = (corner.Y - origin.Y) * spriteInfo.Destination.Height;
- if (_spriteQueueCount >= _spriteQueue.Length)
- {
- bool lockTaken = false;
- try
- {
- _spinLock.Enter(ref lockTaken);
+ vertex->X = spriteInfo.Destination.X + posX;
+ vertex->Y = spriteInfo.Destination.Y + posY;
+ vertex->Z = spriteInfo.Depth;
+ vertex->W = 1.0f;
- int size = _spriteQueue.Length * 2;
- _sortIndices = new int[size];
- _sortedSprites = new SpriteInfo[size];
- Array.Resize(ref _spriteQueue, size);
- Array.Resize(ref _spriteTextures, size);
- }
- finally
- {
- if (lockTaken)
- {
- _spinLock.Exit(false);
- }
- }
- }
+ vertex->R = spriteInfo.Color.R * spriteInfo.Opacity;
+ vertex->G = spriteInfo.Color.G * spriteInfo.Opacity;
+ vertex->B = spriteInfo.Color.B * spriteInfo.Opacity;
+ vertex->A = spriteInfo.Color.A * spriteInfo.Opacity;
- if (!_textureInfos.TryGetValue(texture.TexturePointer, out TextureInfo textureInfo))
- {
- bool lockTaken = false;
- try
- {
- _spinLock.Enter(ref lockTaken);
- if (!_textureInfos.TryGetValue(texture.TexturePointer, out textureInfo))
- {
- textureInfo = new TextureInfo(texture.TextureView, texture.Width, texture.Height);
- _textureInfos.Add(texture.TexturePointer, textureInfo);
- }
- }
- finally
- {
- if (lockTaken)
- {
- _spinLock.Exit(false);
- }
+ corner = s_cornerOffsets[j ^ (int)spriteInfo.SpriteEffects];
+ vertex->U = (spriteInfo.Source.X + (corner.X * spriteInfo.Source.Width)) * deltaX;
+ vertex->V = (spriteInfo.Source.Y + (corner.Y * spriteInfo.Source.Height)) * deltaY;
}
}
-
- int spriteQueueCount = Interlocked.Increment(ref _spriteQueueCount) - 1;
- fixed (SpriteInfo* spriteInfo = &_spriteQueue[spriteQueueCount])
+ else
{
- float width;
- float height;
- if (sourceRectangle.HasValue)
- {
- Rectangle rectangle = sourceRectangle.Value;
- spriteInfo->Source.X = rectangle.X;
- spriteInfo->Source.Y = rectangle.Y;
- width = rectangle.Width;
- height = rectangle.Height;
- }
- else
+ float cos = (float)Math.Cos(spriteInfo.Rotation);
+ float sin = (float)Math.Sin(spriteInfo.Rotation);
+ for (int j = 0; j < VERTICES_PER_SPRITE; j++)
{
- spriteInfo->Source.X = 0;
- spriteInfo->Source.Y = 0;
- width = texture.Width;
- height = texture.Height;
- }
-
- spriteInfo->Source.Width = width;
- spriteInfo->Source.Height = height;
+ VertexPositionColorTexture* vertex = vpctPtr + j;
- spriteInfo->Destination.X = destination.X;
- spriteInfo->Destination.Y = destination.Y;
+ Vector2 corner = s_cornerOffsets[j];
+ float posX = (corner.X - origin.X) * spriteInfo.Destination.Width;
+ float posY = (corner.Y - origin.Y) * spriteInfo.Destination.Height;
- if (scaleDestination)
- {
- spriteInfo->Destination.Width = destination.Width * width;
- spriteInfo->Destination.Height = destination.Height * height;
- }
- else
- {
- spriteInfo->Destination.Width = destination.Width;
- spriteInfo->Destination.Height = destination.Height;
- }
+ vertex->X = (spriteInfo.Destination.X + (posX * cos)) - (posY * sin);
+ vertex->Y = spriteInfo.Destination.Y + (posX * sin) + (posY * cos);
+ vertex->Z = spriteInfo.Depth;
+ vertex->W = 1.0f;
- if (spriteInfo->Destination.Width < 0)
- {
- spriteInfo->Destination.X += spriteInfo->Destination.Width;
- spriteInfo->Destination.Width = -spriteInfo->Destination.Width;
- }
+ vertex->R = spriteInfo.Color.R * spriteInfo.Opacity;
+ vertex->G = spriteInfo.Color.G * spriteInfo.Opacity;
+ vertex->B = spriteInfo.Color.B * spriteInfo.Opacity;
+ vertex->A = spriteInfo.Color.A * spriteInfo.Opacity;
- if (spriteInfo->Destination.Height < 0)
- {
- spriteInfo->Destination.Y += spriteInfo->Destination.Height;
- spriteInfo->Destination.Height = -spriteInfo->Destination.Height;
+ corner = s_cornerOffsets[j ^ (int)spriteInfo.SpriteEffects];
+ vertex->U = (spriteInfo.Source.X + (corner.X * spriteInfo.Source.Width)) * deltaX;
+ vertex->V = (spriteInfo.Source.Y + (corner.Y * spriteInfo.Source.Height)) * deltaY;
}
-
- spriteInfo->Origin = origin;
- spriteInfo->Rotation = rotation;
- spriteInfo->Depth = depth;
- spriteInfo->SpriteEffects = effects;
- spriteInfo->Color = color;
- spriteInfo->Opacity = opacity;
}
-
- _spriteTextures[spriteQueueCount] = textureInfo;
- }
-
- #endregion
-
- #region SpiteFont
-
- ///
- /// Draw text.
- ///
- /// The font.
- /// The text.
- /// The position.
- /// The color.
- /// Depth of the layer.
- public void DrawText(SpriteFont font, string text, in Vector2 position, in Color color, float layerDepth)
- {
- font.Draw(
- DrawTextInternal, text, position,
- color, 0f, Vector2.Zero, 1.0f, SpriteEffects.None, layerDepth);
- }
-
- ///
- /// Draw text.
- ///
- /// The font.
- /// The text.
- /// The position.
- /// The color.
- /// The rotation.
- /// Depth of the layer.
- public void DrawText(SpriteFont font,
- string text,
- in Vector2 position,
- in Color color,
- float rotation,
- float layerDepth)
- {
- font.Draw(
- DrawTextInternal, text, position,
- color, rotation, Vector2.Zero, 1.0f, SpriteEffects.None, layerDepth);
- }
-
- ///
- /// Draw text.
- ///
- /// The font.
- /// The text.
- /// The position.
- /// The color.
- /// The rotation.
- /// The origin.
- /// The opacity.
- /// The effects.
- /// Depth of the layer.
- public void DrawText(SpriteFont font,
- string text,
- in Vector2 position,
- in Color color,
- float rotation,
- in Vector2 origin,
- float opacity,
- SpriteEffects effects,
- float layerDepth)
- {
- font.Draw(
- DrawTextInternal, text, position,
- color, rotation, origin, opacity, effects, layerDepth);
- }
-
- ///
- /// Draw text.
- ///
- /// The font.
- /// The text.
- /// The start.
- /// The end.
- /// The position.
- /// The color.
- /// The rotation.
- /// The origin.
- /// The opacity.
- /// The effects.
- /// Depth of the layer.
- public void DrawText(SpriteFont font,
- string text,
- int start,
- int end,
- in Vector2 position,
- in Color color,
- float rotation,
- in Vector2 origin,
- float opacity,
- SpriteEffects effects,
- float layerDepth)
- {
- font.Draw(
- DrawTextInternal, text, start, end, position,
- color, rotation, origin, opacity, effects, layerDepth);
- }
-
- ///
- /// Draw text.
- ///
- /// The font.
- /// The text.
- /// The start.
- /// The end.
- /// The position.
- /// The dimension.
- /// The color.
- /// The rotation.
- /// The origin.
- /// The opacity.
- /// The effects.
- /// Depth of the layer.
- public void DrawText(SpriteFont font,
- string text,
- int start,
- int end,
- in Vector2 position,
- in Size2F dimension,
- in Color color,
- float rotation,
- in Vector2 origin,
- float opacity,
- SpriteEffects effects,
- float layerDepth)
- {
- font.Draw(
- DrawTextInternal, text, start, end, position, dimension,
- color, rotation, origin, opacity, effects, layerDepth);
- }
-
- ///
- /// Draw text.
- ///
- /// The font.
- /// The text.
- /// The position.
- /// The color.
- /// Depth of the layer.
- public void DrawText(SpriteFont font, StringBuilder text, in Vector2 position, in Color color, float layerDepth)
- {
- font.Draw(
- DrawTextInternal, text, position,
- color, 0f, Vector2.Zero, 1.0f, SpriteEffects.None, layerDepth);
- }
-
- ///
- /// Draw text.
- ///
- /// The font.
- /// The text.
- /// The position.
- /// The color.
- /// The rotation.
- /// Depth of the layer.
- public void DrawText(SpriteFont font,
- StringBuilder text,
- in Vector2 position,
- in Color color,
- float rotation,
- float layerDepth)
- {
- font.Draw(
- DrawTextInternal, text, position,
- color, rotation, Vector2.Zero, 1.0f, SpriteEffects.None, layerDepth);
- }
-
- ///
- /// Draw text.
- ///
- /// The font.
- /// The text.
- /// The position.
- /// The color.
- /// The rotation.
- /// The origin.
- /// The opacity.
- /// The effects.
- /// Depth of the layer.
- public void DrawText(SpriteFont font,
- StringBuilder text,
- in Vector2 position,
- in Color color,
- float rotation,
- in Vector2 origin,
- float opacity,
- SpriteEffects effects,
- float layerDepth)
- {
- font.Draw(
- DrawTextInternal, text, position,
- color, rotation, origin, opacity, effects, layerDepth);
- }
-
- ///
- /// Draw text.
- ///
- /// The font.
- /// The text.
- /// The start.
- /// The end.
- /// The position.
- /// The color.
- /// The rotation.
- /// The origin.
- /// The opacity.
- /// The effects.
- /// Depth of the layer.
- public void DrawText(SpriteFont font,
- StringBuilder text,
- int start,
- int end,
- in Vector2 position,
- in Color color,
- float rotation,
- in Vector2 origin,
- float opacity,
- SpriteEffects effects,
- float layerDepth)
- {
- font.Draw(
- DrawTextInternal, text, start, end, position,
- color, rotation, origin, opacity, effects, layerDepth);
- }
-
- ///
- /// Draw text.
- ///
- /// The font.
- /// The text.
- /// The start.
- /// The end.
- /// The position.
- /// The dimension.
- /// The color.
- /// The rotation.
- /// The origin.
- /// The opacity.
- /// The effects.
- /// Depth of the layer.
- public void DrawText(SpriteFont font,
- StringBuilder text,
- int start,
- int end,
- in Vector2 position,
- in Size2F dimension,
- in Color color,
- float rotation,
- in Vector2 origin,
- float opacity,
- SpriteEffects effects,
- float layerDepth)
- {
- font.Draw(
- DrawTextInternal, text, start, end, position, dimension,
- color, rotation, origin, opacity, effects, layerDepth);
}
- ///
- /// Draw text internal.
- ///
- /// The texture.
- /// The position.
- /// Source rectangle.
- /// The color.
- /// The rotation.
- /// The origin.
- /// The scale.
- /// The opacity.
- /// The effects.
- /// Depth of the layer.
- internal void DrawTextInternal(Texture texture,
- in Vector2 position,
- in Rectangle? sourceRectangle,
- in Color color,
- float rotation,
- in Vector2 origin,
- float scale,
- float opacity,
- SpriteEffects effects,
- float layerDepth)
- {
- DrawSprite(
- texture, new RectangleF(position.X, position.Y, scale, scale), true, sourceRectangle,
- color, rotation, origin, opacity, effects, layerDepth);
- }
-
- #endregion
-
- #endregion
-
#region IDisposable Support
///
@@ -1590,15 +545,9 @@ private void Dispose(bool disposing)
Utilities.Dispose(ref _samplerState);
Utilities.Dispose(ref _depthStencilState);
- Utilities.Dispose(ref _defaultBlendState);
- Utilities.Dispose(ref _defaultRasterizerState);
- Utilities.Dispose(ref _defaultSamplerState);
- Utilities.Dispose(ref _defaultRasterizerScissorEnabledState);
- Utilities.Dispose(ref _defaultDepthStencilState);
-
_vertexBuffer.Dispose();
- _perFrameBuffer.Dispose();
_indexBuffer.Dispose();
+ _perFrameBuffer.Dispose();
_shader.Dispose();
_vertexInputLayout.Dispose();
@@ -1608,6 +557,14 @@ private void Dispose(bool disposing)
}
}
+ ///
+ /// Finalizes an instance of the class.
+ ///
+ ~SpriteBatch()
+ {
+ Dispose(false);
+ }
+
///
public void Dispose()
{
diff --git a/src/Exomia.Framework/Graphics/SpriteFontCR.cs b/src/Exomia.Framework/Graphics/SpriteFont.ContentSerializationReader.cs
similarity index 87%
rename from src/Exomia.Framework/Graphics/SpriteFontCR.cs
rename to src/Exomia.Framework/Graphics/SpriteFont.ContentSerializationReader.cs
index 97ad13db..130d2a2c 100644
--- a/src/Exomia.Framework/Graphics/SpriteFontCR.cs
+++ b/src/Exomia.Framework/Graphics/SpriteFont.ContentSerializationReader.cs
@@ -15,10 +15,7 @@
namespace Exomia.Framework.Graphics
{
- ///
- /// A sprite font carriage return. This class cannot be inherited.
- ///
- sealed class SpriteFontCR : ContentSerializationReader
+ sealed class SpriteFontContentSerializationReader : ContentSerializationReader
{
///
public override SpriteFont ReadContext(ContentSerializationContext context)
@@ -40,9 +37,6 @@ public override SpriteFont ReadContext(ContentSerializationContext context)
}
}
- ///
- /// A sprite font glyph carriage return. This class cannot be inherited.
- ///
sealed class SpriteFontGlyphCR : ContentSerializationReader
{
///
@@ -59,9 +53,6 @@ public override SpriteFont.Glyph ReadContext(ContentSerializationContext context
}
}
- ///
- /// A sprite font kerning carriage return. This class cannot be inherited.
- ///
sealed class SpriteFontKerningCR : ContentSerializationReader
{
///
diff --git a/src/Exomia.Framework/Graphics/SpriteFontCW.cs b/src/Exomia.Framework/Graphics/SpriteFont.ContentSerializationWriter.cs
similarity index 85%
rename from src/Exomia.Framework/Graphics/SpriteFontCW.cs
rename to src/Exomia.Framework/Graphics/SpriteFont.ContentSerializationWriter.cs
index 21ee3554..0b921186 100644
--- a/src/Exomia.Framework/Graphics/SpriteFontCW.cs
+++ b/src/Exomia.Framework/Graphics/SpriteFont.ContentSerializationWriter.cs
@@ -13,10 +13,7 @@
namespace Exomia.Framework.Graphics
{
- ///
- /// A sprite font cw. This class cannot be inherited.
- ///
- sealed class SpriteFontCW : ContentSerializationWriter
+ sealed class SpriteFontContentSerializationWriter : ContentSerializationWriter
{
///
public override void WriteContext(ContentSerializationContext context, SpriteFont obj)
@@ -40,9 +37,6 @@ public override void WriteContext(ContentSerializationContext context, SpriteFon
}
}
- ///
- /// A sprite font glyph cw. This class cannot be inherited.
- ///
sealed class SpriteFontGlyphCW : ContentSerializationWriter
{
///
@@ -56,9 +50,6 @@ public override void WriteContext(ContentSerializationContext context, SpriteFon
}
}
- ///
- /// A sprite font kerning cw. This class cannot be inherited.
- ///
sealed class SpriteFontKerningCW : ContentSerializationWriter
{
///
diff --git a/src/Exomia.Framework/Graphics/SpriteFont.Glyph.cs b/src/Exomia.Framework/Graphics/SpriteFont.Glyph.cs
new file mode 100644
index 00000000..cf2c264a
--- /dev/null
+++ b/src/Exomia.Framework/Graphics/SpriteFont.Glyph.cs
@@ -0,0 +1,50 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using Exomia.Framework.ContentSerialization;
+using SharpDX;
+
+namespace Exomia.Framework.Graphics
+{
+ public sealed partial class SpriteFont
+ {
+ ///
+ /// A glyph.
+ ///
+ [ContentSerializable(typeof(SpriteFontGlyphCR), typeof(SpriteFontGlyphCW))]
+ public struct Glyph
+ {
+ ///
+ /// The character.
+ ///
+ public int Character;
+
+ ///
+ /// The subrect.
+ ///
+ public Rectangle Subrect;
+
+ ///
+ /// The offset x coordinate.
+ ///
+ public int OffsetX;
+
+ ///
+ /// The offset y coordinate.
+ ///
+ public int OffsetY;
+
+ ///
+ /// The advance.
+ ///
+ public int XAdvance;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Graphics/SpriteFont.Kerning.cs b/src/Exomia.Framework/Graphics/SpriteFont.Kerning.cs
new file mode 100644
index 00000000..74dff3b0
--- /dev/null
+++ b/src/Exomia.Framework/Graphics/SpriteFont.Kerning.cs
@@ -0,0 +1,39 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using Exomia.Framework.ContentSerialization;
+
+namespace Exomia.Framework.Graphics
+{
+ public sealed partial class SpriteFont
+ {
+ ///
+ /// A kerning.
+ ///
+ [ContentSerializable(typeof(SpriteFontKerningCR), typeof(SpriteFontKerningCW))]
+ public struct Kerning
+ {
+ ///
+ /// The first.
+ ///
+ public int First;
+
+ ///
+ /// The second.
+ ///
+ public int Second;
+
+ ///
+ /// The offset.
+ ///
+ public int Offset;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Graphics/SpriteFont.Methods.cs b/src/Exomia.Framework/Graphics/SpriteFont.Methods.cs
new file mode 100644
index 00000000..32084504
--- /dev/null
+++ b/src/Exomia.Framework/Graphics/SpriteFont.Methods.cs
@@ -0,0 +1,531 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using System;
+using System.Runtime.CompilerServices;
+using SharpDX;
+
+namespace Exomia.Framework.Graphics
+{
+ public sealed partial class SpriteFont
+ {
+ ///
+ /// Returns the size of this text.
+ ///
+ /// The text.
+ ///
+ /// A with x and y set to width and height of
+ ///
+#if NETSTANDARD2_1
+ public Vector2 MeasureText(ReadOnlySpan text)
+#else
+ public Vector2 MeasureText(string text)
+#endif
+ {
+ return MeasureText(text, 0, text.Length);
+ }
+
+ ///
+ /// Returns the size of this text from to .
+ ///
+ /// The text.
+ /// The start.
+ /// The end.
+ ///
+ /// A with x and y set to width and height of
+ ///
+#if NETSTANDARD2_1
+ public Vector2 MeasureText(ReadOnlySpan text, int start, int end)
+#else
+ public Vector2 MeasureText(string text, int start, int end)
+#endif
+ {
+ Vector2 size = Vector2.Zero;
+
+ if (start >= end) { return size; }
+ if (end > text.Length) { end = text.Length; }
+ if (start < 0) { start = 0; }
+
+ float x = 0;
+ float y = 0;
+
+ int key = 0;
+
+ for (int i = start; i < end; i++)
+ {
+ char c = text[i];
+ switch (c)
+ {
+ case '\r':
+ {
+ key |= c;
+ continue;
+ }
+ case '\n':
+ {
+ key = 0;
+ x = 0;
+ y += LineSpacing;
+ }
+ break;
+ default:
+ {
+ if (!_glyphs.TryGetValue(c, out Glyph glyph))
+ {
+ if (IgnoreUnknownCharacters)
+ {
+ continue;
+ }
+
+ glyph = _defaultGlyph;
+ }
+ key |= c;
+
+ float dx = glyph.OffsetX;
+ if (Kernings.TryGetValue(key, out Kerning kerning))
+ {
+ dx += kerning.Offset;
+ }
+
+ float nextX = x + glyph.XAdvance + SpacingX;
+
+ float h = y + LineSpacing;
+ if (nextX + dx > size.X)
+ {
+ size.X = nextX;
+ }
+ if (h > size.Y)
+ {
+ size.Y = h;
+ }
+
+ x = nextX;
+ }
+ break;
+ }
+
+ key <<= 16;
+ }
+
+ return size;
+ }
+
+ ///
+ /// Determines which item (if any) has been hit.
+ ///
+ /// The text.
+ /// The start.
+ /// The end.
+ /// The position.
+ /// The position.
+ ///
+ /// An int.
+ ///
+#if NETSTANDARD2_1
+ public int HitTest(ReadOnlySpan text, int start, int end, float xPos, float yPos)
+#else
+ public int HitTest(string text, int start, int end, float xPos, float yPos)
+#endif
+ {
+ if (start >= end) { return end; }
+ if (end > text.Length) { end = text.Length; }
+ if (start < 0) { start = 0; }
+
+ if (xPos < 0) { return -1; }
+ if (yPos < 0) { return -1; }
+
+ float x = 0;
+ float y = 0;
+
+ int key = 0;
+
+ for (int i = start; i < end; i++)
+ {
+ char c = text[i];
+ switch (c)
+ {
+ case '\r':
+ {
+ key |= c;
+ continue;
+ }
+ case '\n':
+ {
+ key = 0;
+ x = 0;
+ y += LineSpacing;
+ }
+ break;
+ default:
+ {
+ if (!_glyphs.TryGetValue(c, out Glyph glyph))
+ {
+ if (IgnoreUnknownCharacters)
+ {
+ continue;
+ }
+ glyph = _defaultGlyph;
+ }
+ key |= c;
+
+ float dx = glyph.OffsetX;
+ if (Kernings.TryGetValue(key, out Kerning kerning))
+ {
+ dx += kerning.Offset;
+ }
+
+ float nextX = x + glyph.XAdvance + SpacingX;
+ float h = y + LineSpacing;
+
+ if (xPos >= x && xPos <= nextX + dx && yPos <= h && yPos >= y)
+ {
+ if (xPos < (x + nextX + dx) * 0.5f) { return i; }
+ return i + 1;
+ }
+ x = nextX;
+ }
+ break;
+ }
+ key <<= 16;
+ }
+
+ return end;
+ }
+
+#if NETSTANDARD2_1
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal void Draw(DrawFont drawCallback,
+ ReadOnlySpan text,
+ in Vector2 position,
+ in Color color,
+ float rotation,
+ in Vector2 origin,
+ float opacity,
+ TextureEffects effects,
+ float layerDepth)
+#else
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal void Draw(DrawFont drawCallback,
+ string text,
+ in Vector2 position,
+ in Color color,
+ float rotation,
+ in Vector2 origin,
+ float opacity,
+ TextureEffects effects,
+ float layerDepth)
+#endif
+ {
+ Draw(
+ drawCallback, text, 0, text.Length,
+ in position, in color, rotation, in origin,
+ opacity, effects, layerDepth);
+ }
+
+#if NETSTANDARD2_1
+ internal void Draw(DrawFont drawCallback,
+ ReadOnlySpan text,
+ int start,
+ int end,
+ in Vector2 position,
+ in Color color,
+ float rotation,
+ in Vector2 origin,
+ float opacity,
+ TextureEffects effects,
+ float layerDepth)
+#else
+ internal void Draw(DrawFont drawCallback,
+ string text,
+ int start,
+ int end,
+ in Vector2 position,
+ in Color color,
+ float rotation,
+ in Vector2 origin,
+ float opacity,
+ TextureEffects effects,
+ float layerDepth)
+#endif
+ {
+ if (end <= start || end > text.Length) { end = text.Length; }
+
+ float x = 0;
+ float y = 0;
+
+ int key = 0;
+
+ if (rotation == 0)
+ {
+ for (int i = start; i < end; i++)
+ {
+ char c = text[i];
+ switch (c)
+ {
+ case '\r':
+ {
+ key |= c;
+ continue;
+ }
+ case '\n':
+ {
+ key = 0;
+ x = 0;
+ y += LineSpacing;
+ }
+ break;
+ default:
+ {
+ if (!_glyphs.TryGetValue(c, out Glyph glyph))
+ {
+ if (IgnoreUnknownCharacters)
+ {
+ continue;
+ }
+
+ glyph = _defaultGlyph;
+ }
+ key |= c;
+
+ float dx = glyph.OffsetX;
+ if (Kernings.TryGetValue(key, out Kerning kerning))
+ {
+ dx += kerning.Offset;
+ }
+
+ drawCallback(
+ _texture,
+ new Vector2(position.X + x + dx, position.Y + y + glyph.OffsetY),
+ glyph.Subrect, color, rotation, origin,
+ 1.0f, opacity, effects, layerDepth);
+
+ x += glyph.XAdvance + SpacingX;
+ }
+ break;
+ }
+
+ key <<= 16;
+ }
+ }
+ else
+ {
+ double cos = Math.Cos(rotation);
+ double sin = Math.Sin(rotation);
+
+ for (int i = start; i < end; i++)
+ {
+ char c = text[i];
+ switch (c)
+ {
+ case '\r':
+ {
+ key |= c;
+ continue;
+ }
+ case '\n':
+ {
+ key = 0;
+ x = 0;
+ y += LineSpacing;
+ }
+ break;
+ default:
+ {
+ if (!_glyphs.TryGetValue(c, out Glyph glyph))
+ {
+ if (IgnoreUnknownCharacters)
+ {
+ continue;
+ }
+
+ glyph = _defaultGlyph;
+ }
+ key |= c;
+
+ float dx = glyph.OffsetX;
+ if (Kernings.TryGetValue(key, out Kerning kerning))
+ {
+ dx += kerning.Offset;
+ }
+
+ float ox = (position.X + x + dx) - origin.X;
+ float oy = (position.Y + y + glyph.OffsetY) - origin.Y;
+ drawCallback(
+ _texture,
+ new Vector2(
+ (float)(((cos * ox) - (sin * oy)) + origin.X),
+ (float)((sin * ox) + (cos * oy) + origin.Y)),
+ glyph.Subrect,
+ color, rotation, Vector2.Zero, 1.0f, opacity, effects, layerDepth);
+
+ x += glyph.XAdvance + SpacingX;
+ }
+ break;
+ }
+
+ key <<= 16;
+ }
+ }
+ }
+
+#if NETSTANDARD2_1
+ internal void Draw(DrawFont drawCallback,
+ ReadOnlySpan text,
+ int start,
+ int end,
+ in Vector2 position,
+ in Size2F dimension,
+ in Color color,
+ float rotation,
+ in Vector2 origin,
+ float opacity,
+ TextureEffects effects,
+ float layerDepth)
+#else
+ internal void Draw(DrawFont drawCallback,
+ string text,
+ int start,
+ int end,
+ in Vector2 position,
+ in Size2F dimension,
+ in Color color,
+ float rotation,
+ in Vector2 origin,
+ float opacity,
+ TextureEffects effects,
+ float layerDepth)
+#endif
+ {
+ if (end <= start || end > text.Length) { end = text.Length; }
+
+ float x = 0;
+ float y = 0;
+
+ int key = 0;
+ if (rotation == 0)
+ {
+ for (int i = start; i < end; i++)
+ {
+ char c = text[i];
+ switch (c)
+ {
+ case '\r':
+ {
+ key |= c;
+ continue;
+ }
+ case '\n':
+ {
+ key = 0;
+ x = 0;
+ y += LineSpacing;
+ }
+ break;
+ default:
+ {
+ if (!_glyphs.TryGetValue(c, out Glyph glyph))
+ {
+ if (IgnoreUnknownCharacters)
+ {
+ continue;
+ }
+
+ glyph = _defaultGlyph;
+ }
+ key |= c;
+
+ float dx = glyph.OffsetX;
+ if (Kernings.TryGetValue(key, out Kerning kerning))
+ {
+ dx += kerning.Offset;
+ }
+
+ if (x + dx + glyph.Subrect.Width > dimension.Width) { return; }
+ if (y + glyph.OffsetY + glyph.Subrect.Height > dimension.Height) { return; }
+
+ drawCallback(
+ _texture,
+ new Vector2(position.X + x + dx, position.Y + y + glyph.OffsetY),
+ glyph.Subrect, color, rotation, origin,
+ 1.0f, opacity, effects, layerDepth);
+
+ x += glyph.XAdvance + SpacingX;
+ }
+ break;
+ }
+
+ key <<= 16;
+ }
+ }
+ else
+ {
+ double cos = Math.Cos(rotation);
+ double sin = Math.Sin(rotation);
+
+ for (int i = start; i < end; i++)
+ {
+ char c = text[i];
+ switch (c)
+ {
+ case '\r':
+ {
+ key |= c;
+ continue;
+ }
+ case '\n':
+ {
+ key = 0;
+ x = 0;
+ y += LineSpacing;
+ }
+ break;
+ default:
+ {
+ if (!_glyphs.TryGetValue(c, out Glyph glyph))
+ {
+ if (IgnoreUnknownCharacters)
+ {
+ continue;
+ }
+
+ glyph = _defaultGlyph;
+ }
+ key |= c;
+
+ float dx = glyph.OffsetX;
+ if (Kernings.TryGetValue(key, out Kerning kerning))
+ {
+ dx += kerning.Offset;
+ }
+
+ if (x + dx + glyph.Subrect.Width > dimension.Width) { return; }
+ if (y + glyph.OffsetY + glyph.Subrect.Height > dimension.Height) { return; }
+
+ float ox = (position.X + x + dx) - origin.X;
+ float oy = (position.Y + y + glyph.OffsetY) - origin.Y;
+ drawCallback(
+ _texture,
+ new Vector2(
+ (float)(((cos * ox) - (sin * oy)) + origin.X),
+ (float)((sin * ox) + (cos * oy) + origin.Y)),
+ glyph.Subrect, color, rotation, Vector2.Zero,
+ 1.0f, opacity, effects, layerDepth);
+
+ x += glyph.XAdvance + SpacingX;
+ }
+ break;
+ }
+
+ key <<= 16;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Graphics/SpriteFont.cs b/src/Exomia.Framework/Graphics/SpriteFont.cs
index 89cb0b98..0ee162c3 100644
--- a/src/Exomia.Framework/Graphics/SpriteFont.cs
+++ b/src/Exomia.Framework/Graphics/SpriteFont.cs
@@ -10,7 +10,6 @@
using System;
using System.Collections.Generic;
-using System.Text;
using Exomia.Framework.Content;
using Exomia.Framework.ContentSerialization;
using SharpDX;
@@ -21,9 +20,20 @@ namespace Exomia.Framework.Graphics
/// A sprite font. This class cannot be inherited.
///
[ContentReadable(typeof(SpriteFontContentReader))]
- [ContentSerializable(typeof(SpriteFontCR), typeof(SpriteFontCW))]
- public sealed class SpriteFont : IDisposable
+ [ContentSerializable(typeof(SpriteFontContentSerializationReader), typeof(SpriteFontContentSerializationWriter))]
+ public sealed partial class SpriteFont : IDisposable
{
+ internal delegate void DrawFont(Texture texture,
+ in Vector2 position,
+ in Rectangle? sourceRectangle,
+ in Color color,
+ float rotation,
+ in Vector2 origin,
+ float scale,
+ float opacity,
+ TextureEffects effects,
+ float layerDepth);
+
private Glyph _defaultGlyph;
private Dictionary _glyphs;
private Texture _texture;
@@ -172,960 +182,10 @@ public SpriteFont()
_texture = Texture.Empty;
}
- ///
- /// Finalizes an instance of the class.
- ///
- ~SpriteFont()
- {
- Dispose(false);
- }
-
- ///
- /// A glyph.
- ///
- [ContentSerializable(typeof(SpriteFontGlyphCR), typeof(SpriteFontGlyphCW))]
- public struct Glyph
- {
- ///
- /// The character.
- ///
- public int Character;
-
- ///
- /// The subrect.
- ///
- public Rectangle Subrect;
-
- ///
- /// The offset x coordinate.
- ///
- public int OffsetX;
-
- ///
- /// The offset y coordinate.
- ///
- public int OffsetY;
-
- ///
- /// The advance.
- ///
- public int XAdvance;
- }
-
- ///
- /// A kerning.
- ///
- [ContentSerializable(typeof(SpriteFontKerningCR), typeof(SpriteFontKerningCW))]
- public struct Kerning
- {
- ///
- /// The first.
- ///
- public int First;
-
- ///
- /// The second.
- ///
- public int Second;
-
- ///
- /// The offset.
- ///
- public int Offset;
- }
-
- ///
- /// Draw font.
- ///
- /// The texture.
- /// The position.
- /// Source rectangle.
- /// The color.
- /// The rotation.
- /// The origin.
- /// The scale.
- /// The opacity.
- /// The effects.
- /// Depth of the layer.
- internal delegate void DrawFont(Texture texture,
- in Vector2 position,
- in Rectangle? sourceRectangle,
- in Color color,
- float rotation,
- in Vector2 origin,
- float scale,
- float opacity,
- SpriteEffects effects,
- float layerDepth);
-
- #region String
-
- ///
- /// Measure text.
- ///
- /// The text.
- ///
- /// A Vector2.
- ///
- public Vector2 MeasureText(string text)
- {
- return MeasureText(text, 0, text.Length);
- }
-
- ///
- /// Measure text.
- ///
- /// The text.
- /// The start.
- /// The end.
- ///
- /// A Vector2.
- ///
- public Vector2 MeasureText(string text, int start, int end)
- {
- Vector2 size = Vector2.Zero;
-
- if (start >= end) { return size; }
- if (end > text.Length) { end = text.Length; }
- if (start < 0) { start = 0; }
-
- float x = 0;
- float y = 0;
-
- int key = 0;
-
- for (int i = start; i < end; i++)
- {
- char c = text[i];
- switch (c)
- {
- case '\r':
- {
- key |= c;
- continue;
- }
- case '\n':
- {
- key = 0;
- x = 0;
- y += LineSpacing;
- }
- break;
- default:
- {
- if (!_glyphs.TryGetValue(c, out Glyph glyph))
- {
- if (IgnoreUnknownCharacters)
- {
- continue;
- }
-
- glyph = _defaultGlyph;
- }
- key |= c;
-
- float dx = glyph.OffsetX;
- if (Kernings.TryGetValue(key, out Kerning kerning))
- {
- dx += kerning.Offset;
- }
-
- float nextX = x + glyph.XAdvance + SpacingX;
-
- float h = y + LineSpacing;
- if (nextX + dx > size.X)
- {
- size.X = nextX;
- }
- if (h > size.Y)
- {
- size.Y = h;
- }
-
- x = nextX;
- }
- break;
- }
-
- key <<= 16;
- }
-
- return size;
- }
-
- ///
- /// Determines which item (if any) has been hit.
- ///
- /// The text.
- /// The start.
- /// The end.
- /// The position.
- /// The position.
- ///
- /// An int.
- ///
- public int HitTest(string text, int start, int end, float xPos, float yPos)
- {
- if (start >= end) { return end; }
- if (end > text.Length) { end = text.Length; }
- if (start < 0) { start = 0; }
-
- if (xPos < 0) { return -1; }
- if (yPos < 0) { return -1; }
-
- float x = 0;
- float y = 0;
-
- int key = 0;
-
- for (int i = start; i < end; i++)
- {
- char c = text[i];
- switch (c)
- {
- case '\r':
- {
- key |= c;
- continue;
- }
- case '\n':
- {
- key = 0;
- x = 0;
- y += LineSpacing;
- }
- break;
- default:
- {
- if (!_glyphs.TryGetValue(c, out Glyph glyph))
- {
- if (IgnoreUnknownCharacters)
- {
- continue;
- }
- glyph = _defaultGlyph;
- }
- key |= c;
-
- float dx = glyph.OffsetX;
- if (Kernings.TryGetValue(key, out Kerning kerning))
- {
- dx += kerning.Offset;
- }
-
- float nextX = x + glyph.XAdvance + SpacingX;
- float h = y + LineSpacing;
-
- if (xPos >= x && xPos <= nextX + dx && yPos <= h && yPos >= y)
- {
- if (xPos < (x + nextX + dx) * 0.5f) { return i; }
- return i + 1;
- }
- x = nextX;
- }
- break;
- }
- key <<= 16;
- }
-
- return end;
- }
-
- ///
- /// Draws.
- ///
- /// The draw callback.
- /// The text.
- /// The position.
- /// The color.
- /// The rotation.
- /// The origin.
- /// The opacity.
- /// The effects.
- /// Depth of the layer.
- internal void Draw(DrawFont drawCallback,
- string text,
- in Vector2 position,
- in Color color,
- float rotation,
- in Vector2 origin,
- float opacity,
- SpriteEffects effects,
- float layerDepth)
- {
- float x = 0;
- float y = 0;
-
- int key = 0;
-
- int l = text.Length;
- for (int i = 0; i < l; i++)
- {
- char c = text[i];
- switch (c)
- {
- case '\r':
- {
- key |= c;
- continue;
- }
- case '\n':
- {
- key = 0;
- x = 0;
- y += LineSpacing;
- }
- break;
- default:
- {
- if (!_glyphs.TryGetValue(c, out Glyph glyph))
- {
- if (IgnoreUnknownCharacters)
- {
- continue;
- }
-
- glyph = _defaultGlyph;
- }
- key |= c;
-
- float dx = glyph.OffsetX;
- if (Kernings.TryGetValue(key, out Kerning kerning))
- {
- dx += kerning.Offset;
- }
-
- drawCallback(
- _texture,
- new Vector2(position.X + x + dx, position.Y + y + glyph.OffsetY),
- glyph.Subrect,
- color, rotation, origin, 1.0f, opacity, effects, layerDepth);
-
- x += glyph.XAdvance + SpacingX;
- }
- break;
- }
-
- key <<= 16;
- }
- }
-
- ///
- /// Draws.
- ///
- /// The draw callback.
- /// The text.
- /// The start.
- /// The end.
- /// The position.
- /// The color.
- /// The rotation.
- /// The origin.
- /// The opacity.
- /// The effects.
- /// Depth of the layer.
- internal void Draw(DrawFont drawCallback,
- string text,
- int start,
- int end,
- in Vector2 position,
- in Color color,
- float rotation,
- in Vector2 origin,
- float opacity,
- SpriteEffects effects,
- float layerDepth)
- {
- if (end <= start || end > text.Length) { end = text.Length; }
-
- float x = 0;
- float y = 0;
-
- int key = 0;
-
- for (int i = start; i < end; i++)
- {
- char c = text[i];
- switch (c)
- {
- case '\r':
- {
- key |= c;
- continue;
- }
- case '\n':
- {
- key = 0;
- x = 0;
- y += LineSpacing;
- }
- break;
- default:
- {
- if (!_glyphs.TryGetValue(c, out Glyph glyph))
- {
- if (IgnoreUnknownCharacters)
- {
- continue;
- }
-
- glyph = _defaultGlyph;
- }
- key |= c;
-
- float dx = glyph.OffsetX;
- if (Kernings.TryGetValue(key, out Kerning kerning))
- {
- dx += kerning.Offset;
- }
-
- drawCallback(
- _texture,
- new Vector2(position.X + x + dx, position.Y + y + glyph.OffsetY),
- glyph.Subrect,
- color, rotation, origin, 1.0f, opacity, effects, layerDepth);
-
- x += glyph.XAdvance + SpacingX;
- }
- break;
- }
-
- key <<= 16;
- }
- }
-
- ///
- /// Draws.
- ///
- /// The draw callback.
- /// The text.
- /// The start.
- /// The end.
- /// The position.
- /// The dimension.
- /// The color.
- /// The rotation.
- /// The origin.
- /// The opacity.
- /// The effects.
- /// Depth of the layer.
- internal void Draw(DrawFont drawCallback,
- string text,
- int start,
- int end,
- in Vector2 position,
- in Size2F dimension,
- in Color color,
- float rotation,
- in Vector2 origin,
- float opacity,
- SpriteEffects effects,
- float layerDepth)
- {
- if (end <= start || end > text.Length) { end = text.Length; }
-
- float x = 0;
- float y = 0;
-
- int key = 0;
-
- for (int i = start; i < end; i++)
- {
- char c = text[i];
- switch (c)
- {
- case '\r':
- {
- key |= c;
- continue;
- }
- case '\n':
- {
- key = 0;
- x = 0;
- y += LineSpacing;
- }
- break;
- default:
- {
- if (!_glyphs.TryGetValue(c, out Glyph glyph))
- {
- if (IgnoreUnknownCharacters)
- {
- continue;
- }
-
- glyph = _defaultGlyph;
- }
- key |= c;
-
- float dx = glyph.OffsetX;
- if (Kernings.TryGetValue(key, out Kerning kerning))
- {
- dx += kerning.Offset;
- }
-
- if (x + dx + glyph.Subrect.Width > dimension.Width) { return; }
- if (y + glyph.OffsetY + glyph.Subrect.Height > dimension.Height) { return; }
-
- drawCallback(
- _texture,
- new Vector2(position.X + x + dx, position.Y + y + glyph.OffsetY),
- glyph.Subrect,
- color, rotation, origin, 1.0f, opacity, effects, layerDepth);
-
- x += glyph.XAdvance + SpacingX;
- }
- break;
- }
-
- key <<= 16;
- }
- }
-
- #endregion
-
- #region StringBuilder
-
- ///
- /// Measure text.
- ///
- /// The text.
- ///
- /// A Vector2.
- ///
- public Vector2 MeasureText(StringBuilder text)
- {
- return MeasureText(text, 0, text.Length);
- }
-
- ///
- /// Measure text.
- ///
- /// The text.
- /// The start.
- /// The end.
- ///
- /// A Vector2.
- ///
- public Vector2 MeasureText(StringBuilder text, int start, int end)
- {
- Vector2 size = Vector2.Zero;
-
- if (start >= end) { return size; }
- if (end > text.Length) { end = text.Length; }
- if (start < 0) { start = 0; }
-
- float x = 0;
- float y = 0;
-
- int key = 0;
-
- for (int i = start; i < end; i++)
- {
- char c = text[i];
- switch (c)
- {
- case '\r':
- {
- key |= c;
- continue;
- }
- case '\n':
- {
- key = 0;
- x = 0;
- y += LineSpacing;
- }
- break;
- default:
- {
- if (!_glyphs.TryGetValue(c, out Glyph glyph))
- {
- if (IgnoreUnknownCharacters)
- {
- continue;
- }
-
- glyph = _defaultGlyph;
- }
- key |= c;
-
- float dx = glyph.OffsetX;
- if (Kernings.TryGetValue(key, out Kerning kerning))
- {
- dx += kerning.Offset;
- }
-
- float nextX = x + glyph.XAdvance + SpacingX;
-
- float h = y + LineSpacing;
- if (nextX + dx > size.X)
- {
- size.X = nextX;
- }
- if (h > size.Y)
- {
- size.Y = h;
- }
-
- x = nextX;
- }
- break;
- }
-
- key <<= 16;
- }
-
- return size;
- }
-
- ///
- /// Determines which item (if any) has been hit.
- ///
- /// The text.
- /// The start.
- /// The end.
- /// The position.
- /// The position.
- ///
- /// An int.
- ///
- public int HitTest(StringBuilder text, int start, int end, float xPos, float yPos)
- {
- if (start >= end) { return end; }
- if (end > text.Length) { end = text.Length; }
- if (start < 0) { start = 0; }
-
- if (xPos < 0) { return -1; }
- if (yPos < 0) { return -1; }
-
- float x = 0;
- float y = 0;
-
- int key = 0;
-
- for (int i = start; i < end; i++)
- {
- char c = text[i];
- switch (c)
- {
- case '\r':
- {
- key |= c;
- continue;
- }
- case '\n':
- {
- key = 0;
- x = 0;
- y += LineSpacing;
- }
- break;
- default:
- {
- if (!_glyphs.TryGetValue(c, out Glyph glyph))
- {
- if (IgnoreUnknownCharacters)
- {
- continue;
- }
- glyph = _defaultGlyph;
- }
- key |= c;
-
- float dx = glyph.OffsetX;
- if (Kernings.TryGetValue(key, out Kerning kerning))
- {
- dx += kerning.Offset;
- }
-
- float nextX = x + glyph.XAdvance + SpacingX;
- float h = y + LineSpacing;
-
- if (xPos >= x && xPos <= nextX + dx && yPos <= h && yPos >= y)
- {
- if (xPos < (x + nextX + dx) * 0.5f) { return i; }
- return i + 1;
- }
- x = nextX;
- }
- break;
- }
- key <<= 16;
- }
-
- return end;
- }
-
- ///
- /// Draws.
- ///
- /// The draw callback.
- /// The text.
- /// The position.
- /// The color.
- /// The rotation.
- /// The origin.
- /// The opacity.
- /// The effects.
- /// Depth of the layer.
- internal void Draw(DrawFont drawCallback,
- StringBuilder text,
- in Vector2 position,
- in Color color,
- float rotation,
- in Vector2 origin,
- float opacity,
- SpriteEffects effects,
- float layerDepth)
- {
- float x = 0;
- float y = 0;
-
- int key = 0;
-
- int l = text.Length;
- for (int i = 0; i < l; i++)
- {
- char c = text[i];
- switch (c)
- {
- case '\r':
- {
- key |= c;
- continue;
- }
- case '\n':
- {
- key = 0;
- x = 0;
- y += LineSpacing;
- break;
- }
- default:
- {
- if (!_glyphs.TryGetValue(c, out Glyph glyph))
- {
- if (IgnoreUnknownCharacters)
- {
- continue;
- }
-
- glyph = _defaultGlyph;
- }
- key |= c;
-
- float dx = glyph.OffsetX;
- if (Kernings.TryGetValue(key, out Kerning kerning))
- {
- dx += kerning.Offset;
- }
-
- drawCallback(
- _texture, new Vector2(position.X + x + dx, position.Y + y + glyph.OffsetY),
- glyph.Subrect,
- color, rotation, origin, 1.0f, opacity, effects, layerDepth);
-
- x += glyph.XAdvance + SpacingX;
- break;
- }
- }
-
- key <<= 16;
- }
- }
-
- ///
- /// Draws.
- ///
- /// The draw callback.
- /// The text.
- /// The start.
- /// The end.
- /// The position.
- /// The color.
- /// The rotation.
- /// The origin.
- /// The opacity.
- /// The effects.
- /// Depth of the layer.
- internal void Draw(DrawFont drawCallback,
- StringBuilder text,
- int start,
- int end,
- in Vector2 position,
- in Color color,
- float rotation,
- in Vector2 origin,
- float opacity,
- SpriteEffects effects,
- float layerDepth)
- {
- if (end <= start || end > text.Length) { end = text.Length; }
-
- float x = 0;
- float y = 0;
-
- int key = 0;
-
- for (int i = start; i < end; i++)
- {
- char c = text[i];
- switch (c)
- {
- case '\r':
- {
- key |= c;
- continue;
- }
- case '\n':
- {
- key = 0;
- x = 0;
- y += LineSpacing;
- }
- break;
- default:
- {
- if (!_glyphs.TryGetValue(c, out Glyph glyph))
- {
- if (IgnoreUnknownCharacters)
- {
- continue;
- }
-
- glyph = _defaultGlyph;
- }
- key |= c;
-
- float dx = glyph.OffsetX;
- if (Kernings.TryGetValue(key, out Kerning kerning))
- {
- dx += kerning.Offset;
- }
-
- drawCallback(
- _texture,
- new Vector2(position.X + x + dx, position.Y + y + glyph.OffsetY),
- glyph.Subrect,
- color, rotation, origin, 1.0f, opacity, effects, layerDepth);
-
- x += glyph.XAdvance + SpacingX;
- }
- break;
- }
-
- key <<= 16;
- }
- }
-
- ///
- /// Draws.
- ///
- /// The draw callback.
- /// The text.
- /// The start.
- /// The end.
- /// The position.
- /// The dimension.
- /// The color.
- /// The rotation.
- /// The origin.
- /// The opacity.
- /// The effects.
- /// Depth of the layer.
- internal void Draw(DrawFont drawCallback,
- StringBuilder text,
- int start,
- int end,
- in Vector2 position,
- in Size2F dimension,
- in Color color,
- float rotation,
- in Vector2 origin,
- float opacity,
- SpriteEffects effects,
- float layerDepth)
- {
- if (end <= start || end > text.Length) { end = text.Length; }
-
- float x = 0;
- float y = 0;
-
- int key = 0;
-
- for (int i = start; i < end; i++)
- {
- char c = text[i];
- switch (c)
- {
- case '\r':
- {
- key |= c;
- continue;
- }
- case '\n':
- {
- key = 0;
- x = 0;
- y += LineSpacing;
- }
- break;
- default:
- {
- if (!_glyphs.TryGetValue(c, out Glyph glyph))
- {
- if (IgnoreUnknownCharacters)
- {
- continue;
- }
-
- glyph = _defaultGlyph;
- }
- key |= c;
-
- float dx = glyph.OffsetX;
- if (Kernings.TryGetValue(key, out Kerning kerning))
- {
- dx += kerning.Offset;
- }
-
- if (x + dx + glyph.Subrect.Width > dimension.Width) { return; }
- if (y + glyph.OffsetY + glyph.Subrect.Height > dimension.Height) { return; }
-
- drawCallback(
- _texture,
- new Vector2(position.X + x + dx, position.Y + y + glyph.OffsetY),
- glyph.Subrect,
- color, rotation, origin, 1.0f, opacity, effects, layerDepth);
-
- x += glyph.XAdvance + SpacingX;
- }
- break;
- }
-
- key <<= 16;
- }
- }
-
- #endregion
-
#region IDisposable Support
-
- ///
- /// True if disposed.
- ///
+
private bool _disposed;
-
- ///
- /// Releases the unmanaged resources used by the Exomia.Framework.Graphics.SpriteFont and
- /// optionally releases the managed resources.
- ///
- ///
- /// True to release both managed and unmanaged resources; false to
- /// release only unmanaged resources.
- ///
+
private void Dispose(bool disposing)
{
if (!_disposed)
@@ -1144,6 +204,14 @@ private void Dispose(bool disposing)
}
}
+ ///
+ /// Finalizes an instance of the class.
+ ///
+ ~SpriteFont()
+ {
+ Dispose(false);
+ }
+
///
public void Dispose()
{
diff --git a/src/Exomia.Framework/Graphics/SpriteFontContentReader.cs b/src/Exomia.Framework/Graphics/SpriteFontContentReader.cs
index e1170373..eb141197 100644
--- a/src/Exomia.Framework/Graphics/SpriteFontContentReader.cs
+++ b/src/Exomia.Framework/Graphics/SpriteFontContentReader.cs
@@ -15,16 +15,13 @@
namespace Exomia.Framework.Graphics
{
- ///
- /// A sprite font content reader. This class cannot be inherited.
- ///
sealed class SpriteFontContentReader : IContentReader
{
///
public object? ReadContent(IContentManager contentManager, ref ContentReaderParameters parameters)
{
SpriteFont font = ContentSerializer.Read(parameters.Stream);
- if (font.ImageData == null)
+ if (font.ImageData.Length <= 0)
{
return null;
}
@@ -34,9 +31,11 @@ sealed class SpriteFontContentReader : IContentReader
try
{
- using MemoryStream ms = new MemoryStream(font.ImageData) { Position = 0 };
- font.Texture = Texture.Load(graphicsDevice.Device, ms) ??
- throw new NullReferenceException($"{nameof(font.Texture)}");
+ using (MemoryStream ms = new MemoryStream(font.ImageData) { Position = 0 })
+ {
+ font.Texture = Texture.Load(graphicsDevice.Device, ms) ??
+ throw new NullReferenceException($"{nameof(font.Texture)}");
+ }
}
catch { return null; }
diff --git a/src/Exomia.Framework/Graphics/SpriteEffects.cs b/src/Exomia.Framework/Graphics/TextureEffects.cs
similarity index 91%
rename from src/Exomia.Framework/Graphics/SpriteEffects.cs
rename to src/Exomia.Framework/Graphics/TextureEffects.cs
index f0c735df..5f6759e5 100644
--- a/src/Exomia.Framework/Graphics/SpriteEffects.cs
+++ b/src/Exomia.Framework/Graphics/TextureEffects.cs
@@ -13,10 +13,10 @@
namespace Exomia.Framework.Graphics
{
///
- /// Bitfield of flags for specifying SpriteEffects.
+ /// Bitfield of flags for specifying TextureEffects.
///
[Flags]
- public enum SpriteEffects
+ public enum TextureEffects
{
///
/// A binary constant representing the none flag.
diff --git a/src/Exomia.Framework/Graphics/Textures.cs b/src/Exomia.Framework/Graphics/Textures.cs
new file mode 100644
index 00000000..0434491c
--- /dev/null
+++ b/src/Exomia.Framework/Graphics/Textures.cs
@@ -0,0 +1,85 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using System;
+using System.IO;
+
+namespace Exomia.Framework.Graphics
+{
+ ///
+ /// The built-in textures. This class cannot be inherited.
+ ///
+ public class Textures : IDisposable
+ {
+ private const string WHITE_TEXTURE_BASE64 =
+ "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+ip1sAAAAASUVORK5CYII=";
+
+ private readonly Texture _white;
+
+ ///
+ /// Built-in white texture object with size of 1x1 px.
+ ///
+ ///
+ /// The white texture.
+ ///
+ public Texture White
+ {
+ get { return _white!; }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The graphics device.
+ /// Thrown when a value was unexpectedly null.
+ internal Textures(IGraphicsDevice graphicsDevice)
+ {
+ using (MemoryStream ms = new MemoryStream(Convert.FromBase64String(WHITE_TEXTURE_BASE64)))
+ {
+ _white = Texture.Load(graphicsDevice.Device, ms) ??
+ throw new NullReferenceException($"{nameof(White)}");
+ }
+ }
+
+ #region IDisposable Support
+
+ private bool _disposed;
+
+ private void Dispose(bool disposing)
+ {
+ if (!_disposed)
+ {
+ if (disposing)
+ {
+ _white.Dispose();
+ }
+
+ _disposed = true;
+ }
+ }
+
+ ///
+ ~Textures()
+ {
+ Dispose(false);
+ }
+
+ ///
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged/managed resources.
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/src/Exomia.Framework/IDrawable.cs b/src/Exomia.Framework/IDrawable.cs
index 4230cddc..5045703a 100644
--- a/src/Exomia.Framework/IDrawable.cs
+++ b/src/Exomia.Framework/IDrawable.cs
@@ -38,7 +38,7 @@ public interface IDrawable
///
/// Gets a value indicating whether the method should be called by
- /// .
+ /// the .
///
///
/// true if this drawable component is visible; otherwise, false.
diff --git a/src/Exomia.Framework/Input/InputState.cs b/src/Exomia.Framework/Input/InputState.cs
new file mode 100644
index 00000000..11063622
--- /dev/null
+++ b/src/Exomia.Framework/Input/InputState.cs
@@ -0,0 +1,28 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+namespace Exomia.Framework.Input
+{
+ ///
+ /// Values that represent EventAction.
+ ///
+ public enum EventAction
+ {
+ ///
+ /// An enum constant representing the continue option.
+ ///
+ Continue = 0,
+
+ ///
+ /// An enum constant representing the stop propagation option.
+ ///
+ StopPropagation = 1,
+ }
+}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Input/KeyEventHandler.cs b/src/Exomia.Framework/Input/KeyEventHandler.cs
index ac1fe9b7..357c7d63 100644
--- a/src/Exomia.Framework/Input/KeyEventHandler.cs
+++ b/src/Exomia.Framework/Input/KeyEventHandler.cs
@@ -18,25 +18,25 @@ namespace Exomia.Framework.Input
/// The key value.
/// The modifiers.
///
- /// true if the key event was handled; false otherwise.
+ /// An .
///
- public delegate bool KeyEventHandler(int keyValue, KeyModifier modifiers);
+ public delegate EventAction KeyEventHandler(int keyValue, KeyModifier modifiers);
///
/// Delegate for handling key press events.
///
/// The key.
///
- /// true if the key press event was handled; false otherwise.
+ /// An .
///
- public delegate bool KeyPressEventHandler(char key);
+ public delegate EventAction KeyPressEventHandler(char key);
///
/// Delegate for handling raw key events.
///
/// The message.
///
- /// true if the message event was handled; false otherwise.
+ /// An .
///
- public delegate bool RawKeyEventHandler(in Message message);
+ public delegate EventAction RawKeyEventHandler(in Message message);
}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Input/MouseEventHandler.cs b/src/Exomia.Framework/Input/MouseEventHandler.cs
index a233656b..c7d25cb6 100644
--- a/src/Exomia.Framework/Input/MouseEventHandler.cs
+++ b/src/Exomia.Framework/Input/MouseEventHandler.cs
@@ -15,7 +15,7 @@ namespace Exomia.Framework.Input
///
/// In mouse event information.
///
- /// true if the mouse event was handled; false otherwise.
+ /// An .
///
- public delegate bool MouseEventHandler(in MouseEventArgs mouseEventArgs);
+ public delegate EventAction MouseEventHandler(in MouseEventArgs mouseEventArgs);
}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Mathematics/Arc2.cs b/src/Exomia.Framework/Mathematics/Arc2.cs
new file mode 100644
index 00000000..5543a59e
--- /dev/null
+++ b/src/Exomia.Framework/Mathematics/Arc2.cs
@@ -0,0 +1,205 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using System;
+using System.Globalization;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using SharpDX;
+
+namespace Exomia.Framework.Mathematics
+{
+ ///
+ /// A 2d arc.
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 20)]
+ public readonly struct Arc2 : IFormattable
+ {
+ ///
+ /// The x value.
+ ///
+ public readonly float X; //Note: do not reorder this field, unless you know what you are doing.
+
+ ///
+ /// The y value.
+ ///
+ public readonly float Y; //Note: do not reorder this field, unless you know what you are doing.
+
+ ///
+ /// The radius.
+ ///
+ public readonly float Radius; //Note: do not reorder this field, unless you know what you are doing.
+
+ ///
+ /// The start angle in radians.
+ ///
+ public readonly float Start; //Note: do not reorder this field, unless you know what you are doing.
+
+ ///
+ /// The end angle in radians.
+ ///
+ public readonly float End; //Note: do not reorder this field, unless you know what you are doing.
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The x value.
+ /// The y value.
+ /// The radius.
+ ///
+ /// (Optional)
+ /// The start angle in radians.
+ ///
+ ///
+ /// (Optional)
+ /// The end angle in radians.
+ ///
+ public Arc2(float x, float y, float radius, float start = 0, float end = MathUtil.TwoPi)
+ {
+ X = x;
+ Y = y;
+ Radius = radius;
+ Start = start;
+ End = end;
+ }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The center.
+ /// The radius.
+ ///
+ /// (Optional)
+ /// The start angle in radians.
+ ///
+ ///
+ /// (Optional)
+ /// The end angle in radians.
+ ///
+ public Arc2(VectorI2 center, float radius, float start = 0, float end = MathUtil.TwoPi)
+ : this(center.X, center.Y, radius, start, end) { }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The center.
+ /// The radius.
+ ///
+ /// (Optional)
+ /// The start angle in radians.
+ ///
+ ///
+ /// (Optional)
+ /// The end angle in radians.
+ ///
+ public Arc2(Vector2 center, float radius, float start = 0, float end = MathUtil.TwoPi)
+ : this(center.X, center.Y, radius, start, end) { }
+
+ ///
+ /// Determines whether the specified is equal to this instance.
+ ///
+ /// The to compare with this instance.
+ ///
+ /// true if the specified is equal to this instance; false otherwise.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool Equals(in Arc2 other)
+ {
+ // ReSharper disable CompareOfFloatsByEqualityOperator
+ return
+ X == other.X &&
+ Y == other.Y &&
+ Radius == other.Radius &&
+ Start == other.Start &&
+ End == other.End;
+
+ // ReSharper restore CompareOfFloatsByEqualityOperator
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public override bool Equals(object value)
+ {
+ return value is Arc2 other && Equals(in other);
+ }
+
+ ///
+ public override int GetHashCode()
+ {
+ return (((((((X.GetHashCode() * 307) ^ Y.GetHashCode()) * 521) ^ Radius.GetHashCode()) * 853) ^
+ Start.GetHashCode()) * 443) ^ End.GetHashCode();
+ }
+
+ ///
+ public override string ToString()
+ {
+ return string.Format(
+ CultureInfo.CurrentCulture,
+ "X:{0} Y:{1} | Radius:{2}, Start:{3}, End:{4}", X, Y, Radius, Start, End);
+ }
+
+ ///
+ /// Returns a that represents this instance.
+ ///
+ /// The format.
+ ///
+ /// A that represents this instance.
+ ///
+ public string ToString(string? format)
+ {
+ if (format == null)
+ {
+ return ToString();
+ }
+
+ return string.Format(
+ CultureInfo.CurrentCulture,
+ "X:{0} Y:{1} | Radius:{2}, Start:{3}, End:{4}",
+ X.ToString(format, CultureInfo.CurrentCulture),
+ Y.ToString(format, CultureInfo.CurrentCulture),
+ Radius.ToString(format, CultureInfo.CurrentCulture),
+ Start.ToString(format, CultureInfo.CurrentCulture),
+ End.ToString(format, CultureInfo.CurrentCulture));
+ }
+
+ ///
+ /// Returns a that represents this instance.
+ ///
+ /// The format provider.
+ ///
+ /// A that represents this instance.
+ ///
+ public string ToString(IFormatProvider formatProvider)
+ {
+ return string.Format(
+ formatProvider,
+ "X:{0} Y:{1} | Radius:{2}, Start:{3}, End:{4}", X, Y, Radius, Start, End);
+ }
+
+ ///
+ public string ToString(string? format, IFormatProvider formatProvider)
+ {
+ if (format == null)
+ {
+ return ToString(formatProvider);
+ }
+
+ return string.Format(
+ formatProvider,
+ "X:{0} Y:{1} | Radius:{2}, Start:{3}, End:{4}",
+ X.ToString(format, formatProvider),
+ Y.ToString(format, formatProvider),
+ Radius.ToString(format, formatProvider),
+ Start.ToString(format, formatProvider),
+ End.ToString(format, formatProvider));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Mathematics/Circle2.cs b/src/Exomia.Framework/Mathematics/Circle2.cs
new file mode 100644
index 00000000..35352916
--- /dev/null
+++ b/src/Exomia.Framework/Mathematics/Circle2.cs
@@ -0,0 +1,162 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using System;
+using System.Globalization;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using SharpDX;
+
+namespace Exomia.Framework.Mathematics
+{
+ ///
+ /// A 2d circle.
+ ///
+ ///
+ [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 12)]
+ public readonly struct Circle2 : IFormattable
+ {
+ ///
+ /// The x value.
+ ///
+ public readonly float X; //Note: do not reorder this field, unless you know what you are doing.
+
+ ///
+ /// The y value.
+ ///
+ public readonly float Y; //Note: do not reorder this field, unless you know what you are doing.
+
+ ///
+ /// The radius.
+ ///
+ public readonly float Radius; //Note: do not reorder this field, unless you know what you are doing.
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The x value.
+ /// The y value.
+ /// The radius.
+ public Circle2(float x, float y, float radius)
+ {
+ X = x;
+ Y = y;
+ Radius = radius;
+ }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The center.
+ /// The radius.
+ public Circle2(VectorI2 center, float radius)
+ : this(center.X, center.Y, radius) { }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The center.
+ /// The radius.
+ public Circle2(Vector2 center, float radius)
+ : this(center.X, center.Y, radius) { }
+
+ ///
+ /// Determines whether the specified is equal to this instance.
+ ///
+ /// The to compare with this instance.
+ ///
+ /// true if the specified is equal to this instance; false otherwise.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool Equals(in Circle2 other)
+ {
+ // ReSharper disable CompareOfFloatsByEqualityOperator
+ return
+ X == other.X &&
+ Y == other.Y &&
+ Radius == other.Radius;
+
+ // ReSharper restore CompareOfFloatsByEqualityOperator
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public override bool Equals(object value)
+ {
+ return value is Circle2 other && Equals(in other);
+ }
+
+ ///
+ public override int GetHashCode()
+ {
+ return (((X.GetHashCode() * 307) ^ Y.GetHashCode()) * 521) ^ Radius.GetHashCode();
+ }
+
+ ///
+ public override string ToString()
+ {
+ return string.Format(
+ CultureInfo.CurrentCulture,
+ "X:{0} Y:{1} | Radius:{2}", X, Y, Radius);
+ }
+
+ ///
+ /// Returns a that represents this instance.
+ ///
+ /// The format.
+ ///
+ /// A that represents this instance.
+ ///
+ public string ToString(string? format)
+ {
+ if (format == null)
+ {
+ return ToString();
+ }
+
+ return string.Format(
+ CultureInfo.CurrentCulture,
+ "X:{0} Y:{1} | Radius:{2}",
+ X.ToString(format, CultureInfo.CurrentCulture),
+ Y.ToString(format, CultureInfo.CurrentCulture),
+ Radius.ToString(format, CultureInfo.CurrentCulture));
+ }
+
+ ///
+ /// Returns a that represents this instance.
+ ///
+ /// The format provider.
+ ///
+ /// A that represents this instance.
+ ///
+ public string ToString(IFormatProvider formatProvider)
+ {
+ return string.Format(
+ formatProvider,
+ "X:{0} Y:{1} | Radius:{2}", X, Y, Radius);
+ }
+
+ ///
+ public string ToString(string? format, IFormatProvider formatProvider)
+ {
+ if (format == null)
+ {
+ return ToString(formatProvider);
+ }
+
+ return string.Format(
+ formatProvider,
+ "X:{0} Y:{1} | Radius:{2}",
+ X.ToString(format, formatProvider),
+ Y.ToString(format, formatProvider),
+ Radius.ToString(format, formatProvider));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Mathematics/Extensions/Vector/Vector2Extensions.cs b/src/Exomia.Framework/Mathematics/Extensions/Vector/Vector2Extensions.cs
index 163d32bf..913fdc05 100644
--- a/src/Exomia.Framework/Mathematics/Extensions/Vector/Vector2Extensions.cs
+++ b/src/Exomia.Framework/Mathematics/Extensions/Vector/Vector2Extensions.cs
@@ -15,31 +15,44 @@
namespace Exomia.Framework.Mathematics.Extensions.Vector
{
///
- /// Vector2Extensions static class.
+ /// A vector 2 extensions class.
///
public static class Vector2Extensions
{
///
- /// calculate the angle between two vectors.
+ /// Calculate the angle from the anchor point to another point vector.
///
- /// this vec1.
- /// vec2.
+ /// This anchor .
+ /// The point .
///
- /// angle between the two vectors in radians.
+ /// The angle from anchor vector to the point vector in radians.
+ ///
+ public static double AngleTo(this Vector2 anchor, in Vector2 point)
+ {
+ return Math.Atan2(point.Y - anchor.Y, point.X - anchor.X);
+ }
+
+ ///
+ /// Calculate the angle between two vectors.
+ ///
+ /// This .
+ /// The .
+ ///
+ /// The angle between the two vectors in radians.
///
public static double AngleBetween(this Vector2 vec1, in Vector2 vec2)
{
- float scalar = (vec1.X * vec2.X) + (vec1.Y * vec2.Y);
- float length = vec1.Length() * vec2.Length();
- return Math.Cos(scalar / length);
+ return Math.Atan2(
+ (vec1.X * vec2.Y) - (vec2.X * vec1.Y),
+ (vec1.X * vec2.X) + (vec1.Y * vec2.Y));
}
///
- /// calculates the horizontal angle of a vector2.
+ /// Calculates the horizontal angle of a .
///
- /// this vec.
+ /// This .
///
- /// angle horizontal.
+ /// The angle horizontal.
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double AngleHorizontal(this Vector2 vec)
@@ -48,11 +61,11 @@ public static double AngleHorizontal(this Vector2 vec)
}
///
- /// calculates the vertical angle of a vector2.
+ /// Calculates the vertical angle of a .
///
- /// this vec.
+ /// This .
///
- /// angle vertical.
+ /// The angle vertical.
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double AngleVertical(this Vector2 vec)
@@ -61,12 +74,12 @@ public static double AngleVertical(this Vector2 vec)
}
///
- /// rotate a vector by an angle (in radian)
+ /// Rotate a by an angle (in radian)
///
- /// this vec.
+ /// This .
/// angle.
///
- /// new rotated vector2.
+ /// The new rotated .
///
public static Vector2 Rotate(this Vector2 vec, double angle)
{
@@ -76,12 +89,12 @@ public static Vector2 Rotate(this Vector2 vec, double angle)
}
///
- /// transforms the vector with a transform matrix.
+ /// Transforms the with a transform .
///
/// this vec.
/// transform.
///
- /// new vector2.
+ /// the new .
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Transform(this Vector2 vec, in Matrix transform)
diff --git a/src/Exomia.Framework/Mathematics/Line2.cs b/src/Exomia.Framework/Mathematics/Line2.cs
new file mode 100644
index 00000000..18658738
--- /dev/null
+++ b/src/Exomia.Framework/Mathematics/Line2.cs
@@ -0,0 +1,297 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using System;
+using System.Globalization;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using SharpDX;
+
+namespace Exomia.Framework.Mathematics
+{
+ ///
+ /// A 2d line.
+ ///
+ ///
+ [StructLayout(LayoutKind.Explicit, Pack = 4, Size = 16)]
+ public readonly struct Line2 : IFormattable
+ {
+ ///
+ /// The first x value.
+ ///
+ [FieldOffset(0)]
+ public readonly float X1;
+
+ ///
+ /// The first y value.
+ ///
+ [FieldOffset(4)]
+ public readonly float Y1;
+
+ ///
+ /// The first xy.
+ ///
+ [FieldOffset(0)]
+ public readonly Vector2 XY1;
+
+ ///
+ /// The second y value.
+ ///
+ [FieldOffset(8)]
+ public readonly float X2;
+
+ ///
+ /// The second x value.
+ ///
+ [FieldOffset(12)]
+ public readonly float Y2;
+
+ ///
+ /// The second xy.
+ ///
+ [FieldOffset(8)]
+ public readonly Vector2 XY2;
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The first x value.
+ /// The first y value.
+ /// The second x value.
+ /// The second y value.
+ public Line2(float x1, float y1, float x2, float y2)
+ : this()
+ {
+ X1 = x1;
+ Y1 = y1;
+ X2 = x2;
+ Y2 = y2;
+ }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// [in,out] The to process.
+ /// [in,out] The to process.
+ public Line2(in VectorI2 a, in VectorI2 b)
+ : this(a.X, a.Y, b.X, b.Y) { }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// [in,out] The to process.
+ /// [in,out] The to process.
+ public Line2(in Vector2 a, in Vector2 b)
+ : this()
+ {
+ XY1 = a;
+ XY2 = b;
+ }
+
+ ///
+ /// Determines whether the specified is equal to this instance.
+ ///
+ /// The to compare with this instance.
+ ///
+ /// true if the specified is equal to this instance; false otherwise.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool Equals(in Line2 other)
+ {
+ // ReSharper disable CompareOfFloatsByEqualityOperator
+ return
+ X1 == other.X1 &&
+ Y1 == other.Y1 &&
+ X2 == other.X2 &&
+ Y2 == other.Y2;
+
+ // ReSharper restore CompareOfFloatsByEqualityOperator
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public override bool Equals(object value)
+ {
+ return value is Line2 other && Equals(in other);
+ }
+
+ ///
+ public override int GetHashCode()
+ {
+ return (((((X1.GetHashCode() * 307) ^ Y1.GetHashCode()) * 521) ^ X2.GetHashCode()) * 853) ^
+ Y2.GetHashCode();
+ }
+
+ ///
+ public override string ToString()
+ {
+ return string.Format(
+ CultureInfo.CurrentCulture,
+ "X1:{0} Y1:{1} | X2:{2} Y2:{3}", X1, Y1, X2, Y2);
+ }
+
+ ///
+ /// Returns a that represents this instance.
+ ///
+ /// The format.
+ ///
+ /// A that represents this instance.
+ ///
+ public string ToString(string? format)
+ {
+ if (format == null)
+ {
+ return ToString();
+ }
+
+ return string.Format(
+ CultureInfo.CurrentCulture,
+ "X1:{0} Y1:{1} | X2:{2} Y2:{3}",
+ X1.ToString(format, CultureInfo.CurrentCulture),
+ Y1.ToString(format, CultureInfo.CurrentCulture),
+ X2.ToString(format, CultureInfo.CurrentCulture),
+ Y2.ToString(format, CultureInfo.CurrentCulture));
+ }
+
+ ///
+ /// Returns a that represents this instance.
+ ///
+ /// The format provider.
+ ///
+ /// A that represents this instance.
+ ///
+ public string ToString(IFormatProvider formatProvider)
+ {
+ return string.Format(
+ formatProvider,
+ "X1:{0} Y1:{1} | X2:{2} Y2:{3}", X1, Y1, X2, Y2);
+ }
+
+ ///
+ public string ToString(string? format, IFormatProvider formatProvider)
+ {
+ if (format == null)
+ {
+ return ToString(formatProvider);
+ }
+
+ return string.Format(
+ formatProvider,
+ "X1:{0} Y1:{1} | X2:{2} Y2:{3}",
+ X1.ToString(format, formatProvider),
+ Y1.ToString(format, formatProvider),
+ X2.ToString(format, formatProvider),
+ Y2.ToString(format, formatProvider));
+ }
+
+ ///
+ /// Intersect with other .
+ ///
+ /// The to compare with this instance.
+ /// [out] The intersection point.
+ ///
+ /// True if it succeeds, false if it fails.
+ ///
+ public bool IntersectWith(in Line2 other, out Vector2 intersectionPoint)
+ {
+ float a1 = Y2 - Y1;
+ float b1 = X1 - X2;
+ float c1 = (a1 * X1) + (b1 * Y1);
+
+ float a2 = other.Y2 - other.Y1;
+ float b2 = other.X1 - other.X2;
+ float c2 = (a2 * other.X1) + (b2 * other.Y1);
+
+ float det = (a1 * b2) - (a2 * b1);
+
+ if (det == 0.0f)
+ {
+ intersectionPoint = default;
+ return false;
+ }
+
+ intersectionPoint.X = ((b2 * c1) - (b1 * c2)) / det;
+ intersectionPoint.Y = ((a1 * c2) - (a2 * c1)) / det;
+ return true;
+ }
+
+ ///
+ /// Gets a perpendicular from this line.
+ ///
+ /// The offset.
+ ///
+ /// The perpendicular.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Line2 GetPerpendicular(float offset)
+ {
+ float dx = X2 - X1;
+ float dy = Y2 - Y1;
+
+ double dl = Math.Sqrt((dx * dx) + (dy * dy));
+ float nx = (float)((dy / dl) * offset);
+ float ny = (float)((dx / dl) * offset);
+
+ return new Line2(X1 - nx, Y1 + ny, X2 - nx, Y2 + ny);
+ }
+
+ ///
+ /// Rotates the line around the given .
+ ///
+ /// The line.
+ /// The rotation (in radians).
+ /// The origin.
+ ///
+ /// A new .
+ ///
+ public static Line2 RotateAround(in Line2 line, float rotation, in Vector2 origin)
+ {
+ double sin = Math.Sin(rotation);
+ double cos = Math.Cos(rotation);
+
+ float x1 = line.X1 - origin.X;
+ float y1 = line.Y1 - origin.Y;
+
+ float x2 = line.X2 - origin.X;
+ float y2 = line.Y2 - origin.Y;
+
+ return new Line2(
+ (float)((x1 * cos) - (y1 * sin)) + origin.X, (float)((x1 * sin) + (y1 * cos)) + origin.Y,
+ (float)((x2 * cos) - (y2 * sin)) + origin.X, (float)((x2 * sin) + (y2 * cos)) + origin.Y);
+ }
+
+ ///
+ /// Creates a line out of and , as well the perpendicular from this line.
+ ///
+ /// [in,out] The first ref .
+ /// [in,out] The second ref .
+ /// The offset.
+ /// [out] The perpendicular.
+ ///
+ /// The line created from and .
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Line2 CreateWithPerpendicular(ref Vector2 p1,
+ ref Vector2 p2,
+ float offset,
+ out Line2 perpendicular)
+ {
+ float dx = p2.X - p1.X;
+ float dy = p2.Y - p1.Y;
+
+ double dl = Math.Sqrt((dx * dx) + (dy * dy));
+ float nx = (float)((dy / dl) * offset);
+ float ny = (float)((dx / dl) * offset);
+
+ perpendicular = new Line2(p1.X - nx, p1.Y + ny, p2.X - nx, p2.Y + ny);
+ return new Line2(p1.X, p1.Y, p2.X, p2.Y);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Mathematics/Triangle2.cs b/src/Exomia.Framework/Mathematics/Triangle2.cs
new file mode 100644
index 00000000..19b207d3
--- /dev/null
+++ b/src/Exomia.Framework/Mathematics/Triangle2.cs
@@ -0,0 +1,256 @@
+#region License
+
+// Copyright (c) 2018-2020, exomia
+// All rights reserved.
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#endregion
+
+using System;
+using System.Globalization;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using SharpDX;
+
+namespace Exomia.Framework.Mathematics
+{
+ ///
+ /// A 2d triangle.
+ ///
+ ///
+ [StructLayout(LayoutKind.Explicit, Pack = 4, Size = 24)]
+ public readonly struct Triangle2 : IFormattable
+ {
+ ///
+ /// The first x value.
+ ///
+ [FieldOffset(0)]
+ public readonly float X1;
+
+ ///
+ /// The first y value.
+ ///
+ [FieldOffset(4)]
+ public readonly float Y1;
+
+ ///
+ /// The first xy.
+ ///
+ [FieldOffset(0)]
+ public readonly Vector2 XY1;
+
+ ///
+ /// The second y value.
+ ///
+ [FieldOffset(8)]
+ public readonly float X2;
+
+ ///
+ /// The second x value.
+ ///
+ [FieldOffset(12)]
+ public readonly float Y2;
+
+ ///
+ /// The second xy.
+ ///
+ [FieldOffset(8)]
+ public readonly Vector2 XY2;
+
+ ///
+ /// The third x value.
+ ///
+ [FieldOffset(16)]
+ public readonly float X3;
+
+ ///
+ /// The third y value.
+ ///
+ [FieldOffset(20)]
+ public readonly float Y3;
+
+ ///
+ /// The third xy.
+ ///
+ [FieldOffset(16)]
+ public readonly Vector2 XY3;
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The first x value.
+ /// The first y value.
+ /// The second x value.
+ /// The second y value.
+ /// The third x value.
+ /// The third y value.
+ public Triangle2(float x1, float y1, float x2, float y2, float x3, float y3)
+ : this()
+ {
+ X1 = x1;
+ Y1 = y1;
+ X2 = x2;
+ Y2 = y2;
+ X3 = x3;
+ Y3 = y3;
+ }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The to process.
+ /// The to process.
+ /// The to process.
+ public Triangle2(in VectorI2 a, in VectorI2 b, in VectorI2 c)
+ : this(a.X, a.Y, b.X, b.Y, c.X, c.Y) { }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The to process.
+ /// The to process.
+ /// The to process.
+ public Triangle2(in Vector2 a, in Vector2 b, in Vector2 c)
+ : this()
+ {
+ XY1 = a;
+ XY2 = b;
+ XY3 = c;
+ }
+
+ ///
+ /// Determines whether the specified is equal to this instance.
+ ///
+ /// The to compare with this instance.
+ ///
+ /// true if the specified is equal to this instance; false otherwise.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool Equals(in Triangle2 other)
+ {
+ // ReSharper disable CompareOfFloatsByEqualityOperator
+ return
+ X1 == other.X1 &&
+ Y1 == other.Y1 &&
+ X2 == other.X2 &&
+ Y2 == other.Y2 &&
+ X3 == other.X3 &&
+ Y3 == other.Y3;
+
+ // ReSharper restore CompareOfFloatsByEqualityOperator
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public override bool Equals(object value)
+ {
+ return value is Triangle2 other && Equals(in other);
+ }
+
+ ///
+ public override int GetHashCode()
+ {
+ return (((((((((X1.GetHashCode() * 307) ^ Y1.GetHashCode()) * 521) ^ X2.GetHashCode()) * 853) ^
+ Y2.GetHashCode()) * 443) ^ X3.GetHashCode()) * 937) ^ Y3.GetHashCode();
+ }
+
+ ///
+ public override string ToString()
+ {
+ return string.Format(
+ CultureInfo.CurrentCulture,
+ "X1:{0} Y1:{1} | X2:{2} Y2:{3} | X3:{4} Y3:{5}",
+ X1, Y1, X2, Y2, X3, Y3);
+ }
+
+ ///
+ /// Returns a that represents this instance.
+ ///
+ /// The format.
+ ///
+ /// A that represents this instance.
+ ///
+ public string ToString(string? format)
+ {
+ if (format == null)
+ {
+ return ToString();
+ }
+
+ return string.Format(
+ CultureInfo.CurrentCulture,
+ "X1:{0} Y1:{1} | X2:{2} Y2:{3} | X3:{4} Y3:{5}",
+ X1.ToString(format, CultureInfo.CurrentCulture),
+ Y1.ToString(format, CultureInfo.CurrentCulture),
+ X2.ToString(format, CultureInfo.CurrentCulture),
+ Y2.ToString(format, CultureInfo.CurrentCulture),
+ X3.ToString(format, CultureInfo.CurrentCulture),
+ Y3.ToString(format, CultureInfo.CurrentCulture));
+ }
+
+ ///
+ /// Returns a that represents this instance.
+ ///
+ /// The format provider.
+ ///
+ /// A that represents this instance.
+ ///
+ public string ToString(IFormatProvider formatProvider)
+ {
+ return string.Format(
+ formatProvider,
+ "X1:{0} Y1:{1} | X2:{2} Y2:{3} | X3:{4} Y3:{5}",
+ X1, Y1, X2, Y2, X3, Y3);
+ }
+
+ ///
+ public string ToString(string? format, IFormatProvider formatProvider)
+ {
+ if (format == null)
+ {
+ return ToString(formatProvider);
+ }
+
+ return string.Format(
+ formatProvider,
+ "X1:{0} Y1:{1} | X2:{2} Y2:{3} | X3:{4} Y3:{5}",
+ X1.ToString(format, formatProvider),
+ Y1.ToString(format, formatProvider),
+ X2.ToString(format, formatProvider),
+ Y2.ToString(format, formatProvider),
+ X3.ToString(format, formatProvider),
+ Y3.ToString(format, formatProvider));
+ }
+
+ ///
+ /// Rotates the triangle around the given .
+ ///
+ /// The triangle.
+ /// The rotation (in radians).
+ /// The origin.
+ ///
+ /// A new .
+ ///
+ public static Triangle2 RotateAround(in Triangle2 triangle, float rotation, in Vector2 origin)
+ {
+ double sin = Math.Sin(rotation);
+ double cos = Math.Cos(rotation);
+
+ float x1 = triangle.X1 - origin.X;
+ float y1 = triangle.Y1 - origin.Y;
+
+ float x2 = triangle.X2 - origin.X;
+ float y2 = triangle.Y2 - origin.Y;
+
+ float x3 = triangle.X3 - origin.X;
+ float y3 = triangle.Y3 - origin.Y;
+
+ return new Triangle2(
+ (float)((x1 * cos) - (y1 * sin)) + origin.X, (float)((x1 * sin) + (y1 * cos)) + origin.Y,
+ (float)((x2 * cos) - (y2 * sin)) + origin.X, (float)((x2 * sin) + (y2 * cos)) + origin.Y,
+ (float)((x3 * cos) - (y3 * sin)) + origin.X, (float)((x3 * sin) + (y3 * cos)) + origin.Y);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Resources/Resources.cs b/src/Exomia.Framework/Resources/Resources.cs
index c352b662..a8774b97 100644
--- a/src/Exomia.Framework/Resources/Resources.cs
+++ b/src/Exomia.Framework/Resources/Resources.cs
@@ -105,5 +105,10 @@ public static class Shaders
/// The position color texture2 shader resource path.
///
public const string POSITION_NORMAL_TEXTURE = "Resources.shaders.position_normal_texture.ehlsl";
+
+ ///
+ /// The canvas shader resource path.
+ ///
+ public const string CANVAS = "Resources.shaders.canvas.ehlsl";
}
}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Resources/shaders/canvas.ehlsl b/src/Exomia.Framework/Resources/shaders/canvas.ehlsl
new file mode 100644
index 00000000..17bcaeea
--- /dev/null
+++ b/src/Exomia.Framework/Resources/shaders/canvas.ehlsl
@@ -0,0 +1,195 @@
+/** Shaderdefinition
+ *
+ * group DEFAULT
+ * vs VSMain vs_5_0 OptimizationLevel3
+ * ps PSMain ps_5_0 OptimizationLevel3
+ */
+
+Texture2D g_Texture1 : register(t0);
+Texture2D g_Texture2 : register(t1);
+Texture2D g_Texture3 : register(t2);
+Texture2D g_Texture4 : register(t3);
+Texture2D g_Texture5 : register(t4);
+Texture2D g_Texture6 : register(t5);
+Texture2D g_Texture7 : register(t6);
+Texture2D g_Texture8 : register(t7);
+
+
+Texture2D g_FontTexture1 : register(t8);
+Texture2D g_FontTexture2 : register(t9);
+Texture2D g_FontTexture3 : register(t10);
+Texture2D g_FontTexture4 : register(t11);
+
+SamplerState g_Sampler : register(s0);
+
+cbuffer PerFrame : register(b0)
+{
+ float4x4 g_WorldViewProjectionMatrix;
+};
+
+struct VS_INPUT
+{
+ float4 p : SV_POSITION0;
+ float4 c : COLOR0;
+ float2 uv : TEXCOORD0;
+ float2 mo : TEXCOORD1;
+};
+
+struct PS_INPUT
+{
+ float4 p : SV_POSITION0;
+ float4 c : COLOR0;
+ float2 uv : TEXCOORD0;
+ float2 mo : TEXCOORD1;
+ float2 zw : TEXCOORD2;
+};
+
+PS_INPUT VSMain(VS_INPUT input)
+{
+ PS_INPUT output = (PS_INPUT)0;
+ output.zw = input.p.zw;
+ output.p = mul(float4(input.p.xy, 0.0f, 1.0f), g_WorldViewProjectionMatrix);
+ output.c = input.c / 255.0f;
+ output.uv = input.uv;
+ output.mo = input.mo;
+ return output;
+}
+
+#define COLOR_MODE 0.0f
+#define TEXTURE_MODE 1.0f
+#define FONT_TEXTURE_MODE 2.0f
+#define FILL_CIRCLE_MODE 3.0f
+#define FILL_CIRCLE_ARC_MODE 4.0f
+#define BORDER_CIRCLE_MODE 5.0f
+#define BORDER_CIRCLE_ARC_MODE 6.0f
+
+#define PI 3.141593f
+
+float4 PSMain(PS_INPUT input) : SV_TARGET
+{
+ switch (input.mo.x)
+ {
+ default:
+ case COLOR_MODE:
+ return input.c;
+ case TEXTURE_MODE:
+ {
+ switch (input.mo.y)
+ {
+ case 0.0f:
+ return g_Texture1.Sample(g_Sampler, input.uv) * input.c;
+ case 1.0f:
+ return g_Texture2.Sample(g_Sampler, input.uv) * input.c;
+ case 2.0f:
+ return g_Texture3.Sample(g_Sampler, input.uv) * input.c;
+ case 3.0f:
+ return g_Texture4.Sample(g_Sampler, input.uv) * input.c;
+ case 4.0f:
+ return g_Texture5.Sample(g_Sampler, input.uv) * input.c;
+ case 5.0f:
+ return g_Texture6.Sample(g_Sampler, input.uv) * input.c;
+ case 6.0f:
+ return g_Texture7.Sample(g_Sampler, input.uv) * input.c;
+ }
+ return g_Texture8.Sample(g_Sampler, input.uv) * input.c;
+ }
+ case FONT_TEXTURE_MODE:
+ {
+ switch (input.mo.y)
+ {
+ case 0.0f:
+ return g_FontTexture1.Sample(g_Sampler, input.uv) * input.c;
+ case 1.0f:
+ return g_FontTexture2.Sample(g_Sampler, input.uv) * input.c;
+ case 2.0f:
+ return g_FontTexture3.Sample(g_Sampler, input.uv) * input.c;
+ }
+ return g_FontTexture4.Sample(g_Sampler, input.uv) * input.c;
+ }
+ case FILL_CIRCLE_MODE:
+ {
+ float2 p = input.p;
+ float2 center = input.zw;
+ float radius = input.mo.y;
+
+ float2 d = center - p;
+ float ls = (d.x * d.x) + (d.y * d.y);
+
+ if (ls > radius * radius)
+ discard;
+
+ return input.c;
+ }
+ case FILL_CIRCLE_ARC_MODE:
+ {
+ float2 p = input.p;
+ float2 center = input.zw;
+ float radius = input.mo.y;
+
+ float2 d = center - p;
+ float ls = (d.x * d.x) + (d.y * d.y);
+
+ if (ls < radius * radius)
+ {
+ float start = input.uv.x;
+ float end = input.uv.y;
+
+ float anglePositive = atan2(d.y, d.x) + PI;
+ float angleNegative = atan2(d.y, d.x) - PI;
+
+ if (anglePositive >= start && anglePositive <= end ||
+ angleNegative >= start && angleNegative <= end)
+ {
+ return input.c;
+ }
+ }
+ discard;
+ return float4(0, 0, 0, 0);
+ }
+ case BORDER_CIRCLE_MODE:
+ {
+ float2 p = input.p;
+ float2 center = input.zw;
+
+ float2 d = center - p;
+ float ls = (d.x * d.x) + (d.y * d.y);
+
+ float r = float(((uint)input.mo.y >> 16) / 10.0f);
+ float l = float(((uint)input.mo.y & 0xffff) / 10.0f);
+
+ if (ls > r * r || ls < l * l)
+ discard;
+
+ return input.c;
+ }
+ case BORDER_CIRCLE_ARC_MODE:
+ {
+ float2 p = input.p;
+ float2 center = input.zw;
+
+ float2 d = center - p;
+ float ls = (d.x * d.x) + (d.y * d.y);
+
+ float r = float(((uint) input.mo.y >> 16) / 10.0f);
+ float l = float(((uint) input.mo.y & 0xffff) / 10.0f);
+
+ if (ls < r * r && ls > l * l)
+ {
+ float start = input.uv.x;
+ float end = input.uv.y;
+
+ float anglePositive = atan2(d.y, d.x) + PI;
+ float angleNegative = atan2(d.y, d.x) - PI;
+
+ if (anglePositive >= start && anglePositive <= end ||
+ angleNegative >= start && angleNegative <= end)
+ {
+ return input.c;
+ }
+ }
+
+ discard;
+ return float4(0, 0, 0, 0);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Exomia.Framework/Resources/shaders/position_color.ehlsl b/src/Exomia.Framework/Resources/shaders/position_color.ehlsl
index 54154171..63b481b8 100644
--- a/src/Exomia.Framework/Resources/shaders/position_color.ehlsl
+++ b/src/Exomia.Framework/Resources/shaders/position_color.ehlsl
@@ -1,6 +1,6 @@
/** Shaderdefinition
*
- * technique DEFAULT
+ * group DEFAULT
* vs VSMain vs_5_0 OptimizationLevel3
* ps PSMain ps_5_0 OptimizationLevel3
*/
diff --git a/src/Exomia.Framework/Resources/shaders/position_color_texture.ehlsl b/src/Exomia.Framework/Resources/shaders/position_color_texture.ehlsl
index 4d73e51f..b957adaa 100644
--- a/src/Exomia.Framework/Resources/shaders/position_color_texture.ehlsl
+++ b/src/Exomia.Framework/Resources/shaders/position_color_texture.ehlsl
@@ -1,6 +1,6 @@
/** Shaderdefinition
*
- * technique DEFAULT
+ * group DEFAULT
* vs VSMain vs_5_0 OptimizationLevel3
* ps PSMain ps_5_0 OptimizationLevel3
*/
diff --git a/src/Exomia.Framework/Resources/shaders/position_normal_texture.ehlsl b/src/Exomia.Framework/Resources/shaders/position_normal_texture.ehlsl
index dfebbd8c..260428d9 100644
--- a/src/Exomia.Framework/Resources/shaders/position_normal_texture.ehlsl
+++ b/src/Exomia.Framework/Resources/shaders/position_normal_texture.ehlsl
@@ -1,18 +1,18 @@
/** Shaderdefinition
*
- * technique VERTEX_LIGHTING_PHONG
+ * group VERTEX_LIGHTING_PHONG
* vs VS_VERTEX_LIGHTING_PHONG vs_5_0 OptimizationLevel3
* ps PS_VERTEX_LIGHTING ps_5_0 OptimizationLevel3
*
- * technique VERTEX_LIGHTING_BLINNPHONG
+ * group VERTEX_LIGHTING_BLINNPHONG
* vs VS_VERTEX_LIGHTING_BLINNPHONG vs_5_0 OptimizationLevel3
* ps PS_VERTEX_LIGHTING ps_5_0 OptimizationLevel3
*
- * technique PIXEL_LIGHTING_PHONG
+ * group PIXEL_LIGHTING_PHONG
* vs VS_PIXEL_LIGHTING_PHONG vs_5_0 OptimizationLevel3
* ps PS_PIXEL_LIGHTING_PHONG ps_5_0 OptimizationLevel3
*
- * technique PIXEL_LIGHTING_BLINNPHONG
+ * group PIXEL_LIGHTING_BLINNPHONG
* vs VS_PIXEL_LIGHTING_BLINNPHONG vs_5_0 OptimizationLevel3
* ps PS_PIXEL_LIGHTING_BLINNPHONG ps_5_0 OptimizationLevel3
*/
@@ -40,15 +40,15 @@ struct Material
//--------------------------------------------------------------------------------------
cbuffer PerFrame : register(b0)
{
- float4x4 g_WorldMatrix;
float4x4 g_ViewMatrix;
float4x4 g_ProjectionMatrix;
- float4x4 g_WorldViewProjectionMatrix;
+ float4x4 g_ViewProjectionMatrix;
float3 g_EyeVector;
};
cbuffer PerObject : register(b1)
{
+ float4x4 g_TransformMatrix;
Material g_Material;
};
@@ -59,7 +59,7 @@ struct VS_INPUT
{
float4 p : SV_POSITION0;
float3 n : NORMAL0;
- float2 t : TEXCOORD0;
+ float2 t : TEXCOORD0;
};
//--------------------------------------------------------------------------------------
@@ -74,10 +74,10 @@ struct PS_INPUT_PV
struct PS_INPUT_PP_PHONG
{
- float4 p : SV_POSITION;
+ float4 p : SV_POSITION;
float4 wp : POSITION;
- float2 t : TEXCOORD;
- float3 n : TEXCOORD1;
+ float2 t : TEXCOORD;
+ float3 n : TEXCOORD1;
};
struct PS_INPUT_PP_BLINNPHONG
@@ -131,13 +131,13 @@ PS_INPUT_PV VS_VERTEX_LIGHTING_PHONG(VS_INPUT input)
PS_INPUT_PV output;
//transform position to clip space
- output.p = mul(input.p, g_WorldViewProjectionMatrix);
+ output.p = mul(input.p, mul(g_TransformMatrix, g_ViewProjectionMatrix));
//set texture coords
output.t = input.t;
//calculate lighting vectors
- float3 n = normalize(mul(input.n, (float3x3)g_WorldMatrix));
+ float3 n = normalize(mul(input.n, (float3x3)g_TransformMatrix));
float3 v = normalize(g_EyeVector - (float3)input.p);
//DONOT USE -light.dir since the reflection returns a ray from the surface
float3 r = reflect(light.direction, n);
@@ -156,14 +156,14 @@ PS_INPUT_PV VS_VERTEX_LIGHTING_BLINNPHONG(VS_INPUT input)
PS_INPUT_PV output;
//transform position to clip space
- output.p = mul(input.p, g_WorldViewProjectionMatrix);
+ output.p = mul(input.p, mul(g_TransformMatrix, g_ViewProjectionMatrix));
//set texture coords
output.t = input.t;
-
+
//calculate lighting
- float3 n = normalize(mul(input.n, (float3x3)g_WorldMatrix));
- float3 v = normalize(g_EyeVector - (float3)input.p);
+ float3 n = normalize(mul(input.n, (float3x3)g_TransformMatrix));
+ float3 v = normalize(g_EyeVector - (float3)input.p);
float3 h = normalize(-light.direction + v);
//calculate per vertex lighting intensity and interpolate it like a color
@@ -178,7 +178,7 @@ PS_INPUT_PV VS_VERTEX_LIGHTING_BLINNPHONG(VS_INPUT input)
float4 PS_VERTEX_LIGHTING(PS_INPUT_PV input) : SV_Target
{
//with texturing
- return input.i * g_Texture.Sample(g_Sampler, input.t);
+ return input.i * g_Texture.Sample(g_Sampler, input.t);
}
//--------------------------------------------------------------------------------------
@@ -189,14 +189,14 @@ PS_INPUT_PP_PHONG VS_PIXEL_LIGHTING_PHONG(VS_INPUT input)
PS_INPUT_PP_PHONG output;
//transform position to clip space - keep worldspace position
- output.wp = mul(input.p, g_WorldMatrix);
- output.p = mul(input.p, g_WorldViewProjectionMatrix);
+ output.wp = mul(input.p, g_TransformMatrix);
+ output.p = mul(input.p, mul(g_TransformMatrix, g_ViewProjectionMatrix));
//set texture coords
output.t = input.t;
//set required lighting vectors for interpolation
- output.n = normalize(mul(input.n, (float3x3)g_WorldMatrix));
+ output.n = normalize(mul(input.n, (float3x3) g_TransformMatrix));
return output;
}
@@ -225,14 +225,14 @@ PS_INPUT_PP_BLINNPHONG VS_PIXEL_LIGHTING_BLINNPHONG(VS_INPUT input)
PS_INPUT_PP_BLINNPHONG output;
//set position into clip space
- output.p = mul(input.p, g_WorldViewProjectionMatrix);
+ output.p = mul(input.p, mul(g_TransformMatrix, g_ViewProjectionMatrix));
//set texture coords
output.t = input.t;
//set required lighting vectors for interpolation
float3 v = normalize(g_EyeVector - (float3)input.p);
- output.n = normalize(mul(input.n, (float3x3)g_WorldMatrix));
+ output.n = normalize(mul(input.n, (float3x3)g_TransformMatrix));
output.h = normalize(-light.direction + v);
return output;
diff --git a/src/Exomia.Framework/UpdateableComparer.cs b/src/Exomia.Framework/UpdateableComparer.cs
index 3a05025a..aa935194 100644
--- a/src/Exomia.Framework/UpdateableComparer.cs
+++ b/src/Exomia.Framework/UpdateableComparer.cs
@@ -30,16 +30,6 @@ public int Compare(IUpdateable left, IUpdateable right)
return 0;
}
- if (left == null)
- {
- return 1;
- }
-
- if (right == null)
- {
- return -1;
- }
-
return left.UpdateOrder < right.UpdateOrder ? 1 : -1;
}
}
diff --git a/src/Exomia.Framework/VectorI2.cs b/src/Exomia.Framework/VectorI2.cs
index 5baa599e..9a15baad 100644
--- a/src/Exomia.Framework/VectorI2.cs
+++ b/src/Exomia.Framework/VectorI2.cs
@@ -79,8 +79,7 @@ public VectorI2(int x, int y)
///
/// The to compare with this instance.
///
- /// true if the specified is equal to this instance; otherwise,
- /// false.
+ /// true if the specified is equal to this instance; false otherwise.
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly bool Equals(in VectorI2 other)
@@ -94,11 +93,7 @@ public readonly bool Equals(in VectorI2 other)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override readonly bool Equals(object value)
{
- if (value is VectorI2 other)
- {
- return Equals(in other);
- }
- return false;
+ return value is VectorI2 other && Equals(in other);
}
///
diff --git a/src/Exomia.Framework/VectorI3.cs b/src/Exomia.Framework/VectorI3.cs
index 98e1d392..173ab08b 100644
--- a/src/Exomia.Framework/VectorI3.cs
+++ b/src/Exomia.Framework/VectorI3.cs
@@ -105,8 +105,7 @@ public VectorI3(in VectorI2 value, int z)
///
/// The to compare with this instance.
///
- /// true if the specified is equal to this instance;
- /// false otherwise.
+ /// true if the specified is equal to this instance; false otherwise.
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly bool Equals(in VectorI3 other)
@@ -121,11 +120,7 @@ public readonly bool Equals(in VectorI3 other)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override readonly bool Equals(object value)
{
- if (value is VectorI3 other)
- {
- return Equals(in other);
- }
- return false;
+ return value is VectorI3 other && Equals(in other);
}
///
diff --git a/src/Exomia.Framework/Win32/Mem.cs b/src/Exomia.Framework/Win32/Mem.cs
index 504fc4bd..31a240f5 100644
--- a/src/Exomia.Framework/Win32/Mem.cs
+++ b/src/Exomia.Framework/Win32/Mem.cs
@@ -8,6 +8,8 @@
#endregion
+using System;
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;
@@ -47,5 +49,42 @@ public static extern void Cpy(void* dest,
public static extern void Move(void* dest,
void* src,
int count);
+
+ ///
+ /// memset call
+ /// Sets the first num bytes of the block of memory pointed by ptr to the specified value
+ /// (interpreted as an unsigned char).
+ ///
+ /// [in,out] destination addr.
+ /// value to be set.
+ /// count of bytes.
+ ///
+ /// Null if it fails, else a void*.
+ ///
+ [SuppressUnmanagedCodeSecurity]
+ [DllImport(
+ "msvcrt.dll", EntryPoint = "memset", CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+ public static extern void* Set(void* dest,
+ int value,
+ int count);
+
+ ///
+ /// Resizes the given array with the given to the given
+ /// .
+ ///
+ /// Generic type parameter.
+ /// [in,out] The source array ptr.
+ /// [in,out] The length of the source array.
+ /// The length of the new array.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void Resize(ref T* src, ref int srcLength, int newLength) where T : unmanaged
+ {
+ T* ptr = (T*)Marshal.AllocHGlobal(sizeof(T) * newLength);
+ Cpy(ptr, src, srcLength * sizeof(T));
+ Marshal.FreeHGlobal(new IntPtr(src));
+
+ src = ptr;
+ srcLength = newLength;
+ }
}
}
\ No newline at end of file
diff --git a/tools/Exomia.Framework.ContentManager/AboutForm.cs b/tools/Exomia.Framework.ContentManager/AboutForm.cs
index 092f05f8..38f9fdb0 100644
--- a/tools/Exomia.Framework.ContentManager/AboutForm.cs
+++ b/tools/Exomia.Framework.ContentManager/AboutForm.cs
@@ -24,7 +24,7 @@ public AboutForm()
private void OnLoad(object sender, EventArgs e)
{
- var assembly = Assembly.GetExecutingAssembly();
+ Assembly? assembly = Assembly.GetExecutingAssembly();
Text = $"About {assembly.GetCustomAttribute().Title}";
productNameLbl.Text = assembly.GetCustomAttribute().Product;
versionLbl.Text = $"Version {assembly.GetName().Version}";
diff --git a/tools/Exomia.Framework.ContentManager/CreateProjectForm.cs b/tools/Exomia.Framework.ContentManager/CreateProjectForm.cs
index 32ec1325..f634f7ad 100644
--- a/tools/Exomia.Framework.ContentManager/CreateProjectForm.cs
+++ b/tools/Exomia.Framework.ContentManager/CreateProjectForm.cs
@@ -37,13 +37,13 @@ public CreateProjectForm()
///
public ProjectFile CreateProjectFile()
{
- var directoryInfo = new DirectoryInfo(Path.Combine(locationTb.Text, nameTb.Text));
+ DirectoryInfo? directoryInfo = new DirectoryInfo(Path.Combine(locationTb.Text, nameTb.Text));
if (!directoryInfo.Exists)
{
directoryInfo.Create();
}
- var projectFile = new ProjectFile(nameTb.Text, directoryInfo.FullName)
+ ProjectFile? projectFile = new ProjectFile(nameTb.Text, directoryInfo.FullName)
{
Content = new ContentPropertyGridItem
{
@@ -73,7 +73,7 @@ private void button1_Click(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(locationTb.Text) || string.IsNullOrEmpty(nameTb.Text)) { return; }
- var fileInfo = new FileInfo(Path.Combine(locationTb.Text, nameTb.Text, $"{nameTb.Text}.ecp"));
+ FileInfo? fileInfo = new FileInfo(Path.Combine(locationTb.Text, nameTb.Text, $"{nameTb.Text}.ecp"));
if (fileInfo.Exists)
{
// ReSharper disable once SwitchStatementHandlesSomeKnownEnumValuesWithDefault
diff --git a/tools/Exomia.Framework.ContentManager/Json.cs b/tools/Exomia.Framework.ContentManager/Json.cs
index 880e6580..9b12e199 100644
--- a/tools/Exomia.Framework.ContentManager/Json.cs
+++ b/tools/Exomia.Framework.ContentManager/Json.cs
@@ -42,8 +42,8 @@ public static void Serialize(string filePath, object value)
public static T? Deserialize(Stream s) where T : class
{
- using (var sr = new StreamReader(s))
- using (var jr = new JsonTextReader(sr))
+ using (StreamReader? sr = new StreamReader(s))
+ using (JsonTextReader? jr = new JsonTextReader(sr))
{
return s_jsonSerializer.Deserialize(jr);
}
@@ -51,7 +51,7 @@ public static void Serialize(string filePath, object value)
public static T? Deserialize(string filePath) where T : class
{
- using (var sr = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.None))
+ using (FileStream? sr = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.None))
{
return Deserialize(sr);
}
diff --git a/tools/Exomia.Framework.ContentManager/MainForm.Build.cs b/tools/Exomia.Framework.ContentManager/MainForm.Build.cs
index 8c54a466..588747a9 100644
--- a/tools/Exomia.Framework.ContentManager/MainForm.Build.cs
+++ b/tools/Exomia.Framework.ContentManager/MainForm.Build.cs
@@ -48,7 +48,7 @@ private void CancelBuild()
int skipped = 0;
int failed = 0;
- var rootNode = treeView1.Nodes[ROOT_KEY_PREFIX];
+ TreeNode? rootNode = treeView1.Nodes[ROOT_KEY_PREFIX];
async Task ForTreeNode(TreeNode node, ContentPropertyGridItem contentPropertyGridItem)
{
diff --git a/tools/Exomia.Framework.ContentManager/MainForm.Core.cs b/tools/Exomia.Framework.ContentManager/MainForm.Core.cs
index 405bf453..885c5b82 100644
--- a/tools/Exomia.Framework.ContentManager/MainForm.Core.cs
+++ b/tools/Exomia.Framework.ContentManager/MainForm.Core.cs
@@ -104,7 +104,8 @@ private void EditItem(TreeNode node)
Path.Combine(_projectFile!.Location, item.VirtualPath, item.Name));
if (description == null) { return; }
- using (var jsonEditorForm = new JsonEditorForm(description) { Text = $"Edit font '{item.Name}'" })
+ using (JsonEditorForm? jsonEditorForm =
+ new JsonEditorForm(description) { Text = $"Edit font '{item.Name}'" })
{
if (jsonEditorForm.ShowDialog() != DialogResult.OK)
{
diff --git a/tools/Exomia.Framework.ContentManager/MainForm.Events.cs b/tools/Exomia.Framework.ContentManager/MainForm.Events.cs
index 28f46fcb..ff339abd 100644
--- a/tools/Exomia.Framework.ContentManager/MainForm.Events.cs
+++ b/tools/Exomia.Framework.ContentManager/MainForm.Events.cs
@@ -116,8 +116,8 @@ private void openToolStripMenuItem_Click(object sender, EventArgs e)
.OfType()
.OrderBy(p => p.VirtualPath!.Length))
{
- var n = GetNodeFromPath(node, f.VirtualPath!)
- ?? throw new InvalidDataException("The project file is corrupt!");
+ TreeNode? n = GetNodeFromPath(node, f.VirtualPath!)
+ ?? throw new InvalidDataException("The project file is corrupt!");
int nodeCount = n.GetNodeCount(false);
n = n.Nodes.Add(
$"{FOLDER_KEY_PREFIX}{nodeCount}", f.Name, 1, 1);
@@ -129,8 +129,8 @@ private void openToolStripMenuItem_Click(object sender, EventArgs e)
.Resources
.OfType())
{
- var n = GetNodeFromPath(node, i.VirtualPath!)
- ?? throw new InvalidDataException("The project file is corrupt!");
+ TreeNode? n = GetNodeFromPath(node, i.VirtualPath!)
+ ?? throw new InvalidDataException("The project file is corrupt!");
int nodeCount = n.GetNodeCount(false);
n = n.Nodes.Add(
$"{FONT_KEY_PREFIX}{nodeCount}", i.Name, 4, 4);
@@ -364,7 +364,7 @@ private void addFolderToolStripMenuItem_Click(object sender, EventArgs e)
treeView1.InvokeIfRequired(
x =>
{
- var selectedNode = x.SelectedNode ?? x.TopNode;
+ TreeNode? selectedNode = x.SelectedNode ?? x.TopNode;
if (selectedNode == null) { return; }
int selectedNodeCount = selectedNode.GetNodeCount(false);
@@ -375,7 +375,7 @@ private void addFolderToolStripMenuItem_Click(object sender, EventArgs e)
di.Create();
}
- var node = selectedNode.Nodes.Add($"{FOLDER_KEY_PREFIX}{selectedNodeCount}", di.Name, 1, 1);
+ TreeNode? node = selectedNode.Nodes.Add($"{FOLDER_KEY_PREFIX}{selectedNodeCount}", di.Name, 1, 1);
node.Tag = _projectFile.AddResource(
new FolderPropertyGridItem
{
@@ -409,11 +409,11 @@ private void addFontToolStripMenuItem_Click(object sender, EventArgs e)
treeView1.InvokeIfRequired(
x =>
{
- var selectedNode = x.SelectedNode ?? x.TopNode;
+ TreeNode? selectedNode = x.SelectedNode ?? x.TopNode;
if (selectedNode == null) { return; }
int selectedNodeCount = selectedNode.GetNodeCount(false);
- using (var jsonEditorForm = new JsonEditorForm(
+ using (JsonEditorForm? jsonEditorForm = new JsonEditorForm(
new FontDescription
{
Name = "Arial",
@@ -442,7 +442,7 @@ private void addFontToolStripMenuItem_Click(object sender, EventArgs e)
jsonEditorForm.Save(fntFilePath);
- var node = selectedNode.Nodes.Add(
+ TreeNode? node = selectedNode.Nodes.Add(
$"{FONT_KEY_PREFIX}{selectedNodeCount}",
Path.GetFileName(fntFilePath), 4, 4);
node.Tag = _projectFile.AddResource(
diff --git a/tools/Exomia.Framework.ContentManager/MainForm.cs b/tools/Exomia.Framework.ContentManager/MainForm.cs
index 90896190..97e86dd4 100644
--- a/tools/Exomia.Framework.ContentManager/MainForm.cs
+++ b/tools/Exomia.Framework.ContentManager/MainForm.cs
@@ -78,29 +78,6 @@ public void SetProgressbarValue(bool state)
});
}
- private static bool IsNumber(object? value)
- {
- return value is sbyte
- || value is byte
- || value is short
- || value is ushort
- || value is int
- || value is uint
- || value is long
- || value is ulong
- || value is float
- || value is double
- || value is decimal;
- }
-
- private static void ForAll(Action action, params T[] items)
- {
- foreach (T item in items)
- {
- action(item);
- }
- }
-
private void Clear()
{
richTextBox1.InvokeIfRequired(
@@ -112,7 +89,7 @@ private void WriteLine(string text, params object?[] args)
richTextBox1.InvokeIfRequired(
x =>
{
- var matches = Regex.Matches(text, "\\{([0-9]+)(?:\\:([A-Za-z]+))?\\}");
+ MatchCollection? matches = Regex.Matches(text, "\\{([0-9]+)(?:\\:([A-Za-z]+))?\\}");
if (matches.Count <= 0)
{
@@ -175,6 +152,29 @@ private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
_projectFile = null;
}
+ private static bool IsNumber(object? value)
+ {
+ return value is sbyte
+ || value is byte
+ || value is short
+ || value is ushort
+ || value is int
+ || value is uint
+ || value is long
+ || value is ulong
+ || value is float
+ || value is double
+ || value is decimal;
+ }
+
+ private static void ForAll(Action action, params T[] items)
+ {
+ foreach (T item in items)
+ {
+ action(item);
+ }
+ }
+
private class NodeSorter : IComparer
{
// Compare the length of the strings, or the strings