├── LightDx
├── FodyWeavers.xml
├── packages.config
├── Samplers.cs
├── DepthTest.cs
├── Vectors.cs
├── NativeException.cs
├── NativeHelper.cs
├── ComScopeGuard.cs
├── LightDx.nuspec
├── Properties
│ └── AssemblyInfo.cs
├── StaticMemory.cs
├── Blenders.cs
├── FrameCounter.cs
├── MatrixHelper.cs
├── Texture2D.cs
├── ConstantBuffer.cs
├── ShaderResourceBuffer.cs
├── ShaderSource.cs
├── VertexBuffer.cs
├── RenderTargetList.cs
├── InputAttributes.cs
├── IndexBuffer.cs
├── VertexDataProcessorGroup.cs
├── TextureFontCache.cs
├── CalliGenerator.cs
├── DDSReader.cs
├── LightDx.csproj
├── VertexDataProcessor.cs
├── Sprite.cs
├── RenderTargetObject.cs
└── AbstractFontCache.cs
├── Examples
├── TextureTriangle
│ ├── Hiyori.png
│ ├── App.config
│ ├── Properties
│ │ ├── Settings.settings
│ │ ├── AssemblyInfo.cs
│ │ ├── Settings.Designer.cs
│ │ ├── Resources.Designer.cs
│ │ └── Resources.resx
│ ├── Shader.fx
│ ├── Program.cs
│ └── TextureTriangle.csproj
├── DrawString
│ ├── App.config
│ ├── README.md
│ ├── Program.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ └── DrawString.csproj
├── Triangle
│ ├── App.config
│ ├── Properties
│ │ ├── Settings.settings
│ │ ├── AssemblyInfo.cs
│ │ ├── Settings.Designer.cs
│ │ ├── Resources.Designer.cs
│ │ └── Resources.resx
│ ├── Shader.fx
│ ├── Program.cs
│ └── Triangle.csproj
└── DynamicTriangle
│ ├── App.config
│ ├── README.md
│ ├── Shader.fx
│ ├── Properties
│ └── AssemblyInfo.cs
│ ├── DynamicTriangle.csproj
│ └── Program.cs
├── Weavers
├── packages.config
├── Properties
│ └── AssemblyInfo.cs
├── UnmanagedConstrainWeaver.cs
├── Weavers.csproj
├── AOTCalliGenerator.cs
└── CalliWeaver.cs
├── Cube
├── App.config
├── Shader.fx
├── Properties
│ └── AssemblyInfo.cs
├── Cube.csproj
├── Camera.cs
└── Program.cs
├── BufferResource
├── App.config
├── Shader.fx
├── Properties
│ └── AssemblyInfo.cs
├── Program.cs
└── BufferResource.csproj
├── LICENSE
├── README.md
├── .gitignore
└── LightDX.sln
/LightDx/FodyWeavers.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/Examples/TextureTriangle/Hiyori.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acaly/LightDx/HEAD/Examples/TextureTriangle/Hiyori.png
--------------------------------------------------------------------------------
/Weavers/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/LightDx/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/Cube/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/BufferResource/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Examples/DrawString/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Examples/Triangle/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/Examples/DynamicTriangle/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Examples/TextureTriangle/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/LightDx/Samplers.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace LightDx
8 | {
9 | public sealed class Sampler
10 | {
11 | //TODO
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/LightDx/DepthTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace LightDx
8 | {
9 | public sealed class DepthTest
10 | {
11 | //TODO
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Examples/Triangle/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Examples/TextureTriangle/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Examples/DynamicTriangle/README.md:
--------------------------------------------------------------------------------
1 | DynamicTriangle
2 | ======
3 |
4 | This project aims to introduce some more useful features supported by LightDx. Currently
5 | it includes:
6 |
7 | * Dynamic vertex buffer.
8 | * Multiple vertex buffer used together.
9 | * Index buffer.
10 | * Constant buffer (one buffer for multiple stages).
11 |
--------------------------------------------------------------------------------
/Examples/Triangle/Shader.fx:
--------------------------------------------------------------------------------
1 | struct VS_IN
2 | {
3 | float4 pos : POSITION;
4 | float4 col : COLOR;
5 | };
6 |
7 | struct PS_IN
8 | {
9 | float4 pos : SV_POSITION;
10 | float4 col : COLOR;
11 | };
12 |
13 | PS_IN VS( VS_IN input )
14 | {
15 | PS_IN output = (PS_IN)0;
16 |
17 | output.pos = input.pos;
18 | output.col = input.col;
19 |
20 | return output;
21 | }
22 |
23 | float4 PS( PS_IN input ) : SV_Target
24 | {
25 | return input.col;
26 | }
--------------------------------------------------------------------------------
/BufferResource/Shader.fx:
--------------------------------------------------------------------------------
1 | struct VS_IN
2 | {
3 | float4 pos : POSITION;
4 | uint col : COLOR;
5 | };
6 |
7 | struct PS_IN
8 | {
9 | float4 pos : SV_POSITION;
10 | float4 col : COLOR;
11 | };
12 |
13 | Buffer colors : register(t0);
14 |
15 | PS_IN VS(VS_IN input)
16 | {
17 | PS_IN output = (PS_IN)0;
18 |
19 | output.pos = input.pos;
20 | output.col = colors.Load(input.col);
21 |
22 | return output;
23 | }
24 |
25 | float4 PS(PS_IN input) : SV_Target
26 | {
27 | return input.col;
28 | }
29 |
--------------------------------------------------------------------------------
/LightDx/Vectors.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.Linq;
5 | using System.Numerics;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace LightDx
10 | {
11 | public static class VectorHelper
12 | {
13 | public static Vector4 WithAlpha(this Color color, float alpha)
14 | {
15 | return new Vector4(color.R / 255.0f, color.G / 255.0f, color.B / 255.0f, alpha);
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Cube/Shader.fx:
--------------------------------------------------------------------------------
1 | struct VS_IN
2 | {
3 | float4 pos : POSITION;
4 | float4 col : COLOR;
5 | };
6 |
7 | struct PS_IN
8 | {
9 | float4 pos : SV_POSITION;
10 | float4 col : COLOR;
11 | };
12 |
13 | cbuffer VS_CONSTANT_BUFFER : register(b0)
14 | {
15 | float4x4 worldViewProj;
16 | }
17 |
18 | PS_IN VS(VS_IN input)
19 | {
20 | PS_IN output = (PS_IN)0;
21 |
22 | output.pos = mul(input.pos, worldViewProj);
23 | output.col = input.col;
24 |
25 | return output;
26 | }
27 |
28 | float4 PS(PS_IN input) : SV_Target
29 | {
30 | return input.col;
31 | }
32 |
--------------------------------------------------------------------------------
/Examples/TextureTriangle/Shader.fx:
--------------------------------------------------------------------------------
1 | struct VS_IN
2 | {
3 | float4 pos : POSITION;
4 | float4 tex : TEXCOORD;
5 | };
6 |
7 | struct PS_IN
8 | {
9 | float4 pos : SV_POSITION;
10 | float4 tex : TEXCOORD;
11 | };
12 |
13 | PS_IN VS( VS_IN input )
14 | {
15 | PS_IN output = (PS_IN)0;
16 |
17 | output.pos = input.pos;
18 | output.tex = input.tex;
19 |
20 | return output;
21 | }
22 |
23 | Texture2D faceTexture : register(t0);
24 | SamplerState textureSampler : register(s0);
25 |
26 | float4 PS( PS_IN input ) : SV_Target
27 | {
28 | return faceTexture.Sample(textureSampler, input.tex.xy);
29 | }
30 |
--------------------------------------------------------------------------------
/Examples/DynamicTriangle/Shader.fx:
--------------------------------------------------------------------------------
1 | struct VS_IN
2 | {
3 | float4 pos : POSITION;
4 | float4 col : COLOR;
5 | };
6 |
7 | struct PS_IN
8 | {
9 | float4 pos : SV_POSITION;
10 | float4 col : COLOR;
11 | };
12 |
13 | cbuffer CONSTANT_BUFFER : register(b0)
14 | {
15 | float4 fGlobalDiffuse;
16 | float fTime;
17 | };
18 |
19 | PS_IN VS(VS_IN input)
20 | {
21 | PS_IN output = (PS_IN)0;
22 |
23 | output.pos = input.pos;
24 | float r = abs(fTime * 2 - 1);
25 | output.col = input.col * (r * 0.5 + 0.5);
26 |
27 | return output;
28 | }
29 |
30 | float4 PS(PS_IN input) : SV_Target
31 | {
32 | return input.col * 0.1 + input.col * fGlobalDiffuse;
33 | }
34 |
--------------------------------------------------------------------------------
/Examples/DrawString/README.md:
--------------------------------------------------------------------------------
1 | DrawString
2 | ======
3 |
4 | This project shows how to draw text with LightDx.
5 |
6 | Instructions
7 | ------
8 | Text rendering is extremely easy. Basically you need 2 things:
9 | * A ```Sprite``` object for 2D rendering. Created from the ```LightDevice``` object.
10 | * A ```TextureFontCache``` for caching characters on internal textures. Created from
11 | the ```LightDevice``` object with a ```System.Drawing.Font``` object, where you specify
12 | the font face and font size.
13 |
14 | When you want to draw your text,
15 |
16 | * Make sure the ```Sprite``` is applied (it will setup the device to use its internal
17 | pipeline).
18 | * Call ```Sprite.DrawString```.
19 |
20 | Note that the metrics of the text can be obtained from the ```System.Drawing.Font```
21 | object.
22 |
--------------------------------------------------------------------------------
/LightDx/NativeException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace LightDx
8 | {
9 | internal class NativeException : Exception
10 | {
11 | public readonly uint Code;
12 |
13 | public NativeException(uint code)
14 | {
15 | Code = code;
16 | }
17 |
18 | public NativeException(uint code, string msg)
19 | : base(msg)
20 | {
21 | Code = code;
22 | }
23 | }
24 |
25 | internal static class NativeErrorHelper
26 | {
27 | public static void Check(this uint code)
28 | {
29 | if (code != 0)
30 | {
31 | throw new NativeException(code);
32 | }
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/LightDx/NativeHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Runtime.InteropServices;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace LightDx
9 | {
10 | internal static class NativeHelper
11 | {
12 | public static int Dispose(ref IntPtr obj)
13 | {
14 | int ret = 0;
15 | if (obj != IntPtr.Zero)
16 | {
17 | ret = Marshal.Release(obj);
18 | obj = IntPtr.Zero;
19 | }
20 | return ret;
21 | }
22 |
23 | public static IntPtr AddRef(this IntPtr comObj)
24 | {
25 | if (comObj != IntPtr.Zero)
26 | {
27 | Marshal.AddRef(comObj);
28 | }
29 | return comObj;
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/LightDx/ComScopeGuard.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Runtime.InteropServices;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace LightDx
9 | {
10 | internal class ComScopeGuard : IDisposable
11 | {
12 | public IntPtr Ptr;
13 |
14 | public ComScopeGuard()
15 | {
16 | }
17 |
18 | public ComScopeGuard(IntPtr ptr)
19 | {
20 | Ptr = ptr;
21 | }
22 |
23 | public void Dispose()
24 | {
25 | if (Ptr != IntPtr.Zero)
26 | {
27 | Marshal.Release(Ptr);
28 | Ptr = IntPtr.Zero;
29 | }
30 | }
31 |
32 | public IntPtr Move()
33 | {
34 | var ret = Ptr;
35 | Ptr = IntPtr.Zero;
36 | return ret;
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/LightDx/LightDx.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | LightDx
5 | 0.1.11
6 | Zhenwei Wu
7 | Zhenwei Wu
8 | https://opensource.org/licenses/MIT
9 | http://github.com/acaly/LightDX
10 | false
11 | A lightweight and easy-to-use C# graphics library backed by DirectX 11.
12 |
13 | Copyright 2018 Zhenwei Wu
14 | direct3d directx graphics utility
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/Examples/Triangle/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // 有关程序集的常规信息通过以下
6 | // 特性集控制。更改这些特性值可修改
7 | // 与程序集关联的信息。
8 | [assembly: AssemblyTitle("Triangle")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Triangle")]
13 | [assembly: AssemblyCopyright("Copyright © 2017")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // 将 ComVisible 设置为 false 使此程序集中的类型
18 | // 对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
19 | // 则将该类型上的 ComVisible 特性设置为 true。
20 | [assembly: ComVisible(false)]
21 |
22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
23 | [assembly: Guid("ba0df0b2-c074-4374-8dd6-fa6406318333")]
24 |
25 | // 程序集的版本信息由下面四个值组成:
26 | //
27 | // 主版本
28 | // 次版本
29 | // 生成号
30 | // 修订号
31 | //
32 | // 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
33 | // 方法是按如下所示使用“*”:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Wu Zhenwei
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Examples/TextureTriangle/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // 有关程序集的常规信息通过以下
6 | // 特性集控制。更改这些特性值可修改
7 | // 与程序集关联的信息。
8 | [assembly: AssemblyTitle("TextureTriangle")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("TextureTriangle")]
13 | [assembly: AssemblyCopyright("Copyright © 2017")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // 将 ComVisible 设置为 false 使此程序集中的类型
18 | // 对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
19 | // 则将该类型上的 ComVisible 特性设置为 true。
20 | [assembly: ComVisible(false)]
21 |
22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
23 | [assembly: Guid("41280b05-9e15-4843-a6d7-25a6510576d8")]
24 |
25 | // 程序集的版本信息由下面四个值组成:
26 | //
27 | // 主版本
28 | // 次版本
29 | // 生成号
30 | // 修订号
31 | //
32 | // 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
33 | // 方法是按如下所示使用“*”:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/Examples/Triangle/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace Triangle.Properties {
12 |
13 |
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.6.0.0")]
16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
17 |
18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
19 |
20 | public static Settings Default {
21 | get {
22 | return defaultInstance;
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/LightDx/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // 有关程序集的常规信息通过以下
6 | // 特性集控制。更改这些特性值可修改
7 | // 与程序集关联的信息。
8 | [assembly: AssemblyTitle("LightDx")]
9 | [assembly: AssemblyDescription("A lightweight and easy-to-use C# graphics library backed by DirectX 11.")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("LightDx")]
13 | [assembly: AssemblyCopyright("Copyright © 2018 Zhenwei Wu")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // 将 ComVisible 设置为 false 使此程序集中的类型
18 | // 对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
19 | // 则将该类型上的 ComVisible 特性设置为 true。
20 | [assembly: ComVisible(false)]
21 |
22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
23 | [assembly: Guid("b5428a8f-cebf-42d1-b673-a416226b910b")]
24 |
25 | // 程序集的版本信息由下面四个值组成:
26 | //
27 | // 主版本
28 | // 次版本
29 | // 生成号
30 | // 修订号
31 | //
32 | // 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
33 | // 方法是按如下所示使用“*”:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("0.1.10.0")]
36 | [assembly: AssemblyFileVersion("0.1.10.0")]
37 |
--------------------------------------------------------------------------------
/Examples/TextureTriangle/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace TextureTriangle.Properties {
12 |
13 |
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.6.0.0")]
16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
17 |
18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
19 |
20 | public static Settings Default {
21 | get {
22 | return defaultInstance;
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/LightDx/StaticMemory.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Runtime.InteropServices;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace LightDx
9 | {
10 | internal static class CompilerStringConstants
11 | {
12 | public static readonly IntPtr VS = Ptr("VS");
13 | public static readonly IntPtr GS = Ptr("GS");
14 | public static readonly IntPtr PS = Ptr("PS");
15 | public static readonly IntPtr vs_4_0 = Ptr("vs_4_0");
16 | public static readonly IntPtr gs_4_0 = Ptr("gs_4_0");
17 | public static readonly IntPtr ps_4_0 = Ptr("ps_4_0");
18 |
19 | private unsafe static IntPtr Ptr(string str)
20 | {
21 | return Marshal.StringToHGlobalAnsi(str);
22 | }
23 | }
24 |
25 | internal static class Guids
26 | {
27 | public static readonly IntPtr Texture2D = Allocate("6f15aaf2-d208-4e89-9ab4-489535d34f9c");
28 | public static readonly IntPtr Factory = Allocate("7b7166ec-21c7-44ae-b21a-c9ae321ae369");
29 |
30 | private static IntPtr Allocate(string guid)
31 | {
32 | IntPtr ret = Marshal.AllocHGlobal(16);
33 | Marshal.StructureToPtr(new Guid(guid), ret, false);
34 | return ret;
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Examples/DrawString/Program.cs:
--------------------------------------------------------------------------------
1 | using LightDx;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Drawing;
5 | using System.Linq;
6 | using System.Numerics;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using System.Windows.Forms;
10 |
11 | namespace DrawString
12 | {
13 | static class Program
14 | {
15 | [STAThread]
16 | static void Main(string[] args)
17 | {
18 | Application.EnableVisualStyles();
19 | Application.SetCompatibleTextRenderingDefault(false);
20 |
21 | var form = new Form();
22 | form.ClientSize = new Size(800, 600);
23 |
24 | using (var device = LightDevice.Create(form))
25 | {
26 | var target = new RenderTargetList(device.GetDefaultTarget(Color.White.WithAlpha(1)));
27 | target.Apply();
28 |
29 | var sprite = new Sprite(device);
30 | var guiFont = new TextureFontCache(device, SystemFonts.DefaultFont);
31 |
32 | form.Show();
33 | device.RunMultithreadLoop(delegate ()
34 | {
35 | target.ClearAll();
36 |
37 | sprite.Apply();
38 | sprite.DrawString(guiFont, "Hello World!", 0, 0, 800);
39 |
40 | device.Present(true);
41 | });
42 | }
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Cube/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Cube")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Cube")]
13 | [assembly: AssemblyCopyright("Copyright © 2019")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("e900f23b-ca00-4fb1-8ff5-7c50f828f763")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/LightDx/Blenders.cs:
--------------------------------------------------------------------------------
1 | using LightDx.Natives;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace LightDx
9 | {
10 | public sealed class Blender
11 | {
12 | private readonly bool _alpha;
13 |
14 | private Blender(bool alpha)
15 | {
16 | _alpha = alpha;
17 | }
18 |
19 | internal unsafe IntPtr CreateBlenderForDevice(LightDevice device)
20 | {
21 | if (!_alpha)
22 | {
23 | return IntPtr.Zero;
24 | }
25 | BlendDescription d = new BlendDescription();
26 | d.RenderTarget0.BlendEnable = 1; //true
27 | d.RenderTarget0.SrcBlend = 5; //D3D11_BLEND_SRC_ALPHA
28 | d.RenderTarget0.DestBlend = 6; //D3D11_BLEND_INV_SRC_ALPHA
29 | d.RenderTarget0.BlendOp = 1; //D3D11_BLEND_OP_ADD
30 | d.RenderTarget0.SrcBlendAlpha = 2; //D3D11_BLEND_ONE
31 | d.RenderTarget0.DestBlendAlpha = 1; //D3D11_BLEND_ZERO
32 | d.RenderTarget0.BlendOpAlpha = 1; //D3D11_BLEND_OP_ADD
33 | d.RenderTarget0.RenderTargetWriteMask = 15; //D3D11_COLOR_WRITE_ENABLE_ALL
34 | Device.CreateBlendState(device.DevicePtr, new IntPtr(&d), out var ret).Check();
35 | return ret;
36 | }
37 |
38 | public static readonly Blender Default = new Blender(false);
39 | public static readonly Blender AlphaBlender = new Blender(true);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Weavers/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Weavers")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Weavers")]
13 | [assembly: AssemblyCopyright("Copyright © 2018")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("5e830bd9-174d-49a2-8f79-4f193711d42a")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/BufferResource/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("BufferResource")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("BufferResource")]
13 | [assembly: AssemblyCopyright("Copyright © 2019")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("87b6f1bd-bab3-4cb0-b18f-218362d6a712")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/Examples/DrawString/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("DrawString")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("DrawString")]
13 | [assembly: AssemblyCopyright("Copyright © 2018")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("fe9bd09a-74e5-4ed8-bd61-1a9f128e5da0")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/Examples/DynamicTriangle/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("DynamicTriangle")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("DynamicTriangle")]
13 | [assembly: AssemblyCopyright("Copyright © 2018")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("d0e73992-784b-4f38-9198-4e08a7baf8ae")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/LightDx/FrameCounter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace LightDx
9 | {
10 | public sealed class FrameCounter
11 | {
12 | public FrameCounter()
13 | {
14 | UpdateMaxTime = 5000;
15 | UpdateMinTime = 50;
16 | UpdateFrame = 30;
17 |
18 | _count = 0;
19 | _clock = new Stopwatch();
20 | }
21 |
22 | public int UpdateMaxTime { get; set; }
23 | public int UpdateMinTime { get; set; }
24 | public int UpdateFrame { get; set; }
25 | private int _count;
26 | private long _totalCount;
27 | private Stopwatch _clock;
28 | private long _lastTick;
29 | private long _fpsStartTick;
30 |
31 | public long CountNumber => _totalCount;
32 |
33 | public void Start()
34 | {
35 | _clock.Start();
36 | }
37 |
38 | public float NextFrame()
39 | {
40 | _count += 1;
41 | _totalCount += 1;
42 | var tick = _clock.ElapsedTicks;
43 | var ret = (tick - _lastTick) / (float)TimeSpan.TicksPerMillisecond;
44 | _lastTick = tick;
45 |
46 | var ms = (tick - _fpsStartTick) / TimeSpan.TicksPerMillisecond;
47 | if (ms > UpdateMaxTime || _count >= UpdateFrame && ms > UpdateMinTime)
48 | {
49 | Update();
50 | }
51 |
52 | return ret;
53 | }
54 |
55 | private void Update()
56 | {
57 | Fps = (float)_count / (_clock.ElapsedTicks - _fpsStartTick) * TimeSpan.TicksPerSecond;
58 | _count = 0;
59 | _fpsStartTick = _clock.ElapsedTicks;
60 | }
61 |
62 | public float Fps { get; private set; }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/Weavers/UnmanagedConstrainWeaver.cs:
--------------------------------------------------------------------------------
1 | using Fody;
2 | using Mono.Cecil;
3 | using Mono.Cecil.Rocks;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace Weavers
11 | {
12 | public class UnmanagedConstrainWeaver : BaseModuleWeaver
13 | {
14 | public override void Execute()
15 | {
16 | var valueType = ModuleDefinition.ImportReference(typeof(ValueType));
17 |
18 | int replacedType = 0, replacedMethod = 0;
19 |
20 | foreach (var t in ModuleDefinition.GetAllTypes())
21 | {
22 | if (t.HasGenericParameters && t.GenericParameters[0].HasConstraints)
23 | {
24 | var g = t.GenericParameters[0];
25 | if (g.Constraints[0].FullName.Contains("Unmanaged"))
26 | {
27 | g.Constraints[0] = valueType;
28 | g.CustomAttributes.RemoveAt(0);
29 | replacedType++;
30 | }
31 | }
32 | }
33 | foreach (var m in ModuleDefinition.GetAllTypes().SelectMany(t => t.Methods))
34 | {
35 | var t = m;
36 | if (t.HasGenericParameters && t.GenericParameters[0].HasConstraints)
37 | {
38 | var g = t.GenericParameters[0];
39 | if (g.Constraints[0].FullName.Contains("Unmanaged"))
40 | {
41 | g.Constraints[0] = valueType;
42 | g.CustomAttributes.RemoveAt(0);
43 | replacedMethod++;
44 | }
45 | }
46 | }
47 |
48 | LogMessage($"LightDx unmanaged constrain weaver finished, replacing {replacedType} types " +
49 | $"and {replacedMethod} methods.", MessageImportance.High);
50 | }
51 |
52 | public override IEnumerable GetAssembliesForScanning()
53 | {
54 | yield break;
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/LightDx/MatrixHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Numerics;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace LightDx
9 | {
10 | public static class MatrixHelper
11 | {
12 | public static Matrix4x4 Transpose(this Matrix4x4 matrix)
13 | {
14 | return Matrix4x4.Transpose(matrix);
15 | }
16 |
17 | public static Matrix4x4 CreatePerspectiveFieldOfView(float fov, float aspectRatio, float nearPlane = 0.1f, float farPlane = 1000f)
18 | {
19 | var yScale = 1 / (float)Math.Tan(fov / 2);
20 | var xScale = yScale / aspectRatio;
21 |
22 | return new Matrix4x4
23 | {
24 | M11 = xScale,
25 | M22 = yScale,
26 | M33 = farPlane / (farPlane - nearPlane),
27 | M34 = 1,
28 | M43 = -nearPlane * farPlane / (farPlane - nearPlane)
29 | };
30 | }
31 |
32 | public static Matrix4x4 CreatePerspectiveFieldOfView(this LightDevice device, float fov, float nearPlane = 0.1f, float farPlane = 1000f)
33 | {
34 | return CreatePerspectiveFieldOfView(fov, device.ScreenWidth / (float)device.ScreenHeight, nearPlane, farPlane);
35 | }
36 |
37 | public static Matrix4x4 CreateLookAt(Vector3 pos, Vector3 lookAt, Vector3 up)
38 | {
39 | var zaxis = Vector3.Normalize(lookAt - pos);
40 | var xaxis = Vector3.Normalize(Vector3.Cross(up, zaxis));
41 | var yaxis = Vector3.Cross(zaxis, xaxis);
42 |
43 | return new Matrix4x4
44 | {
45 | M11 = xaxis.X,
46 | M21 = xaxis.Y,
47 | M31 = xaxis.Z,
48 | M12 = yaxis.X,
49 | M22 = yaxis.Y,
50 | M32 = yaxis.Z,
51 | M13 = zaxis.X,
52 | M23 = zaxis.Y,
53 | M33 = zaxis.Z,
54 | M41 = Vector3.Dot(xaxis, pos) * -1f,
55 | M42 = Vector3.Dot(yaxis, pos) * -1f,
56 | M43 = Vector3.Dot(zaxis, pos) * -1f,
57 | M44 = 1
58 | };
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/LightDx/Texture2D.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace LightDx
8 | {
9 | public sealed class Texture2D : IDisposable
10 | {
11 | private readonly LightDevice _device;
12 |
13 | private bool _holdPointer;
14 | private IntPtr _texture, _view;
15 | internal IntPtr ViewPtr => _view;
16 | internal IntPtr TexturePtr => _texture;
17 | public int Width { get; private set; }
18 | public int Height { get; private set; }
19 |
20 | private bool _disposed;
21 |
22 | internal Texture2D(LightDevice device, IntPtr tex, IntPtr view, int w, int h, bool holdPtr = true)
23 | {
24 | _device = device;
25 | device.AddComponent(this);
26 |
27 | _holdPointer = holdPtr;
28 |
29 | _texture = tex;
30 | _view = view;
31 |
32 | Width = w;
33 | Height = h;
34 | }
35 |
36 | ~Texture2D()
37 | {
38 | Dispose(false);
39 | }
40 |
41 | public void Dispose()
42 | {
43 | Dispose(true);
44 | }
45 |
46 | private void Dispose(bool disposing)
47 | {
48 | if (_disposed)
49 | {
50 | return;
51 | }
52 |
53 | if (_holdPointer)
54 | {
55 | NativeHelper.Dispose(ref _texture);
56 | NativeHelper.Dispose(ref _view);
57 | }
58 | else
59 | {
60 | _texture = _view = IntPtr.Zero;
61 | }
62 |
63 | if (disposing)
64 | {
65 | _device.RemoveComponent(this);
66 | }
67 |
68 | _disposed = true;
69 | GC.SuppressFinalize(this);
70 | }
71 |
72 | internal void UpdatePointer(int w, int h, IntPtr tex, IntPtr view)
73 | {
74 | if (_holdPointer)
75 | {
76 | throw new InvalidOperationException();
77 | }
78 | Width = w;
79 | Height = h;
80 | _texture = tex;
81 | _view = view;
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/Examples/Triangle/Program.cs:
--------------------------------------------------------------------------------
1 | using LightDx;
2 | using LightDx.InputAttributes;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Drawing;
6 | using System.Linq;
7 | using System.Numerics;
8 | using System.Reflection;
9 | using System.Threading.Tasks;
10 | using System.Windows.Forms;
11 |
12 | namespace Triangle
13 | {
14 | static class Program
15 | {
16 | private struct Vertex
17 | {
18 | [Position]
19 | public Vector4 Position;
20 | [Color]
21 | public Vector4 Color;
22 | }
23 |
24 | [STAThread]
25 | static void Main()
26 | {
27 | Application.EnableVisualStyles();
28 | Application.SetCompatibleTextRenderingDefault(false);
29 |
30 | var form = new Form();
31 | form.ClientSize = new Size(800, 600);
32 |
33 | using (var device = LightDevice.Create(form))
34 | {
35 | var target = new RenderTargetList(device.GetDefaultTarget());
36 | target.Apply();
37 |
38 | Pipeline pipeline = device.CompilePipeline(InputTopology.Triangle,
39 | ShaderSource.FromResource("Shader.fx", ShaderType.Vertex | ShaderType.Pixel));
40 | pipeline.Apply();
41 |
42 | var input = pipeline.CreateVertexDataProcessor();
43 | var buffer = input.CreateImmutableBuffer(new[] {
44 | new Vertex { Color = Color.Green.WithAlpha(1), Position = new Vector4(0.0f, 0.5f, 0.5f, 1.0f) },
45 | new Vertex { Color = Color.Red.WithAlpha(1), Position = new Vector4(0.5f, -0.5f, 0.5f, 1.0f) },
46 | new Vertex { Color = Color.Blue.WithAlpha(1), Position = new Vector4(-0.5f, -0.5f, 0.5f, 1.0f) },
47 | });
48 |
49 | var indexBuffer = pipeline.CreateImmutableIndexBuffer(new uint[] { 2, 0, 1 });
50 |
51 | form.Show();
52 | device.RunMultithreadLoop(delegate()
53 | {
54 | target.ClearAll();
55 | indexBuffer.DrawAll(buffer);
56 | device.Present(true);
57 | });
58 | }
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/LightDx/ConstantBuffer.cs:
--------------------------------------------------------------------------------
1 | using LightDx.Natives;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Runtime.InteropServices;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace LightDx
10 | {
11 | //TODO use same baseclass for all buffers
12 | public abstract class AbstractConstantBuffer : IDisposable
13 | {
14 | protected LightDevice _device;
15 | protected IntPtr _buffer;
16 | private bool _disposed;
17 |
18 | internal IntPtr BufferPtr => _buffer;
19 |
20 | internal protected AbstractConstantBuffer(LightDevice device, IntPtr buffer)
21 | {
22 | _device = device;
23 | device.AddComponent(this);
24 |
25 | _buffer = buffer;
26 | }
27 |
28 | ~AbstractConstantBuffer()
29 | {
30 | Dispose(false);
31 | }
32 |
33 | public void Dispose()
34 | {
35 | Dispose(true);
36 | }
37 |
38 | protected virtual void Dispose(bool disposing)
39 | {
40 | if (_disposed)
41 | {
42 | return;
43 | }
44 | NativeHelper.Dispose(ref _buffer);
45 |
46 | if (disposing)
47 | {
48 | _device.RemoveComponent(this);
49 | }
50 |
51 | _disposed = true;
52 | GC.SuppressFinalize(this);
53 | }
54 | }
55 |
56 | public unsafe sealed class ConstantBuffer : AbstractConstantBuffer
57 | where T : unmanaged
58 | {
59 | private static readonly int _Size = sizeof(T);
60 |
61 | internal ConstantBuffer(LightDevice device, IntPtr buffer)
62 | : base(device, buffer)
63 | {
64 | }
65 |
66 | public T Value;
67 |
68 | public void Update()
69 | {
70 | //Use Map/Unmap instead of UpdateSubresource.
71 | SubresourceData ret;
72 | DeviceContext.Map(_device.ContextPtr, _buffer, 0,
73 | 4 /* WRITE_DISCARD */, 0, &ret).Check();
74 | fixed (T* ptr = &Value)
75 | {
76 | Buffer.MemoryCopy(ptr, ret.pSysMem.ToPointer(), _Size, _Size);
77 | }
78 | DeviceContext.Unmap(_device.ContextPtr, _buffer, 0);
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/LightDx/ShaderResourceBuffer.cs:
--------------------------------------------------------------------------------
1 | using LightDx.Natives;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Runtime.InteropServices;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace LightDx
10 | {
11 | public abstract class AbstractShaderResourceBuffer : IDisposable
12 | {
13 | internal AbstractShaderResourceBuffer(LightDevice device, IntPtr pBuffer, IntPtr pView)
14 | {
15 | _device = device;
16 | device.AddComponent(this);
17 |
18 | _pBuffer = pBuffer;
19 | _pView = pView;
20 | }
21 |
22 | ~AbstractShaderResourceBuffer()
23 | {
24 | Dispose(false);
25 | }
26 |
27 | protected readonly LightDevice _device;
28 | protected IntPtr _pBuffer, _pView;
29 | private bool _disposed;
30 |
31 | internal IntPtr ViewPtr => _pView;
32 |
33 | public void Dispose()
34 | {
35 | Dispose(true);
36 | }
37 |
38 | private void Dispose(bool disposing)
39 | {
40 | if (_disposed)
41 | {
42 | return;
43 | }
44 | NativeHelper.Dispose(ref _pView);
45 | NativeHelper.Dispose(ref _pBuffer);
46 |
47 | if (disposing)
48 | {
49 | _device.RemoveComponent(this);
50 | }
51 |
52 | _disposed = true;
53 | GC.SuppressFinalize(this);
54 | }
55 | }
56 |
57 | public class ShaderResourceBuffer : AbstractShaderResourceBuffer where T : unmanaged
58 | {
59 | private static readonly int _Size = Marshal.SizeOf();
60 |
61 | internal ShaderResourceBuffer(LightDevice device, IntPtr pBuffer, IntPtr pView)
62 | : base(device, pBuffer, pView)
63 | {
64 | }
65 |
66 | public unsafe void Update(T[] data, int start = 0, int length = -1)
67 | {
68 | int realLength = length == -1 ? data.Length - start : length;
69 |
70 | SubresourceData ret;
71 | DeviceContext.Map(_device.ContextPtr, _pBuffer, 0,
72 | 4 /* WRITE_DISCARD */, 0, &ret).Check();
73 |
74 | fixed (T* pData = &data[start])
75 | {
76 | Buffer.MemoryCopy(pData, ret.pSysMem.ToPointer(), _Size * realLength, _Size * realLength);
77 | }
78 |
79 | DeviceContext.Unmap(_device.ContextPtr, _pBuffer, 0);
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/LightDx/ShaderSource.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Reflection;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace LightDx
10 | {
11 | public sealed class ShaderSource
12 | {
13 | internal byte[] Data { get; private set; }
14 | internal ShaderType ShaderTypes { get; private set; }
15 |
16 | private ShaderSource(Stream stream, ShaderType types)
17 | {
18 | stream.Seek(0, SeekOrigin.Begin);
19 |
20 | int start = 0;
21 |
22 | //Skip UTF-8 BOM
23 | if (stream.Length > 3)
24 | {
25 | byte[] bom = new byte[3];
26 | stream.Read(bom, 0, 3);
27 | if (bom[0] == 0xEF && bom[1] == 0xBB && bom[2] == 0xBF)
28 | {
29 | start = 3;
30 | }
31 | else
32 | {
33 | stream.Seek(0, SeekOrigin.Begin);
34 | }
35 | }
36 |
37 | byte[] shaderCode = new byte[stream.Length - start];
38 | stream.Read(shaderCode, 0, shaderCode.Length);
39 | Data = shaderCode;
40 | ShaderTypes = types;
41 | }
42 |
43 | private ShaderSource(byte[] data, ShaderType types)
44 | {
45 | Data = data;
46 | ShaderTypes = types;
47 | }
48 |
49 | public static ShaderSource FromString(string code, ShaderType types)
50 | {
51 | return new ShaderSource(Encoding.ASCII.GetBytes(code), types);
52 | }
53 |
54 | public static ShaderSource FromFile(string filename, ShaderType types)
55 | {
56 | using (var file = File.OpenRead(filename))
57 | {
58 | return new ShaderSource(file, types);
59 | }
60 | }
61 |
62 | public static ShaderSource FromStream(Stream stream, ShaderType types)
63 | {
64 | return new ShaderSource(stream, types);
65 | }
66 |
67 | public static ShaderSource FromResource(string name, ShaderType types)
68 | {
69 | return FromResource(Assembly.GetEntryAssembly(), name, types);
70 | }
71 |
72 | public static ShaderSource FromResource(Assembly assembly, string name, ShaderType types)
73 | {
74 | return FromStream(assembly.GetManifestResourceStream(assembly.GetName().Name + "." + name), types);
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/BufferResource/Program.cs:
--------------------------------------------------------------------------------
1 | using LightDx;
2 | using LightDx.InputAttributes;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Drawing;
6 | using System.Linq;
7 | using System.Numerics;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 | using System.Windows.Forms;
11 |
12 | namespace BufferResource
13 | {
14 | class Program
15 | {
16 | private struct Vertex
17 | {
18 | [Position]
19 | public Vector4 Position;
20 | [Color(Format = 42 /* DXGI_FORMAT_R32_UINT */)]
21 | public uint Color;
22 | }
23 |
24 | [STAThread]
25 | static void Main()
26 | {
27 | Application.EnableVisualStyles();
28 | Application.SetCompatibleTextRenderingDefault(false);
29 |
30 | var form = new Form();
31 | form.ClientSize = new Size(800, 600);
32 |
33 | using (var device = LightDevice.Create(form))
34 | {
35 | var target = new RenderTargetList(device.GetDefaultTarget());
36 | target.Apply();
37 |
38 | Pipeline pipeline = device.CompilePipeline(InputTopology.Triangle,
39 | ShaderSource.FromResource("Shader.fx", ShaderType.Vertex | ShaderType.Pixel));
40 | pipeline.Apply();
41 |
42 | var input = pipeline.CreateVertexDataProcessor();
43 | var buffer = input.CreateImmutableBuffer(new[] {
44 | new Vertex { Color = 0, Position = new Vector4(0.0f, 0.5f, 0.5f, 1.0f) },
45 | new Vertex { Color = 1, Position = new Vector4(0.5f, -0.5f, 0.5f, 1.0f) },
46 | new Vertex { Color = 2, Position = new Vector4(-0.5f, -0.5f, 0.5f, 1.0f) },
47 | });
48 |
49 | var indexBuffer = pipeline.CreateImmutableIndexBuffer(new uint[] { 2, 0, 1 });
50 |
51 | var srBuffer = pipeline.CreateShaderResourceBuffer(new[]
52 | {
53 | Color.Blue.WithAlpha(1),
54 | Color.Red.WithAlpha(1),
55 | Color.Green.WithAlpha(1),
56 | }, false);
57 | pipeline.SetResource(ShaderType.Vertex, 0, srBuffer);
58 |
59 | form.Show();
60 | device.RunMultithreadLoop(delegate ()
61 | {
62 | target.ClearAll();
63 | indexBuffer.DrawAll(buffer);
64 | device.Present(true);
65 | });
66 | }
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/LightDx/VertexBuffer.cs:
--------------------------------------------------------------------------------
1 | using LightDx.Natives;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace LightDx
9 | {
10 | public sealed class VertexBuffer : IDisposable
11 | {
12 | private readonly LightDevice _device;
13 | private readonly IBufferUpdate _update;
14 |
15 | //support only one buffer
16 | private IntPtr _buffer;
17 | private IntPtr _layout;
18 | private uint _stride;
19 | private int _vertexCount;
20 | private bool _isDynamic;
21 |
22 | private bool _disposed;
23 |
24 | internal bool IsDynamic => _isDynamic;
25 | internal uint Stride => _stride;
26 | internal IntPtr BufferPtr => _buffer;
27 | internal int VertexCount => _vertexCount;
28 |
29 | internal VertexBuffer(LightDevice device, IBufferUpdate update, IntPtr buffer, IntPtr layout,
30 | int stride, int vertexCount, bool isDynamic)
31 | {
32 | _device = device;
33 | device.AddComponent(this);
34 |
35 | _update = update;
36 | _buffer = buffer;
37 | _layout = layout;
38 | _stride = (uint)stride;
39 | _vertexCount = vertexCount;
40 | _isDynamic = isDynamic;
41 | }
42 |
43 | ~VertexBuffer()
44 | {
45 | Dispose(false);
46 | }
47 |
48 | public void Dispose()
49 | {
50 | Dispose(true);
51 | }
52 |
53 | private void Dispose(bool disposing)
54 | {
55 | if (_disposed)
56 | {
57 | return;
58 | }
59 | NativeHelper.Dispose(ref _buffer);
60 | NativeHelper.Dispose(ref _layout);
61 |
62 | if (disposing)
63 | {
64 | _device.RemoveComponent(this);
65 | }
66 |
67 | _disposed = true;
68 | GC.SuppressFinalize(this);
69 | }
70 |
71 | internal unsafe void Bind()
72 | {
73 | DeviceContext.IASetInputLayout(_device.ContextPtr, _layout);
74 | uint stride = _stride, offset = 0;
75 | IntPtr buffer = _buffer;
76 | DeviceContext.IASetVertexBuffers(_device.ContextPtr, 0, 1, &buffer, &stride, &offset);
77 | }
78 |
79 | public void Update(Array data, int start = 0, int length = -1)
80 | {
81 | _update.UpdateBuffer(this, data, start, length);
82 | }
83 |
84 | public void DrawAll()
85 | {
86 | Draw(0, _vertexCount);
87 | }
88 |
89 | public void Draw(int vertexOffset, int vertexCount)
90 | {
91 | Bind();
92 | DeviceContext.Draw(_device.ContextPtr, (uint)vertexCount, (uint)vertexOffset);
93 | }
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/LightDx/RenderTargetList.cs:
--------------------------------------------------------------------------------
1 | using LightDx.Natives;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Runtime.InteropServices;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace LightDx
10 | {
11 | public sealed class RenderTargetList
12 | {
13 | private RenderTargetObject[] _renderTargets;
14 | private IntPtr[] _viewPtr; //The COM objects will be freed by RenderTargetObjects.
15 | private RenderTargetObject _depthStencil;
16 |
17 | public RenderTargetList(params RenderTargetObject[] renderTargetObjects)
18 | {
19 | if (renderTargetObjects.Length < 1)
20 | {
21 | throw new ArgumentException(nameof(renderTargetObjects));
22 | }
23 | LightDevice device = renderTargetObjects[0].Device;
24 | int renderTarget = 0, depthStencil = 0;
25 | if (renderTargetObjects[0].IsDepthStencil)
26 | {
27 | depthStencil += 1;
28 | }
29 | else
30 | {
31 | renderTarget += 1;
32 | }
33 | for (int i = 1; i < renderTargetObjects.Length; ++i)
34 | {
35 | if (renderTargetObjects[i].Device != device)
36 | {
37 | throw new ArgumentException("target not from same device");
38 | }
39 | if (renderTargetObjects[i].IsDepthStencil)
40 | {
41 | depthStencil += 1;
42 | }
43 | else
44 | {
45 | renderTarget += 1;
46 | }
47 | }
48 | if (renderTarget == 0 || depthStencil > 1)
49 | {
50 | throw new ArgumentException("invalid target type");
51 | }
52 | _renderTargets = renderTargetObjects.Where(t => !t.IsDepthStencil).ToArray();
53 | _depthStencil = renderTargetObjects.FirstOrDefault(t => t.IsDepthStencil);
54 | _viewPtr = new IntPtr[_renderTargets.Length];
55 | }
56 |
57 | public unsafe void Apply()
58 | {
59 | var device = _renderTargets[0].Device;
60 | for (int i = 0; i < _renderTargets.Length; ++i)
61 | {
62 | _viewPtr[i] = _renderTargets[i].ViewPtr;
63 | }
64 | fixed (IntPtr* ptr = _viewPtr)
65 | {
66 | DeviceContext.OMSetRenderTargets(device.ContextPtr, (uint)_renderTargets.Length,
67 | ptr, _depthStencil?.ViewPtr ?? IntPtr.Zero);
68 | }
69 | device.CurrentTarget = this;
70 | }
71 |
72 | public void ClearAll()
73 | {
74 | foreach (var t in _renderTargets)
75 | {
76 | t.Clear();
77 | }
78 | _depthStencil?.Clear();
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/Examples/TextureTriangle/Program.cs:
--------------------------------------------------------------------------------
1 | using LightDx;
2 | using LightDx.InputAttributes;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Drawing;
6 | using System.Linq;
7 | using System.Numerics;
8 | using System.Reflection;
9 | using System.Threading.Tasks;
10 | using System.Windows.Forms;
11 |
12 | namespace TextureTriangle
13 | {
14 | static class Program
15 | {
16 | private struct Vertex
17 | {
18 | [Position]
19 | public Vector4 Position;
20 | [TexCoord]
21 | public Vector4 TexCoord;
22 | }
23 |
24 | [STAThread]
25 | static void Main()
26 | {
27 | Application.EnableVisualStyles();
28 | Application.SetCompatibleTextRenderingDefault(false);
29 |
30 | var form = new Form();
31 | form.ClientSize = new Size(800, 600);
32 |
33 | using (var device = LightDevice.Create(form))
34 | {
35 | var target = new RenderTargetList(device.GetDefaultTarget());
36 | target.Apply();
37 |
38 | Pipeline pipeline = device.CompilePipeline(InputTopology.Triangle,
39 | ShaderSource.FromResource("Shader.fx", ShaderType.Vertex | ShaderType.Pixel));
40 |
41 | Texture2D texture;
42 | using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("TextureTriangle.Hiyori.png"))
43 | {
44 | using (var bitmap = new Bitmap(stream))
45 | {
46 | texture = device.CreateTexture2D(bitmap);
47 | pipeline.SetResource(0, texture);
48 | }
49 | }
50 |
51 | pipeline.Apply();
52 |
53 | var input = pipeline.CreateVertexDataProcessor();
54 | var buffer = input.CreateImmutableBuffer(new[] {
55 | new Vertex { TexCoord = new Vector4(0, 0, 0, 0), Position = new Vector4(-0.5f, 0.5f, 0.5f, 1.0f) },
56 | new Vertex { TexCoord = new Vector4(1, 0, 0, 0), Position = new Vector4(0.5f, 0.5f, 0.5f, 1.0f) },
57 | new Vertex { TexCoord = new Vector4(0, 1, 0, 0), Position = new Vector4(-0.5f, -0.5f, 0.5f, 1.0f) },
58 |
59 | new Vertex { TexCoord = new Vector4(0, 1, 0, 0), Position = new Vector4(-0.5f, -0.5f, 0.5f, 1.0f) },
60 | new Vertex { TexCoord = new Vector4(1, 0, 0, 0), Position = new Vector4(0.5f, 0.5f, 0.5f, 1.0f) },
61 | new Vertex { TexCoord = new Vector4(1, 1, 0, 0), Position = new Vector4(0.5f, -0.5f, 0.5f, 1.0f) },
62 | });
63 |
64 | form.Show();
65 | device.RunMultithreadLoop(delegate()
66 | {
67 | target.ClearAll();
68 | buffer.DrawAll();
69 | device.Present(true);
70 | });
71 | }
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/Examples/Triangle/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace Triangle.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Triangle.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/Examples/TextureTriangle/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace TextureTriangle.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("TextureTriangle.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/LightDx/InputAttributes.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Runtime.InteropServices;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace LightDx.InputAttributes
9 | {
10 | public abstract class InputAttribute : Attribute
11 | {
12 | internal abstract IntPtr SemanticName { get; }
13 | internal int SemanticIndex { get; set; }
14 |
15 | public int Format { get; set; }
16 |
17 | internal static readonly IntPtr POSITION = Marshal.StringToHGlobalAnsi("POSITION");
18 | internal static readonly IntPtr COLOR = Marshal.StringToHGlobalAnsi("COLOR");
19 | internal static readonly IntPtr TEXCOORD = Marshal.StringToHGlobalAnsi("TEXCOORD");
20 | internal static readonly IntPtr NORMAL = Marshal.StringToHGlobalAnsi("NORMAL");
21 | internal static readonly IntPtr TANGENT = Marshal.StringToHGlobalAnsi("TANGENT");
22 | internal static readonly IntPtr BINORMAL = Marshal.StringToHGlobalAnsi("BINORMAL");
23 | }
24 |
25 | public sealed class PositionAttribute : InputAttribute
26 | {
27 | public PositionAttribute(int id = 0)
28 | {
29 | SemanticIndex = id;
30 | }
31 |
32 | internal override IntPtr SemanticName
33 | {
34 | get { return POSITION; }
35 | }
36 | }
37 |
38 | public sealed class ColorAttribute : InputAttribute
39 | {
40 | public ColorAttribute(int id = 0)
41 | {
42 | SemanticIndex = id;
43 | }
44 |
45 | internal override IntPtr SemanticName
46 | {
47 | get { return COLOR; }
48 | }
49 | }
50 |
51 | public sealed class TexCoordAttribute : InputAttribute
52 | {
53 | public TexCoordAttribute(int id = 0)
54 | {
55 | SemanticIndex = id;
56 | }
57 |
58 | internal override IntPtr SemanticName
59 | {
60 | get { return TEXCOORD; }
61 | }
62 | }
63 |
64 | public sealed class NormalAttribute : InputAttribute
65 | {
66 | public NormalAttribute(int id = 0)
67 | {
68 | SemanticIndex = id;
69 | }
70 |
71 | internal override IntPtr SemanticName
72 | {
73 | get { return NORMAL; }
74 | }
75 | }
76 |
77 | public sealed class TangentAttribute : InputAttribute
78 | {
79 | public TangentAttribute(int id = 0)
80 | {
81 | SemanticIndex = id;
82 | }
83 |
84 | internal override IntPtr SemanticName
85 | {
86 | get { return TANGENT; }
87 | }
88 | }
89 |
90 | public sealed class BinormalAttribute : InputAttribute
91 | {
92 | public BinormalAttribute(int id = 0)
93 | {
94 | SemanticIndex = id;
95 | }
96 |
97 | internal override IntPtr SemanticName
98 | {
99 | get { return BINORMAL; }
100 | }
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/Cube/Cube.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {E900F23B-CA00-4FB1-8FF5-7C50F828F763}
8 | WinExe
9 | Cube
10 | Cube
11 | v4.7
12 | 512
13 | true
14 |
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 | true
26 |
27 |
28 | AnyCPU
29 | pdbonly
30 | true
31 | bin\Release\
32 | TRACE
33 | prompt
34 | 4
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 | {45b0c93a-0aaf-41e3-bf58-61f42ef2c256}
63 | LightDx
64 |
65 |
66 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/BufferResource/BufferResource.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {87B6F1BD-BAB3-4CB0-B18F-218362D6A712}
8 | WinExe
9 | BufferResource
10 | BufferResource
11 | v4.7
12 | 512
13 | true
14 | true
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 | true
26 |
27 |
28 | AnyCPU
29 | pdbonly
30 | true
31 | bin\Release\
32 | TRACE
33 | prompt
34 | 4
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | {45b0c93a-0aaf-41e3-bf58-61f42ef2c256}
62 | LightDx
63 |
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # LightDX
2 | [](https://www.nuget.org/packages/LightDx/)
3 |
4 | LightDX is a graphics library in C#. It is designed to be used for those who want
5 | to use DirectX for accelerated rendering (visualization or a simple game). It supports
6 | most important funtions in Direct3D, but heavily relys on .NET Framework on other works.
7 |
8 | ## **Note**
9 | This is a work in progress, so public APIs are expected to have breaking changes.
10 |
11 | # Features
12 | * **Lightweight.**
13 | No dependencies except the Framework. Less than 100KB after compiled. You can just
14 | copy the source to your project and include them (though it requires unsafe). Even
15 | if you don't want to directly include them, you can still have everything in a
16 | single small DLL (SharpDX can generously give you 7). No native DLL is needed, so it
17 | works on 'AnyCPU'.
18 | * **Clean.**
19 | Focus on Direct3D. Use the .NET Framework as much as possible: Bitmap format
20 | conversion, font rendering, mouse and keyboard input, vector and matrix math.
21 | Fortunately the .NET Framework API is well designed and can be directly used here,
22 | which avoids tons of work.
23 | * **Easy to use.**
24 | Unlike SharpDX or SlimDX, LightDX is not a DirectX binding. Therefore it hides
25 | the complicated details of creating each components and only provides simplified
26 | API, which makes it much easier to use. This may have some limits, but hopefully
27 | LightDX will provide everything you really need.
28 | * **Fast.**
29 | LightDX utilizes calli instruction to call native COM methods, as
30 | SharpDX does. This should be the fastest method. Other parts are also written with
31 | efficiency in mind (at least to my best).
32 |
33 | # Limitations
34 | Limitations in design:
35 | * Single thread API. No multithread rendering.
36 | * Only supports Windows desktop application. Other platforms are not tested.
37 |
38 | Limitations in current implementation (may be fixed in the future):
39 | * Only support Texture2D as ShaderResource.
40 |
41 | ... and many other not supported features in DX11...
42 |
43 | # How to use
44 | Nuget package ```LightDx``` is available now. (Only .NET Framework 4.7 is supported.)
45 |
46 | Please check the following projects that uses LightDx:
47 | * [Examples](Examples) folder.
48 | * [DirectX 11 Tutorial](https://github.com/acaly/LightDx.DirectX11Tutorials), implementing
49 | some of the examples from http://rastertek.com/tutdx11.html.
50 | * [ImGuiOnLightDx](https://github.com/acaly/ImGuiOnLightDx), a simple implementation of
51 | the ImGui backend.
52 | * [MMDRenderer](https://github.com/acaly/MMDRenderer), a simple MMD model renderer using
53 | deferred rendering pipeline.
54 | * [Sandbox](https://github.com/acaly/Sandbox), a high-performance Minecraft-like world
55 | rendering engine.
56 | * [VoxelModelEditor](https://github.com/acaly/VoxelModelEditor), a model and animation
57 | editor using WinForms.
58 |
59 | ### About Cube example
60 |
61 | * It's outside the examples folder by mistake.
62 | * The `Camera` class should have a `GetViewMatrix` method:
63 |
64 | ```c#
65 | public Matrix4x4 GetViewMatrix()
66 | {
67 | return MatrixHelper.CreateLookAt(Position, Position + CalcOffset(), Vector3.UnitZ).Transpose();
68 | }
69 | ```
70 |
--------------------------------------------------------------------------------
/LightDx/IndexBuffer.cs:
--------------------------------------------------------------------------------
1 | using LightDx.Natives;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace LightDx
9 | {
10 | public sealed class IndexBuffer : IDisposable
11 | {
12 | internal IndexBuffer(LightDevice device, IntPtr ptr, int bitWidth, int size)
13 | {
14 | _device = device;
15 | device.AddComponent(this);
16 |
17 | _ptr = ptr;
18 | _bitWidth = bitWidth;
19 | _size = size;
20 | }
21 |
22 | ~IndexBuffer()
23 | {
24 | Dispose(false);
25 | }
26 |
27 | private readonly LightDevice _device;
28 | private IntPtr _ptr;
29 | private readonly int _bitWidth;
30 | private readonly int _size;
31 | private bool _disposed;
32 |
33 | public void Dispose()
34 | {
35 | Dispose(true);
36 | }
37 |
38 | private void Dispose(bool disposing)
39 | {
40 | if (_disposed)
41 | {
42 | return;
43 | }
44 | NativeHelper.Dispose(ref _ptr);
45 |
46 | if (disposing)
47 | {
48 | _device.RemoveComponent(this);
49 | }
50 |
51 | _disposed = true;
52 | GC.SuppressFinalize(this);
53 | }
54 |
55 | internal void Bind()
56 | {
57 | DeviceContext.IASetIndexBuffer(_device.ContextPtr, _ptr,
58 | _bitWidth == 16 ? 57u /* DXGI_FORMAT_R16_UINT */ : 42u /* DXGI_FORMAT_R32_UINT */, 0);
59 | }
60 |
61 | public unsafe void UpdateDynamic(T[] data, int startIndex = 0, int length = -1) where T : unmanaged
62 | {
63 | int realLength = length == -1 ? data.Length - startIndex : length;
64 | SubresourceData ret;
65 | DeviceContext.Map(_device.ContextPtr, _ptr, 0, 4 /* WRITE_DISCARD */, 0, &ret).Check();
66 |
67 | if (_bitWidth != sizeof(T) * 8)
68 | {
69 | throw new ArgumentException("Invalid index size");
70 | }
71 |
72 | var copyLen = sizeof(T) * realLength;
73 | fixed (T* pData = &data[startIndex])
74 | {
75 | Buffer.MemoryCopy(pData, ret.pSysMem.ToPointer(), copyLen, copyLen);
76 | }
77 |
78 | DeviceContext.Unmap(_device.ContextPtr, _ptr, 0);
79 | }
80 |
81 | public void DrawAll(VertexBuffer vertex)
82 | {
83 | Draw(vertex, 0, _size);
84 | }
85 |
86 | public void Draw(VertexBuffer vertex, int startIndex, int indexCount)
87 | {
88 | Bind();
89 | vertex.Bind();
90 | DeviceContext.DrawIndexed(_device.ContextPtr, (uint)indexCount, (uint)startIndex, 0);
91 | }
92 |
93 | public void DrawAll(VertexDataProcessorGroup group, VertexBuffer[] vertex)
94 | {
95 | Draw(group, vertex, 0, _size);
96 | }
97 |
98 | public void Draw(VertexDataProcessorGroup group, VertexBuffer[] vertex,
99 | int startIndex, int indexCount)
100 | {
101 | Bind();
102 | group.Bind(vertex);
103 | DeviceContext.DrawIndexed(_device.ContextPtr, (uint)indexCount, (uint)startIndex, 0);
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/Cube/Camera.cs:
--------------------------------------------------------------------------------
1 | using LightDx;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Numerics;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using System.Windows.Forms;
9 |
10 | namespace Cube
11 | {
12 | class Camera
13 | {
14 | public Vector3 Position;
15 | public float yaw, pitch;
16 |
17 | private Dictionary keys;
18 |
19 | public Camera(Vector3 pos)
20 | {
21 | Position = pos;
22 | }
23 |
24 | private Vector3 CalcOffset()
25 | {
26 | Vector4 offset = new Vector4(-10, 0, 0, 0);
27 | Vector4 x = new Vector4(0, 1, 0, 0);
28 | offset = Vector4.Transform(offset, Matrix4x4.CreateRotationZ(yaw));
29 | x = Vector4.Transform(x, Matrix4x4.CreateRotationZ(yaw));
30 | pitch = Math.Min((float)Math.PI / 2.001f, pitch);
31 | pitch = Math.Max((float)Math.PI / -2.001f, pitch);
32 | offset = Vector4.Transform(offset, Matrix4x4.CreateFromAxisAngle(new Vector3(x.X, x.Y, x.Z), -pitch));
33 | return new Vector3(offset.X, offset.Y, offset.Z);
34 | }
35 |
36 | public Vector3 MoveHorizontal(Vector4 b)
37 | {
38 | Vector4 move = b;
39 | move = Vector4.Transform(move, Matrix4x4.CreateRotationZ(yaw));
40 | return new Vector3(move.X, move.Y, move.Z);
41 | }
42 |
43 | public Vector3 MoveHorizontal(float x, float y)
44 | {
45 | return MoveHorizontal(new Vector4(x, y, 0, 0));
46 | }
47 |
48 | public void SetForm(Form form)
49 | {
50 | keys = new Dictionary() {
51 | { Keys.W, false }, { Keys.S, false }, { Keys.A, false }, { Keys.D, false },
52 | { Keys.Up, false }, { Keys.Down, false }, { Keys.Left, false }, { Keys.Right, false },
53 | { Keys.Q, false }, { Keys.E, false },
54 | { Keys.Space, false }, { Keys.Z, false },
55 | };
56 | form.KeyDown += delegate (object obj, KeyEventArgs e)
57 | {
58 | if (keys.ContainsKey(e.KeyCode)) keys[e.KeyCode] = true;
59 | };
60 | form.KeyUp += delegate (object obj, KeyEventArgs e)
61 | {
62 | if (keys.ContainsKey(e.KeyCode)) keys[e.KeyCode] = false;
63 | };
64 | }
65 |
66 | public void Step()
67 | {
68 | Vector3 acc;
69 | Vector4 movedir = new Vector4(0, 0, 0, 0);
70 | if (keys[Keys.W]) movedir.X -= 1;
71 | if (keys[Keys.S]) movedir.X += 1;
72 | if (keys[Keys.A]) movedir.Y += 1;
73 | if (keys[Keys.D]) movedir.Y -= 1;
74 | if (movedir.LengthSquared() > 0)
75 | {
76 | movedir = Vector4.Normalize(movedir);
77 | acc = MoveHorizontal(movedir);
78 | Position += acc * 0.05f;
79 | }
80 |
81 | if (keys[Keys.Up]) pitch -= 0.03f;
82 | if (keys[Keys.Down]) pitch += 0.03f;
83 | if (keys[Keys.Left]) yaw -= 0.03f;
84 | if (keys[Keys.Right]) yaw += 0.03f;
85 |
86 | if (keys[Keys.Space])
87 | {
88 | Position.Z += 0.01f;
89 | }
90 | else if (keys[Keys.Z])
91 | {
92 | Position.Z -= 0.05f;
93 | }
94 | }
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/Weavers/Weavers.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {5E830BD9-174D-49A2-8F79-4F193711D42A}
8 | Library
9 | Properties
10 | Weavers
11 | Weavers
12 | v4.7
13 | 512
14 |
15 |
16 |
17 |
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 | true
26 |
27 |
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 |
35 |
36 |
37 | ..\packages\FodyHelpers.3.0.3\lib\net46\FodyHelpers.dll
38 |
39 |
40 | ..\packages\FodyHelpers.3.0.3\lib\net46\Mono.Cecil.dll
41 |
42 |
43 | ..\packages\FodyHelpers.3.0.3\lib\net46\Mono.Cecil.Mdb.dll
44 |
45 |
46 | ..\packages\FodyHelpers.3.0.3\lib\net46\Mono.Cecil.Pdb.dll
47 |
48 |
49 | ..\packages\FodyHelpers.3.0.3\lib\net46\Mono.Cecil.Rocks.dll
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/LightDx/VertexDataProcessorGroup.cs:
--------------------------------------------------------------------------------
1 | using LightDx.Natives;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace LightDx
9 | {
10 | public class VertexDataProcessorGroup : IDisposable
11 | {
12 | private readonly LightDevice _device;
13 | internal readonly Type[] VertexTypes;
14 | internal readonly object[] Processors;
15 | private IntPtr _layout;
16 | private bool _disposed;
17 |
18 | private readonly uint[] _offsets;
19 |
20 | public VertexDataProcessorGroup(LightDevice device, Type[] vertexTypes, object[] processors, IntPtr layout)
21 | {
22 | _device = device;
23 | VertexTypes = vertexTypes;
24 | Processors = processors;
25 | _layout = layout;
26 | _offsets = new uint[vertexTypes.Length];
27 | }
28 |
29 | ~VertexDataProcessorGroup()
30 | {
31 | Dispose(false);
32 | }
33 |
34 | public void Dispose()
35 | {
36 | Dispose(true);
37 | }
38 |
39 | protected void Dispose(bool disposing)
40 | {
41 | if (_disposed) return;
42 |
43 | NativeHelper.Dispose(ref _layout);
44 |
45 | if (disposing)
46 | {
47 | foreach (var p in Processors)
48 | {
49 | ((IDisposable)p).Dispose();
50 | }
51 | }
52 |
53 | _disposed = true;
54 | GC.SuppressFinalize(this);
55 | }
56 |
57 | public VertexDataProcessor GetVertexDataProcessor() where T : unmanaged
58 | {
59 | for (int i = 0; i < VertexTypes.Length; ++i)
60 | {
61 | if (VertexTypes[i] == typeof(T))
62 | {
63 | return (VertexDataProcessor)Processors[i];
64 | }
65 | }
66 | return null;
67 | }
68 |
69 | public unsafe void Bind(VertexBuffer[] buffers, uint[] offsets = null)
70 | {
71 | if (buffers.Length != VertexTypes.Length)
72 | {
73 | throw new ArgumentException();
74 | }
75 | DeviceContext.IASetInputLayout(_device.ContextPtr, _layout);
76 |
77 | uint[] strides = new uint[buffers.Length];
78 | IntPtr[] ptrs = new IntPtr[buffers.Length];
79 | for (int i = 0; i < buffers.Length; ++i)
80 | {
81 | strides[i] = buffers[i].Stride;
82 | ptrs[i] = buffers[i].BufferPtr;
83 | }
84 | uint[] realOffset = offsets ?? _offsets;
85 |
86 | fixed (uint* pstrides = strides)
87 | {
88 | fixed (IntPtr* pptrs = ptrs)
89 | {
90 | fixed (uint* poffsets = realOffset)
91 | {
92 | DeviceContext.IASetVertexBuffers(_device.ContextPtr, 0, (uint)buffers.Length, pptrs, pstrides, poffsets);
93 | }
94 | }
95 | }
96 | }
97 |
98 | public void Draw(int vertexOffset, int vertexCount)
99 | {
100 | DeviceContext.Draw(_device.ContextPtr, (uint)vertexCount, (uint)vertexOffset);
101 | }
102 |
103 | public void BindAndDrawAll(VertexBuffer[] buffers)
104 | {
105 | BindAndDraw(buffers, 0, buffers[0].VertexCount);
106 | }
107 |
108 | public void BindAndDraw(VertexBuffer[] buffers, int vertexOffset, int vertexCount)
109 | {
110 | Bind(buffers);
111 | Draw(vertexOffset, vertexCount);
112 | }
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/LightDx/TextureFontCache.cs:
--------------------------------------------------------------------------------
1 | using LightDx.Natives;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Drawing;
5 | using System.Drawing.Imaging;
6 | using System.Linq;
7 | using System.Runtime.InteropServices;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 |
11 | namespace LightDx
12 | {
13 | public sealed class TextureFontCache : AbstractFontCache
14 | {
15 | private class MemoryCacheItem : IDisposable
16 | {
17 | public MemoryCacheItem(IntPtr ptr, int stride, int height)
18 | {
19 | Ptr = ptr;
20 | Stride = stride;
21 | Height = height;
22 | }
23 |
24 | ~MemoryCacheItem()
25 | {
26 | Dispose();
27 | }
28 |
29 | public IntPtr Ptr;
30 | public int Stride;
31 | public int Height;
32 |
33 | public void Dispose()
34 | {
35 | Marshal.FreeHGlobal(Ptr);
36 | Ptr = IntPtr.Zero;
37 | }
38 | }
39 |
40 | public TextureFontCache(LightDevice device, Font font)
41 | : base(device, font, PixelFormat.Format32bppArgb, Color.Black, Color.Transparent)
42 | {
43 | }
44 |
45 | private readonly Dictionary _memCache = new Dictionary();
46 | private readonly HashSet _dirtyCache = new HashSet();
47 | private const int PixelSize = 1;
48 |
49 | protected override Texture2D CreateBitmap(int w, int h)
50 | {
51 | var ret = _device.CreateTexture2D(w, h, 65 /*A8_UNORM*/, IntPtr.Zero, 0, true);
52 | //Possible memory leak (only when the new fails). Won't fix.
53 | _memCache.Add(ret,
54 | new MemoryCacheItem(Marshal.AllocHGlobal(w * h * PixelSize), w * PixelSize, h));
55 | return ret;
56 | }
57 |
58 | protected override void DisposeBitmap(Texture2D bitmap)
59 | {
60 | _memCache[bitmap].Dispose();
61 | _memCache.Remove(bitmap);
62 | bitmap.Dispose();
63 | }
64 |
65 | protected override unsafe void UpdateCache(Texture2D bitmap,
66 | int x, int y, int w, int h, BitmapData data)
67 | {
68 | var p = _memCache[bitmap];
69 | byte* destScan0 = ((byte*)p.Ptr) + p.Stride * y + PixelSize * x;
70 | for (int b = 0; b < h; ++b)
71 | {
72 | byte* src = ((byte*)data.Scan0) + data.Stride * b + 3;
73 | byte* dest = destScan0 + p.Stride * b;
74 | for (int a = 0; a < w; ++a)
75 | {
76 | *dest = *src;
77 | dest += 1;
78 | src += 4;
79 | }
80 | }
81 | _dirtyCache.Add(bitmap);
82 | }
83 |
84 | protected override unsafe void FlushCache(Texture2D bitmap)
85 | {
86 | if (_dirtyCache.Contains(bitmap))
87 | {
88 | _dirtyCache.Remove(bitmap);
89 |
90 | SubresourceData d;
91 | DeviceContext.Map(_device.ContextPtr, bitmap.TexturePtr, 0, 4, 0, &d).Check();
92 |
93 | var p = _memCache[bitmap];
94 | for (int i = 0; i < p.Height; ++i)
95 | {
96 | System.Buffer.MemoryCopy((byte*)p.Ptr.ToPointer() + p.Stride * i,
97 | (byte*)d.pSysMem + d.SysMemPitch * i, p.Stride, p.Stride);
98 | }
99 |
100 | DeviceContext.Unmap(_device.ContextPtr, bitmap.TexturePtr, 0);
101 | }
102 | }
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/Examples/DrawString/DrawString.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {FE9BD09A-74E5-4ED8-BD61-1A9F128E5DA0}
8 | WinExe
9 | DrawString
10 | DrawString
11 | v4.7
12 | 512
13 | true
14 |
15 |
16 | AnyCPU
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 | true
25 |
26 |
27 | AnyCPU
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 |
35 |
36 |
37 |
38 |
39 | true
40 | bin\x64\Debug\
41 | DEBUG;TRACE
42 | full
43 | x64
44 | prompt
45 | MinimumRecommendedRules.ruleset
46 | true
47 |
48 |
49 | bin\x64\Release\
50 | TRACE
51 | true
52 | pdbonly
53 | x64
54 | prompt
55 | MinimumRecommendedRules.ruleset
56 | true
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | {45b0c93a-0aaf-41e3-bf58-61f42ef2c256}
81 | LightDx
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/Examples/DynamicTriangle/DynamicTriangle.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {D0E73992-784B-4F38-9198-4E08A7BAF8AE}
8 | WinExe
9 | DynamicTriangle
10 | DynamicTriangle
11 | v4.7
12 | 512
13 | true
14 |
15 |
16 | AnyCPU
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 | true
25 |
26 |
27 | AnyCPU
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 |
35 |
36 |
37 |
38 |
39 | true
40 | bin\x64\Debug\
41 | DEBUG;TRACE
42 | full
43 | x64
44 | prompt
45 | MinimumRecommendedRules.ruleset
46 | true
47 |
48 |
49 | bin\x64\Release\
50 | TRACE
51 | true
52 | pdbonly
53 | x64
54 | prompt
55 | MinimumRecommendedRules.ruleset
56 | true
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | {45b0c93a-0aaf-41e3-bf58-61f42ef2c256}
81 | LightDx
82 |
83 |
84 |
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | build/
21 | bld/
22 | [Bb]in/
23 | [Oo]bj/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 |
28 | # MSTest test Results
29 | [Tt]est[Rr]esult*/
30 | [Bb]uild[Ll]og.*
31 |
32 | # NUNIT
33 | *.VisualState.xml
34 | TestResult.xml
35 |
36 | # Build Results of an ATL Project
37 | [Dd]ebugPS/
38 | [Rr]eleasePS/
39 | dlldata.c
40 |
41 | # DNX
42 | project.lock.json
43 | artifacts/
44 |
45 | *_i.c
46 | *_p.c
47 | *_i.h
48 | *.ilk
49 | *.meta
50 | *.obj
51 | *.pch
52 | *.pdb
53 | *.pgc
54 | *.pgd
55 | *.rsp
56 | *.sbr
57 | *.tlb
58 | *.tli
59 | *.tlh
60 | *.tmp
61 | *.tmp_proj
62 | *.log
63 | *.vspscc
64 | *.vssscc
65 | .builds
66 | *.pidb
67 | *.svclog
68 | *.scc
69 |
70 | # Chutzpah Test files
71 | _Chutzpah*
72 |
73 | # Visual C++ cache files
74 | ipch/
75 | *.aps
76 | *.ncb
77 | *.opensdf
78 | *.sdf
79 | *.cachefile
80 |
81 | # Visual Studio profiler
82 | *.psess
83 | *.vsp
84 | *.vspx
85 |
86 | # TFS 2012 Local Workspace
87 | $tf/
88 |
89 | # Guidance Automation Toolkit
90 | *.gpState
91 |
92 | # ReSharper is a .NET coding add-in
93 | _ReSharper*/
94 | *.[Rr]e[Ss]harper
95 | *.DotSettings.user
96 |
97 | # JustCode is a .NET coding add-in
98 | .JustCode
99 |
100 | # TeamCity is a build add-in
101 | _TeamCity*
102 |
103 | # DotCover is a Code Coverage Tool
104 | *.dotCover
105 |
106 | # NCrunch
107 | _NCrunch_*
108 | .*crunch*.local.xml
109 |
110 | # MightyMoose
111 | *.mm.*
112 | AutoTest.Net/
113 |
114 | # Web workbench (sass)
115 | .sass-cache/
116 |
117 | # Installshield output folder
118 | [Ee]xpress/
119 |
120 | # DocProject is a documentation generator add-in
121 | DocProject/buildhelp/
122 | DocProject/Help/*.HxT
123 | DocProject/Help/*.HxC
124 | DocProject/Help/*.hhc
125 | DocProject/Help/*.hhk
126 | DocProject/Help/*.hhp
127 | DocProject/Help/Html2
128 | DocProject/Help/html
129 |
130 | # Click-Once directory
131 | publish/
132 |
133 | # Publish Web Output
134 | *.[Pp]ublish.xml
135 | *.azurePubxml
136 | # TODO: Comment the next line if you want to checkin your web deploy settings
137 | # but database connection strings (with potential passwords) will be unencrypted
138 | *.pubxml
139 | *.publishproj
140 |
141 | # NuGet Packages
142 | *.nupkg
143 | # The packages folder can be ignored because of Package Restore
144 | **/packages/*
145 | # except build/, which is used as an MSBuild target.
146 | !**/packages/build/
147 | # Uncomment if necessary however generally it will be regenerated when needed
148 | #!**/packages/repositories.config
149 |
150 | # Windows Azure Build Output
151 | csx/
152 | *.build.csdef
153 |
154 | # Windows Store app package directory
155 | AppPackages/
156 |
157 | # Visual Studio cache files
158 | # files ending in .cache can be ignored
159 | *.[Cc]ache
160 | # but keep track of directories ending in .cache
161 | !*.[Cc]ache/
162 |
163 | # Others
164 | ClientBin/
165 | [Ss]tyle[Cc]op.*
166 | ~$*
167 | *~
168 | *.dbmdl
169 | *.dbproj.schemaview
170 | *.pfx
171 | *.publishsettings
172 | node_modules/
173 | orleans.codegen.cs
174 |
175 | # RIA/Silverlight projects
176 | Generated_Code/
177 |
178 | # Backup & report files from converting an old project file
179 | # to a newer Visual Studio version. Backup files are not needed,
180 | # because we have git ;-)
181 | _UpgradeReport_Files/
182 | Backup*/
183 | UpgradeLog*.XML
184 | UpgradeLog*.htm
185 |
186 | # SQL Server files
187 | *.mdf
188 | *.ldf
189 |
190 | # Business Intelligence projects
191 | *.rdl.data
192 | *.bim.layout
193 | *.bim_*.settings
194 |
195 | # Microsoft Fakes
196 | FakesAssemblies/
197 |
198 | # Node.js Tools for Visual Studio
199 | .ntvs_analysis.dat
200 |
201 | # Visual Studio 6 build log
202 | *.plg
203 |
204 | # Visual Studio 6 workspace options file
205 | *.opt
--------------------------------------------------------------------------------
/Cube/Program.cs:
--------------------------------------------------------------------------------
1 | using LightDx;
2 | using LightDx.InputAttributes;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Drawing;
6 | using System.Linq;
7 | using System.Numerics;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 | using System.Windows.Forms;
11 |
12 | namespace Cube
13 | {
14 | class Program
15 | {
16 | private struct Vertex
17 | {
18 | [Position]
19 | public Vector4 Position;
20 | [Color]
21 | public Vector4 Color;
22 | }
23 |
24 | private static void SetupCubeFace(Vertex[] buffer, int offset, Vector3 center3, Vector3 u3, Vector3 v3)
25 | {
26 | var center = new Vector4(center3, 1);
27 | var u = new Vector4(u3 / 2, 0);
28 | var v = new Vector4(v3 / 2, 0);
29 | var pp = center + u + v;
30 | var pn = center + u - v;
31 | var np = center - u + v;
32 | var nn = center - u - v;
33 | buffer[offset + 0].Position = np;
34 | buffer[offset + 1].Position = pp;
35 | buffer[offset + 2].Position = pn;
36 | buffer[offset + 3].Position = pn;
37 | buffer[offset + 4].Position = nn;
38 | buffer[offset + 5].Position = np;
39 | }
40 |
41 | [STAThread]
42 | static void Main()
43 | {
44 | Application.EnableVisualStyles();
45 | Application.SetCompatibleTextRenderingDefault(false);
46 |
47 | var form = new Form();
48 | form.ClientSize = new Size(800, 600);
49 |
50 | using (var device = LightDevice.Create(form))
51 | {
52 | var target = new RenderTargetList(device.GetDefaultTarget(), device.CreateDepthStencilTarget());
53 | target.Apply();
54 |
55 | Pipeline pipeline = device.CompilePipeline(InputTopology.Triangle,
56 | ShaderSource.FromResource("Shader.fx", ShaderType.Vertex | ShaderType.Pixel));
57 | pipeline.Apply();
58 |
59 | var vertexConstant = pipeline.CreateConstantBuffer();
60 | pipeline.SetConstant(ShaderType.Vertex, 0, vertexConstant);
61 |
62 | var input = pipeline.CreateVertexDataProcessor();
63 | var bufferData = new Vertex[6 * 6];
64 | for (int i = 0; i < bufferData.Length; ++i)
65 | {
66 | bufferData[i].Color = Color.FromArgb(250, i / 6 * 40, 250 - i / 6 * 30).WithAlpha(1);
67 | }
68 | SetupCubeFace(bufferData, 00, new Vector3(0.5f, 0, 0), new Vector3(0, 0, 1), new Vector3(0, 1, 0));
69 | SetupCubeFace(bufferData, 06, new Vector3(-0.5f, 0, 0), new Vector3(0, 1, 0), new Vector3(0, 0, 1));
70 | SetupCubeFace(bufferData, 12, new Vector3(0, 0.5f, 0), new Vector3(1, 0, 0), new Vector3(0, 0, 1));
71 | SetupCubeFace(bufferData, 18, new Vector3(0, -0.5f, 0), new Vector3(0, 0, 1), new Vector3(1, 0, 0));
72 | SetupCubeFace(bufferData, 24, new Vector3(0, 0, 0.5f), new Vector3(0, 1, 0), new Vector3(1, 0, 0));
73 | SetupCubeFace(bufferData, 30, new Vector3(0, 0, -0.5f), new Vector3(1, 0, 0), new Vector3(0, 1, 0));
74 | var buffer = input.CreateImmutableBuffer(bufferData);
75 |
76 | var camera = new Camera(new Vector3(10, 0, 0));
77 | camera.SetForm(form);
78 | var proj = device.CreatePerspectiveFieldOfView((float)Math.PI / 4).Transpose();
79 |
80 | vertexConstant.Value = proj * camera.GetViewMatrix();
81 | var pt = new Vector4(0, 0, 0, 0);
82 | var r = Vector4.Transform(pt, vertexConstant.Value);
83 |
84 | form.Show();
85 | device.RunMultithreadLoop(delegate ()
86 | {
87 | target.ClearAll();
88 |
89 | camera.Step();
90 | vertexConstant.Value = proj * camera.GetViewMatrix();
91 | vertexConstant.Update();
92 |
93 | buffer.DrawAll();
94 | device.Present(true);
95 | });
96 | }
97 | }
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/LightDx/CalliGenerator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Reflection;
5 | using System.Reflection.Emit;
6 | using System.Runtime.InteropServices;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace LightDx
11 | {
12 | //This class is modified version of http://rogue-modron.blogspot.ca/2011/11/invoking-native.html
13 | internal class CalliGenerator
14 | {
15 | public static TDelegate GetCalliDelegate(int offset)
16 | where TDelegate : class
17 | {
18 | var delegateType = typeof(TDelegate);
19 | var invokeInfo = delegateType.GetMethod("Invoke");
20 |
21 | ScanParameter(invokeInfo.GetParameters(),
22 | out var invokeTypes, out var calliTypes, out var lastRefIntPtr);
23 |
24 | var calliMethod = new DynamicMethod("CalliInvoke",
25 | invokeInfo.ReturnType, invokeTypes, typeof(CalliGenerator).Module, true);
26 | var generator = calliMethod.GetILGenerator();
27 |
28 | // Generate the pinned local
29 | generator.DeclareLocal(typeof(IntPtr*), true);
30 |
31 | // Pin the out IntPtr
32 | if (lastRefIntPtr != -1)
33 | {
34 | generator.Emit(OpCodes.Ldarg, lastRefIntPtr);
35 | generator.Emit(OpCodes.Stloc_0);
36 | }
37 |
38 | GeneratePushArguments(generator, calliTypes.Length, lastRefIntPtr, -1);
39 | GenerateGetVTable(generator, offset);
40 | generator.EmitCalli(OpCodes.Calli, CallingConvention.StdCall,
41 | invokeInfo.ReturnType, calliTypes);
42 |
43 | generator.Emit(OpCodes.Ret);
44 |
45 | return (TDelegate)(object)calliMethod.CreateDelegate(delegateType);
46 | }
47 |
48 | private static void ScanParameter(ParameterInfo[] parameters,
49 | out Type[] invokeTypes, out Type[] calliTypes, out int lastRefIntPtr)
50 | {
51 | invokeTypes = new Type[parameters.Length];
52 | calliTypes = new Type[parameters.Length];
53 | lastRefIntPtr = -1;
54 |
55 | for (int i = 0; i < parameters.Length; i++)
56 | {
57 | var type = parameters[i].ParameterType;
58 | invokeTypes[i] = type;
59 | calliTypes[i] = GetPointerTypeIfReference(type);
60 | if (type.IsByRef && type.GetElementType() == typeof(IntPtr))
61 | {
62 | lastRefIntPtr = i;
63 | }
64 | }
65 | }
66 |
67 | private static Type GetPointerTypeIfReference(Type type)
68 | {
69 | if (type.IsByRef)
70 | {
71 | return type.GetElementType().MakePointerType();
72 | }
73 | return type;
74 | }
75 |
76 | private static void GeneratePushArguments(ILGenerator generator, int count, int pinnedRef, int pinnedRef2)
77 | {
78 | for (int i = 0; i < count; i++)
79 | {
80 | if (i == pinnedRef)
81 | {
82 | generator.Emit(OpCodes.Ldloc_0);
83 | }
84 | else if (i == pinnedRef2)
85 | {
86 | generator.Emit(OpCodes.Ldloc_1);
87 | }
88 | else if (i == 0)
89 | {
90 | generator.Emit(OpCodes.Ldarg_0);
91 | }
92 | else if (i == 1)
93 | {
94 | generator.Emit(OpCodes.Ldarg_1);
95 | }
96 | else if (i == 2)
97 | {
98 | generator.Emit(OpCodes.Ldarg_2);
99 | }
100 | else if (i == 3)
101 | {
102 | generator.Emit(OpCodes.Ldarg_3);
103 | }
104 | else
105 | {
106 | generator.Emit(OpCodes.Ldarg, i);
107 | }
108 | }
109 | }
110 |
111 | private static void GenerateGetVTable(ILGenerator generator, int offset)
112 | {
113 | generator.Emit(OpCodes.Ldarg_0);
114 | generator.Emit(OpCodes.Ldind_I);
115 | generator.Emit(OpCodes.Ldc_I4, offset);
116 | generator.Emit(OpCodes.Conv_I);
117 | generator.Emit(OpCodes.Sizeof, typeof(void*));
118 | generator.Emit(OpCodes.Mul);
119 | generator.Emit(OpCodes.Add);
120 | generator.Emit(OpCodes.Ldind_I);
121 | }
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/Examples/DynamicTriangle/Program.cs:
--------------------------------------------------------------------------------
1 | using LightDx;
2 | using LightDx.InputAttributes;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Diagnostics;
6 | using System.Drawing;
7 | using System.Linq;
8 | using System.Numerics;
9 | using System.Reflection;
10 | using System.Text;
11 | using System.Threading.Tasks;
12 | using System.Windows.Forms;
13 |
14 | namespace DynamicTriangle
15 | {
16 | static class Program
17 | {
18 | private struct VertexP
19 | {
20 | [Position]
21 | public Vector4 Position;
22 | }
23 | private struct VertexC
24 | {
25 | [Color]
26 | public Vector4 Color;
27 | }
28 |
29 | private struct ConstantBuffer
30 | {
31 | public Vector4 GlobalAlpha;
32 | public float Time;
33 | }
34 |
35 | static void SetCoordinate(LightDevice device, ref Vector4 position, double angle)
36 | {
37 | position.X = 0.5f * (float)Math.Cos(angle) * 600 / device.ScreenWidth;
38 | position.Y = 0.5f * (float)Math.Sin(angle) * 600 / device.ScreenHeight;
39 | }
40 |
41 | [STAThread]
42 | static void Main()
43 | {
44 | Application.EnableVisualStyles();
45 | Application.SetCompatibleTextRenderingDefault(false);
46 |
47 | var form = new Form();
48 | form.ClientSize = new Size(800, 600);
49 |
50 | using (var device = LightDevice.Create(form))
51 | {
52 | var target = new RenderTargetList(device.GetDefaultTarget());
53 | target.Apply();
54 |
55 | Pipeline pipeline = device.CompilePipeline(InputTopology.Triangle,
56 | ShaderSource.FromResource("Shader.fx", ShaderType.Vertex | ShaderType.Pixel));
57 | pipeline.Apply();
58 |
59 | var inputGroup = pipeline.CreateVertexDataProcessors(new[] {
60 | typeof(VertexP),
61 | typeof(VertexC),
62 | });
63 | var input1 = inputGroup.GetVertexDataProcessor();
64 | var input2 = inputGroup.GetVertexDataProcessor();
65 |
66 | var buffer1 = input1.CreateDynamicBuffer(3);
67 | var vertexPosData = new[] {
68 | new VertexP { Position = new Vector4(0, 0, 0.5f, 1) },
69 | new VertexP { Position = new Vector4(0, 0, 0.5f, 1) },
70 | new VertexP { Position = new Vector4(0, 0, 0.5f, 1) },
71 | };
72 | var buffer2 = input2.CreateImmutableBuffer(new[] {
73 | new VertexC { Color = Color.Green.WithAlpha(1) },
74 | new VertexC { Color = Color.Red.WithAlpha(1) },
75 | new VertexC { Color = Color.Blue.WithAlpha(1) },
76 | });
77 | var bufferGroup = new[] { buffer1, buffer2 };
78 |
79 | var indexBuffer = pipeline.CreateImmutableIndexBuffer(new uint[] { 0, 1, 2 });
80 |
81 | var constantBuffer = pipeline.CreateConstantBuffer();
82 | pipeline.SetConstant(ShaderType.Vertex, 0, constantBuffer);
83 | pipeline.SetConstant(ShaderType.Pixel, 0, constantBuffer);
84 |
85 | constantBuffer.Value.GlobalAlpha = new Vector4(1, 1, 1, 1);
86 |
87 | form.Show();
88 |
89 | var i = 0;
90 | var rand = new Random();
91 |
92 | var clock = Stopwatch.StartNew();
93 | device.RunMultithreadLoop(delegate ()
94 | {
95 | var angle = -clock.Elapsed.TotalSeconds * Math.PI / 3;
96 | var distance = Math.PI * 2 / 3;
97 |
98 | SetCoordinate(device, ref vertexPosData[0].Position, angle);
99 | SetCoordinate(device, ref vertexPosData[1].Position, angle - distance);
100 | SetCoordinate(device, ref vertexPosData[2].Position, angle + distance);
101 | buffer1.Update(vertexPosData);
102 |
103 | constantBuffer.Value.Time = ((float)clock.Elapsed.TotalSeconds % 2) / 2;
104 |
105 | if (++i == 60)
106 | {
107 | i = 0;
108 | constantBuffer.Value.GlobalAlpha.X = (float)rand.NextDouble() * 0.5f + 0.5f;
109 | constantBuffer.Value.GlobalAlpha.Y = (float)rand.NextDouble() * 0.5f + 0.5f;
110 | constantBuffer.Value.GlobalAlpha.Z = (float)rand.NextDouble() * 0.5f + 0.5f;
111 | }
112 | constantBuffer.Update();
113 |
114 | target.ClearAll();
115 | indexBuffer.DrawAll(inputGroup, bufferGroup);
116 |
117 | device.Present(true);
118 | });
119 | }
120 | }
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/Examples/Triangle/Triangle.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {B35FE686-B955-4C7A-AA7F-BA1FF5185674}
8 | WinExe
9 | Properties
10 | Triangle
11 | Triangle
12 | v4.7
13 | 512
14 |
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 | true
26 |
27 |
28 | AnyCPU
29 | pdbonly
30 | true
31 | bin\Release\
32 | TRACE
33 | prompt
34 | 4
35 |
36 |
37 | true
38 | bin\x64\Debug\
39 | DEBUG;TRACE
40 | full
41 | x64
42 | prompt
43 | MinimumRecommendedRules.ruleset
44 | true
45 |
46 |
47 | bin\x64\Release\
48 | TRACE
49 | true
50 | pdbonly
51 | x64
52 | prompt
53 | MinimumRecommendedRules.ruleset
54 | true
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | ResXFileCodeGenerator
74 | Resources.Designer.cs
75 | Designer
76 |
77 |
78 | True
79 | Resources.resx
80 | True
81 |
82 |
83 | SettingsSingleFileGenerator
84 | Settings.Designer.cs
85 |
86 |
87 | True
88 | Settings.settings
89 | True
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 | {45b0c93a-0aaf-41e3-bf58-61f42ef2c256}
101 | LightDx
102 |
103 |
104 |
105 |
112 |
--------------------------------------------------------------------------------
/Weavers/AOTCalliGenerator.cs:
--------------------------------------------------------------------------------
1 | using Mono.Cecil;
2 | using Mono.Cecil.Cil;
3 | using Mono.Cecil.Rocks;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace Weavers
11 | {
12 | class AOTCalliGenerator
13 | {
14 | public static void Generate(ModuleDefinition module, MethodReference invokeInfo, MethodDefinition gen, int offset, TypeReference pinnedPtrIntPtr, TypeReference ptrVoid)
15 | {
16 | ScanParameter(invokeInfo.Parameters.ToArray(),
17 | out var invokeTypes, out var calliTypes, out var lastRefIntPtr);
18 |
19 | // Generate the pinned local
20 | var local0 = new VariableDefinition(pinnedPtrIntPtr);
21 | gen.Body.Variables.Add(local0);
22 |
23 | // Pin the out IntPtr
24 | if (lastRefIntPtr != -1)
25 | {
26 | gen.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_S, gen.Parameters[lastRefIntPtr]));
27 | gen.Body.Instructions.Add(Instruction.Create(OpCodes.Stloc_0));
28 | }
29 |
30 | GeneratePushArguments(gen, calliTypes.Length, lastRefIntPtr, -1, gen.Parameters);
31 | GenerateGetVTable(gen, offset, ptrVoid);
32 |
33 | var callsite = new CallSite(invokeInfo.ReturnType);
34 | callsite.CallingConvention = MethodCallingConvention.StdCall;
35 | foreach (var p in calliTypes)
36 | {
37 | callsite.Parameters.Add(new ParameterDefinition(p));
38 | }
39 |
40 | gen.Body.Instructions.Add(Instruction.Create(OpCodes.Calli, callsite));
41 |
42 | gen.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
43 | }
44 |
45 | private static void ScanParameter(ParameterDefinition[] parameters,
46 | out TypeReference[] invokeTypes, out TypeReference[] calliTypes, out int lastRefIntPtr)
47 | {
48 | invokeTypes = new TypeReference[parameters.Length];
49 | calliTypes = new TypeReference[parameters.Length];
50 | lastRefIntPtr = -1;
51 |
52 | for (int i = 0; i < parameters.Length; i++)
53 | {
54 | var type = parameters[i].ParameterType;
55 | invokeTypes[i] = type;
56 | calliTypes[i] = GetPointerTypeIfReference(type); //TODO import?
57 | if (type.IsByReference && type.GetElementType().FullName == "System.IntPtr")
58 | {
59 | lastRefIntPtr = i;
60 | }
61 | }
62 | }
63 |
64 | private static TypeReference GetPointerTypeIfReference(TypeReference type)
65 | {
66 | if (type.IsByReference)
67 | {
68 | return type.GetElementType().MakePointerType();
69 | }
70 | return type;
71 | }
72 |
73 | private static void GeneratePushArguments(MethodDefinition gen, int count, int pinnedRef, int pinnedRef2, IList parameters)
74 | {
75 | for (int i = 0; i < count; i++)
76 | {
77 | if (i == pinnedRef)
78 | {
79 | gen.Body.Instructions.Add(Instruction.Create(OpCodes.Ldloc_0));
80 | }
81 | else if (i == pinnedRef2)
82 | {
83 | gen.Body.Instructions.Add(Instruction.Create(OpCodes.Ldloc_1));
84 | }
85 | else if (i == 0)
86 | {
87 | gen.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0));
88 | }
89 | else if (i == 1)
90 | {
91 | gen.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_1));
92 | }
93 | else if (i == 2)
94 | {
95 | gen.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_2));
96 | }
97 | else if (i == 3)
98 | {
99 | gen.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_3));
100 | }
101 | else
102 | {
103 | gen.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_S, parameters[i]));
104 | }
105 | }
106 | }
107 |
108 | private static void GenerateGetVTable(MethodDefinition gen, int offset, TypeReference ptrVoid)
109 | {
110 | gen.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0));
111 | gen.Body.Instructions.Add(Instruction.Create(OpCodes.Ldind_I));
112 | gen.Body.Instructions.Add(Instruction.Create(OpCodes.Ldc_I4, offset));
113 | gen.Body.Instructions.Add(Instruction.Create(OpCodes.Conv_I));
114 | gen.Body.Instructions.Add(Instruction.Create(OpCodes.Sizeof, ptrVoid));
115 | gen.Body.Instructions.Add(Instruction.Create(OpCodes.Mul));
116 | gen.Body.Instructions.Add(Instruction.Create(OpCodes.Add));
117 | gen.Body.Instructions.Add(Instruction.Create(OpCodes.Ldind_I));
118 | }
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/Examples/TextureTriangle/TextureTriangle.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {69D3CBDE-6740-4199-96EC-622240537C8A}
8 | WinExe
9 | Properties
10 | TextureTriangle
11 | TextureTriangle
12 | v4.7
13 | 512
14 |
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 | true
26 |
27 |
28 | AnyCPU
29 | pdbonly
30 | true
31 | bin\Release\
32 | TRACE
33 | prompt
34 | 4
35 |
36 |
37 | true
38 | bin\x64\Debug\
39 | DEBUG;TRACE
40 | full
41 | x64
42 | prompt
43 | MinimumRecommendedRules.ruleset
44 | true
45 |
46 |
47 | bin\x64\Release\
48 | TRACE
49 | true
50 | pdbonly
51 | x64
52 | prompt
53 | MinimumRecommendedRules.ruleset
54 | true
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | ResXFileCodeGenerator
74 | Resources.Designer.cs
75 | Designer
76 |
77 |
78 | True
79 | Resources.resx
80 | True
81 |
82 |
83 | SettingsSingleFileGenerator
84 | Settings.Designer.cs
85 |
86 |
87 | True
88 | Settings.settings
89 | True
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 | {45b0c93a-0aaf-41e3-bf58-61f42ef2c256}
98 | LightDx
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
115 |
--------------------------------------------------------------------------------
/Examples/Triangle/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/Examples/TextureTriangle/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/LightDx/DDSReader.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace LightDx
9 | {
10 | internal unsafe class DDSReader
11 | {
12 | #pragma warning disable CS0649
13 |
14 | struct DdsHeader
15 | {
16 | public uint Magic;
17 | public uint Size;
18 | public uint Flags;
19 | public uint Height;
20 | public uint Width;
21 | public uint PitchOrLinearSize;
22 | public uint Depth;
23 | public uint MipMapCount;
24 | public fixed uint Reserved1[11];
25 | public PixelFormat PixelFormat;
26 | public fixed uint caps[4];
27 | public uint Reserved2;
28 | };
29 |
30 | private struct PixelFormat
31 | {
32 | public uint Size;
33 | public uint Flags;
34 | public uint FourCC;
35 | public uint RGBBitCount;
36 | public uint RBitMask;
37 | public uint GBitMask;
38 | public uint BBitMask;
39 | public uint ABitMask;
40 | };
41 |
42 | private struct HeaderDx10
43 | {
44 | public uint DXGIFormat;
45 | public uint ResourceDimension;
46 | public uint MiscFlag;
47 | public uint ArraySize;
48 | public uint MiscFlags2;
49 | };
50 |
51 | #pragma warning restore CS0649
52 |
53 | private const uint MagicDDS = 0x20534444; //"DDS "
54 | private const uint MagicDXT1 = 0x31545844; //"DXT1"
55 | private const uint MagicDXT3 = 0x33545844; //"DXT3"
56 | private const uint MagicDXT5 = 0x35545844; //"DXT5"
57 | private const uint MagicDX10 = 0x30315844; //"DX10"
58 |
59 | public static bool CheckHeader(byte[] magic)
60 | {
61 | return BitConverter.ToUInt32(magic, 0) == MagicDDS;
62 | }
63 |
64 | private static readonly byte[] s_buffer = new byte[4 * 32];
65 |
66 | private static T Read(Stream stream) where T : unmanaged
67 | {
68 | lock (s_buffer)
69 | {
70 | var r = stream.Read(s_buffer, 0, sizeof(T));
71 | Check(r == sizeof(T));
72 | fixed (byte* bufferPtr = s_buffer)
73 | {
74 | return *(T*)bufferPtr;
75 | }
76 | }
77 | }
78 |
79 | private static void Check(bool cond)
80 | {
81 | if (!cond)
82 | {
83 | throw new IOException("Invalid DDS file");
84 | }
85 | }
86 |
87 | public static Texture2D Load(LightDevice device, Stream stream)
88 | {
89 | var header1 = Read(stream);
90 | Check(header1.Magic == MagicDDS);
91 | Check(header1.Size == 124);
92 | Check((header1.Flags & 7) == 7); //caps, height, width
93 | Check(header1.PixelFormat.Size == 32);
94 | uint format = 0;
95 | uint pitch = 0;
96 | if ((header1.PixelFormat.Flags & 0x40) == 0x40) //DDPF_RGB
97 | {
98 | Check((header1.PixelFormat.Flags & 1) == 1); //Contains alpha
99 | Check(header1.PixelFormat.ABitMask == 0xFF000000);
100 | Check(header1.PixelFormat.RBitMask == 0x00FF0000);
101 | Check(header1.PixelFormat.GBitMask == 0x0000FF00);
102 | Check(header1.PixelFormat.BBitMask == 0x000000FF);
103 | format = 87; //DXGI_FORMAT_B8G8R8A8_UNORM
104 |
105 | //There must be at least one way to calculate pitch (providing RGBBitCount or PitchOrLinearSize)
106 | if ((header1.PixelFormat.Flags & 0x40) == 0x40) //DDPF_RGB
107 | {
108 | pitch = (header1.Width * header1.PixelFormat.RGBBitCount + 7) / 8;
109 | }
110 | else
111 | {
112 | Check((header1.Flags & 8) == 8); //pitch
113 | }
114 | }
115 | else
116 | {
117 | Check((header1.PixelFormat.Flags & 0x4) == 0x4); //DDPF_FOURCC
118 | switch (header1.PixelFormat.FourCC)
119 | {
120 | case MagicDXT1:
121 | format = 71; //DXGI_FORMAT_BC1_UNORM
122 | pitch = (header1.Width + 3) / 4 * 8;
123 | break;
124 | case MagicDXT3:
125 | format = 74; //DXGI_FORMAT_BC2_UNORM
126 | pitch = (header1.Width + 3) / 4 * 16;
127 | break;
128 | case MagicDXT5:
129 | format = 77; //DXGI_FORMAT_BC3_UNORM
130 | pitch = (header1.Width + 3) / 4 * 16;
131 | break;
132 | case MagicDX10:
133 | {
134 | var header2 = Read(stream);
135 | Check(header2.ResourceDimension == 3 /*DDS_DIMENSION_TEXTURE2D*/);
136 | Check(header2.ArraySize == 1);
137 | format = header2.DXGIFormat;
138 | }
139 | break;
140 | default:
141 | Check(false);
142 | break;
143 | }
144 | }
145 | if ((header1.Flags & 8) == 8)
146 | {
147 | pitch = header1.PitchOrLinearSize;
148 | }
149 | var data = new byte[stream.Length - stream.Position];
150 | Check(stream.Read(data, 0, data.Length) == data.Length);
151 | fixed (byte* pData = data)
152 | {
153 | return device.CreateTexture2D((int)header1.Width, (int)header1.Height, (int)format,
154 | new IntPtr(pData), (int)pitch, false);
155 | }
156 | }
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/LightDx/LightDx.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {45B0C93A-0AAF-41E3-BF58-61F42EF2C256}
8 | Library
9 | Properties
10 | LightDx
11 | LightDx
12 | v4.7
13 | 512
14 |
15 |
16 |
17 |
18 |
19 | true
20 | full
21 | false
22 | bin\Debug\
23 | DEBUG;TRACE
24 | prompt
25 | 4
26 | true
27 | true
28 | latest
29 |
30 |
31 | pdbonly
32 | true
33 | bin\Release\
34 | TRACE
35 | prompt
36 | 4
37 | true
38 | latest
39 |
40 |
41 | true
42 | bin\x64\Debug\
43 | DEBUG;TRACE
44 | true
45 | full
46 | x64
47 | prompt
48 | MinimumRecommendedRules.ruleset
49 | latest
50 |
51 |
52 | bin\x64\Release\
53 | TRACE
54 | true
55 | true
56 | pdbonly
57 | x64
58 | prompt
59 | MinimumRecommendedRules.ruleset
60 | latest
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
117 |
118 |
119 |
120 |
127 |
--------------------------------------------------------------------------------
/LightDX.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27428.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LightDx", "LightDx\LightDx.csproj", "{45B0C93A-0AAF-41E3-BF58-61F42EF2C256}"
7 | ProjectSection(ProjectDependencies) = postProject
8 | {5E830BD9-174D-49A2-8F79-4F193711D42A} = {5E830BD9-174D-49A2-8F79-4F193711D42A}
9 | EndProjectSection
10 | EndProject
11 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Triangle", "Examples\Triangle\Triangle.csproj", "{B35FE686-B955-4C7A-AA7F-BA1FF5185674}"
12 | EndProject
13 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{8A9515FE-6CCF-4B80-9A37-87C2C3583424}"
14 | EndProject
15 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TextureTriangle", "Examples\TextureTriangle\TextureTriangle.csproj", "{69D3CBDE-6740-4199-96EC-622240537C8A}"
16 | EndProject
17 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DrawString", "Examples\DrawString\DrawString.csproj", "{FE9BD09A-74E5-4ED8-BD61-1A9F128E5DA0}"
18 | EndProject
19 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DynamicTriangle", "Examples\DynamicTriangle\DynamicTriangle.csproj", "{D0E73992-784B-4F38-9198-4E08A7BAF8AE}"
20 | EndProject
21 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Weavers", "Weavers\Weavers.csproj", "{5E830BD9-174D-49A2-8F79-4F193711D42A}"
22 | EndProject
23 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cube", "Cube\Cube.csproj", "{E900F23B-CA00-4FB1-8FF5-7C50F828F763}"
24 | EndProject
25 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BufferResource", "BufferResource\BufferResource.csproj", "{87B6F1BD-BAB3-4CB0-B18F-218362D6A712}"
26 | EndProject
27 | Global
28 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
29 | Debug|Any CPU = Debug|Any CPU
30 | Debug|x64 = Debug|x64
31 | Release|Any CPU = Release|Any CPU
32 | Release|x64 = Release|x64
33 | EndGlobalSection
34 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
35 | {45B0C93A-0AAF-41E3-BF58-61F42EF2C256}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
36 | {45B0C93A-0AAF-41E3-BF58-61F42EF2C256}.Debug|Any CPU.Build.0 = Debug|Any CPU
37 | {45B0C93A-0AAF-41E3-BF58-61F42EF2C256}.Debug|x64.ActiveCfg = Debug|x64
38 | {45B0C93A-0AAF-41E3-BF58-61F42EF2C256}.Debug|x64.Build.0 = Debug|x64
39 | {45B0C93A-0AAF-41E3-BF58-61F42EF2C256}.Release|Any CPU.ActiveCfg = Release|Any CPU
40 | {45B0C93A-0AAF-41E3-BF58-61F42EF2C256}.Release|Any CPU.Build.0 = Release|Any CPU
41 | {45B0C93A-0AAF-41E3-BF58-61F42EF2C256}.Release|x64.ActiveCfg = Release|x64
42 | {45B0C93A-0AAF-41E3-BF58-61F42EF2C256}.Release|x64.Build.0 = Release|x64
43 | {B35FE686-B955-4C7A-AA7F-BA1FF5185674}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
44 | {B35FE686-B955-4C7A-AA7F-BA1FF5185674}.Debug|Any CPU.Build.0 = Debug|Any CPU
45 | {B35FE686-B955-4C7A-AA7F-BA1FF5185674}.Debug|x64.ActiveCfg = Debug|x64
46 | {B35FE686-B955-4C7A-AA7F-BA1FF5185674}.Debug|x64.Build.0 = Debug|x64
47 | {B35FE686-B955-4C7A-AA7F-BA1FF5185674}.Release|Any CPU.ActiveCfg = Release|Any CPU
48 | {B35FE686-B955-4C7A-AA7F-BA1FF5185674}.Release|Any CPU.Build.0 = Release|Any CPU
49 | {B35FE686-B955-4C7A-AA7F-BA1FF5185674}.Release|x64.ActiveCfg = Release|x64
50 | {B35FE686-B955-4C7A-AA7F-BA1FF5185674}.Release|x64.Build.0 = Release|x64
51 | {69D3CBDE-6740-4199-96EC-622240537C8A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
52 | {69D3CBDE-6740-4199-96EC-622240537C8A}.Debug|Any CPU.Build.0 = Debug|Any CPU
53 | {69D3CBDE-6740-4199-96EC-622240537C8A}.Debug|x64.ActiveCfg = Debug|x64
54 | {69D3CBDE-6740-4199-96EC-622240537C8A}.Debug|x64.Build.0 = Debug|x64
55 | {69D3CBDE-6740-4199-96EC-622240537C8A}.Release|Any CPU.ActiveCfg = Release|Any CPU
56 | {69D3CBDE-6740-4199-96EC-622240537C8A}.Release|Any CPU.Build.0 = Release|Any CPU
57 | {69D3CBDE-6740-4199-96EC-622240537C8A}.Release|x64.ActiveCfg = Release|x64
58 | {69D3CBDE-6740-4199-96EC-622240537C8A}.Release|x64.Build.0 = Release|x64
59 | {FE9BD09A-74E5-4ED8-BD61-1A9F128E5DA0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
60 | {FE9BD09A-74E5-4ED8-BD61-1A9F128E5DA0}.Debug|Any CPU.Build.0 = Debug|Any CPU
61 | {FE9BD09A-74E5-4ED8-BD61-1A9F128E5DA0}.Debug|x64.ActiveCfg = Debug|x64
62 | {FE9BD09A-74E5-4ED8-BD61-1A9F128E5DA0}.Debug|x64.Build.0 = Debug|x64
63 | {FE9BD09A-74E5-4ED8-BD61-1A9F128E5DA0}.Release|Any CPU.ActiveCfg = Release|Any CPU
64 | {FE9BD09A-74E5-4ED8-BD61-1A9F128E5DA0}.Release|Any CPU.Build.0 = Release|Any CPU
65 | {FE9BD09A-74E5-4ED8-BD61-1A9F128E5DA0}.Release|x64.ActiveCfg = Release|x64
66 | {FE9BD09A-74E5-4ED8-BD61-1A9F128E5DA0}.Release|x64.Build.0 = Release|x64
67 | {D0E73992-784B-4F38-9198-4E08A7BAF8AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
68 | {D0E73992-784B-4F38-9198-4E08A7BAF8AE}.Debug|Any CPU.Build.0 = Debug|Any CPU
69 | {D0E73992-784B-4F38-9198-4E08A7BAF8AE}.Debug|x64.ActiveCfg = Debug|x64
70 | {D0E73992-784B-4F38-9198-4E08A7BAF8AE}.Debug|x64.Build.0 = Debug|x64
71 | {D0E73992-784B-4F38-9198-4E08A7BAF8AE}.Release|Any CPU.ActiveCfg = Release|Any CPU
72 | {D0E73992-784B-4F38-9198-4E08A7BAF8AE}.Release|Any CPU.Build.0 = Release|Any CPU
73 | {D0E73992-784B-4F38-9198-4E08A7BAF8AE}.Release|x64.ActiveCfg = Release|x64
74 | {D0E73992-784B-4F38-9198-4E08A7BAF8AE}.Release|x64.Build.0 = Release|x64
75 | {5E830BD9-174D-49A2-8F79-4F193711D42A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
76 | {5E830BD9-174D-49A2-8F79-4F193711D42A}.Debug|Any CPU.Build.0 = Debug|Any CPU
77 | {5E830BD9-174D-49A2-8F79-4F193711D42A}.Debug|x64.ActiveCfg = Debug|Any CPU
78 | {5E830BD9-174D-49A2-8F79-4F193711D42A}.Debug|x64.Build.0 = Debug|Any CPU
79 | {5E830BD9-174D-49A2-8F79-4F193711D42A}.Release|Any CPU.ActiveCfg = Release|Any CPU
80 | {5E830BD9-174D-49A2-8F79-4F193711D42A}.Release|Any CPU.Build.0 = Release|Any CPU
81 | {5E830BD9-174D-49A2-8F79-4F193711D42A}.Release|x64.ActiveCfg = Release|Any CPU
82 | {5E830BD9-174D-49A2-8F79-4F193711D42A}.Release|x64.Build.0 = Release|Any CPU
83 | {E900F23B-CA00-4FB1-8FF5-7C50F828F763}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
84 | {E900F23B-CA00-4FB1-8FF5-7C50F828F763}.Debug|Any CPU.Build.0 = Debug|Any CPU
85 | {E900F23B-CA00-4FB1-8FF5-7C50F828F763}.Debug|x64.ActiveCfg = Debug|Any CPU
86 | {E900F23B-CA00-4FB1-8FF5-7C50F828F763}.Debug|x64.Build.0 = Debug|Any CPU
87 | {E900F23B-CA00-4FB1-8FF5-7C50F828F763}.Release|Any CPU.ActiveCfg = Release|Any CPU
88 | {E900F23B-CA00-4FB1-8FF5-7C50F828F763}.Release|Any CPU.Build.0 = Release|Any CPU
89 | {E900F23B-CA00-4FB1-8FF5-7C50F828F763}.Release|x64.ActiveCfg = Release|Any CPU
90 | {E900F23B-CA00-4FB1-8FF5-7C50F828F763}.Release|x64.Build.0 = Release|Any CPU
91 | {87B6F1BD-BAB3-4CB0-B18F-218362D6A712}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
92 | {87B6F1BD-BAB3-4CB0-B18F-218362D6A712}.Debug|Any CPU.Build.0 = Debug|Any CPU
93 | {87B6F1BD-BAB3-4CB0-B18F-218362D6A712}.Debug|x64.ActiveCfg = Debug|Any CPU
94 | {87B6F1BD-BAB3-4CB0-B18F-218362D6A712}.Debug|x64.Build.0 = Debug|Any CPU
95 | {87B6F1BD-BAB3-4CB0-B18F-218362D6A712}.Release|Any CPU.ActiveCfg = Release|Any CPU
96 | {87B6F1BD-BAB3-4CB0-B18F-218362D6A712}.Release|Any CPU.Build.0 = Release|Any CPU
97 | {87B6F1BD-BAB3-4CB0-B18F-218362D6A712}.Release|x64.ActiveCfg = Release|Any CPU
98 | {87B6F1BD-BAB3-4CB0-B18F-218362D6A712}.Release|x64.Build.0 = Release|Any CPU
99 | EndGlobalSection
100 | GlobalSection(SolutionProperties) = preSolution
101 | HideSolutionNode = FALSE
102 | EndGlobalSection
103 | GlobalSection(NestedProjects) = preSolution
104 | {B35FE686-B955-4C7A-AA7F-BA1FF5185674} = {8A9515FE-6CCF-4B80-9A37-87C2C3583424}
105 | {69D3CBDE-6740-4199-96EC-622240537C8A} = {8A9515FE-6CCF-4B80-9A37-87C2C3583424}
106 | {FE9BD09A-74E5-4ED8-BD61-1A9F128E5DA0} = {8A9515FE-6CCF-4B80-9A37-87C2C3583424}
107 | {D0E73992-784B-4F38-9198-4E08A7BAF8AE} = {8A9515FE-6CCF-4B80-9A37-87C2C3583424}
108 | {E900F23B-CA00-4FB1-8FF5-7C50F828F763} = {8A9515FE-6CCF-4B80-9A37-87C2C3583424}
109 | {87B6F1BD-BAB3-4CB0-B18F-218362D6A712} = {8A9515FE-6CCF-4B80-9A37-87C2C3583424}
110 | EndGlobalSection
111 | GlobalSection(ExtensibilityGlobals) = postSolution
112 | SolutionGuid = {7448F4E7-EE62-47E7-92EA-7833EE840AA1}
113 | EndGlobalSection
114 | EndGlobal
115 |
--------------------------------------------------------------------------------
/LightDx/VertexDataProcessor.cs:
--------------------------------------------------------------------------------
1 | using LightDx.InputAttributes;
2 | using LightDx.Natives;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Numerics;
7 | using System.Reflection;
8 | using System.Runtime.InteropServices;
9 | using System.Text;
10 | using System.Threading.Tasks;
11 |
12 | namespace LightDx
13 | {
14 | internal interface IBufferUpdate
15 | {
16 | void UpdateBuffer(VertexBuffer buffer, Array data, int start, int length);
17 | }
18 |
19 | internal class InputElementDescriptionFactory
20 | {
21 | public static int GetFormatFromType(Type t)
22 | {
23 | if (t == typeof(float))
24 | {
25 | return 41; //DXGI_FORMAT_R32_FLOAT
26 | }
27 | else if (t == typeof(Vector4))
28 | {
29 | return 2; //R32G32B32A32_Float
30 | }
31 | else if (t == typeof(Vector3))
32 | {
33 | return 6; //DXGI_FORMAT_R32G32B32_FLOAT
34 | }
35 | else if (t == typeof(Vector2))
36 | {
37 | return 16; //DXGI_FORMAT_R32G32_FLOAT
38 | }
39 | else if (t == typeof(uint))
40 | {
41 | return 28; //DXGI_FORMAT_R8G8B8A8_UNORM
42 | }
43 | return 0;
44 | }
45 | public static InputElementDescription[] Create(Type t, int slot)
46 | {
47 | List fieldList = new List();
48 | foreach (var field in t.GetFields())
49 | {
50 | var attr = field.GetCustomAttribute();
51 | if (attr == null) continue;
52 | int offset = Marshal.OffsetOf(t, field.Name).ToInt32();
53 | int format = attr.Format;
54 | if (format == 0)
55 | {
56 | format = GetFormatFromType(field.FieldType);
57 | if (format == 0)
58 | {
59 | throw new ArgumentException("Unknown input field type: " + field.FieldType.Name);
60 | }
61 | }
62 | fieldList.Add(new InputElementDescription
63 | {
64 | SemanticName = attr.SemanticName,
65 | SemanticIndex = attr.SemanticIndex,
66 | Format = format,
67 | AlignedByteOffset = offset,
68 | Slot = slot,
69 | });
70 | }
71 | fieldList.Sort((InputElementDescription a, InputElementDescription b) =>
72 | a.AlignedByteOffset.CompareTo(b.AlignedByteOffset));
73 | return fieldList.ToArray();
74 | }
75 | }
76 |
77 | public sealed class VertexDataProcessor : IDisposable
78 | where T : unmanaged
79 | {
80 | private class BufferUpdate : IBufferUpdate
81 | {
82 | private LightDevice _device;
83 |
84 | public BufferUpdate(LightDevice device)
85 | {
86 | _device = device;
87 | }
88 |
89 | public void UpdateBuffer(VertexBuffer buffer, Array data, int start, int length)
90 | {
91 | UpdateBufferInternal(buffer, (T[])data, start, length);
92 | }
93 |
94 | private unsafe void UpdateBufferInternal(VertexBuffer buffer, T[] data, int start, int length)
95 | {
96 | int realLength = length == -1 ? data.Length - start : length;
97 | if (buffer.IsDynamic)
98 | {
99 | SubresourceData ret;
100 | DeviceContext.Map(_device.ContextPtr, buffer.BufferPtr, 0,
101 | 4 /* WRITE_DISCARD */, 0, &ret).Check();
102 |
103 | fixed (T* pData = &data[start])
104 | {
105 | Buffer.MemoryCopy(pData, ret.pSysMem.ToPointer(), _Size * realLength, _Size * realLength);
106 | }
107 |
108 | DeviceContext.Unmap(_device.ContextPtr, buffer.BufferPtr, 0);
109 | }
110 | else
111 | {
112 | var box = stackalloc uint[6] { 0, 0, 0, (uint)(realLength * _Size), 1, 1 };
113 | fixed (T* pData = &data[start])
114 | {
115 | DeviceContext.UpdateSubresource(_device.ContextPtr, buffer.BufferPtr, 0, box, pData, 0, 0);
116 | }
117 | }
118 | }
119 | }
120 |
121 | private static int _Size = Marshal.SizeOf(typeof(T));
122 | private readonly LightDevice _device;
123 | private IntPtr _inputLayout;
124 | private BufferUpdate _bufferUpdate;
125 |
126 | private bool _disposed;
127 |
128 | internal VertexDataProcessor(LightDevice device, IntPtr layout)
129 | {
130 | _device = device;
131 | device.AddComponent(this);
132 |
133 | _inputLayout = layout;
134 | _bufferUpdate = new BufferUpdate(device);
135 | }
136 |
137 | internal VertexDataProcessor(LightDevice device)
138 | : this(device, IntPtr.Zero)
139 | {
140 | }
141 |
142 | ~VertexDataProcessor()
143 | {
144 | Dispose(false);
145 | }
146 |
147 | public void Dispose()
148 | {
149 | Dispose(true);
150 | }
151 |
152 | public unsafe VertexBuffer CreateImmutableBuffer(T[] data, int offset = 0, int length = -1)
153 | {
154 | int realLength = length == -1 ? data.Length - offset : length;
155 | BufferDescription bd = new BufferDescription()
156 | {
157 | ByteWidth = (uint)(_Size * realLength),
158 | Usage = 0, //default
159 | BindFlags = 1, //vertexbuffer
160 | CPUAccessFlags = 0, //none. or write (65536)
161 | MiscFlags = 0,
162 | StructureByteStride = (uint)_Size
163 | };
164 | fixed (T* pData = &data[offset])
165 | {
166 | DataBox box = new DataBox
167 | {
168 | DataPointer = pData,
169 | RowPitch = 0,
170 | SlicePitch = 0,
171 | };
172 | using (var vb = new ComScopeGuard())
173 | {
174 | Device.CreateBuffer(_device.DevicePtr, &bd, &box, out vb.Ptr).Check();
175 | return new VertexBuffer(_device, _bufferUpdate, vb.Move(), _inputLayout.AddRef(), _Size, realLength, false);
176 | }
177 | }
178 | }
179 |
180 | public unsafe VertexBuffer CreateDynamicBuffer(int nElement)
181 | {
182 | BufferDescription bd = new BufferDescription()
183 | {
184 | ByteWidth = (uint)(_Size * nElement),
185 | Usage = 2, //dynamic
186 | BindFlags = 1, //vertexbuffer
187 | CPUAccessFlags = 0x10000, //write
188 | MiscFlags = 0,
189 | StructureByteStride = (uint)_Size
190 | };
191 | using (var vb = new ComScopeGuard())
192 | {
193 | Device.CreateBuffer(_device.DevicePtr, &bd, null, out vb.Ptr).Check();
194 | return new VertexBuffer(_device, _bufferUpdate, vb.Move(), _inputLayout.AddRef(), _Size, nElement, true);
195 | }
196 | }
197 |
198 | internal static InputElementDescription[] CreateLayoutFromType(int slot)
199 | {
200 | return InputElementDescriptionFactory.Create(typeof(T), slot);
201 | }
202 |
203 | private void Dispose(bool disposing)
204 | {
205 | if (_disposed)
206 | {
207 | return;
208 | }
209 | NativeHelper.Dispose(ref _inputLayout);
210 |
211 | if (disposing)
212 | {
213 | _device.RemoveComponent(this);
214 | }
215 |
216 | _disposed = true;
217 | GC.SuppressFinalize(this);
218 | }
219 | }
220 | }
221 |
--------------------------------------------------------------------------------
/LightDx/Sprite.cs:
--------------------------------------------------------------------------------
1 | using LightDx.InputAttributes;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Numerics;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace LightDx
10 | {
11 | //TODO specify address and filtering options (at startup)
12 | //TODO support color
13 | public sealed class Sprite : IDisposable
14 | {
15 | private struct Vertex
16 | {
17 | [Position]
18 | public Vector4 Position;
19 | [TexCoord]
20 | public Vector4 TexCoord;
21 | }
22 |
23 | private struct VSConstant
24 | {
25 | public float Width;
26 | public float Height;
27 | }
28 |
29 | private readonly LightDevice _device;
30 | private readonly Pipeline _pipeline;
31 | private readonly VertexDataProcessor _vertexProcessor;
32 | private readonly VertexBuffer _buffer;
33 | private readonly ConstantBuffer _constant;
34 | private readonly Vertex[] _array;
35 | private bool _disposed;
36 |
37 | public Sprite(LightDevice device)
38 | {
39 | _device = device;
40 | device.AddComponent(this);
41 |
42 | _pipeline = device.CompilePipeline(InputTopology.Triangle,
43 | ShaderSource.FromString(PipelineCode, ShaderType.Vertex | ShaderType.Pixel));
44 | _pipeline.SetBlender(Blender.AlphaBlender);
45 |
46 | _vertexProcessor = _pipeline.CreateVertexDataProcessor();
47 | _array = new[] {
48 | new Vertex { TexCoord = new Vector4(0, 0, 0, 0), Position = new Vector4(0, 0, 0, 0) },
49 | new Vertex { TexCoord = new Vector4(1, 0, 0, 0), Position = new Vector4(1, 0, 0, 0) },
50 | new Vertex { TexCoord = new Vector4(0, 1, 0, 0), Position = new Vector4(0, 1, 0, 0) },
51 |
52 | new Vertex { TexCoord = new Vector4(0, 1, 0, 0), Position = new Vector4(0, 1, 0, 0) },
53 | new Vertex { TexCoord = new Vector4(1, 0, 0, 0), Position = new Vector4(1, 0, 0, 0) },
54 | new Vertex { TexCoord = new Vector4(1, 1, 0, 0), Position = new Vector4(1, 1, 0, 0) },
55 | };
56 | _buffer = _vertexProcessor.CreateDynamicBuffer(6);
57 |
58 | _constant = _pipeline.CreateConstantBuffer();
59 | _pipeline.SetConstant(ShaderType.Vertex, 0, _constant);
60 | }
61 |
62 | ~Sprite()
63 | {
64 | Dispose(false);
65 | }
66 |
67 | public void Dispose()
68 | {
69 | Dispose(true);
70 | }
71 |
72 | private void Dispose(bool disposing)
73 | {
74 | if (_disposed)
75 | {
76 | return;
77 | }
78 |
79 | if (disposing)
80 | {
81 | _pipeline.Dispose();
82 | _vertexProcessor.Dispose();
83 | _buffer.Dispose();
84 | _constant.Dispose();
85 |
86 | _device.RemoveComponent(this);
87 | }
88 |
89 | _disposed = true;
90 | GC.SuppressFinalize(this);
91 | }
92 |
93 | public void Apply()
94 | {
95 | _constant.Value.Width = _device.ScreenWidth;
96 | _constant.Value.Height = _device.ScreenHeight;
97 | _constant.Update();
98 |
99 | _pipeline.Apply();
100 | }
101 |
102 | private void CheckPipeline()
103 | {
104 | if (!_pipeline.IsActive)
105 | {
106 | throw new InvalidOperationException();
107 | }
108 | }
109 |
110 | public void DrawTexture(Texture2D tex, int x, int y, int w, int h)
111 | {
112 | CheckPipeline();
113 | DrawTextureInternal(tex, x, y, w, h, 0, 0, tex.Width, tex.Height, 0, 0, 0);
114 | }
115 |
116 | public void DrawTexture(Texture2D tex, float x, float y, float w, float h, int tx, int ty, int tw, int th)
117 | {
118 | CheckPipeline();
119 | DrawTextureInternal(tex, x, y, w, h, tx, ty, tw, th, 0, 0, 0);
120 | }
121 |
122 | public void DrawTexture(Texture2D tex, float x, float y, float w, float h, int tx, int ty, int tw, int th, float cx, float cy, float rotate)
123 | {
124 | CheckPipeline();
125 | DrawTextureInternal(tex, x, y, w, h, tx, ty, tw, th, cx, cy, rotate);
126 | }
127 |
128 | private void DrawTextureInternal(Texture2D tex, float x, float y, float w, float h, int tx, int ty, int tw, int th, float cx, float cy, float rotate)
129 | {
130 | var fx = tx / (float)tex.Width;
131 | var fy = ty / (float)tex.Height;
132 | var fr = (tx + w) / (float)tex.Width;
133 | var fb = (ty + h) / (float)tex.Height;
134 |
135 | var cl = -cx;
136 | var ct = -cy;
137 | var cr = w - cx;
138 | var cb = h - cy;
139 | var s = (float)Math.Sin(rotate);
140 | var c = (float)Math.Cos(rotate);
141 |
142 | UpdatePoint(ref _array[0], x, y, cl, ct, s, c, fx, fy);
143 | UpdatePoint(ref _array[1], x, y, cr, ct, s, c, fr, fy);
144 | UpdatePoint(ref _array[2], x, y, cl, cb, s, c, fx, fb);
145 | UpdatePoint(ref _array[3], x, y, cl, cb, s, c, fx, fb);
146 | UpdatePoint(ref _array[4], x, y, cr, ct, s, c, fr, fy);
147 | UpdatePoint(ref _array[5], x, y, cr, cb, s, c, fr, fb);
148 |
149 | _pipeline.SetResource(0, tex);
150 | _buffer.Update(_array);
151 | _buffer.DrawAll();
152 | }
153 |
154 | private void UpdatePoint(ref Vertex v, float x, float y, float dx, float dy, float s, float c, float tx, float ty)
155 | {
156 | v.Position.X = x + dx * c - dy * s;
157 | v.Position.Y = y + dy * c + dx * s;
158 | v.TexCoord.X = tx;
159 | v.TexCoord.Y = ty;
160 | }
161 |
162 | public void DrawString(TextureFontCache font, string str, float x, float y, float maxWidth)
163 | {
164 | CheckPipeline();
165 | font.CacheString(str);
166 | var drawX = x;
167 | var maxX = x + maxWidth;
168 | for (int i = 0; i < str.Length && drawX < maxX; ++i)
169 | {
170 | if (i < str.Length - 1 && Char.IsSurrogatePair(str[i], str[i + 1]))
171 | {
172 | drawX = DrawChar(font, str[i] | str[i + 1] << 16, drawX, y, maxX);
173 | i += 1;
174 | }
175 | else
176 | {
177 | drawX = DrawChar(font, str[i], drawX, y, maxX);
178 | }
179 | }
180 | }
181 |
182 | private float DrawChar(TextureFontCache font, int c, float x, float y, float maxX)
183 | {
184 | font.DrawChar(c, out var b, out var k, out var ax, out var h);
185 | x += k;
186 | if (x + b.Width > maxX)
187 | {
188 | return maxX;
189 | }
190 | if (b.Bitmap != null)
191 | {
192 | //Non-space character
193 | DrawTextureInternal(b.Bitmap, x, y, b.Width, b.Height, b.X, b.Y, b.Width, b.Height, 0, 0, 0);
194 | }
195 | return x + ax;
196 | }
197 |
198 | private static readonly string PipelineCode = @"
199 | struct VS_IN
200 | {
201 | float4 pos : POSITION;
202 | float4 tex : TEXCOORD;
203 | };
204 |
205 | struct PS_IN
206 | {
207 | float4 pos : SV_POSITION;
208 | float4 tex : TEXCOORD;
209 | };
210 |
211 | cbuffer VS_CONSTANT_BUFFER : register(b0)
212 | {
213 | float fWidth;
214 | float fHeight;
215 | };
216 |
217 | PS_IN VS(VS_IN input)
218 | {
219 | PS_IN output = (PS_IN)0;
220 |
221 | output.pos.x = (input.pos.x / fWidth * 2) - 1;
222 | output.pos.y = 1 - (input.pos.y / fHeight * 2);
223 | output.pos.w = 1;
224 | output.tex = input.tex;
225 |
226 | return output;
227 | }
228 |
229 | Texture2D faceTexture : register(t0);
230 | SamplerState textureSampler : register(s0);
231 |
232 | float4 PS(PS_IN input) : SV_Target
233 | {
234 | return faceTexture.Sample(textureSampler, input.tex.xy);
235 | }";
236 | }
237 | }
238 |
--------------------------------------------------------------------------------
/LightDx/RenderTargetObject.cs:
--------------------------------------------------------------------------------
1 | using LightDx.Natives;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Numerics;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace LightDx
10 | {
11 | internal enum RenderTargetObjectSizeMode
12 | {
13 | Equal,
14 | }
15 |
16 | internal enum RenderTargetObjectType
17 | {
18 | SwapchainTarget,
19 | TextureTarget,
20 | }
21 |
22 | public sealed class RenderTargetObject : IDisposable
23 | {
24 | private LightDevice _device;
25 | private bool _disposed;
26 |
27 | private RenderTargetObjectType _type;
28 | private bool _isDepthStencil;
29 | private IntPtr _TexturePtr;
30 | private IntPtr _viewPtrTarget;
31 | private IntPtr _viewPtrResource;
32 | private int _texWidth, _texHeight;
33 |
34 | internal RenderTargetObjectType TargetType => _type;
35 | internal IntPtr ViewPtr => _viewPtrTarget;
36 | internal bool IsDepthStencil => _isDepthStencil;
37 |
38 | internal LightDevice Device => _device;
39 | public Vector4 ClearColor { get; set; }
40 |
41 | //swapchain target: no arguments
42 |
43 | //texture target
44 | private int _formatTexture, _formatTarget, _formatResource;
45 | private Texture2D _textureObj;
46 |
47 | internal static RenderTargetObject CreateSwapchainTarget(LightDevice device)
48 | {
49 | var ret = new RenderTargetObject(device);
50 | ret._type = RenderTargetObjectType.SwapchainTarget;
51 | ret._isDepthStencil = false;
52 | ret.RebuildView();
53 | return ret;
54 | }
55 |
56 | internal static RenderTargetObject CreateDepthStencilTarget(LightDevice device,
57 | int formatTexture, int formatTarget, int formatResource)
58 | {
59 | var ret = new RenderTargetObject(device);
60 | ret._type = RenderTargetObjectType.TextureTarget;
61 | ret._isDepthStencil = true;
62 | ret._formatTexture = formatTexture;
63 | ret._formatTarget = formatTarget;
64 | ret._formatResource = formatResource;
65 | ret.RebuildView();
66 | return ret;
67 | }
68 |
69 | internal static RenderTargetObject CreateTextureTarget(LightDevice device, int format)
70 | {
71 | var ret = new RenderTargetObject(device);
72 | ret._type = RenderTargetObjectType.TextureTarget;
73 | ret._isDepthStencil = false;
74 | ret._formatTexture = format;
75 | ret._formatTarget = format;
76 | ret._formatResource = format;
77 | ret._textureObj = new Texture2D(device, IntPtr.Zero, IntPtr.Zero, 0, 0, false);
78 | ret.RebuildView();
79 | return ret;
80 | }
81 |
82 | private RenderTargetObject(LightDevice device)
83 | {
84 | _device = device;
85 | device.AddComponent(this);
86 | device.ReleaseRenderTargets += ReleaseView;
87 | device.RebuildRenderTargets += RebuildView;
88 | }
89 |
90 | ~RenderTargetObject()
91 | {
92 | Dispose(false);
93 | }
94 |
95 | public void Dispose()
96 | {
97 | Dispose(true);
98 | }
99 |
100 | private void Dispose(bool disposing)
101 | {
102 | if (_disposed)
103 | {
104 | return;
105 | }
106 | NativeHelper.Dispose(ref _TexturePtr);
107 | NativeHelper.Dispose(ref _viewPtrTarget);
108 | NativeHelper.Dispose(ref _viewPtrResource);
109 |
110 | if (disposing)
111 | {
112 | _device.ReleaseRenderTargets -= ReleaseView;
113 | _device.RebuildRenderTargets -= RebuildView;
114 |
115 | _device.RemoveComponent(this);
116 | }
117 |
118 | _disposed = true;
119 | GC.SuppressFinalize(this);
120 | }
121 |
122 | internal void ReleaseView()
123 | {
124 | if (_textureObj != null)
125 | {
126 | _textureObj.UpdatePointer(0, 0, IntPtr.Zero, IntPtr.Zero);
127 | }
128 | NativeHelper.Dispose(ref _TexturePtr);
129 | NativeHelper.Dispose(ref _viewPtrTarget);
130 | NativeHelper.Dispose(ref _viewPtrResource);
131 | }
132 |
133 | internal void RebuildView()
134 | {
135 | if (_type == RenderTargetObjectType.SwapchainTarget)
136 | {
137 | _viewPtrTarget = _device.DefaultRenderView.AddRef();
138 | }
139 | else
140 | {
141 | _texWidth = _device.ScreenWidth;
142 | _texHeight = _device.ScreenHeight;
143 |
144 | Texture2DDescription desc = new Texture2DDescription
145 | {
146 | Width = (uint)_texWidth,
147 | Height = (uint)_texHeight,
148 | MipLevels = 1,
149 | ArraySize = 1,
150 | Format = (uint)_formatTexture,
151 | SampleCount = 1,
152 | SampleQuality = 0,
153 | Usage = 0, //Default
154 | CPUAccessFlags = 0,
155 | MiscFlags = 0,
156 | };
157 | if (_isDepthStencil)
158 | {
159 | desc.BindFlags = 64 + 8; //DepthStencil+ShaderResource
160 | RebuildViewStencilInternal(ref desc);
161 | }
162 | else
163 | {
164 | desc.BindFlags = 32 + 8; //RenderTarget+ShaderResource
165 | RebuildViewTextureInternal(ref desc);
166 | }
167 | }
168 | }
169 |
170 | //Note: The following 2 methods are separated from RebuildView to avoid fat method to be modified by Mono.Cecil,
171 | //which when doing so will corrupt the binary for unknown reason.
172 |
173 | private unsafe void RebuildViewStencilInternal(ref Texture2DDescription desc)
174 | {
175 | using (var depthTex = new ComScopeGuard())
176 | {
177 | int* depthStencilDesc = stackalloc int[6]
178 | {
179 | _formatTarget,
180 | 3, //D3D11_DSV_DIMENSION_TEXTURE2D
181 | 0, //Flags = 0
182 | 0, //MipSlice = 0
183 | 0,
184 | 0,
185 | };
186 | Natives.Device.CreateTexture2D(_device.DevicePtr, ref desc, IntPtr.Zero, out depthTex.Ptr).Check();
187 | Natives.Device.CreateDepthStencilView(_device.DevicePtr, depthTex.Ptr, depthStencilDesc, out _viewPtrTarget).Check();
188 | _TexturePtr = depthTex.Move();
189 | }
190 | RebuildResourceView();
191 | }
192 |
193 | private unsafe void RebuildViewTextureInternal(ref Texture2DDescription desc)
194 | {
195 | using (ComScopeGuard tex = new ComScopeGuard(), targetView = new ComScopeGuard(), resView = new ComScopeGuard())
196 | {
197 | int* renderTargetDesc = stackalloc int[5]
198 | {
199 | _formatTarget,
200 | 4, //D3D11_RTV_DIMENSION_TEXTURE2D
201 | 0, //MipSlice = 0
202 | 0, //Not used in tex2d
203 | 0, //Not used in tex2d
204 | };
205 | Natives.Device.CreateTexture2D(_device.DevicePtr, ref desc, IntPtr.Zero, out tex.Ptr).Check();
206 | Natives.Device.CreateRenderTargetView(_device.DevicePtr, tex.Ptr, renderTargetDesc, out targetView.Ptr).Check();
207 | _TexturePtr = tex.Move();
208 | _viewPtrTarget = targetView.Move();
209 | }
210 | RebuildResourceView();
211 | }
212 |
213 | private unsafe void RebuildResourceView()
214 | {
215 | if (_textureObj == null)
216 | {
217 | return;
218 | }
219 | int* resourceDesc = stackalloc int[5]
220 | {
221 | _formatResource,
222 | 4, //D3D11_SRV_DIMENSION_TEXTURE2D
223 | 0, //MostDetailedMip = 0
224 | 1, //MipLevels = 1
225 | 0, //Not used in tex2d
226 | };
227 | Natives.Device.CreateShaderResourceView(_device.DevicePtr, _TexturePtr, resourceDesc, out _viewPtrResource).Check();
228 | _textureObj.UpdatePointer(_texWidth, _texHeight, _TexturePtr, _viewPtrResource);
229 | }
230 |
231 | public void Clear()
232 | {
233 | if (_isDepthStencil)
234 | {
235 | DeviceContext.ClearDepthStencilView(_device.ContextPtr, _viewPtrTarget, 1, 1.0f, 0);
236 | }
237 | else
238 | {
239 | Vector4 color = ClearColor;
240 | DeviceContext.ClearRenderTargetView(_device.ContextPtr, _viewPtrTarget, ref color);
241 | }
242 | }
243 |
244 | public Texture2D GetTexture2D()
245 | {
246 | if (_type != RenderTargetObjectType.TextureTarget)
247 | {
248 | throw new InvalidOperationException();
249 | }
250 | if (_textureObj == null)
251 | {
252 | _textureObj = new Texture2D(_device, IntPtr.Zero, IntPtr.Zero, 0, 0, false);
253 | RebuildResourceView();
254 | }
255 | return _textureObj;
256 | }
257 | }
258 | }
259 |
--------------------------------------------------------------------------------
/Weavers/CalliWeaver.cs:
--------------------------------------------------------------------------------
1 | using Fody;
2 | using Mono.Cecil;
3 | using Mono.Cecil.Cil;
4 | using Mono.Cecil.Rocks;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 |
11 | namespace Weavers
12 | {
13 | public class CalliWeaver : BaseModuleWeaver
14 | {
15 | public override void Execute()
16 | {
17 | Dictionary generatedList = new Dictionary();
18 | HashSet modifiedDelegateTypes = new HashSet();
19 | List> removedTypes =
20 | new List>();
21 | HashSet removedFields = new HashSet();
22 | int instructionReplaced = 0;
23 |
24 | //Import all required types
25 |
26 | var objectType = ModuleDefinition.ImportReference(typeof(object));
27 | var intPtrType = ModuleDefinition.ImportReference(typeof(IntPtr));
28 |
29 | var ptrIntPtr = ModuleDefinition.ImportReference(intPtrType.MakePointerType());
30 | var pinnedPtrIntPtr = ModuleDefinition.ImportReference(new PinnedType(ptrIntPtr));
31 |
32 | //Wrapper class
33 |
34 | var newType = new TypeDefinition("LightDx", "FodyGenerated",
35 | TypeAttributes.Abstract | TypeAttributes.Sealed,
36 | objectType);
37 |
38 | //Find all types
39 |
40 | Dictionary allTypeNames = new Dictionary();
41 | foreach (var t in ModuleDefinition.GetAllTypes())
42 | {
43 | allTypeNames.Add(t.FullName, t);
44 | }
45 |
46 | //Generate new methods for each candidate fields
47 |
48 | foreach (var f in GetAllFields())
49 | {
50 | if (!allTypeNames.TryGetValue(f.FieldType.FullName, out var delegateType))
51 | {
52 | //Type not in this module, not what we're looking for
53 | continue;
54 | }
55 |
56 | //Confirm it's in top-level class
57 | if (f.DeclaringType.DeclaringType != null)
58 | {
59 | throw new Exception();
60 | }
61 |
62 | var delegateInvoke = delegateType.Methods.Where(m => m.Name == "Invoke").Single();
63 | var retType = delegateInvoke.ReturnType;
64 |
65 | //Make a new method
66 |
67 | var methodName = f.DeclaringType.Name + "_" + f.Name;
68 | var method = new MethodDefinition(methodName,
69 | MethodAttributes.Public | MethodAttributes.Static,
70 | retType);
71 |
72 | foreach (var p in delegateInvoke.Parameters)
73 | {
74 | method.Parameters.Add(new ParameterDefinition(p.Name, p.Attributes, p.ParameterType));
75 | }
76 |
77 | //Generate the body
78 |
79 | var id = GetFunctionIdInVTab(f);
80 |
81 | AOTCalliGenerator.Generate(ModuleDefinition, delegateInvoke, method, id, pinnedPtrIntPtr, ptrIntPtr);
82 |
83 | newType.Methods.Add(method);
84 |
85 | //Make some records to be used later
86 |
87 | generatedList.Add(methodName, method);
88 | modifiedDelegateTypes.Add(delegateType.FullName);
89 |
90 | removedFields.Add(f);
91 | removedTypes.Add(new Tuple(delegateType.DeclaringType, delegateType));
92 | removedTypes.Add(new Tuple(null, f.DeclaringType));
93 | }
94 |
95 | ModuleDefinition.Types.Add(newType);
96 |
97 | //Look through all instructions and replace the call from delegate to generated method
98 |
99 | Stack methodStack = new Stack();
100 | Dictionary jumpMapping = new Dictionary();
101 | foreach (var modify in ModuleDefinition.GetAllTypes().SelectMany(t => t.Methods))
102 | {
103 | jumpMapping.Clear();
104 | if (!modify.HasBody) continue;
105 | var instList = modify.Body.Instructions;
106 |
107 | //Change ldsfld + callvirt to nop + call
108 | for (int i = 0; i < instList.Count; ++i)
109 | {
110 | if (instList[i].OpCode == OpCodes.Ldsfld)
111 | {
112 | var field = (FieldReference)instList[i].Operand;
113 | //Save information to the stack
114 | if (generatedList.TryGetValue(field.DeclaringType.Name + "_" + field.Name, out var generated))
115 | {
116 | var newInst = Instruction.Create(OpCodes.Nop);
117 | jumpMapping.Add(instList[i], newInst);
118 |
119 | instList.RemoveAt(i);
120 | instList.Insert(i, newInst);
121 |
122 | methodStack.Push(generated);
123 | }
124 | }
125 | else if (instList[i].OpCode == OpCodes.Callvirt)
126 | {
127 | var method = (MethodReference)instList[i].Operand;
128 | var type = method.DeclaringType;
129 | if (modifiedDelegateTypes.Contains(type.FullName))
130 | {
131 | //TODO maybe we should confirm the signature is the same
132 | var generated = methodStack.Pop();
133 | var newInst = Instruction.Create(OpCodes.Call, generated);
134 | jumpMapping.Add(instList[i], newInst);
135 |
136 | instList.RemoveAt(i);
137 | instList.Insert(i, newInst);
138 |
139 | instructionReplaced += 1;
140 | }
141 | }
142 | }
143 |
144 | //Update jump dest
145 | for (int i = 0; i < instList.Count; ++i)
146 | {
147 | if (instList[i].Operand is Instruction inst && jumpMapping.TryGetValue(inst, out var newInst))
148 | {
149 | instList[i].Operand = newInst;
150 | }
151 | }
152 |
153 | //Confirm we are changing pairs
154 | if (methodStack.Count != 0)
155 | {
156 | throw new Exception("Error in processing method " + modify.FullName);
157 | }
158 | }
159 |
160 | //Remove fields and types
161 |
162 | foreach (var removed in removedFields)
163 | {
164 | removed.DeclaringType.Fields.Remove(removed);
165 | }
166 |
167 | foreach (var removed in removedTypes.Distinct())
168 | {
169 | if (removed.Item1 != null)
170 | {
171 | removed.Item1.NestedTypes.Remove(removed.Item2);
172 | }
173 | else
174 | {
175 | ModuleDefinition.Types.Remove(removed.Item2);
176 | }
177 | }
178 |
179 | ModuleDefinition.Types.Remove(allTypeNames["LightDx.CalliGenerator"]);
180 |
181 | LogMessage($"LightDx calli weaver finished, replacing {generatedList.Count} methods " +
182 | $"and {instructionReplaced} instructions.", MessageImportance.High);
183 | }
184 |
185 | private int GetFunctionIdInVTab(FieldDefinition field)
186 | {
187 | var t = field.DeclaringType.Resolve();
188 | var m = t.Methods.Where(mm => mm.Name == ".cctor").Single();
189 | var instList = m.Body.Instructions;
190 | int lastIndex = 0;
191 | int lastInst = 0;
192 | foreach (var i in instList)
193 | {
194 | if (GetLdcI4(i, out var index))
195 | {
196 | if (lastInst != 0) throw new Exception("Invalid instruction for " + field.FullName);
197 | lastInst = 1;
198 | lastIndex = index;
199 | }
200 | else if (i.OpCode == OpCodes.Call)
201 | {
202 | if (lastInst != 1) throw new Exception("Invalid instruction for " + field.FullName);
203 | lastInst = 2;
204 | }
205 | else if (i.OpCode == OpCodes.Stsfld)
206 | {
207 | if (lastInst != 2) throw new Exception("Invalid instruction for " + field.FullName);
208 | lastInst = 0;
209 | var stfield = (FieldReference)i.Operand;
210 | if (stfield.Resolve().FullName == field.FullName)
211 | {
212 | return lastIndex;
213 | }
214 | }
215 | else if (i.OpCode == OpCodes.Ret)
216 | {
217 | if (lastInst != 0) throw new Exception("Invalid instruction for " + field.FullName);
218 | lastInst = -1;
219 | break;
220 | }
221 | }
222 | throw new Exception("Index not found");
223 | }
224 |
225 | private static bool GetLdcI4(Instruction i, out int val)
226 | {
227 | if (i.OpCode == OpCodes.Ldc_I4_S)
228 | {
229 | val = (sbyte)i.Operand;
230 | return true;
231 | }
232 | else if (i.OpCode == OpCodes.Ldc_I4_0)
233 | {
234 | val = 0;
235 | return true;
236 | }
237 | else if (i.OpCode == OpCodes.Ldc_I4_1)
238 | {
239 | val = 1;
240 | return true;
241 | }
242 | else if (i.OpCode == OpCodes.Ldc_I4_2)
243 | {
244 | val = 2;
245 | return true;
246 | }
247 | else if (i.OpCode == OpCodes.Ldc_I4_3)
248 | {
249 | val = 3;
250 | return true;
251 | }
252 | else if (i.OpCode == OpCodes.Ldc_I4_4)
253 | {
254 | val = 4;
255 | return true;
256 | }
257 | else if (i.OpCode == OpCodes.Ldc_I4_5)
258 | {
259 | val = 5;
260 | return true;
261 | }
262 | else if (i.OpCode == OpCodes.Ldc_I4_6)
263 | {
264 | val = 6;
265 | return true;
266 | }
267 | else if (i.OpCode == OpCodes.Ldc_I4_7)
268 | {
269 | val = 7;
270 | return true;
271 | }
272 | else if (i.OpCode == OpCodes.Ldc_I4_8)
273 | {
274 | val = 8;
275 | return true;
276 | }
277 | val = 0;
278 | return false;
279 | }
280 |
281 | private IEnumerable GetAllFields()
282 | {
283 | foreach (var type in ModuleDefinition.Types) //Using Types because all such types are top-level
284 | {
285 | foreach (var field in type.Fields.ToArray())
286 | {
287 | var fieldType = field.FieldType.Resolve();
288 | //Type and field must be declared in the same type
289 | if (fieldType?.DeclaringType?.FullName != type.FullName)
290 | {
291 | continue;
292 | }
293 | //Must be a delegate
294 | if (fieldType.BaseType.FullName == "System.MulticastDelegate")
295 | {
296 | yield return field;
297 | }
298 | }
299 | }
300 | }
301 |
302 | public override IEnumerable GetAssembliesForScanning()
303 | {
304 | yield return "mscorlib";
305 | yield return "System";
306 | }
307 | }
308 | }
309 |
--------------------------------------------------------------------------------
/LightDx/AbstractFontCache.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.Drawing.Imaging;
5 | using System.Drawing.Text;
6 | using System.IO;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 |
11 | namespace LightDx
12 | {
13 | public abstract class AbstractFontCache : IDisposable
14 | where T : class, IDisposable
15 | {
16 | public struct CachedRegion
17 | {
18 | public T Bitmap;
19 | public int X;
20 | public int Y;
21 | public int Width;
22 | public int Height;
23 | }
24 |
25 | private struct CharacterInfo
26 | {
27 | public int BufferId;
28 | public int X;
29 | public int Y;
30 | public int Width;
31 | public int Height;
32 | }
33 |
34 | public AbstractFontCache(LightDevice device, Font font, PixelFormat format, Color foreground, Color background)
35 | {
36 | _device = device;
37 | device.AddComponent(this);
38 |
39 | Font = font;
40 | PixelFormat = format;
41 | BackgroundColor = background;
42 | ForegroundColor = foreground;
43 | _brush = new SolidBrush(foreground);
44 | var height = (int)Math.Ceiling(font.GetHeight());
45 | int bitmapSize;
46 | if (height < 85)
47 | {
48 | bitmapSize = 256;
49 | }
50 | else
51 | {
52 | bitmapSize = Round2Power(height * 3);
53 | }
54 | BufferWidth = bitmapSize;
55 | BufferHeight = bitmapSize;
56 | _gdiBitmap = new Bitmap(BufferWidth, BufferHeight, format);
57 | _gdiBitmapGraphics = Graphics.FromImage(_gdiBitmap);
58 | _gdiBitmapGraphics.TextRenderingHint = TextRenderingHint.AntiAlias;
59 |
60 | _formatSingle = new StringFormat();
61 | _formatSingle.SetMeasurableCharacterRanges(new[] { new CharacterRange(0, 1) });
62 | _formatDouble = new StringFormat();
63 | _formatDouble.SetMeasurableCharacterRanges(new[] { new CharacterRange(0, 2) });
64 | _empty = new CachedRegion
65 | {
66 | Bitmap = null,
67 | X = 0,
68 | Y = 0,
69 | Width = 0,
70 | Height = 0,
71 | };
72 | }
73 |
74 | private static int Round2Power(int x)
75 | {
76 | --x;
77 | x |= x >> 1;
78 | x |= x >> 2;
79 | x |= x >> 4;
80 | x |= x >> 8;
81 | x |= x >> 16;
82 | return x + 1;
83 | }
84 |
85 | ~AbstractFontCache()
86 | {
87 | Dispose(false);
88 | }
89 |
90 | private bool _disposed;
91 | protected LightDevice _device;
92 |
93 | public Font Font { get; private set; }
94 | public PixelFormat PixelFormat { get; private set; }
95 | public Color ForegroundColor { get; private set; }
96 | public Color BackgroundColor { get; private set; }
97 | public int BufferWidth { get; private set; }
98 | public int BufferHeight { get; private set; }
99 | public TextRenderingHint RenderQuality
100 | {
101 | get => _gdiBitmapGraphics.TextRenderingHint;
102 | set => _gdiBitmapGraphics.TextRenderingHint = value;
103 | }
104 |
105 | private readonly Brush _brush;
106 | private readonly char[] _stringBuffer = new char[2];
107 | private readonly StringFormat _formatSingle, _formatDouble;
108 | private readonly Bitmap _gdiBitmap;
109 | private readonly Graphics _gdiBitmapGraphics;
110 | private readonly List _bufferList = new List();
111 | private readonly Dictionary _characters = new Dictionary();
112 | private readonly Dictionary _kerning = new Dictionary();
113 | private readonly CachedRegion _empty;
114 |
115 | private T _currentBuffer;
116 | private int _currentBufferX, _currentBufferY, _currentBufferHeight;
117 |
118 | private int _drawLastChar;
119 |
120 | public void Dispose()
121 | {
122 | Dispose(true);
123 | }
124 |
125 | protected virtual void Dispose(bool disposing)
126 | {
127 | if (_disposed)
128 | {
129 | return;
130 | }
131 |
132 | if (disposing)
133 | {
134 | _gdiBitmapGraphics.Dispose();
135 | _gdiBitmap.Dispose();
136 | _brush.Dispose();
137 | _formatSingle.Dispose();
138 | _formatDouble.Dispose();
139 | foreach (var b in _bufferList)
140 | {
141 | DisposeBitmap(b);
142 | }
143 | _bufferList.Clear();
144 |
145 | _device.RemoveComponent(this);
146 | }
147 |
148 | _disposed = true;
149 | GC.SuppressFinalize(this);
150 | }
151 |
152 | public void CacheChar(int c)
153 | {
154 | if (!_characters.ContainsKey(c))
155 | {
156 | AddCharacter(c);
157 | }
158 | }
159 |
160 | public void CacheString(string str)
161 | {
162 | for (int i = 0; i < str.Length; ++i)
163 | {
164 | if (i < str.Length - 1 && Char.IsSurrogatePair(str[i], str[i + 1]))
165 | {
166 | CacheChar(str[i] | str[i + 1] << 16);
167 | i += 1;
168 | }
169 | else
170 | {
171 | CacheChar(str[i]);
172 | }
173 | }
174 | }
175 |
176 | public void DrawChar(int c, out CachedRegion bitmap,
177 | out int kernX, out int advanceX, out int height)
178 | {
179 | if (!_characters.TryGetValue(c, out var info))
180 | {
181 | AddCharacter(c);
182 | info = _characters[c];
183 | }
184 |
185 | if (info.BufferId < 0)
186 | {
187 | bitmap = _empty;
188 | kernX = GetKerning(c);
189 | advanceX = info.Width;
190 | height = 0;
191 | return;
192 | }
193 |
194 | CachedRegion ret = new CachedRegion()
195 | {
196 | Bitmap = _bufferList[info.BufferId],
197 | X = info.X,
198 | Y = info.Y,
199 | Width = info.Width,
200 | Height = info.Height
201 | };
202 | FlushCache(ret.Bitmap);
203 |
204 | bitmap = ret;
205 | kernX = GetKerning(c);
206 | advanceX = ret.Width;
207 | height = ret.Height;
208 | }
209 |
210 | public void TryDrawChar(int c, out CachedRegion bitmap,
211 | out int kernX, out int advanceX, out int height)
212 | {
213 | try
214 | {
215 | DrawChar(c, out bitmap, out kernX, out advanceX, out height);
216 | }
217 | catch
218 | {
219 | bitmap = _empty;
220 | kernX = 0;
221 | advanceX = 0;
222 | height = 0;
223 | }
224 | }
225 |
226 | private int GetKerning(int c)
227 | {
228 | //TODO support kerning
229 | _drawLastChar = c;
230 | return 0;
231 | }
232 |
233 | public void ResetDraw()
234 | {
235 | _drawLastChar = 0;
236 | }
237 |
238 | private void AddCharacter(int c)
239 | {
240 | if (_currentBuffer == null)
241 | {
242 | NewBuffer();
243 | }
244 |
245 | //measure
246 | _stringBuffer[0] = (char)c;
247 | _stringBuffer[1] = (char)(c >> 16);
248 | if (_stringBuffer[1] != 0 &&
249 | !Char.IsSurrogatePair(_stringBuffer[0], _stringBuffer[1]))
250 | {
251 | throw new ArgumentException("Invalid char");
252 | }
253 | var str = new string(_stringBuffer, 0, _stringBuffer[1] != 0 ? 2 : 1);
254 | RectangleF rect = new RectangleF(0, 0, 1E10F, 1E10F);
255 | var region = _gdiBitmapGraphics.MeasureCharacterRanges(str, Font, rect,
256 | _stringBuffer[1] != 0 ? _formatDouble : _formatSingle)[0];
257 | var size = region.GetBounds(_gdiBitmapGraphics);
258 | var x = (int)Math.Ceiling(size.X);
259 | var y = (int)Math.Ceiling(size.Y);
260 | var w = (int)Math.Ceiling(size.Width);
261 | var h = (int)Math.Ceiling(size.Height);
262 |
263 | //draw
264 | _gdiBitmapGraphics.Clear(BackgroundColor);
265 | _gdiBitmapGraphics.DrawString(str, Font, _brush, 0, 0);
266 |
267 | if (w <= 0 || h <= 0)
268 | {
269 | //empty char
270 | _characters.Add(c, new CharacterInfo
271 | {
272 | BufferId = -1,
273 | Width = MeasureWhitespace(c),
274 | Height = 0,
275 | });
276 | return;
277 | }
278 |
279 | //lock
280 | _gdiBitmapGraphics.Flush();
281 | var l = _gdiBitmap.LockBits(new Rectangle(x, y, w, h),
282 | ImageLockMode.ReadOnly, PixelFormat);
283 |
284 | try
285 | {
286 | if (_currentBufferX + w <= BufferWidth &&
287 | _currentBufferY + h <= BufferHeight)
288 | {
289 | //current line
290 | UpdateCache(_currentBuffer, _currentBufferX, _currentBufferY,
291 | w, h, l);
292 | AddCharInfo(c, w, h);
293 | }
294 | else if (w <= BufferWidth &&
295 | _currentBufferY + _currentBufferHeight + h <= BufferHeight)
296 | {
297 | //new line
298 | _currentBufferX = 0;
299 | _currentBufferY += _currentBufferHeight;
300 | _currentBufferHeight = 0;
301 | UpdateCache(_currentBuffer, _currentBufferX, _currentBufferY,
302 | w, h, l);
303 | AddCharInfo(c, w, h);
304 | }
305 | else if (w <= BufferWidth && h <= BufferHeight)
306 | {
307 | //new buffer
308 | NewBuffer();
309 | UpdateCache(_currentBuffer, _currentBufferX, _currentBufferY,
310 | w, h, l);
311 | AddCharInfo(c, w, h);
312 | }
313 | else
314 | {
315 | throw new ArgumentException("Size too large");
316 | }
317 | }
318 | finally
319 | {
320 | _gdiBitmap.UnlockBits(l);
321 | }
322 | }
323 |
324 | private int MeasureWhitespace(int c)
325 | {
326 | var sb = new StringBuilder();
327 | sb.Append('O');
328 | sb.Append((char)c);
329 | var d = false;
330 | if ((c >> 16) != 0)
331 | {
332 | d = true;
333 | sb.Append((char)(c >> 16));
334 | }
335 | sb.Append('O');
336 | var fmt = new StringFormat();
337 | fmt.SetMeasurableCharacterRanges(new[]
338 | {
339 | new CharacterRange(0, 1),
340 | new CharacterRange(d ? 3 : 2, 1),
341 | });
342 | var m = _gdiBitmapGraphics.MeasureCharacterRanges(sb.ToString(), Font,
343 | new RectangleF(0, 0, 1E10F, 1E10F), fmt);
344 | var m0 = m[0].GetBounds(_gdiBitmapGraphics);
345 | var m1 = m[1].GetBounds(_gdiBitmapGraphics);
346 | return (int)(m1.X - m0.X - m0.Width);
347 | }
348 |
349 | private void AddCharInfo(int c, int w, int h)
350 | {
351 | _characters.Add(c, new CharacterInfo
352 | {
353 | BufferId = _bufferList.Count - 1,
354 | X = _currentBufferX,
355 | Y = _currentBufferY,
356 | Width = w,
357 | Height = h,
358 | });
359 | _currentBufferX += w;
360 | _currentBufferHeight = Math.Max(_currentBufferHeight, h);
361 | }
362 |
363 | private void NewBuffer()
364 | {
365 | var b = CreateBitmap(BufferWidth, BufferHeight);
366 | _bufferList.Add(b);
367 | _currentBufferX = 0;
368 | _currentBufferY = 0;
369 | _currentBufferHeight = 0;
370 | _currentBuffer = b;
371 | }
372 |
373 | protected abstract T CreateBitmap(int w, int h);
374 | protected abstract void UpdateCache(T bitmap, int x, int y, int w, int h, BitmapData data);
375 | protected abstract void DisposeBitmap(T bitmap);
376 | protected abstract void FlushCache(T bitmap);
377 | }
378 | }
379 |
--------------------------------------------------------------------------------