mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 13:01:52 +00:00
Compare commits
219
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4874cfe511 | ||
|
|
63b9270710 | ||
|
|
2bac6a8d05 | ||
|
|
e51fc77c3f | ||
|
|
8c53f21690 | ||
|
|
ad1b37dc64 | ||
|
|
8e46945362 | ||
|
|
6a250d4927 | ||
|
|
9c93ccee47 | ||
|
|
f1ce63ee3b | ||
|
|
e685b4fbba | ||
|
|
9105c12e33 | ||
|
|
863c264001 | ||
|
|
bec202e23a | ||
|
|
bca72cf0d4 | ||
|
|
af37154071 | ||
|
|
c7fde476e8 | ||
|
|
604e34a12a | ||
|
|
b94c84d304 | ||
|
|
d47bc37886 | ||
|
|
c13b0a26d1 | ||
|
|
e82f70ba02 | ||
|
|
cbee9f59d8 | ||
|
|
afe36b19df | ||
|
|
9197a209d6 | ||
|
|
ba5ccd7107 | ||
|
|
c80ca4d9a1 | ||
|
|
92fd8bb572 | ||
|
|
b341c70a26 | ||
|
|
8c8f0d9fc7 | ||
|
|
8638b7ac3b | ||
|
|
be7c3d1d8b | ||
|
|
699522ff67 | ||
|
|
6f999da1b8 | ||
|
|
373980d5ad | ||
|
|
0db85de067 | ||
|
|
fae2bdf084 | ||
|
|
0f0afc2a90 | ||
|
|
66dad82dc6 | ||
|
|
0e684af17d | ||
|
|
82898f1d5c | ||
|
|
a2db0774f8 | ||
|
|
5b1f694bc9 | ||
|
|
69be98bb38 | ||
|
|
7eb4001a1b | ||
|
|
bca4552341 | ||
|
|
d96ec6f21b | ||
|
|
44fe2c3281 | ||
|
|
6a55108a37 | ||
|
|
a7b2515cf4 | ||
|
|
ee9dfd4593 | ||
|
|
3c1897b926 | ||
|
|
8a84843f54 | ||
|
|
06469f3350 | ||
|
|
78faf4cb81 | ||
|
|
e292029015 | ||
|
|
5373d92297 | ||
|
|
deedb62a03 | ||
|
|
6199496987 | ||
|
|
826ac68873 | ||
|
|
b2ce560bfc | ||
|
|
664ba552ea | ||
|
|
b555cc37d1 | ||
|
|
b3ab30e72a | ||
|
|
1cc37ee168 | ||
|
|
f4d64b15fa | ||
|
|
e55b73db0f | ||
|
|
f28984bec5 | ||
|
|
0fd6ac1dee | ||
|
|
419509ab7f | ||
|
|
2bc87b437a | ||
|
|
b3f9376dc8 | ||
|
|
ffafa380ea | ||
|
|
90e654b750 | ||
|
|
adaf62de62 | ||
|
|
dcb8424c2d | ||
|
|
84df8c111b | ||
|
|
cd82a99450 | ||
|
|
9216462a51 | ||
|
|
3eb7068bca | ||
|
|
54870330b6 | ||
|
|
ac74aeb116 | ||
|
|
b5bfcf5741 | ||
|
|
0cbbf94fe6 | ||
|
|
84daee95e4 | ||
|
|
2cd9ab3e69 | ||
|
|
5a82b89622 | ||
|
|
b020855ec5 | ||
|
|
4dc6c916ae | ||
|
|
9a9d75afbc | ||
|
|
fab0f99951 | ||
|
|
122f7e9904 | ||
|
|
eb2bbf4b82 | ||
|
|
611782653c | ||
|
|
229d2b578e | ||
|
|
8e39d7988b | ||
|
|
4debaee7d4 | ||
|
|
4af61a372f | ||
|
|
3f1f5736b5 | ||
|
|
2afff4ec20 | ||
|
|
764b9f27b6 | ||
|
|
2d5c408b54 | ||
|
|
22a4bc355e | ||
|
|
90284739c0 | ||
|
|
8471b7d7b9 | ||
|
|
38fd5fa2c8 | ||
|
|
0c4fd27226 | ||
|
|
a80a63fbc1 | ||
|
|
9cd95ed0e4 | ||
|
|
b5efaf2b5b | ||
|
|
da6d242353 | ||
|
|
0b1ec9a837 | ||
|
|
45d298b755 | ||
|
|
266d7a4651 | ||
|
|
d051b392d0 | ||
|
|
e2fc373a06 | ||
|
|
48de55f987 | ||
|
|
0079b80b1c | ||
|
|
f6b073557a | ||
|
|
b8626f3c27 | ||
|
|
0b8be33d68 | ||
|
|
e14ebec387 | ||
|
|
b4bb5c4a39 | ||
|
|
c04cd8a956 | ||
|
|
908167c83e | ||
|
|
ab17598972 | ||
|
|
db05a5a6a9 | ||
|
|
cb2c83678e | ||
|
|
b0b5f76423 | ||
|
|
44374a84a7 | ||
|
|
39f5893c7e | ||
|
|
89bb475994 | ||
|
|
c4ed04ba96 | ||
|
|
886ce2fe3d | ||
|
|
8442f7741d | ||
|
|
29749f64e9 | ||
|
|
5c95668a1d | ||
|
|
cb51880925 | ||
|
|
da24643c64 | ||
|
|
f761f87e1d | ||
|
|
fc2f1cd7e6 | ||
|
|
155495eeef | ||
|
|
1491ea8e75 | ||
|
|
ff4cd48f1e | ||
|
|
d555a80d8d | ||
|
|
2d8efa0154 | ||
|
|
78aeacc8a1 | ||
|
|
5545d84284 | ||
|
|
30280c5f93 | ||
|
|
e42b587d88 | ||
|
|
c270fdcb03 | ||
|
|
0534824c07 | ||
|
|
5ce7ebe674 | ||
|
|
c9e9a11e4e | ||
|
|
d1175519eb | ||
|
|
566b4ea59e | ||
|
|
0e7217778f | ||
|
|
b376525d30 | ||
|
|
ce03f7c600 | ||
|
|
eafdc2f17f | ||
|
|
22252f9161 | ||
|
|
7dda8bdd25 | ||
|
|
41754f5c67 | ||
|
|
099763e1e3 | ||
|
|
a8bef51834 | ||
|
|
c880c4ef73 | ||
|
|
8ab740fa2e | ||
|
|
93513f3ea8 | ||
|
|
9dbf9fd501 | ||
|
|
e239de52d6 | ||
|
|
9e06d4d51f | ||
|
|
d200c2c849 | ||
|
|
f5f3bad8db | ||
|
|
344accea60 | ||
|
|
2326e69c0c | ||
|
|
80e0bae347 | ||
|
|
5c0ee3bae0 | ||
|
|
e04d058381 | ||
|
|
0735aae74f | ||
|
|
3ac99491cf | ||
|
|
303578a83f | ||
|
|
ce163db30b | ||
|
|
dbdb8a0d32 | ||
|
|
9b418521af | ||
|
|
b1ad7b5ba3 | ||
|
|
9158da60c2 | ||
|
|
7f8379ea6c | ||
|
|
8c957f9d9f | ||
|
|
819476a3ec | ||
|
|
1f1b32e101 | ||
|
|
f131b21273 | ||
|
|
5ae0192bc6 | ||
|
|
dc088dcb0a | ||
|
|
bf94f10a64 | ||
|
|
562f4855bd | ||
|
|
64579f9603 | ||
|
|
ae290936b9 | ||
|
|
0f2c481616 | ||
|
|
b19dd60e52 | ||
|
|
2f281f13fd | ||
|
|
3eeca63d91 | ||
|
|
3f938d3488 | ||
|
|
7fb1f30303 | ||
|
|
3e0c4b2eb7 | ||
|
|
bfd81745e9 | ||
|
|
6376bde112 | ||
|
|
047c09017c | ||
|
|
1f687f9b96 | ||
|
|
ad4933a1f9 | ||
|
|
838bb7ec2e | ||
|
|
92a3eaa426 | ||
|
|
4227882afa | ||
|
|
5a8499ac43 | ||
|
|
72cb982b13 | ||
|
|
92b22acb91 | ||
|
|
2ad45edef5 | ||
|
|
cfff2cb738 | ||
|
|
163dadbe37 | ||
|
|
08daa2f59e |
+1
-2
@@ -4,5 +4,4 @@ build/
|
|||||||
.vs/
|
.vs/
|
||||||
recovery/
|
recovery/
|
||||||
vendor/directx
|
vendor/directx
|
||||||
Sandbox/imgui.ini
|
imgui.ini
|
||||||
Sandbox/worlds
|
|
||||||
|
|||||||
+21
-6
@@ -1,12 +1,27 @@
|
|||||||
[submodule "GlitchyEngine/vendor/directx"]
|
[submodule "GlitchyEngine/vendor/directx"]
|
||||||
path = GlitchyEngine/vendor/directx
|
path = GlitchyEngine/vendor/directx
|
||||||
url = https://github.com/aharabada/directx-beef.git
|
url = https://github.com/aharabada/directx-beef.git
|
||||||
[submodule "GlitchyEngine/vendor/imgui-beef"]
|
|
||||||
path = GlitchyEngine/vendor/imgui-beef
|
|
||||||
url = https://github.com/aharabada/imgui-beef
|
|
||||||
[submodule ".\\GlitchyEngine\\vendor\\DirectXTK"]
|
|
||||||
path = .\\GlitchyEngine\\vendor\\DirectXTK
|
|
||||||
url = https://github.com/aharabada/DirectXTK-beef.git
|
|
||||||
[submodule "vendor/lodepng-beef"]
|
[submodule "vendor/lodepng-beef"]
|
||||||
path = vendor/lodepng-beef
|
path = vendor/lodepng-beef
|
||||||
url = https://github.com/aharabada/lodepng-beef.git
|
url = https://github.com/aharabada/lodepng-beef.git
|
||||||
|
[submodule "GlitchyEngine/vendor/freetype"]
|
||||||
|
path = GlitchyEngine/vendor/freetype
|
||||||
|
url = https://github.com/aharabada/FreeType-beef.git
|
||||||
|
[submodule "GlitchyEngine/vendor/gltf"]
|
||||||
|
path = GlitchyEngine/vendor/gltf
|
||||||
|
url = https://github.com/aharabada/cgltf-beef.git
|
||||||
|
[submodule "GlitchyEngine/vendor/msdfgen"]
|
||||||
|
path = GlitchyEngine/vendor/msdfgen
|
||||||
|
url = https://github.com/aharabada/msdfgen-beef.git
|
||||||
|
[submodule "GlitchyEngine/vendor/imgui"]
|
||||||
|
path = GlitchyEngine/vendor/imgui
|
||||||
|
url = https://github.com/aharabada/ImGui_GlitchyEngine.git
|
||||||
|
[submodule "GlitchyEngineHelper/vendor/xxHash"]
|
||||||
|
path = GlitchyEngineHelper/vendor/xxHash
|
||||||
|
url = https://github.com/Cyan4973/xxHash.git
|
||||||
|
[submodule "GlitchyEngine/vendor/bon"]
|
||||||
|
path = GlitchyEngine/vendor/bon
|
||||||
|
url = https://github.com/EinScott/bon.git
|
||||||
|
[submodule "GlitchyEngineHelper/vendor/DirectXTK"]
|
||||||
|
path = GlitchyEngineHelper/vendor/DirectXTK
|
||||||
|
url = https://github.com/microsoft/DirectXTK.git
|
||||||
+3
-2
@@ -1,5 +1,6 @@
|
|||||||
FileVersion = 1
|
FileVersion = 1
|
||||||
Projects = {Sandbox = {Path = "Sandbox"}, GlitchyEngine = {Path = "GlitchyEngine"}, GlitchLog = {Path = "GlitchLog"}, DirectX = {Path = "GlitchyEngine/vendor/directx/DirectX"}, ImGui = {Path = "GlitchyEngine/vendor/imgui-beef/ImGui"}, ImGuiImplWin32 = {Path = "GlitchyEngine/vendor/imgui-beef/ImGuiImplWin32"}, ImGuiImplDX11 = {Path = "GlitchyEngine/vendor/imgui-beef/ImGuiImplDX11"}, DirectXTK = {Path = "GlitchyEngine/vendor/DirectXTK/DirectXTK-beef"}, LodePng = {Path = "vendor/lodepng-beef/lodepng-beef"}}
|
Projects = {Sandbox = {Path = "Sandbox"}, GlitchyEngine = {Path = "GlitchyEngine"}, GlitchLog = {Path = "GlitchLog"}, DirectX = {Path = "GlitchyEngine/vendor/directx/DirectX"}, LodePng = {Path = "vendor/lodepng-beef/lodepng-beef"}, FreeType = {Path = "GlitchyEngine/vendor/freetype"}, cgltf-beef = {Path = "GlitchyEngine/vendor/gltf/cgltf-beef"}, GlitchyEditor = {Path = "GlitchyEditor"}, msdfgen-beef = {Path = "GlitchyEngine/vendor/msdfgen/msdfgen-beef"}, ImGui = {Path = "GlitchyEngine/vendor/imgui/ImGui"}, ImGuiImplDX11 = {Path = "GlitchyEngine/vendor/imgui/ImGuiImplDX11"}, ImGuiImplWin32 = {Path = "GlitchyEngine/vendor/imgui/ImGuiImplWin32"}, ImGuizmo = {Path = "GlitchyEngine/vendor/imgui/ImGuizmo"}, GlitchyEngineHelper = {Path = "GlitchyEngineHelper"}, bon = {Path = "GlitchyEngine/vendor/bon"}}
|
||||||
|
WorkspaceFolders = {GlitchyEngine = ["GlitchyEngine", "GlitchLog", "GlitchyEngineHelper"], "GlitchyEngine/Dependencies" = ["cgltf-beef", "DirectX", "FreeType", "ImGui", "ImGuiImplDX11", "ImGuiImplWin32", "ImGuizmo", "LodePng", "msdfgen-beef", "bon"]}
|
||||||
|
|
||||||
[Workspace]
|
[Workspace]
|
||||||
StartupProject = "Sandbox"
|
StartupProject = "GlitchyEditor"
|
||||||
|
|||||||
@@ -50,10 +50,10 @@ namespace GlitchLog
|
|||||||
|
|
||||||
public this()
|
public this()
|
||||||
{
|
{
|
||||||
Runtime.Assert(Debug.IsDebuggerPresent, "The DebugLogger requires a debugger to be present.");
|
//Debug.Assert(Debug.IsDebuggerPresent, "The DebugLogger requires a debugger to be present.");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if GL_NOLOG || GL_NOTRACE
|
#if GL_NOLOG || GL_LOG_NOTRACE
|
||||||
[SkipCall]
|
[SkipCall]
|
||||||
#endif
|
#endif
|
||||||
[Inline]
|
[Inline]
|
||||||
@@ -62,7 +62,7 @@ namespace GlitchLog
|
|||||||
InternalLog(.Trace, format, params args);
|
InternalLog(.Trace, format, params args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if GL_NOLOG || GL_NOINFO
|
#if GL_NOLOG || GL_LOG_NOINFO
|
||||||
[SkipCall]
|
[SkipCall]
|
||||||
#endif
|
#endif
|
||||||
[Inline]
|
[Inline]
|
||||||
@@ -71,7 +71,7 @@ namespace GlitchLog
|
|||||||
InternalLog(.Info, format, params args);
|
InternalLog(.Info, format, params args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if GL_NOLOG || GL_NOWARNING
|
#if GL_NOLOG || GL_LOG_NOWARNING
|
||||||
[SkipCall]
|
[SkipCall]
|
||||||
#endif
|
#endif
|
||||||
[Inline]
|
[Inline]
|
||||||
@@ -80,7 +80,7 @@ namespace GlitchLog
|
|||||||
InternalLog(.Warning, format, params args);
|
InternalLog(.Warning, format, params args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if GL_NOLOG || GL_NOERROR
|
#if GL_NOLOG || GL_LOG_NOERROR
|
||||||
[SkipCall]
|
[SkipCall]
|
||||||
#endif
|
#endif
|
||||||
[Inline]
|
[Inline]
|
||||||
@@ -89,7 +89,7 @@ namespace GlitchLog
|
|||||||
InternalLog(.Error, format, params args);
|
InternalLog(.Error, format, params args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if GL_NOLOG || GL_NOCRITICAL
|
#if GL_NOLOG || GL_LOG_NOCRITICAL
|
||||||
[SkipCall]
|
[SkipCall]
|
||||||
#endif
|
#endif
|
||||||
[Inline]
|
[Inline]
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
FileVersion = 1
|
||||||
|
Dependencies = {corlib = "*", GlitchLog = "*", GlitchyEngine = "*"}
|
||||||
|
|
||||||
|
[Project]
|
||||||
|
Name = "GlitchyEditor"
|
||||||
|
TargetType = "BeefGUIApplication"
|
||||||
|
StartupObject = "GlitchyEngine.Program"
|
||||||
Binary file not shown.
@@ -0,0 +1,62 @@
|
|||||||
|
Texture2D Texture : register(t0);
|
||||||
|
SamplerState Sampler : register(s0);
|
||||||
|
|
||||||
|
cbuffer Constants : register(b0)
|
||||||
|
{
|
||||||
|
float4x4 ViewProjection;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VS_Input
|
||||||
|
{
|
||||||
|
float2 Position : POSITION;
|
||||||
|
float2 Texcoord : TEXCOORD0;
|
||||||
|
float4x4 Transform : TRANSFORM;
|
||||||
|
float4 Color : COLOR;
|
||||||
|
float4 UVTransform : TEXCOORD1;
|
||||||
|
float InnerRadius : TEXCOORD2;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PS_Input
|
||||||
|
{
|
||||||
|
float4 Position : SV_Position;
|
||||||
|
float2 RawPos : TEXCOORD0;
|
||||||
|
float2 Texcoord : TEXCOORD1;
|
||||||
|
float4 Color : COLOR;
|
||||||
|
float InnerRadius : TEXCOORD2;
|
||||||
|
};
|
||||||
|
|
||||||
|
PS_Input VS(VS_Input input)
|
||||||
|
{
|
||||||
|
PS_Input output;
|
||||||
|
|
||||||
|
output.Position = mul(ViewProjection, mul(input.Transform, float4(input.Position, 0.0f, 1.0f)));
|
||||||
|
output.Texcoord = input.UVTransform.xy + input.UVTransform.zw * input.Texcoord;
|
||||||
|
output.RawPos = input.Position;
|
||||||
|
output.Color = input.Color;
|
||||||
|
output.InnerRadius = input.InnerRadius;
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
float4 PS(PS_Input input) : SV_Target0
|
||||||
|
{
|
||||||
|
float2 uv = input.RawPos * 2;
|
||||||
|
|
||||||
|
float distance = 1.0f - length(uv);
|
||||||
|
|
||||||
|
// Smoothing edges based on derivative (not sure if RawPos is the best value for this)
|
||||||
|
float f = fwidth(input.RawPos.x) + fwidth(input.RawPos.y);
|
||||||
|
|
||||||
|
float amount = smoothstep(0.0f, f, distance);
|
||||||
|
amount *= smoothstep(input.InnerRadius + f, input.InnerRadius, distance);
|
||||||
|
|
||||||
|
// Discard invisible pixels
|
||||||
|
clip(amount - 0.5f);
|
||||||
|
|
||||||
|
float4 color = Texture.Sample(Sampler, input.Texcoord) * input.Color;
|
||||||
|
color.a *= amount;
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
#effect[VS=VS, PS=PS]
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
cbuffer Constants : register(b0)
|
||||||
|
{
|
||||||
|
float4x4 ViewProjection;
|
||||||
|
float4 Color;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VS_Input
|
||||||
|
{
|
||||||
|
float4 Position : POSITION;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PS_Input
|
||||||
|
{
|
||||||
|
float4 Position : SV_Position;
|
||||||
|
};
|
||||||
|
|
||||||
|
PS_Input VS(VS_Input input)
|
||||||
|
{
|
||||||
|
PS_Input output;
|
||||||
|
|
||||||
|
output.Position = mul(ViewProjection, input.Position);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
float4 PS(PS_Input input) : SV_Target0
|
||||||
|
{
|
||||||
|
return Color;
|
||||||
|
}
|
||||||
|
|
||||||
|
#effect[VS=VS, PS=PS]
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
Texture2D<float3> Texture : register(t0);
|
||||||
|
SamplerState Sampler : register(s0);
|
||||||
|
|
||||||
|
cbuffer Constants
|
||||||
|
{
|
||||||
|
float4x4 ViewProjection;
|
||||||
|
float2 UnitRange;
|
||||||
|
float screenPixelRange = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct VS_Input
|
||||||
|
{
|
||||||
|
float2 Position : POSITION;
|
||||||
|
float2 Texcoord : TEXCOORD0;
|
||||||
|
float4x4 Tranform : TRANSFORM;
|
||||||
|
float4 Color : COLOR;
|
||||||
|
float4 UVTransform : TEXCOORD1;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PS_Input
|
||||||
|
{
|
||||||
|
float4 Position : SV_Position;
|
||||||
|
float2 TexCoord : TEXCOORD0;
|
||||||
|
float4 Color : COLOR;
|
||||||
|
};
|
||||||
|
|
||||||
|
PS_Input VS(VS_Input input)
|
||||||
|
{
|
||||||
|
PS_Input output;
|
||||||
|
|
||||||
|
output.Position = mul(ViewProjection, mul(input.Tranform, float4(input.Position, 0.0f, 1.0f)));
|
||||||
|
output.TexCoord = input.UVTransform.xy + input.UVTransform.zw * input.Texcoord;
|
||||||
|
output.Color = input.Color;
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
in vec2 texCoord;
|
||||||
|
out vec4 color;
|
||||||
|
uniform sampler2D msdf;
|
||||||
|
uniform vec4 bgColor;
|
||||||
|
uniform vec4 fgColor;
|
||||||
|
|
||||||
|
float median(float r, float g, float b) {
|
||||||
|
return max(min(r, g), min(max(r, g), b));
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec3 msd = texture(msdf, texCoord).rgb;
|
||||||
|
float sd = median(msd.r, msd.g, msd.b);
|
||||||
|
float screenPxDistance = screenPxRange()*(sd - 0.5);
|
||||||
|
float opacity = clamp(screenPxDistance + 0.5, 0.0, 1.0);
|
||||||
|
color = mix(bgColor, fgColor, opacity);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
float median(float r, float g, float b)
|
||||||
|
{
|
||||||
|
return max(min(r, g), min(max(r, g), b));
|
||||||
|
}
|
||||||
|
|
||||||
|
float ScreenPxRange(float2 texcoord)
|
||||||
|
{
|
||||||
|
float2 screenTexSize = 1.0f / fwidth(texcoord);
|
||||||
|
return max(0.5f * dot(UnitRange, screenTexSize), 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
float4 PS(PS_Input input) : SV_Target0
|
||||||
|
{
|
||||||
|
float3 msd = Texture.Sample(Sampler, input.TexCoord);
|
||||||
|
float sd = median(msd.r, msd.g, msd.b);
|
||||||
|
float screenPxDistance = ScreenPxRange(input.TexCoord) * (sd - 0.5);
|
||||||
|
float opacity = clamp(screenPxDistance + 0.5, 0.0, 1.0);
|
||||||
|
|
||||||
|
return float4(input.Color.rgb, opacity * input.Color.a);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// 2D
|
||||||
|
float4 PS(PS_Input input) : SV_Target0
|
||||||
|
{
|
||||||
|
float3 msd = Texture.Sample(Sampler, input.TexCoord).rgb;
|
||||||
|
float sd = median(msd.r, msd.g, msd.b);
|
||||||
|
float screenPxDistance = screenPixelRange*(sd - 0.5);
|
||||||
|
float opacity = clamp(screenPxDistance + 0.5, 0.0, 1.0);
|
||||||
|
|
||||||
|
return float4(input.Color.rgb, opacity * input.Color.a);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#effect[VS=VS, PS=PS]
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
Texture2D Texture : register(t0);
|
||||||
|
SamplerState Sampler : register(s0);
|
||||||
|
|
||||||
|
cbuffer Constants : register(b0)
|
||||||
|
{
|
||||||
|
float4x4 ViewProjection;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VS_Input
|
||||||
|
{
|
||||||
|
float2 Position : POSITION;
|
||||||
|
float2 Texcoord : TEXCOORD0;
|
||||||
|
float4x4 Transform : TRANSFORM;
|
||||||
|
float4 Color : COLOR;
|
||||||
|
float4 UVTransform : TEXCOORD1;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PS_Input
|
||||||
|
{
|
||||||
|
float4 Position : SV_Position;
|
||||||
|
float2 Texcoord : TEXCOORD;
|
||||||
|
float4 Color : COLOR;
|
||||||
|
};
|
||||||
|
|
||||||
|
PS_Input VS(VS_Input input)
|
||||||
|
{
|
||||||
|
PS_Input output;
|
||||||
|
|
||||||
|
output.Position = mul(ViewProjection, mul(input.Transform, float4(input.Position, 0.0f, 1.0f)));
|
||||||
|
output.Texcoord = input.UVTransform.xy + input.UVTransform.zw * input.Texcoord;
|
||||||
|
output.Color = input.Color;
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
float4 PS(PS_Input input) : SV_Target0
|
||||||
|
{
|
||||||
|
return Texture.Sample(Sampler, input.Texcoord) * input.Color;
|
||||||
|
}
|
||||||
|
|
||||||
|
#effect[VS=VS, PS=PS]
|
||||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 258 B |
@@ -0,0 +1,298 @@
|
|||||||
|
using ImGui;
|
||||||
|
using GlitchyEngine.World;
|
||||||
|
using System;
|
||||||
|
using GlitchyEngine.Math;
|
||||||
|
using System.Collections;
|
||||||
|
|
||||||
|
namespace GlitchyEditor.EditWindows
|
||||||
|
{
|
||||||
|
using internal GlitchyEngine.World.TransformComponent;
|
||||||
|
|
||||||
|
class ComponentEditWindow : EditorWindow
|
||||||
|
{
|
||||||
|
public const String s_WindowTitle = "Components";
|
||||||
|
|
||||||
|
private EntityHierarchyWindow _entityHierarchyWindow;
|
||||||
|
|
||||||
|
private List<(Type, ComponentAttribute attribute)> _componentTypes = new .() ~ delete _;
|
||||||
|
|
||||||
|
public this(EntityHierarchyWindow entityHierarchyWindow)
|
||||||
|
{
|
||||||
|
_entityHierarchyWindow = entityHierarchyWindow;
|
||||||
|
|
||||||
|
for (let type in Type.Types)
|
||||||
|
{
|
||||||
|
if (let componentAttribute = type.GetCustomAttribute<ComponentAttribute>())
|
||||||
|
{
|
||||||
|
_componentTypes.Add((type, componentAttribute));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void InternalShow()
|
||||||
|
{
|
||||||
|
ImGui.PushStyleVar(.WindowMinSize, ImGui.Vec2(1000, 100));
|
||||||
|
|
||||||
|
if(!ImGui.Begin(s_WindowTitle, &_open, .None))
|
||||||
|
{
|
||||||
|
ImGui.PopStyleVar();
|
||||||
|
ImGui.End();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_entityHierarchyWindow.SelectedEntities.Count == 1)
|
||||||
|
{
|
||||||
|
Entity entity = _entityHierarchyWindow.SelectedEntities.Front;
|
||||||
|
|
||||||
|
ShowComponents(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.PopStyleVar();
|
||||||
|
ImGui.End();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowComponents(Entity entity)
|
||||||
|
{
|
||||||
|
ShowNameComponentEditor(entity);
|
||||||
|
|
||||||
|
ShowComponentEditor<TransformComponent>("Transform", entity, => ShowTransformComponentEditor);
|
||||||
|
ShowComponentEditor<CameraComponent>("Camera", entity, => ShowCameraComponentEditor, => ShowComponentContextMenu<CameraComponent>);
|
||||||
|
ShowComponentEditor<SpriterRendererComponent>("Sprite Renderer", entity, => ShowSpriteRendererComponentEditor, => ShowComponentContextMenu<SpriterRendererComponent>);
|
||||||
|
|
||||||
|
ShowAddComponentButton(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ShowComponentContextMenu<TComponent>(Entity entity, TComponent* component) where TComponent: struct, new
|
||||||
|
{
|
||||||
|
if (ImGui.Selectable("Remove Component"))
|
||||||
|
entity.RemoveComponent<TComponent>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ShowComponentEditor<TComponent>(String header, Entity entity, function void(Entity, TComponent*) showComponentEditor, function void(Entity, TComponent*) showComponentContextMenu = null) where TComponent: struct, new
|
||||||
|
{
|
||||||
|
if (!entity.HasComponent<TComponent>())
|
||||||
|
return;
|
||||||
|
|
||||||
|
TComponent* component = entity.GetComponent<TComponent>();
|
||||||
|
|
||||||
|
ImGui.PushID(header);
|
||||||
|
|
||||||
|
bool nodeOpen = ImGui.TreeNodeEx(header.CStr(), .DefaultOpen | .AllowItemOverlap | .Framed | .SpanFullWidth);
|
||||||
|
|
||||||
|
if (showComponentContextMenu != null)
|
||||||
|
{
|
||||||
|
ImGui.SameLine(ImGui.GetWindowContentRegionMax().x - ImGui.CalcTextSize("...").x - 2 * ImGui.GetStyle().FramePadding.x);
|
||||||
|
|
||||||
|
if (ImGui.SmallButton("..."))
|
||||||
|
{
|
||||||
|
ImGui.OpenPopup("component_popup");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.BeginPopup("component_popup"))
|
||||||
|
{
|
||||||
|
showComponentContextMenu(entity, component);
|
||||||
|
|
||||||
|
ImGui.EndPopup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nodeOpen)
|
||||||
|
{
|
||||||
|
showComponentEditor(entity, component);
|
||||||
|
|
||||||
|
ImGui.TreePop();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.PopID();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ShowNameComponentEditor(Entity entity)
|
||||||
|
{
|
||||||
|
if (!entity.HasComponent<DebugNameComponent>())
|
||||||
|
return;
|
||||||
|
|
||||||
|
char8[256] nameBuffer = default;
|
||||||
|
|
||||||
|
DebugNameComponent* component = entity.GetComponent<DebugNameComponent>();
|
||||||
|
|
||||||
|
String name = null;
|
||||||
|
|
||||||
|
if(component != null)
|
||||||
|
{
|
||||||
|
name = component.DebugName;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
name = scope:: $"Entity {entity.Handle.[Friend]Index}";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy name to buffer
|
||||||
|
Internal.MemCpy(&nameBuffer, name.Ptr, Math.Min(nameBuffer.Count, name.Length));
|
||||||
|
|
||||||
|
if(ImGui.InputText("Name", &nameBuffer, nameBuffer.Count))
|
||||||
|
{
|
||||||
|
if(component == null)
|
||||||
|
{
|
||||||
|
component = entity.AddComponent<DebugNameComponent>();
|
||||||
|
}
|
||||||
|
|
||||||
|
component.DebugName.Clear();
|
||||||
|
component.DebugName.Append(&nameBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ShowTransformComponentEditor(Entity entity, TransformComponent* transform)
|
||||||
|
{
|
||||||
|
float textWidth = ImGui.CalcTextSize("Position".CStr()).x;
|
||||||
|
textWidth = Math.Max(textWidth, ImGui.CalcTextSize("Rotation".CStr()).x);
|
||||||
|
textWidth = Math.Max(textWidth, ImGui.CalcTextSize("Scale".CStr()).x);
|
||||||
|
|
||||||
|
textWidth += ImGui.GetStyle().FramePadding.x * 3.0f;
|
||||||
|
|
||||||
|
Vector3 position = transform.Position;
|
||||||
|
if (ImGui.EditVector3("Position", ref position, .Zero, 0.1f, textWidth))
|
||||||
|
transform.Position = position;
|
||||||
|
|
||||||
|
Vector3 rotationEuler = MathHelper.ToDegrees(transform.EditorRotationEuler);
|
||||||
|
if (ImGui.EditVector3("Rotation", ref rotationEuler, .Zero, 0.1f, textWidth))
|
||||||
|
transform.EditorRotationEuler = MathHelper.ToRadians(rotationEuler);
|
||||||
|
|
||||||
|
Vector3 scale = transform.Scale;
|
||||||
|
if (ImGui.EditVector3("Scale", ref scale, .One, 0.1f, textWidth))
|
||||||
|
transform.Scale = scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String[] strings = new String[]("Orthographic", "Perspective", "Perspective (Infinite)") ~ delete _;
|
||||||
|
|
||||||
|
private static void ShowCameraComponentEditor(Entity entity, CameraComponent* cameraComponent)
|
||||||
|
{
|
||||||
|
ImGui.Checkbox("Primary", &cameraComponent.Primary);
|
||||||
|
|
||||||
|
var camera = ref cameraComponent.Camera;
|
||||||
|
|
||||||
|
String typeName = strings[camera.ProjectionType.Underlying];
|
||||||
|
|
||||||
|
if (ImGui.BeginCombo("Projection", typeName.CStr()))
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
bool isSelected = (typeName == strings[i]);
|
||||||
|
|
||||||
|
if (ImGui.Selectable(strings[i], isSelected))
|
||||||
|
{
|
||||||
|
camera.ProjectionType = (.)i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSelected)
|
||||||
|
ImGui.SetItemDefaultFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndCombo();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (camera.ProjectionType == .Perspective)
|
||||||
|
{
|
||||||
|
float fovY = MathHelper.ToDegrees(camera.PerspectiveFovY);
|
||||||
|
if (ImGui.DragFloat("Fov Y", &fovY, 0.1f))
|
||||||
|
camera.PerspectiveFovY = MathHelper.ToRadians(fovY);
|
||||||
|
|
||||||
|
float near = camera.PerspectiveNearPlane;
|
||||||
|
if (ImGui.DragFloat("Near", &near, 0.1f))
|
||||||
|
camera.PerspectiveNearPlane = near;
|
||||||
|
|
||||||
|
float far = camera.PerspectiveFarPlane;
|
||||||
|
if (ImGui.DragFloat("Far", &far, 0.1f))
|
||||||
|
camera.PerspectiveFarPlane = far;
|
||||||
|
}
|
||||||
|
else if (camera.ProjectionType == .InfinitePerspective)
|
||||||
|
{
|
||||||
|
float fovY = MathHelper.ToDegrees(camera.PerspectiveFovY);
|
||||||
|
if (ImGui.DragFloat("Vertical FOV", &fovY, 0.1f))
|
||||||
|
camera.PerspectiveFovY = MathHelper.ToRadians(fovY);
|
||||||
|
|
||||||
|
float near = camera.PerspectiveNearPlane;
|
||||||
|
if (ImGui.DragFloat("Near", &near, 0.1f))
|
||||||
|
camera.PerspectiveNearPlane = near;
|
||||||
|
}
|
||||||
|
else if (camera.ProjectionType == .Orthographic)
|
||||||
|
{
|
||||||
|
float size = camera.OrthographicHeight;
|
||||||
|
if (ImGui.DragFloat("Size", &size, 0.1f))
|
||||||
|
camera.OrthographicHeight = size;
|
||||||
|
|
||||||
|
float near = camera.OrthographicNearPlane;
|
||||||
|
if (ImGui.DragFloat("Near", &near, 0.1f))
|
||||||
|
camera.OrthographicNearPlane = near;
|
||||||
|
|
||||||
|
float far = camera.OrthographicFarPlane;
|
||||||
|
if (ImGui.DragFloat("Far", &far, 0.1f))
|
||||||
|
camera.OrthographicFarPlane = far;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fixedAspectRatio = camera.FixedAspectRatio;
|
||||||
|
if (ImGui.Checkbox("Fixed Aspect Ratio", &fixedAspectRatio))
|
||||||
|
camera.FixedAspectRatio = fixedAspectRatio;
|
||||||
|
|
||||||
|
if (fixedAspectRatio)
|
||||||
|
{
|
||||||
|
float aspect = camera.AspectRatio;
|
||||||
|
if (ImGui.DragFloat("Aspect Ratio", &aspect, 0.1f))
|
||||||
|
camera.AspectRatio = aspect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ShowSpriteRendererComponentEditor(Entity entity, SpriterRendererComponent* spriteRendererComponent)
|
||||||
|
{
|
||||||
|
ImGui.ColorEdit4("Color", ref spriteRendererComponent.Color);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ShowAddComponentButton(Entity entity)
|
||||||
|
{
|
||||||
|
static char8[128] searchBuffer = .();
|
||||||
|
static StringView searchFilter = .();
|
||||||
|
|
||||||
|
static float buttonWidth = 100;
|
||||||
|
|
||||||
|
ImGui.NewLine();
|
||||||
|
ImGui.Separator();
|
||||||
|
ImGui.NewLine();
|
||||||
|
|
||||||
|
void ShowComponentButton<TComponent>(String name) where TComponent : struct, new
|
||||||
|
{
|
||||||
|
float textWidth = ImGui.CalcTextSize(name.CStr()).x;
|
||||||
|
buttonWidth = Math.Max(buttonWidth, textWidth + ImGui.GetStyle().FramePadding.x * 2);
|
||||||
|
|
||||||
|
if (name.Contains(searchFilter, true) && ImGui.Selectable(name))
|
||||||
|
{
|
||||||
|
if (!entity.HasComponent<TComponent>())
|
||||||
|
entity.AddComponent<TComponent>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float textWidth = ImGui.CalcTextSize("Add Component...").x;
|
||||||
|
buttonWidth = Math.Max(buttonWidth, textWidth + ImGui.GetStyle().FramePadding.x * 2);
|
||||||
|
|
||||||
|
ImGui.PushItemWidth(buttonWidth);
|
||||||
|
|
||||||
|
ImGui.NewLine();
|
||||||
|
ImGui.SameLine(ImGui.GetContentRegionMax().x / 2 - buttonWidth / 2);
|
||||||
|
|
||||||
|
if (ImGui.BeginCombo("##add_component_combo", "Add Component...", .NoArrowButton))
|
||||||
|
{
|
||||||
|
if (ImGui.InputText("##search_component_name", &searchBuffer, (.)searchBuffer.Count))
|
||||||
|
{
|
||||||
|
searchFilter = .(&searchBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.Separator();
|
||||||
|
|
||||||
|
ShowComponentButton<CameraComponent>("Camera");
|
||||||
|
ShowComponentButton<SpriterRendererComponent>("Sprite Renderer");
|
||||||
|
|
||||||
|
ImGui.EndCombo();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.PopItemWidth();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
namespace GlitchyEditor.EditWindows
|
||||||
|
{
|
||||||
|
abstract class EditorWindow
|
||||||
|
{
|
||||||
|
protected Editor _editor;
|
||||||
|
|
||||||
|
protected bool _open = true;
|
||||||
|
protected bool _hasFocus;
|
||||||
|
|
||||||
|
public bool Open
|
||||||
|
{
|
||||||
|
get => _open;
|
||||||
|
set => _open = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HasFocus
|
||||||
|
{
|
||||||
|
get => _hasFocus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Show()
|
||||||
|
{
|
||||||
|
if(!_open)
|
||||||
|
return;
|
||||||
|
|
||||||
|
InternalShow();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void InternalShow();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,477 @@
|
|||||||
|
using GlitchyEngine.Collections;
|
||||||
|
using GlitchyEngine.World;
|
||||||
|
using ImGui;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using GlitchyEngine;
|
||||||
|
|
||||||
|
namespace GlitchyEditor.EditWindows
|
||||||
|
{
|
||||||
|
using internal GlitchyEditor;
|
||||||
|
|
||||||
|
/// A window for viewing and editing the scene hierarchy
|
||||||
|
class EntityHierarchyWindow : EditorWindow
|
||||||
|
{
|
||||||
|
public const String s_WindowTitle = "Entity Hierarchy";
|
||||||
|
|
||||||
|
/// Buffer for the entity search string.
|
||||||
|
private char8[64] _entitySearchChars;
|
||||||
|
|
||||||
|
private Scene _scene;
|
||||||
|
|
||||||
|
private List<Entity> _selectedEntities = new .() ~ delete _;
|
||||||
|
|
||||||
|
public List<Entity> SelectedEntities => _selectedEntities;
|
||||||
|
|
||||||
|
public this(Scene scene)
|
||||||
|
{
|
||||||
|
SetContext(scene);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetContext(Scene scene)
|
||||||
|
{
|
||||||
|
_scene = scene;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void InternalShow()
|
||||||
|
{
|
||||||
|
if(!ImGui.Begin(s_WindowTitle, &_open, .MenuBar))
|
||||||
|
{
|
||||||
|
ImGui.End();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShowEntityHierarchyMenuBar();
|
||||||
|
|
||||||
|
if (ImGui.BeginPopupContextWindow(s_WindowTitle))
|
||||||
|
{
|
||||||
|
Show_ContextMenu_Create(true, false, false);
|
||||||
|
|
||||||
|
ImGui.EndPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
ShowEntityHierarchy();
|
||||||
|
|
||||||
|
if ((ImGui.IsMouseDown(.Left) || ImGui.IsMouseDown(.Right)) && !ImGui.IsAnyItemHovered() && !ImGui.GetIO().KeyCtrl && ImGui.IsWindowHovered(.AllowWhenBlockedByPopup))
|
||||||
|
_selectedEntities.Clear();
|
||||||
|
|
||||||
|
ImGui.End();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns whether or not all selected entities have the same parent.
|
||||||
|
internal bool AllSelectionsOnSameLevel()
|
||||||
|
{
|
||||||
|
EcsEntity? parent = .InvalidEntity;
|
||||||
|
|
||||||
|
for(var selectedEntity in _selectedEntities)
|
||||||
|
{
|
||||||
|
var transformComponent = selectedEntity.GetComponent<TransformComponent>();
|
||||||
|
|
||||||
|
if(parent == .InvalidEntity)
|
||||||
|
{
|
||||||
|
parent = transformComponent.Parent;
|
||||||
|
}
|
||||||
|
else if(transformComponent.Parent != parent)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Finds all children of the given entity and stores their IDs in the given list.
|
||||||
|
internal void FindChildren(EcsEntity entity, List<EcsEntity> entities)
|
||||||
|
{
|
||||||
|
for(var (child, childTransform) in _scene.[Friend]_ecsWorld.Enumerate<TransformComponent>())
|
||||||
|
{
|
||||||
|
if(childTransform.Parent == entity)
|
||||||
|
{
|
||||||
|
if(!entities.Contains(child))
|
||||||
|
entities.Add(child);
|
||||||
|
|
||||||
|
FindChildren(child, entities);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deletes all selected entities and their children.
|
||||||
|
internal void DeleteSelectedEntities()
|
||||||
|
{
|
||||||
|
for (var entity in _selectedEntities)
|
||||||
|
{
|
||||||
|
_scene.DestroyEntity(entity, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowEntityHierarchyMenuBar()
|
||||||
|
{
|
||||||
|
if(ImGui.BeginMenuBar())
|
||||||
|
{
|
||||||
|
Show_ContextMenu_Create(true, true, true);
|
||||||
|
|
||||||
|
Show_ContextMenu_Delete();
|
||||||
|
|
||||||
|
if(ImGui.MenuItem("Delete", null, false, !_selectedEntities.IsEmpty) ||
|
||||||
|
(Input.IsKeyPressed(.Delete) && ImGui.IsWindowHovered()))
|
||||||
|
{
|
||||||
|
DeleteSelectedEntities();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ImGui.IsItemHovered())
|
||||||
|
ImGui.SetTooltip("Deletes the selected Entities and their children.");
|
||||||
|
|
||||||
|
ImGui.Text("Search:");
|
||||||
|
|
||||||
|
ImGui.InputText(String.Empty, &_entitySearchChars, (.)_entitySearchChars.Count);
|
||||||
|
|
||||||
|
ImGui.EndMenuBar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new entity that is a child of the given entity.
|
||||||
|
private void CreateChild(Entity? entity)
|
||||||
|
{
|
||||||
|
var newEntity = _scene.CreateEntity();
|
||||||
|
|
||||||
|
var transformCmp = newEntity.GetComponent<TransformComponent>();
|
||||||
|
// Last entity in list is the entity that has been selected last.
|
||||||
|
transformCmp.Parent = entity?.Handle ?? .InvalidEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new entity that is a parent of the selected entities.
|
||||||
|
private void CreateParent()
|
||||||
|
{
|
||||||
|
if (_selectedEntities.IsEmpty || !AllSelectionsOnSameLevel())
|
||||||
|
{
|
||||||
|
Log.EngineLogger.Error("Cannot create parent entity.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var commonParent = _selectedEntities.Front.GetComponent<TransformComponent>();
|
||||||
|
|
||||||
|
var newEntity = _scene.CreateEntity();
|
||||||
|
|
||||||
|
if(commonParent != null)
|
||||||
|
{
|
||||||
|
// parent of selected entities is parent of the new entity.
|
||||||
|
// (which is why this doesn't work if the entities don't have the same parent)
|
||||||
|
var newEntityTransform = newEntity.GetComponent<TransformComponent>();
|
||||||
|
newEntityTransform.Parent = commonParent.Parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// new entity is parent of all selected entities.
|
||||||
|
for(var selectedEntity in _selectedEntities)
|
||||||
|
{
|
||||||
|
var selectedTransform = selectedEntity.GetComponent<TransformComponent>();
|
||||||
|
selectedTransform.Parent = newEntity.Handle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Show_ContextMenu_Create(bool allowEmpty = true, bool allowChild = true, bool allowParent = true)
|
||||||
|
{
|
||||||
|
if (ImGui.BeginMenu("Create"))
|
||||||
|
{
|
||||||
|
if (allowEmpty)
|
||||||
|
{
|
||||||
|
if(ImGui.MenuItem("Empty Entity"))
|
||||||
|
{
|
||||||
|
if (_selectedEntities.IsEmpty)
|
||||||
|
_scene.CreateEntity();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Entity? parent = _selectedEntities.Back.Parent;
|
||||||
|
CreateChild(parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ImGui.IsItemHovered())
|
||||||
|
{
|
||||||
|
ImGui.SetTooltip("Create a new Entity.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allowChild)
|
||||||
|
{
|
||||||
|
if(ImGui.MenuItem("Empty Child", null, false, !_selectedEntities.IsEmpty))
|
||||||
|
{
|
||||||
|
CreateChild(_selectedEntities.Back);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ImGui.IsItemHovered())
|
||||||
|
ImGui.SetTooltip("Create a new Entity that is a child of the selected entity.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allowParent)
|
||||||
|
{
|
||||||
|
if(ImGui.MenuItem("Parent", null, false, !_selectedEntities.IsEmpty && AllSelectionsOnSameLevel()))
|
||||||
|
{
|
||||||
|
CreateParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ImGui.IsItemHovered())
|
||||||
|
ImGui.SetTooltip("Create a new Entity that is the parent of the selected entities.");
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ImGui.IsItemHovered())
|
||||||
|
ImGui.SetTooltip("Create a new Entity.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool Show_ContextMenu_Delete()
|
||||||
|
{
|
||||||
|
bool deleted = false;
|
||||||
|
|
||||||
|
if(ImGui.MenuItem("Delete", null, false, !_selectedEntities.IsEmpty))
|
||||||
|
{
|
||||||
|
DeleteSelectedEntities();
|
||||||
|
|
||||||
|
deleted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ImGui.IsItemHovered())
|
||||||
|
ImGui.SetTooltip("Deletes the selected Entities and their children.");
|
||||||
|
|
||||||
|
return deleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ImGuiPrintEntityTree(TreeNode<Entity> tree)
|
||||||
|
{
|
||||||
|
String name = null;
|
||||||
|
|
||||||
|
var nameComponent = tree.Value.GetComponent<DebugNameComponent>();
|
||||||
|
|
||||||
|
if(nameComponent != null)
|
||||||
|
{
|
||||||
|
name = nameComponent.DebugName;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
name = scope:: $"Entity {(tree.Value.Handle.[Friend]Index)}";
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.TreeNodeFlags flags = .OpenOnArrow | .DefaultOpen | .SpanAvailWidth;
|
||||||
|
|
||||||
|
if(tree.Children.Count == 0)
|
||||||
|
flags |= .Leaf;
|
||||||
|
|
||||||
|
bool inSelectedList = _selectedEntities.Contains(tree.Value);
|
||||||
|
|
||||||
|
if(inSelectedList)
|
||||||
|
flags |= .Selected;
|
||||||
|
|
||||||
|
bool isOpen = ImGui.TreeNodeEx((void*)(uint)tree.Value.Handle.[Friend]Index, flags, $"{name}");
|
||||||
|
|
||||||
|
ImGui.PushID((void*)(uint)tree.Value.Handle.[Friend]Index);
|
||||||
|
|
||||||
|
bool deleted = false;
|
||||||
|
|
||||||
|
if (ImGui.BeginPopupContextItem("treeNodePopup"))
|
||||||
|
{
|
||||||
|
Show_ContextMenu_Create(true, true, true);
|
||||||
|
deleted = Show_ContextMenu_Delete();
|
||||||
|
|
||||||
|
ImGui.EndPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.PopID();
|
||||||
|
|
||||||
|
if (deleted)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(ImGui.BeginDragDropSource())
|
||||||
|
{
|
||||||
|
ImGui.SetDragDropPayload("DND_Entity", &tree.Value, sizeof(Entity));
|
||||||
|
|
||||||
|
ImGui.Text(name);
|
||||||
|
|
||||||
|
ImGui.EndDragDropSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ImGui.BeginDragDropTarget())
|
||||||
|
{
|
||||||
|
ImGui.Payload* payload = ImGui.AcceptDragDropPayload("DND_Entity");
|
||||||
|
|
||||||
|
if(payload != null)
|
||||||
|
{
|
||||||
|
Log.ClientLogger.AssertDebug(payload.DataSize == sizeof(Entity));
|
||||||
|
|
||||||
|
Entity movedEntity = *(Entity*)payload.Data;
|
||||||
|
|
||||||
|
bool dropLegal = true;
|
||||||
|
|
||||||
|
Entity walker = tree.Value;
|
||||||
|
|
||||||
|
// make sure the dropped entity is not a parent of the entity we dropped it on.
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
var parentTransform = walker.GetComponent<TransformComponent>();
|
||||||
|
|
||||||
|
if(parentTransform.Parent == .InvalidEntity)
|
||||||
|
{
|
||||||
|
dropLegal = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if(parentTransform.Parent == movedEntity.Handle)
|
||||||
|
{
|
||||||
|
dropLegal = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
walker = .(parentTransform.Parent, _scene);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dropLegal)
|
||||||
|
{
|
||||||
|
var movedEntityTransform = movedEntity.GetComponent<TransformComponent>();
|
||||||
|
movedEntityTransform.Parent = tree.Value.Handle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndDragDropTarget();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool clicked = ImGui.IsItemClicked(.Left);
|
||||||
|
bool clickedRight = ImGui.IsItemClicked(.Right);
|
||||||
|
|
||||||
|
if(isOpen)
|
||||||
|
{
|
||||||
|
for(var child in tree.Children)
|
||||||
|
{
|
||||||
|
ImGuiPrintEntityTree(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.TreePop();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clicked || clickedRight)
|
||||||
|
{
|
||||||
|
if (inSelectedList && !clickedRight)
|
||||||
|
{
|
||||||
|
_selectedEntities.Remove(tree.Value);
|
||||||
|
inSelectedList = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!ImGui.GetIO().KeyCtrl && !clickedRight)
|
||||||
|
{
|
||||||
|
_selectedEntities.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
_selectedEntities.Add(tree.Value);
|
||||||
|
inSelectedList = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowEntityHierarchy()
|
||||||
|
{
|
||||||
|
StringView searchString = StringView(&_entitySearchChars);
|
||||||
|
|
||||||
|
if(searchString.IsWhiteSpace)
|
||||||
|
{
|
||||||
|
// Show entity hierarchy as tree
|
||||||
|
|
||||||
|
TreeNode<Entity> root = scope .(Entity(.InvalidEntity, _scene));
|
||||||
|
|
||||||
|
TreeNode<Entity> InsertIntoTree(Entity entity)
|
||||||
|
{
|
||||||
|
var transform = entity.GetComponent<TransformComponent>();
|
||||||
|
|
||||||
|
if(transform == null)
|
||||||
|
{
|
||||||
|
return root.AddChild(entity);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var parentEntity = Entity(transform.Parent, _scene);
|
||||||
|
|
||||||
|
var parentNode = root.FindNode(parentEntity);
|
||||||
|
|
||||||
|
if(parentNode == null)
|
||||||
|
parentNode = InsertIntoTree(parentEntity);
|
||||||
|
|
||||||
|
return parentNode.AddChild(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(var entityId in _scene.[Friend]_ecsWorld.Enumerate())
|
||||||
|
{
|
||||||
|
Entity entity = .(entityId, _scene);
|
||||||
|
|
||||||
|
//if (!entity.HasComponent<EditorComponent>())
|
||||||
|
InsertIntoTree(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ImGui.TreeNodeEx("Scene", .DefaultOpen))
|
||||||
|
{
|
||||||
|
if(ImGui.BeginDragDropTarget())
|
||||||
|
{
|
||||||
|
ImGui.Payload* payload = ImGui.AcceptDragDropPayload("DND_Entity");
|
||||||
|
|
||||||
|
if(payload != null)
|
||||||
|
{
|
||||||
|
Log.ClientLogger.AssertDebug(payload.DataSize == sizeof(Entity));
|
||||||
|
|
||||||
|
Entity movedEntity = *(Entity*)payload.Data;
|
||||||
|
|
||||||
|
// Also mark transform as dirty
|
||||||
|
var transformComponent = movedEntity.GetComponent<TransformComponent>();
|
||||||
|
transformComponent.Parent = .InvalidEntity;
|
||||||
|
//transformComponent?.IsDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndDragDropTarget();
|
||||||
|
}
|
||||||
|
|
||||||
|
for(var child in root.Children)
|
||||||
|
{
|
||||||
|
ImGuiPrintEntityTree(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.TreePop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Otherwise
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Show search results as flat list
|
||||||
|
|
||||||
|
List<StringView> searchTokens = new:ScopedAlloc! .(searchString.Split(' ', .RemoveEmptyEntries));
|
||||||
|
|
||||||
|
worldEnumeration:
|
||||||
|
for(var entityId in _scene.[Friend]_ecsWorld.Enumerate())
|
||||||
|
{
|
||||||
|
Entity entity = .(entityId, _scene);
|
||||||
|
|
||||||
|
String name = null;
|
||||||
|
|
||||||
|
var nameComponent = entity.GetComponent<DebugNameComponent>();
|
||||||
|
|
||||||
|
if(nameComponent != null)
|
||||||
|
{
|
||||||
|
name = nameComponent.DebugName;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
name = scope:worldEnumeration $"Entity {entityId.[Friend]Index}";
|
||||||
|
}
|
||||||
|
|
||||||
|
StringView nameView = StringView(name);
|
||||||
|
|
||||||
|
for(var token in searchTokens)
|
||||||
|
{
|
||||||
|
if(nameView.IndexOf(token, true) == -1)
|
||||||
|
{
|
||||||
|
continue worldEnumeration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGuiPrintEntityTree(scope .(entity));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
using System;
|
||||||
|
using ImGui;
|
||||||
|
using GlitchyEngine.Renderer;
|
||||||
|
using GlitchyEngine.Math;
|
||||||
|
using GlitchyEngine;
|
||||||
|
using GlitchyEngine.World;
|
||||||
|
using ImGuizmo;
|
||||||
|
|
||||||
|
namespace GlitchyEditor.EditWindows
|
||||||
|
{
|
||||||
|
class SceneViewportWindow : EditorWindow
|
||||||
|
{
|
||||||
|
//public OldCamera _camera;
|
||||||
|
|
||||||
|
public const String s_WindowTitle = "Scene";
|
||||||
|
|
||||||
|
private RenderTarget2D _renderTarget ~ _?.ReleaseRef();
|
||||||
|
|
||||||
|
public Event<EventHandler<Vector2>> ViewportSizeChangedEvent ~ _.Dispose();
|
||||||
|
|
||||||
|
public RenderTarget2D RenderTarget
|
||||||
|
{
|
||||||
|
get => _renderTarget;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if(_renderTarget == value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SetReference!(_renderTarget, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public this(Editor editor)
|
||||||
|
{
|
||||||
|
_editor = editor;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ImGui.Vec2 oldViewportSize;
|
||||||
|
private bool viewPortChanged;
|
||||||
|
|
||||||
|
public Entity CameraEntity { get; set; }
|
||||||
|
|
||||||
|
protected override void InternalShow()
|
||||||
|
{
|
||||||
|
ImGui.PushStyleVar(.WindowPadding, ImGui.Vec2(1, 1));
|
||||||
|
defer ImGui.PopStyleVar();
|
||||||
|
|
||||||
|
if(!ImGui.Begin(s_WindowTitle, &_open, .NoScrollbar))
|
||||||
|
{
|
||||||
|
ImGui.End();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ImGui.IsWindowHovered() && Input.IsMouseButtonPressing(.RightButton))
|
||||||
|
{
|
||||||
|
var currentWindow = ImGui.GetCurrentWindow();
|
||||||
|
ImGui.FocusWindow(currentWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
_hasFocus = ImGui.IsWindowFocused();
|
||||||
|
|
||||||
|
var viewportSize = ImGui.GetContentRegionAvail();
|
||||||
|
|
||||||
|
if(_renderTarget != null)
|
||||||
|
{
|
||||||
|
ImGui.Image(_renderTarget, viewportSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawImGuizmo(viewportSize);
|
||||||
|
|
||||||
|
ImGui.End();
|
||||||
|
|
||||||
|
if(oldViewportSize != viewportSize)
|
||||||
|
{
|
||||||
|
ViewportSizeChangedEvent.Invoke(this, (Vector2)viewportSize);
|
||||||
|
viewPortChanged = true;
|
||||||
|
oldViewportSize = viewportSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawImGuizmo(ImGui.Vec2 viewportSize)
|
||||||
|
{
|
||||||
|
ImGuizmo.SetDrawlist();
|
||||||
|
|
||||||
|
var topLeft = ImGui.GetWindowPos();
|
||||||
|
var cntMin = ImGui.GetWindowContentRegionMin();
|
||||||
|
|
||||||
|
topLeft.x += cntMin.x;
|
||||||
|
topLeft.y += cntMin.y;
|
||||||
|
ImGuizmo.SetRect(topLeft.x, topLeft.y, viewportSize.x, viewportSize.y);
|
||||||
|
|
||||||
|
var cameraTransformCmp = CameraEntity.GetComponent<TransformComponent>();
|
||||||
|
var view = cameraTransformCmp.WorldTransform.Invert();
|
||||||
|
|
||||||
|
var cameraCmp = CameraEntity.GetComponent<CameraComponent>();
|
||||||
|
var projection = cameraCmp.Camera.Projection;
|
||||||
|
|
||||||
|
Matrix mat = .Identity;
|
||||||
|
ImGuizmo.DrawGrid((.)&view, (.)&projection, (.)&mat, 10);
|
||||||
|
|
||||||
|
if(_editor.SelectedEntities.Count > 0)
|
||||||
|
{
|
||||||
|
var entity = _editor.SelectedEntities.Front;
|
||||||
|
|
||||||
|
var transformCmp = _editor.World.GetComponent<TransformComponent>(entity);
|
||||||
|
|
||||||
|
var transform = transformCmp.LocalTransform;
|
||||||
|
|
||||||
|
ImGuizmo.SetRect(topLeft.x, topLeft.y, viewportSize.x, viewportSize.y);
|
||||||
|
|
||||||
|
ImGuizmo.Manipulate((.)&view, (.)&projection, .TRANSLATE, .LOCAL, (.)&transform);
|
||||||
|
|
||||||
|
transformCmp.LocalTransform = transform;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
using GlitchyEngine.World;
|
||||||
|
using ImGui;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using GlitchyEngine.Collections;
|
||||||
|
using GlitchyEditor.EditWindows;
|
||||||
|
using GlitchyEngineHelper;
|
||||||
|
using System.IO;
|
||||||
|
using GlitchyEngineHelper.DotNet;
|
||||||
|
|
||||||
|
namespace GlitchyEditor
|
||||||
|
{
|
||||||
|
class Editor
|
||||||
|
{
|
||||||
|
private EcsWorld _ecsWorld;
|
||||||
|
private Scene _scene;
|
||||||
|
|
||||||
|
private EntityHierarchyWindow _entityHierarchyWindow ~ delete _;
|
||||||
|
private ComponentEditWindow _componentEditWindow ~ delete _;
|
||||||
|
private SceneViewportWindow _sceneViewportWindow = new .(this) ~ delete _;
|
||||||
|
|
||||||
|
private List<EcsEntity> _selectedEntities = new .() ~ delete _;
|
||||||
|
|
||||||
|
public EcsWorld World => _ecsWorld;
|
||||||
|
|
||||||
|
public List<EcsEntity> SelectedEntities => _selectedEntities;
|
||||||
|
|
||||||
|
public EntityHierarchyWindow EntityHierarchyWindow => _entityHierarchyWindow;
|
||||||
|
public ComponentEditWindow ComponentEditWindow => _componentEditWindow;
|
||||||
|
public SceneViewportWindow SceneViewportWindow => _sceneViewportWindow;
|
||||||
|
|
||||||
|
/// Creates a new editor for the given world
|
||||||
|
public this(Scene scene)
|
||||||
|
{
|
||||||
|
String exePath = Environment.GetExecutableFilePath(.. scope String());
|
||||||
|
|
||||||
|
String exeDir = Path.GetDirectoryPath(exePath, .. scope String());
|
||||||
|
|
||||||
|
String assemblyPath = scope String(exeDir, "/DotNetScriptingHelper.dll");
|
||||||
|
|
||||||
|
DotNetContext dotty = new DotNetContext(assemblyPath);
|
||||||
|
defer delete dotty;
|
||||||
|
|
||||||
|
dotty.Init();
|
||||||
|
|
||||||
|
dotty.GetFunctionPointerUnmanagedCallersOnly("DotNetScriptingHelper.ScriptableEntity, DotNetScriptingHelper", "CreateInstance", out DotNetScriptComponent.CreateInstanceFn);
|
||||||
|
dotty.GetFunctionPointerUnmanagedCallersOnly("DotNetScriptingHelper.ScriptableEntity, DotNetScriptingHelper", "UpdateEntity", out DotNetScriptComponent.UpdateInstanceFn);
|
||||||
|
dotty.GetFunctionPointerUnmanagedCallersOnly("DotNetScriptingHelper.ScriptableEntity, DotNetScriptingHelper", "DestroyEntity", out DotNetScriptComponent.DestroyInstanceFn);
|
||||||
|
|
||||||
|
_scene = scene;
|
||||||
|
_ecsWorld = _scene.[Friend]_ecsWorld;
|
||||||
|
|
||||||
|
_entityHierarchyWindow = new EntityHierarchyWindow(_scene);
|
||||||
|
_componentEditWindow = new ComponentEditWindow(_entityHierarchyWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update()
|
||||||
|
{
|
||||||
|
_entityHierarchyWindow.Show();
|
||||||
|
_componentEditWindow.Show();
|
||||||
|
_sceneViewportWindow.Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new entity with a transform component.
|
||||||
|
internal EcsEntity CreateEntityWithTransform()
|
||||||
|
{
|
||||||
|
var entity = _ecsWorld.NewEntity();
|
||||||
|
|
||||||
|
var transformComponent = ref *_ecsWorld.AssignComponent<TransformComponent>(entity);
|
||||||
|
transformComponent = TransformComponent();
|
||||||
|
|
||||||
|
var nameComponent = ref *_ecsWorld.AssignComponent<DebugNameComponent>(entity);
|
||||||
|
nameComponent.SetName("Entity");
|
||||||
|
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Returns whether or not all selected entities have the same parent.
|
||||||
|
internal bool AllSelectionsOnSameLevel()
|
||||||
|
{
|
||||||
|
EcsEntity? parent = .InvalidEntity;
|
||||||
|
|
||||||
|
for(var selectedEntity in _selectedEntities)
|
||||||
|
{
|
||||||
|
var parentComponent = _ecsWorld.GetComponent<ParentComponent>(selectedEntity);
|
||||||
|
|
||||||
|
if(parent == .InvalidEntity)
|
||||||
|
{
|
||||||
|
parent = parentComponent?.Entity;
|
||||||
|
}
|
||||||
|
else if(parentComponent?.Entity != parent)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Finds all children of the given entity and stores their IDs in the given list.
|
||||||
|
internal void FindChildren(EcsEntity entity, List<EcsEntity> entities)
|
||||||
|
{
|
||||||
|
for(var (child, childParent) in _ecsWorld.Enumerate<ParentComponent>())
|
||||||
|
{
|
||||||
|
if(childParent.Entity == entity)
|
||||||
|
{
|
||||||
|
if(!entities.Contains(child))
|
||||||
|
entities.Add(child);
|
||||||
|
|
||||||
|
FindChildren(child, entities);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deletes all selected entities and their children.
|
||||||
|
internal void DeleteSelectedEntities()
|
||||||
|
{
|
||||||
|
List<EcsEntity> entities = scope .();
|
||||||
|
|
||||||
|
for(var entity in _selectedEntities)
|
||||||
|
{
|
||||||
|
entities.Add(entity);
|
||||||
|
|
||||||
|
FindChildren(entity, entities);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(var entity in entities)
|
||||||
|
{
|
||||||
|
_ecsWorld.RemoveEntity(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
_selectedEntities.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
using System;
|
||||||
|
using GlitchyEngine;
|
||||||
|
|
||||||
|
namespace GlitchyEditor
|
||||||
|
{
|
||||||
|
class EditorApp : Application
|
||||||
|
{
|
||||||
|
public this()
|
||||||
|
{
|
||||||
|
PushLayer(new EditorLayer());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Export, LinkName("CreateApplication")]
|
||||||
|
public static Application CreateApplication()
|
||||||
|
{
|
||||||
|
return new EditorApp();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
using GlitchyEngine;
|
||||||
|
using GlitchyEngine.Math;
|
||||||
|
using GlitchyEngine.World;
|
||||||
|
|
||||||
|
namespace GlitchyEditor
|
||||||
|
{
|
||||||
|
class EditorCameraController : ScriptableEntity
|
||||||
|
{
|
||||||
|
private float _cameraTranslationSpeed = 2.0f;
|
||||||
|
private float _cameraRotationSpeedX = 0.001f;
|
||||||
|
private float _cameraRotationSpeedY = 0.001f;
|
||||||
|
|
||||||
|
public bool IsEnabled = false;
|
||||||
|
|
||||||
|
protected override void OnUpdate(GameTime gt)
|
||||||
|
{
|
||||||
|
if (!IsEnabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Debug.Profiler.ProfileFunction!();
|
||||||
|
|
||||||
|
Vector3 movement = .();
|
||||||
|
|
||||||
|
if(Input.IsKeyPressed(Key.W))
|
||||||
|
movement.Z += 1;
|
||||||
|
if(Input.IsKeyPressed(Key.S))
|
||||||
|
movement.Z -= 1;
|
||||||
|
|
||||||
|
if(Input.IsKeyPressed(Key.A))
|
||||||
|
movement.X -= 1;
|
||||||
|
if(Input.IsKeyPressed(Key.D))
|
||||||
|
movement.X += 1;
|
||||||
|
|
||||||
|
if(Input.IsKeyPressed(Key.Space))
|
||||||
|
movement.Y += 1;
|
||||||
|
if(Input.IsKeyPressed(Key.Control))
|
||||||
|
movement.Y -= 1;
|
||||||
|
|
||||||
|
var transformComponent = transform;
|
||||||
|
|
||||||
|
if(movement != .Zero)
|
||||||
|
{
|
||||||
|
movement.Normalize();
|
||||||
|
|
||||||
|
movement *= (float)(gt.FrameTime.TotalSeconds) * _cameraTranslationSpeed;
|
||||||
|
|
||||||
|
Matrix view = transformComponent.WorldTransform.Invert();
|
||||||
|
|
||||||
|
Vector4 delta = Vector4(movement, 1.0f) * view;
|
||||||
|
|
||||||
|
transformComponent.Position = transformComponent.Position + delta.XYZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Camera rotation
|
||||||
|
var mouseDelta = Input.GetMouseMovement();
|
||||||
|
|
||||||
|
float rotY = mouseDelta.X * _cameraRotationSpeedX;
|
||||||
|
float rotX = mouseDelta.Y * _cameraRotationSpeedY;
|
||||||
|
|
||||||
|
transformComponent.RotationEuler = transformComponent.RotationEuler + .(rotX, rotY, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,270 @@
|
|||||||
|
using System;
|
||||||
|
using ImGui;
|
||||||
|
using GlitchyEngine;
|
||||||
|
using GlitchyEditor.EditWindows;
|
||||||
|
using GlitchyEngine.Events;
|
||||||
|
using GlitchyEngine.ImGui;
|
||||||
|
using GlitchyEngine.Math;
|
||||||
|
using GlitchyEngine.Renderer;
|
||||||
|
using GlitchyEngine.World;
|
||||||
|
|
||||||
|
namespace GlitchyEditor
|
||||||
|
{
|
||||||
|
class EditorLayer : Layer
|
||||||
|
{
|
||||||
|
RasterizerState _rasterizerState ~ _?.ReleaseRef();
|
||||||
|
RasterizerState _rasterizerStateClockWise ~ _?.ReleaseRef();
|
||||||
|
|
||||||
|
GraphicsContext _context ~ _.ReleaseRef();
|
||||||
|
|
||||||
|
BlendState _alphaBlendState ~ _.ReleaseRef();
|
||||||
|
BlendState _opaqueBlendState ~ _.ReleaseRef();
|
||||||
|
DepthStencilState _depthStencilState ~ _.ReleaseRef();
|
||||||
|
|
||||||
|
Scene _scene = new Scene() ~ delete _;
|
||||||
|
|
||||||
|
Editor _editor ~ delete _;
|
||||||
|
|
||||||
|
RenderTarget2D _viewportTarget ~ _?.ReleaseRef();
|
||||||
|
|
||||||
|
SettingsWindow _settingsWindow = new .() ~ delete _;
|
||||||
|
|
||||||
|
Entity _cameraEntity;
|
||||||
|
Entity _otherCameraEntity;
|
||||||
|
|
||||||
|
class CameraController : ScriptableEntity
|
||||||
|
{
|
||||||
|
protected override void OnCreate()
|
||||||
|
{
|
||||||
|
Log.EngineLogger.Trace("Cam controller created!");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnUpdate(GameTime gameTime)
|
||||||
|
{
|
||||||
|
var transformCmp = GetComponent<TransformComponent>();
|
||||||
|
|
||||||
|
Vector3 position = transformCmp.Position;
|
||||||
|
|
||||||
|
if (Input.IsKeyPressed(Key.A))
|
||||||
|
{
|
||||||
|
position.X -= gameTime.DeltaTime;
|
||||||
|
}
|
||||||
|
if (Input.IsKeyPressed(Key.D))
|
||||||
|
{
|
||||||
|
position.X += gameTime.DeltaTime;
|
||||||
|
}
|
||||||
|
if (Input.IsKeyPressed(Key.W))
|
||||||
|
{
|
||||||
|
position.Y += gameTime.DeltaTime;
|
||||||
|
}
|
||||||
|
if (Input.IsKeyPressed(Key.S))
|
||||||
|
{
|
||||||
|
position.Y -= gameTime.DeltaTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
transformCmp.Position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnDestroy()
|
||||||
|
{
|
||||||
|
Log.EngineLogger.Trace("Cam controller destroyed!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public this() : base("Example")
|
||||||
|
{
|
||||||
|
Application.Get().Window.IsVSync = false;
|
||||||
|
|
||||||
|
InitGraphics();
|
||||||
|
|
||||||
|
{
|
||||||
|
_cameraEntity = _scene.CreateEntity("Camera Entity");
|
||||||
|
let camera = _cameraEntity.AddComponent<CameraComponent>();
|
||||||
|
camera.Camera.SetPerspective(MathHelper.ToRadians(75), 0.1f, 10000.0f);
|
||||||
|
camera.Primary = true;
|
||||||
|
camera.FixedAspectRatio = false;
|
||||||
|
let transform = _cameraEntity.GetComponent<TransformComponent>();
|
||||||
|
transform.Position = .(0, 0, -5);
|
||||||
|
|
||||||
|
_cameraEntity.AddComponent<NativeScriptComponent>().Bind<EditorCameraController>();
|
||||||
|
_cameraEntity.AddComponent<EditorComponent>();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
_otherCameraEntity = _scene.CreateEntity("Other Camera Entity");
|
||||||
|
let camera = _otherCameraEntity.AddComponent<CameraComponent>();
|
||||||
|
camera.Camera.SetPerspective(MathHelper.ToRadians(45), 0.1f, 1000.0f);
|
||||||
|
camera.Primary = false;
|
||||||
|
camera.FixedAspectRatio = false;
|
||||||
|
let transform = _otherCameraEntity.GetComponent<TransformComponent>();
|
||||||
|
transform.Position = .(0, 0, -5);
|
||||||
|
|
||||||
|
_otherCameraEntity.AddComponent<NativeScriptComponent>().Bind<EditorCameraController>();
|
||||||
|
_otherCameraEntity.AddComponent<EditorComponent>();
|
||||||
|
}
|
||||||
|
|
||||||
|
InitEditor();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitGraphics()
|
||||||
|
{
|
||||||
|
_context = Application.Get().Window.Context..AddRef();
|
||||||
|
|
||||||
|
RasterizerStateDescription rsDesc = .(.Solid, .Back, true);
|
||||||
|
_rasterizerState = new RasterizerState(rsDesc);
|
||||||
|
|
||||||
|
rsDesc.FrontCounterClockwise = false;
|
||||||
|
_rasterizerStateClockWise = new RasterizerState(rsDesc);
|
||||||
|
|
||||||
|
BlendStateDescription blendDesc = .();
|
||||||
|
blendDesc.RenderTarget[0] = .(true, .SourceAlpha, .InvertedSourceAlpha, .Add, .SourceAlpha, .InvertedSourceAlpha, .Add, .All);
|
||||||
|
_alphaBlendState = new BlendState(blendDesc);
|
||||||
|
_opaqueBlendState = new BlendState(.Default);
|
||||||
|
|
||||||
|
DepthStencilStateDescription dsDesc = .();
|
||||||
|
_depthStencilState = new DepthStencilState(dsDesc);
|
||||||
|
|
||||||
|
_viewportTarget = new RenderTarget2D(RenderTarget2DDescription(.R8G8B8A8_UNorm, 100, 100) {DepthStencilFormat = .D32_Float});
|
||||||
|
_viewportTarget.SamplerState = SamplerStateManager.LinearClamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitEditor()
|
||||||
|
{
|
||||||
|
_editor = new Editor(_scene);
|
||||||
|
_editor.SceneViewportWindow.ViewportSizeChangedEvent.Add(new (s, e) => ViewportSizeChanged(s, e));
|
||||||
|
|
||||||
|
//_editor.[Friend]CreateEntityWithTransform();
|
||||||
|
|
||||||
|
_editor.SceneViewportWindow.CameraEntity = _cameraEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update(GameTime gameTime)
|
||||||
|
{
|
||||||
|
var scriptComponent = _cameraEntity.GetComponent<NativeScriptComponent>();
|
||||||
|
|
||||||
|
if (var camController = scriptComponent.Instance as EditorCameraController)
|
||||||
|
{
|
||||||
|
camController.IsEnabled = (_editor.SceneViewportWindow.HasFocus && Input.IsMouseButtonPressed(.RightButton));
|
||||||
|
}
|
||||||
|
|
||||||
|
//TransformSystem.Update(_world);
|
||||||
|
|
||||||
|
RenderCommand.Clear(_viewportTarget, .Color | .Depth, .(0.2f, 0.2f, 0.2f), 1.0f, 0);
|
||||||
|
|
||||||
|
RenderCommand.SetRenderTarget(_viewportTarget, 0, true);
|
||||||
|
RenderCommand.BindRenderTargets();
|
||||||
|
|
||||||
|
RenderCommand.SetViewport(Viewport(0, 0, _viewportTarget.Width, _viewportTarget.Height));
|
||||||
|
|
||||||
|
RenderCommand.SetBlendState(_alphaBlendState);
|
||||||
|
RenderCommand.SetDepthStencilState(_depthStencilState);
|
||||||
|
|
||||||
|
//Renderer.BeginScene(_cameraController.Camera);
|
||||||
|
|
||||||
|
//DebugRenderer.Render(_scene.[Friend]_ecsWorld);
|
||||||
|
|
||||||
|
//Renderer.EndScene();
|
||||||
|
|
||||||
|
_scene.Update(gameTime);
|
||||||
|
|
||||||
|
RenderCommand.Clear(null, .Color | .Depth, .(0.2f, 0.2f, 0.2f), 1.0f, 0);
|
||||||
|
|
||||||
|
RenderCommand.SetRenderTarget(null, 0, true);
|
||||||
|
RenderCommand.BindRenderTargets();
|
||||||
|
|
||||||
|
RenderCommand.SetViewport(_context.SwapChain.BackbufferViewport);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnEvent(Event event)
|
||||||
|
{
|
||||||
|
EventDispatcher dispatcher = EventDispatcher(event);
|
||||||
|
|
||||||
|
dispatcher.Dispatch<ImGuiRenderEvent>(scope (e) => OnImGuiRender(e));
|
||||||
|
dispatcher.Dispatch<WindowResizeEvent>(scope (e) => OnWindowResize(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.ID _mainDockspaceId;
|
||||||
|
|
||||||
|
private bool OnImGuiRender(ImGuiRenderEvent event)
|
||||||
|
{
|
||||||
|
ImGui.Begin("Test");
|
||||||
|
|
||||||
|
static bool cameraA = true;
|
||||||
|
|
||||||
|
if (ImGui.Checkbox("Camera A", &cameraA))
|
||||||
|
{
|
||||||
|
_cameraEntity.GetComponent<CameraComponent>().Primary = cameraA;
|
||||||
|
_otherCameraEntity.GetComponent<CameraComponent>().Primary = !cameraA;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.End();
|
||||||
|
|
||||||
|
ImGui.Viewport* viewport = ImGui.GetMainViewport();
|
||||||
|
ImGui.DockSpaceOverViewport(viewport);
|
||||||
|
|
||||||
|
DrawMainMenuBar();
|
||||||
|
|
||||||
|
_editor.SceneViewportWindow.RenderTarget = _viewportTarget;
|
||||||
|
|
||||||
|
_editor.Update();
|
||||||
|
|
||||||
|
_settingsWindow.Show();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawMainMenuBar()
|
||||||
|
{
|
||||||
|
ImGui.BeginMainMenuBar();
|
||||||
|
|
||||||
|
if(ImGui.BeginMenu("File", true))
|
||||||
|
{
|
||||||
|
if (ImGui.MenuItem("Settings"))
|
||||||
|
_settingsWindow.Open = true;
|
||||||
|
|
||||||
|
ImGui.EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ImGui.BeginMenu("View", true))
|
||||||
|
{
|
||||||
|
if(ImGui.MenuItem(EntityHierarchyWindow.s_WindowTitle))
|
||||||
|
{
|
||||||
|
_editor.EntityHierarchyWindow.Open = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ImGui.MenuItem(ComponentEditWindow.s_WindowTitle))
|
||||||
|
{
|
||||||
|
_editor.ComponentEditWindow.Open = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ImGui.MenuItem(SceneViewportWindow.s_WindowTitle))
|
||||||
|
{
|
||||||
|
_editor.SceneViewportWindow.Open = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ImGui.EndMainMenuBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool OnWindowResize(WindowResizeEvent e)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ViewportSizeChanged(Object sender, Vector2 viewportSize)
|
||||||
|
{
|
||||||
|
uint32 sizeX = (uint32)viewportSize.X;
|
||||||
|
uint32 sizeY = (uint32)viewportSize.Y;
|
||||||
|
|
||||||
|
if(sizeX == 0 || sizeY == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_viewportTarget.Resize(sizeX, sizeY);
|
||||||
|
|
||||||
|
_scene.OnViewportResize(sizeX, sizeY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,253 @@
|
|||||||
|
using GlitchyEditor.EditWindows;
|
||||||
|
using ImGui;
|
||||||
|
using GlitchyEngine;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace GlitchyEditor
|
||||||
|
{
|
||||||
|
class SettingsWindow : EditorWindow
|
||||||
|
{
|
||||||
|
class Binding
|
||||||
|
{
|
||||||
|
public Object SettingsObject;
|
||||||
|
public String Name ~ delete _;
|
||||||
|
public String FieldName ~ delete _;
|
||||||
|
|
||||||
|
public this(StringView name, StringView fieldName, Object settingsObject)
|
||||||
|
{
|
||||||
|
Name = new String(name);
|
||||||
|
FieldName = new String(fieldName);
|
||||||
|
SettingsObject = settingsObject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Category
|
||||||
|
{
|
||||||
|
public List<Binding> _bindings = new .() ~ DeleteContainerAndItems!(_);
|
||||||
|
|
||||||
|
public String Header ~ delete _;
|
||||||
|
|
||||||
|
public Object SettingsObject;
|
||||||
|
|
||||||
|
public this(String header)
|
||||||
|
{
|
||||||
|
Header = new String(header);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddSetting(StringView name, StringView fieldName, Object settingsObject = null)
|
||||||
|
{
|
||||||
|
Binding binding = new .(name, fieldName, settingsObject ?? SettingsObject);
|
||||||
|
_bindings.Add(binding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Settings _settings;
|
||||||
|
|
||||||
|
bool _settingsChanged = false;
|
||||||
|
|
||||||
|
private Dictionary<String, Category> _categories = new .() ~ DeleteDictionaryAndValues!(_);
|
||||||
|
|
||||||
|
public this()
|
||||||
|
{
|
||||||
|
_open = false;
|
||||||
|
|
||||||
|
_settings = Application.Get().Settings;
|
||||||
|
|
||||||
|
Create();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Create()
|
||||||
|
{
|
||||||
|
ScanForSettings(_settings);
|
||||||
|
|
||||||
|
/*for (ISettings settings in _settings.[Friend]_userSettings)
|
||||||
|
{
|
||||||
|
ScanForSettings(settings);
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
Category AddCategory(String header)
|
||||||
|
{
|
||||||
|
if (_categories.TryGetValue(header, let category))
|
||||||
|
return category;
|
||||||
|
|
||||||
|
Category newCat = new Category(header);
|
||||||
|
_categories.Add(newCat.Header, newCat);
|
||||||
|
|
||||||
|
return newCat;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScanForSettings(Object container)
|
||||||
|
{
|
||||||
|
Type type = container.GetType();
|
||||||
|
|
||||||
|
for (var field in type.GetFields())
|
||||||
|
{
|
||||||
|
Result<SettingAttribute> settingResult = field.GetCustomAttribute<SettingAttribute>();
|
||||||
|
|
||||||
|
if (settingResult case .Ok(let settingInfo))
|
||||||
|
{
|
||||||
|
AddSetting(settingInfo.Category, settingInfo.Name, field.Name, container);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<SettingContainerAttribute> containerResult = field.GetCustomAttribute<SettingContainerAttribute>();
|
||||||
|
|
||||||
|
if (containerResult case .Ok(let containerInfo))
|
||||||
|
{
|
||||||
|
var res = field.GetValue<Object>(container, let childContainer);
|
||||||
|
|
||||||
|
if (res case .Err(let error))
|
||||||
|
{
|
||||||
|
Log.EngineLogger.Error($"Failed to get settings container. Error: {error}");
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScanForSettings(childContainer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddSetting(String categoryName, String name, StringView fieldName, Object container)
|
||||||
|
{
|
||||||
|
Category category = AddCategory(categoryName);
|
||||||
|
|
||||||
|
category.AddSetting(name, fieldName, container);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void InternalShow()
|
||||||
|
{
|
||||||
|
ImGui.Begin("Settings", &_open, .NoDocking);
|
||||||
|
defer ImGui.End();
|
||||||
|
|
||||||
|
// Leave room for 1 line below us
|
||||||
|
ImGui.BeginChild("item view", ImGui.Vec2(0, -ImGui.GetFrameHeightWithSpacing()));
|
||||||
|
|
||||||
|
ImGui.BeginTabBar("##Tabs");
|
||||||
|
|
||||||
|
for (Category category in _categories.Values)
|
||||||
|
{
|
||||||
|
if (ImGui.BeginTabItem(category.Header))
|
||||||
|
{
|
||||||
|
ImGui.Columns(2);
|
||||||
|
defer ImGui.Columns(1);
|
||||||
|
ImGui.SetColumnWidth(0, 100);
|
||||||
|
|
||||||
|
for (Binding setting in category._bindings)
|
||||||
|
{
|
||||||
|
ImGui.TextUnformatted(setting.Name);
|
||||||
|
|
||||||
|
ImGui.NextColumn();
|
||||||
|
|
||||||
|
Type settingsObjectType = setting.SettingsObject.GetType();
|
||||||
|
|
||||||
|
Result<FieldInfo> result = settingsObjectType.GetField(setting.FieldName);
|
||||||
|
|
||||||
|
if (result case .Err)
|
||||||
|
{
|
||||||
|
ImGui.PushStyleColor(.Text, ImGui.Vec4(1f, 0f, 0f, 1f));
|
||||||
|
ImGui.Text($"Field {setting.FieldName} not found.");
|
||||||
|
ImGui.PopStyleColor();
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
FieldInfo fieldInfo = result.Get();
|
||||||
|
|
||||||
|
Type fieldType = fieldInfo.FieldType;
|
||||||
|
|
||||||
|
mixin GetSettingValue<T>()
|
||||||
|
{
|
||||||
|
var error = fieldInfo.GetValue<T>(setting.SettingsObject, var value);
|
||||||
|
|
||||||
|
if (error case .Err(let err))
|
||||||
|
{
|
||||||
|
Log.EngineLogger.Error($"Could not get value of setting {setting.FieldName}. Error: {err}");
|
||||||
|
|
||||||
|
ImGui.PushStyleColor(.Text, ImGui.Vec4(1f, 0f, 0f, 1f));
|
||||||
|
ImGui.Text($"Could not get value of setting {setting.FieldName}. Error: {err}");
|
||||||
|
ImGui.PopStyleColor();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
value
|
||||||
|
}
|
||||||
|
|
||||||
|
mixin SetSettingValue<T>(T value)
|
||||||
|
{
|
||||||
|
var error = fieldInfo.SetValue(setting.SettingsObject, value);
|
||||||
|
|
||||||
|
if (error case .Err(let err))
|
||||||
|
{
|
||||||
|
Log.EngineLogger.Error($"Could not set value of setting {setting.FieldName}. Error: {err}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (fieldType)
|
||||||
|
{
|
||||||
|
case typeof(int32):
|
||||||
|
int32 value = GetSettingValue!<int32>();
|
||||||
|
|
||||||
|
if (!ImGui.InputInt(scope $"##{setting.Name}", &value))
|
||||||
|
break;
|
||||||
|
|
||||||
|
SetSettingValue!(value);
|
||||||
|
|
||||||
|
_settingsChanged = true;
|
||||||
|
case typeof(String):
|
||||||
|
String value = GetSettingValue!<String>();
|
||||||
|
|
||||||
|
char8[256] buffer = .();
|
||||||
|
|
||||||
|
value.CopyTo(buffer);
|
||||||
|
|
||||||
|
if (ImGui.InputText(scope $"##{setting.Name}", &buffer, buffer.Count))
|
||||||
|
{
|
||||||
|
value..Clear().Append(&buffer);
|
||||||
|
|
||||||
|
_settingsChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.NextColumn();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndTabItem();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndTabBar();
|
||||||
|
|
||||||
|
ImGui.EndChild();
|
||||||
|
|
||||||
|
ImGui.BeginDisabled(!_settingsChanged);
|
||||||
|
|
||||||
|
if (ImGui.Button("Save"))
|
||||||
|
{
|
||||||
|
_settings.Save();
|
||||||
|
_settings.Apply();
|
||||||
|
_open = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
|
||||||
|
if (ImGui.Button("Apply"))
|
||||||
|
{
|
||||||
|
_settings.Apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndDisabled();
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
|
||||||
|
if (ImGui.Button("Cancel"))
|
||||||
|
{
|
||||||
|
Settings.Load();
|
||||||
|
_open = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
FileVersion = 1
|
||||||
|
Dependencies = {corlib = "*", GlitchyEngine = "*"}
|
||||||
|
|
||||||
|
[Project]
|
||||||
|
Name = "GlitchyEngine.Test"
|
||||||
|
TargetType = "BeefTest"
|
||||||
|
StartupObject = "GlitchyEngine.Test.Program"
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
FileVersion = 1
|
||||||
|
Projects = {"GlitchyEngine.Test" = {Path = "."}, GlitchyEngine = {Path = "../GlitchyEngine"}, GlitchLog = {Path = "../GlitchLog"}, DirectX = {Path = "../GlitchyEngine/vendor/directx/DirectX"}, ImGui = {Path = "../GlitchyEngine/vendor/imgui-beef/ImGui"}, ImGuiImplWin32 = {Path = "../GlitchyEngine/vendor/imgui-beef/ImGuiImplWin32"}, ImGuiImplDX11 = {Path = "../GlitchyEngine/vendor/imgui-beef/ImGuiImplDX11"}, DirectXTK = {Path = "../GlitchyEngine/vendor/DirectXTK/DirectXTK-beef"}, FreeType = {Path = "../GlitchyEngine/vendor/freetype"}, cgltf-beef = {Path = "../GlitchyEngine/vendor/gltf/cgltf-beef"}}
|
||||||
|
|
||||||
|
[Workspace]
|
||||||
|
StartupProject = "GlitchyEngine.Test"
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
using System;
|
||||||
|
using GlitchyEngine.Math;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Test.Math
|
||||||
|
{
|
||||||
|
static class MathHelperTest
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public static void TestDegToRad()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
float deg = 0;
|
||||||
|
float rad = MathHelper.ToRadians(deg);
|
||||||
|
Test.Assert(rad == 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
float deg = 45;
|
||||||
|
float rad = MathHelper.ToRadians(deg);
|
||||||
|
Test.Assert(rad == MathHelper.PiOverFour);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
float deg = 180;
|
||||||
|
float rad = MathHelper.ToRadians(deg);
|
||||||
|
Test.Assert(rad == MathHelper.Pi);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
float deg = -360;
|
||||||
|
float rad = MathHelper.ToRadians(deg);
|
||||||
|
Test.Assert(rad == -MathHelper.TwoPi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public static void TestRadToDeg()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
float rad = 0;
|
||||||
|
float deg = MathHelper.ToDegrees(rad);
|
||||||
|
Test.Assert(deg == 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
float rad = MathHelper.PiOverFour;
|
||||||
|
float deg = MathHelper.ToDegrees(rad);
|
||||||
|
Test.Assert(deg == 45);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
float rad = MathHelper.Pi;
|
||||||
|
float deg = MathHelper.ToDegrees(rad);
|
||||||
|
Test.Assert(deg == 180);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
float rad = -MathHelper.TwoPi;
|
||||||
|
float deg = MathHelper.ToDegrees(rad);
|
||||||
|
Test.Assert(deg == -360);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,199 @@
|
|||||||
|
using System;
|
||||||
|
using GlitchyEngine.Math;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Test.Math
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @Note Testing 180° Angles is quite stupid as 180° = -180° and thus the result is quite dependant of floating point precision...
|
||||||
|
*/
|
||||||
|
static class QuaternionTest
|
||||||
|
{
|
||||||
|
static bool QuatEquals(Quaternion q1, Quaternion q2, float delta = 0.0001f)
|
||||||
|
{
|
||||||
|
return Math.Abs(q1.X - q2.X) < delta && Math.Abs(q1.Y - q2.Y) < delta &&
|
||||||
|
Math.Abs(q1.Z - q2.Z) < delta && Math.Abs(q1.W - q2.W) < delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool Vector3Equals(Vector3 v1, Vector3 v2, float delta = 0.0001f)
|
||||||
|
{
|
||||||
|
return Math.Abs(v1.X - v2.X) < delta && Math.Abs(v1.Y - v2.Y) < delta &&
|
||||||
|
Math.Abs(v1.Z - v2.Z) < delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool FloatEquals(float l, float r, float delta = 0.0001f)
|
||||||
|
{
|
||||||
|
return Math.Abs(l - r) < delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public static void TestAxisAngleToQuaternion()
|
||||||
|
{
|
||||||
|
// angle in degrees
|
||||||
|
void Test(Vector3 axis, float angle, Quaternion expectedQuat)
|
||||||
|
{
|
||||||
|
float angleRad = MathHelper.ToRadians(angle);
|
||||||
|
Quaternion result = .FromAxisAngle(axis, angleRad);
|
||||||
|
|
||||||
|
Quaternion resultNormalized = .Normalize(result);
|
||||||
|
Quaternion expectedNormalized = .Normalize(expectedQuat);
|
||||||
|
|
||||||
|
Test.Assert(QuatEquals(resultNormalized, expectedNormalized));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reference for conversions: https://www.andre-gaschler.com/rotationconverter/
|
||||||
|
|
||||||
|
Test(.(0, 0, 0), 55, Quaternion.Identity);
|
||||||
|
|
||||||
|
// x: 90°
|
||||||
|
Test(.(1, 0, 0), 90, Quaternion(1, 0, 0, 1));
|
||||||
|
// y: 90°
|
||||||
|
Test(.(0, 1, 0), 90, Quaternion(0, 1, 0, 1));
|
||||||
|
// z: 90°
|
||||||
|
Test(.(0, 0, 1), 90, Quaternion(0, 0, 1, 1));
|
||||||
|
|
||||||
|
Test(.(1, 1, 0), 90, Quaternion(0.5f, 0.5f, 0, 0.707107f));
|
||||||
|
|
||||||
|
Test(.(1, 1, 1), 90, Quaternion(0.4082483f, 0.4082483f, 0.4082483f, 0.7071068f));
|
||||||
|
|
||||||
|
Test(.(0.3f, 0.5f, 0.4f), -25, Quaternion(-0.0918276f, -0.1530459f, -0.1224367f, 0.976296f));
|
||||||
|
|
||||||
|
Test(.(0.3f, -0.5f, 0.4f), -25, Quaternion(-0.0918276f, 0.1530459f, -0.1224367f, 0.976296f));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public static void TestQuaternionToAxisAngle()
|
||||||
|
{
|
||||||
|
// angle in degrees
|
||||||
|
void Test(Quaternion quat, Vector3 expectedAxis, float expectedAngle)
|
||||||
|
{
|
||||||
|
Quaternion quatNrm = .Normalize(quat);
|
||||||
|
(Vector3 resultAxis, float resultAngle) = quatNrm.ToAxisAngle();
|
||||||
|
|
||||||
|
resultAxis.Normalize();
|
||||||
|
resultAngle = MathHelper.ToDegrees(resultAngle);
|
||||||
|
|
||||||
|
Vector3 nrmExpectedAxis = .Normalize(expectedAxis);
|
||||||
|
|
||||||
|
Test.Assert(Vector3Equals(resultAxis, nrmExpectedAxis) && FloatEquals(expectedAngle, resultAngle));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reference for conversions: https://www.andre-gaschler.com/rotationconverter/
|
||||||
|
|
||||||
|
Test(Quaternion.Identity, .(0, 0, 0), 0);
|
||||||
|
|
||||||
|
// x: 90°
|
||||||
|
Test(Quaternion(1, 0, 0, 1), .(1, 0, 0), 90);
|
||||||
|
// y: 90°
|
||||||
|
Test(Quaternion(0, 1, 0, 1), .(0, 1, 0), 90);
|
||||||
|
// z: 90°
|
||||||
|
Test(Quaternion(0, 0, 1, 1), .(0, 0, 1), 90);
|
||||||
|
|
||||||
|
Test(Quaternion(0.5f, 0.5f, 0, 0.707107f), .(1, 1, 0), 90);
|
||||||
|
|
||||||
|
Test(Quaternion(0.4082483f, 0.4082483f, 0.4082483f, 0.7071068f), .(1, 1, 1), 90);
|
||||||
|
|
||||||
|
Test(Quaternion(-0.0918276f, -0.1530459f, -0.1224367f, 0.976296f), .(-0.4242643f, -0.7071067f, -0.5656853f), 24.9999988f);
|
||||||
|
Test(Quaternion(-0.0918276f, 0.1530459f, -0.1224367f, 0.976296f), .(-0.4242643f, 0.7071067f, -0.5656853f), 24.9999988f);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public static void TestEulerToQuaternion()
|
||||||
|
{
|
||||||
|
void Test(Vector3 inEuler, Quaternion expectedQuat)
|
||||||
|
{
|
||||||
|
Quaternion result = .FromEulerAngles(MathHelper.ToRadians(inEuler.Y), MathHelper.ToRadians(inEuler.X), MathHelper.ToRadians(inEuler.Z));
|
||||||
|
|
||||||
|
Test.Assert(QuatEquals(result, expectedQuat));
|
||||||
|
}
|
||||||
|
|
||||||
|
Test(Vector3.Zero, Quaternion.Identity);
|
||||||
|
|
||||||
|
// X: 90°
|
||||||
|
Test(.(90, 0, 0), Quaternion(1, 0, 0, 1)..Normalize());
|
||||||
|
|
||||||
|
// Y: 90°
|
||||||
|
Test(.(0, 90, 0), Quaternion(0, 1, 0, 1)..Normalize());
|
||||||
|
|
||||||
|
// Z: 90°
|
||||||
|
Test(.(0, 0, 90), Quaternion(0, 0, 1, 1)..Normalize());
|
||||||
|
|
||||||
|
// X: 90° Y: 90°
|
||||||
|
Test(.(90, 90, 0), Quaternion(1, 1, -1, 1)..Normalize());
|
||||||
|
|
||||||
|
// 90° 45° 30°
|
||||||
|
Test(.(90, 45, 30), Quaternion(0.7010574f, 0.4304593f, -0.092296f, 0.5609855f)..Normalize());
|
||||||
|
|
||||||
|
// 105° 90° 0°
|
||||||
|
Test(.(105, 90, 0), Quaternion(0.560986f, 0.430459f, -0.560986f, 0.430459f)..Normalize());
|
||||||
|
|
||||||
|
// 180° 90° -75°
|
||||||
|
Test(.(180, 90, -75), Quaternion(0.5609855f, -0.4304593f, -0.5609855f, 0.4304593f)..Normalize());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public static void TestQuaternionToEuler()
|
||||||
|
{
|
||||||
|
void Test(Quaternion inQuat, Vector3 expectedEuler)
|
||||||
|
{
|
||||||
|
Quaternion nrmInQuat = .Normalize(inQuat);
|
||||||
|
|
||||||
|
Vector3 result = Quaternion.ToEulerAngles(nrmInQuat);
|
||||||
|
Vector3 resultDeg = MathHelper.ToDegrees(result);
|
||||||
|
|
||||||
|
Test.Assert(Vector3Equals(resultDeg, expectedEuler));
|
||||||
|
}
|
||||||
|
|
||||||
|
Test(Quaternion.Identity, Vector3.Zero);
|
||||||
|
|
||||||
|
// X: 90°
|
||||||
|
Test(Quaternion(1, 0, 0, 1), .(90, 0, 0));
|
||||||
|
|
||||||
|
// Y: 90°
|
||||||
|
Test(Quaternion(0, 1, 0, 1), .(0, 90, 0));
|
||||||
|
|
||||||
|
// Z: 90°
|
||||||
|
Test(Quaternion(0, 0, 1, 1), .(0, 0, 90));
|
||||||
|
|
||||||
|
// X: 90° Y: 90°
|
||||||
|
Test(Quaternion(1, 1, -1, 1), .(90, 90, 0));
|
||||||
|
|
||||||
|
// 90° 45° 30°
|
||||||
|
Test(Quaternion(0.7010574f, 0.4304593f, -0.092296f, 0.5609855f), .(90, 45, 30));
|
||||||
|
|
||||||
|
// 105° 90° 0°
|
||||||
|
Test(Quaternion(0.560986f, 0.430459f, -0.560986f, 0.430459f), .(105, 90, 0));
|
||||||
|
|
||||||
|
// 180° 90° -75°
|
||||||
|
Test(Quaternion(0.5609855f, -0.4304593f, -0.5609855f, 0.4304593f), .(180, 90, -75));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public static void TestEulerToQautToEuler()
|
||||||
|
{
|
||||||
|
void Test(float yaw, float pitch, float roll)
|
||||||
|
{
|
||||||
|
Quaternion quat = .FromEulerAngles(MathHelper.ToRadians(yaw), MathHelper.ToRadians(pitch), MathHelper.ToRadians(roll));
|
||||||
|
|
||||||
|
Vector3 result = Quaternion.ToEulerAngles(quat);
|
||||||
|
|
||||||
|
result = .(MathHelper.ToDegrees(result.X), MathHelper.ToDegrees(result.Y), MathHelper.ToDegrees(result.Z));
|
||||||
|
|
||||||
|
Test.Assert(Vector3Equals(.(pitch, yaw, roll), result));
|
||||||
|
}
|
||||||
|
|
||||||
|
Test(0, 90, 0);
|
||||||
|
Test(90, 0, 0);
|
||||||
|
Test(0, 0, 90);
|
||||||
|
|
||||||
|
Test(90, 90, 0);
|
||||||
|
|
||||||
|
Test(90, 45, 0);
|
||||||
|
|
||||||
|
Test(90, 45, 30);
|
||||||
|
|
||||||
|
Test(105, 90, 0);
|
||||||
|
|
||||||
|
Test(179, 90, -75);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+11
-15
@@ -1,22 +1,9 @@
|
|||||||
FileVersion = 1
|
FileVersion = 1
|
||||||
Dependencies = {GlitchLog = "*", corlib = "*", DirectX = "*", ImGui = "*", ImGuiImplWin32 = "*", ImGuiImplDX11 = "*", DirectXTK = "*"}
|
Dependencies = {GlitchLog = "*", corlib = "*", DirectX = "*", FreeType = "*", cgltf-beef = "*", msdfgen-beef = "*", ImGui = "*", ImGuiImplDX11 = "*", ImGuiImplWin32 = "*", ImGuizmo = "*", Beefy2D = "*", LodePng = "*", GlitchyEngineHelper = "*", bon = "*"}
|
||||||
|
|
||||||
[Project]
|
[Project]
|
||||||
Name = "GlitchyEngine"
|
Name = "GlitchyEngine"
|
||||||
ProcessorMacros = ["GE_ERROR_SHADER_MATRIX_MISMATCH", "GE_ERROR_SHADER_VAR_TYPE_MISMATCH"]
|
ProcessorMacros = ["GE_GRAPHICS_DX11", "GE_SHADER_MATRIX_MISMATCH_IS_ERROR", "GE_SHADER_VAR_TYPE_MISMATCH_IS_ERROR", "GE_SHADER_UNUSED_VARIABLE_IS_WARNING", "GE_WINDOWS"]
|
||||||
|
|
||||||
[Configs.Debug.Win32]
|
|
||||||
PreprocessorMacros = ["DEBUG", "GE_WINDOWS"]
|
|
||||||
|
|
||||||
[Configs.Debug.Win64]
|
|
||||||
CLibType = "DynamicDebug"
|
|
||||||
PreprocessorMacros = ["DEBUG", "GE_WINDOWS", "GE_D3D11"]
|
|
||||||
|
|
||||||
[Configs.Release.Win32]
|
|
||||||
PreprocessorMacros = ["RELEASE", "GE_WINDOWS"]
|
|
||||||
|
|
||||||
[Configs.Release.Win64]
|
|
||||||
PreprocessorMacros = ["RELEASE", "GE_WINDOWS"]
|
|
||||||
|
|
||||||
[Configs.Paranoid.Win32]
|
[Configs.Paranoid.Win32]
|
||||||
PreprocessorMacros = ["DEBUG", "PARANOID", "GE_WINDOWS"]
|
PreprocessorMacros = ["DEBUG", "PARANOID", "GE_WINDOWS"]
|
||||||
@@ -24,8 +11,17 @@ PreprocessorMacros = ["DEBUG", "PARANOID", "GE_WINDOWS"]
|
|||||||
[Configs.Paranoid.Win64]
|
[Configs.Paranoid.Win64]
|
||||||
PreprocessorMacros = ["DEBUG", "PARANOID", "GE_WINDOWS"]
|
PreprocessorMacros = ["DEBUG", "PARANOID", "GE_WINDOWS"]
|
||||||
|
|
||||||
|
[Configs.Release.Win32]
|
||||||
|
PreprocessorMacros = ["RELEASE", "GE_WINDOWS"]
|
||||||
|
|
||||||
|
[Configs.Release.Win64]
|
||||||
|
PreprocessorMacros = ["IMGUI", "RELEASE", "GE_PROFILE"]
|
||||||
|
|
||||||
[Configs.Test.Win32]
|
[Configs.Test.Win32]
|
||||||
PreprocessorMacros = ["TEST", "GE_WINDOWS"]
|
PreprocessorMacros = ["TEST", "GE_WINDOWS"]
|
||||||
|
|
||||||
[Configs.Test.Win64]
|
[Configs.Test.Win64]
|
||||||
PreprocessorMacros = ["TEST", "GE_WINDOWS"]
|
PreprocessorMacros = ["TEST", "GE_WINDOWS"]
|
||||||
|
|
||||||
|
[Configs.Debug.Win64]
|
||||||
|
PreprocessorMacros = ["DEBUG", "GE_PROFILE", "GE_PROFILE_RENDERER", "GE_PROFILE_RESOURCES", "IMGUI"]
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ using System;
|
|||||||
using GlitchyEngine.Events;
|
using GlitchyEngine.Events;
|
||||||
using GlitchyEngine.ImGui;
|
using GlitchyEngine.ImGui;
|
||||||
using GlitchyEngine.Renderer;
|
using GlitchyEngine.Renderer;
|
||||||
|
using GlitchyEngine.Debug;
|
||||||
|
using GlitchyEngine.Content;
|
||||||
|
|
||||||
namespace GlitchyEngine
|
namespace GlitchyEngine
|
||||||
{
|
{
|
||||||
@@ -9,53 +11,102 @@ namespace GlitchyEngine
|
|||||||
{
|
{
|
||||||
static Application s_Instance = null;
|
static Application s_Instance = null;
|
||||||
|
|
||||||
private Window _window ~ delete _;
|
private Window _window;
|
||||||
private RendererAPI _rendererApi ~ delete _;
|
private RendererAPI _rendererApi;
|
||||||
|
private EffectLibrary _effectLibrary;
|
||||||
|
|
||||||
private bool _running = true;
|
private bool _running = true;
|
||||||
|
private bool _isMinimized = false;
|
||||||
|
|
||||||
private LayerStack _layerStack = new LayerStack() ~ delete _;
|
private LayerStack _layerStack;
|
||||||
|
|
||||||
|
#if IMGUI
|
||||||
private ImGuiLayer _imGuiLayer;
|
private ImGuiLayer _imGuiLayer;
|
||||||
|
#endif
|
||||||
|
|
||||||
private GameTime _gameTime = new GameTime(true) ~ delete _;
|
private GameTime _gameTime;
|
||||||
|
|
||||||
|
private IContentManager _contentManager;
|
||||||
|
|
||||||
public bool IsRunning => _running;
|
public bool IsRunning => _running;
|
||||||
public Window Window => _window;
|
public Window Window => _window;
|
||||||
|
|
||||||
|
public EffectLibrary EffectLibrary => _effectLibrary;
|
||||||
|
|
||||||
|
public IContentManager ContentManager => _contentManager;
|
||||||
|
|
||||||
|
public bool IsMinimized => _isMinimized;
|
||||||
|
|
||||||
[Inline]
|
[Inline]
|
||||||
public static Application Get() => s_Instance;
|
public static Application Get() => s_Instance;
|
||||||
|
|
||||||
|
public Settings Settings {get; private set;} = new .() ~ delete _;
|
||||||
|
|
||||||
public this()
|
public this()
|
||||||
{
|
{
|
||||||
|
Profiler.ProfileFunction!();
|
||||||
|
|
||||||
Log.EngineLogger.Assert(s_Instance == null, "Tried to create a second application.");
|
Log.EngineLogger.Assert(s_Instance == null, "Tried to create a second application.");
|
||||||
s_Instance = this;
|
s_Instance = this;
|
||||||
|
|
||||||
|
_layerStack = new LayerStack();
|
||||||
|
_gameTime = new GameTime(true);
|
||||||
|
|
||||||
_window = new Window(.Default);
|
_window = new Window(.Default);
|
||||||
_window.EventCallback = new => OnEvent;
|
_window.EventCallback = new => OnEvent;
|
||||||
|
|
||||||
_rendererApi = new RendererAPI();
|
_rendererApi = new RendererAPI();
|
||||||
_rendererApi.Context = _window.Context;
|
_rendererApi.Context = _window.Context;
|
||||||
|
|
||||||
SamplerStateManager.Init(_window.Context);
|
_contentManager = new ContentManager("./content");
|
||||||
|
|
||||||
|
SamplerStateManager.Init();
|
||||||
|
|
||||||
RenderCommand.RendererAPI = _rendererApi;
|
RenderCommand.RendererAPI = _rendererApi;
|
||||||
|
|
||||||
Renderer.Init(_window.Context);
|
_effectLibrary = new EffectLibrary();
|
||||||
|
|
||||||
|
Renderer.Init(_window.Context, _effectLibrary);
|
||||||
|
|
||||||
|
#if IMGUI
|
||||||
_imGuiLayer = new ImGuiLayer();
|
_imGuiLayer = new ImGuiLayer();
|
||||||
PushOverlay(_imGuiLayer);
|
PushOverlay(_imGuiLayer);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
GlitchyEngine.Settings.Load();
|
||||||
|
Settings.Apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ~this()
|
public ~this()
|
||||||
{
|
{
|
||||||
|
Profiler.ProfileFunction!();
|
||||||
|
|
||||||
SamplerStateManager.Uninit();
|
SamplerStateManager.Uninit();
|
||||||
|
Renderer.Deinit();
|
||||||
|
|
||||||
|
delete _effectLibrary;
|
||||||
|
|
||||||
|
delete _contentManager;
|
||||||
|
|
||||||
|
delete _rendererApi;
|
||||||
|
delete _window;
|
||||||
|
|
||||||
|
delete _gameTime;
|
||||||
|
delete _layerStack;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnEvent(Event e)
|
public void OnEvent(Event e)
|
||||||
{
|
{
|
||||||
EventDispatcher dispatcher = scope .(e);
|
Debug.Profiler.ProfileFunction!();
|
||||||
|
|
||||||
|
if(!_running)
|
||||||
|
return;
|
||||||
|
|
||||||
|
EventDispatcher dispatcher = EventDispatcher(e);
|
||||||
dispatcher.Dispatch<WindowCloseEvent>(scope => OnWindowClose);
|
dispatcher.Dispatch<WindowCloseEvent>(scope => OnWindowClose);
|
||||||
|
|
||||||
|
dispatcher.Dispatch<WindowResizeEvent>(scope => OnWindowResize);
|
||||||
|
|
||||||
for(Layer layer in _layerStack)
|
for(Layer layer in _layerStack)
|
||||||
{
|
{
|
||||||
layer.OnEvent(e);
|
layer.OnEvent(e);
|
||||||
@@ -64,33 +115,91 @@ namespace GlitchyEngine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if GE_APP_SINGLESTEP
|
||||||
|
bool allowFrame = false;
|
||||||
|
bool disableSingleFrame = false;
|
||||||
|
#else
|
||||||
|
const bool allowFrame = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
public void Run()
|
public void Run()
|
||||||
{
|
{
|
||||||
|
Debug.Profiler.ProfileFunction!();
|
||||||
|
|
||||||
while(_running)
|
while(_running)
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileScope!("Loop");
|
||||||
|
|
||||||
|
if(allowFrame)
|
||||||
{
|
{
|
||||||
_gameTime.NewFrame();
|
_gameTime.NewFrame();
|
||||||
|
}
|
||||||
|
|
||||||
Input.NewFrame();
|
Input.NewFrame();
|
||||||
|
|
||||||
|
#if GE_APP_SINGLESTEP
|
||||||
|
allowFrame = disableSingleFrame || Input.IsKeyPressing(Key.F10);
|
||||||
|
|
||||||
|
if(Input.IsKeyPressing(Key.F11))
|
||||||
|
{
|
||||||
|
disableSingleFrame = !disableSingleFrame;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(allowFrame && !_isMinimized)
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileScope!("Update Layers");
|
||||||
|
|
||||||
for(Layer layer in _layerStack)
|
for(Layer layer in _layerStack)
|
||||||
layer.Update(_gameTime);
|
layer.Update(_gameTime);
|
||||||
|
}
|
||||||
|
|
||||||
_window.Update();
|
_window.Update();
|
||||||
|
|
||||||
|
if(allowFrame)
|
||||||
|
{
|
||||||
|
#if IMGUI
|
||||||
_imGuiLayer.ImGuiRender();
|
_imGuiLayer.ImGuiRender();
|
||||||
|
#endif
|
||||||
|
|
||||||
_window.Context.SwapChain.Present();
|
_window.Context.SwapChain.Present();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void PushLayer(Layer ownLayer) => _layerStack.PushLayer(ownLayer);
|
public void PushLayer(Layer ownLayer)
|
||||||
|
{
|
||||||
|
Profiler.ProfileFunction!();
|
||||||
|
|
||||||
public void PushOverlay(Layer ownOverlay) => _layerStack.PushOverlay(ownOverlay);
|
_layerStack.PushLayer(ownLayer);
|
||||||
|
ownLayer.OnAttach();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PushOverlay(Layer ownOverlay)
|
||||||
|
{
|
||||||
|
Profiler.ProfileFunction!();
|
||||||
|
|
||||||
|
_layerStack.PushOverlay(ownOverlay);
|
||||||
|
ownOverlay.OnAttach();
|
||||||
|
}
|
||||||
|
|
||||||
public bool OnWindowClose(WindowCloseEvent e)
|
public bool OnWindowClose(WindowCloseEvent e)
|
||||||
{
|
{
|
||||||
_running = false;
|
_running = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool OnWindowResize(WindowResizeEvent e)
|
||||||
|
{
|
||||||
|
if(e.Width == 0 || e.Height == 0)
|
||||||
|
{
|
||||||
|
_isMinimized = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_isMinimized = false;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
using System.Collections;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Collections
|
||||||
|
{
|
||||||
|
public class TreeNode<T>
|
||||||
|
{
|
||||||
|
public T Value;
|
||||||
|
|
||||||
|
public List<Self> Children = new .() ~ DeleteContainerAndItems!(_);
|
||||||
|
|
||||||
|
public this() {}
|
||||||
|
|
||||||
|
public this(T value)
|
||||||
|
{
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Self AddChild(T value)
|
||||||
|
{
|
||||||
|
for (var child in Children)
|
||||||
|
{
|
||||||
|
if(child.Value == value)
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
|
Self newChild = new .(value);
|
||||||
|
|
||||||
|
Children.Add(newChild);
|
||||||
|
|
||||||
|
return newChild;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Self FindNode(T value)
|
||||||
|
{
|
||||||
|
if (Value == value)
|
||||||
|
return this;
|
||||||
|
|
||||||
|
for (var child in Children)
|
||||||
|
{
|
||||||
|
var childResult = child.FindNode(value);
|
||||||
|
if (childResult != null)
|
||||||
|
return childResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using xxHash;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Content
|
||||||
|
{
|
||||||
|
class ContentId
|
||||||
|
{
|
||||||
|
private readonly String _string;
|
||||||
|
private readonly XXH64_hash _hash;
|
||||||
|
|
||||||
|
public String String => _string;
|
||||||
|
public XXH64_hash Hash => _hash;
|
||||||
|
|
||||||
|
[AllowAppend]
|
||||||
|
public this(StringView id)
|
||||||
|
{
|
||||||
|
String str = append String(id);
|
||||||
|
|
||||||
|
_string = str;
|
||||||
|
|
||||||
|
_hash = xxHash.ComputeHash(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IContentManager
|
||||||
|
{
|
||||||
|
void GetFilePath(String outFilename, String filename);
|
||||||
|
|
||||||
|
Stream GetFile(String filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
class ContentManager : IContentManager
|
||||||
|
{
|
||||||
|
private String _contentRoot;
|
||||||
|
|
||||||
|
[AllowAppend]
|
||||||
|
public this(String contentRoot)
|
||||||
|
{
|
||||||
|
String cntRoot = append String(contentRoot);
|
||||||
|
_contentRoot = cntRoot;
|
||||||
|
|
||||||
|
Runtime.Assert(Directory.Exists(contentRoot), "Content root directory doesn't exist.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void GetFilePath(String outFilename, String filename)
|
||||||
|
{
|
||||||
|
Path.InternalCombine(outFilename, _contentRoot, filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Stream GetFile(String filename)
|
||||||
|
{
|
||||||
|
String fullpath = scope .(_contentRoot.Length + 1 + filename.Length);
|
||||||
|
GetFilePath(fullpath, filename);
|
||||||
|
|
||||||
|
FileStream stream = new FileStream();
|
||||||
|
var result = stream.Open(fullpath, .Read, .Read);
|
||||||
|
|
||||||
|
if (result case .Err(let error))
|
||||||
|
{
|
||||||
|
Log.EngineLogger.Error($"Failed to open file \"{fullpath}\". Error: {error}");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,635 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using cgltf;
|
||||||
|
using GlitchyEngine.Math;
|
||||||
|
using GlitchyEngine.Renderer;
|
||||||
|
using GlitchyEngine.Renderer.Animation;
|
||||||
|
using GlitchyEngine.World;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Content
|
||||||
|
{
|
||||||
|
public static class ModelLoader
|
||||||
|
{
|
||||||
|
static readonly Matrix RightToLeftHand = .Scaling(1, 1, -1);
|
||||||
|
|
||||||
|
public static void LoadModel(String filename, Effect validationEffect, Material material, EcsWorld world,
|
||||||
|
List<AnimationClip> outClips)
|
||||||
|
{
|
||||||
|
CGLTF.Options options = .();
|
||||||
|
CGLTF.Data* data;
|
||||||
|
CGLTF.Result result = CGLTF.ParseFile(options, filename, out data);
|
||||||
|
|
||||||
|
Log.EngineLogger.Assert(result == .Success, "Failed to load model.");
|
||||||
|
|
||||||
|
result = CGLTF.LoadBuffers(options, data, filename);
|
||||||
|
|
||||||
|
Log.EngineLogger.Assert(result == .Success, "Failed to load buffers");
|
||||||
|
|
||||||
|
for(var node in data.Scenes[0].Nodes)
|
||||||
|
{
|
||||||
|
NodesToEntities(data, node, null, world, validationEffect, material, outClips);
|
||||||
|
}
|
||||||
|
|
||||||
|
CGLTF.Free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void NodesToEntities(CGLTF.Data* data, CGLTF.Node* node, EcsEntity? parentEntity, EcsWorld world, Effect validationEffect, Material material, List<AnimationClip> clips)
|
||||||
|
{
|
||||||
|
EcsEntity entity = world.NewEntity();
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
var nameComponent = world.AssignComponent<DebugNameComponent>(entity);
|
||||||
|
|
||||||
|
if (node.Name != null)
|
||||||
|
{
|
||||||
|
nameComponent.SetName(StringView(node.Name));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nameComponent.SetName("Unnamed Node");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(parentEntity.HasValue)
|
||||||
|
{
|
||||||
|
var childParent = world.AssignComponent<ParentComponent>(entity);
|
||||||
|
childParent.Entity = parentEntity.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
var childTransform = world.AssignComponent<TransformComponent>(entity);
|
||||||
|
|
||||||
|
if(node.HasMatrix)
|
||||||
|
{
|
||||||
|
childTransform.LocalTransform = *(Matrix*)&node.Matrix;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(node.HasTranslation)
|
||||||
|
childTransform.Position = *(Vector3*)&node.Translation;
|
||||||
|
else
|
||||||
|
childTransform.Position = .Zero;
|
||||||
|
|
||||||
|
if(node.HasRotation)
|
||||||
|
childTransform.Rotation = *(Quaternion*)&node.Rotation;
|
||||||
|
else
|
||||||
|
childTransform.Rotation = .Identity;
|
||||||
|
|
||||||
|
if(node.HasScale)
|
||||||
|
childTransform.Scale = *(Vector3*)&node.Scale;
|
||||||
|
else
|
||||||
|
childTransform.Scale = .(1, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invert the Z-Axis of the root Node to convert the coordinate system from right-handed to left-handed
|
||||||
|
if(parentEntity == null)
|
||||||
|
childTransform.Scale *= .(1, 1, -1);
|
||||||
|
|
||||||
|
Skeleton skeleton = null;
|
||||||
|
|
||||||
|
if(node.Skin != null)
|
||||||
|
{
|
||||||
|
skeleton = ExtractSkeleton(node.Skin);
|
||||||
|
|
||||||
|
LoadAnimationClips(data, node.Skin, skeleton, clips);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(node.Mesh != null)
|
||||||
|
{
|
||||||
|
// If we have only one primitive, add it directly to the entity
|
||||||
|
if(node.Mesh.Primitives.Length == 1)
|
||||||
|
{
|
||||||
|
var mesh = world.AssignComponent<MeshComponent>(entity);
|
||||||
|
|
||||||
|
using (var geo = PrimitiveToGeoBinding(node.Mesh.Primitives[0], validationEffect))
|
||||||
|
{
|
||||||
|
mesh.Mesh = geo;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(skeleton == null)
|
||||||
|
{
|
||||||
|
var meshRenderer = world.AssignComponent<MeshRendererComponent>(entity);
|
||||||
|
meshRenderer.Material = material;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var meshRenderer = world.AssignComponent<SkinnedMeshRendererComponent>(entity);
|
||||||
|
meshRenderer.Material = material;
|
||||||
|
meshRenderer.Skeleton = skeleton;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// otherwise one child-entity per primitive
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(var primitive in node.Mesh.Primitives)
|
||||||
|
{
|
||||||
|
EcsEntity meshEntity = world.NewEntity();
|
||||||
|
|
||||||
|
var meshParent = world.AssignComponent<ParentComponent>(meshEntity);
|
||||||
|
meshParent.Entity = entity;
|
||||||
|
|
||||||
|
var mesh = world.AssignComponent<MeshComponent>(meshEntity);
|
||||||
|
mesh.Mesh = PrimitiveToGeoBinding(primitive, validationEffect);
|
||||||
|
|
||||||
|
if(skeleton == null)
|
||||||
|
{
|
||||||
|
var meshRenderer = world.AssignComponent<MeshRendererComponent>(meshEntity);
|
||||||
|
meshRenderer.Material = material;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var meshRenderer = world.AssignComponent<SkinnedMeshRendererComponent>(meshEntity);
|
||||||
|
meshRenderer.Material = material;
|
||||||
|
meshRenderer.Skeleton = skeleton;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
skeleton?.ReleaseRef();
|
||||||
|
|
||||||
|
for(var child in node.Children)
|
||||||
|
{
|
||||||
|
NodesToEntities(data, child, entity, world, validationEffect, material, clips);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GeometryBinding PrimitiveToGeoBinding(CGLTF.Primitive primitive, Effect validationEffect)
|
||||||
|
{
|
||||||
|
GeometryBinding binding = new GeometryBinding();
|
||||||
|
|
||||||
|
// primitive topology
|
||||||
|
switch(primitive.Type)
|
||||||
|
{
|
||||||
|
case .Points:
|
||||||
|
binding.SetPrimitiveTopology(.PointList);
|
||||||
|
case .Lines:
|
||||||
|
binding.SetPrimitiveTopology(.LineList);
|
||||||
|
case .LineStrip:
|
||||||
|
binding.SetPrimitiveTopology(.LineStrip);
|
||||||
|
case .Triangles:
|
||||||
|
binding.SetPrimitiveTopology(.TriangleList);
|
||||||
|
case .TriangleStrip:
|
||||||
|
binding.SetPrimitiveTopology(.TriangleStrip);
|
||||||
|
default:
|
||||||
|
Log.EngineLogger.Assert(false, scope $"{primitive.Type} not supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// indices
|
||||||
|
{
|
||||||
|
CGLTF.Accessor* indices = primitive.Indices;
|
||||||
|
|
||||||
|
if(indices != null)
|
||||||
|
{
|
||||||
|
bool is16bit = indices.ComponentType == .R_16u || indices.ComponentType == .R_16;
|
||||||
|
|
||||||
|
IndexBuffer ib = new IndexBuffer((.)indices.Count, .Immutable, .None, is16bit ? .Index16Bit : .Index32Bit);
|
||||||
|
|
||||||
|
uint8* bufferData = (uint8*)indices.BufferView.Buffer.Data;
|
||||||
|
bufferData += indices.BufferView.Offset;
|
||||||
|
|
||||||
|
// TODO: this is a mess
|
||||||
|
ib.SetData<uint8>(bufferData, (.)indices.BufferView.Size);
|
||||||
|
|
||||||
|
binding.SetIndexBuffer(ib);
|
||||||
|
|
||||||
|
ib.ReleaseRef();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasNormals = false;
|
||||||
|
bool hasTangents = false;
|
||||||
|
|
||||||
|
// vertices
|
||||||
|
{
|
||||||
|
List<VertexElement> elements = scope .(primitive.Attributes.Length);
|
||||||
|
Dictionary<void*, VertexBuffer> buffers = scope .();
|
||||||
|
List<VertexBufferBinding> bindings = scope .();
|
||||||
|
|
||||||
|
for(var attribute in primitive.Attributes)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
StringView attributeName = StringView(attribute.Name);
|
||||||
|
|
||||||
|
if(attributeName.Equals("NORMAL"))
|
||||||
|
{
|
||||||
|
hasNormals = true;
|
||||||
|
}
|
||||||
|
else if(attributeName.Equals("TANGENT"))
|
||||||
|
{
|
||||||
|
hasTangents = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get Input Element format
|
||||||
|
Format format = FormatFromVectorComponent(attribute.Data.Type, attribute.Data.ComponentType);
|
||||||
|
Log.EngineLogger.AssertDebug(format != .Unknown, "Vertex element format must not be \"Unknown.\"");
|
||||||
|
|
||||||
|
VertexBuffer vertexBuffer = null;
|
||||||
|
|
||||||
|
binding.VertexCount = (uint32)attribute.Data.Count;
|
||||||
|
|
||||||
|
// Get vertex buffer
|
||||||
|
{
|
||||||
|
CGLTF.BufferView* bufferView = attribute.Data.BufferView;
|
||||||
|
|
||||||
|
// if buffer doesn't exist -> create
|
||||||
|
if(!buffers.TryGetValue(bufferView, out vertexBuffer))
|
||||||
|
{
|
||||||
|
vertexBuffer = new VertexBuffer(1, (uint32)bufferView.Size, .Immutable)..ReleaseRefNoDelete();
|
||||||
|
|
||||||
|
uint8* bufferData = (uint8*)bufferView.Buffer.Data;
|
||||||
|
bufferData += bufferView.Offset;
|
||||||
|
|
||||||
|
vertexBuffer.SetData(bufferData, (.)bufferView.Size);
|
||||||
|
|
||||||
|
buffers.Add(attribute.Data.BufferView, vertexBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.EngineLogger.AssertDebug(vertexBuffer != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
VertexBufferBinding bufferBinding = .(vertexBuffer, (.)attribute.Data.Stride, (.)attribute.Data.Offset);
|
||||||
|
|
||||||
|
// get slot of bufferBinding
|
||||||
|
int bindingSlot = bindings.IndexOf(bufferBinding);
|
||||||
|
|
||||||
|
// binding has no slot -> add to list
|
||||||
|
if(bindingSlot == -1)
|
||||||
|
{
|
||||||
|
bindingSlot = bindings.Count;
|
||||||
|
bindings.Add(bufferBinding);
|
||||||
|
|
||||||
|
binding.SetVertexBufferSlot(bufferBinding, (.)bindingSlot);
|
||||||
|
}
|
||||||
|
|
||||||
|
StringView strView = .(attribute.Name);
|
||||||
|
|
||||||
|
// Remove number from end of name
|
||||||
|
while((*(strView.EndPtr - 1)).IsDigit)
|
||||||
|
{
|
||||||
|
strView.Length--;
|
||||||
|
}
|
||||||
|
|
||||||
|
VertexElement element = .(format, new String(strView), true, (.)attribute.Index, (.)bindingSlot);
|
||||||
|
elements.Add(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate normals if missing
|
||||||
|
if(!hasNormals)
|
||||||
|
{
|
||||||
|
CGLTF.Accessor* positions = null;
|
||||||
|
|
||||||
|
// Find position accessor
|
||||||
|
for(var attribute in primitive.Attributes)
|
||||||
|
{
|
||||||
|
if(StringView(attribute.Name).Equals("POSITION"))
|
||||||
|
{
|
||||||
|
positions = attribute.Data;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.EngineLogger.AssertDebug(positions != null, "The model appears to have no position data?!");
|
||||||
|
|
||||||
|
Vector3[] normals = new Vector3[positions.Count];
|
||||||
|
|
||||||
|
if(primitive.Indices != null)
|
||||||
|
GenerateNormals(primitive.Indices, positions, normals);
|
||||||
|
else
|
||||||
|
GenerateNormals(positions, normals);
|
||||||
|
|
||||||
|
VertexBuffer vertexBuffer = new VertexBuffer((uint32)sizeof(Vector3), (uint32)normals.Count, .Immutable);
|
||||||
|
vertexBuffer.SetData<Vector3>(normals);
|
||||||
|
|
||||||
|
bindings.Add(vertexBuffer.Binding);
|
||||||
|
|
||||||
|
uint32 bindingSlot = (.)bindings.Count - 1;
|
||||||
|
|
||||||
|
binding.SetVertexBufferSlot(vertexBuffer.Binding, (.)bindingSlot);
|
||||||
|
VertexElement element = .(.R32G32B32_Float, "NORMAL", false, 0, bindingSlot);
|
||||||
|
elements.Add(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: validate vertex layout somewhere else
|
||||||
|
|
||||||
|
VertexElement[] vertexElements = new VertexElement[elements.Count];
|
||||||
|
for(int i < elements.Count)
|
||||||
|
{
|
||||||
|
vertexElements[i] = elements[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
VertexLayout layout = new VertexLayout(vertexElements, true, validationEffect.VertexShader);
|
||||||
|
binding.SetVertexLayout(layout..ReleaseRefNoDelete());
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: calculate tangents if missing (MikkTSpace algorithm)
|
||||||
|
// Note: Bitangent = cross(normal, tangent.xyz) * tangent.w
|
||||||
|
|
||||||
|
return binding;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generates the normals for one triangle
|
||||||
|
static mixin GenerateTriangleNormals(int index0, int index1, int index2, CGLTF.Accessor* positions, Vector3[] normals)
|
||||||
|
{
|
||||||
|
Vector3 position0 = GetEntry<Vector3>(positions, (.)index0);
|
||||||
|
Vector3 position1 = GetEntry<Vector3>(positions, (.)index1);
|
||||||
|
Vector3 position2 = GetEntry<Vector3>(positions, (.)index2);
|
||||||
|
|
||||||
|
ref Vector3 normal0 = ref normals[(.)index0];
|
||||||
|
ref Vector3 normal1 = ref normals[(.)index1];
|
||||||
|
ref Vector3 normal2 = ref normals[(.)index2];
|
||||||
|
|
||||||
|
Vector3 e0 = position1 - position0;
|
||||||
|
Vector3 e1 = position2 - position0;
|
||||||
|
|
||||||
|
Vector3 normal = Vector3.Cross(e0, e1);
|
||||||
|
|
||||||
|
normal0 += normal;
|
||||||
|
normal1 += normal;
|
||||||
|
normal2 += normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Inline]
|
||||||
|
static void NormalizeNormals(Vector3[] normals)
|
||||||
|
{
|
||||||
|
for(int i < normals.Count)
|
||||||
|
{
|
||||||
|
normals[i].Normalize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generates normals for the given model using indexed geometry
|
||||||
|
static void GenerateNormals(CGLTF.Accessor* indices, CGLTF.Accessor* positions, Vector3[] normals)
|
||||||
|
{
|
||||||
|
/// Enumerate triangle-wise
|
||||||
|
for(uint t = 0; t < indices.Count; t += 3)
|
||||||
|
{
|
||||||
|
int index0 = (.)CGLTF.AccessorReadIndex(indices, t);
|
||||||
|
int index1 = (.)CGLTF.AccessorReadIndex(indices, t + 1);
|
||||||
|
int index2 = (.)CGLTF.AccessorReadIndex(indices, t + 2);
|
||||||
|
|
||||||
|
GenerateTriangleNormals!(index0, index1, index2, positions, normals);
|
||||||
|
}
|
||||||
|
|
||||||
|
NormalizeNormals(normals);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generates normals for the given model using nonindexed geometry
|
||||||
|
static void GenerateNormals(CGLTF.Accessor* positions, Vector3[] normals)
|
||||||
|
{
|
||||||
|
/// Enumerate triangle-wise
|
||||||
|
for(int i = 0; i < (.)positions.Count; i += 3)
|
||||||
|
{
|
||||||
|
GenerateTriangleNormals!(i, i + 1, i + 2, positions, normals);
|
||||||
|
}
|
||||||
|
|
||||||
|
NormalizeNormals(normals);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Skeleton ExtractSkeleton(CGLTF.Skin* skin)
|
||||||
|
{
|
||||||
|
Skeleton skeleton = new Skeleton();
|
||||||
|
skeleton.Joints = new Joint[skin.Joints.Length];
|
||||||
|
|
||||||
|
for(int i < skin.Joints.Length)
|
||||||
|
{
|
||||||
|
ref Joint joint = ref skeleton.Joints[i];
|
||||||
|
|
||||||
|
joint.InverseBindPose = GetEntry<Matrix>(skin.InverseBindMatrices, i);
|
||||||
|
|
||||||
|
if (skin.Joints[i].Name != null)
|
||||||
|
joint.Name = new String(skin.Joints[i].Name);
|
||||||
|
|
||||||
|
int parentId = skin.Joints.IndexOf(skin.Joints[i].Parent);
|
||||||
|
|
||||||
|
Log.EngineLogger.AssertDebug(parentId < uint8.MaxValue, scope $"A skeleton must not have more than {uint8.MaxValue - 1} bones.");
|
||||||
|
|
||||||
|
if(parentId == -1)
|
||||||
|
joint.ParentID = uint8.MaxValue;
|
||||||
|
else
|
||||||
|
joint.ParentID = (uint8)parentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
return skeleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool AnimationBelongsToSkeleton(CGLTF.Animation animation, CGLTF.Skin* skin)
|
||||||
|
{
|
||||||
|
for(var channel in animation.Channels)
|
||||||
|
{
|
||||||
|
if(skin.Joints.IndexOf(channel.TargetNode) == -1)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void LoadAnimationClips(CGLTF.Data* data, CGLTF.Skin* skin, Skeleton skeleton, List<AnimationClip> clips)
|
||||||
|
{
|
||||||
|
for(var animation in data.Animations)
|
||||||
|
{
|
||||||
|
if(!AnimationBelongsToSkeleton(animation, skin))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
AnimationClip clip = new AnimationClip(skeleton);
|
||||||
|
clips.Add(clip);
|
||||||
|
clip.IsLooping = true;
|
||||||
|
|
||||||
|
for(var channel in animation.Channels)
|
||||||
|
{
|
||||||
|
int nodeIndex = skin.Joints.IndexOf(channel.TargetNode);
|
||||||
|
|
||||||
|
Log.EngineLogger.AssertDebug(nodeIndex != -1);
|
||||||
|
|
||||||
|
ref JointAnimation jointAnimation = ref clip.JointAnimations[nodeIndex];
|
||||||
|
|
||||||
|
if(jointAnimation == null)
|
||||||
|
jointAnimation = new JointAnimation();
|
||||||
|
|
||||||
|
Log.EngineLogger.AssertDebug(channel.Sampler.Input.Count == channel.Sampler.Output.Count);
|
||||||
|
|
||||||
|
int samples = (int)channel.Sampler.Input.Count;
|
||||||
|
|
||||||
|
Log.EngineLogger.AssertDebug(channel.Sampler.Input.ComponentType == .R_32f);
|
||||||
|
Log.EngineLogger.AssertDebug(channel.Sampler.Input.Type == .Scalar);
|
||||||
|
|
||||||
|
InterpolationMode interpolationMode;
|
||||||
|
|
||||||
|
switch(channel.Sampler.Interpolation)
|
||||||
|
{
|
||||||
|
case .Step:
|
||||||
|
interpolationMode = .Step;
|
||||||
|
case .Linear:
|
||||||
|
interpolationMode = .Linear;
|
||||||
|
case .CubicSpline:
|
||||||
|
interpolationMode = .CubicSpline;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(channel.TargetPath)
|
||||||
|
{
|
||||||
|
case .Translation:
|
||||||
|
jointAnimation.TranslationChannel = new .(samples, interpolationMode);
|
||||||
|
|
||||||
|
Log.EngineLogger.AssertDebug(channel.Sampler.Output.ComponentType == .R_32f);
|
||||||
|
Log.EngineLogger.AssertDebug(channel.Sampler.Output.Type == .Vec3);
|
||||||
|
|
||||||
|
for(int i < samples)
|
||||||
|
{
|
||||||
|
float timeStamp = GetEntry<float>(channel.Sampler.Input, i);
|
||||||
|
Vector3 sample = GetEntry<Vector3>(channel.Sampler.Output, i);
|
||||||
|
|
||||||
|
jointAnimation.TranslationChannel.TimeStamps[i] = timeStamp;
|
||||||
|
jointAnimation.TranslationChannel.Values[i] = sample;
|
||||||
|
}
|
||||||
|
case .Rotation:
|
||||||
|
jointAnimation.RotationChannel = new .(samples, interpolationMode);
|
||||||
|
|
||||||
|
Log.EngineLogger.AssertDebug(channel.Sampler.Output.ComponentType == .R_32f);
|
||||||
|
Log.EngineLogger.AssertDebug(channel.Sampler.Output.Type == .Vec4);
|
||||||
|
|
||||||
|
for(int i < samples)
|
||||||
|
{
|
||||||
|
float timeStamp = GetEntry<float>(channel.Sampler.Input, i);
|
||||||
|
Quaternion sample = GetEntry<Quaternion>(channel.Sampler.Output, i);
|
||||||
|
|
||||||
|
jointAnimation.RotationChannel.TimeStamps[i] = timeStamp;
|
||||||
|
jointAnimation.RotationChannel.Values[i] = sample;
|
||||||
|
}
|
||||||
|
case .Scale:
|
||||||
|
jointAnimation.ScaleChannel = new .(samples, interpolationMode);
|
||||||
|
|
||||||
|
Log.EngineLogger.AssertDebug(channel.Sampler.Output.ComponentType == .R_32f);
|
||||||
|
Log.EngineLogger.AssertDebug(channel.Sampler.Output.Type == .Vec3);
|
||||||
|
|
||||||
|
for(int i < samples)
|
||||||
|
{
|
||||||
|
float timeStamp = GetEntry<float>(channel.Sampler.Input, i);
|
||||||
|
Vector3 sample = GetEntry<Vector3>(channel.Sampler.Output, i);
|
||||||
|
|
||||||
|
jointAnimation.ScaleChannel.TimeStamps[i] = timeStamp;
|
||||||
|
jointAnimation.ScaleChannel.Values[i] = sample;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
Log.EngineLogger.Error($"Unknown channel target path \"{channel.TargetPath}\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
clip.Duration = Math.Max(clip.Duration, jointAnimation.Duration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static T GetEntry<T>(CGLTF.Accessor* accessor, int index)
|
||||||
|
{
|
||||||
|
Log.EngineLogger.AssertDebug((uint)index < accessor.Count);
|
||||||
|
|
||||||
|
T result = ?;
|
||||||
|
|
||||||
|
switch(typeof(T))
|
||||||
|
{
|
||||||
|
case typeof(float):
|
||||||
|
CGLTF.AccessorReadFloat(accessor, (uint)index, (float*)&result, 1);
|
||||||
|
case typeof(Vector2):
|
||||||
|
CGLTF.AccessorReadFloat(accessor, (uint)index, (float*)&result, 2);
|
||||||
|
case typeof(Vector3):
|
||||||
|
CGLTF.AccessorReadFloat(accessor, (uint)index, (float*)&result, 3);
|
||||||
|
case typeof(Vector4), typeof(Quaternion):
|
||||||
|
CGLTF.AccessorReadFloat(accessor, (uint)index, (float*)&result, 4);
|
||||||
|
case typeof(Matrix):
|
||||||
|
CGLTF.AccessorReadFloat(accessor, (uint)index, (float*)&result, 16);
|
||||||
|
case typeof(uint16):
|
||||||
|
CGLTF.AccessorReadUint(accessor, (uint)index, (uint32*)&result, 2);
|
||||||
|
case default:
|
||||||
|
uint8* data = (uint8*)accessor.BufferView.Buffer.Data;
|
||||||
|
|
||||||
|
data += accessor.BufferView.Offset;
|
||||||
|
|
||||||
|
data += accessor.Offset;
|
||||||
|
|
||||||
|
data += accessor.Stride * (uint)index;
|
||||||
|
|
||||||
|
result = *(T*)data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
/*
|
||||||
|
uint8* data = (uint8*)accessor.BufferView.Buffer.Data;
|
||||||
|
|
||||||
|
data += accessor.BufferView.Offset;
|
||||||
|
|
||||||
|
data += accessor.Offset;
|
||||||
|
|
||||||
|
data += accessor.Stride * (uint)index;
|
||||||
|
|
||||||
|
return *(T*)data;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the vector and component type to the corresponding Format.
|
||||||
|
*/
|
||||||
|
static Format FormatFromVectorComponent(CGLTF.Type vectorType, CGLTF.ComponentType componentType)
|
||||||
|
{
|
||||||
|
switch((vectorType, componentType))
|
||||||
|
{
|
||||||
|
case (.Scalar, .R_8):
|
||||||
|
return .R8_SInt;
|
||||||
|
case (.Scalar, .R_8u):
|
||||||
|
return .R8_UInt;
|
||||||
|
case (.Scalar, .R_16):
|
||||||
|
return .R16_SInt;
|
||||||
|
case (.Scalar, .R_16u):
|
||||||
|
return .R16_UInt;
|
||||||
|
case (.Scalar, .R_32u):
|
||||||
|
return .R32_UInt;
|
||||||
|
case (.Scalar, .R_32f):
|
||||||
|
return .R32_Float;
|
||||||
|
|
||||||
|
case (.Vec2, .R_8):
|
||||||
|
return .R8G8_SInt;
|
||||||
|
case (.Vec2, .R_8u):
|
||||||
|
return .R8G8_UInt;
|
||||||
|
case (.Vec2, .R_16):
|
||||||
|
return .R16G16_SInt;
|
||||||
|
case (.Vec2, .R_16u):
|
||||||
|
return .R16G16_UInt;
|
||||||
|
case (.Vec2, .R_32u):
|
||||||
|
return .R32G32_UInt;
|
||||||
|
case (.Vec2, .R_32f):
|
||||||
|
return .R32G32_Float;
|
||||||
|
|
||||||
|
//case (.Vec3, .R_8):
|
||||||
|
//case (.Vec3, .R_8u):
|
||||||
|
//case (.Vec3, .R_16):
|
||||||
|
//case (.Vec3, .R_16u):
|
||||||
|
case (.Vec3, .R_32u):
|
||||||
|
return .R32G32B32_UInt;
|
||||||
|
case (.Vec3, .R_32f):
|
||||||
|
return .R32G32B32_Float;
|
||||||
|
|
||||||
|
case (.Vec4, .R_8):
|
||||||
|
return .R8G8B8A8_SInt;
|
||||||
|
case (.Vec4, .R_8u):
|
||||||
|
return .R8G8B8A8_UInt;
|
||||||
|
case (.Vec4, .R_16):
|
||||||
|
return .R16G16B16A16_SInt;
|
||||||
|
case (.Vec4, .R_16u):
|
||||||
|
return .R16G16B16A16_UInt;
|
||||||
|
case (.Vec4, .R_32u):
|
||||||
|
return .R32G32B32A32_UInt;
|
||||||
|
case (.Vec4, .R_32f):
|
||||||
|
return .R32G32B32A32_Float;
|
||||||
|
|
||||||
|
case (.Mat4, .R_32f):
|
||||||
|
return .R32G32B32A32_Float;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Log.EngineLogger.Assert(false, scope $"Unhandled vector - componenttype combination. ({vectorType}, {componentType})");
|
||||||
|
}
|
||||||
|
|
||||||
|
return .Unknown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Core
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Provides a reference counter that, when reaching 0, automatically deletes itself.
|
||||||
|
* Implements the IDisposable interface so that it can be used with a using-Block so that the counter
|
||||||
|
* will be decremented automatically after leaving the block.
|
||||||
|
*/
|
||||||
|
public class RefCounter : System.RefCounted, IDisposable
|
||||||
|
{
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
ReleaseRef();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
using System;
|
||||||
|
using Beefy.utils;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Debug
|
||||||
|
{
|
||||||
|
public static class Profiler
|
||||||
|
{
|
||||||
|
#if !GE_PROFILE
|
||||||
|
[SkipCall]
|
||||||
|
#endif
|
||||||
|
public static void BeginProfiling(StringView serverName = "127.0.0.1", StringView sessionName = "GlitchyEngine")
|
||||||
|
{
|
||||||
|
BeefPerf.Init(serverName, sessionName);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !GE_PROFILE
|
||||||
|
[SkipCall]
|
||||||
|
#endif
|
||||||
|
public static void EndProfiling()
|
||||||
|
{
|
||||||
|
BeefPerf.Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !GE_PROFILE
|
||||||
|
[SkipCall]
|
||||||
|
#endif
|
||||||
|
public static mixin ProfileFunction()
|
||||||
|
{
|
||||||
|
scope:mixin PerformanceTimer()
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !GE_PROFILE
|
||||||
|
[SkipCall]
|
||||||
|
#endif
|
||||||
|
public static mixin ProfileScope(char8* scopeName)
|
||||||
|
{
|
||||||
|
scope:mixin PerformanceTimer(scopeName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extension
|
||||||
|
|
||||||
|
#if !GE_PROFILE_RENDERER
|
||||||
|
[SkipCall]
|
||||||
|
#endif
|
||||||
|
public static mixin ProfileRendererFunction()
|
||||||
|
{
|
||||||
|
scope:mixin PerformanceTimer()
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !GE_PROFILE_RENDERER
|
||||||
|
[SkipCall]
|
||||||
|
#endif
|
||||||
|
public static mixin ProfileRendererScope(char8* scopeName)
|
||||||
|
{
|
||||||
|
scope:mixin PerformanceTimer(scopeName)
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !GE_PROFILE_RESOURCES
|
||||||
|
[SkipCall]
|
||||||
|
#endif
|
||||||
|
public static mixin ProfileResourceFunction()
|
||||||
|
{
|
||||||
|
scope:mixin PerformanceTimer()
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !GE_PROFILE_RESOURCES
|
||||||
|
[SkipCall]
|
||||||
|
#endif
|
||||||
|
public static mixin ProfileResourceScope(char8* scopeName)
|
||||||
|
{
|
||||||
|
scope:mixin PerformanceTimer(scopeName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PerformanceTimer
|
||||||
|
{
|
||||||
|
[Inline]
|
||||||
|
public this(char8* name = Compiler.CallerMemberName)
|
||||||
|
{
|
||||||
|
#if GE_PROFILE
|
||||||
|
[Inline]
|
||||||
|
BeefPerf.Enter(name);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
[Inline]
|
||||||
|
public ~this()
|
||||||
|
{
|
||||||
|
#if GE_PROFILE
|
||||||
|
[Inline]
|
||||||
|
BeefPerf.Leave();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,9 +26,9 @@ namespace GlitchyEngine.Events
|
|||||||
private bool _isResizing;
|
private bool _isResizing;
|
||||||
|
|
||||||
/// The new width of the window.
|
/// The new width of the window.
|
||||||
public int32 Width = _width;
|
public int32 Width => _width;
|
||||||
/// The new height of the window.
|
/// The new height of the window.
|
||||||
public int32 Height = _height;
|
public int32 Height => _height;
|
||||||
/*
|
/*
|
||||||
* If true, indicates that the resizing is not finished.
|
* If true, indicates that the resizing is not finished.
|
||||||
*/
|
*/
|
||||||
@@ -89,4 +89,44 @@ namespace GlitchyEngine.Events
|
|||||||
strBuffer.AppendF("WindowMovedEvent: {}, {} (is moving: {})", _x, _y, _isMoving);
|
strBuffer.AppendF("WindowMovedEvent: {}, {} (is moving: {})", _x, _y, _isMoving);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class WindowActivateEvent : Event, IEvent
|
||||||
|
{
|
||||||
|
public override EventType EventType => .WindowMoved;
|
||||||
|
|
||||||
|
public override StringView Name => "WindowActivated";
|
||||||
|
|
||||||
|
public override EventCategory Category => .Application;
|
||||||
|
|
||||||
|
public static EventType StaticType => .WindowActivated;
|
||||||
|
|
||||||
|
public this()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ToString(String strBuffer)
|
||||||
|
{
|
||||||
|
strBuffer.AppendF("WindowActivatedEvent");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class WindowDeactivateEvent : Event, IEvent
|
||||||
|
{
|
||||||
|
public override EventType EventType => .WindowMoved;
|
||||||
|
|
||||||
|
public override StringView Name => "WindowDeactivated";
|
||||||
|
|
||||||
|
public override EventCategory Category => .Application;
|
||||||
|
|
||||||
|
public static EventType StaticType => .WindowDeactivated;
|
||||||
|
|
||||||
|
public this()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ToString(String strBuffer)
|
||||||
|
{
|
||||||
|
strBuffer.AppendF("WindowDeactivatedEvent");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ namespace GlitchyEngine.Events
|
|||||||
public enum EventType
|
public enum EventType
|
||||||
{
|
{
|
||||||
None = 0,
|
None = 0,
|
||||||
WindowClose, WindowResize, WindowFocus, WindowLostFocus, WindowMoved,
|
WindowClose, WindowResize, WindowFocus, WindowLostFocus, WindowMoved, WindowActivated, WindowDeactivated,
|
||||||
AppTick, AppUpdate, AppRender,
|
AppTick, AppUpdate, AppRender,
|
||||||
KeyPressed, KeyReleased, KeyTyped,
|
KeyPressed, KeyReleased, KeyTyped,
|
||||||
MouseButtonPressed, MouseButtonReleased, MouseMoved, MouseScrolled
|
MouseButtonPressed, MouseButtonReleased, MouseMoved, MouseScrolled
|
||||||
@@ -50,7 +50,7 @@ namespace GlitchyEngine.Events
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class EventDispatcher
|
public struct EventDispatcher
|
||||||
{
|
{
|
||||||
private Event _event;
|
private Event _event;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
namespace System
|
||||||
|
{
|
||||||
|
public extension Array1<T>
|
||||||
|
{
|
||||||
|
/// Returns the index of the given element or -1 if it is not in this array.
|
||||||
|
public int IndexOf(T element)
|
||||||
|
{
|
||||||
|
for(int i < mLength)
|
||||||
|
if(Ptr[i] == element)
|
||||||
|
return i;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uses Binary Search to find the index of the given Element.
|
||||||
|
* @param element The element whose element will be returned.
|
||||||
|
* @returns The index of the element in the array or -1 if it is not in the array.
|
||||||
|
* @Note this function only works if the entries of the array are sorted in ascending order.
|
||||||
|
*/
|
||||||
|
public int IndexOfBinary(T element) where bool : operator T < T
|
||||||
|
{
|
||||||
|
int lowerBound = 0;
|
||||||
|
int upperBound = mLength;
|
||||||
|
|
||||||
|
while(lowerBound != upperBound)
|
||||||
|
{
|
||||||
|
int index = (lowerBound + upperBound) / 2;
|
||||||
|
|
||||||
|
T elementAtIndex = Ptr[index];
|
||||||
|
|
||||||
|
if(elementAtIndex == element)
|
||||||
|
{
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
else if(elementAtIndex < element)
|
||||||
|
{
|
||||||
|
upperBound = index;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lowerBound = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
namespace System
|
||||||
|
{
|
||||||
|
extension Runtime
|
||||||
|
{
|
||||||
|
[NoReturn, Warn("The method is not implemented.")]
|
||||||
|
#unwarn
|
||||||
|
public static void NotImplemented(String filePath = Compiler.CallerFilePath, int line = Compiler.CallerLineNum)
|
||||||
|
{
|
||||||
|
String failStr = scope .()..AppendF("Not Implemented at line {} in {}", line, filePath);
|
||||||
|
Internal.FatalError(failStr, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
namespace System
|
||||||
|
{
|
||||||
|
extension String
|
||||||
|
{
|
||||||
|
[Inline]
|
||||||
|
public void CopyTo(Span<char8> target)
|
||||||
|
{
|
||||||
|
CopyTo(target.Ptr, target.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Inline]
|
||||||
|
public void CopyTo(char8* target, int targetLength)
|
||||||
|
{
|
||||||
|
int copiedChars = Math.Min(targetLength - 1, Length);
|
||||||
|
|
||||||
|
Internal.MemCpy(target, Ptr, copiedChars);
|
||||||
|
|
||||||
|
target[copiedChars] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@ namespace GlitchyEngine
|
|||||||
*/
|
*/
|
||||||
public class GameTime
|
public class GameTime
|
||||||
{
|
{
|
||||||
private Stopwatch _stopwatch ~ delete:append _;
|
private Stopwatch _stopwatch;
|
||||||
|
|
||||||
private uint64 _frameCount;
|
private uint64 _frameCount;
|
||||||
|
|
||||||
@@ -28,6 +28,9 @@ namespace GlitchyEngine
|
|||||||
*/
|
*/
|
||||||
public uint64 FrameCount => _frameCount;
|
public uint64 FrameCount => _frameCount;
|
||||||
|
|
||||||
|
/// The interval in seconds from the last frame to the current one.
|
||||||
|
public float DeltaTime => (float)_frameTime.TotalSeconds;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes a new instance of a GameTime.
|
* Initializes a new instance of a GameTime.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
using static System.Compiler;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Generators
|
||||||
|
{
|
||||||
|
public class NewDisposableComponentGenerator : Generator
|
||||||
|
{
|
||||||
|
public override String Name => "New Disposable Component";
|
||||||
|
|
||||||
|
public override void InitUI()
|
||||||
|
{
|
||||||
|
AddEdit("name", "Component Name", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Generate(String outFileName, String outText, ref Flags generateFlags)
|
||||||
|
{
|
||||||
|
var name = mParams["name"];
|
||||||
|
if (name.EndsWith(".bf", .OrdinalIgnoreCase))
|
||||||
|
name.RemoveFromEnd(3);
|
||||||
|
outFileName.Append(name);
|
||||||
|
|
||||||
|
outText.AppendF(
|
||||||
|
$"""
|
||||||
|
using GlitchyEngine.World;
|
||||||
|
|
||||||
|
namespace {Namespace}
|
||||||
|
{{
|
||||||
|
struct {name} : IDisposableComponent
|
||||||
|
{{
|
||||||
|
public void Dispose() mut
|
||||||
|
{{
|
||||||
|
// TODO: Dispose of the content
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
using System;
|
||||||
|
using static System.Compiler;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Generators
|
||||||
|
{
|
||||||
|
public class NewStructGenerator : Generator
|
||||||
|
{
|
||||||
|
public override String Name => "New Struct";
|
||||||
|
|
||||||
|
public override void InitUI()
|
||||||
|
{
|
||||||
|
AddEdit("name", "Struct Name", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Generate(String outFileName, String outText, ref Flags generateFlags)
|
||||||
|
{
|
||||||
|
var name = mParams["name"];
|
||||||
|
if (name.EndsWith(".bf", .OrdinalIgnoreCase))
|
||||||
|
name.RemoveFromEnd(3);
|
||||||
|
outFileName.Append(name);
|
||||||
|
outText.AppendF(
|
||||||
|
$"""
|
||||||
|
namespace {Namespace}
|
||||||
|
{{
|
||||||
|
struct {name}
|
||||||
|
{{
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
using DirectX.Common;
|
||||||
|
using GlitchyEngine.Core;
|
||||||
|
|
||||||
|
namespace GlitchyEngine
|
||||||
|
{
|
||||||
|
static
|
||||||
|
{
|
||||||
|
/// Releases the reference to destination, writes newValue into it and adds a reference to newValue.
|
||||||
|
public static mixin SetReference<T>(T destination, T newValue) where T: RefCounter
|
||||||
|
{
|
||||||
|
var oldDest = destination;
|
||||||
|
destination = newValue;
|
||||||
|
destination?.AddRef();
|
||||||
|
oldDest?.ReleaseRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Releases the reference to value and nullifies it.
|
||||||
|
public static mixin ReleaseRefAndNullify<T>(T value) where T: RefCounter
|
||||||
|
{
|
||||||
|
value?.ReleaseRef();
|
||||||
|
value = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static mixin DeleteContainerAndReleaseItems(var container)
|
||||||
|
{
|
||||||
|
if (container != null)
|
||||||
|
{
|
||||||
|
for (var value in container)
|
||||||
|
value?.ReleaseRef();
|
||||||
|
delete container;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static mixin ClearAndReleaseItems(var container)
|
||||||
|
{
|
||||||
|
for (var value in container)
|
||||||
|
value?.ReleaseRef();
|
||||||
|
container.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,24 @@
|
|||||||
using GlitchyEngine.Math;
|
using GlitchyEngine.Math;
|
||||||
|
using GlitchyEngine.Renderer;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace ImGui
|
namespace ImGui
|
||||||
{
|
{
|
||||||
extension ImGui
|
extension ImGui
|
||||||
{
|
{
|
||||||
// TODO: Color-functions
|
extension Vec2
|
||||||
|
{
|
||||||
|
public static explicit operator Vector2(Vec2 v) => .(v.x, v.y);
|
||||||
|
public static explicit operator Vec2(Vector2 v) => .(v.X, v.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Vec4
|
||||||
|
{
|
||||||
|
public static explicit operator Vector4(Vec4 v) => .(v.x, v.y, v.z, v.w);
|
||||||
|
public static explicit operator Vec4(Vector4 v) => .(v.X, v.Y, v.Z, v.W);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Color-functions
|
||||||
public static bool ColorEdit3(char* label, ref ColorRGB col, ColorEditFlags flags = (ColorEditFlags) 0) => ColorEdit3Impl(label, *(float[3]*)&col, flags);
|
public static bool ColorEdit3(char* label, ref ColorRGB col, ColorEditFlags flags = (ColorEditFlags) 0) => ColorEdit3Impl(label, *(float[3]*)&col, flags);
|
||||||
public static bool ColorEdit3(char* label, ref ColorRGBA col, ColorEditFlags flags = (ColorEditFlags) 0) => ColorEdit3Impl(label, *(float[3]*)&col, flags);
|
public static bool ColorEdit3(char* label, ref ColorRGBA col, ColorEditFlags flags = (ColorEditFlags) 0) => ColorEdit3Impl(label, *(float[3]*)&col, flags);
|
||||||
|
|
||||||
@@ -14,5 +28,99 @@ namespace ImGui
|
|||||||
public static bool ColorPicker3(char* label, ref ColorRGBA col, ColorEditFlags flags = (ColorEditFlags) 0) => ColorPicker3Impl(label, *(float[3]*)&col, flags);
|
public static bool ColorPicker3(char* label, ref ColorRGBA col, ColorEditFlags flags = (ColorEditFlags) 0) => ColorPicker3Impl(label, *(float[3]*)&col, flags);
|
||||||
|
|
||||||
public static bool ColorPicker4(char* label, ref ColorRGBA col, ColorEditFlags flags = (ColorEditFlags) 0, float* ref_col = null) => ColorPicker4Impl(label, *(float[4]*)&col, flags, ref_col);
|
public static bool ColorPicker4(char* label, ref ColorRGBA col, ColorEditFlags flags = (ColorEditFlags) 0, float* ref_col = null) => ColorPicker4Impl(label, *(float[4]*)&col, flags, ref_col);
|
||||||
|
|
||||||
|
public static extern void Image(Texture2D texture, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, Vec4 tint_col = Vec4.Ones, Vec4 border_col = Vec4.Zero);
|
||||||
|
// Wouldn't be necesseary if RenderTarget2D was Texture2D
|
||||||
|
public static extern void Image(RenderTarget2D texture, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, Vec4 tint_col = Vec4.Ones, Vec4 border_col = Vec4.Zero);
|
||||||
|
|
||||||
|
public static void TextUnformatted(StringView text) => TextUnformattedImpl(text.Ptr, text.Ptr + text.Length);
|
||||||
|
|
||||||
|
public static void PushID(StringView id) => PushID(id.Ptr, id.Ptr + id.Length);
|
||||||
|
|
||||||
|
/// Releases references that accumulated calls like ImGui::Image
|
||||||
|
protected internal static extern void CleanupFrame();
|
||||||
|
|
||||||
|
/// Control to edit a vector 3 with drag functionality and reset buttons
|
||||||
|
public static bool EditVector3(StringView label, ref Vector3 value, Vector3 resetValues = .Zero, float dragSpeed = 0.1f, float columnWidth = 100f)
|
||||||
|
{
|
||||||
|
bool changed = false;
|
||||||
|
|
||||||
|
PushID(label);
|
||||||
|
defer PopID();
|
||||||
|
|
||||||
|
Columns(2);
|
||||||
|
defer Columns(1);
|
||||||
|
SetColumnWidth(0, columnWidth);
|
||||||
|
|
||||||
|
TextUnformatted(label);
|
||||||
|
|
||||||
|
NextColumn();
|
||||||
|
|
||||||
|
PushMultiItemsWidths(3, CalcItemWidth());
|
||||||
|
PushStyleVar(.ItemSpacing, Vec2.Zero);
|
||||||
|
defer PopStyleVar();
|
||||||
|
|
||||||
|
float lineHeight = GetFont().FontSize + GetStyle().FramePadding.y * 2.0f;
|
||||||
|
ImGui.Vec2 buttonSize = .(lineHeight + 3.0f, lineHeight);
|
||||||
|
|
||||||
|
PushStyleColor(.Button, Color(230, 25, 45).Value);
|
||||||
|
PushStyleColor(.ButtonHovered, Color(150, 25, 45).Value);
|
||||||
|
PushStyleColor(.ButtonActive, Color(230, 120, 130).Value);
|
||||||
|
|
||||||
|
if (Button("X", buttonSize))
|
||||||
|
{
|
||||||
|
value.X = resetValues.X;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
SameLine();
|
||||||
|
|
||||||
|
if (DragFloat("##X", &value.X, dragSpeed))
|
||||||
|
changed = true;
|
||||||
|
|
||||||
|
PopItemWidth();
|
||||||
|
SameLine();
|
||||||
|
|
||||||
|
PopStyleColor(3);
|
||||||
|
PushStyleColor(.Button, Color(50, 190, 15).Value);
|
||||||
|
PushStyleColor(.ButtonHovered, Color(50, 120, 15).Value);
|
||||||
|
PushStyleColor(.ButtonActive, Color(116, 190, 99).Value);
|
||||||
|
|
||||||
|
if (Button("Y", buttonSize))
|
||||||
|
{
|
||||||
|
value.Y = resetValues.Y;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
SameLine();
|
||||||
|
|
||||||
|
if (DragFloat("##Y", &value.Y, dragSpeed))
|
||||||
|
changed = true;
|
||||||
|
|
||||||
|
PopItemWidth();
|
||||||
|
SameLine();
|
||||||
|
|
||||||
|
PopStyleColor(3);
|
||||||
|
PushStyleColor(.Button, Color(55, 55, 230).Value);
|
||||||
|
PushStyleColor(.ButtonHovered, Color(55, 55, 150).Value);
|
||||||
|
PushStyleColor(.ButtonActive, Color(90, 90, 230).Value);
|
||||||
|
|
||||||
|
if (Button("Z", buttonSize))
|
||||||
|
{
|
||||||
|
value.Z = resetValues.Z;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
SameLine();
|
||||||
|
|
||||||
|
if (DragFloat("##Z", &value.Z, dragSpeed))
|
||||||
|
changed = true;
|
||||||
|
|
||||||
|
PopItemWidth();
|
||||||
|
|
||||||
|
PopStyleColor(3);
|
||||||
|
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,33 @@
|
|||||||
using System;
|
using System;
|
||||||
using ImGui;
|
using ImGui;
|
||||||
using GlitchyEngine.Events;
|
using GlitchyEngine.Events;
|
||||||
|
using ImGuizmo;
|
||||||
|
using GlitchyEngine.Renderer;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
using internal ImGui;
|
||||||
|
|
||||||
|
#if GE_GRAPHICS_DX11
|
||||||
|
|
||||||
|
using GlitchyEngine.Platform.DX11;
|
||||||
|
using internal GlitchyEngine.Platform.DX11;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace GlitchyEngine.ImGui
|
namespace GlitchyEngine.ImGui
|
||||||
{
|
{
|
||||||
public class ImGuiLayer : Layer
|
public class ImGuiLayer : Layer
|
||||||
{
|
{
|
||||||
|
ImGui.IO* _io;
|
||||||
|
|
||||||
|
public bool SettingsInvalid;
|
||||||
|
|
||||||
public this() : base("ImGuiLayer") { }
|
public this() : base("ImGuiLayer") { }
|
||||||
|
|
||||||
public override void OnAttach()
|
public override void OnAttach()
|
||||||
{
|
{
|
||||||
|
Debug.Profiler.ProfileFunction!();
|
||||||
|
|
||||||
//ImGuiImplWin32.EnableDpiAwareness();
|
//ImGuiImplWin32.EnableDpiAwareness();
|
||||||
Log.EngineLogger.Trace("Initializing ImGui...");
|
Log.EngineLogger.Trace("Initializing ImGui...");
|
||||||
|
|
||||||
@@ -17,198 +35,114 @@ namespace GlitchyEngine.ImGui
|
|||||||
ImGui.CreateContext();
|
ImGui.CreateContext();
|
||||||
ImGui.StyleColorsDark();
|
ImGui.StyleColorsDark();
|
||||||
|
|
||||||
ref ImGui.IO io = ref ImGui.GetIO();
|
_io = ImGui.GetIO();
|
||||||
io.ConfigFlags |= .NavEnableKeyboard;
|
_io.ConfigFlags |= .NavEnableKeyboard;
|
||||||
io.ConfigFlags |= .DockingEnable;
|
_io.ConfigFlags |= .DockingEnable;
|
||||||
io.ConfigFlags |= .ViewportsEnable;
|
_io.ConfigFlags |= .ViewportsEnable;
|
||||||
|
|
||||||
// Todo: currently broken in ImGui
|
// Todo: currently broken in ImGui
|
||||||
//io.ConfigFlags |= .DpiEnableScaleFonts;
|
//io.ConfigFlags |= .DpiEnableScaleFonts;
|
||||||
//io.ConfigFlags |= .DpiEnableScaleViewports;
|
//io.ConfigFlags |= .DpiEnableScaleViewports;
|
||||||
|
|
||||||
// When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
|
// When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
|
||||||
ref ImGui.Style style = ref ImGui.GetStyle();
|
ImGui.Style* style = ImGui.GetStyle();
|
||||||
if(io.ConfigFlags.HasFlag(.ViewportsEnable))
|
if(_io.ConfigFlags.HasFlag(.ViewportsEnable))
|
||||||
{
|
{
|
||||||
style.WindowRounding = 0.0f;
|
style.WindowRounding = 0.0f;
|
||||||
style.Colors[(int)ImGui.Col.WindowBg].w = 1.0f;
|
style.Colors[(int)ImGui.Col.WindowBg].w = 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if GE_WINDOWS
|
#if BF_PLATFORM_WINDOWS
|
||||||
// Todo: temporary, needs to be platform independent
|
ImGuiImplWin32.Init(Application.Get().Window.NativeWindow);
|
||||||
ImGuiImplWin32.Init((Windows.HWnd)(int)Application.Get().Window.NativeWindow);
|
|
||||||
|
|
||||||
var context = Application.Get().Window.Context;
|
|
||||||
|
|
||||||
ImGuiImplDX11.Init(context.[Friend]nativeDevice, context.[Friend]nativeContext);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if GE_GRAPHICS_DX11
|
||||||
|
ImGuiImplDX11.Init(NativeDevice, NativeContext);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnDetach()
|
public override void OnDetach()
|
||||||
{
|
{
|
||||||
|
Debug.Profiler.ProfileFunction!();
|
||||||
|
|
||||||
|
#if GE_GRAPHICS_DX11
|
||||||
ImGuiImplDX11.Shutdown();
|
ImGuiImplDX11.Shutdown();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if BF_PLATFORM_WINDOWS
|
||||||
ImGuiImplWin32.Shutdown();
|
ImGuiImplWin32.Shutdown();
|
||||||
|
#endif
|
||||||
|
|
||||||
ImGui.DestroyContext();
|
ImGui.DestroyContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnEvent(Event event)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
EventDispatcher dispatcher = scope EventDispatcher(event);
|
|
||||||
|
|
||||||
dispatcher.Dispatch<WindowResizeEvent>(scope (e) =>
|
|
||||||
{
|
|
||||||
//ref ImGui.IO io = ref ImGui.GetIO();
|
|
||||||
//io.DisplaySize = .(e.Width, e.Height);
|
|
||||||
//io.DisplayFramebufferScale = .(1.0f, 1.0f);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
dispatcher.Dispatch<MouseMovedEvent>(scope (e) =>
|
|
||||||
{
|
|
||||||
ref ImGui.IO io = ref ImGui.GetIO();
|
|
||||||
io.MousePos = ImGui.Vec2(e.PositionX, e.PositionY);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
dispatcher.Dispatch<MouseButtonPressedEvent>(scope (e) =>
|
|
||||||
{
|
|
||||||
int button = 0;
|
|
||||||
switch(e.MouseButton)
|
|
||||||
{
|
|
||||||
case .LeftButton:
|
|
||||||
button = (uint)ImGui.MouseButton.Left;
|
|
||||||
case .RightButton:
|
|
||||||
button = (uint)ImGui.MouseButton.Right;
|
|
||||||
case .MiddleButton:
|
|
||||||
button = (uint)ImGui.MouseButton.Middle;
|
|
||||||
case .XButton1:
|
|
||||||
button = (uint)3;
|
|
||||||
case .XButton2:
|
|
||||||
button = (uint)4;
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
ref ImGui.IO io = ref ImGui.GetIO();
|
|
||||||
io.MouseDown[button] = true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
dispatcher.Dispatch<MouseButtonReleasedEvent>(scope (e) =>
|
|
||||||
{
|
|
||||||
int button = 0;
|
|
||||||
switch(e.MouseButton)
|
|
||||||
{
|
|
||||||
case .LeftButton:
|
|
||||||
button = (uint)ImGui.MouseButton.Left;
|
|
||||||
case .RightButton:
|
|
||||||
button = (uint)ImGui.MouseButton.Right;
|
|
||||||
case .MiddleButton:
|
|
||||||
button = (uint)ImGui.MouseButton.Middle;
|
|
||||||
case .XButton1:
|
|
||||||
button = (uint)3;
|
|
||||||
case .XButton2:
|
|
||||||
button = (uint)4;
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
ref ImGui.IO io = ref ImGui.GetIO();
|
|
||||||
io.MouseDown[button] = false;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
dispatcher.Dispatch<MouseScrolledEvent>(scope (e) =>
|
|
||||||
{
|
|
||||||
ref ImGui.IO io = ref ImGui.GetIO();
|
|
||||||
io.MouseWheel += e.YOffset;
|
|
||||||
io.MouseWheelH += e.XOffset; // Todo: horizontal mousewheel inverted?!
|
|
||||||
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
dispatcher.Dispatch<KeyPressedEvent>(scope (e) =>
|
|
||||||
{
|
|
||||||
if(e.KeyCode >= (.)256)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
ref ImGui.IO io = ref ImGui.GetIO();
|
|
||||||
io.KeysDown[(int32)e.KeyCode] = true;
|
|
||||||
|
|
||||||
io.KeyCtrl = io.KeysDown[(int32)Key.Control];
|
|
||||||
io.KeyShift = io.KeysDown[(int32)Key.Shift];
|
|
||||||
io.KeyAlt = io.KeysDown[(int32)Key.Alt];
|
|
||||||
io.KeySuper = io.KeysDown[(int32)Key.LeftSuper] || io.KeysDown[(int32)Key.RightSuper];
|
|
||||||
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
dispatcher.Dispatch<KeyReleasedEvent>(scope (e) =>
|
|
||||||
{
|
|
||||||
if(e.KeyCode >= (.)256)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
ref ImGui.IO io = ref ImGui.GetIO();
|
|
||||||
io.KeysDown[(int32)e.KeyCode] = false;
|
|
||||||
|
|
||||||
io.KeyCtrl = io.KeysDown[(int32)Key.Control];
|
|
||||||
io.KeyShift = io.KeysDown[(int32)Key.Shift];
|
|
||||||
io.KeyAlt = io.KeysDown[(int32)Key.Alt];
|
|
||||||
io.KeySuper = io.KeysDown[(int32)Key.LeftSuper] || io.KeysDown[(int32)Key.RightSuper];
|
|
||||||
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
dispatcher.Dispatch<KeyTypedEvent>(scope (e) =>
|
|
||||||
{
|
|
||||||
ref ImGui.IO io = ref ImGui.GetIO();
|
|
||||||
io.AddInputCharacterUTF16((uint16)e.Char);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Begin()
|
public void Begin()
|
||||||
{
|
{
|
||||||
// Todo:
|
Debug.Profiler.ProfileFunction!();
|
||||||
//var v = DirectX.ImmediateContext;
|
|
||||||
//v.OutputMerger.SetRenderTargets(1, &DirectX.BackBufferTarget, null);
|
|
||||||
Application.Get().Window.Context.SetRenderTarget(null);
|
|
||||||
|
|
||||||
ImGuiImplDX11.NewFrame();
|
ImGuiImplDX11.NewFrame();
|
||||||
ImGuiImplWin32.NewFrame();
|
ImGuiImplWin32.NewFrame();
|
||||||
ImGui.NewFrame();
|
ImGui.NewFrame();
|
||||||
|
ImGuizmo.BeginFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool showDemo = true;
|
|
||||||
public void ImGuiRender()
|
public void ImGuiRender()
|
||||||
{
|
{
|
||||||
|
Debug.Profiler.ProfileFunction!();
|
||||||
|
|
||||||
|
if (SettingsInvalid)
|
||||||
|
{
|
||||||
|
var settings = Application.Get().Settings.ImGuiSettings;
|
||||||
|
|
||||||
|
ImGui.GetIO().Fonts.Clear();
|
||||||
|
|
||||||
|
String fullpath = scope String();
|
||||||
|
Application.Get().ContentManager.GetFilePath(fullpath, settings.FontName);
|
||||||
|
if (File.Exists(fullpath))
|
||||||
|
{
|
||||||
|
ImGui.GetIO().Fonts.AddFontFromFileTTF(fullpath, settings.FontSize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui.GetIO().Fonts.AddFontDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if GE_GRAPHICS_DX11
|
||||||
|
ImGuiImplDX11.CreateDeviceObjects();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SettingsInvalid = false;
|
||||||
|
}
|
||||||
|
|
||||||
Begin();
|
Begin();
|
||||||
|
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileScope!("ImGuiRenderEvent");
|
||||||
|
|
||||||
var event = scope ImGuiRenderEvent();
|
var event = scope ImGuiRenderEvent();
|
||||||
Application.Get().OnEvent(event);
|
Application.Get().OnEvent(event);
|
||||||
|
}
|
||||||
ImGui.ShowDemoWindow(&showDemo);
|
|
||||||
|
|
||||||
End();
|
End();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void End()
|
public void End()
|
||||||
{
|
{
|
||||||
ref ImGui.IO io = ref ImGui.GetIO();
|
Debug.Profiler.ProfileFunction!();
|
||||||
|
|
||||||
let window = Application.Get().Window;
|
|
||||||
io.DisplaySize = .(window.Width, window.Height);
|
|
||||||
|
|
||||||
ImGui.Render();
|
ImGui.Render();
|
||||||
ImGuiImplDX11.RenderDrawData(ref ImGui.GetDrawData());
|
|
||||||
|
|
||||||
if(io.ConfigFlags.HasFlag(.ViewportsEnable))
|
RenderCommand.SetDepthStencilTarget(null);
|
||||||
|
RenderCommand.SetRenderTarget(null);
|
||||||
|
RenderCommand.BindRenderTargets();
|
||||||
|
|
||||||
|
#if GE_GRAPHICS_DX11
|
||||||
|
ImGuiImplDX11.RenderDrawData(ImGui.GetDrawData());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ImGui.CleanupFrame();
|
||||||
|
|
||||||
|
if(_io.ConfigFlags.HasFlag(.ViewportsEnable))
|
||||||
{
|
{
|
||||||
ImGui.UpdatePlatformWindows();
|
ImGui.UpdatePlatformWindows();
|
||||||
ImGui.RenderPlatformWindowsDefault();
|
ImGui.RenderPlatformWindowsDefault();
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ namespace GlitchyEngine
|
|||||||
{
|
{
|
||||||
public static class Input
|
public static class Input
|
||||||
{
|
{
|
||||||
public static extern bool RawInput {get; set;}
|
|
||||||
|
|
||||||
public static extern bool IsKeyPressed(Key keycode);
|
public static extern bool IsKeyPressed(Key keycode);
|
||||||
public static extern bool IsKeyReleased(Key keycode);
|
public static extern bool IsKeyReleased(Key keycode);
|
||||||
public static extern bool IsKeyToggled(Key keycode);
|
public static extern bool IsKeyToggled(Key keycode);
|
||||||
@@ -40,15 +38,9 @@ namespace GlitchyEngine
|
|||||||
public static extern int32 GetLastMouseY();
|
public static extern int32 GetLastMouseY();
|
||||||
|
|
||||||
public static extern bool IsMouseButtonPressing(MouseButton button);
|
public static extern bool IsMouseButtonPressing(MouseButton button);
|
||||||
public static extern bool IsMouseButtonReleasiong(MouseButton button);
|
public static extern bool IsMouseButtonReleasing(MouseButton button);
|
||||||
public static extern Point GetMouseMovement();
|
public static extern Point GetMouseMovement();
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the raw mouse (that is the mouse movement taken direcly from the device instead of the movement processed by the OS).
|
|
||||||
* Requires RawInput to be true. If RawInput is false (or could not be initialized) this method will return the same value as GetMouseMovement();
|
|
||||||
*/
|
|
||||||
public static extern Int32_2 GetRawMouseMovement();
|
|
||||||
|
|
||||||
public static extern void NewFrame();
|
public static extern void NewFrame();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ namespace GlitchyEngine
|
|||||||
case Z = 90; // Z key
|
case Z = 90; // Z key
|
||||||
case LeftSuper = 91; // Left Windows key(Microsoft® Natural® keyboard)
|
case LeftSuper = 91; // Left Windows key(Microsoft® Natural® keyboard)
|
||||||
case RightSuper = 92; // Right Windows key(Natural keyboard)
|
case RightSuper = 92; // Right Windows key(Natural keyboard)
|
||||||
|
case ContextMenu = 93; // Context Menu key (VK_APPS)
|
||||||
case Numpad0 = 96; // Numeric keypad 0 key
|
case Numpad0 = 96; // Numeric keypad 0 key
|
||||||
case Numpad1 = 97; // Numeric keypad 1 key
|
case Numpad1 = 97; // Numeric keypad 1 key
|
||||||
case Numpad2 = 98; // Numeric keypad 2 key
|
case Numpad2 = 98; // Numeric keypad 2 key
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ namespace GlitchyEngine
|
|||||||
public void PushLayer(Layer ownLayer)
|
public void PushLayer(Layer ownLayer)
|
||||||
{
|
{
|
||||||
_layers.Insert(_insertIndex++, ownLayer);
|
_layers.Insert(_insertIndex++, ownLayer);
|
||||||
ownLayer.OnAttach();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -40,7 +39,6 @@ namespace GlitchyEngine
|
|||||||
public void PushOverlay(Layer ownOverlay)
|
public void PushOverlay(Layer ownOverlay)
|
||||||
{
|
{
|
||||||
_layers.Add(ownOverlay);
|
_layers.Add(ownOverlay);
|
||||||
ownOverlay.OnAttach();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -18,6 +18,11 @@ namespace GlitchyEngine.Math
|
|||||||
|
|
||||||
public this(int initialCapacity = sizeof(uint))
|
public this(int initialCapacity = sizeof(uint))
|
||||||
{
|
{
|
||||||
|
var initialCapacity;
|
||||||
|
|
||||||
|
if (initialCapacity < sizeof(uint))
|
||||||
|
initialCapacity = sizeof(uint);
|
||||||
|
|
||||||
EnsureCapacity(initialCapacity);
|
EnsureCapacity(initialCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,12 +13,12 @@ namespace System
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Inline]
|
[Inline]
|
||||||
public Int32_2 XX => Int32_2((int32)this);
|
public Int2 XX => Int2((int32)this);
|
||||||
|
|
||||||
[Inline]
|
[Inline]
|
||||||
public Int32_3 XXX => Int32_3((int32)this);
|
public Int3 XXX => Int3((int32)this);
|
||||||
|
|
||||||
[Inline]
|
[Inline]
|
||||||
public Int32_4 XXXX => Int32_4((int32)this);
|
public Int4 XXXX => Int4((int32)this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Math
|
||||||
|
{
|
||||||
|
public static class MathHelper
|
||||||
|
{
|
||||||
|
/// An optimal representation of π.
|
||||||
|
public const float Pi = 3.141592654f;
|
||||||
|
/// An optimal representation of 2*π.
|
||||||
|
public const float TwoPi = 6.283185307f;
|
||||||
|
/// An optimal representation of 1/π.
|
||||||
|
public const float OneOverPi = 0.318309886f;
|
||||||
|
/// An optimal representation of 2/π.
|
||||||
|
public const float OneOverTwoPi = 0.159154943f;
|
||||||
|
/// An optimal representation of π/2.
|
||||||
|
public const float PiOverTwo = 1.570796327f;
|
||||||
|
/// An optimal representation of π/4.
|
||||||
|
public const float PiOverFour = 0.785398163f;
|
||||||
|
|
||||||
|
/// Converts radians to degrees
|
||||||
|
public const float RadToDeg = 180.0f / Pi;
|
||||||
|
|
||||||
|
/// Converts radians to degrees
|
||||||
|
public const float DegToRad = Pi / 180.0f;
|
||||||
|
|
||||||
|
// Converts the given radians to degrees
|
||||||
|
public static float ToDegrees(float radians)
|
||||||
|
{
|
||||||
|
return radians * RadToDeg;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts the given radians to degrees
|
||||||
|
public static Vector2 ToDegrees(Vector2 radians)
|
||||||
|
{
|
||||||
|
return radians * RadToDeg;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts the given radians to degrees
|
||||||
|
public static Vector3 ToDegrees(Vector3 radians)
|
||||||
|
{
|
||||||
|
return radians * RadToDeg;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts the given radians to degrees
|
||||||
|
public static Vector4 ToDegrees(Vector4 radians)
|
||||||
|
{
|
||||||
|
return radians * RadToDeg;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts the given degrees to radians
|
||||||
|
public static float ToRadians(float degrees)
|
||||||
|
{
|
||||||
|
return degrees * DegToRad;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts the given degrees to radians
|
||||||
|
public static Vector2 ToRadians(Vector2 degrees)
|
||||||
|
{
|
||||||
|
return degrees * DegToRad;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts the given degrees to radians
|
||||||
|
public static Vector3 ToRadians(Vector3 degrees)
|
||||||
|
{
|
||||||
|
return degrees * DegToRad;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts the given degrees to radians
|
||||||
|
public static Vector4 ToRadians(Vector4 degrees)
|
||||||
|
{
|
||||||
|
return degrees * DegToRad;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float epsilon = 0.0000001f;
|
||||||
|
|
||||||
|
public static bool IsZero(float value)
|
||||||
|
{
|
||||||
|
return Math.Abs(value) < epsilon;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
using System;
|
||||||
|
using GlitchyEngine.Math;
|
||||||
|
using GlitchyEngine;
|
||||||
|
|
||||||
|
namespace DirectX.Math
|
||||||
|
{
|
||||||
|
extension Matrix
|
||||||
|
{
|
||||||
|
typealias Vec3 = GlitchyEngine.Math.Vector3;
|
||||||
|
|
||||||
|
public static Self RotationQuaternion(Quaternion rotation)
|
||||||
|
{
|
||||||
|
float xSq = 2 * rotation.X * rotation.X;
|
||||||
|
float ySq = 2 * rotation.Y * rotation.Y;
|
||||||
|
float zSq = 2 * rotation.Z * rotation.Z;
|
||||||
|
|
||||||
|
float xy = 2 * rotation.X * rotation.Y;
|
||||||
|
float xz = 2 * rotation.X * rotation.Z;
|
||||||
|
float xw = 2 * rotation.X * rotation.W;
|
||||||
|
float yz = 2 * rotation.Y * rotation.Z;
|
||||||
|
float yw = 2 * rotation.Y * rotation.W;
|
||||||
|
float zw = 2 * rotation.Z * rotation.W;
|
||||||
|
|
||||||
|
Self result = ?;
|
||||||
|
|
||||||
|
result.V._11 = 1 - ySq - zSq;
|
||||||
|
result.V._21 = xy + zw;
|
||||||
|
result.V._31 = xz - yw;
|
||||||
|
result.V._41 = 0;
|
||||||
|
|
||||||
|
result.V._12 = xy - zw;
|
||||||
|
result.V._22 = 1 - xSq - zSq;
|
||||||
|
result.V._32 = yz + xw;
|
||||||
|
result.V._42 = 0;
|
||||||
|
|
||||||
|
result.V._13 = xz + yw;
|
||||||
|
result.V._23 = yz - xw;
|
||||||
|
result.V._33 = 1 - xSq - ySq;
|
||||||
|
result.V._43 = 0;
|
||||||
|
|
||||||
|
result.V._14 = 0;
|
||||||
|
result.V._24 = 0;
|
||||||
|
result.V._34 = 0;
|
||||||
|
result.V._44 = 1;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Decompose(Self matrix, out Vec3 position, out Quaternion rotation, out Vec3 scale)
|
||||||
|
{
|
||||||
|
var matrix;
|
||||||
|
|
||||||
|
// Translation -> get last column
|
||||||
|
position = matrix.Translation;
|
||||||
|
// Zero translation for next step
|
||||||
|
matrix.Translation = .Zero;
|
||||||
|
|
||||||
|
// TODO: this doesn't detect mirroring
|
||||||
|
|
||||||
|
// Extract scaling from matrix
|
||||||
|
scale.X = (*(Vec3*)&matrix.Columns[0]).Magnitude();
|
||||||
|
scale.Y = (*(Vec3*)&matrix.Columns[1]).Magnitude();
|
||||||
|
scale.Z = (*(Vec3*)&matrix.Columns[2]).Magnitude();
|
||||||
|
|
||||||
|
if(MathHelper.IsZero(scale.X) || MathHelper.IsZero(scale.Y) || MathHelper.IsZero(scale.Z))
|
||||||
|
{
|
||||||
|
rotation = .Identity;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove scale from matrix (normalize the columns)
|
||||||
|
matrix.Columns[0] /= scale.X;
|
||||||
|
matrix.Columns[1] /= scale.Y;
|
||||||
|
matrix.Columns[2] /= scale.Z;
|
||||||
|
|
||||||
|
rotation = Quaternion.FromMatrix(matrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*[Test]
|
||||||
|
static void TestQuaternionToMatrix()
|
||||||
|
{
|
||||||
|
// Rotation around Z-Axis by 90°
|
||||||
|
Quaternion quat = .(0, 0, 0.707107f, 0.707107f);
|
||||||
|
quat.Normalize();
|
||||||
|
|
||||||
|
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,378 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Math
|
||||||
|
{
|
||||||
|
public struct Quaternion
|
||||||
|
{
|
||||||
|
public const Quaternion Zero = .();
|
||||||
|
public const Quaternion One = .(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
public const Quaternion Identity = .(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
public float X, Y, Z, W;
|
||||||
|
|
||||||
|
public this() => this = default;
|
||||||
|
|
||||||
|
public this(float x, float y, float z, float w)
|
||||||
|
{
|
||||||
|
X = x;
|
||||||
|
Y = y;
|
||||||
|
Z = z;
|
||||||
|
W = w;
|
||||||
|
}
|
||||||
|
|
||||||
|
public this(Vector3 xy, float z, float w)
|
||||||
|
{
|
||||||
|
X = xy.X;
|
||||||
|
Y = xy.Y;
|
||||||
|
Z = z;
|
||||||
|
W = w;
|
||||||
|
}
|
||||||
|
|
||||||
|
public this(Vector3 xyz, float w)
|
||||||
|
{
|
||||||
|
X = xyz.X;
|
||||||
|
Y = xyz.Y;
|
||||||
|
Z = xyz.Z;
|
||||||
|
W = w;
|
||||||
|
}
|
||||||
|
|
||||||
|
public this(Vector4 vector)
|
||||||
|
{
|
||||||
|
X = vector.X;
|
||||||
|
Y = vector.Y;
|
||||||
|
Z = vector.Z;
|
||||||
|
W = vector.W;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3 Vector
|
||||||
|
{
|
||||||
|
get => .(X, Y, Z);
|
||||||
|
set mut
|
||||||
|
{
|
||||||
|
X = value.X;
|
||||||
|
Y = value.Y;
|
||||||
|
Z = value.Z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float Scalar
|
||||||
|
{
|
||||||
|
get => W;
|
||||||
|
set mut => W = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Normalize() mut
|
||||||
|
{
|
||||||
|
float invLength = 1.0f / Length();
|
||||||
|
|
||||||
|
X *= invLength;
|
||||||
|
Y *= invLength;
|
||||||
|
Z *= invLength;
|
||||||
|
W *= invLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Quaternion Normalize(Quaternion q)
|
||||||
|
{
|
||||||
|
float invLength = 1.0f / Length(q);
|
||||||
|
|
||||||
|
return Quaternion(q.X * invLength, q.Y * invLength, q.Z * invLength, q.W * invLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float Length()
|
||||||
|
{
|
||||||
|
return Math.Sqrt([Inline]LengthSquared());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float Length(Quaternion q)
|
||||||
|
{
|
||||||
|
return Math.Sqrt([Inline]LengthSquared(q));
|
||||||
|
}
|
||||||
|
|
||||||
|
public float LengthSquared()
|
||||||
|
{
|
||||||
|
return X * X + Y * Y + Z * Z + W * W;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float LengthSquared(Quaternion q)
|
||||||
|
{
|
||||||
|
return q.X * q.X + q.Y * q.Y + q.Z * q.Z + q.W * q.W;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float Dot(Self l, Self r)
|
||||||
|
{
|
||||||
|
return l.X * r.X + l.Y * r.Y + l.Z * r.Z + l.W * r.W;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Quaternion Lerp(Quaternion a, Quaternion b, float interpolationValue)
|
||||||
|
{
|
||||||
|
return a + interpolationValue * (b - a);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Quaternion Slerp(Quaternion previousQuaternion, Quaternion nextQuaternion, float interpolationValue)
|
||||||
|
{
|
||||||
|
// Based on https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_007_Animations.md
|
||||||
|
|
||||||
|
var nextQuaternion;
|
||||||
|
|
||||||
|
float dot = Dot(previousQuaternion, nextQuaternion);
|
||||||
|
|
||||||
|
//make sure we take the shortest path in case dot Product is negative
|
||||||
|
if(dot < 0.0f)
|
||||||
|
{
|
||||||
|
nextQuaternion = -nextQuaternion;
|
||||||
|
dot = -dot;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if the two quaternions are too close to each other, just linear interpolate between the 4D vector
|
||||||
|
if(dot > 0.9995f)
|
||||||
|
return Normalize(previousQuaternion + interpolationValue * (nextQuaternion - previousQuaternion));
|
||||||
|
|
||||||
|
//perform the spherical linear interpolation
|
||||||
|
var theta_0 = Math.Acos(dot);
|
||||||
|
var theta = interpolationValue * theta_0;
|
||||||
|
var sin_theta = Math.Sin(theta);
|
||||||
|
var sin_theta_0 = Math.Sin(theta_0);
|
||||||
|
|
||||||
|
var scalePreviousQuat = Math.Cos(theta) - dot * sin_theta / sin_theta_0;
|
||||||
|
var scaleNextQuat = sin_theta / sin_theta_0;
|
||||||
|
return scalePreviousQuat * previousQuaternion + scaleNextQuat * nextQuaternion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Quaternion FromMatrix(Matrix matrix)
|
||||||
|
{
|
||||||
|
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/
|
||||||
|
|
||||||
|
var m = matrix.V;
|
||||||
|
|
||||||
|
Quaternion result = ?;
|
||||||
|
|
||||||
|
float tr = m._11 + m._22 + m._33;
|
||||||
|
|
||||||
|
if (tr > 0) {
|
||||||
|
float S = Math.Sqrt(tr + 1.0f) * 2f; // S=4*result.W
|
||||||
|
result.W = 0.25f * S;
|
||||||
|
result.X = (m._32 - m._23) / S;
|
||||||
|
result.Y = (m._13 - m._31) / S;
|
||||||
|
result.Z = (m._21 - m._12) / S;
|
||||||
|
} else if ((m._11 > m._22)&(m._11 > m._33)) {
|
||||||
|
float S = Math.Sqrt(1.0f + m._11 - m._22 - m._33) * 2f; // S=4*result.X
|
||||||
|
result.W = (m._32 - m._23) / S;
|
||||||
|
result.X = 0.25f * S;
|
||||||
|
result.Y = (m._12 + m._21) / S;
|
||||||
|
result.Z = (m._13 + m._31) / S;
|
||||||
|
} else if (m._22 > m._33) {
|
||||||
|
float S = Math.Sqrt(1.0f + m._22 - m._11 - m._33) * 2f; // S=4*result.Y
|
||||||
|
result.W = (m._13 - m._31) / S;
|
||||||
|
result.X = (m._12 + m._21) / S;
|
||||||
|
result.Y = 0.25f * S;
|
||||||
|
result.Z = (m._23 + m._32) / S;
|
||||||
|
} else {
|
||||||
|
float S = Math.Sqrt(1.0f + m._33 - m._11 - m._22) * 2f; // S=4*result.Z
|
||||||
|
result.W = (m._21 - m._12) / S;
|
||||||
|
result.X = (m._13 + m._31) / S;
|
||||||
|
result.Y = (m._23 + m._32) / S;
|
||||||
|
result.Z = 0.25f * S;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Self operator +(Self value) => value;
|
||||||
|
|
||||||
|
public static Self operator +(Self l, Self r) => Self(l.X + r.X, l.Y + r.Y, l.Z + r.Z, l.W + r.W);
|
||||||
|
|
||||||
|
public static Self operator -(Self value) => Self(-value.X, -value.Y, -value.Z, -value.W);
|
||||||
|
|
||||||
|
public static Self operator -(Self l, Self r) => Self(l.X - r.X, l.Y - r.Y, l.Z - r.Z, l.W - r.W);
|
||||||
|
|
||||||
|
public static Self operator *(float l, Self r) => Self(l * r.X, l * r.Y, l * r.Z, l * r.W);
|
||||||
|
|
||||||
|
public static Self operator /(Self l, float r) => Self(l.X * r, l.Y * r, l.Z * r, l.W * r);
|
||||||
|
|
||||||
|
public static Self operator *(Self l, Self r)
|
||||||
|
{
|
||||||
|
Quaternion result;
|
||||||
|
|
||||||
|
Vector3 v = l.Vector * r.Vector + (l.W * r.Vector) + (r.W * l.Vector);
|
||||||
|
result.X = v.X;
|
||||||
|
result.Y = v.Y;
|
||||||
|
result.Z = v.Z;
|
||||||
|
result.W = (l.W * r.W) - Vector3.Dot(l.Vector, r.Vector);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Quaternion Conjugate(Quaternion q)
|
||||||
|
{
|
||||||
|
return Quaternion(-q.Vector, q.Scalar);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Quaternion Inverse(Quaternion q)
|
||||||
|
{
|
||||||
|
Quaternion conjugate = Conjugate(q);
|
||||||
|
|
||||||
|
float magSquared = LengthSquared(q);
|
||||||
|
|
||||||
|
return conjugate / magSquared;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Inline]
|
||||||
|
#unwarn
|
||||||
|
public static implicit operator Vector4(in Self value) => *(Vector4*)&value;
|
||||||
|
|
||||||
|
[Inline]
|
||||||
|
#unwarn
|
||||||
|
public static implicit operator Quaternion(in Vector4 value) => *(Quaternion*)&value;
|
||||||
|
|
||||||
|
public static bool operator ==(Quaternion l, Quaternion r)
|
||||||
|
{
|
||||||
|
return l.X == r.X && l.Y == r.Y && l.Z == r.Z && l.W == r.W;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(Quaternion l, Quaternion r)
|
||||||
|
{
|
||||||
|
return l.X != r.X && l.Y != r.Y && l.Z != r.Z && l.W != r.W;
|
||||||
|
}
|
||||||
|
|
||||||
|
public (Vector3 Axis, float Angle) ToAxisAngle()
|
||||||
|
{
|
||||||
|
// scalar part = cos(θ/2)
|
||||||
|
// So, we can extract the angle directly.
|
||||||
|
float angle = 2.0f * Math.Acos(W);
|
||||||
|
|
||||||
|
// vector part = axis * sin(θ/2)
|
||||||
|
// In other words, the vector part is the axis, but with length of sin(θ/2).
|
||||||
|
// We assume quaternion is unit length, so subtracting w^2 gives us length of just vector part (aka sin(θ/2)).
|
||||||
|
float length = Math.Sqrt(1.0f - (W * W));
|
||||||
|
|
||||||
|
Vector3 axis;
|
||||||
|
|
||||||
|
// Normalize vector part to get the axis!
|
||||||
|
if(length == 0)
|
||||||
|
{
|
||||||
|
axis = Vector3.Zero;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
length = 1.0f / length;
|
||||||
|
axis.X = X * length;
|
||||||
|
axis.Y = Y * length;
|
||||||
|
axis.Z = Z * length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (axis, angle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Quaternion FromAxisAngle(Vector3 axis, float angle)
|
||||||
|
{
|
||||||
|
float lengthSq = axis.MagnitudeSquared();
|
||||||
|
|
||||||
|
if(lengthSq == 0)
|
||||||
|
{
|
||||||
|
return .Identity;
|
||||||
|
}
|
||||||
|
|
||||||
|
float halfAngle = angle * 0.5f;
|
||||||
|
|
||||||
|
float sin = Math.Sin(halfAngle) / Math.Sqrt(lengthSq);
|
||||||
|
|
||||||
|
Quaternion result;
|
||||||
|
result.X = axis.X * sin;
|
||||||
|
result.Y = axis.Y * sin;
|
||||||
|
result.Z = axis.Z * sin;
|
||||||
|
result.W = Math.Cos(halfAngle);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assumes YZX-Order meaning Y applied first, Z second and x last
|
||||||
|
public static Quaternion FromEulerAngles(float yaw, float pitch, float roll)
|
||||||
|
{
|
||||||
|
float halfYaw = yaw / 2.0f;
|
||||||
|
float halfPitch = pitch / 2.0f;
|
||||||
|
float halfRoll = roll / 2.0f;
|
||||||
|
|
||||||
|
float cosYaw = Math.Cos(halfYaw);//heading
|
||||||
|
float sinYaw = Math.Sin(halfYaw);
|
||||||
|
float cosRoll = Math.Cos(halfRoll);//attitude
|
||||||
|
float sinRoll = Math.Sin(halfRoll);
|
||||||
|
float cosPitch = Math.Cos(halfPitch);//bank
|
||||||
|
float sinPitch = Math.Sin(halfPitch);
|
||||||
|
|
||||||
|
float cosYawCosRoll = cosYaw * cosRoll;
|
||||||
|
float sinYawSinRoll = sinYaw * sinRoll;
|
||||||
|
float cosYawSinRoll = cosYaw * sinRoll;
|
||||||
|
float sinYawCosRoll = sinYaw * cosRoll;
|
||||||
|
|
||||||
|
Quaternion result;
|
||||||
|
|
||||||
|
result.W = cosYawCosRoll * cosPitch - sinYawSinRoll * sinPitch;
|
||||||
|
result.X = cosYawCosRoll * sinPitch + sinYawSinRoll * cosPitch;
|
||||||
|
result.Y = sinYawCosRoll * cosPitch + cosYawSinRoll * sinPitch;
|
||||||
|
result.Z = cosYawSinRoll * cosPitch - sinYawCosRoll * sinPitch;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector3 ToEulerAngles(Quaternion q)
|
||||||
|
{
|
||||||
|
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/
|
||||||
|
|
||||||
|
Vector3 result;
|
||||||
|
|
||||||
|
float sqw = q.W*q.W;
|
||||||
|
float sqx = q.X*q.X;
|
||||||
|
float sqy = q.Y*q.Y;
|
||||||
|
float sqz = q.Z*q.Z;
|
||||||
|
float unit = sqx + sqy + sqz + sqw; // if normalised is one, otherwise is correction factor
|
||||||
|
float test = q.X*q.Y + q.Z*q.W;
|
||||||
|
if (test > 0.4999f*unit) { // singularity at north pole
|
||||||
|
result.Y = 2.0f * Math.Atan2(q.X,q.W);
|
||||||
|
result.Z = Math.PI_f / 2.0f;
|
||||||
|
result.X = 0.0f;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if (test < -0.4999f*unit) { // singularity at south pole
|
||||||
|
result.Y = -2.0f * Math.Atan2(q.X,q.W);
|
||||||
|
result.Z = -Math.PI_f / 2.0f;
|
||||||
|
result.X = 0.0f;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
result.Y = Math.Atan2(2*q.Y*q.W-2*q.X*q.Z , sqx - sqy - sqz + sqw);
|
||||||
|
result.Z = Math.Asin(2*test/unit);
|
||||||
|
result.X = Math.Atan2(2*q.X*q.W-2*q.Y*q.Z , -sqx + sqy - sqz + sqw);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
//return .(q.Pitch(), q.Yaw(), q.Roll());
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
public float Pitch()
|
||||||
|
{
|
||||||
|
float y = 2.0f * (Y * Z + W * X);
|
||||||
|
float x = W * W - X * X - Y * Y + Z * Z;
|
||||||
|
|
||||||
|
if (Vector2(x, y).Equals(.Zero)) //avoid atan2(0,0) - handle singularity - Matiis
|
||||||
|
return 2.0f * Math.Atan2(X, W);
|
||||||
|
|
||||||
|
return Math.Atan2(y, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float Yaw()
|
||||||
|
{
|
||||||
|
return Math.Asin(Math.Clamp(-2.0f * (X * Z - W * Y), -1.0f, 1.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
public float Roll()
|
||||||
|
{
|
||||||
|
float y = 2.0f * (X * Y + W * Z);
|
||||||
|
float x = W * W + X * X - Y * Y - Z * Z;
|
||||||
|
|
||||||
|
if (Vector2(x, y).Equals(.Zero)) //avoid atan2(0,0) - handle singularity - Matiis
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return Math.Atan2(y, x);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
namespace GlitchyEngine.Math
|
|
||||||
{
|
|
||||||
struct Ray
|
|
||||||
{
|
|
||||||
public Vector3 Start;
|
|
||||||
public Vector3 Direction;
|
|
||||||
|
|
||||||
public this() => this = default;
|
|
||||||
|
|
||||||
public this(Vector3 start, Vector3 direction)
|
|
||||||
{
|
|
||||||
Start = start;
|
|
||||||
Direction = direction;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Math
|
||||||
|
{
|
||||||
|
public struct ResourceBox
|
||||||
|
{
|
||||||
|
/// The x position of the left hand side of the box.
|
||||||
|
public uint32 Left;
|
||||||
|
/// The y position of the top of the box.
|
||||||
|
public uint32 Top;
|
||||||
|
/// The z position of the front of the box.
|
||||||
|
public uint32 Front;
|
||||||
|
/// The x position of the right hand side of the box.
|
||||||
|
public uint32 Right;
|
||||||
|
/// The y position of the bottom of the box.
|
||||||
|
public uint32 Bottom;
|
||||||
|
/// The z position of the back of the box.
|
||||||
|
public uint32 Back;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the box is empty.
|
||||||
|
* A box is empty if the top value is greater than or equal to the bottom value,
|
||||||
|
* or the left value is greater than or equal to the right value,
|
||||||
|
* or the front value is greater than or equal to the back value.
|
||||||
|
*/
|
||||||
|
public bool IsEmpty => Top >= Bottom || Left >= Right || Front >= Back;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new instance of an uninitialized Box structure.
|
||||||
|
*/
|
||||||
|
public this()
|
||||||
|
{
|
||||||
|
this = default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new instance of a Box structure that is initialized with the dimensions of a box.
|
||||||
|
*/
|
||||||
|
public this(uint32 left, uint32 top, uint32 front, uint32 right, uint32 bottom, uint32 back)
|
||||||
|
{
|
||||||
|
Left = left;
|
||||||
|
Top = top;
|
||||||
|
Front = front;
|
||||||
|
Right = right;
|
||||||
|
Bottom = bottom;
|
||||||
|
Back = back;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Inline]
|
||||||
|
public static bool operator ==(ResourceBox l, ResourceBox r)
|
||||||
|
{
|
||||||
|
return l.Left == r.Left && l.Top == r.Top && l.Front == r.Front &&
|
||||||
|
l.Right == r.Right && l.Bottom == r.Bottom && l.Back == r.Back;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Inline]
|
||||||
|
public static bool operator !=(ResourceBox l, ResourceBox r)
|
||||||
|
{
|
||||||
|
return !(l == r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,9 +21,9 @@ namespace GlitchyEngine.Math
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines whether or not a swizzle operator can have a valid setter (e.g. no component assigned twice)
|
* Returns true if the swizzle operator is invalid (same component assigned twice).
|
||||||
*/
|
*/
|
||||||
static bool invalidSetter(int[4] cmp, int vecSize)
|
static bool IsSetterValid(int[4] cmp, int vecSize)
|
||||||
{
|
{
|
||||||
return cmp[0] == cmp[1] || (vecSize >= 3 && cmp[0] == cmp[2]) || (vecSize == 4 && cmp[0] == cmp[3]) ||
|
return cmp[0] == cmp[1] || (vecSize >= 3 && cmp[0] == cmp[2]) || (vecSize == 4 && cmp[0] == cmp[3]) ||
|
||||||
(vecSize >= 3 && cmp[1] == cmp[2]) || (vecSize == 4 && cmp[1] == cmp[3]) ||
|
(vecSize >= 3 && cmp[1] == cmp[2]) || (vecSize == 4 && cmp[1] == cmp[3]) ||
|
||||||
@@ -49,9 +49,18 @@ namespace GlitchyEngine.Math
|
|||||||
{
|
{
|
||||||
String swizzleName = scope String(swizzleCount);
|
String swizzleName = scope String(swizzleCount);
|
||||||
String swizzleConstructor = scope String(swizzleCount * 3);
|
String swizzleConstructor = scope String(swizzleCount * 3);
|
||||||
String setter = scope String();
|
String setter = scope String(128);
|
||||||
|
|
||||||
bool setterInvalid = invalidSetter(cmp, swizzleCount);
|
bool setterInvalid = IsSetterValid(cmp, swizzleCount);
|
||||||
|
|
||||||
|
if (!setterInvalid)
|
||||||
|
{
|
||||||
|
setter.Append(
|
||||||
|
"""
|
||||||
|
set mut
|
||||||
|
{
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
|
||||||
for(int c = 0; c < swizzleCount; c++)
|
for(int c = 0; c < swizzleCount; c++)
|
||||||
{
|
{
|
||||||
@@ -69,15 +78,20 @@ namespace GlitchyEngine.Math
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//{(setterInvalid ? "[Error(\"Cannot assign multiple values to same component.\")]" : String.Empty)}
|
if (!setterInvalid)
|
||||||
|
{
|
||||||
|
setter.Append(
|
||||||
|
"""
|
||||||
|
|
||||||
|
}
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
|
||||||
String swizzleString = scope $"""
|
String swizzleString = scope $"""
|
||||||
public {_vectorTypeName}{swizzleCount} {swizzleName}
|
public {_vectorTypeName}{swizzleCount} {swizzleName}
|
||||||
{{
|
{{
|
||||||
get => .({swizzleConstructor});
|
get => .({swizzleConstructor});
|
||||||
set mut
|
{setter}
|
||||||
{{{setter}
|
|
||||||
}}
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
""";
|
""";
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ using System;
|
|||||||
|
|
||||||
namespace GlitchyEngine.Math
|
namespace GlitchyEngine.Math
|
||||||
{
|
{
|
||||||
//[SwizzleVector(2, "Vector")]
|
[SwizzleVector(2, "Vector")]
|
||||||
public struct Vector2
|
public struct Vector2
|
||||||
{
|
{
|
||||||
public const Vector2 Zero = .(0f, 0f);
|
public const Vector2 Zero = .(0f, 0f);
|
||||||
@@ -10,7 +10,7 @@ namespace GlitchyEngine.Math
|
|||||||
public const Vector2 UnitY = .(0f, 1f);
|
public const Vector2 UnitY = .(0f, 1f);
|
||||||
public const Vector2 One = .(1f, 1f);
|
public const Vector2 One = .(1f, 1f);
|
||||||
|
|
||||||
public const int Length = 2;
|
public const int ComponentCount = 2;
|
||||||
|
|
||||||
public float X, Y;
|
public float X, Y;
|
||||||
|
|
||||||
@@ -31,18 +31,61 @@ namespace GlitchyEngine.Math
|
|||||||
public ref float this[int index]
|
public ref float this[int index]
|
||||||
{
|
{
|
||||||
[Checked]
|
[Checked]
|
||||||
get
|
get mut
|
||||||
{
|
{
|
||||||
if(index < 0 || index >= Length)
|
if(index < 0 || index >= ComponentCount)
|
||||||
Internal.ThrowIndexOutOfRange(1);
|
Internal.ThrowIndexOutOfRange(1);
|
||||||
|
|
||||||
#unwarn
|
|
||||||
return ref (&X)[index];
|
return ref (&X)[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
[Inline]
|
[Inline]
|
||||||
#unwarn
|
get mut => ref (&X)[index];
|
||||||
get => ref (&X)[index];
|
}
|
||||||
|
|
||||||
|
public float this[int index]
|
||||||
|
{
|
||||||
|
[Checked]
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if(index < 0 || index >= ComponentCount)
|
||||||
|
Internal.ThrowIndexOutOfRange(1);
|
||||||
|
|
||||||
|
if(index == 0)
|
||||||
|
return X;
|
||||||
|
else
|
||||||
|
return Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Inline]
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if(index == 0)
|
||||||
|
return X;
|
||||||
|
else
|
||||||
|
return Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Checked]
|
||||||
|
set mut
|
||||||
|
{
|
||||||
|
if(index < 0 || index >= ComponentCount)
|
||||||
|
Internal.ThrowIndexOutOfRange(1);
|
||||||
|
|
||||||
|
if(index == 0)
|
||||||
|
X = value;
|
||||||
|
else
|
||||||
|
Y = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Inline]
|
||||||
|
set mut
|
||||||
|
{
|
||||||
|
if(index == 0)
|
||||||
|
X = value;
|
||||||
|
else
|
||||||
|
Y = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -90,7 +133,7 @@ namespace GlitchyEngine.Math
|
|||||||
/**
|
/**
|
||||||
* Calculates the projection of a onto b
|
* Calculates the projection of a onto b
|
||||||
*/
|
*/
|
||||||
public Vector2 Project(Vector2 a, Vector2 b)
|
public static Vector2 Project(Vector2 a, Vector2 b)
|
||||||
{
|
{
|
||||||
return (b * (Dot(a, b) / Dot(b, b)));
|
return (b * (Dot(a, b) / Dot(b, b)));
|
||||||
}
|
}
|
||||||
@@ -98,11 +141,33 @@ namespace GlitchyEngine.Math
|
|||||||
/**
|
/**
|
||||||
* Calculates the rejection of a from b
|
* Calculates the rejection of a from b
|
||||||
*/
|
*/
|
||||||
public Vector2 Reject(Vector2 a, Vector2 b)
|
public static Vector2 Reject(Vector2 a, Vector2 b)
|
||||||
{
|
{
|
||||||
return (a - b * (Dot(a, b) / Dot(b, b)));
|
return (a - b * (Dot(a, b) / Dot(b, b)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interpolates linearly between two given vectors.
|
||||||
|
* @param a The first vector.
|
||||||
|
* @param b The second vector.
|
||||||
|
* @param interpolationValue The value that linearly interpolates between a and b.
|
||||||
|
* (0 means a will be returned, 1 means b will be returned.)
|
||||||
|
* @returns The resulting linear interpolation.
|
||||||
|
*/
|
||||||
|
public static Vector2 Lerp(Vector2 a, Vector2 b, float interpolationValue)
|
||||||
|
{
|
||||||
|
return a + interpolationValue * (b - a);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector2 Min(Vector2 a, Vector2 b)
|
||||||
|
{
|
||||||
|
return .(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector2 Max(Vector2 a, Vector2 b)
|
||||||
|
{
|
||||||
|
return .(Math.Max(a.X, b.X), Math.Max(a.Y, b.Y));
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Assignment operators
|
// Assignment operators
|
||||||
@@ -217,14 +282,12 @@ namespace GlitchyEngine.Math
|
|||||||
|
|
||||||
public override void ToString(String strBuffer) => strBuffer.AppendF("X:{0} Y:{1}", X, Y);
|
public override void ToString(String strBuffer) => strBuffer.AppendF("X:{0} Y:{1}", X, Y);
|
||||||
|
|
||||||
// Todo: move to extension
|
|
||||||
[Inline]
|
|
||||||
public static implicit operator DirectX.Math.Vector2(in Self value) => *(DirectX.Math.Vector2*)&value;
|
|
||||||
|
|
||||||
[Inline]
|
|
||||||
public static implicit operator Self(in DirectX.Math.Vector2 value) => *(Self*)&value;
|
|
||||||
|
|
||||||
[Inline]
|
[Inline]
|
||||||
public static explicit operator Self(float value) => Self(value);
|
public static explicit operator Self(float value) => Self(value);
|
||||||
|
|
||||||
|
public bool Equals(Vector2 v, float epsilon = Math.[Friend]sMachineEpsilonFloat)
|
||||||
|
{
|
||||||
|
return (Math.Abs(v.X - X) < epsilon) && (Math.Abs(v.Y - Y) < epsilon);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ using System;
|
|||||||
|
|
||||||
namespace GlitchyEngine.Math
|
namespace GlitchyEngine.Math
|
||||||
{
|
{
|
||||||
//[SwizzleVector(3, "Vector")]
|
[SwizzleVector(3, "Vector")]
|
||||||
public struct Vector3
|
public struct Vector3
|
||||||
{
|
{
|
||||||
public const Vector3 Zero = .(0f, 0f, 0f);
|
public const Vector3 Zero = .(0f, 0f, 0f);
|
||||||
@@ -18,6 +18,8 @@ namespace GlitchyEngine.Math
|
|||||||
public const Vector3 Up = .(0f, 1f, 0f);
|
public const Vector3 Up = .(0f, 1f, 0f);
|
||||||
public const Vector3 Down = .(0f, -1f, 0f);
|
public const Vector3 Down = .(0f, -1f, 0f);
|
||||||
|
|
||||||
|
public const int ComponentCount = 3;
|
||||||
|
|
||||||
public float X, Y, Z;
|
public float X, Y, Z;
|
||||||
|
|
||||||
public this() => this = default;
|
public this() => this = default;
|
||||||
@@ -46,18 +48,41 @@ namespace GlitchyEngine.Math
|
|||||||
public ref float this[int index]
|
public ref float this[int index]
|
||||||
{
|
{
|
||||||
[Checked]
|
[Checked]
|
||||||
get
|
get mut
|
||||||
{
|
{
|
||||||
if(index < 0 || index > 2)
|
if(index < 0 || index >= ComponentCount)
|
||||||
Internal.ThrowIndexOutOfRange();
|
Internal.ThrowIndexOutOfRange(1);
|
||||||
|
|
||||||
#unwarn
|
|
||||||
return ref (&X)[index];
|
return ref (&X)[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
[Inline]
|
[Inline]
|
||||||
#unwarn
|
get mut => ref (&X)[index];
|
||||||
get => ref (&X)[index];
|
}
|
||||||
|
|
||||||
|
public float this[int index]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
switch(index)
|
||||||
|
{
|
||||||
|
case 0: return X;
|
||||||
|
case 1: return Y;
|
||||||
|
case 2: return Z;
|
||||||
|
default: Internal.ThrowIndexOutOfRange(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set mut
|
||||||
|
{
|
||||||
|
switch(index)
|
||||||
|
{
|
||||||
|
case 0: X = value;
|
||||||
|
case 1: Y = value;
|
||||||
|
case 2: Z = value;
|
||||||
|
default: Internal.ThrowIndexOutOfRange(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -156,6 +181,29 @@ namespace GlitchyEngine.Math
|
|||||||
return .(Math.Floor(value.X), Math.Floor(value.Y), Math.Floor(value.Z));
|
return .(Math.Floor(value.X), Math.Floor(value.Y), Math.Floor(value.Z));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interpolates linearly between two given vectors.
|
||||||
|
* @param a The first vector.
|
||||||
|
* @param b The second vector.
|
||||||
|
* @param interpolationValue The value that linearly interpolates between a and b.
|
||||||
|
* (0 means a will be returned, 1 means b will be returned.)
|
||||||
|
* @returns The resulting linear interpolation.
|
||||||
|
*/
|
||||||
|
public static Vector3 Lerp(Vector3 a, Vector3 b, float interpolationValue)
|
||||||
|
{
|
||||||
|
return a + interpolationValue * (b - a);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector3 Min(Vector3 a, Vector3 b)
|
||||||
|
{
|
||||||
|
return .(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y), Math.Min(a.Z, b.Z));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector3 Max(Vector3 a, Vector3 b)
|
||||||
|
{
|
||||||
|
return .(Math.Max(a.X, b.X), Math.Max(a.Y, b.Y), Math.Min(a.Z, b.Z));
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Assignment operators
|
// Assignment operators
|
||||||
//
|
//
|
||||||
@@ -286,14 +334,6 @@ namespace GlitchyEngine.Math
|
|||||||
|
|
||||||
public override void ToString(String strBuffer) => strBuffer.AppendF("X:{0} Y:{1} Z:{2}", X, Y, Z);
|
public override void ToString(String strBuffer) => strBuffer.AppendF("X:{0} Y:{1} Z:{2}", X, Y, Z);
|
||||||
|
|
||||||
// Todo: move to extension
|
|
||||||
|
|
||||||
[Inline]
|
|
||||||
public static implicit operator DirectX.Math.Vector3(in Self value) => *(DirectX.Math.Vector3*)&value;
|
|
||||||
|
|
||||||
[Inline]
|
|
||||||
public static implicit operator Self(in DirectX.Math.Vector3 value) => *(Self*)&value;
|
|
||||||
|
|
||||||
[Inline]
|
[Inline]
|
||||||
public static explicit operator Self(float value) => Self(value);
|
public static explicit operator Self(float value) => Self(value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ using System;
|
|||||||
|
|
||||||
namespace GlitchyEngine.Math
|
namespace GlitchyEngine.Math
|
||||||
{
|
{
|
||||||
//[SwizzleVector(4, "Vector")]
|
[SwizzleVector(4, "Vector")]
|
||||||
public struct Vector4
|
public struct Vector4
|
||||||
{
|
{
|
||||||
public const Vector4 Zero = .(0f, 0f, 0f, 0f);
|
public const Vector4 Zero = .(0f, 0f, 0f, 0f);
|
||||||
@@ -12,6 +12,8 @@ namespace GlitchyEngine.Math
|
|||||||
public const Vector4 UnitW = .(0f, 0f, 0f, 1f);
|
public const Vector4 UnitW = .(0f, 0f, 0f, 1f);
|
||||||
public const Vector4 One = .(1f, 1f, 1f, 1f);
|
public const Vector4 One = .(1f, 1f, 1f, 1f);
|
||||||
|
|
||||||
|
public const int ComponentCount = 4;
|
||||||
|
|
||||||
public float X, Y, Z, W;
|
public float X, Y, Z, W;
|
||||||
|
|
||||||
public this() => this = default;
|
public this() => this = default;
|
||||||
@@ -59,17 +61,43 @@ namespace GlitchyEngine.Math
|
|||||||
public ref float this[int index]
|
public ref float this[int index]
|
||||||
{
|
{
|
||||||
[Checked]
|
[Checked]
|
||||||
get
|
get mut
|
||||||
{
|
{
|
||||||
if(index < 0 || index > 3)
|
if(index < 0 || index >= ComponentCount)
|
||||||
Internal.ThrowIndexOutOfRange();
|
Internal.ThrowIndexOutOfRange(1);
|
||||||
#unwarn
|
|
||||||
return ref (&X)[index];
|
return ref (&X)[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
[Inline]
|
[Inline]
|
||||||
#unwarn
|
get mut => ref (&X)[index];
|
||||||
get => ref (&X)[index];
|
}
|
||||||
|
|
||||||
|
public float this[int index]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
switch(index)
|
||||||
|
{
|
||||||
|
case 0: return X;
|
||||||
|
case 1: return Y;
|
||||||
|
case 2: return Z;
|
||||||
|
case 3: return W;
|
||||||
|
default: Internal.ThrowIndexOutOfRange(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set mut
|
||||||
|
{
|
||||||
|
switch(index)
|
||||||
|
{
|
||||||
|
case 0: X = value;
|
||||||
|
case 1: Y = value;
|
||||||
|
case 2: Z = value;
|
||||||
|
case 3: W = value;
|
||||||
|
default: Internal.ThrowIndexOutOfRange(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -138,6 +166,29 @@ namespace GlitchyEngine.Math
|
|||||||
return (a - b * (Dot(a, b) / Dot(b, b)));
|
return (a - b * (Dot(a, b) / Dot(b, b)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interpolates linearly between two given vectors.
|
||||||
|
* @param a The first vector.
|
||||||
|
* @param b The second vector.
|
||||||
|
* @param interpolationValue The value that linearly interpolates between a and b.
|
||||||
|
* (0 means a will be returned, 1 means b will be returned.)
|
||||||
|
* @returns The resulting linear interpolation.
|
||||||
|
*/
|
||||||
|
public static Vector4 Lerp(Vector4 a, Vector4 b, float interpolationValue)
|
||||||
|
{
|
||||||
|
return a + interpolationValue * (b - a);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector4 Min(Vector4 a, Vector4 b)
|
||||||
|
{
|
||||||
|
return .(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y), Math.Min(a.Z, b.Z), Math.Min(a.W, b.W));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector4 Max(Vector4 a, Vector4 b)
|
||||||
|
{
|
||||||
|
return .(Math.Max(a.X, b.X), Math.Max(a.Y, b.Y), Math.Min(a.Z, b.Z), Math.Min(a.W, b.W));
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Assignment operators
|
// Assignment operators
|
||||||
//
|
//
|
||||||
@@ -267,14 +318,6 @@ namespace GlitchyEngine.Math
|
|||||||
|
|
||||||
public override void ToString(String strBuffer) => strBuffer.AppendF("X:{0} Y:{1} Z:{2} W:{3}", X, Y, Z, W);
|
public override void ToString(String strBuffer) => strBuffer.AppendF("X:{0} Y:{1} Z:{2} W:{3}", X, Y, Z, W);
|
||||||
|
|
||||||
// Todo: move to extension
|
|
||||||
|
|
||||||
[Inline]
|
|
||||||
public static implicit operator DirectX.Math.Vector4(in Self value) => *(DirectX.Math.Vector4*)&value;
|
|
||||||
|
|
||||||
[Inline]
|
|
||||||
public static implicit operator Self(in DirectX.Math.Vector4 value) => *(Self*)&value;
|
|
||||||
|
|
||||||
[Inline]
|
[Inline]
|
||||||
public static explicit operator Self(float value) => Self(value);
|
public static explicit operator Self(float value) => Self(value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,162 @@
|
|||||||
|
#pragma warning disable 4204
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Math
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* A Vector with two components of type int32.
|
||||||
|
*/
|
||||||
|
[SwizzleVector(2, "Int")]
|
||||||
|
public struct Int2 : IHashable
|
||||||
|
{
|
||||||
|
public const Int2 Zero = .(0, 0);
|
||||||
|
public const Int2 UnitX = .(1, 0);
|
||||||
|
public const Int2 UnitY = .(0, 1);
|
||||||
|
public const Int2 One = .(1, 1);
|
||||||
|
|
||||||
|
public int32 X, Y;
|
||||||
|
|
||||||
|
public this() => this = default;
|
||||||
|
|
||||||
|
public this(int32 value)
|
||||||
|
{
|
||||||
|
X = value;
|
||||||
|
Y = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public this(int value)
|
||||||
|
{
|
||||||
|
X = (.)value;
|
||||||
|
Y = (.)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public this(int32 x, int32 y)
|
||||||
|
{
|
||||||
|
X = x;
|
||||||
|
Y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public this(int x, int y)
|
||||||
|
{
|
||||||
|
X = (.)x;
|
||||||
|
Y = (.)y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ref int32 this[int index]
|
||||||
|
{
|
||||||
|
[Inline]
|
||||||
|
get
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
if(index < 0 || index >= 2)
|
||||||
|
Internal.ThrowIndexOutOfRange(1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ref (&X)[index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int32 MagnitudeSquared() => X * X + Y * Y;
|
||||||
|
|
||||||
|
public float Magnitude() => Math.Sqrt(X * X + Y * Y);
|
||||||
|
|
||||||
|
public Int2 Abs() => .(Math.Abs(X), Math.Abs(Y));
|
||||||
|
|
||||||
|
//
|
||||||
|
// Assignment operators
|
||||||
|
//
|
||||||
|
|
||||||
|
public void operator +=(Int2 value) mut
|
||||||
|
{
|
||||||
|
X += value.X;
|
||||||
|
Y += value.Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void operator +=(int32 value) mut
|
||||||
|
{
|
||||||
|
X += value;
|
||||||
|
Y += value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void operator -=(Int2 value) mut
|
||||||
|
{
|
||||||
|
X -= value.X;
|
||||||
|
Y -= value.Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void operator -=(int32 value) mut
|
||||||
|
{
|
||||||
|
X -= value;
|
||||||
|
Y -= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void operator *=(Int2 value) mut
|
||||||
|
{
|
||||||
|
X *= value.X;
|
||||||
|
Y *= value.Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void operator *=(int32 value) mut
|
||||||
|
{
|
||||||
|
X *= value;
|
||||||
|
Y *= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void operator /=(Int2 value) mut
|
||||||
|
{
|
||||||
|
X /= value.X;
|
||||||
|
Y /= value.Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void operator /=(int32 value) mut
|
||||||
|
{
|
||||||
|
X /= value;
|
||||||
|
Y /= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Operators
|
||||||
|
|
||||||
|
public static Int2 operator +(Int2 value) => value;
|
||||||
|
public static Int2 operator +(Int2 left, Int2 right) => .(left.X + right.X, left.Y + right.Y);
|
||||||
|
public static Int2 operator +(Int2 left, int32 right) => .(left.X + right, left.Y + right);
|
||||||
|
public static Int2 operator +(int32 left, Int2 right) => .(left + right.X, left + right.Y);
|
||||||
|
|
||||||
|
public static Int2 operator -(Int2 value) => .(-value.X, -value.Y);
|
||||||
|
public static Int2 operator -(Int2 left, Int2 right) => .(left.X - right.X, left.Y - right.Y);
|
||||||
|
public static Int2 operator -(Int2 left, int32 right) => .(left.X - right, left.Y - right);
|
||||||
|
public static Int2 operator -(int32 left, Int2 right) => .(left - right.X, left - right.Y);
|
||||||
|
|
||||||
|
public static Int2 operator *(Int2 left, Int2 right) => .(left.X * right.X, left.Y * right.Y);
|
||||||
|
public static Int2 operator *(Int2 left, int32 right) => .(left.X * right, left.Y * right);
|
||||||
|
public static Int2 operator *(int32 left, Int2 right) => .(left * right.X, left * right.Y);
|
||||||
|
|
||||||
|
public static Int2 operator /(Int2 left, Int2 right) => .(left.X / right.X, left.Y / right.Y);
|
||||||
|
public static Int2 operator /(Int2 left, int32 right) => .(left.X / right, left.Y / right);
|
||||||
|
public static Int2 operator /(int32 left, Int2 right) => .(left / right.X, left / right.Y);
|
||||||
|
|
||||||
|
public static Int2 operator %(Int2 left, Int2 right) => .(left.X % right.X, left.Y % right.Y);
|
||||||
|
public static Int2 operator %(Int2 left, int32 right) => .(left.X % right, left.Y % right);
|
||||||
|
public static Int2 operator %(int32 left, Int2 right) => .(left % right.X, left % right.Y);
|
||||||
|
|
||||||
|
public static bool operator ==(Int2 left, Int2 right) => left.X == right.X && left.Y == right.Y;
|
||||||
|
public static bool operator ==(Int2 left, int32 right) => left.X == right && left.Y == right;
|
||||||
|
public static bool operator ==(int32 left, Int2 right) => left == right.X && left == right.Y;
|
||||||
|
|
||||||
|
public static bool operator !=(Int2 left, Int2 right) => left.X != right.X || left.Y != right.Y;
|
||||||
|
public static bool operator !=(Int2 left, int32 right) => left.X != right || left.Y != right;
|
||||||
|
public static bool operator !=(int32 left, Int2 right) => left != right.X || left != right.Y;
|
||||||
|
|
||||||
|
public override void ToString(String strBuffer) => strBuffer.AppendF($"X:{X} Y:{Y}");
|
||||||
|
|
||||||
|
public static explicit operator Vector2(Int2 point) => .(point.X, point.Y);
|
||||||
|
|
||||||
|
public static explicit operator Int2(Vector2 point) => .((int32)point.X, (int32)point.Y);
|
||||||
|
|
||||||
|
public int GetHashCode()
|
||||||
|
{
|
||||||
|
return (X * 39) ^ Y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,206 @@
|
|||||||
|
#pragma warning disable 4204
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Math
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* A Vector with three components of type int32.
|
||||||
|
*/
|
||||||
|
[SwizzleVector(3, "Int")]
|
||||||
|
public struct Int3 : IHashable
|
||||||
|
{
|
||||||
|
public const Int3 Zero = .(0, 0, 0);
|
||||||
|
public const Int3 UnitX = .(1, 0, 0);
|
||||||
|
public const Int3 UnitY = .(0, 1, 0);
|
||||||
|
public const Int3 UnitZ = .(0, 0, 1);
|
||||||
|
public const Int3 One = .(1, 1, 1);
|
||||||
|
|
||||||
|
public int32 X, Y, Z;
|
||||||
|
|
||||||
|
public this() => this = default;
|
||||||
|
|
||||||
|
public this(int32 value)
|
||||||
|
{
|
||||||
|
X = value;
|
||||||
|
Y = value;
|
||||||
|
Z = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public this(int value)
|
||||||
|
{
|
||||||
|
X = (.)value;
|
||||||
|
Y = (.)value;
|
||||||
|
Z = (.)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public this(int32 x, int32 y, int32 z)
|
||||||
|
{
|
||||||
|
X = x;
|
||||||
|
Y = y;
|
||||||
|
Z = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public this(Int2 xy, int32 z)
|
||||||
|
{
|
||||||
|
X = xy.X;
|
||||||
|
Y = xy.Y;
|
||||||
|
Z = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public this(int32 x, Int2 yz)
|
||||||
|
{
|
||||||
|
X = x;
|
||||||
|
Y = yz.X;
|
||||||
|
Z = yz.Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public this(int x, int y, int z)
|
||||||
|
{
|
||||||
|
X = (.)x;
|
||||||
|
Y = (.)y;
|
||||||
|
Z = (.)z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public this(Int2 xy, int z)
|
||||||
|
{
|
||||||
|
X = xy.X;
|
||||||
|
Y = xy.Y;
|
||||||
|
Z = (.)z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public this(int x, Int2 yz)
|
||||||
|
{
|
||||||
|
X = (.)x;
|
||||||
|
Y = yz.X;
|
||||||
|
Z = yz.Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ref int32 this[int index]
|
||||||
|
{
|
||||||
|
[Inline]
|
||||||
|
get
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
if(index < 0 || index >= 3)
|
||||||
|
Internal.ThrowIndexOutOfRange(1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ref (&X)[index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int32 MagnitudeSquared() => X * X + Y * Y + Z * Z;
|
||||||
|
|
||||||
|
public float Magnitude() => Math.Sqrt(X * X + Y * Y + Z * Z);
|
||||||
|
|
||||||
|
public Int3 Abs() => .(Math.Abs(X), Math.Abs(Y), Math.Abs(Z));
|
||||||
|
|
||||||
|
//
|
||||||
|
// Assignment operators
|
||||||
|
//
|
||||||
|
|
||||||
|
public void operator +=(Int3 value) mut
|
||||||
|
{
|
||||||
|
X += value.X;
|
||||||
|
Y += value.Y;
|
||||||
|
Z += value.Z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void operator +=(int32 value) mut
|
||||||
|
{
|
||||||
|
X += value;
|
||||||
|
Y += value;
|
||||||
|
Z += value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void operator -=(Int3 value) mut
|
||||||
|
{
|
||||||
|
X -= value.X;
|
||||||
|
Y -= value.Y;
|
||||||
|
Z -= value.Z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void operator -=(int32 value) mut
|
||||||
|
{
|
||||||
|
X -= value;
|
||||||
|
Y -= value;
|
||||||
|
Z -= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void operator *=(Int3 value) mut
|
||||||
|
{
|
||||||
|
X *= value.X;
|
||||||
|
Y *= value.Y;
|
||||||
|
Z *= value.Z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void operator *=(int32 value) mut
|
||||||
|
{
|
||||||
|
X *= value;
|
||||||
|
Y *= value;
|
||||||
|
Z *= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void operator /=(Int3 value) mut
|
||||||
|
{
|
||||||
|
X /= value.X;
|
||||||
|
Y /= value.Y;
|
||||||
|
Z /= value.Z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void operator /=(int32 value) mut
|
||||||
|
{
|
||||||
|
X /= value;
|
||||||
|
Y /= value;
|
||||||
|
Z /= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Operators
|
||||||
|
|
||||||
|
public static Int3 operator +(Int3 value) => value;
|
||||||
|
public static Int3 operator +(Int3 left, Int3 right) => .(left.X + right.X, left.Y + right.Y, left.Z + right.Z);
|
||||||
|
public static Int3 operator +(Int3 left, int32 right) => .(left.X + right, left.Y + right, left.Z + right);
|
||||||
|
public static Int3 operator +(int32 left, Int3 right) => .(left + right.X, left + right.Y, left + right.Z);
|
||||||
|
|
||||||
|
public static Int3 operator -(Int3 value) => .(-value.X, -value.Y, -value.Z);
|
||||||
|
public static Int3 operator -(Int3 left, Int3 right) => .(left.X - right.X, left.Y - right.Y, left.Z - right.Z);
|
||||||
|
public static Int3 operator -(Int3 left, int32 right) => .(left.X - right, left.Y - right, left.Z- right);
|
||||||
|
public static Int3 operator -(int32 left, Int3 right) => .(left - right.X, left - right.Y, left - right.Z);
|
||||||
|
|
||||||
|
public static Int3 operator *(Int3 left, Int3 right) => .(left.X * right.X, left.Y * right.Y, left.Z * right.Z);
|
||||||
|
public static Int3 operator *(Int3 left, int32 right) => .(left.X * right, left.Y * right, left.Z * right);
|
||||||
|
public static Int3 operator *(int32 left, Int3 right) => .(left * right.X, left * right.Y, left * right.Z);
|
||||||
|
|
||||||
|
public static Int3 operator /(Int3 left, Int3 right) => .(left.X / right.X, left.Y / right.Y, left.Z / right.Z);
|
||||||
|
public static Int3 operator /(Int3 left, int32 right) => .(left.X / right, left.Y / right, left.Z / right);
|
||||||
|
public static Int3 operator /(int32 left, Int3 right) => .(left / right.X, left / right.Y, left / right.Z);
|
||||||
|
|
||||||
|
public static Int3 operator %(Int3 left, Int3 right) => .(left.X % right.X, left.Y % right.Y, left.Z % right.Z);
|
||||||
|
public static Int3 operator %(Int3 left, int32 right) => .(left.X % right, left.Y % right, left.Z % right);
|
||||||
|
public static Int3 operator %(int32 left, Int3 right) => .(left % right.X, left % right.Y, left % right.Z);
|
||||||
|
|
||||||
|
public static bool operator ==(Int3 left, Int3 right) => left.X == right.X && left.Y == right.Y && left.Z == right.Z;
|
||||||
|
public static bool operator ==(Int3 left, int32 right) => left.X == right && left.Y == right && left.Z == right;
|
||||||
|
public static bool operator ==(int32 left, Int3 right) => left == right.X && left == right.Y && left == right.Z;
|
||||||
|
|
||||||
|
public static bool operator !=(Int3 left, Int3 right) => left.X != right.X || left.Y != right.Y || left.Z != right.Z;
|
||||||
|
public static bool operator !=(Int3 left, int32 right) => left.X != right || left.Y != right || left.Z != right;
|
||||||
|
public static bool operator !=(int32 left, Int3 right) => left != right.X || left != right.Y || left != right.Z;
|
||||||
|
|
||||||
|
public override void ToString(String strBuffer) => strBuffer.AppendF($"X:{X} Y:{Y} Z:{Z}");
|
||||||
|
|
||||||
|
public static explicit operator Vector3(Int3 point) => .(point.X, point.Y, point.Z);
|
||||||
|
|
||||||
|
public static explicit operator Int3(Vector3 point) => .((int32)point.X, (int32)point.Y, (int32)point.Z);
|
||||||
|
|
||||||
|
[Inline]
|
||||||
|
public static explicit operator Int2(in Int3 point) => *(Int2*)&point;
|
||||||
|
|
||||||
|
public int GetHashCode()
|
||||||
|
{
|
||||||
|
return (((X * 39) ^ Y) * 39) ^ Z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,162 +0,0 @@
|
|||||||
#pragma warning disable 4204
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
|
|
||||||
namespace GlitchyEngine.Math
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* A Vector with two components of type int32.
|
|
||||||
*/
|
|
||||||
[SwizzleVector(2, "Int32_")]
|
|
||||||
public struct Int32_2 : IHashable
|
|
||||||
{
|
|
||||||
public const Int32_2 Zero = .(0, 0);
|
|
||||||
public const Int32_2 UnitX = .(1, 0);
|
|
||||||
public const Int32_2 UnitY = .(0, 1);
|
|
||||||
public const Int32_2 One = .(1, 1);
|
|
||||||
|
|
||||||
public int32 X, Y;
|
|
||||||
|
|
||||||
public this() => this = default;
|
|
||||||
|
|
||||||
public this(int32 value)
|
|
||||||
{
|
|
||||||
X = value;
|
|
||||||
Y = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(int value)
|
|
||||||
{
|
|
||||||
X = (.)value;
|
|
||||||
Y = (.)value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(int32 x, int32 y)
|
|
||||||
{
|
|
||||||
X = x;
|
|
||||||
Y = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(int x, int y)
|
|
||||||
{
|
|
||||||
X = (.)x;
|
|
||||||
Y = (.)y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ref int32 this[int index]
|
|
||||||
{
|
|
||||||
[Inline]
|
|
||||||
get
|
|
||||||
{
|
|
||||||
#if DEBUG
|
|
||||||
if(index < 0 || index >= 2)
|
|
||||||
Internal.ThrowIndexOutOfRange(1);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return ref (&X)[index];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int32 MagnitudeSquared() => X * X + Y * Y;
|
|
||||||
|
|
||||||
public float Magnitude() => Math.Sqrt(X * X + Y * Y);
|
|
||||||
|
|
||||||
public Int32_2 Abs() => .(Math.Abs(X), Math.Abs(Y));
|
|
||||||
|
|
||||||
//
|
|
||||||
// Assignment operators
|
|
||||||
//
|
|
||||||
|
|
||||||
public void operator +=(Int32_2 value) mut
|
|
||||||
{
|
|
||||||
X += value.X;
|
|
||||||
Y += value.Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator +=(int32 value) mut
|
|
||||||
{
|
|
||||||
X += value;
|
|
||||||
Y += value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator -=(Int32_2 value) mut
|
|
||||||
{
|
|
||||||
X -= value.X;
|
|
||||||
Y -= value.Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator -=(int32 value) mut
|
|
||||||
{
|
|
||||||
X -= value;
|
|
||||||
Y -= value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator *=(Int32_2 value) mut
|
|
||||||
{
|
|
||||||
X *= value.X;
|
|
||||||
Y *= value.Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator *=(int32 value) mut
|
|
||||||
{
|
|
||||||
X *= value;
|
|
||||||
Y *= value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator /=(Int32_2 value) mut
|
|
||||||
{
|
|
||||||
X /= value.X;
|
|
||||||
Y /= value.Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator /=(int32 value) mut
|
|
||||||
{
|
|
||||||
X /= value;
|
|
||||||
Y /= value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Operators
|
|
||||||
|
|
||||||
public static Int32_2 operator +(Int32_2 value) => value;
|
|
||||||
public static Int32_2 operator +(Int32_2 left, Int32_2 right) => .(left.X + right.X, left.Y + right.Y);
|
|
||||||
public static Int32_2 operator +(Int32_2 left, int32 right) => .(left.X + right, left.Y + right);
|
|
||||||
public static Int32_2 operator +(int32 left, Int32_2 right) => .(left + right.X, left + right.Y);
|
|
||||||
|
|
||||||
public static Int32_2 operator -(Int32_2 value) => .(-value.X, -value.Y);
|
|
||||||
public static Int32_2 operator -(Int32_2 left, Int32_2 right) => .(left.X - right.X, left.Y - right.Y);
|
|
||||||
public static Int32_2 operator -(Int32_2 left, int32 right) => .(left.X - right, left.Y - right);
|
|
||||||
public static Int32_2 operator -(int32 left, Int32_2 right) => .(left - right.X, left - right.Y);
|
|
||||||
|
|
||||||
public static Int32_2 operator *(Int32_2 left, Int32_2 right) => .(left.X * right.X, left.Y * right.Y);
|
|
||||||
public static Int32_2 operator *(Int32_2 left, int32 right) => .(left.X * right, left.Y * right);
|
|
||||||
public static Int32_2 operator *(int32 left, Int32_2 right) => .(left * right.X, left * right.Y);
|
|
||||||
|
|
||||||
public static Int32_2 operator /(Int32_2 left, Int32_2 right) => .(left.X / right.X, left.Y / right.Y);
|
|
||||||
public static Int32_2 operator /(Int32_2 left, int32 right) => .(left.X / right, left.Y / right);
|
|
||||||
public static Int32_2 operator /(int32 left, Int32_2 right) => .(left / right.X, left / right.Y);
|
|
||||||
|
|
||||||
public static Int32_2 operator %(Int32_2 left, Int32_2 right) => .(left.X % right.X, left.Y % right.Y);
|
|
||||||
public static Int32_2 operator %(Int32_2 left, int32 right) => .(left.X % right, left.Y % right);
|
|
||||||
public static Int32_2 operator %(int32 left, Int32_2 right) => .(left % right.X, left % right.Y);
|
|
||||||
|
|
||||||
public static bool operator ==(Int32_2 left, Int32_2 right) => left.X == right.X && left.Y == right.Y;
|
|
||||||
public static bool operator ==(Int32_2 left, int32 right) => left.X == right && left.Y == right;
|
|
||||||
public static bool operator ==(int32 left, Int32_2 right) => left == right.X && left == right.Y;
|
|
||||||
|
|
||||||
public static bool operator !=(Int32_2 left, Int32_2 right) => left.X != right.X || left.Y != right.Y;
|
|
||||||
public static bool operator !=(Int32_2 left, int32 right) => left.X != right || left.Y != right;
|
|
||||||
public static bool operator !=(int32 left, Int32_2 right) => left != right.X || left != right.Y;
|
|
||||||
|
|
||||||
public override void ToString(String strBuffer) => strBuffer.AppendF($"X:{X} Y:{Y}");
|
|
||||||
|
|
||||||
public static explicit operator Vector2(Int32_2 point) => .(point.X, point.Y);
|
|
||||||
|
|
||||||
public static explicit operator Int32_2(Vector2 point) => .((int32)point.X, (int32)point.Y);
|
|
||||||
|
|
||||||
public int GetHashCode()
|
|
||||||
{
|
|
||||||
return (X * 39) ^ Y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,206 +0,0 @@
|
|||||||
#pragma warning disable 4204
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
|
|
||||||
namespace GlitchyEngine.Math
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* A Vector with three components of type int32.
|
|
||||||
*/
|
|
||||||
[SwizzleVector(3, "Int32_")]
|
|
||||||
public struct Int32_3 : IHashable
|
|
||||||
{
|
|
||||||
public const Int32_3 Zero = .(0, 0, 0);
|
|
||||||
public const Int32_3 UnitX = .(1, 0, 0);
|
|
||||||
public const Int32_3 UnitY = .(0, 1, 0);
|
|
||||||
public const Int32_3 UnitZ = .(0, 0, 1);
|
|
||||||
public const Int32_3 One = .(1, 1, 1);
|
|
||||||
|
|
||||||
public int32 X, Y, Z;
|
|
||||||
|
|
||||||
public this() => this = default;
|
|
||||||
|
|
||||||
public this(int32 value)
|
|
||||||
{
|
|
||||||
X = value;
|
|
||||||
Y = value;
|
|
||||||
Z = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(int value)
|
|
||||||
{
|
|
||||||
X = (.)value;
|
|
||||||
Y = (.)value;
|
|
||||||
Z = (.)value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(int32 x, int32 y, int32 z)
|
|
||||||
{
|
|
||||||
X = x;
|
|
||||||
Y = y;
|
|
||||||
Z = z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(Int32_2 xy, int32 z)
|
|
||||||
{
|
|
||||||
X = xy.X;
|
|
||||||
Y = xy.Y;
|
|
||||||
Z = z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(int32 x, Int32_2 yz)
|
|
||||||
{
|
|
||||||
X = x;
|
|
||||||
Y = yz.X;
|
|
||||||
Z = yz.Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(int x, int y, int z)
|
|
||||||
{
|
|
||||||
X = (.)x;
|
|
||||||
Y = (.)y;
|
|
||||||
Z = (.)z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(Int32_2 xy, int z)
|
|
||||||
{
|
|
||||||
X = xy.X;
|
|
||||||
Y = xy.Y;
|
|
||||||
Z = (.)z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(int x, Int32_2 yz)
|
|
||||||
{
|
|
||||||
X = (.)x;
|
|
||||||
Y = yz.X;
|
|
||||||
Z = yz.Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ref int32 this[int index]
|
|
||||||
{
|
|
||||||
[Inline]
|
|
||||||
get
|
|
||||||
{
|
|
||||||
#if DEBUG
|
|
||||||
if(index < 0 || index >= 3)
|
|
||||||
Internal.ThrowIndexOutOfRange(1);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return ref (&X)[index];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int32 MagnitudeSquared() => X * X + Y * Y + Z * Z;
|
|
||||||
|
|
||||||
public float Magnitude() => Math.Sqrt(X * X + Y * Y + Z * Z);
|
|
||||||
|
|
||||||
public Int32_3 Abs() => .(Math.Abs(X), Math.Abs(Y), Math.Abs(Z));
|
|
||||||
|
|
||||||
//
|
|
||||||
// Assignment operators
|
|
||||||
//
|
|
||||||
|
|
||||||
public void operator +=(Int32_3 value) mut
|
|
||||||
{
|
|
||||||
X += value.X;
|
|
||||||
Y += value.Y;
|
|
||||||
Z += value.Z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator +=(int32 value) mut
|
|
||||||
{
|
|
||||||
X += value;
|
|
||||||
Y += value;
|
|
||||||
Z += value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator -=(Int32_3 value) mut
|
|
||||||
{
|
|
||||||
X -= value.X;
|
|
||||||
Y -= value.Y;
|
|
||||||
Z -= value.Z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator -=(int32 value) mut
|
|
||||||
{
|
|
||||||
X -= value;
|
|
||||||
Y -= value;
|
|
||||||
Z -= value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator *=(Int32_3 value) mut
|
|
||||||
{
|
|
||||||
X *= value.X;
|
|
||||||
Y *= value.Y;
|
|
||||||
Z *= value.Z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator *=(int32 value) mut
|
|
||||||
{
|
|
||||||
X *= value;
|
|
||||||
Y *= value;
|
|
||||||
Z *= value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator /=(Int32_3 value) mut
|
|
||||||
{
|
|
||||||
X /= value.X;
|
|
||||||
Y /= value.Y;
|
|
||||||
Z /= value.Z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator /=(int32 value) mut
|
|
||||||
{
|
|
||||||
X /= value;
|
|
||||||
Y /= value;
|
|
||||||
Z /= value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Operators
|
|
||||||
|
|
||||||
public static Int32_3 operator +(Int32_3 value) => value;
|
|
||||||
public static Int32_3 operator +(Int32_3 left, Int32_3 right) => .(left.X + right.X, left.Y + right.Y, left.Z + right.Z);
|
|
||||||
public static Int32_3 operator +(Int32_3 left, int32 right) => .(left.X + right, left.Y + right, left.Z + right);
|
|
||||||
public static Int32_3 operator +(int32 left, Int32_3 right) => .(left + right.X, left + right.Y, left + right.Z);
|
|
||||||
|
|
||||||
public static Int32_3 operator -(Int32_3 value) => .(-value.X, -value.Y, -value.Z);
|
|
||||||
public static Int32_3 operator -(Int32_3 left, Int32_3 right) => .(left.X - right.X, left.Y - right.Y, left.Z - right.Z);
|
|
||||||
public static Int32_3 operator -(Int32_3 left, int32 right) => .(left.X - right, left.Y - right, left.Z- right);
|
|
||||||
public static Int32_3 operator -(int32 left, Int32_3 right) => .(left - right.X, left - right.Y, left - right.Z);
|
|
||||||
|
|
||||||
public static Int32_3 operator *(Int32_3 left, Int32_3 right) => .(left.X * right.X, left.Y * right.Y, left.Z * right.Z);
|
|
||||||
public static Int32_3 operator *(Int32_3 left, int32 right) => .(left.X * right, left.Y * right, left.Z * right);
|
|
||||||
public static Int32_3 operator *(int32 left, Int32_3 right) => .(left * right.X, left * right.Y, left * right.Z);
|
|
||||||
|
|
||||||
public static Int32_3 operator /(Int32_3 left, Int32_3 right) => .(left.X / right.X, left.Y / right.Y, left.Z / right.Z);
|
|
||||||
public static Int32_3 operator /(Int32_3 left, int32 right) => .(left.X / right, left.Y / right, left.Z / right);
|
|
||||||
public static Int32_3 operator /(int32 left, Int32_3 right) => .(left / right.X, left / right.Y, left / right.Z);
|
|
||||||
|
|
||||||
public static Int32_3 operator %(Int32_3 left, Int32_3 right) => .(left.X % right.X, left.Y % right.Y, left.Z % right.Z);
|
|
||||||
public static Int32_3 operator %(Int32_3 left, int32 right) => .(left.X % right, left.Y % right, left.Z % right);
|
|
||||||
public static Int32_3 operator %(int32 left, Int32_3 right) => .(left % right.X, left % right.Y, left % right.Z);
|
|
||||||
|
|
||||||
public static bool operator ==(Int32_3 left, Int32_3 right) => left.X == right.X && left.Y == right.Y && left.Z == right.Z;
|
|
||||||
public static bool operator ==(Int32_3 left, int32 right) => left.X == right && left.Y == right && left.Z == right;
|
|
||||||
public static bool operator ==(int32 left, Int32_3 right) => left == right.X && left == right.Y && left == right.Z;
|
|
||||||
|
|
||||||
public static bool operator !=(Int32_3 left, Int32_3 right) => left.X != right.X || left.Y != right.Y || left.Z != right.Z;
|
|
||||||
public static bool operator !=(Int32_3 left, int32 right) => left.X != right || left.Y != right || left.Z != right;
|
|
||||||
public static bool operator !=(int32 left, Int32_3 right) => left != right.X || left != right.Y || left != right.Z;
|
|
||||||
|
|
||||||
public override void ToString(String strBuffer) => strBuffer.AppendF($"X:{X} Y:{Y} Z:{Z}");
|
|
||||||
|
|
||||||
public static explicit operator Vector3(Int32_3 point) => .(point.X, point.Y, point.Z);
|
|
||||||
|
|
||||||
public static explicit operator Int32_3(Vector3 point) => .((int32)point.X, (int32)point.Y, (int32)point.Z);
|
|
||||||
|
|
||||||
[Inline]
|
|
||||||
public static explicit operator Int32_2(in Int32_3 point) => *(Int32_2*)&point;
|
|
||||||
|
|
||||||
public int GetHashCode()
|
|
||||||
{
|
|
||||||
return (((X * 39) ^ Y) * 39) ^ Z;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,234 +0,0 @@
|
|||||||
#pragma warning disable 4204
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
|
|
||||||
namespace GlitchyEngine.Math
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* A Vector with four components of type int32.
|
|
||||||
*/
|
|
||||||
[SwizzleVector(4, "Int32_")]
|
|
||||||
public struct Int32_4 : IHashable
|
|
||||||
{
|
|
||||||
public const Int32_4 Zero = .(0, 0, 0, 0);
|
|
||||||
public const Int32_4 UnitX = .(1, 0, 0, 0);
|
|
||||||
public const Int32_4 UnitY = .(0, 1, 0, 0);
|
|
||||||
public const Int32_4 UnitZ = .(0, 0, 1, 0);
|
|
||||||
public const Int32_4 UnitW = .(0, 0, 0, 1);
|
|
||||||
public const Int32_4 One = .(1, 1, 1, 1);
|
|
||||||
|
|
||||||
public int32 X, Y, Z, W;
|
|
||||||
|
|
||||||
public this() => this = default;
|
|
||||||
|
|
||||||
public this(int32 value)
|
|
||||||
{
|
|
||||||
X = value;
|
|
||||||
Y = value;
|
|
||||||
Z = value;
|
|
||||||
W = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(int value)
|
|
||||||
{
|
|
||||||
X = (.)value;
|
|
||||||
Y = (.)value;
|
|
||||||
Z = (.)value;
|
|
||||||
W = (.)value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(int32 x, int32 y, int32 z, int32 w)
|
|
||||||
{
|
|
||||||
X = x;
|
|
||||||
Y = y;
|
|
||||||
Z = z;
|
|
||||||
W = w;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(Int32_2 xy, int32 z, int32 w)
|
|
||||||
{
|
|
||||||
X = xy.X;
|
|
||||||
Y = xy.Y;
|
|
||||||
Z = z;
|
|
||||||
W = w;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(int32 x, Int32_2 yz, int32 w)
|
|
||||||
{
|
|
||||||
X = x;
|
|
||||||
Y = yz.X;
|
|
||||||
Z = yz.Y;
|
|
||||||
W = w;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(int32 x, int32 y, Int32_2 zw)
|
|
||||||
{
|
|
||||||
X = x;
|
|
||||||
Y = y;
|
|
||||||
Z = zw.X;
|
|
||||||
W = zw.Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(Int32_2 xy, Int32_2 zw)
|
|
||||||
{
|
|
||||||
X = xy.X;
|
|
||||||
Y = xy.Y;
|
|
||||||
Z = zw.X;
|
|
||||||
W = zw.Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(Int32_3 xyz, int32 w)
|
|
||||||
{
|
|
||||||
X = xyz.X;
|
|
||||||
Y = xyz.Y;
|
|
||||||
Z = xyz.Z;
|
|
||||||
W = w;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(int32 x, Int32_3 yzw)
|
|
||||||
{
|
|
||||||
X = x;
|
|
||||||
Y = yzw.X;
|
|
||||||
Z = yzw.Y;
|
|
||||||
W = yzw.Z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ref int32 this[int index]
|
|
||||||
{
|
|
||||||
[Inline]
|
|
||||||
get
|
|
||||||
{
|
|
||||||
#if DEBUG
|
|
||||||
if(index < 0 || index >= 3)
|
|
||||||
Internal.ThrowIndexOutOfRange(1);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return ref (&X)[index];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int32 MagnitudeSquared() => X * X + Y * Y + Z * Z + W * W;
|
|
||||||
|
|
||||||
public float Magnitude() => Math.Sqrt(X * X + Y * Y + Z * Z + W * W);
|
|
||||||
|
|
||||||
public Int32_4 Abs() => .(Math.Abs(X), Math.Abs(Y), Math.Abs(Z), Math.Abs(W));
|
|
||||||
|
|
||||||
//
|
|
||||||
// Assignment operators
|
|
||||||
//
|
|
||||||
|
|
||||||
public void operator +=(Int32_4 value) mut
|
|
||||||
{
|
|
||||||
X += value.X;
|
|
||||||
Y += value.Y;
|
|
||||||
Z += value.Z;
|
|
||||||
W += value.W;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator +=(int32 value) mut
|
|
||||||
{
|
|
||||||
X += value;
|
|
||||||
Y += value;
|
|
||||||
Z += value;
|
|
||||||
W += value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator -=(Int32_4 value) mut
|
|
||||||
{
|
|
||||||
X -= value.X;
|
|
||||||
Y -= value.Y;
|
|
||||||
Z -= value.Z;
|
|
||||||
W -= value.W;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator -=(int32 value) mut
|
|
||||||
{
|
|
||||||
X -= value;
|
|
||||||
Y -= value;
|
|
||||||
Z -= value;
|
|
||||||
W -= value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator *=(Int32_4 value) mut
|
|
||||||
{
|
|
||||||
X *= value.X;
|
|
||||||
Y *= value.Y;
|
|
||||||
Z *= value.Z;
|
|
||||||
W *= value.W;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator *=(int32 value) mut
|
|
||||||
{
|
|
||||||
X *= value;
|
|
||||||
Y *= value;
|
|
||||||
Z *= value;
|
|
||||||
W *= value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator /=(Int32_4 value) mut
|
|
||||||
{
|
|
||||||
X /= value.X;
|
|
||||||
Y /= value.Y;
|
|
||||||
Z /= value.Z;
|
|
||||||
W /= value.W;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator /=(int32 value) mut
|
|
||||||
{
|
|
||||||
X /= value;
|
|
||||||
Y /= value;
|
|
||||||
Z /= value;
|
|
||||||
W /= value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Operators
|
|
||||||
|
|
||||||
public static Int32_4 operator +(Int32_4 value) => value;
|
|
||||||
public static Int32_4 operator +(Int32_4 left, Int32_4 right) => .(left.X + right.X, left.Y + right.Y, left.Z + right.Z, left.W + right.W);
|
|
||||||
public static Int32_4 operator +(Int32_4 left, int32 right) => .(left.X + right, left.Y + right, left.Z + right, left.W + right);
|
|
||||||
public static Int32_4 operator +(int32 left, Int32_4 right) => .(left + right.X, left + right.Y, left + right.Z, left + right.W);
|
|
||||||
|
|
||||||
public static Int32_4 operator -(Int32_4 value) => .(-value.X, -value.Y, -value.Z, -value.W);
|
|
||||||
public static Int32_4 operator -(Int32_4 left, Int32_4 right) => .(left.X - right.X, left.Y - right.Y, left.Z - right.Z, left.W - right.W);
|
|
||||||
public static Int32_4 operator -(Int32_4 left, int32 right) => .(left.X - right, left.Y - right, left.Z - right, left.W - right);
|
|
||||||
public static Int32_4 operator -(int32 left, Int32_4 right) => .(left - right.X, left - right.Y, left - right.Z, left - right.W);
|
|
||||||
|
|
||||||
public static Int32_4 operator *(Int32_4 left, Int32_4 right) => .(left.X * right.X, left.Y * right.Y, left.Z * right.Z, left.W * right.W);
|
|
||||||
public static Int32_4 operator *(Int32_4 left, int32 right) => .(left.X * right, left.Y * right, left.Z * right, left.W * right);
|
|
||||||
public static Int32_4 operator *(int32 left, Int32_4 right) => .(left * right.X, left * right.Y, left * right.Z, left * right.W);
|
|
||||||
|
|
||||||
public static Int32_4 operator /(Int32_4 left, Int32_4 right) => .(left.X / right.X, left.Y / right.Y, left.Z / right.Z, left.W / right.W);
|
|
||||||
public static Int32_4 operator /(Int32_4 left, int32 right) => .(left.X / right, left.Y / right, left.Z / right, left.W / right);
|
|
||||||
public static Int32_4 operator /(int32 left, Int32_4 right) => .(left / right.X, left / right.Y, left / right.Z, left / right.W);
|
|
||||||
|
|
||||||
public static Int32_4 operator %(Int32_4 left, Int32_4 right) => .(left.X % right.X, left.Y % right.Y, left.Z % right.Z, left.W % right.W);
|
|
||||||
public static Int32_4 operator %(Int32_4 left, int32 right) => .(left.X % right, left.Y % right, left.Z % right, left.W % right);
|
|
||||||
public static Int32_4 operator %(int32 left, Int32_4 right) => .(left % right.X, left % right.Y, left % right.Z, left % right.W);
|
|
||||||
|
|
||||||
public static bool operator ==(Int32_4 left, Int32_4 right) => left.X == right.X && left.Y == right.Y && left.Z == right.Z && left.W == right.W;
|
|
||||||
public static bool operator ==(Int32_4 left, int32 right) => left.X == right && left.Y == right && left.Z == right && left.W == right;
|
|
||||||
public static bool operator ==(int32 left, Int32_4 right) => left == right.X && left == right.Y && left == right.Z && left == right.W;
|
|
||||||
|
|
||||||
public static bool operator !=(Int32_4 left, Int32_4 right) => left.X != right.X || left.Y != right.Y || left.Z != right.Z || left.W != right.W;
|
|
||||||
public static bool operator !=(Int32_4 left, int32 right) => left.X != right || left.Y != right || left.Z != right || left.W != right;
|
|
||||||
public static bool operator !=(int32 left, Int32_4 right) => left != right.X || left != right.Y || left != right.Z || left != right.W;
|
|
||||||
|
|
||||||
public override void ToString(String strBuffer) => strBuffer.AppendF($"X:{X} Y:{Y} Z:{Z} W:{W}");
|
|
||||||
|
|
||||||
public static explicit operator Vector4(Int32_4 point) => .(point.X, point.Y, point.Z, point.W);
|
|
||||||
|
|
||||||
public static explicit operator Int32_4(Vector4 point) => .((int32)point.X, (int32)point.Y, (int32)point.Z, (int32)point.W);
|
|
||||||
|
|
||||||
[Inline]
|
|
||||||
public static explicit operator Int32_2(in Int32_4 point) => *(Int32_2*)&point;
|
|
||||||
|
|
||||||
[Inline]
|
|
||||||
public static explicit operator Int32_3(in Int32_4 point) => *(Int32_3*)&point;
|
|
||||||
|
|
||||||
public int GetHashCode()
|
|
||||||
{
|
|
||||||
return (((((X * 39) ^ Y) * 39) ^ Z) * 39) ^ W;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,234 @@
|
|||||||
|
#pragma warning disable 4204
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Math
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* A Vector with four components of type int32.
|
||||||
|
*/
|
||||||
|
[SwizzleVector(4, "Int")]
|
||||||
|
public struct Int4 : IHashable
|
||||||
|
{
|
||||||
|
public const Int4 Zero = .(0, 0, 0, 0);
|
||||||
|
public const Int4 UnitX = .(1, 0, 0, 0);
|
||||||
|
public const Int4 UnitY = .(0, 1, 0, 0);
|
||||||
|
public const Int4 UnitZ = .(0, 0, 1, 0);
|
||||||
|
public const Int4 UnitW = .(0, 0, 0, 1);
|
||||||
|
public const Int4 One = .(1, 1, 1, 1);
|
||||||
|
|
||||||
|
public int32 X, Y, Z, W;
|
||||||
|
|
||||||
|
public this() => this = default;
|
||||||
|
|
||||||
|
public this(int32 value)
|
||||||
|
{
|
||||||
|
X = value;
|
||||||
|
Y = value;
|
||||||
|
Z = value;
|
||||||
|
W = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public this(int value)
|
||||||
|
{
|
||||||
|
X = (.)value;
|
||||||
|
Y = (.)value;
|
||||||
|
Z = (.)value;
|
||||||
|
W = (.)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public this(int32 x, int32 y, int32 z, int32 w)
|
||||||
|
{
|
||||||
|
X = x;
|
||||||
|
Y = y;
|
||||||
|
Z = z;
|
||||||
|
W = w;
|
||||||
|
}
|
||||||
|
|
||||||
|
public this(Int2 xy, int32 z, int32 w)
|
||||||
|
{
|
||||||
|
X = xy.X;
|
||||||
|
Y = xy.Y;
|
||||||
|
Z = z;
|
||||||
|
W = w;
|
||||||
|
}
|
||||||
|
|
||||||
|
public this(int32 x, Int2 yz, int32 w)
|
||||||
|
{
|
||||||
|
X = x;
|
||||||
|
Y = yz.X;
|
||||||
|
Z = yz.Y;
|
||||||
|
W = w;
|
||||||
|
}
|
||||||
|
|
||||||
|
public this(int32 x, int32 y, Int2 zw)
|
||||||
|
{
|
||||||
|
X = x;
|
||||||
|
Y = y;
|
||||||
|
Z = zw.X;
|
||||||
|
W = zw.Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public this(Int2 xy, Int2 zw)
|
||||||
|
{
|
||||||
|
X = xy.X;
|
||||||
|
Y = xy.Y;
|
||||||
|
Z = zw.X;
|
||||||
|
W = zw.Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public this(Int3 xyz, int32 w)
|
||||||
|
{
|
||||||
|
X = xyz.X;
|
||||||
|
Y = xyz.Y;
|
||||||
|
Z = xyz.Z;
|
||||||
|
W = w;
|
||||||
|
}
|
||||||
|
|
||||||
|
public this(int32 x, Int3 yzw)
|
||||||
|
{
|
||||||
|
X = x;
|
||||||
|
Y = yzw.X;
|
||||||
|
Z = yzw.Y;
|
||||||
|
W = yzw.Z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ref int32 this[int index]
|
||||||
|
{
|
||||||
|
[Inline]
|
||||||
|
get
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
if(index < 0 || index >= 3)
|
||||||
|
Internal.ThrowIndexOutOfRange(1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ref (&X)[index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int32 MagnitudeSquared() => X * X + Y * Y + Z * Z + W * W;
|
||||||
|
|
||||||
|
public float Magnitude() => Math.Sqrt(X * X + Y * Y + Z * Z + W * W);
|
||||||
|
|
||||||
|
public Int4 Abs() => .(Math.Abs(X), Math.Abs(Y), Math.Abs(Z), Math.Abs(W));
|
||||||
|
|
||||||
|
//
|
||||||
|
// Assignment operators
|
||||||
|
//
|
||||||
|
|
||||||
|
public void operator +=(Int4 value) mut
|
||||||
|
{
|
||||||
|
X += value.X;
|
||||||
|
Y += value.Y;
|
||||||
|
Z += value.Z;
|
||||||
|
W += value.W;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void operator +=(int32 value) mut
|
||||||
|
{
|
||||||
|
X += value;
|
||||||
|
Y += value;
|
||||||
|
Z += value;
|
||||||
|
W += value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void operator -=(Int4 value) mut
|
||||||
|
{
|
||||||
|
X -= value.X;
|
||||||
|
Y -= value.Y;
|
||||||
|
Z -= value.Z;
|
||||||
|
W -= value.W;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void operator -=(int32 value) mut
|
||||||
|
{
|
||||||
|
X -= value;
|
||||||
|
Y -= value;
|
||||||
|
Z -= value;
|
||||||
|
W -= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void operator *=(Int4 value) mut
|
||||||
|
{
|
||||||
|
X *= value.X;
|
||||||
|
Y *= value.Y;
|
||||||
|
Z *= value.Z;
|
||||||
|
W *= value.W;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void operator *=(int32 value) mut
|
||||||
|
{
|
||||||
|
X *= value;
|
||||||
|
Y *= value;
|
||||||
|
Z *= value;
|
||||||
|
W *= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void operator /=(Int4 value) mut
|
||||||
|
{
|
||||||
|
X /= value.X;
|
||||||
|
Y /= value.Y;
|
||||||
|
Z /= value.Z;
|
||||||
|
W /= value.W;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void operator /=(int32 value) mut
|
||||||
|
{
|
||||||
|
X /= value;
|
||||||
|
Y /= value;
|
||||||
|
Z /= value;
|
||||||
|
W /= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Operators
|
||||||
|
|
||||||
|
public static Int4 operator +(Int4 value) => value;
|
||||||
|
public static Int4 operator +(Int4 left, Int4 right) => .(left.X + right.X, left.Y + right.Y, left.Z + right.Z, left.W + right.W);
|
||||||
|
public static Int4 operator +(Int4 left, int32 right) => .(left.X + right, left.Y + right, left.Z + right, left.W + right);
|
||||||
|
public static Int4 operator +(int32 left, Int4 right) => .(left + right.X, left + right.Y, left + right.Z, left + right.W);
|
||||||
|
|
||||||
|
public static Int4 operator -(Int4 value) => .(-value.X, -value.Y, -value.Z, -value.W);
|
||||||
|
public static Int4 operator -(Int4 left, Int4 right) => .(left.X - right.X, left.Y - right.Y, left.Z - right.Z, left.W - right.W);
|
||||||
|
public static Int4 operator -(Int4 left, int32 right) => .(left.X - right, left.Y - right, left.Z - right, left.W - right);
|
||||||
|
public static Int4 operator -(int32 left, Int4 right) => .(left - right.X, left - right.Y, left - right.Z, left - right.W);
|
||||||
|
|
||||||
|
public static Int4 operator *(Int4 left, Int4 right) => .(left.X * right.X, left.Y * right.Y, left.Z * right.Z, left.W * right.W);
|
||||||
|
public static Int4 operator *(Int4 left, int32 right) => .(left.X * right, left.Y * right, left.Z * right, left.W * right);
|
||||||
|
public static Int4 operator *(int32 left, Int4 right) => .(left * right.X, left * right.Y, left * right.Z, left * right.W);
|
||||||
|
|
||||||
|
public static Int4 operator /(Int4 left, Int4 right) => .(left.X / right.X, left.Y / right.Y, left.Z / right.Z, left.W / right.W);
|
||||||
|
public static Int4 operator /(Int4 left, int32 right) => .(left.X / right, left.Y / right, left.Z / right, left.W / right);
|
||||||
|
public static Int4 operator /(int32 left, Int4 right) => .(left / right.X, left / right.Y, left / right.Z, left / right.W);
|
||||||
|
|
||||||
|
public static Int4 operator %(Int4 left, Int4 right) => .(left.X % right.X, left.Y % right.Y, left.Z % right.Z, left.W % right.W);
|
||||||
|
public static Int4 operator %(Int4 left, int32 right) => .(left.X % right, left.Y % right, left.Z % right, left.W % right);
|
||||||
|
public static Int4 operator %(int32 left, Int4 right) => .(left % right.X, left % right.Y, left % right.Z, left % right.W);
|
||||||
|
|
||||||
|
public static bool operator ==(Int4 left, Int4 right) => left.X == right.X && left.Y == right.Y && left.Z == right.Z && left.W == right.W;
|
||||||
|
public static bool operator ==(Int4 left, int32 right) => left.X == right && left.Y == right && left.Z == right && left.W == right;
|
||||||
|
public static bool operator ==(int32 left, Int4 right) => left == right.X && left == right.Y && left == right.Z && left == right.W;
|
||||||
|
|
||||||
|
public static bool operator !=(Int4 left, Int4 right) => left.X != right.X || left.Y != right.Y || left.Z != right.Z || left.W != right.W;
|
||||||
|
public static bool operator !=(Int4 left, int32 right) => left.X != right || left.Y != right || left.Z != right || left.W != right;
|
||||||
|
public static bool operator !=(int32 left, Int4 right) => left != right.X || left != right.Y || left != right.Z || left != right.W;
|
||||||
|
|
||||||
|
public override void ToString(String strBuffer) => strBuffer.AppendF($"X:{X} Y:{Y} Z:{Z} W:{W}");
|
||||||
|
|
||||||
|
public static explicit operator Vector4(Int4 point) => .(point.X, point.Y, point.Z, point.W);
|
||||||
|
|
||||||
|
public static explicit operator Int4(Vector4 point) => .((int32)point.X, (int32)point.Y, (int32)point.Z, (int32)point.W);
|
||||||
|
|
||||||
|
[Inline]
|
||||||
|
public static explicit operator Int2(in Int4 point) => *(Int2*)&point;
|
||||||
|
|
||||||
|
[Inline]
|
||||||
|
public static explicit operator Int3(in Int4 point) => *(Int3*)&point;
|
||||||
|
|
||||||
|
public int GetHashCode()
|
||||||
|
{
|
||||||
|
return (((((X * 39) ^ Y) * 39) ^ Z) * 39) ^ W;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
using GlitchyEngine.Renderer;
|
||||||
|
using GlitchyEngine.Events;
|
||||||
|
using GlitchyEngine.Math;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace GlitchyEngine
|
||||||
|
{
|
||||||
|
/// A simple controller for an orthographic camera
|
||||||
|
public class OrthographicCameraController
|
||||||
|
{
|
||||||
|
private OrthographicCamera _camera ~ delete _;
|
||||||
|
private float _aspectRatio;
|
||||||
|
private float _zoomLevel = 1.0f;
|
||||||
|
|
||||||
|
private bool _rotation;
|
||||||
|
|
||||||
|
private Vector3 _cameraPosition;
|
||||||
|
private float _cameraRotation;
|
||||||
|
private float _cameraTranslationSpeed = 1.0f;
|
||||||
|
private float _cameraRotationSpeed = 1.0f;
|
||||||
|
|
||||||
|
public OrthographicCamera Camera => _camera;
|
||||||
|
|
||||||
|
public this(float aspectRatio, bool rotation = false)
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileFunction!();
|
||||||
|
|
||||||
|
_aspectRatio = aspectRatio;
|
||||||
|
_rotation = rotation;
|
||||||
|
|
||||||
|
_camera = new OrthographicCamera();
|
||||||
|
_camera.NearPlane = -10f;
|
||||||
|
_camera.FarPlane = 10f;
|
||||||
|
|
||||||
|
UpdateCamera();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(GameTime gameTime)
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileFunction!();
|
||||||
|
|
||||||
|
if(Application.Get().Window.IsActive)
|
||||||
|
{
|
||||||
|
Vector3 movement = .();
|
||||||
|
|
||||||
|
if(Input.IsKeyPressed(Key.W))
|
||||||
|
{
|
||||||
|
movement.Y += 1;
|
||||||
|
}
|
||||||
|
if(Input.IsKeyPressed(Key.S))
|
||||||
|
{
|
||||||
|
movement.Y -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Input.IsKeyPressed(Key.A))
|
||||||
|
{
|
||||||
|
movement.X -= 1;
|
||||||
|
}
|
||||||
|
if(Input.IsKeyPressed(Key.D))
|
||||||
|
{
|
||||||
|
movement.X += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(movement != .Zero)
|
||||||
|
movement.Normalize();
|
||||||
|
|
||||||
|
movement *= (float)(gameTime.FrameTime.TotalSeconds) * _cameraTranslationSpeed * _zoomLevel;
|
||||||
|
|
||||||
|
_cameraPosition += movement;
|
||||||
|
|
||||||
|
if(_rotation)
|
||||||
|
{
|
||||||
|
if(Input.IsKeyPressed(Key.Q))
|
||||||
|
{
|
||||||
|
_cameraRotation += (float)(gameTime.FrameTime.TotalSeconds) * _cameraRotationSpeed;
|
||||||
|
}
|
||||||
|
if(Input.IsKeyPressed(Key.E))
|
||||||
|
{
|
||||||
|
_cameraRotation -= (float)(gameTime.FrameTime.TotalSeconds) * _cameraRotationSpeed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateCamera();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnEvent(Event e)
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileFunction!();
|
||||||
|
|
||||||
|
EventDispatcher dispatcher = EventDispatcher(e);
|
||||||
|
dispatcher.Dispatch<MouseScrolledEvent>(scope => OnMouseScrolled);
|
||||||
|
dispatcher.Dispatch<WindowResizeEvent>(scope => OnWindowResized);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool OnMouseScrolled(MouseScrolledEvent e)
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileFunction!();
|
||||||
|
|
||||||
|
_zoomLevel -= e.YOffset * 0.25f;
|
||||||
|
|
||||||
|
_zoomLevel = Math.Max(_zoomLevel, 0.25f);
|
||||||
|
|
||||||
|
UpdateCamera();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool OnWindowResized(WindowResizeEvent e)
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileFunction!();
|
||||||
|
|
||||||
|
_aspectRatio = (float)e.Width / (float)e.Height;
|
||||||
|
|
||||||
|
UpdateCamera();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateCamera()
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileFunction!();
|
||||||
|
|
||||||
|
_camera.Left = -_aspectRatio * _zoomLevel;
|
||||||
|
_camera.Right = _aspectRatio * _zoomLevel;
|
||||||
|
_camera.Top = _zoomLevel;
|
||||||
|
_camera.Bottom = -_zoomLevel;
|
||||||
|
_camera.Rotation = .(_camera.Rotation.X, _camera.Rotation.Y, _cameraRotation);
|
||||||
|
_camera.Position = _cameraPosition;
|
||||||
|
|
||||||
|
_camera.Update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,186 @@
|
|||||||
|
using System;
|
||||||
|
using GlitchyEngine.Events;
|
||||||
|
using GlitchyEngine.Math;
|
||||||
|
using GlitchyEngine.Renderer;
|
||||||
|
|
||||||
|
namespace GlitchyEngine
|
||||||
|
{
|
||||||
|
/// A simple controller for a perspective camera
|
||||||
|
public class PerspectiveCameraController
|
||||||
|
{
|
||||||
|
private PerspectiveCamera _camera ~ delete _;
|
||||||
|
private float _aspectRatio;
|
||||||
|
private float _fovY = Math.PI_f / 4;
|
||||||
|
|
||||||
|
private Vector3 _cameraPosition;
|
||||||
|
private Vector3 _cameraRotation;
|
||||||
|
|
||||||
|
private float _cameraTranslationSpeed = 1.0f;
|
||||||
|
private float _cameraRotationSpeedX = 0.001f;
|
||||||
|
private float _cameraRotationSpeedY = 0.001f;
|
||||||
|
|
||||||
|
public PerspectiveCamera Camera => _camera;
|
||||||
|
|
||||||
|
public float TranslationSpeed
|
||||||
|
{
|
||||||
|
get => _cameraTranslationSpeed;
|
||||||
|
set => _cameraTranslationSpeed = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector2 RotationSpeed
|
||||||
|
{
|
||||||
|
get => .(_cameraRotationSpeedX, _cameraRotationSpeedY);
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_cameraRotationSpeedX = value.X;
|
||||||
|
_cameraRotationSpeedY = value.Y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3 CameraPosition
|
||||||
|
{
|
||||||
|
get => _cameraPosition;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_cameraPosition = value;
|
||||||
|
|
||||||
|
UpdateCamera();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3 CameraRotation
|
||||||
|
{
|
||||||
|
get => _cameraRotation;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_cameraRotation = value;
|
||||||
|
|
||||||
|
UpdateCamera();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float FovY
|
||||||
|
{
|
||||||
|
get => _fovY;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_fovY = value;
|
||||||
|
|
||||||
|
UpdateCamera();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float AspectRatio
|
||||||
|
{
|
||||||
|
get => _aspectRatio;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_aspectRatio = value;
|
||||||
|
|
||||||
|
UpdateCamera();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public this(float aspectRatio)
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileFunction!();
|
||||||
|
|
||||||
|
_aspectRatio = aspectRatio;
|
||||||
|
|
||||||
|
_camera = new PerspectiveCamera();
|
||||||
|
_camera.ProjectionType = .Infinite;
|
||||||
|
_camera.NearPlane = 0.01f;
|
||||||
|
|
||||||
|
UpdateCamera();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(GameTime gameTime)
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileFunction!();
|
||||||
|
|
||||||
|
if(Application.Get().Window.IsActive)
|
||||||
|
{
|
||||||
|
Vector3 movement = .();
|
||||||
|
|
||||||
|
if(Input.IsKeyPressed(Key.W))
|
||||||
|
{
|
||||||
|
movement.Z += 1;
|
||||||
|
}
|
||||||
|
if(Input.IsKeyPressed(Key.S))
|
||||||
|
{
|
||||||
|
movement.Z -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Input.IsKeyPressed(Key.A))
|
||||||
|
{
|
||||||
|
movement.X -= 1;
|
||||||
|
}
|
||||||
|
if(Input.IsKeyPressed(Key.D))
|
||||||
|
{
|
||||||
|
movement.X += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Input.IsKeyPressed(Key.Space))
|
||||||
|
{
|
||||||
|
movement.Y += 1;
|
||||||
|
}
|
||||||
|
if(Input.IsKeyPressed(Key.Control))
|
||||||
|
{
|
||||||
|
movement.Y -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(movement != .Zero)
|
||||||
|
movement.Normalize();
|
||||||
|
|
||||||
|
movement *= (float)(gameTime.FrameTime.TotalSeconds) * _cameraTranslationSpeed;
|
||||||
|
|
||||||
|
Vector4 delta = Vector4(movement, 1.0f) * _camera.View;
|
||||||
|
|
||||||
|
_cameraPosition += Vector3(delta.X, delta.Y, delta.Z);
|
||||||
|
//_cameraPosition += movement;
|
||||||
|
|
||||||
|
// Camera rotation
|
||||||
|
var mouseDelta = Input.GetMouseMovement();
|
||||||
|
|
||||||
|
float rotY = mouseDelta.X * _cameraRotationSpeedX;
|
||||||
|
float rotX = mouseDelta.Y * _cameraRotationSpeedY;
|
||||||
|
|
||||||
|
_cameraRotation.X += rotX;
|
||||||
|
_cameraRotation.Y += rotY;
|
||||||
|
|
||||||
|
UpdateCamera();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnEvent(Event e)
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileFunction!();
|
||||||
|
|
||||||
|
EventDispatcher dispatcher = EventDispatcher(e);
|
||||||
|
dispatcher.Dispatch<WindowResizeEvent>(scope => OnWindowResized);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool OnWindowResized(WindowResizeEvent e)
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileFunction!();
|
||||||
|
|
||||||
|
_aspectRatio = (float)e.Width / (float)e.Height;
|
||||||
|
|
||||||
|
UpdateCamera();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateCamera()
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileFunction!();
|
||||||
|
|
||||||
|
_camera.AspectRatio = _aspectRatio;
|
||||||
|
_camera.FovY = _fovY;
|
||||||
|
_camera.Rotation = _cameraRotation;
|
||||||
|
_camera.Position = _cameraPosition;
|
||||||
|
|
||||||
|
_camera.Update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
#if GE_GRAPHICS_DX11
|
||||||
|
|
||||||
|
#if !BF_PLATFORM_WINDOWS
|
||||||
|
#error DirectX 11 (GE_GRAPHICS_DX11) can only be used on Windows.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using DirectX.Common;
|
||||||
|
using DirectX.D3D11;
|
||||||
|
using DirectX.D3D11.SDKLayers;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Platform.DX11
|
||||||
|
{
|
||||||
|
static
|
||||||
|
{
|
||||||
|
/// Gets whether or not the DX11 device is initialized.
|
||||||
|
protected internal static bool IsDx11Initialized => NativeDevice != null;
|
||||||
|
protected internal static ID3D11Device* NativeDevice;
|
||||||
|
protected internal static ID3D11DeviceContext* NativeContext;
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
protected internal static ID3D11Debug* DebugDevice;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
internal static void Dx11Init()
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileFunction!();
|
||||||
|
|
||||||
|
if(!IsDx11Initialized)
|
||||||
|
{
|
||||||
|
Log.EngineLogger.Trace("Creating D3D11 Device and Context...");
|
||||||
|
|
||||||
|
DeviceCreationFlags deviceFlags = .None;
|
||||||
|
#if DEBUG
|
||||||
|
deviceFlags |= .Debug;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
FeatureLevel[] levels = scope .(.Level_11_0);
|
||||||
|
|
||||||
|
FeatureLevel deviceLevel = ?;
|
||||||
|
|
||||||
|
HResult deviceResult;
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileScope!("D3D11.CreateDevice");
|
||||||
|
deviceResult = D3D11.CreateDevice(null, .Hardware, 0, deviceFlags, levels, &NativeDevice, &deviceLevel, &NativeContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.EngineLogger.Assert(deviceResult.Succeeded, scope $"Failed to create D3D11 Device. Message({(int32)deviceResult}): {deviceResult}");
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileScope!("Query for ID3D11Debug");
|
||||||
|
if(NativeDevice.QueryInterface<ID3D11Debug>(out DebugDevice).Succeeded)
|
||||||
|
{
|
||||||
|
ID3D11InfoQueue* infoQueue;
|
||||||
|
if(NativeDevice.QueryInterface<ID3D11InfoQueue>(out infoQueue).Succeeded)
|
||||||
|
{
|
||||||
|
infoQueue.SetBreakOnSeverity(.Corruption, true);
|
||||||
|
infoQueue.SetBreakOnSeverity(.Error, true);
|
||||||
|
|
||||||
|
infoQueue.Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Log.EngineLogger.Trace($"D3D11 Device and Context created (Feature level: {deviceLevel})");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We created a second GraphicsContext (for some reason?) just increment references.
|
||||||
|
NativeDevice.AddRef();
|
||||||
|
NativeContext.AddRef();
|
||||||
|
#if DEBUG
|
||||||
|
DebugDevice.AddRef();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Dx11Release()
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileFunction!();
|
||||||
|
|
||||||
|
NativeDevice.Release();
|
||||||
|
NativeContext.Release();
|
||||||
|
#if DEBUG
|
||||||
|
Debug.WriteLine("""
|
||||||
|
|
||||||
|
-------------------------
|
||||||
|
Live DX Objects Report:
|
||||||
|
|
||||||
|
""");
|
||||||
|
|
||||||
|
DebugDevice.ReportLiveDeviceObjects(.Detail | .IgnoreInternal);
|
||||||
|
|
||||||
|
Debug.WriteLine("""
|
||||||
|
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
""");
|
||||||
|
|
||||||
|
DebugDevice.Release();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
#if GE_GRAPHICS_DX11
|
||||||
|
|
||||||
|
using GlitchyEngine.Renderer;
|
||||||
|
using System.Collections;
|
||||||
|
using DirectX.D3D11;
|
||||||
|
|
||||||
|
namespace ImGui
|
||||||
|
{
|
||||||
|
using internal GlitchyEngine.Renderer;
|
||||||
|
|
||||||
|
extension ImGui
|
||||||
|
{
|
||||||
|
static List<ID3D11ShaderResourceView*> _resourceViews = new .() ~ delete _;
|
||||||
|
|
||||||
|
public static override void Image(Texture2D texture, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, Vec4 tint_col = Vec4.Ones, Vec4 border_col = Vec4.Zero)
|
||||||
|
{
|
||||||
|
var view = texture.nativeResourceView..AddRef();
|
||||||
|
_resourceViews.Add(view);
|
||||||
|
|
||||||
|
ImGui.Image(view, size, uv0, uv1, tint_col, border_col);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static override void Image(RenderTarget2D texture, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, Vec4 tint_col = Vec4.Ones, Vec4 border_col = Vec4.Zero)
|
||||||
|
{
|
||||||
|
var view = texture._nativeResourceView..AddRef();
|
||||||
|
_resourceViews.Add(view);
|
||||||
|
|
||||||
|
ImGui.Image(view, size, uv0, uv1, tint_col, border_col);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected internal static override void CleanupFrame()
|
||||||
|
{
|
||||||
|
for(var view in _resourceViews)
|
||||||
|
{
|
||||||
|
view.Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
_resourceViews.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,9 +1,12 @@
|
|||||||
|
#if GE_GRAPHICS_DX11
|
||||||
|
|
||||||
|
// Disable warning when taking pointer of in-Parameter
|
||||||
#pragma warning disable 4204
|
#pragma warning disable 4204
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace GlitchyEngine.Math
|
namespace GlitchyEngine.Math
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
extension Vector2
|
extension Vector2
|
||||||
{
|
{
|
||||||
[Inline]
|
[Inline]
|
||||||
@@ -30,5 +33,6 @@ namespace GlitchyEngine.Math
|
|||||||
[Inline]
|
[Inline]
|
||||||
public static implicit operator Self(in DirectX.Math.Vector4 value) => *(Self*)&value;
|
public static implicit operator Self(in DirectX.Math.Vector4 value) => *(Self*)&value;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -1,22 +1,24 @@
|
|||||||
|
#if GE_GRAPHICS_DX11
|
||||||
|
|
||||||
using DirectX.D3D11;
|
using DirectX.D3D11;
|
||||||
using DirectX.Common;
|
using DirectX.Common;
|
||||||
using GlitchyEngine.Math;
|
using GlitchyEngine.Math;
|
||||||
|
|
||||||
using internal GlitchyEngine.Renderer;
|
using internal GlitchyEngine.Renderer;
|
||||||
|
|
||||||
|
using GlitchyEngine.Platform.DX11;
|
||||||
|
using internal GlitchyEngine.Platform.DX11;
|
||||||
|
|
||||||
namespace GlitchyEngine.Renderer
|
namespace GlitchyEngine.Renderer
|
||||||
{
|
{
|
||||||
extension BlendState
|
extension BlendState
|
||||||
{
|
{
|
||||||
internal ID3D11BlendState* nativeBlendState ~ _?.Release();
|
internal ID3D11BlendState* nativeBlendState ~ _?.Release();
|
||||||
|
|
||||||
public override void Bind(ColorRGBA blendFactor)
|
|
||||||
{
|
|
||||||
_context.nativeContext.OutputMerger.SetBlendState(nativeBlendState, blendFactor);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void PlatformCreateBlendState()
|
protected override void PlatformCreateBlendState()
|
||||||
{
|
{
|
||||||
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
|
||||||
BlendDescription nativeDesc = .Default;
|
BlendDescription nativeDesc = .Default;
|
||||||
nativeDesc.IndependentBlendEnable = _desc.IndependentBlendEnable;
|
nativeDesc.IndependentBlendEnable = _desc.IndependentBlendEnable;
|
||||||
nativeDesc.AlphaToCoverageEnable = _desc.AlphaToCoverageEnable;
|
nativeDesc.AlphaToCoverageEnable = _desc.AlphaToCoverageEnable;
|
||||||
@@ -33,9 +35,11 @@ namespace GlitchyEngine.Renderer
|
|||||||
nativeDesc.RenderTarget[i].RenderTargetWriteMask = _desc.RenderTarget[i].RenderTargetWriteMask;
|
nativeDesc.RenderTarget[i].RenderTargetWriteMask = _desc.RenderTarget[i].RenderTargetWriteMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
HResult result = _context.nativeDevice.CreateBlendState(ref nativeDesc, &nativeBlendState);
|
HResult result = NativeDevice.CreateBlendState(ref nativeDesc, &nativeBlendState);
|
||||||
|
|
||||||
Log.EngineLogger.Assert(result.Succeeded, scope $"Failed to create blend state. Error({(int)result}): {result}");
|
Log.EngineLogger.Assert(result.Succeeded, scope $"Failed to create blend state. Error({(int)result}): {result}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -1,27 +1,16 @@
|
|||||||
|
#if GE_GRAPHICS_DX11
|
||||||
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System;
|
using System;
|
||||||
using DirectX.D3D11;
|
using DirectX.D3D11;
|
||||||
|
|
||||||
using internal GlitchyEngine.Renderer;
|
using internal GlitchyEngine.Renderer;
|
||||||
|
|
||||||
|
using GlitchyEngine.Platform.DX11;
|
||||||
|
using internal GlitchyEngine.Platform.DX11;
|
||||||
|
|
||||||
namespace GlitchyEngine.Renderer
|
namespace GlitchyEngine.Renderer
|
||||||
{
|
{
|
||||||
extension CPUAccessFlags
|
|
||||||
{
|
|
||||||
public static explicit operator DirectX.D3D11.CpuAccessFlags(Self cpuAccessFlags)
|
|
||||||
{
|
|
||||||
DirectX.D3D11.CpuAccessFlags flags = .None;
|
|
||||||
|
|
||||||
if(cpuAccessFlags.HasFlag(.Read))
|
|
||||||
flags |= .Read;
|
|
||||||
|
|
||||||
if(cpuAccessFlags.HasFlag(.Write))
|
|
||||||
flags |= .Write;
|
|
||||||
|
|
||||||
return flags;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension BufferDescription
|
extension BufferDescription
|
||||||
{
|
{
|
||||||
public static operator DirectX.D3D11.BufferDescription(Self desc)
|
public static operator DirectX.D3D11.BufferDescription(Self desc)
|
||||||
@@ -71,6 +60,8 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
private Result<void> InternalCreateBuffer(void* data, uint32 byteLength, uint32 dstByteOffset)
|
private Result<void> InternalCreateBuffer(void* data, uint32 byteLength, uint32 dstByteOffset)
|
||||||
{
|
{
|
||||||
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
|
||||||
nativeDescription = (.)_description;
|
nativeDescription = (.)_description;
|
||||||
|
|
||||||
uint8* byteData = (.)data;
|
uint8* byteData = (.)data;
|
||||||
@@ -79,11 +70,11 @@ namespace GlitchyEngine.Renderer
|
|||||||
{
|
{
|
||||||
byteData = new uint8[nativeDescription.ByteWidth]*;
|
byteData = new uint8[nativeDescription.ByteWidth]*;
|
||||||
defer:: delete byteData;
|
defer:: delete byteData;
|
||||||
Internal.MemCpy(byteData + dstByteOffset, data, byteLength);
|
Internal.MemCpy(byteData + dstByteOffset, data, Math.Min(nativeDescription.ByteWidth, byteLength));
|
||||||
}
|
}
|
||||||
|
|
||||||
SubresourceData srData = .(byteData, byteLength, 0);
|
SubresourceData srData = .(byteData, byteLength, 0);
|
||||||
var result = _context.nativeDevice.CreateBuffer(ref nativeDescription, &srData, &nativeBuffer);
|
var result = NativeDevice.CreateBuffer(ref nativeDescription, &srData, &nativeBuffer);
|
||||||
if(result.Failed)
|
if(result.Failed)
|
||||||
{
|
{
|
||||||
Log.EngineLogger.Error($"Failed to create buffer. Message({(int)result}):{result}");
|
Log.EngineLogger.Error($"Failed to create buffer. Message({(int)result}):{result}");
|
||||||
@@ -95,6 +86,8 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
protected override Result<void> PlatformSetData(void* data, uint32 byteLength, uint32 dstByteOffset, GlitchyEngine.Renderer.MapType mapType)
|
protected override Result<void> PlatformSetData(void* data, uint32 byteLength, uint32 dstByteOffset, GlitchyEngine.Renderer.MapType mapType)
|
||||||
{
|
{
|
||||||
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
|
||||||
if(nativeBuffer == null)
|
if(nativeBuffer == null)
|
||||||
{
|
{
|
||||||
// We can pass the data while creating the buffer, so we can return here.
|
// We can pass the data while creating the buffer, so we can return here.
|
||||||
@@ -107,14 +100,14 @@ namespace GlitchyEngine.Renderer
|
|||||||
{
|
{
|
||||||
case .Default:
|
case .Default:
|
||||||
Box dataBox = .(dstByteOffset, 0, 0, dstByteOffset + byteLength, 1, 1);
|
Box dataBox = .(dstByteOffset, 0, 0, dstByteOffset + byteLength, 1, 1);
|
||||||
_context.nativeContext.UpdateSubresource(nativeBuffer, 0, &dataBox, data, byteLength, byteLength);
|
NativeContext.UpdateSubresource(nativeBuffer, 0, &dataBox, data, byteLength, byteLength);
|
||||||
case .Dynamic:
|
case .Dynamic:
|
||||||
Debug.Assert(mapType.CanWrite, "The map type has to have write access.");
|
Debug.Assert(mapType.CanWrite, "The map type has to have write access.");
|
||||||
// Todo: DoNotWaitFlag
|
// Todo: DoNotWaitFlag
|
||||||
MappedSubresource map = ?;
|
MappedSubresource map = ?;
|
||||||
_context.nativeContext.Map(nativeBuffer, 0, (.)mapType, .None, &map);
|
NativeContext.Map(nativeBuffer, 0, (.)mapType, .None, &map);
|
||||||
Internal.MemCpy(((uint8*)map.Data) + dstByteOffset, data, byteLength);
|
Internal.MemCpy(((uint8*)map.Data) + dstByteOffset, data, byteLength);
|
||||||
_context.nativeContext.Unmap(nativeBuffer, 0);
|
NativeContext.Unmap(nativeBuffer, 0);
|
||||||
case .Immutable:
|
case .Immutable:
|
||||||
Log.EngineLogger.Error("Can't set the data of an immutable resource.");
|
Log.EngineLogger.Error("Can't set the data of an immutable resource.");
|
||||||
return .Err;
|
return .Err;
|
||||||
@@ -127,3 +120,5 @@ namespace GlitchyEngine.Renderer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#if GE_GRAPHICS_DX11
|
||||||
|
|
||||||
using DirectX.D3D11;
|
using DirectX.D3D11;
|
||||||
|
|
||||||
using internal GlitchyEngine.Renderer;
|
using internal GlitchyEngine.Renderer;
|
||||||
@@ -10,6 +12,8 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
internal void PlatformFetchNativeBuffers()
|
internal void PlatformFetchNativeBuffers()
|
||||||
{
|
{
|
||||||
|
Debug.Profiler.ProfileRendererFunction!();
|
||||||
|
|
||||||
for(let buffer in _buffers)
|
for(let buffer in _buffers)
|
||||||
{
|
{
|
||||||
nativeBuffers[buffer.Index] = buffer.Buffer.nativeBuffer;
|
nativeBuffers[buffer.Index] = buffer.Buffer.nativeBuffer;
|
||||||
@@ -17,3 +21,5 @@ namespace GlitchyEngine.Renderer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#if GE_GRAPHICS_DX11
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Renderer
|
||||||
|
{
|
||||||
|
extension CPUAccessFlags
|
||||||
|
{
|
||||||
|
public static explicit operator DirectX.D3D11.CpuAccessFlags(Self cpuAccessFlags)
|
||||||
|
{
|
||||||
|
DirectX.D3D11.CpuAccessFlags flags = .None;
|
||||||
|
|
||||||
|
if(cpuAccessFlags.HasFlag(.Read))
|
||||||
|
flags |= .Read;
|
||||||
|
|
||||||
|
if(cpuAccessFlags.HasFlag(.Write))
|
||||||
|
flags |= .Write;
|
||||||
|
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#if GE_GRAPHICS_DX11
|
||||||
|
|
||||||
using DirectX.Common;
|
using DirectX.Common;
|
||||||
using DirectX.D3D11Shader;
|
using DirectX.D3D11Shader;
|
||||||
using System;
|
using System;
|
||||||
@@ -10,6 +12,8 @@ namespace GlitchyEngine.Renderer
|
|||||||
{
|
{
|
||||||
internal this(ConstantBuffer constantBuffer, ID3D11ShaderReflectionVariable* variableReflection)
|
internal this(ConstantBuffer constantBuffer, ID3D11ShaderReflectionVariable* variableReflection)
|
||||||
{
|
{
|
||||||
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
|
||||||
_constantBuffer = constantBuffer;
|
_constantBuffer = constantBuffer;
|
||||||
|
|
||||||
HResult result = variableReflection.GetDescription(let variableDescription);
|
HResult result = variableReflection.GetDescription(let variableDescription);
|
||||||
@@ -27,14 +31,19 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
switch(shaderTypeDescription.Type)
|
switch(shaderTypeDescription.Type)
|
||||||
{
|
{
|
||||||
|
case .Bool:
|
||||||
|
_type = .Bool;
|
||||||
case .Float:
|
case .Float:
|
||||||
_type = .Float;
|
_type = .Float;
|
||||||
|
case .Int:
|
||||||
|
_type = .Int;
|
||||||
default:
|
default:
|
||||||
Log.EngineLogger.Assert(false, scope $"Unhandled shader variable type: {shaderTypeDescription.Type}");
|
Log.EngineLogger.Assert(false, scope $"Unhandled shader variable type: {shaderTypeDescription.Type}");
|
||||||
}
|
}
|
||||||
|
|
||||||
_columns = shaderTypeDescription.Columns;
|
_columns = shaderTypeDescription.Columns;
|
||||||
_rows = shaderTypeDescription.Rows;
|
_rows = shaderTypeDescription.Rows;
|
||||||
|
_elements = shaderTypeDescription.Elements;
|
||||||
|
|
||||||
SetRawData(variableDescription.DefaultValue);
|
SetRawData(variableDescription.DefaultValue);
|
||||||
}
|
}
|
||||||
@@ -42,8 +51,10 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
extension ConstantBuffer
|
extension ConstantBuffer
|
||||||
{
|
{
|
||||||
internal this(GraphicsContext context, ID3D11ShaderReflectionConstantBuffer* bufferReflection) : base(context)
|
internal this(ID3D11ShaderReflectionConstantBuffer* bufferReflection)
|
||||||
{
|
{
|
||||||
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
|
||||||
Reflect(bufferReflection);
|
Reflect(bufferReflection);
|
||||||
|
|
||||||
ConstructBuffer();
|
ConstructBuffer();
|
||||||
@@ -53,6 +64,8 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
private void Reflect(ID3D11ShaderReflectionConstantBuffer* bufferReflection)
|
private void Reflect(ID3D11ShaderReflectionConstantBuffer* bufferReflection)
|
||||||
{
|
{
|
||||||
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
|
||||||
HResult result = bufferReflection.GetDescription(let bufferDescription);
|
HResult result = bufferReflection.GetDescription(let bufferDescription);
|
||||||
Log.EngineLogger.Assert(result.Succeeded, scope $"Failed to get buffer description. Error({(int)result}): {result}");
|
Log.EngineLogger.Assert(result.Succeeded, scope $"Failed to get buffer description. Error({(int)result}): {result}");
|
||||||
|
|
||||||
@@ -75,3 +88,5 @@ namespace GlitchyEngine.Renderer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
#if GE_GRAPHICS_DX11
|
||||||
|
|
||||||
|
using DirectX.D3D11;
|
||||||
|
using GlitchyEngine.Platform.DX11;
|
||||||
|
|
||||||
|
using internal GlitchyEngine.Renderer;
|
||||||
|
using internal GlitchyEngine.Platform.DX11;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Renderer
|
||||||
|
{
|
||||||
|
internal typealias D3DDepthStencilStateDesc = DirectX.D3D11.DepthStencilStateDescription;
|
||||||
|
internal typealias DxDSSDesc = DirectX.D3D11.DepthStencilStateDescription;
|
||||||
|
internal typealias GEDSSDesc = GlitchyEngine.Renderer.DepthStencilStateDescription;
|
||||||
|
|
||||||
|
internal typealias DxDepthStencilOpDesc = DirectX.D3D11.DepthStencilOperationDescription;
|
||||||
|
|
||||||
|
extension StencilOperation
|
||||||
|
{
|
||||||
|
public static explicit operator DirectX.D3D11.StencilOperation(Self self)
|
||||||
|
{
|
||||||
|
return (.)self.Underlying;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension DepthStencilOperationDescription
|
||||||
|
{
|
||||||
|
public static explicit operator DxDepthStencilOpDesc(Self desc)
|
||||||
|
{
|
||||||
|
return DxDepthStencilOpDesc((.)desc.StencilFailOperation, (.)desc.StencilDepthFailOperation,
|
||||||
|
(.)desc.StencilPassOperation, (.)desc.StencilFunction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension DepthStencilStateDescription
|
||||||
|
{
|
||||||
|
public static explicit operator DxDSSDesc(Self desc)
|
||||||
|
{
|
||||||
|
return DxDSSDesc(desc.DepthEnabled, desc.WriteDepth ? .All : .Zero, (.)desc.DepthFunction, desc.StencilEnabled,
|
||||||
|
desc.StencilReadMask, desc.StencilWriteMask, (.)desc.FrontFace, (.)desc.BackFace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension DepthStencilState
|
||||||
|
{
|
||||||
|
internal DxDSSDesc nativeDescription;
|
||||||
|
internal ID3D11DepthStencilState* nativeDepthStencilState ~ _?.Release();
|
||||||
|
|
||||||
|
public this(GEDSSDesc description)
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
|
||||||
|
_description = description;
|
||||||
|
nativeDescription = (.)description;
|
||||||
|
|
||||||
|
var result = NativeDevice.CreateDepthStencilState(ref nativeDescription, &nativeDepthStencilState);
|
||||||
|
if (result.Failed)
|
||||||
|
{
|
||||||
|
Log.EngineLogger.Error($"Failed to create depth stencil state. Message({(int)result}): {result}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,16 +1,45 @@
|
|||||||
|
#if GE_GRAPHICS_DX11
|
||||||
|
|
||||||
using DirectX.D3D11;
|
using DirectX.D3D11;
|
||||||
using internal GlitchyEngine.Renderer;
|
using internal GlitchyEngine.Renderer;
|
||||||
|
|
||||||
|
using GlitchyEngine.Platform.DX11;
|
||||||
|
using internal GlitchyEngine.Platform.DX11;
|
||||||
|
|
||||||
namespace GlitchyEngine.Renderer
|
namespace GlitchyEngine.Renderer
|
||||||
{
|
{
|
||||||
|
extension DepthStencilFormat
|
||||||
|
{
|
||||||
|
public static explicit operator Format(Self self)
|
||||||
|
{
|
||||||
|
switch(self)
|
||||||
|
{
|
||||||
|
case .D16_UNorm:
|
||||||
|
return .D16_UNorm;
|
||||||
|
case .D24_UNorm_S8_UInt:
|
||||||
|
return .D24_UNorm_S8_UInt;
|
||||||
|
case .D32_Float:
|
||||||
|
return .D32_Float;
|
||||||
|
case .D32_Float_S8X24_UInt:
|
||||||
|
return .D32_Float_S8X24_UInt;
|
||||||
|
case .None:
|
||||||
|
Log.EngineLogger.Assert(false, "None is not a valid depth stencil format");
|
||||||
|
return .Unknown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Depth stencil target is technically just a RenderTarget
|
||||||
extension DepthStencilTarget
|
extension DepthStencilTarget
|
||||||
{
|
{
|
||||||
internal ID3D11DepthStencilView* nativeView ~ _?.Release();
|
internal ID3D11DepthStencilView* nativeView ~ _?.Release();
|
||||||
|
|
||||||
protected override void PlatformCreate()
|
protected override void PlatformCreate()
|
||||||
{
|
{
|
||||||
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
|
||||||
Texture2DDescription desc = .();
|
Texture2DDescription desc = .();
|
||||||
desc.Format = .D32_Float;
|
desc.Format = (.)_format;
|
||||||
desc.ArraySize = 1;
|
desc.ArraySize = 1;
|
||||||
desc.BindFlags = .DepthStencil;
|
desc.BindFlags = .DepthStencil;
|
||||||
desc.Width = _width;
|
desc.Width = _width;
|
||||||
@@ -18,21 +47,13 @@ namespace GlitchyEngine.Renderer
|
|||||||
desc.SampleDesc = .(1, 0);
|
desc.SampleDesc = .(1, 0);
|
||||||
|
|
||||||
ID3D11Texture2D* tex = ?;
|
ID3D11Texture2D* tex = ?;
|
||||||
_context.nativeDevice.CreateTexture2D(ref desc, null, &tex);
|
NativeDevice.CreateTexture2D(ref desc, null, &tex);
|
||||||
|
|
||||||
_context.nativeDevice.CreateDepthStencilView(tex, null, &nativeView);
|
NativeDevice.CreateDepthStencilView(tex, null, &nativeView);
|
||||||
|
|
||||||
tex.Release();
|
tex.Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Bind()
|
|
||||||
{
|
|
||||||
_context.SetDepthStencilTarget(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Clear(float depthValue, uint8 stencilValue, DepthStencilClearFlag clearFlags)
|
|
||||||
{
|
|
||||||
_context.nativeContext.ClearDepthStencilView(nativeView, (.)clearFlags, depthValue, stencilValue);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#if GE_GRAPHICS_DX11
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using DirectX;
|
using DirectX;
|
||||||
using DirectX.D3D11;
|
using DirectX.D3D11;
|
||||||
@@ -10,9 +12,11 @@ namespace GlitchyEngine.Renderer
|
|||||||
{
|
{
|
||||||
protected override void Compile(String vsPath, String vsEntry, String psPath, String psEntry)
|
protected override void Compile(String vsPath, String vsEntry, String psPath, String psEntry)
|
||||||
{
|
{
|
||||||
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
|
||||||
// Todo: macros
|
// Todo: macros
|
||||||
VertexShader = new VertexShader(_context, vsPath, vsEntry);
|
VertexShader = new VertexShader(vsPath, vsEntry);
|
||||||
PixelShader = new PixelShader(_context, psPath, psEntry);
|
PixelShader = new PixelShader(psPath, psEntry);
|
||||||
|
|
||||||
Reflect();
|
Reflect();
|
||||||
}
|
}
|
||||||
@@ -23,3 +27,5 @@ namespace GlitchyEngine.Renderer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
|
#if GE_GRAPHICS_DX11
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using DirectX.D3D11;
|
using DirectX.D3D11;
|
||||||
|
using GlitchyEngine.Platform.DX11;
|
||||||
|
|
||||||
|
using internal GlitchyEngine.Renderer;
|
||||||
|
using internal GlitchyEngine.Platform.DX11;
|
||||||
|
|
||||||
namespace GlitchyEngine.Renderer
|
namespace GlitchyEngine.Renderer
|
||||||
{
|
{
|
||||||
using internal GlitchyEngine.Renderer;
|
|
||||||
|
|
||||||
extension GeometryBinding
|
extension GeometryBinding
|
||||||
{
|
{
|
||||||
internal ID3D11Buffer*[DirectX.D3D11.D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT] nativeBuffers;
|
internal ID3D11Buffer*[DirectX.D3D11.D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT] nativeBuffers;
|
||||||
@@ -27,6 +31,8 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
protected override void PlatformSetVertexBuffer(VertexBufferBinding binding, uint32 slot)
|
protected override void PlatformSetVertexBuffer(VertexBufferBinding binding, uint32 slot)
|
||||||
{
|
{
|
||||||
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
|
||||||
Log.EngineLogger.Assert(slot < nativeBuffers.Count, "The buffer slot has to be in the range from 0 to 31.");
|
Log.EngineLogger.Assert(slot < nativeBuffers.Count, "The buffer slot has to be in the range from 0 to 31.");
|
||||||
|
|
||||||
VertexBuffer vertexBuffer = binding.Buffer;
|
VertexBuffer vertexBuffer = binding.Buffer;
|
||||||
@@ -40,8 +46,8 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
nativeBuffers[slot] = vertexBuffer.nativeBuffer..AddRef();
|
nativeBuffers[slot] = vertexBuffer.nativeBuffer..AddRef();
|
||||||
|
|
||||||
bufferStrides[slot] = vertexBuffer.Binding.Stride;
|
bufferStrides[slot] = binding.Stride;
|
||||||
bufferOffsets[slot] = vertexBuffer.Binding.Offset;
|
bufferOffsets[slot] = binding.Offset;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -55,12 +61,16 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
protected override void PlatformSetVertexLayout(VertexLayout vertexLayout)
|
protected override void PlatformSetVertexLayout(VertexLayout vertexLayout)
|
||||||
{
|
{
|
||||||
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
|
||||||
nativeVertexLayout?.Release();
|
nativeVertexLayout?.Release();
|
||||||
nativeVertexLayout = vertexLayout?.nativeLayout..AddRef();
|
nativeVertexLayout = vertexLayout?.nativeLayout..AddRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void PlatformSetIndexBuffer(IndexBuffer indexBuffer)
|
protected override void PlatformSetIndexBuffer(IndexBuffer indexBuffer)
|
||||||
{
|
{
|
||||||
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
|
||||||
Log.EngineLogger.Assert(indexBuffer.nativeDescription.BindFlags.HasFlag(.IndexBuffer),
|
Log.EngineLogger.Assert(indexBuffer.nativeDescription.BindFlags.HasFlag(.IndexBuffer),
|
||||||
scope $"Buffer ({indexBuffer.nativeBuffer.GetDebugName(.. scope .())}) must have IndexBuffer-flag set to be bound as an index buffer.");
|
scope $"Buffer ({indexBuffer.nativeBuffer.GetDebugName(.. scope .())}) must have IndexBuffer-flag set to be bound as an index buffer.");
|
||||||
|
|
||||||
@@ -73,32 +83,33 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Bind(GraphicsContext context = null)
|
public override void Bind()
|
||||||
{
|
{
|
||||||
var context;
|
Debug.Profiler.ProfileRendererFunction!();
|
||||||
context ??= _context;
|
|
||||||
|
|
||||||
context.nativeContext.InputAssembler.SetVertexBuffers(0, nativeBuffers.Count, &nativeBuffers, &bufferStrides, &bufferOffsets);
|
NativeContext.InputAssembler.SetVertexBuffers(0, nativeBuffers.Count, &nativeBuffers, &bufferStrides, &bufferOffsets);
|
||||||
context.nativeContext.InputAssembler.SetInputLayout(_vertexLayout.nativeLayout);
|
NativeContext.InputAssembler.SetInputLayout(_vertexLayout.nativeLayout);
|
||||||
context.nativeContext.InputAssembler.SetPrimitiveTopology((.)_primitiveTopology);
|
NativeContext.InputAssembler.SetPrimitiveTopology((.)_primitiveTopology);
|
||||||
|
|
||||||
context.nativeContext.InputAssembler.SetIndexBuffer(_indexBuffer.nativeBuffer, _indexBuffer.Format == .Index32Bit ? .R32_UInt : .R16_UInt, _indexByteOffset);
|
if(_indexBuffer != null)
|
||||||
|
NativeContext.InputAssembler.SetIndexBuffer(_indexBuffer.nativeBuffer, _indexBuffer.Format == .Index32Bit ? .R32_UInt : .R16_UInt, _indexByteOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Unbind(GraphicsContext context = null)
|
public override void Unbind()
|
||||||
{
|
{
|
||||||
var context;
|
Debug.Profiler.ProfileRendererFunction!();
|
||||||
context ??= _context;
|
|
||||||
|
|
||||||
ID3D11Buffer*[nativeBuffers.Count] nullBuffers = .();
|
ID3D11Buffer*[nativeBuffers.Count] nullBuffers = .();
|
||||||
uint32[nativeBuffers.Count] zeroStrides = .();
|
uint32[nativeBuffers.Count] zeroStrides = .();
|
||||||
uint32[nativeBuffers.Count] zeroOffsets = .();
|
uint32[nativeBuffers.Count] zeroOffsets = .();
|
||||||
|
|
||||||
context.nativeContext.InputAssembler.SetVertexBuffers(0, nativeBuffers.Count, &nullBuffers, &zeroStrides, &zeroOffsets);
|
NativeContext.InputAssembler.SetVertexBuffers(0, nativeBuffers.Count, &nullBuffers, &zeroStrides, &zeroOffsets);
|
||||||
context.nativeContext.InputAssembler.SetInputLayout(null);
|
NativeContext.InputAssembler.SetInputLayout(null);
|
||||||
context.nativeContext.InputAssembler.SetPrimitiveTopology(.Undefined);
|
NativeContext.InputAssembler.SetPrimitiveTopology(.Undefined);
|
||||||
|
|
||||||
context.nativeContext.InputAssembler.SetIndexBuffer(null, .R16_UNorm, 0);
|
NativeContext.InputAssembler.SetIndexBuffer(null, .R16_UNorm, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#if GE_GRAPHICS_DX11
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using DirectX.Common;
|
using DirectX.Common;
|
||||||
@@ -6,9 +8,12 @@ using DirectX.D3D11.SDKLayers;
|
|||||||
using DirectX.DXGI.DXGI1_2;
|
using DirectX.DXGI.DXGI1_2;
|
||||||
using GlitchyEngine.Renderer;
|
using GlitchyEngine.Renderer;
|
||||||
using GlitchyEngine.Math;
|
using GlitchyEngine.Math;
|
||||||
|
using DirectX.D3D11.DeviceContextStages;
|
||||||
using internal GlitchyEngine.Renderer;
|
using internal GlitchyEngine.Renderer;
|
||||||
|
|
||||||
|
using GlitchyEngine.Platform.DX11;
|
||||||
|
using internal GlitchyEngine.Platform.DX11;
|
||||||
|
|
||||||
namespace GlitchyEngine.Renderer
|
namespace GlitchyEngine.Renderer
|
||||||
{
|
{
|
||||||
/// DirectX 11 specific implementation of the GraphicsContext
|
/// DirectX 11 specific implementation of the GraphicsContext
|
||||||
@@ -18,10 +23,12 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
internal Windows.HWnd nativeWindowHandle;
|
internal Windows.HWnd nativeWindowHandle;
|
||||||
|
|
||||||
internal ID3D11Device* nativeDevice;
|
/// Gets whether or not the DX11 device is initialized.
|
||||||
internal ID3D11DeviceContext* nativeContext;
|
//internal bool IsDx11Initialized => nativeDevice != null;
|
||||||
|
//internal ID3D11Device* nativeDevice => NativeDevice;
|
||||||
|
//internal ID3D11DeviceContext* nativeContext => NativeContext;
|
||||||
|
|
||||||
private ID3D11Debug* _debugDevice;
|
//internal ID3D11Debug* debugDevice => DebugDevice;
|
||||||
|
|
||||||
public override SwapChain SwapChain => _swapChain;
|
public override SwapChain SwapChain => _swapChain;
|
||||||
|
|
||||||
@@ -31,24 +38,29 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
public this(Windows.HWnd windowHandle)
|
public this(Windows.HWnd windowHandle)
|
||||||
{
|
{
|
||||||
|
Debug.Profiler.ProfileFunction!();
|
||||||
|
|
||||||
nativeWindowHandle = windowHandle;
|
nativeWindowHandle = windowHandle;
|
||||||
|
|
||||||
_swapChain = new SwapChain(this);
|
_swapChain = new SwapChain(this);
|
||||||
|
|
||||||
|
s_GraphicsContext = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ~this()
|
public ~this()
|
||||||
{
|
{
|
||||||
|
Debug.Profiler.ProfileFunction!();
|
||||||
|
|
||||||
delete _swapChain;
|
delete _swapChain;
|
||||||
|
|
||||||
nativeDevice?.Release();
|
Dx11Release();
|
||||||
nativeContext?.Release();
|
|
||||||
_debugDevice.ReportLiveDeviceObjects(.Detail);
|
|
||||||
_debugDevice?.Release();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Init()
|
public override void Init()
|
||||||
{
|
{
|
||||||
InitDevice();
|
Debug.Profiler.ProfileFunction!();
|
||||||
|
|
||||||
|
Dx11Init();
|
||||||
|
|
||||||
SwapChain.Init();
|
SwapChain.Init();
|
||||||
}
|
}
|
||||||
@@ -56,11 +68,11 @@ namespace GlitchyEngine.Renderer
|
|||||||
/**
|
/**
|
||||||
* Initializes the Device and ImmediateContext.
|
* Initializes the Device and ImmediateContext.
|
||||||
*/
|
*/
|
||||||
|
/*
|
||||||
void InitDevice()
|
void InitDevice()
|
||||||
{
|
{
|
||||||
nativeDevice?.Release();
|
if(!IsDx11Initialized)
|
||||||
nativeContext?.Release();
|
{
|
||||||
|
|
||||||
Log.EngineLogger.Trace("Creating D3D11 Device and Context...");
|
Log.EngineLogger.Trace("Creating D3D11 Device and Context...");
|
||||||
|
|
||||||
DeviceCreationFlags deviceFlags = .None;
|
DeviceCreationFlags deviceFlags = .None;
|
||||||
@@ -72,10 +84,10 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
FeatureLevel deviceLevel = ?;
|
FeatureLevel deviceLevel = ?;
|
||||||
var deviceResult = D3D11.CreateDevice(null, .Hardware, 0, deviceFlags, levels, &nativeDevice, &deviceLevel, &nativeContext);
|
var deviceResult = D3D11.CreateDevice(null, .Hardware, 0, deviceFlags, levels, &nativeDevice, &deviceLevel, &nativeContext);
|
||||||
Debug.Assert(deviceResult.Succeeded, scope $"Failed to create D3D11 Device. Message(0x{(int32)deviceResult}): {deviceResult}");
|
Log.EngineLogger.Assert(deviceResult.Succeeded, scope $"Failed to create D3D11 Device. Message({(int32)deviceResult}): {deviceResult}");
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
if(nativeDevice.QueryInterface<ID3D11Debug>(out _debugDevice).Succeeded)
|
if(nativeDevice.QueryInterface<ID3D11Debug>(out debugDevice).Succeeded)
|
||||||
{
|
{
|
||||||
ID3D11InfoQueue* infoQueue;
|
ID3D11InfoQueue* infoQueue;
|
||||||
if(nativeDevice.QueryInterface<ID3D11InfoQueue>(out infoQueue).Succeeded)
|
if(nativeDevice.QueryInterface<ID3D11InfoQueue>(out infoQueue).Succeeded)
|
||||||
@@ -90,104 +102,149 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
Log.EngineLogger.Trace($"D3D11 Device and Context created (Feature level: {deviceLevel})");
|
Log.EngineLogger.Trace($"D3D11 Device and Context created (Feature level: {deviceLevel})");
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We created a second GraphicsContext (for some reason?) just increment references.
|
||||||
|
nativeDevice.AddRef();
|
||||||
|
nativeContext.AddRef();
|
||||||
|
debugDevice.AddRef();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
private ID3D11DepthStencilView* _depthStencilTarget;
|
private ID3D11DepthStencilView* _depthStencilTarget;
|
||||||
private ID3D11RenderTargetView*[MaxRTVCount] _renderTargets;
|
private ID3D11RenderTargetView*[MaxRTVCount] _renderTargets;
|
||||||
|
|
||||||
internal void SetDepthStencilTarget(DepthStencilTarget target)
|
public override void SetDepthStencilTarget(DepthStencilTarget target)
|
||||||
{
|
{
|
||||||
_depthStencilTarget = target?.nativeView;
|
_depthStencilTarget = target?.nativeView;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void SetRenderTarget(RenderTarget renderTarget, int slot = 0)
|
public override void SetRenderTarget(RenderTarget2D renderTarget, int slot, bool setDepthTarget)
|
||||||
{
|
{
|
||||||
if(renderTarget == null)
|
_renderTargets[slot] = (renderTarget ?? _swapChain.BackBuffer)._nativeRenderTargetView;
|
||||||
|
|
||||||
|
if(slot == 0 && setDepthTarget)
|
||||||
{
|
{
|
||||||
_renderTargets[slot] = _swapChain.nativeBackBufferTarget;
|
SetDepthStencilTarget((renderTarget ?? _swapChain.BackBuffer).DepthStencilTarget);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Runtime.NotImplemented();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void BindRenderTargets()
|
public override void BindRenderTargets()
|
||||||
{
|
{
|
||||||
nativeContext.OutputMerger.SetRenderTargets(MaxRTVCount, &_renderTargets, _depthStencilTarget);
|
NativeContext.OutputMerger.SetRenderTargets(MaxRTVCount, &_renderTargets, _depthStencilTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ClearRenderTarget(RenderTarget renderTarget, ColorRGBA color)
|
public override void ClearRenderTarget(RenderTarget2D renderTarget, ColorRGBA color)
|
||||||
{
|
{
|
||||||
if(renderTarget == null)
|
NativeContext.ClearRenderTargetView((renderTarget ?? _swapChain.BackBuffer)._nativeRenderTargetView, color);
|
||||||
{
|
|
||||||
nativeContext.ClearRenderTargetView(_swapChain.nativeBackBufferTarget, color);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Runtime.NotImplemented();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void SetVertexBuffer(uint32 slot, Buffer buffer, uint32 stride, uint32 offset = 0)
|
public override void SetVertexBuffer(uint32 slot, Buffer buffer, uint32 stride, uint32 offset = 0)
|
||||||
{
|
{
|
||||||
// make stride and offset mutable so that we can take their pointers.
|
// make stride and offset mutable so that we can take their pointers.
|
||||||
var stride, offset;
|
var stride, offset;
|
||||||
nativeContext.InputAssembler.SetVertexBuffers(slot, 1, &buffer.nativeBuffer, &stride, &offset);
|
NativeContext.InputAssembler.SetVertexBuffers(slot, 1, &buffer.nativeBuffer, &stride, &offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Draw(uint32 vertexCount, uint32 startVertexIndex = 0)
|
public override void Draw(uint32 vertexCount, uint32 startVertexIndex = 0)
|
||||||
{
|
{
|
||||||
nativeContext.Draw(vertexCount, startVertexIndex);
|
NativeContext.Draw(vertexCount, startVertexIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void DrawIndexed(uint32 indexCount, uint32 startIndexLocation = 0, int32 vertexOffset = 0)
|
public override void DrawIndexed(uint32 indexCount, uint32 startIndexLocation = 0, int32 vertexOffset = 0)
|
||||||
{
|
{
|
||||||
nativeContext.DrawIndexed(indexCount, startIndexLocation, vertexOffset);
|
NativeContext.DrawIndexed(indexCount, startIndexLocation, vertexOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void SetIndexBuffer(Buffer buffer, IndexFormat indexFormat = .Index16Bit, uint32 byteOffset = 0)
|
public override void SetIndexBuffer(Buffer buffer, IndexFormat indexFormat = .Index16Bit, uint32 byteOffset = 0)
|
||||||
{
|
{
|
||||||
nativeContext.InputAssembler.SetIndexBuffer(buffer.nativeBuffer, indexFormat == .Index32Bit ? .R32_UInt : .R16_UInt, byteOffset);
|
NativeContext.InputAssembler.SetIndexBuffer(buffer.nativeBuffer, indexFormat == .Index32Bit ? .R32_UInt : .R16_UInt, byteOffset);
|
||||||
}
|
|
||||||
|
|
||||||
protected override void SetRasterizerStateImpl()
|
|
||||||
{
|
|
||||||
nativeContext.Rasterizer.SetState(_currentRasterizerState.nativeRasterizerState);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void SetViewports(uint32 viewportsCount, GlitchyEngine.Renderer.Viewport* viewports)
|
public override void SetViewports(uint32 viewportsCount, GlitchyEngine.Renderer.Viewport* viewports)
|
||||||
{
|
{
|
||||||
nativeContext.Rasterizer.SetViewports(viewportsCount, (.)viewports);
|
NativeContext.Rasterizer.SetViewports(viewportsCount, (.)viewports);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void SetVertexLayout(VertexLayout vertexLayout)
|
public override void SetVertexLayout(VertexLayout vertexLayout)
|
||||||
{
|
{
|
||||||
nativeContext.InputAssembler.SetInputLayout(vertexLayout.nativeLayout);
|
NativeContext.InputAssembler.SetInputLayout(vertexLayout.nativeLayout);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void SetPrimitiveTopology(GlitchyEngine.Renderer.PrimitiveTopology primitiveTopology)
|
public override void SetPrimitiveTopology(GlitchyEngine.Renderer.PrimitiveTopology primitiveTopology)
|
||||||
{
|
{
|
||||||
nativeContext.InputAssembler.SetPrimitiveTopology((DirectX.Common.PrimitiveTopology)primitiveTopology);
|
NativeContext.InputAssembler.SetPrimitiveTopology((DirectX.Common.PrimitiveTopology)primitiveTopology);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binds the given shader to the corresponding shader stage.
|
||||||
|
* @param shader The shader that will be bound to the graphics context.
|
||||||
|
*/
|
||||||
|
private void BindShaderToStage<TShader>(TShader shader) where TShader : Shader
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileRendererFunction!();
|
||||||
|
|
||||||
|
uint32 _firstTexture = D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT;
|
||||||
|
uint32 _textureCount = 0;
|
||||||
|
|
||||||
|
ID3D11ShaderResourceView*[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT] _textures = .();
|
||||||
|
ID3D11SamplerState*[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT] _samplers = .();
|
||||||
|
|
||||||
|
for(let entry in shader.Textures)
|
||||||
|
{
|
||||||
|
_textures[entry.Index] = entry.Texture?.nativeResourceView;
|
||||||
|
_samplers[entry.Index] = entry.Texture?.SamplerState?.nativeSamplerState;
|
||||||
|
|
||||||
|
if(entry.Index >= _textureCount)
|
||||||
|
_textureCount = entry.Index + 1;
|
||||||
|
if(entry.Index < _firstTexture)
|
||||||
|
_firstTexture = entry.Index;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_textureCount > 0)
|
||||||
|
{
|
||||||
|
switch(typeof(TShader))
|
||||||
|
{
|
||||||
|
// TODO: Add remaining shader stages
|
||||||
|
case typeof(PixelShader):
|
||||||
|
// TODO: bind uavs
|
||||||
|
NativeContext.PixelShader.SetShaderResources(_firstTexture, _textureCount, &_textures[_firstTexture]);
|
||||||
|
NativeContext.PixelShader.SetSamplers(_firstTexture, _textureCount, &_samplers[_firstTexture]);
|
||||||
|
case typeof(VertexShader):
|
||||||
|
NativeContext.VertexShader.SetShaderResources(_firstTexture, _textureCount, &_textures[_firstTexture]);
|
||||||
|
NativeContext.VertexShader.SetSamplers(_firstTexture, _textureCount, &_samplers[_firstTexture]);
|
||||||
|
default:
|
||||||
|
Runtime.FatalError(scope $"Shader stage \"{typeof(TShader)}\" not implemented.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shader.Buffers.PlatformFetchNativeBuffers();
|
||||||
|
|
||||||
|
switch(typeof(TShader))
|
||||||
|
{
|
||||||
|
// TODO: Add remaining shader stages
|
||||||
|
case typeof(PixelShader):
|
||||||
|
NativeContext.PixelShader.SetConstantBuffers(0, shader.Buffers.nativeBuffers.Count, &shader.Buffers.nativeBuffers);
|
||||||
|
[IgnoreErrors]{ NativeContext.PixelShader.SetShader(((PixelShader)shader).nativeShader); }
|
||||||
|
case typeof(VertexShader):
|
||||||
|
NativeContext.VertexShader.SetConstantBuffers(0, shader.Buffers.nativeBuffers.Count, &shader.Buffers.nativeBuffers);
|
||||||
|
[IgnoreErrors]{ NativeContext.VertexShader.SetShader(((VertexShader)shader).nativeShader); }
|
||||||
|
default:
|
||||||
|
Runtime.FatalError(scope $"Shader stage \"{typeof(TShader)}\" not implemented.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void SetVertexShader(VertexShader vertexShader)
|
public override void SetVertexShader(VertexShader vertexShader)
|
||||||
{
|
{
|
||||||
//Todo: nativeContext.VertexShader.SetSamplers();
|
BindShaderToStage(vertexShader);
|
||||||
vertexShader.Buffers.PlatformFetchNativeBuffers();
|
|
||||||
nativeContext.VertexShader.SetConstantBuffers(0, vertexShader.Buffers.nativeBuffers.Count, &vertexShader.Buffers.nativeBuffers);
|
|
||||||
//Todo: nativeContext.VertexShader.SetShaderResources();
|
|
||||||
nativeContext.VertexShader.SetShader(vertexShader.nativeShader);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void SetPixelShader(PixelShader pixelShader)
|
public override void SetPixelShader(PixelShader pixelShader)
|
||||||
{
|
{
|
||||||
//Todo: nativeContext.PixelShader.SetSamplers();
|
BindShaderToStage(pixelShader);
|
||||||
pixelShader.Buffers.PlatformFetchNativeBuffers();
|
|
||||||
nativeContext.PixelShader.SetConstantBuffers(0, pixelShader.Buffers.nativeBuffers.Count, &pixelShader.Buffers.nativeBuffers);
|
|
||||||
//Todo: nativeContext.PixelShader.SetShaderResources();
|
|
||||||
nativeContext.PixelShader.SetShader(pixelShader.nativeShader);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
|
#if GE_GRAPHICS_DX11
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using DirectX.D3D11;
|
using DirectX.D3D11;
|
||||||
using DirectX.D3DCompiler;
|
using DirectX.D3DCompiler;
|
||||||
|
using GlitchyEngine.Platform.DX11;
|
||||||
|
|
||||||
using internal GlitchyEngine.Renderer;
|
using internal GlitchyEngine.Renderer;
|
||||||
|
using internal GlitchyEngine.Platform.DX11;
|
||||||
|
|
||||||
namespace GlitchyEngine.Renderer
|
namespace GlitchyEngine.Renderer
|
||||||
{
|
{
|
||||||
@@ -12,15 +16,23 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
public override void CompileFromSource(String code, String entryPoint, ShaderDefine[] macros = null)
|
public override void CompileFromSource(String code, String entryPoint, ShaderDefine[] macros = null)
|
||||||
{
|
{
|
||||||
|
Debug.Profiler.ProfileRendererFunction!();
|
||||||
|
|
||||||
Shader.PlattformCompileShaderFromSource(code, macros, entryPoint, "ps_5_0", DefaultCompileFlags, out nativeCode);
|
Shader.PlattformCompileShaderFromSource(code, macros, entryPoint, "ps_5_0", DefaultCompileFlags, out nativeCode);
|
||||||
|
|
||||||
var result = _context.nativeDevice.CreatePixelShader(nativeCode.GetBufferPointer(), nativeCode.GetBufferSize(), null, &nativeShader);
|
{
|
||||||
|
Debug.Profiler.ProfileResourceScope!("CreateNativePixelShader");
|
||||||
|
|
||||||
|
var result = NativeDevice.CreatePixelShader(nativeCode.GetBufferPointer(), nativeCode.GetBufferSize(), null, &nativeShader);
|
||||||
if(result.Failed)
|
if(result.Failed)
|
||||||
{
|
{
|
||||||
Log.EngineLogger.Error($"Failed to create pixel shader: Message ({(int)result}): {result}");
|
Log.EngineLogger.Error($"Failed to create pixel shader: Message ({(int)result}): {result}");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Reflect(nativeCode);
|
Reflect(nativeCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
|
#if GE_GRAPHICS_DX11
|
||||||
|
|
||||||
using DirectX.D3D11;
|
using DirectX.D3D11;
|
||||||
|
using GlitchyEngine.Platform.DX11;
|
||||||
|
|
||||||
using internal GlitchyEngine.Renderer;
|
using internal GlitchyEngine.Renderer;
|
||||||
|
using internal GlitchyEngine.Platform.DX11;
|
||||||
|
|
||||||
namespace GlitchyEngine.Renderer
|
namespace GlitchyEngine.Renderer
|
||||||
{
|
{
|
||||||
@@ -48,12 +52,14 @@ namespace GlitchyEngine.Renderer
|
|||||||
internal DirectX.D3D11.RasterizerStateDescription nativeDescription;
|
internal DirectX.D3D11.RasterizerStateDescription nativeDescription;
|
||||||
internal ID3D11RasterizerState* nativeRasterizerState ~ _?.Release();
|
internal ID3D11RasterizerState* nativeRasterizerState ~ _?.Release();
|
||||||
|
|
||||||
public override this(GraphicsContext context, GlitchyEngine.Renderer.RasterizerStateDescription description) : this(context)
|
public override this(GlitchyEngine.Renderer.RasterizerStateDescription description)
|
||||||
{
|
{
|
||||||
|
Debug.Profiler.ProfileRendererFunction!();
|
||||||
|
|
||||||
_description = description;
|
_description = description;
|
||||||
nativeDescription = (.)_description;
|
nativeDescription = (.)_description;
|
||||||
|
|
||||||
var result = context.nativeDevice.CreateRasterizerState(ref nativeDescription, &nativeRasterizerState);
|
var result = NativeDevice.CreateRasterizerState(ref nativeDescription, &nativeRasterizerState);
|
||||||
if(result.Failed)
|
if(result.Failed)
|
||||||
{
|
{
|
||||||
Log.EngineLogger.Error($"Failed to create rasterizer state. Message({(int)result}): {result}");
|
Log.EngineLogger.Error($"Failed to create rasterizer state. Message({(int)result}): {result}");
|
||||||
@@ -61,3 +67,5 @@ namespace GlitchyEngine.Renderer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -0,0 +1,125 @@
|
|||||||
|
#if GE_GRAPHICS_DX11
|
||||||
|
|
||||||
|
using DirectX.Common;
|
||||||
|
using DirectX.D3D11;
|
||||||
|
using GlitchyEngine.Platform.DX11;
|
||||||
|
using DirectX.DXGI.DXGI1_2;
|
||||||
|
|
||||||
|
using internal GlitchyEngine.Platform.DX11;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Renderer
|
||||||
|
{
|
||||||
|
using internal GlitchyEngine.Renderer;
|
||||||
|
|
||||||
|
extension RenderTarget2D
|
||||||
|
{
|
||||||
|
protected internal ID3D11Texture2D* _nativeTexture ~ _?.Release();
|
||||||
|
protected internal ID3D11ShaderResourceView* _nativeResourceView ~ _?.Release();
|
||||||
|
protected internal ID3D11RenderTargetView* _nativeRenderTargetView ~ _?.Release();
|
||||||
|
|
||||||
|
private void ReleaseAndNullify()
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
|
||||||
|
ReleaseAndNullify!(_nativeTexture);
|
||||||
|
ReleaseAndNullify!(_nativeResourceView);
|
||||||
|
ReleaseAndNullify!(_nativeRenderTargetView);
|
||||||
|
|
||||||
|
ReleaseRefAndNullify!(_depthStenilTarget);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Resize(uint32 width, uint32 height)
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
|
||||||
|
ReleaseAndNullify();
|
||||||
|
|
||||||
|
_description.Width = width;
|
||||||
|
_description.Height = height;
|
||||||
|
|
||||||
|
ApplyChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void PlatformApplyChanges()
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
|
||||||
|
ReleaseAndNullify();
|
||||||
|
|
||||||
|
if(_description.IsSwapchainTarget)
|
||||||
|
{
|
||||||
|
// TODO: if the engine supports multiple windows it has to support multiple swap chains.
|
||||||
|
|
||||||
|
// kinda dirty...
|
||||||
|
var context = GraphicsContext.Get();
|
||||||
|
|
||||||
|
context.SwapChain.GetBackbuffer(out _nativeTexture);
|
||||||
|
|
||||||
|
CreateViews();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PlatformCreateTexture();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_description.DepthStencilFormat != .None)
|
||||||
|
{
|
||||||
|
_depthStenilTarget = new DepthStencilTarget(_description.Width, _description.Height, _description.DepthStencilFormat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PlatformCreateTexture()
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
|
||||||
|
Texture2DDescription desc = .()
|
||||||
|
{
|
||||||
|
Width = _description.Width,
|
||||||
|
Height = _description.Height,
|
||||||
|
ArraySize = _description.ArraySize,
|
||||||
|
MipLevels = _description.MipLevels,
|
||||||
|
Format = _description.PixelFormat,
|
||||||
|
// Always bindable as ShaderResource and RenderTarget
|
||||||
|
BindFlags = .ShaderResource | .RenderTarget,
|
||||||
|
CpuAccessFlags = (.)_description.CpuAccess,
|
||||||
|
// 2D RenderTarget never has misc flags
|
||||||
|
MiscFlags = .None,
|
||||||
|
SampleDesc = .(_description.SampleCount, _description.SampleQuality),
|
||||||
|
// RenderTarget has always Default usage
|
||||||
|
Usage = .Default
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = NativeDevice.CreateTexture2D(ref desc, null, &_nativeTexture);
|
||||||
|
Log.EngineLogger.Assert(result.Succeeded, "Failed to create RenderTarget2D");
|
||||||
|
|
||||||
|
CreateViews();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateViews()
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
|
||||||
|
if(_description.IsSwapchainTarget)
|
||||||
|
{
|
||||||
|
var result = NativeDevice.CreateShaderResourceView(_nativeTexture, null, &_nativeResourceView);
|
||||||
|
Log.EngineLogger.Assert(result.Succeeded, "Failed to create resource view");
|
||||||
|
|
||||||
|
// TODO: SRGB...
|
||||||
|
//RenderTargetViewDescription rtvDesc = .(_nativeTexture, .Texture2D, .R8G8B8A8_UNorm_SRGB);
|
||||||
|
//result = NativeDevice.CreateRenderTargetView(_nativeTexture, &rtvDesc, &_nativeRenderTargetView);
|
||||||
|
result = NativeDevice.CreateRenderTargetView(_nativeTexture, null, &_nativeRenderTargetView);
|
||||||
|
Log.EngineLogger.Assert(result.Succeeded, "Failed to create render target view");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var result = NativeDevice.CreateShaderResourceView(_nativeTexture, null, &_nativeResourceView);
|
||||||
|
Log.EngineLogger.Assert(result.Succeeded, "Failed to create resource view");
|
||||||
|
|
||||||
|
result = NativeDevice.CreateRenderTargetView(_nativeTexture, null, &_nativeRenderTargetView);
|
||||||
|
Log.EngineLogger.Assert(result.Succeeded, "Failed to create render target view");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,39 +1,141 @@
|
|||||||
|
#if GE_GRAPHICS_DX11
|
||||||
|
|
||||||
using GlitchyEngine.Math;
|
using GlitchyEngine.Math;
|
||||||
|
using GlitchyEngine.Platform.DX11;
|
||||||
|
|
||||||
using internal GlitchyEngine.Renderer;
|
using internal GlitchyEngine.Renderer;
|
||||||
|
using internal GlitchyEngine.Platform.DX11;
|
||||||
|
|
||||||
namespace GlitchyEngine.Renderer
|
namespace GlitchyEngine.Renderer
|
||||||
{
|
{
|
||||||
|
using internal GlitchyEngine.Renderer;
|
||||||
|
|
||||||
extension RendererAPI
|
extension RendererAPI
|
||||||
{
|
{
|
||||||
private GraphicsContext _context;
|
private GraphicsContext _context ~ _?.ReleaseRef();
|
||||||
|
|
||||||
public GraphicsContext Context
|
public GraphicsContext Context
|
||||||
{
|
{
|
||||||
get => _context;
|
get => _context;
|
||||||
set => _context = value;
|
set => SetReference!(_context, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static override API Api => .D3D11;
|
public static override API Api => .D3D11;
|
||||||
|
|
||||||
public override void Init()
|
public override void Init()
|
||||||
{
|
{
|
||||||
|
Debug.Profiler.ProfileFunction!();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Clear(RenderTarget renderTarget, ColorRGBA clearColor)
|
private mixin RtOrBackbuffer(RenderTarget2D renderTarget)
|
||||||
{
|
{
|
||||||
_context.ClearRenderTarget(renderTarget, clearColor);
|
renderTarget ?? _context.SwapChain.BackBuffer
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Clear(DepthStencilTarget target, float depthValue, uint8 stencilValue, DepthStencilClearFlag clearFlags)
|
public override void Clear(RenderTarget2D renderTarget, ColorRGBA color)
|
||||||
{
|
{
|
||||||
_context.nativeContext.ClearDepthStencilView(target.nativeView, (.)clearFlags, depthValue, stencilValue);
|
Debug.Profiler.ProfileRendererFunction!();
|
||||||
|
|
||||||
|
NativeContext.ClearRenderTargetView(RtOrBackbuffer!(renderTarget)._nativeRenderTargetView, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Clear(DepthStencilTarget target, ClearOptions clearOptions, float depth, uint8 stencil)
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileRendererFunction!();
|
||||||
|
|
||||||
|
if(target == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
DirectX.D3D11.ClearFlag flags = default;
|
||||||
|
|
||||||
|
if(clearOptions.HasFlag(.Depth))
|
||||||
|
{
|
||||||
|
flags |= .Depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(clearOptions.HasFlag(.Stencil))
|
||||||
|
{
|
||||||
|
flags |= .Stencil;
|
||||||
|
}
|
||||||
|
|
||||||
|
NativeContext.ClearDepthStencilView(target.nativeView, flags, depth, stencil);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetRenderTarget(RenderTarget2D renderTarget, int slot, bool setDepthBuffer)
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileRendererFunction!();
|
||||||
|
|
||||||
|
_context.SetRenderTarget(renderTarget, slot, setDepthBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetDepthStencilTarget(DepthStencilTarget target)
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileRendererFunction!();
|
||||||
|
|
||||||
|
_context.SetDepthStencilTarget(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void BindRenderTargets()
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileRendererFunction!();
|
||||||
|
|
||||||
|
_context.BindRenderTargets();
|
||||||
|
}
|
||||||
|
|
||||||
|
private RasterizerState _currentRasterizerState ~ _?.ReleaseRef();
|
||||||
|
|
||||||
|
public override void SetRasterizerState(RasterizerState rasterizerState)
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileRendererFunction!();
|
||||||
|
|
||||||
|
SetReference!(_currentRasterizerState, rasterizerState);
|
||||||
|
NativeContext.Rasterizer.SetState(_currentRasterizerState.nativeRasterizerState);
|
||||||
|
}
|
||||||
|
|
||||||
|
private BlendState _currentBlendState ~ _?.ReleaseRef();
|
||||||
|
|
||||||
|
public override void SetBlendState(BlendState blendState, ColorRGBA blendFactor)
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileRendererFunction!();
|
||||||
|
|
||||||
|
SetReference!(_currentBlendState, blendState);
|
||||||
|
NativeContext.OutputMerger.SetBlendState(_currentBlendState.nativeBlendState, blendFactor);
|
||||||
|
}
|
||||||
|
|
||||||
|
private DepthStencilState _currentDepthStencilState ~ _?.ReleaseRef();
|
||||||
|
|
||||||
|
public override void SetDepthStencilState(DepthStencilState depthStencilState, uint8 stencilReference)
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileRendererFunction!();
|
||||||
|
|
||||||
|
SetReference!(_currentDepthStencilState, depthStencilState);
|
||||||
|
NativeContext.OutputMerger.SetDepthStencilState(_currentDepthStencilState.nativeDepthStencilState, stencilReference);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void DrawIndexed(GeometryBinding geometry)
|
public override void DrawIndexed(GeometryBinding geometry)
|
||||||
{
|
{
|
||||||
|
Debug.Profiler.ProfileRendererFunction!();
|
||||||
|
|
||||||
|
if(geometry.IsIndexed)
|
||||||
_context.DrawIndexed(geometry.IndexCount, geometry.IndexByteOffset, 0);
|
_context.DrawIndexed(geometry.IndexCount, geometry.IndexByteOffset, 0);
|
||||||
|
else
|
||||||
|
_context.Draw(geometry.VertexCount, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void DrawIndexedInstanced(GeometryBinding geometry)
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileRendererFunction!();
|
||||||
|
|
||||||
|
NativeContext.DrawIndexedInstanced(geometry.IndexCount, geometry.InstanceCount, geometry.IndexByteOffset, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetViewport(Viewport viewport)
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileRendererFunction!();
|
||||||
|
|
||||||
|
_context.SetViewport(viewport);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
using DirectX.D3D11;
|
#if GE_GRAPHICS_DX11
|
||||||
|
|
||||||
using DirectX.Common;
|
using DirectX.Common;
|
||||||
|
using DirectX.D3D11;
|
||||||
|
using GlitchyEngine.Platform.DX11;
|
||||||
|
|
||||||
|
using internal GlitchyEngine.Renderer;
|
||||||
|
using internal GlitchyEngine.Platform.DX11;
|
||||||
|
|
||||||
namespace DirectX.D3D11
|
namespace DirectX.D3D11
|
||||||
{
|
{
|
||||||
@@ -73,8 +79,6 @@ namespace DirectX.D3D11
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
using internal GlitchyEngine.Renderer;
|
|
||||||
|
|
||||||
namespace GlitchyEngine.Renderer
|
namespace GlitchyEngine.Renderer
|
||||||
{
|
{
|
||||||
extension SamplerStateDescription
|
extension SamplerStateDescription
|
||||||
@@ -107,17 +111,21 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
protected override void PlatformCreateSamplerState()
|
protected override void PlatformCreateSamplerState()
|
||||||
{
|
{
|
||||||
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
|
||||||
_desc.ToNative(var nativeDesc);
|
_desc.ToNative(var nativeDesc);
|
||||||
|
|
||||||
HResult result = _context.nativeDevice.CreateSamplerState(ref nativeDesc, &nativeSamplerState);
|
HResult result = NativeDevice.CreateSamplerState(ref nativeDesc, &nativeSamplerState);
|
||||||
|
|
||||||
Log.EngineLogger.Assert(result.Succeeded, scope $"Failed to create SamplerState. Error({(int)result}): {result}");
|
Log.EngineLogger.Assert(result.Succeeded, scope $"Failed to create SamplerState. Error({(int)result}): {result}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Bind(uint32 slot)
|
public override void Bind(uint32 slot)
|
||||||
{
|
{
|
||||||
_context.nativeContext.VertexShader.SetSamplers(slot, 1, &nativeSamplerState);
|
NativeContext.VertexShader.SetSamplers(slot, 1, &nativeSamplerState);
|
||||||
_context.nativeContext.PixelShader.SetSamplers(slot, 1, &nativeSamplerState);
|
NativeContext.PixelShader.SetSamplers(slot, 1, &nativeSamplerState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#if GE_GRAPHICS_DX11
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using GlitchyEngine.Renderer;
|
using GlitchyEngine.Renderer;
|
||||||
using DirectX.Common;
|
using DirectX.Common;
|
||||||
@@ -16,7 +18,7 @@ namespace GlitchyEngine.Renderer
|
|||||||
*/
|
*/
|
||||||
internal ID3DBlob* nativeCode ~ _?.Release();
|
internal ID3DBlob* nativeCode ~ _?.Release();
|
||||||
|
|
||||||
protected const ShaderCompileFlags DefaultCompileFlags =
|
protected const ShaderCompileFlags DefaultCompileFlags = .EnableStrictness |
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
.Debug;
|
.Debug;
|
||||||
#else
|
#else
|
||||||
@@ -25,6 +27,8 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
internal static void PlattformCompileShaderFromSource(String code, ShaderDefine[] macros, String entryPoint, String target, ShaderCompileFlags compileFlags, out ID3DBlob* shaderBlob)
|
internal static void PlattformCompileShaderFromSource(String code, ShaderDefine[] macros, String entryPoint, String target, ShaderCompileFlags compileFlags, out ID3DBlob* shaderBlob)
|
||||||
{
|
{
|
||||||
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
|
||||||
ShaderMacro* nativeMacros = macros == null ? null : new:ScopedAlloc! ShaderMacro[macros.Count]*;
|
ShaderMacro* nativeMacros = macros == null ? null : new:ScopedAlloc! ShaderMacro[macros.Count]*;
|
||||||
|
|
||||||
for(int i < macros?.Count ?? 0)
|
for(int i < macros?.Count ?? 0)
|
||||||
@@ -42,72 +46,67 @@ namespace GlitchyEngine.Renderer
|
|||||||
var result = D3DCompiler.D3DCompile(code.CStr(), (.)code.Length, null, nativeMacros, null, entryPoint, target, compileFlags, .None, &shaderBlob, &errorBlob);
|
var result = D3DCompiler.D3DCompile(code.CStr(), (.)code.Length, null, nativeMacros, null, entryPoint, target, compileFlags, .None, &shaderBlob, &errorBlob);
|
||||||
if(result.Failed)
|
if(result.Failed)
|
||||||
{
|
{
|
||||||
StringView str = StringView((char8*)errorBlob.GetBufferPointer(), errorBlob.GetBufferSize());
|
StringView str = StringView((char8*)errorBlob.GetBufferPointer(), (int)errorBlob.GetBufferSize());
|
||||||
Log.EngineLogger.Error($"Failed to compile Shader: Error Code({(int)result}): {result} | Error Message: {str}");
|
Log.EngineLogger.Error($"Failed to compile Shader: Error Code({(int)result}): {result} | Error Message: {str}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected internal void Reflect(ID3DBlob* shaderCode)
|
protected internal void Reflect(ID3DBlob* shaderCode)
|
||||||
{
|
{
|
||||||
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
|
||||||
ID3D11ShaderReflection* reflection = null;
|
ID3D11ShaderReflection* reflection = null;
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileResourceScope!("D3DReflect");
|
||||||
|
|
||||||
var result = D3DCompiler.D3DReflect(shaderCode.GetBufferPointer(), shaderCode.GetBufferSize(), &reflection);
|
var result = D3DCompiler.D3DReflect(shaderCode.GetBufferPointer(), shaderCode.GetBufferSize(), &reflection);
|
||||||
if(result.Failed)
|
if(result.Failed)
|
||||||
{
|
{
|
||||||
Log.EngineLogger.Error($"Failed to reflect shader: Message ({(int)result}): {result}");
|
Log.EngineLogger.Error($"Failed to reflect shader: Message ({(int)result}): {result}");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
reflection.GetDescription(let desc);
|
reflection.GetDescription(let desc);
|
||||||
uint32 cBufferCount = desc.ConstantBuffers;
|
|
||||||
|
|
||||||
for(uint32 i < cBufferCount)
|
uint32 resourceCount = desc.BoundResources;
|
||||||
|
for (uint32 i < resourceCount)
|
||||||
{
|
{
|
||||||
reflection.GetResourceBindingDescription(i, let bindDesc);
|
var res = reflection.GetResourceBindingDescription(i, let bindDesc);
|
||||||
|
|
||||||
var bufferReflection = reflection.GetConstantBufferByIndex(i);
|
if (res.Failed)
|
||||||
|
{
|
||||||
|
Log.EngineLogger.Error($"Error({(int)res}) {res}: Failed to get resource binding desc for resource {i}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(bindDesc.Type)
|
||||||
|
{
|
||||||
|
case .ConstantBuffer:
|
||||||
|
var bufferReflection = reflection.GetConstantBufferByName(bindDesc.Name);
|
||||||
|
|
||||||
bufferReflection.GetDescription(let bufferDesc);
|
bufferReflection.GetDescription(let bufferDesc);
|
||||||
|
|
||||||
// ConstantBuffer
|
// ConstantBuffer
|
||||||
if(bufferDesc.Type == .D3D11_CT_CBUFFER)
|
if(bufferDesc.Type == .D3D11_CT_CBUFFER)
|
||||||
{
|
{
|
||||||
let buffer = new ConstantBuffer(_context, bufferReflection);
|
let buffer = new ConstantBuffer(bufferReflection);
|
||||||
|
|
||||||
_buffers.Add(bindDesc.BindPoint, buffer.Name, buffer);
|
_buffers.Add(bindDesc.BindPoint, buffer.Name, buffer);
|
||||||
|
|
||||||
buffer.ReleaseRef();
|
buffer.ReleaseRef();
|
||||||
}
|
}
|
||||||
/*
|
case .Texture:
|
||||||
bufferReflection.GetDescription(let bufferDesc);
|
_textures.Add(scope String(bindDesc.Name), bindDesc.BindPoint, null);
|
||||||
|
case .Sampler:
|
||||||
// ConstantBuffer
|
// TODO: do we have to do something for samplers?
|
||||||
if(bufferDesc.Type == .D3D11_CT_CBUFFER)
|
default:
|
||||||
{
|
Log.EngineLogger.Warning($"Unhandled shader resource type: \"{bindDesc.Type}\"");
|
||||||
GlitchyEngine.Renderer.BufferDescription cBufferDesc = .(bufferDesc.Size, .Constant, .Dynamic, .Write);
|
}
|
||||||
|
|
||||||
let buffer = new Buffer(_context, cBufferDesc);
|
|
||||||
|
|
||||||
_buffers.Add(bindDesc.BindPoint, StringView(bufferDesc.Name), buffer);//, true
|
|
||||||
buffer.ReleaseRef();
|
|
||||||
|
|
||||||
// Buffer for default values
|
|
||||||
uint8* rawData = new:ScopedAlloc! uint8[bufferDesc.Size]*;
|
|
||||||
|
|
||||||
// Get default values
|
|
||||||
for(uint32 variable < bufferDesc.Variables)
|
|
||||||
{
|
|
||||||
let variableReflection = bufferReflection.GetVariableByIndex(variable);
|
|
||||||
|
|
||||||
variableReflection.GetDescription(let varDesc);
|
|
||||||
|
|
||||||
if(varDesc.DefaultValue != null)
|
|
||||||
Internal.MemCpy(rawData + varDesc.StartOffset, varDesc.DefaultValue, varDesc.Size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.SetData(Span<uint8>(rawData, bufferDesc.Size));
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
reflection.Release();
|
reflection.Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -1,56 +1,24 @@
|
|||||||
|
#if GE_GRAPHICS_DX11
|
||||||
|
|
||||||
using DirectX.D3D11;
|
using DirectX.D3D11;
|
||||||
using DirectX.DXGI.DXGI1_2;
|
using DirectX.DXGI.DXGI1_2;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using GlitchyEngine.Platform.DX11;
|
||||||
|
|
||||||
using internal GlitchyEngine.Renderer;
|
using internal GlitchyEngine.Renderer;
|
||||||
|
using internal GlitchyEngine.Platform.DX11;
|
||||||
|
|
||||||
namespace GlitchyEngine.Renderer
|
namespace GlitchyEngine.Renderer
|
||||||
{
|
{
|
||||||
public extension SwapChain
|
public extension SwapChain
|
||||||
{
|
{
|
||||||
private GraphicsContext _context;
|
|
||||||
|
|
||||||
private bool _changed;
|
|
||||||
|
|
||||||
private uint32 _width, _height;
|
|
||||||
|
|
||||||
internal DirectX.DXGI.IDXGIDevice* nativeDxgiDevice;
|
internal DirectX.DXGI.IDXGIDevice* nativeDxgiDevice;
|
||||||
internal IDXGISwapChain1* nativeSwapChain;
|
internal IDXGISwapChain1* nativeSwapChain;
|
||||||
|
|
||||||
internal ID3D11RenderTargetView* nativeBackBufferTarget;
|
|
||||||
|
|
||||||
public override uint32 Width
|
|
||||||
{
|
|
||||||
get => _width;
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if(_width == value)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_width = value;
|
|
||||||
_changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override uint32 Height
|
|
||||||
{
|
|
||||||
get => _height;
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if(_height == value)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_height = value;
|
|
||||||
_changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override GraphicsContext Context => _context;
|
|
||||||
|
|
||||||
public this(GraphicsContext context)
|
public this(GraphicsContext context)
|
||||||
{
|
{
|
||||||
|
Debug.Profiler.ProfileFunction!();
|
||||||
|
|
||||||
_context = context;
|
_context = context;
|
||||||
|
|
||||||
SetResolutionFromWindow();
|
SetResolutionFromWindow();
|
||||||
@@ -58,9 +26,10 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
public ~this()
|
public ~this()
|
||||||
{
|
{
|
||||||
|
Debug.Profiler.ProfileFunction!();
|
||||||
|
|
||||||
nativeDxgiDevice?.Release();
|
nativeDxgiDevice?.Release();
|
||||||
nativeSwapChain?.Release();
|
nativeSwapChain?.Release();
|
||||||
nativeBackBufferTarget?.Release();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetResolutionFromWindow()
|
void SetResolutionFromWindow()
|
||||||
@@ -73,11 +42,15 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
public override void Init()
|
public override void Init()
|
||||||
{
|
{
|
||||||
|
Debug.Profiler.ProfileFunction!();
|
||||||
|
|
||||||
ApplyChanges();
|
ApplyChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ApplyChanges()
|
public override void ApplyChanges()
|
||||||
{
|
{
|
||||||
|
Debug.Profiler.ProfileFunction!();
|
||||||
|
|
||||||
if(!_changed)
|
if(!_changed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -89,6 +62,8 @@ namespace GlitchyEngine.Renderer
|
|||||||
*/
|
*/
|
||||||
public void UpdateSwapchain()
|
public void UpdateSwapchain()
|
||||||
{
|
{
|
||||||
|
Debug.Profiler.ProfileFunction!();
|
||||||
|
|
||||||
Log.EngineLogger.Trace($"Updating swap chain ({_width}, {_height})");
|
Log.EngineLogger.Trace($"Updating swap chain ({_width}, {_height})");
|
||||||
|
|
||||||
uint32 backBufferCount = 2;
|
uint32 backBufferCount = 2;
|
||||||
@@ -97,7 +72,8 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
if(nativeSwapChain != null)
|
if(nativeSwapChain != null)
|
||||||
{
|
{
|
||||||
nativeBackBufferTarget.Release();
|
//nativeBackBufferTarget.Release();
|
||||||
|
_backBuffer.ReleaseRef();
|
||||||
|
|
||||||
var resizeResult = nativeSwapChain.ResizeBuffers(backBufferCount, _width, _height, backBufferFormat, .None);
|
var resizeResult = nativeSwapChain.ResizeBuffers(backBufferCount, _width, _height, backBufferFormat, .None);
|
||||||
if(resizeResult.Failed)
|
if(resizeResult.Failed)
|
||||||
@@ -107,7 +83,7 @@ namespace GlitchyEngine.Renderer
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_context.nativeDevice.QueryInterface(out nativeDxgiDevice);
|
NativeDevice.QueryInterface(out nativeDxgiDevice);
|
||||||
|
|
||||||
nativeDxgiDevice.GetAdapter(let adapter);
|
nativeDxgiDevice.GetAdapter(let adapter);
|
||||||
adapter.GetParent<DirectX.DXGI.IDXGIFactory2>(let factory);
|
adapter.GetParent<DirectX.DXGI.IDXGIFactory2>(let factory);
|
||||||
@@ -118,14 +94,14 @@ namespace GlitchyEngine.Renderer
|
|||||||
swDesc.Height = _height;
|
swDesc.Height = _height;
|
||||||
swDesc.Format = backBufferFormat;
|
swDesc.Format = backBufferFormat;
|
||||||
swDesc.SampleDescription = .(1, 0);
|
swDesc.SampleDescription = .(1, 0);
|
||||||
swDesc.BufferUsage = .RenderTargetOutput;
|
swDesc.BufferUsage = .RenderTargetOutput | .ShaderInput;
|
||||||
swDesc.BufferCount = backBufferCount;
|
swDesc.BufferCount = backBufferCount;
|
||||||
swDesc.SwapEffect = .FlipDiscard;
|
swDesc.SwapEffect = .FlipDiscard;
|
||||||
|
|
||||||
SwapChainFullscreenDescription fsSwapChainDesc = .();
|
SwapChainFullscreenDescription fsSwapChainDesc = .();
|
||||||
fsSwapChainDesc.Windowed = true;
|
fsSwapChainDesc.Windowed = true;
|
||||||
|
|
||||||
var createResult = factory.CreateSwapChainForHwnd((.)_context.nativeDevice, _context.nativeWindowHandle, ref swDesc, &fsSwapChainDesc, null, &nativeSwapChain);
|
var createResult = factory.CreateSwapChainForHwnd((.)NativeDevice, _context.nativeWindowHandle, ref swDesc, &fsSwapChainDesc, null, &nativeSwapChain);
|
||||||
if(createResult.Failed)
|
if(createResult.Failed)
|
||||||
{
|
{
|
||||||
Log.EngineLogger.Error($"Failed to create swap chain. Message({(int)createResult}):{createResult}");
|
Log.EngineLogger.Error($"Failed to create swap chain. Message({(int)createResult}):{createResult}");
|
||||||
@@ -134,19 +110,31 @@ namespace GlitchyEngine.Renderer
|
|||||||
factory.Release();
|
factory.Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
nativeSwapChain.GetBuffer<ID3D11Texture2D>(0, let backBuffer);
|
RenderTarget2DDescription desc = .(backBufferFormat, _width, _height);
|
||||||
|
desc.DepthStencilFormat = _depthStencilFormat;
|
||||||
|
desc.IsSwapchainTarget = true;
|
||||||
|
|
||||||
RenderTargetViewDescription rtvDesc = .(backBuffer, .Texture2D, backBufferViewFormat);
|
// Todo: perhaps just update the render target
|
||||||
_context.nativeDevice.CreateRenderTargetView(backBuffer, &rtvDesc, &nativeBackBufferTarget);
|
_backBuffer = new RenderTarget2D(desc);
|
||||||
|
|
||||||
_backBufferViewport = GlitchyEngine.Renderer.Viewport(0, 0, _width, _height, 0.0f, 1.0f);
|
_backBufferViewport = GlitchyEngine.Renderer.Viewport(0, 0, _width, _height, 0.0f, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
backBuffer.Release();
|
internal void GetBackbuffer(out ID3D11Texture2D* texture)
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
|
||||||
|
var result = nativeSwapChain.GetBuffer<ID3D11Texture2D>(0, out texture);
|
||||||
|
Log.EngineLogger.Assert(result.Succeeded, "Failed to get backbuffer.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Present()
|
public override void Present()
|
||||||
{
|
{
|
||||||
|
Debug.Profiler.ProfileFunction!();
|
||||||
|
|
||||||
nativeSwapChain.Present(Application.Get().Window.IsVSync ? 1 : 0, .None);
|
nativeSwapChain.Present(Application.Get().Window.IsVSync ? 1 : 0, .None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -1,22 +1,60 @@
|
|||||||
|
#if GE_GRAPHICS_DX11
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.IO;
|
||||||
using DirectX.D3D11;
|
using DirectX.D3D11;
|
||||||
using DirectX.Common;
|
using DirectX.Common;
|
||||||
using DirectXTK;
|
using DirectXTK;
|
||||||
|
using GlitchyEngine.Math;
|
||||||
|
using GlitchyEngine.Platform.DX11;
|
||||||
|
using System.Collections;
|
||||||
|
|
||||||
using internal GlitchyEngine.Renderer;
|
using internal GlitchyEngine.Renderer;
|
||||||
|
using internal GlitchyEngine.Platform.DX11;
|
||||||
typealias NativeTex2DDesc = DirectX.D3D11.Texture2DDescription;
|
|
||||||
|
|
||||||
namespace GlitchyEngine.Renderer
|
namespace GlitchyEngine.Renderer
|
||||||
{
|
{
|
||||||
|
internal typealias NativeTex2DDesc = DirectX.D3D11.Texture2DDescription;
|
||||||
|
|
||||||
extension Texture
|
extension Texture
|
||||||
{
|
{
|
||||||
protected internal ID3D11ShaderResourceView* nativeView ~ _?.Release();
|
protected internal ID3D11ShaderResourceView* nativeResourceView ~ _?.Release();
|
||||||
|
|
||||||
protected override void ImplBind(uint32 slot)
|
/** \brief Loads the texture from the specified path.
|
||||||
|
* @param path The path of the texture to load.
|
||||||
|
* @param texture The reference to the pointer that will hold the texture.
|
||||||
|
* @returns true if the texture was loaded successfully; false otherwise.
|
||||||
|
*/
|
||||||
|
protected bool LoadDdsResourcePlatform<T>(Stream stream, ref T* texture) where T : ID3D11Resource
|
||||||
{
|
{
|
||||||
_context.nativeContext.VertexShader.SetShaderResources(slot, 1, &nativeView);
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
_context.nativeContext.PixelShader.SetShaderResources(slot, 1, &nativeView);
|
|
||||||
|
uint8[] ddsData = new:ScopedAlloc! uint8[stream.Length];
|
||||||
|
|
||||||
|
var result = stream.TryRead(ddsData);
|
||||||
|
|
||||||
|
if (result case .Err(let err))
|
||||||
|
{
|
||||||
|
Log.EngineLogger.Error($"Failed to read texture data from stream. Error: {err}");
|
||||||
|
}
|
||||||
|
|
||||||
|
((ID3D11Resource*)texture)?.Release();
|
||||||
|
nativeResourceView?.Release();
|
||||||
|
|
||||||
|
HResult loadResult = DDSTextureLoader.CreateDDSTextureFromMemory(NativeDevice,
|
||||||
|
ddsData.Ptr, (uint)ddsData.Count, (.)&texture, &nativeResourceView);
|
||||||
|
|
||||||
|
if(loadResult.Failed)
|
||||||
|
{
|
||||||
|
Log.EngineLogger.Error($"Failed to load texture. Error({(int)loadResult}): {loadResult}");
|
||||||
|
|
||||||
|
ReleaseAndNullify!(texture);
|
||||||
|
ReleaseAndNullify!(nativeResourceView);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,15 +72,16 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
// TODO: missing options
|
// TODO: missing options
|
||||||
desc.SampleDesc = .(1, 0);
|
desc.SampleDesc = .(1, 0);
|
||||||
desc.Usage = .Immutable;
|
desc.Usage = (.)Usage;
|
||||||
desc.BindFlags = .ShaderResource;
|
desc.BindFlags = .ShaderResource;
|
||||||
desc.CpuAccessFlags = .None;
|
|
||||||
|
desc.CpuAccessFlags = (.)CpuAccess;
|
||||||
desc.MiscFlags = .None;
|
desc.MiscFlags = .None;
|
||||||
|
|
||||||
return desc;
|
return desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static implicit operator NativeTex2DDesc(Self desc) => desc.ToNative();
|
public static explicit operator NativeTex2DDesc(Self desc) => desc.ToNative();
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Texture2D
|
extension Texture2D
|
||||||
@@ -55,23 +94,11 @@ namespace GlitchyEngine.Renderer
|
|||||||
public override uint32 ArraySize => nativeDesc.ArraySize;
|
public override uint32 ArraySize => nativeDesc.ArraySize;
|
||||||
public override uint32 MipLevels => nativeDesc.MipLevels;
|
public override uint32 MipLevels => nativeDesc.MipLevels;
|
||||||
|
|
||||||
protected override void LoadTexturePlatform()
|
protected override void LoadDdsPlatform(Stream stream)
|
||||||
{
|
{
|
||||||
nativeTexture?.Release();
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
nativeView?.Release();
|
|
||||||
|
|
||||||
HResult loadResult = DDSTextureLoader.CreateDDSTextureFromFile(_context.nativeDevice, _path.ToScopedNativeWChar!(),
|
LoadDdsResourcePlatform(stream, ref nativeTexture);
|
||||||
(.)&nativeTexture, &nativeView);
|
|
||||||
|
|
||||||
if(loadResult.Failed)
|
|
||||||
{
|
|
||||||
Log.EngineLogger.Error($"Failed to load texture \"{_path}\". Error({(int)loadResult}): {loadResult}");
|
|
||||||
|
|
||||||
nativeTexture?.Release();
|
|
||||||
nativeView?.Release();
|
|
||||||
|
|
||||||
// TODO: load fallback texture
|
|
||||||
}
|
|
||||||
|
|
||||||
let resType = nativeTexture.GetResourceType();
|
let resType = nativeTexture.GetResourceType();
|
||||||
Log.EngineLogger.Assert(resType == .Texture2D, scope $"The texture \"{_path}\" is not a 2D texture (it is {resType}).");
|
Log.EngineLogger.Assert(resType == .Texture2D, scope $"The texture \"{_path}\" is not a 2D texture (it is {resType}).");
|
||||||
@@ -79,22 +106,156 @@ namespace GlitchyEngine.Renderer
|
|||||||
nativeTexture.GetDescription(out nativeDesc);
|
nativeTexture.GetDescription(out nativeDesc);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void CreateTexturePlatform(Texture2DDesc desc, void* data, uint32 linePitch)
|
protected override void CreateTexturePlatform(Texture2DDesc desc, bool isRenderTarget, void* data, uint32 linePitch)
|
||||||
{
|
{
|
||||||
nativeTexture?.Release();
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
nativeView?.Release();
|
|
||||||
|
|
||||||
nativeDesc = desc;
|
PrepareTexturePlatform(desc, isRenderTarget);
|
||||||
SubresourceData resData = .(data, linePitch, 0);
|
InternalCreateTexture(data, linePitch, 0);
|
||||||
|
}
|
||||||
|
|
||||||
var result = _context.[Friend]nativeDevice.CreateTexture2D(ref nativeDesc, &resData, &nativeTexture);
|
private void InternalCreateTexture(void* data, uint32 linePitch, uint32 slicePitch)
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
|
||||||
|
SubresourceData resData = .(data, linePitch, slicePitch);
|
||||||
|
|
||||||
|
// If data is null, set subresourceData null
|
||||||
|
SubresourceData* resDataPtr = data == null ? null : &resData;
|
||||||
|
|
||||||
|
var result = NativeDevice.CreateTexture2D(ref nativeDesc, resDataPtr, &nativeTexture);
|
||||||
Log.EngineLogger.Assert(result.Succeeded, scope $"Failed to create texture 2D. Error ({result.Underlying}): {result}");
|
Log.EngineLogger.Assert(result.Succeeded, scope $"Failed to create texture 2D. Error ({result.Underlying}): {result}");
|
||||||
|
|
||||||
result = _context.[Friend]nativeDevice.CreateShaderResourceView(nativeTexture, null, &nativeView);
|
result = NativeDevice.CreateShaderResourceView(nativeTexture, null, &nativeResourceView);
|
||||||
|
|
||||||
Log.EngineLogger.Assert(result.Succeeded, scope $"Failed to create texture view. Error ({result.Underlying}): {result}");
|
Log.EngineLogger.Assert(result.Succeeded, scope $"Failed to create texture view. Error ({result.Underlying}): {result}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void PrepareTexturePlatform(Texture2DDesc desc, bool isRenderTarget)
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
|
||||||
|
nativeTexture?.Release();
|
||||||
|
nativeTexture = null;
|
||||||
|
nativeResourceView?.Release();
|
||||||
|
nativeResourceView = null;
|
||||||
|
|
||||||
|
nativeDesc = (NativeTex2DDesc)desc;
|
||||||
|
|
||||||
|
if(isRenderTarget)
|
||||||
|
nativeDesc.BindFlags |= .RenderTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Update Texture Arrays!
|
||||||
|
protected override System.Result<void> PlatformSetData(void* data, uint32 elementSize, uint32 destX,
|
||||||
|
uint32 destY, uint32 destWidth, uint32 destHeight, uint32 arraySlice, uint32 mipLevel, GlitchyEngine.Renderer.MapType mapType)
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
|
||||||
|
if(nativeTexture == null)
|
||||||
|
{
|
||||||
|
if(destX == 0 && destY == 0 && destWidth == nativeDesc.Width && destHeight == nativeDesc.Height)
|
||||||
|
{
|
||||||
|
// We can pass the data while creating the buffer, so we can return here.
|
||||||
|
var rowPitch = elementSize * destWidth;
|
||||||
|
return InternalCreateTexture(data, rowPitch, rowPitch * destHeight);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If we don't set the entire texture we need to create the texture with unknown content and set it manually
|
||||||
|
Log.EngineLogger.Assert(nativeDesc.Usage != .Immutable, "The entire immutable texture has to be initialized.");
|
||||||
|
InternalCreateTexture(null, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Log.EngineLogger.AssertDebug();
|
||||||
|
// TODO: Debug.Assert(dstByteOffset + byteLength <= _description.Size, "The destination offset and byte length are too long for the target buffer.");
|
||||||
|
|
||||||
|
uint32 subresourceIndex = D3D11.CalcSubresource(mipLevel, arraySlice, nativeDesc.MipLevels);
|
||||||
|
|
||||||
|
switch(nativeDesc.Usage)
|
||||||
|
{
|
||||||
|
case .Default:
|
||||||
|
Box dataBox = .(destX, destY, 0, destX + destWidth, destY + destHeight, 1);
|
||||||
|
var rowPitch = elementSize * destWidth;
|
||||||
|
NativeContext.UpdateSubresource(nativeTexture, subresourceIndex, &dataBox, data, rowPitch, rowPitch * destHeight);
|
||||||
|
case .Dynamic:
|
||||||
|
Runtime.NotImplemented();
|
||||||
|
/*
|
||||||
|
Log.EngineLogger.Assert(mapType.CanWrite, "The map type has to have write access.");
|
||||||
|
// Todo: DoNotWaitFlag
|
||||||
|
MappedSubresource map = ?;
|
||||||
|
_context.nativeContext.Map(nativeBuffer, 0, (.)mapType, .None, &map);
|
||||||
|
Internal.MemCpy(((uint8*)map.Data) + dstByteOffset, data, byteLength);
|
||||||
|
_context.nativeContext.Unmap(nativeBuffer, 0);
|
||||||
|
*/
|
||||||
|
case .Immutable:
|
||||||
|
Log.EngineLogger.Error("Can't set the data of an immutable resource.");
|
||||||
|
return .Err;
|
||||||
|
default:
|
||||||
|
Log.EngineLogger.Error($"Unknown resource usage: {nativeDesc.Usage}");
|
||||||
|
return .Err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return .Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static override void CopySubresourceRegion(Texture2D source, Texture2D destination,
|
||||||
|
ResourceBox sourceBox = default, uint32 destX = 0, uint32 destY = 0,
|
||||||
|
uint32 srcArraySlice = 0, uint32 srcMipSlice = 0, uint32 destArraySlice = 0, uint32 destMipSlice = 0)
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
|
||||||
|
Log.EngineLogger.AssertDebug(source != destination || srcArraySlice != destArraySlice
|
||||||
|
|| srcMipSlice != destMipSlice, "Cannot copy from and to the same sub resource.");
|
||||||
|
|
||||||
|
Log.EngineLogger.AssertDebug(source.nativeDesc.Format == destination.nativeDesc.Format,
|
||||||
|
"Source and destination resources must have the same texel-format.");
|
||||||
|
|
||||||
|
var sourceBox;
|
||||||
|
|
||||||
|
if(sourceBox.Right == 0)
|
||||||
|
{
|
||||||
|
sourceBox.Right = source.Width;
|
||||||
|
sourceBox.Bottom = source.Height;
|
||||||
|
sourceBox.Back = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the destination was initialized
|
||||||
|
if(destination.nativeTexture == null)
|
||||||
|
destination.InternalCreateTexture(null, 0, 0);
|
||||||
|
|
||||||
|
NativeContext.CopySubresourceRegion(destination.nativeTexture,
|
||||||
|
D3D11.CalcSubresource(destMipSlice, destArraySlice, destination.MipLevels), destX, destY, 0,
|
||||||
|
source.nativeTexture, D3D11.CalcSubresource(srcMipSlice, srcArraySlice, source.MipLevels), (.)&sourceBox);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void CopyTo(Texture2D destination)
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
|
||||||
|
if(nativeTexture == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Log.EngineLogger.AssertDebug(nativeDesc.Format == destination.nativeDesc.Format,
|
||||||
|
"Source and destination resources must have the same texel-format.");
|
||||||
|
|
||||||
|
// Make sure the destination was initialized
|
||||||
|
if(destination.nativeTexture == null)
|
||||||
|
destination.InternalCreateTexture(null, 0, 0);
|
||||||
|
|
||||||
|
uint32 arraySlices = Math.Min(ArraySize, destination.ArraySize);
|
||||||
|
uint32 mipSlices = Math.Min(MipLevels, destination.MipLevels);
|
||||||
|
|
||||||
|
for(uint32 arraySlice < arraySlices)
|
||||||
|
for(uint32 mipSlice < mipSlices)
|
||||||
|
{
|
||||||
|
Box sourceBox = .(0, 0, 0, Width, Height, 1);
|
||||||
|
|
||||||
|
NativeContext.CopySubresourceRegion(destination.nativeTexture,
|
||||||
|
D3D11.CalcSubresource(mipSlice, arraySlice, destination.MipLevels), 0, 0, 0,
|
||||||
|
nativeTexture, D3D11.CalcSubresource(mipSlice, arraySlice, MipLevels), (.)&sourceBox);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension TextureCube
|
extension TextureCube
|
||||||
@@ -107,23 +268,11 @@ namespace GlitchyEngine.Renderer
|
|||||||
public override uint32 ArraySize => nativeDesc.ArraySize / 6;
|
public override uint32 ArraySize => nativeDesc.ArraySize / 6;
|
||||||
public override uint32 MipLevels => nativeDesc.MipLevels;
|
public override uint32 MipLevels => nativeDesc.MipLevels;
|
||||||
|
|
||||||
protected override void LoadTexturePlatform()
|
protected override void LoadTexturePlatform(Stream stream)
|
||||||
{
|
{
|
||||||
nativeTexture?.Release();
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
nativeView?.Release();
|
|
||||||
|
|
||||||
HResult loadResult = DDSTextureLoader.CreateDDSTextureFromFile(_context.nativeDevice, _path.ToScopedNativeWChar!(),
|
LoadDdsResourcePlatform(stream, ref nativeTexture);
|
||||||
(.)&nativeTexture, &nativeView);
|
|
||||||
|
|
||||||
if(loadResult.Failed)
|
|
||||||
{
|
|
||||||
Log.EngineLogger.Error($"Failed to load texture \"{_path}\". Error({(int)loadResult}): {loadResult}");
|
|
||||||
|
|
||||||
nativeTexture?.Release();
|
|
||||||
nativeView?.Release();
|
|
||||||
|
|
||||||
// TODO: load fallback texture
|
|
||||||
}
|
|
||||||
|
|
||||||
let resType = nativeTexture.GetResourceType();
|
let resType = nativeTexture.GetResourceType();
|
||||||
Log.EngineLogger.Assert(resType == .Texture2D, scope $"The texture \"{_path}\" is not a texture cube (it is {resType}).");
|
Log.EngineLogger.Assert(resType == .Texture2D, scope $"The texture \"{_path}\" is not a texture cube (it is {resType}).");
|
||||||
@@ -135,3 +284,5 @@ namespace GlitchyEngine.Renderer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
|
#if GE_GRAPHICS_DX11
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using DirectX.D3D11;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using DirectX.Common;
|
using DirectX.Common;
|
||||||
|
using DirectX.D3D11;
|
||||||
|
using GlitchyEngine.Platform.DX11;
|
||||||
|
|
||||||
using internal GlitchyEngine.Renderer;
|
using internal GlitchyEngine.Renderer;
|
||||||
|
using internal GlitchyEngine.Platform.DX11;
|
||||||
|
|
||||||
namespace GlitchyEngine.Renderer
|
namespace GlitchyEngine.Renderer
|
||||||
{
|
{
|
||||||
@@ -13,12 +17,12 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
public ID3DBlob* nativeShaderCode ~ _?.Release();
|
public ID3DBlob* nativeShaderCode ~ _?.Release();
|
||||||
|
|
||||||
public this(GraphicsContext context, VertexElement[] elements, VertexShader vertexShader)
|
public this(VertexElement[] elements, bool ownsElements, VertexShader vertexShader)
|
||||||
{
|
{
|
||||||
nativeShaderCode = vertexShader.nativeCode..AddRef();
|
nativeShaderCode = vertexShader.nativeCode..AddRef();
|
||||||
|
|
||||||
_context = context..AddRef();
|
|
||||||
_elements = elements;
|
_elements = elements;
|
||||||
|
_ownsElements = ownsElements;
|
||||||
|
|
||||||
CreateNativeLayout();
|
CreateNativeLayout();
|
||||||
}
|
}
|
||||||
@@ -28,16 +32,18 @@ namespace GlitchyEngine.Renderer
|
|||||||
Debug.Assert(input.Count == output.Count);
|
Debug.Assert(input.Count == output.Count);
|
||||||
|
|
||||||
for(int i < input.Count)
|
for(int i < input.Count)
|
||||||
output[i] = .(input[i].SemanticName, input[i].SemanticIndex, input[i].Format, input[i].InputSlot, input[i].AlignedByteOffset, (.)input[i].InputSlotClass);
|
output[i] = .(input[i].SemanticName, input[i].SemanticIndex, input[i].Format, input[i].InputSlot, input[i].AlignedByteOffset, (.)input[i].InputSlotClass, input[i].InstanceDataStepRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void CreateNativeLayout()
|
protected override void CreateNativeLayout()
|
||||||
{
|
{
|
||||||
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
|
||||||
var nativeElements = scope InputElementDescription[_elements.Count];
|
var nativeElements = scope InputElementDescription[_elements.Count];
|
||||||
|
|
||||||
ToNativeLayout(_elements, nativeElements);
|
ToNativeLayout(_elements, nativeElements);
|
||||||
|
|
||||||
var result = _context.nativeDevice.CreateInputLayout(nativeElements.CArray(), (.)nativeElements.Count, nativeShaderCode.GetBufferPointer(), nativeShaderCode.GetBufferSize(), &nativeLayout);
|
var result = NativeDevice.CreateInputLayout(nativeElements.CArray(), (.)nativeElements.Count, nativeShaderCode.GetBufferPointer(), nativeShaderCode.GetBufferSize(), &nativeLayout);
|
||||||
if(result.Failed)
|
if(result.Failed)
|
||||||
{
|
{
|
||||||
Log.EngineLogger.Error($"Failed to create D3D11 input layout: Message({(int)result}): {result}");
|
Log.EngineLogger.Error($"Failed to create D3D11 input layout: Message({(int)result}): {result}");
|
||||||
@@ -45,3 +51,5 @@ namespace GlitchyEngine.Renderer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
|
#if GE_GRAPHICS_DX11
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using GlitchyEngine.Renderer;
|
using GlitchyEngine.Renderer;
|
||||||
using DirectX.Common;
|
|
||||||
using DirectX.D3D11;
|
using DirectX.D3D11;
|
||||||
using DirectX.D3DCompiler;
|
using DirectX.D3DCompiler;
|
||||||
|
using GlitchyEngine.Platform.DX11;
|
||||||
|
|
||||||
using internal GlitchyEngine.Renderer;
|
using internal GlitchyEngine.Renderer;
|
||||||
|
using internal GlitchyEngine.Platform.DX11;
|
||||||
|
|
||||||
namespace GlitchyEngine.Renderer
|
namespace GlitchyEngine.Renderer
|
||||||
{
|
{
|
||||||
@@ -14,15 +17,23 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
public override void CompileFromSource(String code, String entryPoint, ShaderDefine[] macros = null)
|
public override void CompileFromSource(String code, String entryPoint, ShaderDefine[] macros = null)
|
||||||
{
|
{
|
||||||
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
|
||||||
Shader.PlattformCompileShaderFromSource(code, macros, entryPoint, "vs_5_0", DefaultCompileFlags, out nativeCode);
|
Shader.PlattformCompileShaderFromSource(code, macros, entryPoint, "vs_5_0", DefaultCompileFlags, out nativeCode);
|
||||||
|
|
||||||
var result = _context.nativeDevice.CreateVertexShader(nativeCode.GetBufferPointer(), nativeCode.GetBufferSize(), null, &nativeShader);
|
{
|
||||||
|
Debug.Profiler.ProfileResourceScope!("CreateNativeVertexShader");
|
||||||
|
|
||||||
|
var result = NativeDevice.CreateVertexShader(nativeCode.GetBufferPointer(), nativeCode.GetBufferSize(), null, &nativeShader);
|
||||||
if(result.Failed)
|
if(result.Failed)
|
||||||
{
|
{
|
||||||
Log.EngineLogger.Error($"Failed to create vertex shader: Message ({(int)result}): {result}");
|
Log.EngineLogger.Error($"Failed to create vertex shader: Message ({(int)result}): {result}");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Reflect(nativeCode);
|
Reflect(nativeCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -1,49 +0,0 @@
|
|||||||
#if BF_PLATFORM_WINDOWS
|
|
||||||
|
|
||||||
using static System.Windows;
|
|
||||||
|
|
||||||
namespace GlitchyEngine.Threading
|
|
||||||
{
|
|
||||||
extension Mutex
|
|
||||||
{
|
|
||||||
internal Handle nativeHandle;
|
|
||||||
|
|
||||||
public this(bool initialyOwned = false)
|
|
||||||
{
|
|
||||||
nativeHandle = CreateMutexW(null, initialyOwned, null);
|
|
||||||
|
|
||||||
Log.EngineLogger.AssertDebug(nativeHandle != 0, scope $"Failed to create mutex. Error code: {GetLastError()}");
|
|
||||||
}
|
|
||||||
|
|
||||||
public ~this()
|
|
||||||
{
|
|
||||||
CloseHandle(nativeHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override LockResult Lock(uint32 timeout = InfiniteTimeout)
|
|
||||||
{
|
|
||||||
int i = WaitForSingleObject(nativeHandle, timeout);
|
|
||||||
|
|
||||||
switch(i)
|
|
||||||
{
|
|
||||||
case 0x00000000L:
|
|
||||||
return .Released;
|
|
||||||
case 0x00000080L:
|
|
||||||
return .Abandoned;
|
|
||||||
case 0x00000102L:
|
|
||||||
return .Timeout;
|
|
||||||
case 0xFFFFFFFF:
|
|
||||||
return .Failed;
|
|
||||||
default:
|
|
||||||
return .Unknown;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Unlock()
|
|
||||||
{
|
|
||||||
return ReleaseMutex(nativeHandle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
#if BF_PLATFORM_WINDOWS
|
|
||||||
|
|
||||||
using static System.Windows;
|
|
||||||
|
|
||||||
namespace GlitchyEngine.Threading
|
|
||||||
{
|
|
||||||
extension Semaphore
|
|
||||||
{
|
|
||||||
internal Handle nativeHandle;
|
|
||||||
|
|
||||||
public override this(int32 initialCount = 1, int32 maximumCount = 1)
|
|
||||||
{
|
|
||||||
nativeHandle = (.)CreateSemaphoreW(null, initialCount, maximumCount, null);
|
|
||||||
|
|
||||||
Log.EngineLogger.AssertDebug(nativeHandle != 0, scope $"Failed to create semaphore. Error code: {GetLastError()}");
|
|
||||||
}
|
|
||||||
|
|
||||||
public ~this()
|
|
||||||
{
|
|
||||||
CloseHandle(nativeHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override LockResult Lock(uint32 timeout = InfiniteTimeout)
|
|
||||||
{
|
|
||||||
int i = WaitForSingleObject(nativeHandle, timeout);
|
|
||||||
|
|
||||||
switch(i)
|
|
||||||
{
|
|
||||||
case 0x00000000L:
|
|
||||||
return .Released;
|
|
||||||
case 0x00000080L:
|
|
||||||
return .Abandoned;
|
|
||||||
case 0x00000102L:
|
|
||||||
return .Timeout;
|
|
||||||
case 0xFFFFFFFF:
|
|
||||||
return .Failed;
|
|
||||||
default:
|
|
||||||
return .Unknown;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Unlock(int32 releaseCount = 1)
|
|
||||||
{
|
|
||||||
return ReleaseSemaphore(nativeHandle, releaseCount, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Unlock(out int32 previousCount, int32 releaseCount = 1)
|
|
||||||
{
|
|
||||||
previousCount = ?;
|
|
||||||
return ReleaseSemaphore(nativeHandle, releaseCount, &previousCount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
namespace System
|
|
||||||
{
|
|
||||||
extension Windows
|
|
||||||
{
|
|
||||||
public struct SecurityAttributes
|
|
||||||
{
|
|
||||||
public uint32 Length;
|
|
||||||
public SECURITY_DESCRIPTOR* SecurityDescriptor;
|
|
||||||
public IntBool InheritHandle;
|
|
||||||
}
|
|
||||||
|
|
||||||
[LinkName(.C)]
|
|
||||||
public static extern Windows.Handle CreateSemaphoreW(SecurityAttributes* semaphoreAttributes, int32 initialCount, int32 maximumCount, char16* name);
|
|
||||||
|
|
||||||
[LinkName(.C)]
|
|
||||||
public static extern uint32 WaitForSingleObject(Handle handle, uint32 timeout);
|
|
||||||
|
|
||||||
[LinkName(.C)]
|
|
||||||
public static extern uint32 WaitForMultipleObjects(uint32 count, Handle *handles, IntBool bWaitAll, uint32 timeout);
|
|
||||||
|
|
||||||
public const uint32 InfiniteTimeout = 0xFFFFFFFF;
|
|
||||||
|
|
||||||
[Inline]
|
|
||||||
public static uint32 WaitForMultipleObjects(Handle[] handles, bool waitForAll, uint32 timeout = InfiniteTimeout)
|
|
||||||
{
|
|
||||||
return WaitForMultipleObjects((.)handles.Count, handles.CArray(), waitForAll, timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
[LinkName(.C)]
|
|
||||||
public static extern IntBool ReleaseSemaphore(Handle semaphore, int32 releaseCount, int32* previousCount);
|
|
||||||
|
|
||||||
[LinkName(.C)]
|
|
||||||
public static extern Handle CreateMutexW(SecurityAttributes* mutexAttributes, IntBool initialOwner, char16* name);
|
|
||||||
|
|
||||||
[LinkName(.C)]
|
|
||||||
public static extern IntBool ReleaseMutex(Handle mutex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#if BF_PLATFORM_WINDOWS
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using GlitchyEngine.Events;
|
using GlitchyEngine.Events;
|
||||||
using DirectX.Windows.VirtualKeyCodes;
|
using DirectX.Windows.VirtualKeyCodes;
|
||||||
@@ -7,39 +9,21 @@ using static System.Windows;
|
|||||||
|
|
||||||
namespace GlitchyEngine
|
namespace GlitchyEngine
|
||||||
{
|
{
|
||||||
|
|
||||||
#if GE_WINDOWS
|
|
||||||
/// Windows (WinApi) specific implementation of the Input-class
|
/// Windows (WinApi) specific implementation of the Input-class
|
||||||
extension Input
|
extension Input
|
||||||
{
|
{
|
||||||
internal static bool sUseRawInput = true;
|
|
||||||
|
|
||||||
public override static bool RawInput
|
|
||||||
{
|
|
||||||
get => sUseRawInput;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if(sUseRawInput == value)
|
|
||||||
return;
|
|
||||||
|
|
||||||
sUseRawInput = value;
|
|
||||||
|
|
||||||
//if(sUseRawInput)
|
|
||||||
// TODO: init raw input
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Represents the state of the input devices on the windows platform (WinApi that is).
|
/// Represents the state of the input devices on the windows platform (WinApi that is).
|
||||||
struct WindowsInputState
|
struct WindowsInputState
|
||||||
{
|
{
|
||||||
public int8[256] KeyStates;
|
public int8[256] KeyStates;
|
||||||
public Point CursorPosition;
|
public Point CursorPosition;
|
||||||
public Point CursorPositionDifference;
|
public Point CursorPositionDifference;
|
||||||
public Int32_2 RawMovement;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static WindowsInputState* CurrentState = new WindowsInputState() ~ delete _;
|
static WindowsInputState[2] IputStates;
|
||||||
static WindowsInputState* LastState = new WindowsInputState() ~ delete _;
|
|
||||||
|
static WindowsInputState* CurrentState = &IputStates[0];
|
||||||
|
static WindowsInputState* LastState = &IputStates[1];
|
||||||
|
|
||||||
//
|
//
|
||||||
// Current Keyboard state
|
// Current Keyboard state
|
||||||
@@ -67,13 +51,13 @@ namespace GlitchyEngine
|
|||||||
//
|
//
|
||||||
public override static bool WasKeyPressed(Key keycode)
|
public override static bool WasKeyPressed(Key keycode)
|
||||||
{
|
{
|
||||||
int8 state = CurrentState.KeyStates[(int)keycode];
|
int8 state = LastState.KeyStates[(int)keycode];
|
||||||
return state < 0;
|
return state < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override static bool WasKeyReleased(Key keycode)
|
public override static bool WasKeyReleased(Key keycode)
|
||||||
{
|
{
|
||||||
int8 state = CurrentState.KeyStates[(int)keycode];
|
int8 state = LastState.KeyStates[(int)keycode];
|
||||||
return state >= 0;
|
return state >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,24 +150,10 @@ namespace GlitchyEngine
|
|||||||
//
|
//
|
||||||
public override static bool IsMouseButtonPressing(MouseButton button) => IsMouseButtonPressed(button) && WasMouseButtonReleased(button);
|
public override static bool IsMouseButtonPressing(MouseButton button) => IsMouseButtonPressed(button) && WasMouseButtonReleased(button);
|
||||||
|
|
||||||
public override static bool IsMouseButtonReleasiong(MouseButton button) => IsMouseButtonReleased(button) && WasMouseButtonPressed(button);
|
public override static bool IsMouseButtonReleasing(MouseButton button) => IsMouseButtonReleased(button) && WasMouseButtonPressed(button);
|
||||||
|
|
||||||
public override static Point GetMouseMovement() => CurrentState.CursorPositionDifference;
|
public override static Point GetMouseMovement() => CurrentState.CursorPositionDifference;
|
||||||
|
|
||||||
public override static Int32_2 GetRawMouseMovement()
|
|
||||||
{
|
|
||||||
if(sUseRawInput)
|
|
||||||
{
|
|
||||||
return CurrentState.RawMovement;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var v = GetMouseMovement();
|
|
||||||
|
|
||||||
return *(Int32_2*)&v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//[CLink, CallingConvention(.Stdcall)]
|
//[CLink, CallingConvention(.Stdcall)]
|
||||||
//static extern int16 GetKeyState(int32 keycode);
|
//static extern int16 GetKeyState(int32 keycode);
|
||||||
[CLink, CallingConvention(.Stdcall)]
|
[CLink, CallingConvention(.Stdcall)]
|
||||||
@@ -191,14 +161,11 @@ namespace GlitchyEngine
|
|||||||
[CLink, CallingConvention(.Stdcall)]
|
[CLink, CallingConvention(.Stdcall)]
|
||||||
static extern IntBool ScreenToClient(HWnd hWnd, ref Point p);
|
static extern IntBool ScreenToClient(HWnd hWnd, ref Point p);
|
||||||
|
|
||||||
internal static Int32_2 rawMovement;
|
|
||||||
|
|
||||||
public override static void NewFrame()
|
public override static void NewFrame()
|
||||||
{
|
{
|
||||||
// Switch last and current states
|
Debug.Profiler.ProfileFunction!();
|
||||||
var buffer = LastState;
|
|
||||||
LastState = CurrentState;
|
Swap!(CurrentState, LastState);
|
||||||
CurrentState = buffer;
|
|
||||||
|
|
||||||
// Get current keyboard state
|
// Get current keyboard state
|
||||||
if(DirectX.Windows.Winuser.GetKeyboardState((uint8*)&CurrentState.KeyStates) == 0)
|
if(DirectX.Windows.Winuser.GetKeyboardState((uint8*)&CurrentState.KeyStates) == 0)
|
||||||
@@ -225,9 +192,8 @@ namespace GlitchyEngine
|
|||||||
|
|
||||||
// Calculate cursor movement
|
// Calculate cursor movement
|
||||||
CurrentState.CursorPositionDifference = CurrentState.CursorPosition - LastState.CursorPosition;
|
CurrentState.CursorPositionDifference = CurrentState.CursorPosition - LastState.CursorPosition;
|
||||||
CurrentState.RawMovement = rawMovement;
|
|
||||||
rawMovement = .Zero;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
using System;
|
||||||
|
using DirectX.Windows.Winuser;
|
||||||
|
using DirectX.Common;
|
||||||
|
|
||||||
|
namespace GlitchyEngine
|
||||||
|
{
|
||||||
|
extension Key
|
||||||
|
{
|
||||||
|
// Todo: make overriding method
|
||||||
|
public void GetKeyName(String strBuffer)
|
||||||
|
{
|
||||||
|
var scanCode = MapVirtualKeyW((.)this, MAPVK_VK_TO_VSC);
|
||||||
|
|
||||||
|
char16[128] name = ?;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
switch (this)
|
||||||
|
{
|
||||||
|
case .Left, .Up, .Right, .Down, .RightControl, .RightAlt,
|
||||||
|
.LeftSuper, .RightSuper, ContextMenu,
|
||||||
|
.Prior, .Next, .End, .Home, .Insert, .Delete, .Divide, .Numlock:
|
||||||
|
// set extended flag
|
||||||
|
scanCode |= 0x0100;
|
||||||
|
fallthrough;
|
||||||
|
default:
|
||||||
|
result = GetKeyNameTextW((.)(scanCode << 16), &name, name.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(result == 0)
|
||||||
|
{
|
||||||
|
HResult error = (.)DirectX.Windows.Kernel32.GetLastError();
|
||||||
|
|
||||||
|
Log.EngineLogger.Error($"Failed to convert keycode {(int)this}({this}) to string. WinAPI error({(int)error}): {error}");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
strBuffer.Append(Span<char16>(&name, result));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts the given windows specific virtual key code to a GlitchyEngine Key.
|
||||||
|
[Inline]
|
||||||
|
internal static Key FromWindowsKeyCode(int32 vKeyCode)
|
||||||
|
{
|
||||||
|
return (.)vKeyCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
#if GE_WINDOWS
|
#if BF_PLATFORM_WINDOWS
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using DirectX.Common;
|
using DirectX.Common;
|
||||||
using DirectX.Windows;
|
using DirectX.Windows;
|
||||||
@@ -9,9 +10,10 @@ using GlitchyEngine.Events;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using GlitchyEngine.Math;
|
using GlitchyEngine.Math;
|
||||||
using GlitchyEngine.Renderer;
|
using GlitchyEngine.Renderer;
|
||||||
using DirectX.Windows.Winuser.RawInput;
|
|
||||||
using static System.Windows;
|
using static System.Windows;
|
||||||
|
|
||||||
|
using internal GlitchyEngine;
|
||||||
|
|
||||||
namespace GlitchyEngine
|
namespace GlitchyEngine
|
||||||
{
|
{
|
||||||
/// The windows specific Window implementation
|
/// The windows specific Window implementation
|
||||||
@@ -32,6 +34,8 @@ namespace GlitchyEngine
|
|||||||
|
|
||||||
private bool _isVSync = true;
|
private bool _isVSync = true;
|
||||||
|
|
||||||
|
private bool _isActive;
|
||||||
|
|
||||||
private GraphicsContext _graphicsContext ~ _?.ReleaseRef();
|
private GraphicsContext _graphicsContext ~ _?.ReleaseRef();
|
||||||
|
|
||||||
public override GraphicsContext Context => _graphicsContext;
|
public override GraphicsContext Context => _graphicsContext;
|
||||||
@@ -150,10 +154,14 @@ namespace GlitchyEngine
|
|||||||
set => _isVSync = value;
|
set => _isVSync = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool IsActive => _isActive;
|
||||||
|
|
||||||
public override void* NativeWindow => (void*)(int)_windowHandle;
|
public override void* NativeWindow => (void*)(int)_windowHandle;
|
||||||
|
|
||||||
public override this(WindowDescription desc)
|
public override this(WindowDescription desc)
|
||||||
{
|
{
|
||||||
|
Debug.Profiler.ProfileFunction!();
|
||||||
|
|
||||||
_minMaxInfo.MaximumTrackingSize.x = int32.MaxValue;
|
_minMaxInfo.MaximumTrackingSize.x = int32.MaxValue;
|
||||||
_minMaxInfo.MaximumTrackingSize.y = int32.MaxValue;
|
_minMaxInfo.MaximumTrackingSize.y = int32.MaxValue;
|
||||||
|
|
||||||
@@ -168,6 +176,8 @@ namespace GlitchyEngine
|
|||||||
|
|
||||||
public ~this()
|
public ~this()
|
||||||
{
|
{
|
||||||
|
Debug.Profiler.ProfileFunction!();
|
||||||
|
|
||||||
if(!DestroyWindow(_windowHandle))
|
if(!DestroyWindow(_windowHandle))
|
||||||
{
|
{
|
||||||
HResult res = (.)GetLastError();
|
HResult res = (.)GetLastError();
|
||||||
@@ -177,8 +187,13 @@ namespace GlitchyEngine
|
|||||||
UnregisterClass(WindowClassName.ToScopedNativeWChar!(), _instanceHandle);
|
UnregisterClass(WindowClassName.ToScopedNativeWChar!(), _instanceHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[LinkName(.C)]
|
||||||
|
static extern HWnd GetActiveWindow();
|
||||||
|
|
||||||
private void Init(WindowDescription desc)
|
private void Init(WindowDescription desc)
|
||||||
{
|
{
|
||||||
|
Debug.Profiler.ProfileFunction!();
|
||||||
|
|
||||||
Log.EngineLogger.Trace($"Creating window \"{desc.Title}\" ({desc.Width}, {desc.Height})...");
|
Log.EngineLogger.Trace($"Creating window \"{desc.Title}\" ({desc.Width}, {desc.Height})...");
|
||||||
|
|
||||||
_instanceHandle = (.)GetModuleHandleW(null);
|
_instanceHandle = (.)GetModuleHandleW(null);
|
||||||
@@ -189,7 +204,11 @@ namespace GlitchyEngine
|
|||||||
_windowClass.HInstance = (.)_instanceHandle;
|
_windowClass.HInstance = (.)_instanceHandle;
|
||||||
|
|
||||||
if (desc.Icon.Ptr != null)
|
if (desc.Icon.Ptr != null)
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileScope!("LoadIcon");
|
||||||
|
|
||||||
_windowClass.Icon = LoadImageW(0, desc.Icon.ToScopedNativeWChar!(), .Icon, 0, 0, .LoadFromFile);
|
_windowClass.Icon = LoadImageW(0, desc.Icon.ToScopedNativeWChar!(), .Icon, 0, 0, .LoadFromFile);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
_windowClass.Icon = 0;
|
_windowClass.Icon = 0;
|
||||||
|
|
||||||
@@ -204,8 +223,12 @@ namespace GlitchyEngine
|
|||||||
Runtime.FatalError("Failed to register window class");
|
Runtime.FatalError("Failed to register window class");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileScope!("CreateWindow");
|
||||||
|
|
||||||
_windowHandle = CreateWindowExW(.None, _windowClass.ClassName, desc.Title.ToScopedNativeWChar!(), .WS_OVERLAPPEDWINDOW | .WS_VISIBLE,
|
_windowHandle = CreateWindowExW(.None, _windowClass.ClassName, desc.Title.ToScopedNativeWChar!(), .WS_OVERLAPPEDWINDOW | .WS_VISIBLE,
|
||||||
CW_USEDEFAULT, CW_USEDEFAULT, desc.Width, desc.Height, 0, 0, (.)_instanceHandle, null);
|
CW_USEDEFAULT, CW_USEDEFAULT, desc.Width, desc.Height, 0, 0, (.)_instanceHandle, null);
|
||||||
|
}
|
||||||
|
|
||||||
_graphicsContext = new GraphicsContext(_windowHandle);
|
_graphicsContext = new GraphicsContext(_windowHandle);
|
||||||
_graphicsContext.Init();
|
_graphicsContext.Init();
|
||||||
@@ -217,40 +240,8 @@ namespace GlitchyEngine
|
|||||||
|
|
||||||
Log.EngineLogger.Trace($"Created window \"{Title}\" ({Width}, {Height})");
|
Log.EngineLogger.Trace($"Created window \"{Title}\" ({Width}, {Height})");
|
||||||
|
|
||||||
if(Input.RawInput)
|
// Determine whether or not the window is currently active
|
||||||
{
|
_isActive = GetActiveWindow() == _windowHandle;
|
||||||
InitRawInput();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[CLink, CallingConvention(.Stdcall)]
|
|
||||||
static extern IntBool RegisterRawInputDevices(RAWINPUTDEVICE* rawInputDevices, uint32 numDevices, uint32 size);
|
|
||||||
|
|
||||||
private void InitRawInput()
|
|
||||||
{
|
|
||||||
RAWINPUTDEVICE[1] Rid;
|
|
||||||
|
|
||||||
Rid[0].UsagePage = 0x01; // HID_USAGE_PAGE_GENERIC
|
|
||||||
Rid[0].Usage = 0x02; // HID_USAGE_GENERIC_MOUSE
|
|
||||||
Rid[0].Flags = 0;//RIDEV_NOLEGACY; // adds mouse and also ignores legacy mouse messages
|
|
||||||
Rid[0].Target = 0;
|
|
||||||
/*
|
|
||||||
Rid[1].UsagePage = 0x01; // HID_USAGE_PAGE_GENERIC
|
|
||||||
Rid[1].Usage = 0x06; // HID_USAGE_GENERIC_KEYBOARD
|
|
||||||
Rid[1].Flags = RIDEV_NOLEGACY; // adds keyboard and also ignores legacy keyboard messages
|
|
||||||
Rid[1].Target = 0;
|
|
||||||
*/
|
|
||||||
if (!RegisterRawInputDevices(&Rid, Rid.Count, sizeof(RAWINPUTDEVICE)))
|
|
||||||
{
|
|
||||||
DirectX.Common.HResult errorCode = (.)GetLastError();
|
|
||||||
Log.EngineLogger.Error($"Failed to register raw input devices. Message({(int32)errorCode}):{errorCode}");
|
|
||||||
// Disable raw input
|
|
||||||
Input.RawInput = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Log.EngineLogger.Trace($"Registered raw input devices.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool _isResizingOrMoving;
|
private bool _isResizingOrMoving;
|
||||||
@@ -259,6 +250,18 @@ namespace GlitchyEngine
|
|||||||
[CLink]
|
[CLink]
|
||||||
static extern IntBool IsWindowUnicode(HWND whnd);
|
static extern IntBool IsWindowUnicode(HWND whnd);
|
||||||
|
|
||||||
|
public Result<void> SetIcon(StringView filePath)
|
||||||
|
{
|
||||||
|
HICON hIcon = LoadImageW(0, filePath.ToScopedNativeWChar!(), .Icon, 0, 0, .LoadFromFile);
|
||||||
|
if (hIcon == 0)
|
||||||
|
return .Err;
|
||||||
|
|
||||||
|
// WM_SETICON 0x0080
|
||||||
|
SendMessageW(_windowHandle, 0x0080, 1 /* ICON_BIG */, (int)hIcon);
|
||||||
|
|
||||||
|
return .Ok;
|
||||||
|
}
|
||||||
|
|
||||||
private static LRESULT MessageHandler(HWND hwnd, uint32 uMsg, WPARAM wParam, LPARAM lParam)
|
private static LRESULT MessageHandler(HWND hwnd, uint32 uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
void* windowPtr = (void*)GetWindowLongPtrW(hwnd, GWL_USERDATA);
|
void* windowPtr = (void*)GetWindowLongPtrW(hwnd, GWL_USERDATA);
|
||||||
@@ -287,27 +290,22 @@ namespace GlitchyEngine
|
|||||||
// Window size changed
|
// Window size changed
|
||||||
case WM_SIZE:
|
case WM_SIZE:
|
||||||
{
|
{
|
||||||
if (wParam == (.)ResizingType.Minimized)
|
window._isMinimized = wParam == (.)ResizingType.Minimized;
|
||||||
{
|
|
||||||
window._isMinimized = true;
|
|
||||||
}
|
|
||||||
else if (window._isMinimized)
|
|
||||||
{
|
|
||||||
window._isMinimized = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SplitHighAndLowOrder!(lParam, out window._clientRect.Width, out window._clientRect.Height);
|
SplitHighAndLowOrder!(lParam, out window._clientRect.Width, out window._clientRect.Height);
|
||||||
|
|
||||||
|
if(window._clientRect.Width != 0 && window._clientRect.Height != 0)
|
||||||
|
{
|
||||||
window._graphicsContext.SwapChain.Width = (.)window._clientRect.Width;
|
window._graphicsContext.SwapChain.Width = (.)window._clientRect.Width;
|
||||||
window._graphicsContext.SwapChain.Height = (.)window._clientRect.Height;
|
window._graphicsContext.SwapChain.Height = (.)window._clientRect.Height;
|
||||||
|
|
||||||
window._graphicsContext.SwapChain.ApplyChanges();
|
window._graphicsContext.SwapChain.ApplyChanges();
|
||||||
|
}
|
||||||
|
|
||||||
WindowResizeEvent event = scope WindowResizeEvent(window._clientRect.Width, window._clientRect.Height, window._isResizingOrMoving);
|
WindowResizeEvent event = scope WindowResizeEvent(window._clientRect.Width, window._clientRect.Height, window._isResizingOrMoving);
|
||||||
window._eventCallback(event);
|
window._eventCallback(event);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// Window position changed
|
// Window position changed
|
||||||
case WM_MOVE:
|
case WM_MOVE:
|
||||||
{
|
{
|
||||||
@@ -341,18 +339,39 @@ namespace GlitchyEngine
|
|||||||
window._eventCallback(moveEvent);
|
window._eventCallback(moveEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 0x0006: //WM_ACTIVATE
|
||||||
|
{
|
||||||
|
SplitHighAndLowOrder!((int64)wParam, let lowWParam, let highWParam);
|
||||||
|
|
||||||
|
bool isActivate = lowWParam > 0;
|
||||||
|
|
||||||
|
//HWnd windowHandle = (.)lParam;
|
||||||
|
|
||||||
|
if(window._isActive != isActivate)
|
||||||
|
{
|
||||||
|
window._isActive = isActivate;
|
||||||
|
|
||||||
|
if(window._isActive)
|
||||||
|
window._eventCallback(scope WindowActivateEvent());
|
||||||
|
else
|
||||||
|
window._eventCallback(scope WindowDeactivateEvent());
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
////
|
////
|
||||||
//// Keyboard input
|
//// Keyboard input
|
||||||
////
|
////
|
||||||
|
|
||||||
case WM_KEYDOWN:
|
case WM_KEYDOWN, WM_SYSKEYDOWN:
|
||||||
{
|
{
|
||||||
var event = scope KeyPressedEvent((Key)wParam, (int32)lParam & 0xFFFF);
|
Key key = WindowMessageToKey(wParam, lParam);
|
||||||
|
var event = scope KeyPressedEvent(key, (int32)lParam & 0xFFFF);
|
||||||
window._eventCallback(event);
|
window._eventCallback(event);
|
||||||
}
|
}
|
||||||
case WM_KEYUP:
|
case WM_KEYUP, WM_SYSKEYUP:
|
||||||
{
|
{
|
||||||
var event = scope KeyReleasedEvent((Key)wParam);
|
Key key = WindowMessageToKey(wParam, lParam);
|
||||||
|
var event = scope KeyReleasedEvent(key);
|
||||||
window._eventCallback(event);
|
window._eventCallback(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -474,130 +493,38 @@ namespace GlitchyEngine
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// Raw Input
|
|
||||||
case 0x00FF: //WM_INPUT
|
|
||||||
{
|
|
||||||
uint32 dataSize = ?;
|
|
||||||
GetRawInputData((.)lParam, RID_INPUT, null, &dataSize, sizeof(RAWINPUTHEADER));
|
|
||||||
|
|
||||||
if (dataSize > 0)
|
|
||||||
{
|
|
||||||
uint8[] rawData = scope .[dataSize];
|
|
||||||
if (GetRawInputData((.)lParam, RID_INPUT, rawData.CArray(), &dataSize, sizeof(RAWINPUTHEADER)) == dataSize)
|
|
||||||
{
|
|
||||||
RAWINPUT* raw = (.)rawData.CArray();
|
|
||||||
if (raw.Header.Type == RIM_TYPEMOUSE)
|
|
||||||
{
|
|
||||||
int32 movementX = raw.Data.Mouse.lLastX;
|
|
||||||
int32 movementY = raw.Data.Mouse.lLastY;
|
|
||||||
|
|
||||||
// TODO: raw.Data.Mouse.usFlags defines whether movement is abosulte, relative, etc...
|
|
||||||
Input.[Friend]rawMovement += .(movementX, movementY);
|
|
||||||
/*
|
|
||||||
var event = scope MouseMovedEvent(movementX, movementY);
|
|
||||||
window._eventCallback(event);
|
|
||||||
|
|
||||||
// Convert button transition flags to a more manageable type
|
|
||||||
var buttonTransitions = (RawMouseButtonTransition)raw.Data.Mouse.DUMMYUNIONNAME.DUMMYSTRUCTNAME.usButtonFlags;
|
|
||||||
|
|
||||||
if(buttonTransitions.HasFlag(.LeftDown))
|
|
||||||
{
|
|
||||||
var buttonEvent = scope MouseButtonPressedEvent(.LeftButton);
|
|
||||||
window._eventCallback(buttonEvent);
|
|
||||||
}
|
|
||||||
else if(buttonTransitions.HasFlag(.LeftUp))
|
|
||||||
{
|
|
||||||
var buttonEvent = scope MouseButtonReleasedEvent(.LeftButton);
|
|
||||||
window._eventCallback(buttonEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(buttonTransitions.HasFlag(.RightDown))
|
|
||||||
{
|
|
||||||
var buttonEvent = scope MouseButtonPressedEvent(.RightButton);
|
|
||||||
window._eventCallback(buttonEvent);
|
|
||||||
}
|
|
||||||
else if(buttonTransitions.HasFlag(.RightUp))
|
|
||||||
{
|
|
||||||
var buttonEvent = scope MouseButtonReleasedEvent(.RightButton);
|
|
||||||
window._eventCallback(buttonEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(buttonTransitions.HasFlag(.MiddleDown))
|
|
||||||
{
|
|
||||||
var buttonEvent = scope MouseButtonPressedEvent(.MiddleButton);
|
|
||||||
window._eventCallback(buttonEvent);
|
|
||||||
}
|
|
||||||
else if(buttonTransitions.HasFlag(.MiddleUp))
|
|
||||||
{
|
|
||||||
var buttonEvent = scope MouseButtonReleasedEvent(.MiddleButton);
|
|
||||||
window._eventCallback(buttonEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(buttonTransitions.HasFlag(.XButton1Down))
|
|
||||||
{
|
|
||||||
var buttonEvent = scope MouseButtonPressedEvent(.XButton1);
|
|
||||||
window._eventCallback(buttonEvent);
|
|
||||||
}
|
|
||||||
else if(buttonTransitions.HasFlag(.XButton1Up))
|
|
||||||
{
|
|
||||||
var buttonEvent = scope MouseButtonReleasedEvent(.XButton1);
|
|
||||||
window._eventCallback(buttonEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(buttonTransitions.HasFlag(.XButton2Down))
|
|
||||||
{
|
|
||||||
var buttonEvent = scope MouseButtonPressedEvent(.XButton2);
|
|
||||||
window._eventCallback(buttonEvent);
|
|
||||||
}
|
|
||||||
else if(buttonTransitions.HasFlag(.XButton2Up))
|
|
||||||
{
|
|
||||||
var buttonEvent = scope MouseButtonReleasedEvent(.XButton2);
|
|
||||||
window._eventCallback(buttonEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(buttonTransitions.HasFlag(.MouseWheel))
|
|
||||||
{
|
|
||||||
int32 rotation = raw.Data.Mouse.DUMMYUNIONNAME.DUMMYSTRUCTNAME.usButtonData / WHEEL_DELTA;
|
|
||||||
|
|
||||||
var scrollEvent = scope MouseScrolledEvent(0, rotation);
|
|
||||||
window._eventCallback(scrollEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(buttonTransitions.HasFlag(.MouseHWheel))
|
|
||||||
{
|
|
||||||
int32 rotation = raw.Data.Mouse.DUMMYUNIONNAME.DUMMYSTRUCTNAME.usButtonData / WHEEL_DELTA;
|
|
||||||
|
|
||||||
var scrollEvent = scope MouseScrolledEvent(rotation, 0);
|
|
||||||
window._eventCallback(scrollEvent);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
|
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum RawMouseButtonTransition
|
/**
|
||||||
|
* Converts the wParam and lParam of a WM_KEYDOWN or WM_KEYUP message to the corresponding engine keycode.
|
||||||
|
*/
|
||||||
|
static Key WindowMessageToKey(WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
LeftDown = 0x0001,
|
Key key = Key.FromWindowsKeyCode((.)wParam);
|
||||||
LeftUp = 0x0002,
|
|
||||||
MiddleDown = 0x0010,
|
var scancode = (lParam & 0x00ff0000) >> 16;
|
||||||
MiddleUp = 0x0020,
|
bool isExtended = (lParam & 0x01000000) > 0;
|
||||||
RightDown = 0x0004,
|
|
||||||
RightUp = 0x0008,
|
switch(key)
|
||||||
XButton1Down = 0x0040,
|
{
|
||||||
XButton1Up = 0x0080,
|
case .Shift:
|
||||||
XButton2Down = 0x0100,
|
return Key.FromWindowsKeyCode((.)MapVirtualKeyW((.)scancode, MAPVK_VSC_TO_VK_EX));
|
||||||
XButton2Up = 0x0200,
|
case .Control:
|
||||||
MouseWheel = 0x0400,
|
return isExtended ? .RightControl : .LeftControl;
|
||||||
MouseHWheel = 0x0800
|
case .Alt:
|
||||||
|
return isExtended ? .RightAlt : .LeftAlt;
|
||||||
|
default:
|
||||||
|
return key;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update()
|
public override void Update()
|
||||||
{
|
{
|
||||||
|
Debug.Profiler.ProfileFunction!();
|
||||||
|
|
||||||
Message message = .();
|
Message message = .();
|
||||||
while (PeekMessageW(&message, 0, 0, 0, .Remove))
|
while (PeekMessageW(&message, 0, 0, 0, .Remove))
|
||||||
{
|
{
|
||||||
@@ -641,4 +568,5 @@ namespace GlitchyEngine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using GlitchLog;
|
using GlitchLog;
|
||||||
|
using GlitchyEngine.Debug;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace GlitchyEngine
|
namespace GlitchyEngine
|
||||||
@@ -11,24 +12,38 @@ namespace GlitchyEngine
|
|||||||
|
|
||||||
public static int Main(String[] args)
|
public static int Main(String[] args)
|
||||||
{
|
{
|
||||||
|
Debug.Profiler.BeginProfiling();
|
||||||
|
|
||||||
|
Application app;
|
||||||
|
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileScope!("Initialize");
|
||||||
|
|
||||||
Log.EngineLogger.Info("Initializing Application...");
|
Log.EngineLogger.Info("Initializing Application...");
|
||||||
|
|
||||||
Stopwatch initWatch = scope Stopwatch();
|
Stopwatch initWatch = scope Stopwatch();
|
||||||
|
|
||||||
var app = CreateApplication();
|
app = CreateApplication();
|
||||||
|
|
||||||
initWatch.Stop();
|
initWatch.Stop();
|
||||||
|
|
||||||
Log.EngineLogger.Info($"Application initialized ({initWatch.ElapsedMilliseconds}ms).");
|
Log.EngineLogger.Info($"Application initialized ({initWatch.ElapsedMilliseconds}ms).");
|
||||||
Log.EngineLogger.Info("Running App...");
|
Log.EngineLogger.Info("Running App...");
|
||||||
|
}
|
||||||
|
|
||||||
app.Run();
|
app.Run();
|
||||||
|
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileScope!("Shutdown");
|
||||||
|
|
||||||
Log.EngineLogger.Info("Uninitializing Application...");
|
Log.EngineLogger.Info("Uninitializing Application...");
|
||||||
|
|
||||||
delete app;
|
delete app;
|
||||||
|
|
||||||
Log.EngineLogger.Info("Application uninitialized.");
|
Log.EngineLogger.Info("Application uninitialized.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.Profiler.EndProfiling();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,279 @@
|
|||||||
|
using System;
|
||||||
|
using GlitchyEngine.Core;
|
||||||
|
using GlitchyEngine.Math;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Renderer.Animation
|
||||||
|
{
|
||||||
|
class AnimationPlayer
|
||||||
|
{
|
||||||
|
public Skeleton Skeleton ~ _.ReleaseRef();
|
||||||
|
public AnimationClip CurrentClip ~ _.ReleaseRef();
|
||||||
|
public float TimeStamp;
|
||||||
|
|
||||||
|
public SkeletonPose Pose ~ delete _;
|
||||||
|
|
||||||
|
public Matrix[] SkinningMatricies ~ delete _;
|
||||||
|
public Matrix3x3[] InvTransSkinningMatricies ~ delete _;
|
||||||
|
|
||||||
|
public this(Skeleton skeleton, AnimationClip clip)
|
||||||
|
{
|
||||||
|
Skeleton = skeleton;
|
||||||
|
CurrentClip = clip;
|
||||||
|
|
||||||
|
Pose = new SkeletonPose(Skeleton);
|
||||||
|
|
||||||
|
SkinningMatricies = new Matrix[Skeleton.Joints.Count];
|
||||||
|
InvTransSkinningMatricies = new Matrix3x3[Skeleton.Joints.Count];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(GameTime gameTime)
|
||||||
|
{
|
||||||
|
TimeStamp += (float)gameTime.FrameTime.TotalSeconds;
|
||||||
|
|
||||||
|
if(CurrentClip.IsLooping && CurrentClip.Duration != 0)
|
||||||
|
{
|
||||||
|
TimeStamp %= CurrentClip.Duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i < Skeleton.Joints.Count)
|
||||||
|
{
|
||||||
|
ref JointPose localPose = ref Pose.LocalPose[i];
|
||||||
|
|
||||||
|
localPose = CurrentClip.JointAnimations[i].GetCurrentPose(TimeStamp);
|
||||||
|
|
||||||
|
Matrix jointToParent =
|
||||||
|
Matrix.Translation(localPose.Translation) *
|
||||||
|
Matrix.RotationQuaternion(localPose.Rotation) *
|
||||||
|
Matrix.Scaling(localPose.Scale);
|
||||||
|
|
||||||
|
uint8 parentIndex = Skeleton.Joints[i].ParentID;
|
||||||
|
|
||||||
|
ref Matrix globalPose = ref Pose.GlobalPose[i];
|
||||||
|
|
||||||
|
if(parentIndex == uint8.MaxValue)
|
||||||
|
{
|
||||||
|
globalPose = jointToParent;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
globalPose = Pose.GlobalPose[parentIndex] * jointToParent;
|
||||||
|
}
|
||||||
|
|
||||||
|
SkinningMatricies[i] = globalPose * Skeleton.Joints[i].InverseBindPose;
|
||||||
|
InvTransSkinningMatricies[i] = ((Matrix3x3)SkinningMatricies[i]).Inverse().Transpose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AnimationClip : RefCounter
|
||||||
|
{
|
||||||
|
private Skeleton _skeleton ~ _.ReleaseRef();
|
||||||
|
public JointAnimation[] JointAnimations ~ delete _;
|
||||||
|
public bool IsLooping;
|
||||||
|
public float Duration;
|
||||||
|
|
||||||
|
public Skeleton Skeleton => _skeleton;
|
||||||
|
|
||||||
|
[AllowAppend]
|
||||||
|
public this(Skeleton skeleton)
|
||||||
|
{
|
||||||
|
var jointAnimations = new JointAnimation[skeleton.Joints.Count];
|
||||||
|
|
||||||
|
Log.EngineLogger.AssertDebug(skeleton != null);
|
||||||
|
|
||||||
|
_skeleton = skeleton..AddRef();
|
||||||
|
JointAnimations = jointAnimations;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: check
|
||||||
|
public ~this()
|
||||||
|
{
|
||||||
|
for(var jointAnimation in JointAnimations)
|
||||||
|
{
|
||||||
|
//jointAnimation.Dispose();
|
||||||
|
delete jointAnimation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum InterpolationMode
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* No keyframe interpolation.
|
||||||
|
* The keyframe with the greates timestamp that is smaller than the current time will be used.
|
||||||
|
*/
|
||||||
|
Step,
|
||||||
|
/**
|
||||||
|
* Linear interpolation between the two keyframes that are closest to the current time.
|
||||||
|
*/
|
||||||
|
Linear,
|
||||||
|
/**
|
||||||
|
* Cubic spline interpolation between the two keyframes that are closest to the current time.
|
||||||
|
*/
|
||||||
|
CubicSpline
|
||||||
|
}
|
||||||
|
|
||||||
|
class JointAnimationChannel<T> where T : struct // : IDisposable
|
||||||
|
{
|
||||||
|
public float[] TimeStamps;
|
||||||
|
public T[] Values;
|
||||||
|
public InterpolationMode InterpolationMode = .Step;
|
||||||
|
|
||||||
|
public float Duration => TimeStamps[TimeStamps.Count - 1];
|
||||||
|
|
||||||
|
public this(int samples, InterpolationMode interpolationMode)
|
||||||
|
{
|
||||||
|
TimeStamps = new float[samples];
|
||||||
|
Values = new T[samples];
|
||||||
|
InterpolationMode = interpolationMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ~this()
|
||||||
|
{
|
||||||
|
delete TimeStamps;
|
||||||
|
delete Values;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public (T, T, float) GetSample(float currentTime)
|
||||||
|
{
|
||||||
|
let (previousIndex, previousTime) = FindPreviousTimeStamp(currentTime);
|
||||||
|
|
||||||
|
T previousSample = Values[previousIndex];
|
||||||
|
|
||||||
|
if(InterpolationMode == .Step)
|
||||||
|
{
|
||||||
|
return (previousSample, default(T), 0f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int nextIndex = previousIndex + 1;
|
||||||
|
if(nextIndex >= Values.Count)
|
||||||
|
nextIndex = Values.Count - 1;
|
||||||
|
|
||||||
|
float nextTime = TimeStamps[nextIndex];
|
||||||
|
|
||||||
|
T nextSample = Values[nextIndex];
|
||||||
|
|
||||||
|
float interpolationValue = (currentTime - previousTime) / (nextTime - previousTime);
|
||||||
|
|
||||||
|
return (previousSample, nextSample, interpolationValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public (int Index, float timeStamp) FindPreviousTimeStamp(float currentTime)
|
||||||
|
{
|
||||||
|
// TODO use binary search to speed things up?
|
||||||
|
|
||||||
|
int index = TimeStamps.Count - 1;
|
||||||
|
|
||||||
|
for(int i < TimeStamps.Count)
|
||||||
|
{
|
||||||
|
if(TimeStamps[i] > currentTime)
|
||||||
|
{
|
||||||
|
index = i - 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(index == -1)
|
||||||
|
index = 0;
|
||||||
|
|
||||||
|
// Don't return -1 but return first frame
|
||||||
|
return (index, TimeStamps[index]);
|
||||||
|
|
||||||
|
//return array.Count - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class JointAnimation// : IDisposable
|
||||||
|
{
|
||||||
|
public JointAnimationChannel<Vector3> TranslationChannel ~ delete _;
|
||||||
|
public JointAnimationChannel<Quaternion> RotationChannel ~ delete _;
|
||||||
|
public JointAnimationChannel<Vector3> ScaleChannel ~ delete _;
|
||||||
|
|
||||||
|
public float Duration
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Math.Max(Math.Max(
|
||||||
|
TranslationChannel?.Duration ?? 0, RotationChannel?.Duration ?? 0), ScaleChannel?.Duration ?? 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
delete TranslationChannel;
|
||||||
|
delete RotationChannel;
|
||||||
|
delete ScaleChannel;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
public JointPose GetCurrentPose(float timeStamp)
|
||||||
|
{
|
||||||
|
JointPose result;
|
||||||
|
|
||||||
|
if(TranslationChannel != null)
|
||||||
|
{
|
||||||
|
let (previous, next, interpolationValue) = TranslationChannel.GetSample(timeStamp);
|
||||||
|
|
||||||
|
switch(TranslationChannel.InterpolationMode)
|
||||||
|
{
|
||||||
|
case .Step:
|
||||||
|
result.Translation = previous;
|
||||||
|
case .Linear:
|
||||||
|
result.Translation = Vector3.Lerp(previous, next, interpolationValue);
|
||||||
|
default:
|
||||||
|
result.Rotation = ?;
|
||||||
|
Runtime.NotImplemented();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.Translation = .Zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(RotationChannel != null)
|
||||||
|
{
|
||||||
|
let (previous, next, interpolationValue) = RotationChannel.GetSample(timeStamp);
|
||||||
|
|
||||||
|
switch(RotationChannel.InterpolationMode)
|
||||||
|
{
|
||||||
|
case .Step:
|
||||||
|
result.Rotation = previous;
|
||||||
|
case .Linear:
|
||||||
|
result.Rotation = Quaternion.Slerp(previous, next, interpolationValue);
|
||||||
|
default:
|
||||||
|
result.Rotation = ?;
|
||||||
|
Runtime.NotImplemented();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.Rotation = .Identity;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ScaleChannel != null)
|
||||||
|
{
|
||||||
|
let (previous, next, interpolationValue) = ScaleChannel.GetSample(timeStamp);
|
||||||
|
|
||||||
|
//switch(ScaleChannel.InterpolationMode)
|
||||||
|
switch(InterpolationMode.Step)
|
||||||
|
{
|
||||||
|
case .Step:
|
||||||
|
result.Scale = previous;
|
||||||
|
case .Linear:
|
||||||
|
result.Scale = Vector3.Lerp(previous, next, interpolationValue);
|
||||||
|
default:
|
||||||
|
result.Rotation = ?;
|
||||||
|
Runtime.NotImplemented();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.Scale = .One;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
using GlitchyEngine.Math;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Renderer.Animation
|
||||||
|
{
|
||||||
|
public struct Joint
|
||||||
|
{
|
||||||
|
/// Converts vertices from model space to joint space
|
||||||
|
public Matrix InverseBindPose;
|
||||||
|
public String Name;
|
||||||
|
public uint8 ParentID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct JointPose
|
||||||
|
{
|
||||||
|
public Quaternion Rotation;
|
||||||
|
public Vector3 Translation;
|
||||||
|
public Vector3 Scale;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
using GlitchyEngine.Core;
|
||||||
|
using GlitchyEngine.Math;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Renderer.Animation
|
||||||
|
{
|
||||||
|
public class Skeleton : RefCounter
|
||||||
|
{
|
||||||
|
public Joint[] Joints ~ delete _;
|
||||||
|
|
||||||
|
public Joint? GetParent(Joint joint)
|
||||||
|
{
|
||||||
|
if(joint.ParentID == uint8.MaxValue)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return Joints[joint.ParentID];
|
||||||
|
}
|
||||||
|
|
||||||
|
public ~this()
|
||||||
|
{
|
||||||
|
for(var joint in Joints)
|
||||||
|
{
|
||||||
|
delete joint.Name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SkeletonPose
|
||||||
|
{
|
||||||
|
private Skeleton _skeleton ~ _.ReleaseRef();
|
||||||
|
public JointPose[] LocalPose ~ delete _;
|
||||||
|
public Matrix[] GlobalPose ~ delete _;
|
||||||
|
|
||||||
|
public Matrix[] SkinningMatricies ~ delete _;
|
||||||
|
public Matrix3x3[] InvTransSkinningMatricies ~ delete _;
|
||||||
|
|
||||||
|
public Skeleton Skeleton => _skeleton;
|
||||||
|
|
||||||
|
public this(Skeleton skeleton)
|
||||||
|
{
|
||||||
|
_skeleton = skeleton..AddRef();
|
||||||
|
|
||||||
|
int jointCount = _skeleton.Joints.Count;
|
||||||
|
|
||||||
|
LocalPose = new JointPose[jointCount];
|
||||||
|
GlobalPose = new Matrix[jointCount];
|
||||||
|
|
||||||
|
SkinningMatricies = new Matrix[jointCount];
|
||||||
|
InvTransSkinningMatricies = new Matrix3x3[jointCount];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using GlitchyEngine.Core;
|
||||||
using GlitchyEngine.Math;
|
using GlitchyEngine.Math;
|
||||||
|
|
||||||
namespace GlitchyEngine.Renderer
|
namespace GlitchyEngine.Renderer
|
||||||
{
|
{
|
||||||
public struct BlendStateDescription
|
public struct BlendStateDescription
|
||||||
@@ -70,23 +72,25 @@ namespace GlitchyEngine.Renderer
|
|||||||
public static readonly Self Default = .(false, false, .(.Default, .Default, .Default, .Default, .Default, .Default, .Default, .Default));
|
public static readonly Self Default = .(false, false, .(.Default, .Default, .Default, .Default, .Default, .Default, .Default, .Default));
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BlendState : RefCounted
|
public class BlendState : RefCounter
|
||||||
{
|
{
|
||||||
protected GraphicsContext _context ~ _?.ReleaseRef();
|
|
||||||
|
|
||||||
protected BlendStateDescription _desc;
|
protected BlendStateDescription _desc;
|
||||||
|
|
||||||
public BlendStateDescription Description => _desc;
|
public BlendStateDescription Description => _desc;
|
||||||
|
|
||||||
public this(GraphicsContext context, BlendStateDescription desc)
|
public this(BlendStateDescription desc)
|
||||||
{
|
{
|
||||||
_context = context..AddRef();
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
|
||||||
_desc = desc;
|
_desc = desc;
|
||||||
|
|
||||||
PlatformCreateBlendState();
|
PlatformCreateBlendState();
|
||||||
}
|
}
|
||||||
|
|
||||||
public extern void Bind(ColorRGBA blendFactor = .White);
|
public ~this()
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
}
|
||||||
|
|
||||||
protected extern void PlatformCreateBlendState();
|
protected extern void PlatformCreateBlendState();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,47 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using GlitchyEngine.Core;
|
||||||
|
|
||||||
namespace GlitchyEngine.Renderer
|
namespace GlitchyEngine.Renderer
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* Identifies expected resource use during rendering.
|
|
||||||
* The usage directly reflects whether a resource is accessible by the CPU and/or the graphics processing unit (GPU).
|
|
||||||
*/
|
|
||||||
public enum Usage
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* A resource that requires read and write access by the GPU.
|
|
||||||
* This is likely to be the most common usage choice.
|
|
||||||
*/
|
|
||||||
Default = 0,
|
|
||||||
/**
|
|
||||||
* A resource that can only be read by the GPU. It cannot be written by the GPU, and cannot be accessed at all by the CPU.
|
|
||||||
*/
|
|
||||||
Immutable = 1,
|
|
||||||
/**
|
|
||||||
* A resource that is accessible by both the GPU (read only) and the CPU (write only).
|
|
||||||
* A dynamic resource is a good choice for a resource that will be updated by the CPU at least once per frame.
|
|
||||||
* To update a dynamic resource, use a Map method.
|
|
||||||
*/
|
|
||||||
Dynamic = 2,
|
|
||||||
/**
|
|
||||||
* A resource that supports data transfer (copy) from the GPU to the CPU.
|
|
||||||
*/
|
|
||||||
Staging = 3
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines how the CPU can access a resource.
|
|
||||||
*/
|
|
||||||
public enum CPUAccessFlags
|
|
||||||
{
|
|
||||||
/// The CPU has no access to the resource.
|
|
||||||
None = 0,
|
|
||||||
/// The CPU has read access to the resource.
|
|
||||||
Read = 1,
|
|
||||||
/// The CPU has write access to the resource.
|
|
||||||
Write = 2
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines how to bind a buffer to the pipeline.
|
* Defines how to bind a buffer to the pipeline.
|
||||||
*/
|
*/
|
||||||
@@ -120,26 +81,19 @@ namespace GlitchyEngine.Renderer
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Represents a buffer containing binary data on the GPU.
|
/// Represents a buffer containing binary data on the GPU.
|
||||||
public class Buffer : RefCounted
|
public class Buffer : RefCounter
|
||||||
{
|
{
|
||||||
internal GraphicsContext _context ~ _?.ReleaseRef();
|
|
||||||
|
|
||||||
protected BufferDescription _description;
|
protected BufferDescription _description;
|
||||||
|
|
||||||
public GraphicsContext Context => _context;
|
|
||||||
|
|
||||||
public BufferDescription Description => _description;
|
public BufferDescription Description => _description;
|
||||||
|
|
||||||
protected this(GraphicsContext context)
|
protected this() { }
|
||||||
{
|
|
||||||
_context = context..AddRef();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance of a Buffer.
|
* Creates a new instance of a Buffer.
|
||||||
* @param description The buffer description.
|
* @param description The buffer description.
|
||||||
*/
|
*/
|
||||||
public this(GraphicsContext context, BufferDescription description) : this(context)
|
public this(BufferDescription description)
|
||||||
{
|
{
|
||||||
_description = description;
|
_description = description;
|
||||||
}
|
}
|
||||||
@@ -201,10 +155,9 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance of a Buffer<T>
|
* Creates a new instance of a Buffer<T>
|
||||||
* @param context The graphics context.
|
|
||||||
* @param description Describes the Buffer. Note: description.Size is ignored, as it will always be sizeof(T).
|
* @param description Describes the Buffer. Note: description.Size is ignored, as it will always be sizeof(T).
|
||||||
*/
|
*/
|
||||||
public this(GraphicsContext context, BufferDescription description) : base(context)
|
public this(BufferDescription description)
|
||||||
{
|
{
|
||||||
_description = description;
|
_description = description;
|
||||||
_description.Size = (uint32)sizeof(T);
|
_description.Size = (uint32)sizeof(T);
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user