mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 13:01:52 +00:00
Compare commits
30
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
65e2248b30 | ||
|
|
a89657591f | ||
|
|
cd929080f4 | ||
|
|
79e160348b | ||
|
|
5a6abc9b8b | ||
|
|
0f62637662 | ||
|
|
1d7029eb0f | ||
|
|
ceb4cef034 | ||
|
|
5873f12643 | ||
|
|
1b00fa67a5 | ||
|
|
dfeed4a5c9 | ||
|
|
ec83dfa21d | ||
|
|
d8f6be1358 | ||
|
|
72400e873d | ||
|
|
a0373366f6 | ||
|
|
8320689d3e | ||
|
|
4e87f5f144 | ||
|
|
3449463282 | ||
|
|
623ada4b2f | ||
|
|
4e377bb117 | ||
|
|
08613b9e82 | ||
|
|
4b032d2c7e | ||
|
|
9d52f77b43 | ||
|
|
7a777bb55e | ||
|
|
f87c0e2ecd | ||
|
|
488d2a55c4 | ||
|
|
cbfbd449ff | ||
|
|
4dcf1b5bec | ||
|
|
afc7594df9 | ||
|
|
0461669e13 |
+2
-1
@@ -4,4 +4,5 @@ build/
|
|||||||
.vs/
|
.vs/
|
||||||
recovery/
|
recovery/
|
||||||
vendor/directx
|
vendor/directx
|
||||||
imgui.ini
|
Sandbox/imgui.ini
|
||||||
|
Sandbox/worlds
|
||||||
|
|||||||
+5
-17
@@ -1,24 +1,12 @@
|
|||||||
[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/DirectXTK"]
|
[submodule "GlitchyEngine/vendor/imgui-beef"]
|
||||||
path = GlitchyEngine/vendor/DirectXTK
|
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
|
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/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
|
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
FileVersion = 1
|
FileVersion = 1
|
||||||
Projects = {Sandbox = {Path = "Sandbox"}, GlitchyEngine = {Path = "GlitchyEngine"}, GlitchLog = {Path = "GlitchLog"}, DirectX = {Path = "GlitchyEngine/vendor/directx/DirectX"}, DirectXTK = {Path = "GlitchyEngine/vendor/DirectXTK/DirectXTK-beef"}, 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"}}
|
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"}}
|
||||||
|
|
||||||
[Workspace]
|
[Workspace]
|
||||||
StartupProject = "Sandbox"
|
StartupProject = "Sandbox"
|
||||||
|
|||||||
@@ -50,10 +50,10 @@ namespace GlitchLog
|
|||||||
|
|
||||||
public this()
|
public this()
|
||||||
{
|
{
|
||||||
//Debug.Assert(Debug.IsDebuggerPresent, "The DebugLogger requires a debugger to be present.");
|
Runtime.Assert(Debug.IsDebuggerPresent, "The DebugLogger requires a debugger to be present.");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if GL_NOLOG || GL_LOG_NOTRACE
|
#if GL_NOLOG || GL_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_LOG_NOINFO
|
#if GL_NOLOG || GL_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_LOG_NOWARNING
|
#if GL_NOLOG || GL_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_LOG_NOERROR
|
#if GL_NOLOG || GL_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_LOG_NOCRITICAL
|
#if GL_NOLOG || GL_NOCRITICAL
|
||||||
[SkipCall]
|
[SkipCall]
|
||||||
#endif
|
#endif
|
||||||
[Inline]
|
[Inline]
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
FileVersion = 1
|
|
||||||
Dependencies = {corlib = "*", GlitchLog = "*", GlitchyEngine = "*"}
|
|
||||||
|
|
||||||
[Project]
|
|
||||||
Name = "GlitchyEditor"
|
|
||||||
TargetType = "BeefGUIApplication"
|
|
||||||
StartupObject = "GlitchyEngine.Program"
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
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]
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
Texture2D Texture : register(t0);
|
|
||||||
SamplerState Sampler : register(s0);
|
|
||||||
|
|
||||||
struct VS_Input
|
|
||||||
{
|
|
||||||
float2 Position : POSITION;
|
|
||||||
float4x4 Tranform : TRANSFORM;
|
|
||||||
float4 Color : COLOR;
|
|
||||||
float4 UVTransform : TEXCOORD;
|
|
||||||
};
|
|
||||||
|
|
||||||
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(float4(input.Position, 0.0f, 1.0f), input.Tranform);
|
|
||||||
output.TexCoord = input.UVTransform.xy + input.UVTransform.zw * input.Position;
|
|
||||||
output.Color = input.Color;
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
float4 PS(PS_Input input) : SV_Target0
|
|
||||||
{
|
|
||||||
float4 color = input.Color * Texture.Sample(Sampler, input.TexCoord);
|
|
||||||
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
|
|
||||||
#effect[VS=VS, PS=PS]
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
cbuffer SceneConstants
|
|
||||||
{
|
|
||||||
float4x4 ViewProjection = float4x4(1, 0, 0, 0,
|
|
||||||
0, 1, 0, 0,
|
|
||||||
0, 0, 1, 0,
|
|
||||||
0, 0, 0, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
cbuffer ObjectConstants
|
|
||||||
{
|
|
||||||
float4x4 Transform;
|
|
||||||
}
|
|
||||||
|
|
||||||
cbuffer Constants
|
|
||||||
{
|
|
||||||
float4 BaseColor;
|
|
||||||
float3 LightDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
cbuffer SkinningMatrices
|
|
||||||
{
|
|
||||||
matrix SkinningMatrices[255];
|
|
||||||
float3x3 InvTransSkinningMatrices[255];
|
|
||||||
}
|
|
||||||
|
|
||||||
struct VS_IN
|
|
||||||
{
|
|
||||||
float3 Position : POSITION;
|
|
||||||
float3 Normal : NORMAL;
|
|
||||||
uint4 JointIndices : JOINTS_0;
|
|
||||||
float4 JointWeights : WEIGHTS_0;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PS_IN
|
|
||||||
{
|
|
||||||
float4 Position : SV_POSITION;
|
|
||||||
float3 Normal : NORMAL;
|
|
||||||
};
|
|
||||||
|
|
||||||
PS_IN VS(VS_IN input)
|
|
||||||
{
|
|
||||||
PS_IN output;
|
|
||||||
|
|
||||||
// Unanimated position in modelspace
|
|
||||||
float4 positionRaw = float4(input.Position, 1);
|
|
||||||
|
|
||||||
// Calculate animated position in modelspace
|
|
||||||
|
|
||||||
float4 position =
|
|
||||||
mul(SkinningMatrices[input.JointIndices.x], positionRaw) * input.JointWeights.x +
|
|
||||||
mul(SkinningMatrices[input.JointIndices.y], positionRaw) * input.JointWeights.y +
|
|
||||||
mul(SkinningMatrices[input.JointIndices.z], positionRaw) * input.JointWeights.z +
|
|
||||||
mul(SkinningMatrices[input.JointIndices.w], positionRaw) * input.JointWeights.w;
|
|
||||||
|
|
||||||
float3 normal =
|
|
||||||
mul(InvTransSkinningMatrices[input.JointIndices.x], input.Normal) * input.JointWeights.x +
|
|
||||||
mul(InvTransSkinningMatrices[input.JointIndices.y], input.Normal) * input.JointWeights.y +
|
|
||||||
mul(InvTransSkinningMatrices[input.JointIndices.z], input.Normal) * input.JointWeights.z +
|
|
||||||
mul(InvTransSkinningMatrices[input.JointIndices.w], input.Normal) * input.JointWeights.w;
|
|
||||||
|
|
||||||
//position = saturate(position - 1000) + positionRaw;
|
|
||||||
|
|
||||||
//float4 position = mul(SkinningMatrices[input.JointIndices.x], positionRaw);
|
|
||||||
|
|
||||||
float4 worldPosition = mul(Transform, position);
|
|
||||||
|
|
||||||
output.Position = mul(ViewProjection, worldPosition);
|
|
||||||
output.Normal = mul((float3x3)Transform, normal);
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
float4 PS(PS_IN input) : SV_TARGET
|
|
||||||
{
|
|
||||||
input.Normal = normalize(input.Normal);
|
|
||||||
|
|
||||||
float shading = dot(LightDir, input.Normal);
|
|
||||||
//float shading = dot(LightDir, LightDir) + 1;
|
|
||||||
shading = clamp(shading, 0.0f, 1.0f);
|
|
||||||
|
|
||||||
return BaseColor * shading;
|
|
||||||
}
|
|
||||||
|
|
||||||
#effect[VS=VS,PS=PS]
|
|
||||||
@@ -1,157 +0,0 @@
|
|||||||
using ImGui;
|
|
||||||
using GlitchyEngine.World;
|
|
||||||
using System;
|
|
||||||
using GlitchyEngine.Math;
|
|
||||||
|
|
||||||
namespace GlitchyEditor.EditWindows
|
|
||||||
{
|
|
||||||
class ComponentEditWindow
|
|
||||||
{
|
|
||||||
public const String s_WindowTitle = "Components";
|
|
||||||
|
|
||||||
private Editor _editor;
|
|
||||||
|
|
||||||
private bool _open = true;
|
|
||||||
|
|
||||||
public Editor Editor => _editor;
|
|
||||||
|
|
||||||
public bool Open
|
|
||||||
{
|
|
||||||
get => _open;
|
|
||||||
set => _open = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(Editor editor)
|
|
||||||
{
|
|
||||||
_editor = editor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Show()
|
|
||||||
{
|
|
||||||
if(!_open)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if(!ImGui.Begin(s_WindowTitle, &_open, .None))
|
|
||||||
{
|
|
||||||
ImGui.End();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(_editor.SelectedEntities.Count == 1)
|
|
||||||
{
|
|
||||||
Entity entity = _editor.SelectedEntities.Front;
|
|
||||||
|
|
||||||
ShowComponents(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.End();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ShowComponents(Entity entity)
|
|
||||||
{
|
|
||||||
NameComponentEditor.Show(_editor.World, entity);
|
|
||||||
TransformComponentEditor.Show(_editor.World, entity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class NameComponentEditor
|
|
||||||
{
|
|
||||||
public static void Show(EcsWorld world, Entity entity)
|
|
||||||
{
|
|
||||||
char8[128] nameBuffer = default;
|
|
||||||
|
|
||||||
DebugNameComponent* component = world.GetComponent<DebugNameComponent>(entity);
|
|
||||||
|
|
||||||
String name = null;
|
|
||||||
|
|
||||||
if(component != null)
|
|
||||||
{
|
|
||||||
name = component.DebugName;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
name = scope:: $"Entity {entity.[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 = world.AssignComponent<DebugNameComponent>(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
component.DebugName.Clear();
|
|
||||||
component.DebugName.Append(&nameBuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class TransformComponentEditor
|
|
||||||
{
|
|
||||||
public static void Show(EcsWorld world, Entity entity)
|
|
||||||
{
|
|
||||||
TransformComponent* component = world.GetComponent<TransformComponent>(entity);
|
|
||||||
|
|
||||||
if(component == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if(ImGui.TreeNodeEx("Transform", .DefaultOpen))
|
|
||||||
{
|
|
||||||
Vector3 position = component.Position;
|
|
||||||
bool positionChanged = false;
|
|
||||||
|
|
||||||
Vector3 rotationEuler = MathHelper.ToDegrees(component.RotationEuler);
|
|
||||||
bool rotationChanged = false;
|
|
||||||
|
|
||||||
Vector3 scale = component.Scale;
|
|
||||||
bool scaleChanged = false;
|
|
||||||
|
|
||||||
void ShowValue(String text, ref float value, ref bool valueChanged, String id)
|
|
||||||
{
|
|
||||||
ImGui.Text(text);
|
|
||||||
ImGui.SameLine();
|
|
||||||
ImGui.PushID(id);
|
|
||||||
valueChanged |= ImGui.DragFloat(String.Empty, &value, 0.1f);
|
|
||||||
ImGui.PopID();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ShowTableRow(String name, ref Vector3 value, ref bool valueChanged)
|
|
||||||
{
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
|
|
||||||
ImGui.Text(name);
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ShowValue("X: ", ref value.X, ref valueChanged, scope $"{name}X");
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ShowValue("Y: ", ref value.Y, ref valueChanged, scope $"{name}Y");
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ShowValue("Z: ", ref value.Z, ref valueChanged, scope $"{name}Z");
|
|
||||||
|
|
||||||
ImGui.TableNextRow();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.BeginTable("posRotScaleTable", 4);
|
|
||||||
|
|
||||||
ShowTableRow("Position", ref position, ref positionChanged);
|
|
||||||
ShowTableRow("Rotation", ref rotationEuler, ref rotationChanged);
|
|
||||||
ShowTableRow("Scale", ref scale, ref scaleChanged);
|
|
||||||
|
|
||||||
ImGui.EndTable();
|
|
||||||
|
|
||||||
if(positionChanged)
|
|
||||||
component.Position = position;
|
|
||||||
|
|
||||||
if(rotationChanged)
|
|
||||||
component.RotationEuler = MathHelper.ToRadians(rotationEuler);
|
|
||||||
|
|
||||||
if(scaleChanged)
|
|
||||||
component.Scale = scale;
|
|
||||||
|
|
||||||
ImGui.TreePop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,340 +0,0 @@
|
|||||||
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
|
|
||||||
{
|
|
||||||
public const String s_WindowTitle = "Entity Hierarchy";
|
|
||||||
|
|
||||||
private Editor _editor;
|
|
||||||
|
|
||||||
/// Buffer for the entity search string.
|
|
||||||
private char8[64] _entitySearchChars;
|
|
||||||
|
|
||||||
private bool _open = true;
|
|
||||||
|
|
||||||
public Editor Editor => _editor;
|
|
||||||
|
|
||||||
public bool Open
|
|
||||||
{
|
|
||||||
get => _open;
|
|
||||||
set => _open = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(Editor editor)
|
|
||||||
{
|
|
||||||
_editor = editor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Show()
|
|
||||||
{
|
|
||||||
if(!_open)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if(!ImGui.Begin(s_WindowTitle, &_open, .MenuBar))
|
|
||||||
{
|
|
||||||
ImGui.End();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ShowEntityHierarchyMenuBar();
|
|
||||||
|
|
||||||
ShowEntityHierarchy();
|
|
||||||
|
|
||||||
ImGui.End();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ShowEntityHierarchyMenuBar()
|
|
||||||
{
|
|
||||||
if(ImGui.BeginMenuBar())
|
|
||||||
{
|
|
||||||
if(ImGui.BeginMenu("Create"))
|
|
||||||
{
|
|
||||||
if(ImGui.MenuItem("Empty Entity"))
|
|
||||||
{
|
|
||||||
_editor.CreateEntityWithTransform();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ImGui.IsItemHovered())
|
|
||||||
ImGui.SetTooltip("Create a new Entity with a transform component.");
|
|
||||||
|
|
||||||
if(ImGui.MenuItem("Empty Child", null, false, !_editor.SelectedEntities.IsEmpty))
|
|
||||||
{
|
|
||||||
var newEntity = _editor.CreateEntityWithTransform();
|
|
||||||
var parent = _editor.World.AssignComponent<ParentComponent>(newEntity);
|
|
||||||
// Last entity in list is the entity that has been selected last.
|
|
||||||
parent.Entity = _editor.SelectedEntities.Back;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ImGui.IsItemHovered())
|
|
||||||
ImGui.SetTooltip("Create a new Entity that is a child of the currently selected entity.");
|
|
||||||
|
|
||||||
if(ImGui.MenuItem("Empty Parent", null, false, !_editor.SelectedEntities.IsEmpty && _editor.AllSelectionsOnSameLevel()))
|
|
||||||
{
|
|
||||||
var commonParent = _editor.World.GetComponent<ParentComponent>(_editor.SelectedEntities.Front);
|
|
||||||
|
|
||||||
var newEntity = _editor.CreateEntityWithTransform();
|
|
||||||
|
|
||||||
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 newEntityParent = _editor.World.AssignComponent<ParentComponent>(newEntity);
|
|
||||||
newEntityParent.Entity = commonParent.Entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
// new entity is parent of all selected entities.
|
|
||||||
for(var selectedEntity in _editor.SelectedEntities)
|
|
||||||
{
|
|
||||||
var selectedEntityParent = _editor.World.AssignComponent<ParentComponent>(selectedEntity);
|
|
||||||
selectedEntityParent.Entity = newEntity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ImGui.IsItemHovered())
|
|
||||||
ImGui.SetTooltip("Create a new Entity that is the parent of the currently selected entities.");
|
|
||||||
|
|
||||||
ImGui.EndMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ImGui.IsItemHovered())
|
|
||||||
ImGui.SetTooltip("Create a new Entity.");
|
|
||||||
|
|
||||||
if(ImGui.MenuItem("Delete", null, false, !_editor.SelectedEntities.IsEmpty) || Input.IsKeyPressed(.Delete))
|
|
||||||
{
|
|
||||||
_editor.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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ImGuiPrintEntityTree(TreeNode<Entity> tree)
|
|
||||||
{
|
|
||||||
String name = null;
|
|
||||||
|
|
||||||
var nameComponent = _editor.World.GetComponent<DebugNameComponent>(tree.Value);
|
|
||||||
|
|
||||||
if(nameComponent != null)
|
|
||||||
{
|
|
||||||
name = nameComponent.DebugName;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
name = scope:: $"Entity {(tree.Value.[Friend]Index)}";
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.TreeNodeFlags flags = .OpenOnArrow;
|
|
||||||
|
|
||||||
if(tree.Children.Count == 0)
|
|
||||||
flags |= .Leaf;
|
|
||||||
|
|
||||||
bool inSelectedList = _editor.SelectedEntities.Contains(tree.Value);
|
|
||||||
|
|
||||||
if(inSelectedList)
|
|
||||||
flags |= .Selected;
|
|
||||||
|
|
||||||
bool isOpen = ImGui.TreeNodeEx(name, flags);
|
|
||||||
|
|
||||||
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 walkerParent = _editor.World.GetComponent<ParentComponent>(walker);
|
|
||||||
|
|
||||||
if(walkerParent == null)
|
|
||||||
{
|
|
||||||
dropLegal = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if(walkerParent.Entity == movedEntity)
|
|
||||||
{
|
|
||||||
dropLegal = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
walker = walkerParent.Entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(dropLegal)
|
|
||||||
{
|
|
||||||
var movedEntityParent = _editor.World.AssignComponent<ParentComponent>(movedEntity);
|
|
||||||
movedEntityParent.Entity = tree.Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.EndDragDropTarget();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool clicked = ImGui.IsItemClicked();
|
|
||||||
|
|
||||||
if(isOpen)
|
|
||||||
{
|
|
||||||
for(var child in tree.Children)
|
|
||||||
{
|
|
||||||
ImGuiPrintEntityTree(child);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.TreePop();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(clicked)
|
|
||||||
{
|
|
||||||
if(inSelectedList)
|
|
||||||
{
|
|
||||||
_editor.SelectedEntities.Remove(tree.Value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(!ImGui.GetIO().KeyCtrl)
|
|
||||||
{
|
|
||||||
_editor.SelectedEntities.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
_editor.SelectedEntities.Add(tree.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
inSelectedList = !inSelectedList;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ShowEntityHierarchy()
|
|
||||||
{
|
|
||||||
StringView searchString = StringView(&_entitySearchChars);
|
|
||||||
|
|
||||||
if(searchString.Length == 0)
|
|
||||||
{
|
|
||||||
// Show entity hierarchy as tree
|
|
||||||
|
|
||||||
TreeNode<Entity> root = scope .(.InvalidEntity);
|
|
||||||
|
|
||||||
TreeNode<Entity> AddEntity(Entity entity)
|
|
||||||
{
|
|
||||||
var parent = _editor.World.GetComponent<ParentComponent>(entity);
|
|
||||||
|
|
||||||
if(parent == null)
|
|
||||||
{
|
|
||||||
return root.AddChild(entity);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var parentNode = root.FindNode(parent.Entity);
|
|
||||||
|
|
||||||
if(parentNode == null)
|
|
||||||
parentNode = AddEntity(parent.Entity);
|
|
||||||
|
|
||||||
return parentNode.AddChild(entity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(var entity in _editor.World.Enumerate())
|
|
||||||
{
|
|
||||||
AddEntity(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;
|
|
||||||
|
|
||||||
_editor.World.RemoveComponent<ParentComponent>(movedEntity);
|
|
||||||
|
|
||||||
// Also mark transform as dirty
|
|
||||||
var transformComponent = _editor.World.GetComponent<TransformComponent>(movedEntity);
|
|
||||||
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 entity in _editor.World.Enumerate())
|
|
||||||
{
|
|
||||||
String name = null;
|
|
||||||
|
|
||||||
var nameComponent = _editor.World.GetComponent<DebugNameComponent>(entity);
|
|
||||||
|
|
||||||
if(nameComponent != null)
|
|
||||||
{
|
|
||||||
name = nameComponent.DebugName;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
name = scope:worldEnumeration $"Entity {entity.[Friend]Index}";
|
|
||||||
}
|
|
||||||
|
|
||||||
StringView nameView = StringView(name);
|
|
||||||
|
|
||||||
for(var token in searchTokens)
|
|
||||||
{
|
|
||||||
if(nameView.IndexOf(token, true) == -1)
|
|
||||||
{
|
|
||||||
continue worldEnumeration;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGuiPrintEntityTree(scope .(entity));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
using System;
|
|
||||||
using ImGui;
|
|
||||||
using GlitchyEngine.Renderer;
|
|
||||||
using GlitchyEngine.Math;
|
|
||||||
using GlitchyEngine;
|
|
||||||
using GlitchyEngine.World;
|
|
||||||
using ImGuizmo;
|
|
||||||
|
|
||||||
namespace GlitchyEditor.EditWindows
|
|
||||||
{
|
|
||||||
class SceneViewportWindow
|
|
||||||
{
|
|
||||||
private Editor _editor;
|
|
||||||
public Camera _camera;
|
|
||||||
|
|
||||||
public const String s_WindowTitle = "Scene";
|
|
||||||
|
|
||||||
private bool _open = true;
|
|
||||||
|
|
||||||
private RenderTarget2D _renderTarget ~ _?.ReleaseRef();
|
|
||||||
|
|
||||||
private bool _hasFocus;
|
|
||||||
|
|
||||||
public Event<EventHandler<Vector2>> ViewportSizeChangedEvent ~ _.Dispose();
|
|
||||||
|
|
||||||
public bool Open
|
|
||||||
{
|
|
||||||
get => _open;
|
|
||||||
set => _open = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool HasFocus
|
|
||||||
{
|
|
||||||
get => _hasFocus;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 void Show()
|
|
||||||
{
|
|
||||||
if(!_open)
|
|
||||||
return;
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(_editor.SelectedEntities.Count > 0)
|
|
||||||
{
|
|
||||||
ImGuizmo.SetDrawlist();
|
|
||||||
|
|
||||||
var entity = _editor.SelectedEntities.Back;
|
|
||||||
|
|
||||||
var transformCmp = _editor.World.GetComponent<TransformComponent>(entity);
|
|
||||||
|
|
||||||
var transform = transformCmp.LocalTransform;
|
|
||||||
|
|
||||||
var view = _camera.View;
|
|
||||||
var projection = _camera.Projection;
|
|
||||||
|
|
||||||
var v = ImGui.GetWindowPos();
|
|
||||||
var cntMin = ImGui.GetWindowContentRegionMin();
|
|
||||||
|
|
||||||
v.x += cntMin.x;
|
|
||||||
v.y += cntMin.y;
|
|
||||||
|
|
||||||
ImGuizmo.SetRect(v.x, v.y, viewportSize.x, viewportSize.y);
|
|
||||||
|
|
||||||
Color c = .(0,0,0,255);
|
|
||||||
|
|
||||||
//ImGuizmo.DrawCubes((.)&view, (.)&projection, (.)&transform, 1);
|
|
||||||
ImGuizmo.Manipulate((.)&view, (.)&projection, .TRANSLATE, .LOCAL, (.)&transform);
|
|
||||||
|
|
||||||
Matrix mat = .Identity;
|
|
||||||
|
|
||||||
ImGuizmo.DrawGrid((.)&view, (.)&projection, (.)&mat, 10);
|
|
||||||
|
|
||||||
transformCmp.LocalTransform = transform;
|
|
||||||
//ImGuizmo.ViewManipulate((.)&view, , .TRANSLATE, .LOCAL, (.)&transform);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.End();
|
|
||||||
|
|
||||||
if(oldViewportSize != viewportSize)
|
|
||||||
{
|
|
||||||
ViewportSizeChangedEvent.Invoke(this, *(Vector2*)&oldViewportSize);
|
|
||||||
viewPortChanged = true;
|
|
||||||
oldViewportSize = viewportSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
using GlitchyEngine.World;
|
|
||||||
using ImGui;
|
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using GlitchyEngine.Collections;
|
|
||||||
using GlitchyEditor.EditWindows;
|
|
||||||
|
|
||||||
namespace GlitchyEditor
|
|
||||||
{
|
|
||||||
class Editor
|
|
||||||
{
|
|
||||||
private EcsWorld _world;
|
|
||||||
|
|
||||||
private EntityHierarchyWindow _entityHierarchyWindow = new .(this) ~ delete _;
|
|
||||||
private ComponentEditWindow _componentEditWindow = new .(this) ~ delete _;
|
|
||||||
private SceneViewportWindow _sceneViewportWindow = new .(this) ~ delete _;
|
|
||||||
|
|
||||||
private List<Entity> _selectedEntities = new .() ~ delete _;
|
|
||||||
|
|
||||||
public EcsWorld World => _world;
|
|
||||||
|
|
||||||
public List<Entity> SelectedEntities => _selectedEntities;
|
|
||||||
|
|
||||||
public EntityHierarchyWindow EntityHierarchyWindow => _entityHierarchyWindow;
|
|
||||||
public ComponentEditWindow ComponentEditWindow => _componentEditWindow;
|
|
||||||
public SceneViewportWindow SceneViewportWindow => _sceneViewportWindow;
|
|
||||||
|
|
||||||
/// Creates a new editor for the given world
|
|
||||||
public this(EcsWorld world)
|
|
||||||
{
|
|
||||||
_world = world;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Update()
|
|
||||||
{
|
|
||||||
_entityHierarchyWindow.Show();
|
|
||||||
_componentEditWindow.Show();
|
|
||||||
_sceneViewportWindow.Show();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new entity with a transform component.
|
|
||||||
internal Entity CreateEntityWithTransform()
|
|
||||||
{
|
|
||||||
var entity = _world.NewEntity();
|
|
||||||
|
|
||||||
var transformComponent = ref *_world.AssignComponent<TransformComponent>(entity);
|
|
||||||
transformComponent = TransformComponent();
|
|
||||||
|
|
||||||
var nameComponent = ref *_world.AssignComponent<DebugNameComponent>(entity);
|
|
||||||
nameComponent.SetName("Entity");
|
|
||||||
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Returns whether or not all selected entities have the same parent.
|
|
||||||
internal bool AllSelectionsOnSameLevel()
|
|
||||||
{
|
|
||||||
Entity? parent = .InvalidEntity;
|
|
||||||
|
|
||||||
for(var selectedEntity in _selectedEntities)
|
|
||||||
{
|
|
||||||
var parentComponent = _world.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(Entity entity, List<Entity> entities)
|
|
||||||
{
|
|
||||||
for(var (child, childParent) in _world.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<Entity> entities = scope .();
|
|
||||||
|
|
||||||
for(var entity in _selectedEntities)
|
|
||||||
{
|
|
||||||
entities.Add(entity);
|
|
||||||
|
|
||||||
FindChildren(entity, entities);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(var entity in entities)
|
|
||||||
{
|
|
||||||
_world.RemoveEntity(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
_selectedEntities.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
using System;
|
|
||||||
using GlitchyEngine;
|
|
||||||
|
|
||||||
namespace GlitchyEditor
|
|
||||||
{
|
|
||||||
class EditorApp : Application
|
|
||||||
{
|
|
||||||
public this()
|
|
||||||
{
|
|
||||||
PushLayer(new EditorLayer());
|
|
||||||
}
|
|
||||||
|
|
||||||
[Export, LinkName("CreateApplication")]
|
|
||||||
public static Application CreateApplication()
|
|
||||||
{
|
|
||||||
return new EditorApp();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,208 +0,0 @@
|
|||||||
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();
|
|
||||||
DepthStencilTarget _swapchainDepthBuffer ~ _?.ReleaseRef();
|
|
||||||
|
|
||||||
BlendState _alphaBlendState ~ _?.ReleaseRef();
|
|
||||||
BlendState _opaqueBlendState ~ _?.ReleaseRef();
|
|
||||||
|
|
||||||
EcsWorld _world = new EcsWorld() ~ delete _;
|
|
||||||
|
|
||||||
Editor _editor ~ delete _;
|
|
||||||
|
|
||||||
PerspectiveCameraController _cameraController ~ delete _;
|
|
||||||
|
|
||||||
RenderTarget2D _renderTarget2D ~ _?.ReleaseRef();
|
|
||||||
|
|
||||||
public this() : base("Example")
|
|
||||||
{
|
|
||||||
Application.Get().Window.IsVSync = false;
|
|
||||||
|
|
||||||
InitGraphics();
|
|
||||||
InitEcs();
|
|
||||||
InitEditor();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InitGraphics()
|
|
||||||
{
|
|
||||||
_context = Application.Get().Window.Context..AddRef();
|
|
||||||
|
|
||||||
_swapchainDepthBuffer = new DepthStencilTarget(_context.SwapChain.Width, _context.SwapChain.Height);
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
_renderTarget2D = new RenderTarget2D(RenderTarget2DDescription(.R8G8B8A8_UNorm, 100, 100) {DepthStencilFormat = .D32_Float});
|
|
||||||
|
|
||||||
SamplerStateDescription desc = .();
|
|
||||||
|
|
||||||
SamplerState sampler = new SamplerState(desc);
|
|
||||||
|
|
||||||
_renderTarget2D.SamplerState = sampler;
|
|
||||||
|
|
||||||
sampler.ReleaseRef();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InitEcs()
|
|
||||||
{
|
|
||||||
_world.Register<DebugNameComponent>();
|
|
||||||
_world.Register<TransformComponent>();
|
|
||||||
_world.Register<ParentComponent>();
|
|
||||||
_world.Register<MeshComponent>();
|
|
||||||
_world.Register<MeshRendererComponent>();
|
|
||||||
_world.Register<SkinnedMeshRendererComponent>();
|
|
||||||
_world.Register<CameraComponent>();
|
|
||||||
_world.Register<AnimationComponent>();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InitEditor()
|
|
||||||
{
|
|
||||||
_editor = new Editor(_world);
|
|
||||||
_editor.SceneViewportWindow.ViewportSizeChangedEvent.Add(new (s, e) => ViewportSizeChanged(s, e));
|
|
||||||
|
|
||||||
_cameraController = new .(Application.Get().Window.Context.SwapChain.BackbufferViewport.Width /
|
|
||||||
Application.Get().Window.Context.SwapChain.BackbufferViewport.Height);
|
|
||||||
_cameraController.CameraPosition = .(0, 0, -5);
|
|
||||||
_cameraController.TranslationSpeed = 10;
|
|
||||||
|
|
||||||
_editor.[Friend]CreateEntityWithTransform();
|
|
||||||
|
|
||||||
_editor.SceneViewportWindow._camera = _cameraController.Camera;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Update(GameTime gameTime)
|
|
||||||
{
|
|
||||||
if(_editor.SceneViewportWindow.HasFocus && Input.IsMouseButtonPressed(.RightButton))
|
|
||||||
_cameraController.Update(gameTime);
|
|
||||||
|
|
||||||
TransformSystem.Update(_world);
|
|
||||||
|
|
||||||
RenderCommand.Clear(_renderTarget2D, .Color | .Depth, .(0.2f, 0.2f, 0.2f), 1.0f, 0);
|
|
||||||
|
|
||||||
_context.SetRenderTarget(_renderTarget2D);
|
|
||||||
_context.BindRenderTargets();
|
|
||||||
|
|
||||||
RenderCommand.SetViewport(Viewport(0, 0, _renderTarget2D.Width, _renderTarget2D.Height));
|
|
||||||
|
|
||||||
RenderCommand.SetBlendState(_opaqueBlendState);
|
|
||||||
|
|
||||||
Renderer.BeginScene(_cameraController.Camera);
|
|
||||||
|
|
||||||
DebugRenderer.Render(_world);
|
|
||||||
|
|
||||||
Renderer.EndScene();
|
|
||||||
|
|
||||||
RenderCommand.Clear(null, .(0.2f, 0.2f, 0.2f));
|
|
||||||
RenderCommand.Clear(_swapchainDepthBuffer, .Depth, 1.0f, 0);
|
|
||||||
|
|
||||||
_context.SetRenderTarget(null);
|
|
||||||
_context.SetDepthStencilTarget(_swapchainDepthBuffer);
|
|
||||||
_context.BindRenderTargets();
|
|
||||||
|
|
||||||
RenderCommand.SetViewport(_context.SwapChain.BackbufferViewport);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnEvent(Event event)
|
|
||||||
{
|
|
||||||
_cameraController.OnEvent(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.Viewport* viewport = ImGui.GetMainViewport();
|
|
||||||
ImGui.DockSpaceOverViewport(viewport);
|
|
||||||
|
|
||||||
DrawMainMenuBar();
|
|
||||||
|
|
||||||
_editor.SceneViewportWindow.RenderTarget = _renderTarget2D;
|
|
||||||
|
|
||||||
_editor.Update();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawMainMenuBar()
|
|
||||||
{
|
|
||||||
ImGui.BeginMainMenuBar();
|
|
||||||
|
|
||||||
if(ImGui.BeginMenu("File", false))
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
_swapchainDepthBuffer.ReleaseRef();
|
|
||||||
_swapchainDepthBuffer = new DepthStencilTarget(_context.SwapChain.Width, _context.SwapChain.Height);
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
_renderTarget2D.Resize(sizeX, sizeY);
|
|
||||||
|
|
||||||
_cameraController.AspectRatio = (float)sizeX / (float)sizeY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
FileVersion = 1
|
|
||||||
Dependencies = {corlib = "*", GlitchyEngine = "*"}
|
|
||||||
|
|
||||||
[Project]
|
|
||||||
Name = "GlitchyEngine.Test"
|
|
||||||
TargetType = "BeefTest"
|
|
||||||
StartupObject = "GlitchyEngine.Test.Program"
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
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"
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,199 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+15
-11
@@ -1,9 +1,22 @@
|
|||||||
FileVersion = 1
|
FileVersion = 1
|
||||||
Dependencies = {GlitchLog = "*", corlib = "*", DirectX = "*", DirectXTK = "*", FreeType = "*", cgltf-beef = "*", msdfgen-beef = "*", ImGui = "*", ImGuiImplDX11 = "*", ImGuiImplWin32 = "*", ImGuizmo = "*", Beefy2D = "*", LodePng = "*"}
|
Dependencies = {GlitchLog = "*", corlib = "*", DirectX = "*", ImGui = "*", ImGuiImplWin32 = "*", ImGuiImplDX11 = "*", DirectXTK = "*"}
|
||||||
|
|
||||||
[Project]
|
[Project]
|
||||||
Name = "GlitchyEngine"
|
Name = "GlitchyEngine"
|
||||||
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"]
|
ProcessorMacros = ["GE_ERROR_SHADER_MATRIX_MISMATCH", "GE_ERROR_SHADER_VAR_TYPE_MISMATCH"]
|
||||||
|
|
||||||
|
[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"]
|
||||||
@@ -11,17 +24,8 @@ 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 = ["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"]
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ using System;
|
|||||||
using GlitchyEngine.Events;
|
using GlitchyEngine.Events;
|
||||||
using GlitchyEngine.ImGui;
|
using GlitchyEngine.ImGui;
|
||||||
using GlitchyEngine.Renderer;
|
using GlitchyEngine.Renderer;
|
||||||
using GlitchyEngine.Debug;
|
|
||||||
|
|
||||||
namespace GlitchyEngine
|
namespace GlitchyEngine
|
||||||
{
|
{
|
||||||
@@ -12,31 +11,22 @@ namespace GlitchyEngine
|
|||||||
|
|
||||||
private Window _window ~ delete _;
|
private Window _window ~ delete _;
|
||||||
private RendererAPI _rendererApi ~ delete _;
|
private RendererAPI _rendererApi ~ delete _;
|
||||||
private EffectLibrary _effectLibrary ~ delete _;
|
|
||||||
|
|
||||||
private bool _running = true;
|
private bool _running = true;
|
||||||
private bool _isMinimized = false;
|
|
||||||
|
|
||||||
private LayerStack _layerStack = new LayerStack();
|
private LayerStack _layerStack = new LayerStack() ~ delete _;
|
||||||
|
|
||||||
private ImGuiLayer _imGuiLayer;
|
private ImGuiLayer _imGuiLayer;
|
||||||
|
|
||||||
private GameTime _gameTime = new GameTime(true);
|
private GameTime _gameTime = new GameTime(true) ~ delete _;
|
||||||
|
|
||||||
public bool IsRunning => _running;
|
public bool IsRunning => _running;
|
||||||
public Window Window => _window;
|
public Window Window => _window;
|
||||||
|
|
||||||
public EffectLibrary EffectLibrary => _effectLibrary;
|
|
||||||
|
|
||||||
public bool IsMinimized => _isMinimized;
|
|
||||||
|
|
||||||
[Inline]
|
[Inline]
|
||||||
public static Application Get() => s_Instance;
|
public static Application Get() => s_Instance;
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
@@ -46,13 +36,11 @@ namespace GlitchyEngine
|
|||||||
_rendererApi = new RendererAPI();
|
_rendererApi = new RendererAPI();
|
||||||
_rendererApi.Context = _window.Context;
|
_rendererApi.Context = _window.Context;
|
||||||
|
|
||||||
SamplerStateManager.Init();
|
SamplerStateManager.Init(_window.Context);
|
||||||
|
|
||||||
RenderCommand.RendererAPI = _rendererApi;
|
RenderCommand.RendererAPI = _rendererApi;
|
||||||
|
|
||||||
_effectLibrary = new EffectLibrary();
|
Renderer.Init(_window.Context);
|
||||||
|
|
||||||
Renderer.Init(_window.Context, _effectLibrary);
|
|
||||||
|
|
||||||
_imGuiLayer = new ImGuiLayer();
|
_imGuiLayer = new ImGuiLayer();
|
||||||
PushOverlay(_imGuiLayer);
|
PushOverlay(_imGuiLayer);
|
||||||
@@ -60,26 +48,14 @@ namespace GlitchyEngine
|
|||||||
|
|
||||||
public ~this()
|
public ~this()
|
||||||
{
|
{
|
||||||
Profiler.ProfileFunction!();
|
|
||||||
|
|
||||||
delete _layerStack;
|
|
||||||
SamplerStateManager.Uninit();
|
SamplerStateManager.Uninit();
|
||||||
Renderer.Deinit();
|
|
||||||
delete _gameTime;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnEvent(Event e)
|
public void OnEvent(Event e)
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileFunction!();
|
EventDispatcher dispatcher = scope .(e);
|
||||||
|
|
||||||
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);
|
||||||
@@ -88,89 +64,33 @@ 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)
|
|
||||||
{
|
|
||||||
_imGuiLayer.ImGuiRender();
|
_imGuiLayer.ImGuiRender();
|
||||||
|
|
||||||
_window.Context.SwapChain.Present();
|
_window.Context.SwapChain.Present();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public void PushLayer(Layer ownLayer)
|
public void PushLayer(Layer ownLayer) => _layerStack.PushLayer(ownLayer);
|
||||||
{
|
|
||||||
Profiler.ProfileFunction!();
|
|
||||||
|
|
||||||
_layerStack.PushLayer(ownLayer);
|
public void PushOverlay(Layer ownOverlay) => _layerStack.PushOverlay(ownOverlay);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,48 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,635 +0,0 @@
|
|||||||
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, Entity? parentEntity, EcsWorld world, Effect validationEffect, Material material, List<AnimationClip> clips)
|
|
||||||
{
|
|
||||||
Entity 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)
|
|
||||||
{
|
|
||||||
Entity 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
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,44 +89,4 @@ 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, WindowActivated, WindowDeactivated,
|
WindowClose, WindowResize, WindowFocus, WindowLostFocus, WindowMoved,
|
||||||
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 struct EventDispatcher
|
public class EventDispatcher
|
||||||
{
|
{
|
||||||
private Event _event;
|
private Event _event;
|
||||||
|
|
||||||
|
|||||||
@@ -1,49 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,7 +8,7 @@ namespace GlitchyEngine
|
|||||||
*/
|
*/
|
||||||
public class GameTime
|
public class GameTime
|
||||||
{
|
{
|
||||||
private Stopwatch _stopwatch;
|
private Stopwatch _stopwatch ~ delete:append _;
|
||||||
|
|
||||||
private uint64 _frameCount;
|
private uint64 _frameCount;
|
||||||
|
|
||||||
@@ -28,9 +28,6 @@ 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.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
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
|
|
||||||
}}
|
|
||||||
}}
|
|
||||||
}}
|
|
||||||
""");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
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}
|
|
||||||
{{
|
|
||||||
}}
|
|
||||||
}}
|
|
||||||
""");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
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,6 +1,4 @@
|
|||||||
using GlitchyEngine.Math;
|
using GlitchyEngine.Math;
|
||||||
using GlitchyEngine.Renderer;
|
|
||||||
|
|
||||||
namespace ImGui
|
namespace ImGui
|
||||||
{
|
{
|
||||||
extension ImGui
|
extension ImGui
|
||||||
@@ -16,12 +14,5 @@ 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);
|
|
||||||
|
|
||||||
/// Releases references that accumulated calls like ImGui::Image
|
|
||||||
protected internal static extern void CleanupFrame();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using ImGui;
|
using ImGui;
|
||||||
using GlitchyEngine.Events;
|
using GlitchyEngine.Events;
|
||||||
using ImGuizmo;
|
|
||||||
|
|
||||||
using internal ImGui;
|
|
||||||
|
|
||||||
#if GE_GRAPHICS_DX11
|
|
||||||
|
|
||||||
using GlitchyEngine.Platform.DX11;
|
|
||||||
using internal GlitchyEngine.Platform.DX11;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace GlitchyEngine.ImGui
|
namespace GlitchyEngine.ImGui
|
||||||
{
|
{
|
||||||
@@ -20,8 +10,6 @@ namespace GlitchyEngine.ImGui
|
|||||||
|
|
||||||
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...");
|
||||||
|
|
||||||
@@ -29,7 +17,7 @@ namespace GlitchyEngine.ImGui
|
|||||||
ImGui.CreateContext();
|
ImGui.CreateContext();
|
||||||
ImGui.StyleColorsDark();
|
ImGui.StyleColorsDark();
|
||||||
|
|
||||||
ImGui.IO* io = ImGui.GetIO();
|
ref ImGui.IO io = ref ImGui.GetIO();
|
||||||
io.ConfigFlags |= .NavEnableKeyboard;
|
io.ConfigFlags |= .NavEnableKeyboard;
|
||||||
io.ConfigFlags |= .DockingEnable;
|
io.ConfigFlags |= .DockingEnable;
|
||||||
io.ConfigFlags |= .ViewportsEnable;
|
io.ConfigFlags |= .ViewportsEnable;
|
||||||
@@ -39,27 +27,26 @@ namespace GlitchyEngine.ImGui
|
|||||||
//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.
|
||||||
ImGui.Style* style = ImGui.GetStyle();
|
ref ImGui.Style style = ref 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 BF_PLATFORM_WINDOWS
|
#if GE_WINDOWS
|
||||||
// Todo: temporary, needs to be platform independent
|
// Todo: temporary, needs to be platform independent
|
||||||
ImGuiImplWin32.Init((void*)(uint)(Windows.HWnd)(int)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!();
|
|
||||||
|
|
||||||
ImGuiImplDX11.Shutdown();
|
ImGuiImplDX11.Shutdown();
|
||||||
ImGuiImplWin32.Shutdown();
|
ImGuiImplWin32.Shutdown();
|
||||||
ImGui.DestroyContext();
|
ImGui.DestroyContext();
|
||||||
@@ -188,8 +175,6 @@ namespace GlitchyEngine.ImGui
|
|||||||
|
|
||||||
public void Begin()
|
public void Begin()
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileFunction!();
|
|
||||||
|
|
||||||
// Todo:
|
// Todo:
|
||||||
//var v = DirectX.ImmediateContext;
|
//var v = DirectX.ImmediateContext;
|
||||||
//v.OutputMerger.SetRenderTargets(1, &DirectX.BackBufferTarget, null);
|
//v.OutputMerger.SetRenderTargets(1, &DirectX.BackBufferTarget, null);
|
||||||
@@ -198,40 +183,30 @@ namespace GlitchyEngine.ImGui
|
|||||||
ImGuiImplDX11.NewFrame();
|
ImGuiImplDX11.NewFrame();
|
||||||
ImGuiImplWin32.NewFrame();
|
ImGuiImplWin32.NewFrame();
|
||||||
ImGui.NewFrame();
|
ImGui.NewFrame();
|
||||||
ImGuizmo.BeginFrame();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool showDemo = true;
|
bool showDemo = true;
|
||||||
public void ImGuiRender()
|
public void ImGuiRender()
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileFunction!();
|
|
||||||
|
|
||||||
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);
|
ImGui.ShowDemoWindow(&showDemo);
|
||||||
|
|
||||||
End();
|
End();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void End()
|
public void End()
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileFunction!();
|
ref ImGui.IO io = ref ImGui.GetIO();
|
||||||
|
|
||||||
ImGui.IO* io = ImGui.GetIO();
|
|
||||||
|
|
||||||
let window = Application.Get().Window;
|
let window = Application.Get().Window;
|
||||||
io.DisplaySize = .(window.Width, window.Height);
|
io.DisplaySize = .(window.Width, window.Height);
|
||||||
|
|
||||||
ImGui.Render();
|
ImGui.Render();
|
||||||
ImGuiImplDX11.RenderDrawData(ImGui.GetDrawData());
|
ImGuiImplDX11.RenderDrawData(ref ImGui.GetDrawData());
|
||||||
|
|
||||||
ImGui.CleanupFrame();
|
|
||||||
|
|
||||||
if(io.ConfigFlags.HasFlag(.ViewportsEnable))
|
if(io.ConfigFlags.HasFlag(.ViewportsEnable))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ 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);
|
||||||
@@ -38,9 +40,15 @@ 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 IsMouseButtonReleasing(MouseButton button);
|
public static extern bool IsMouseButtonReleasiong(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,7 +68,6 @@ 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,6 +29,7 @@ namespace GlitchyEngine
|
|||||||
public void PushLayer(Layer ownLayer)
|
public void PushLayer(Layer ownLayer)
|
||||||
{
|
{
|
||||||
_layers.Insert(_insertIndex++, ownLayer);
|
_layers.Insert(_insertIndex++, ownLayer);
|
||||||
|
ownLayer.OnAttach();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -39,6 +40,7 @@ namespace GlitchyEngine
|
|||||||
public void PushOverlay(Layer ownOverlay)
|
public void PushOverlay(Layer ownOverlay)
|
||||||
{
|
{
|
||||||
_layers.Add(ownOverlay);
|
_layers.Add(ownOverlay);
|
||||||
|
ownOverlay.OnAttach();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -13,12 +13,12 @@ namespace System
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Inline]
|
[Inline]
|
||||||
public Int2 XX => Int2((int32)this);
|
public Int32_2 XX => Int32_2((int32)this);
|
||||||
|
|
||||||
[Inline]
|
[Inline]
|
||||||
public Int3 XXX => Int3((int32)this);
|
public Int32_3 XXX => Int32_3((int32)this);
|
||||||
|
|
||||||
[Inline]
|
[Inline]
|
||||||
public Int4 XXXX => Int4((int32)this);
|
public Int32_4 XXXX => Int32_4((int32)this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,81 +0,0 @@
|
|||||||
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
|
|
||||||
const float RadToDeg = 180.0f / Pi;
|
|
||||||
|
|
||||||
/// Converts radians to degrees
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
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();
|
|
||||||
|
|
||||||
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,348 +0,0 @@
|
|||||||
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 q1)
|
|
||||||
{
|
|
||||||
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/
|
|
||||||
|
|
||||||
Vector3 result;
|
|
||||||
|
|
||||||
float sqw = q1.W*q1.W;
|
|
||||||
float sqx = q1.X*q1.X;
|
|
||||||
float sqy = q1.Y*q1.Y;
|
|
||||||
float sqz = q1.Z*q1.Z;
|
|
||||||
float unit = sqx + sqy + sqz + sqw; // if normalised is one, otherwise is correction factor
|
|
||||||
float test = q1.X*q1.Y + q1.Z*q1.W;
|
|
||||||
if (test > 0.499f*unit) { // singularity at north pole
|
|
||||||
result.Y = 2.0f * Math.Atan2(q1.X,q1.W);
|
|
||||||
result.Z = Math.PI_f / 2.0f;
|
|
||||||
result.X = 0.0f;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
if (test < -0.499f*unit) { // singularity at south pole
|
|
||||||
result.Y = -2.0f * Math.Atan2(q1.X,q1.W);
|
|
||||||
result.Z = -Math.PI_f / 2.0f;
|
|
||||||
result.X = 0.0f;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
result.Y = Math.Atan2(2*q1.Y*q1.W-2*q1.X*q1.Z , sqx - sqy - sqz + sqw);
|
|
||||||
result.Z = Math.Asin(2*test/unit);
|
|
||||||
result.X = Math.Atan2(2*q1.X*q1.W-2*q1.Y*q1.Z , -sqx + sqy - sqz + sqw);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -33,8 +33,7 @@ namespace GlitchyEngine.Math
|
|||||||
[Comptime]
|
[Comptime]
|
||||||
public void ApplyToType(Type type)
|
public void ApplyToType(Type type)
|
||||||
{
|
{
|
||||||
// TODO: report bug... sized array not working
|
String[4] componentNames = .("X", "Y", "Z", "W");
|
||||||
String[] componentNames = scope String[]("X", "Y", "Z", "W");
|
|
||||||
|
|
||||||
for(int swizzleCount = 2; swizzleCount <= 4; swizzleCount++)
|
for(int swizzleCount = 2; swizzleCount <= 4; swizzleCount++)
|
||||||
{
|
{
|
||||||
@@ -50,7 +49,7 @@ 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(128);
|
String setter = scope String();
|
||||||
|
|
||||||
bool setterInvalid = invalidSetter(cmp, swizzleCount);
|
bool setterInvalid = invalidSetter(cmp, swizzleCount);
|
||||||
|
|
||||||
@@ -64,7 +63,7 @@ namespace GlitchyEngine.Math
|
|||||||
}
|
}
|
||||||
swizzleConstructor.Append(componentNames[cmp[c]]);
|
swizzleConstructor.Append(componentNames[cmp[c]]);
|
||||||
|
|
||||||
if(!setterInvalid && c < _vectorSize) //
|
if(!setterInvalid && c < _vectorSize)
|
||||||
{
|
{
|
||||||
setter.AppendF($"\n\t\t{componentNames[cmp[c]]} = value.{componentNames[c]};");
|
setter.AppendF($"\n\t\t{componentNames[cmp[c]]} = value.{componentNames[c]};");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 ComponentCount = 2;
|
public const int Length = 2;
|
||||||
|
|
||||||
public float X, Y;
|
public float X, Y;
|
||||||
|
|
||||||
@@ -31,61 +31,18 @@ namespace GlitchyEngine.Math
|
|||||||
public ref float this[int index]
|
public ref float this[int index]
|
||||||
{
|
{
|
||||||
[Checked]
|
[Checked]
|
||||||
get mut
|
get
|
||||||
{
|
{
|
||||||
if(index < 0 || index >= ComponentCount)
|
if(index < 0 || index >= Length)
|
||||||
Internal.ThrowIndexOutOfRange(1);
|
Internal.ThrowIndexOutOfRange(1);
|
||||||
|
|
||||||
|
#unwarn
|
||||||
return ref (&X)[index];
|
return ref (&X)[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
[Inline]
|
[Inline]
|
||||||
get mut => ref (&X)[index];
|
#unwarn
|
||||||
}
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -133,7 +90,7 @@ namespace GlitchyEngine.Math
|
|||||||
/**
|
/**
|
||||||
* Calculates the projection of a onto b
|
* Calculates the projection of a onto b
|
||||||
*/
|
*/
|
||||||
public static Vector2 Project(Vector2 a, Vector2 b)
|
public Vector2 Project(Vector2 a, Vector2 b)
|
||||||
{
|
{
|
||||||
return (b * (Dot(a, b) / Dot(b, b)));
|
return (b * (Dot(a, b) / Dot(b, b)));
|
||||||
}
|
}
|
||||||
@@ -141,33 +98,11 @@ namespace GlitchyEngine.Math
|
|||||||
/**
|
/**
|
||||||
* Calculates the rejection of a from b
|
* Calculates the rejection of a from b
|
||||||
*/
|
*/
|
||||||
public static Vector2 Reject(Vector2 a, Vector2 b)
|
public 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
|
||||||
@@ -282,6 +217,13 @@ 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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,8 +18,6 @@ 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;
|
||||||
@@ -48,41 +46,18 @@ namespace GlitchyEngine.Math
|
|||||||
public ref float this[int index]
|
public ref float this[int index]
|
||||||
{
|
{
|
||||||
[Checked]
|
[Checked]
|
||||||
get mut
|
get
|
||||||
{
|
{
|
||||||
if(index < 0 || index >= ComponentCount)
|
if(index < 0 || index > 2)
|
||||||
Internal.ThrowIndexOutOfRange(1);
|
Internal.ThrowIndexOutOfRange();
|
||||||
|
|
||||||
|
#unwarn
|
||||||
return ref (&X)[index];
|
return ref (&X)[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
[Inline]
|
[Inline]
|
||||||
get mut => ref (&X)[index];
|
#unwarn
|
||||||
}
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -181,29 +156,6 @@ 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
|
||||||
//
|
//
|
||||||
@@ -334,6 +286,14 @@ 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,8 +12,6 @@ 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;
|
||||||
@@ -61,43 +59,17 @@ namespace GlitchyEngine.Math
|
|||||||
public ref float this[int index]
|
public ref float this[int index]
|
||||||
{
|
{
|
||||||
[Checked]
|
[Checked]
|
||||||
get mut
|
get
|
||||||
{
|
{
|
||||||
if(index < 0 || index >= ComponentCount)
|
if(index < 0 || index > 3)
|
||||||
Internal.ThrowIndexOutOfRange(1);
|
Internal.ThrowIndexOutOfRange();
|
||||||
|
#unwarn
|
||||||
return ref (&X)[index];
|
return ref (&X)[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
[Inline]
|
[Inline]
|
||||||
get mut => ref (&X)[index];
|
#unwarn
|
||||||
}
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -166,29 +138,6 @@ 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
|
||||||
//
|
//
|
||||||
@@ -318,6 +267,14 @@ 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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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, "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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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, "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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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, "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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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, "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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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, "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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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, "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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,134 +0,0 @@
|
|||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,186 +0,0 @@
|
|||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
#if GE_GRAPHICS_DX11
|
|
||||||
|
|
||||||
#if !BF_PLATFORM_WINDOWS
|
|
||||||
#error DirectX 11 (GE_GRAPHICS_DX11) can on be used on Windows.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using DirectX.Common;
|
|
||||||
using DirectX.D3D11;
|
|
||||||
using DirectX.D3D11.SDKLayers;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
protected internal static ID3D11Debug* DebugDevice;
|
|
||||||
|
|
||||||
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();
|
|
||||||
DebugDevice.AddRef();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void Dx11Release()
|
|
||||||
{
|
|
||||||
Debug.Profiler.ProfileFunction!();
|
|
||||||
|
|
||||||
NativeDevice.Release();
|
|
||||||
NativeContext.Release();
|
|
||||||
DebugDevice.ReportLiveDeviceObjects(.Detail);
|
|
||||||
DebugDevice.Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
#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,12 +1,9 @@
|
|||||||
#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]
|
||||||
@@ -33,6 +30,5 @@ 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,24 +1,22 @@
|
|||||||
#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;
|
||||||
@@ -35,11 +33,9 @@ namespace GlitchyEngine.Renderer
|
|||||||
nativeDesc.RenderTarget[i].RenderTargetWriteMask = _desc.RenderTarget[i].RenderTargetWriteMask;
|
nativeDesc.RenderTarget[i].RenderTargetWriteMask = _desc.RenderTarget[i].RenderTargetWriteMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
HResult result = NativeDevice.CreateBlendState(ref nativeDesc, &nativeBlendState);
|
HResult result = _context.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,16 +1,27 @@
|
|||||||
#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)
|
||||||
@@ -60,8 +71,6 @@ 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;
|
||||||
@@ -70,11 +79,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, Math.Min(nativeDescription.ByteWidth, byteLength));
|
Internal.MemCpy(byteData + dstByteOffset, data, byteLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
SubresourceData srData = .(byteData, byteLength, 0);
|
SubresourceData srData = .(byteData, byteLength, 0);
|
||||||
var result = NativeDevice.CreateBuffer(ref nativeDescription, &srData, &nativeBuffer);
|
var result = _context.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}");
|
||||||
@@ -86,8 +95,6 @@ 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.
|
||||||
@@ -100,14 +107,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);
|
||||||
NativeContext.UpdateSubresource(nativeBuffer, 0, &dataBox, data, byteLength, byteLength);
|
_context.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 = ?;
|
||||||
NativeContext.Map(nativeBuffer, 0, (.)mapType, .None, &map);
|
_context.nativeContext.Map(nativeBuffer, 0, (.)mapType, .None, &map);
|
||||||
Internal.MemCpy(((uint8*)map.Data) + dstByteOffset, data, byteLength);
|
Internal.MemCpy(((uint8*)map.Data) + dstByteOffset, data, byteLength);
|
||||||
NativeContext.Unmap(nativeBuffer, 0);
|
_context.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;
|
||||||
@@ -120,5 +127,3 @@ namespace GlitchyEngine.Renderer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
#if GE_GRAPHICS_DX11
|
|
||||||
|
|
||||||
using DirectX.D3D11;
|
using DirectX.D3D11;
|
||||||
|
|
||||||
using internal GlitchyEngine.Renderer;
|
using internal GlitchyEngine.Renderer;
|
||||||
@@ -12,8 +10,6 @@ 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;
|
||||||
@@ -21,5 +17,3 @@ namespace GlitchyEngine.Renderer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
#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,5 +1,3 @@
|
|||||||
#if GE_GRAPHICS_DX11
|
|
||||||
|
|
||||||
using DirectX.Common;
|
using DirectX.Common;
|
||||||
using DirectX.D3D11Shader;
|
using DirectX.D3D11Shader;
|
||||||
using System;
|
using System;
|
||||||
@@ -12,8 +10,6 @@ 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);
|
||||||
@@ -31,19 +27,14 @@ 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);
|
||||||
}
|
}
|
||||||
@@ -51,10 +42,8 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
extension ConstantBuffer
|
extension ConstantBuffer
|
||||||
{
|
{
|
||||||
internal this(ID3D11ShaderReflectionConstantBuffer* bufferReflection)
|
internal this(GraphicsContext context, ID3D11ShaderReflectionConstantBuffer* bufferReflection) : base(context)
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileResourceFunction!();
|
|
||||||
|
|
||||||
Reflect(bufferReflection);
|
Reflect(bufferReflection);
|
||||||
|
|
||||||
ConstructBuffer();
|
ConstructBuffer();
|
||||||
@@ -64,8 +53,6 @@ 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}");
|
||||||
|
|
||||||
@@ -88,5 +75,3 @@ namespace GlitchyEngine.Renderer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -1,64 +0,0 @@
|
|||||||
#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,45 +1,16 @@
|
|||||||
#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 = (.)_format;
|
desc.Format = .D32_Float;
|
||||||
desc.ArraySize = 1;
|
desc.ArraySize = 1;
|
||||||
desc.BindFlags = .DepthStencil;
|
desc.BindFlags = .DepthStencil;
|
||||||
desc.Width = _width;
|
desc.Width = _width;
|
||||||
@@ -47,13 +18,21 @@ namespace GlitchyEngine.Renderer
|
|||||||
desc.SampleDesc = .(1, 0);
|
desc.SampleDesc = .(1, 0);
|
||||||
|
|
||||||
ID3D11Texture2D* tex = ?;
|
ID3D11Texture2D* tex = ?;
|
||||||
NativeDevice.CreateTexture2D(ref desc, null, &tex);
|
_context.nativeDevice.CreateTexture2D(ref desc, null, &tex);
|
||||||
|
|
||||||
NativeDevice.CreateDepthStencilView(tex, null, &nativeView);
|
_context.nativeDevice.CreateDepthStencilView(tex, null, &nativeView);
|
||||||
|
|
||||||
tex.Release();
|
tex.Release();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public override void Bind()
|
||||||
|
{
|
||||||
|
_context.SetDepthStencilTarget(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
public override void Clear(float depthValue, uint8 stencilValue, DepthStencilClearFlag clearFlags)
|
||||||
|
{
|
||||||
|
_context.nativeContext.ClearDepthStencilView(nativeView, (.)clearFlags, depthValue, stencilValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
#if GE_GRAPHICS_DX11
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using DirectX;
|
using DirectX;
|
||||||
using DirectX.D3D11;
|
using DirectX.D3D11;
|
||||||
@@ -12,11 +10,9 @@ 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(vsPath, vsEntry);
|
VertexShader = new VertexShader(_context, vsPath, vsEntry);
|
||||||
PixelShader = new PixelShader(psPath, psEntry);
|
PixelShader = new PixelShader(_context, psPath, psEntry);
|
||||||
|
|
||||||
Reflect();
|
Reflect();
|
||||||
}
|
}
|
||||||
@@ -27,5 +23,3 @@ namespace GlitchyEngine.Renderer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -1,14 +1,10 @@
|
|||||||
#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;
|
||||||
@@ -31,8 +27,6 @@ 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;
|
||||||
@@ -46,8 +40,8 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
nativeBuffers[slot] = vertexBuffer.nativeBuffer..AddRef();
|
nativeBuffers[slot] = vertexBuffer.nativeBuffer..AddRef();
|
||||||
|
|
||||||
bufferStrides[slot] = binding.Stride;
|
bufferStrides[slot] = vertexBuffer.Binding.Stride;
|
||||||
bufferOffsets[slot] = binding.Offset;
|
bufferOffsets[slot] = vertexBuffer.Binding.Offset;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -61,16 +55,12 @@ 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.");
|
||||||
|
|
||||||
@@ -83,33 +73,32 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Bind()
|
public override void Bind(GraphicsContext context = null)
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileRendererFunction!();
|
var context;
|
||||||
|
context ??= _context;
|
||||||
|
|
||||||
NativeContext.InputAssembler.SetVertexBuffers(0, nativeBuffers.Count, &nativeBuffers, &bufferStrides, &bufferOffsets);
|
context.nativeContext.InputAssembler.SetVertexBuffers(0, nativeBuffers.Count, &nativeBuffers, &bufferStrides, &bufferOffsets);
|
||||||
NativeContext.InputAssembler.SetInputLayout(_vertexLayout.nativeLayout);
|
context.nativeContext.InputAssembler.SetInputLayout(_vertexLayout.nativeLayout);
|
||||||
NativeContext.InputAssembler.SetPrimitiveTopology((.)_primitiveTopology);
|
context.nativeContext.InputAssembler.SetPrimitiveTopology((.)_primitiveTopology);
|
||||||
|
|
||||||
if(_indexBuffer != null)
|
context.nativeContext.InputAssembler.SetIndexBuffer(_indexBuffer.nativeBuffer, _indexBuffer.Format == .Index32Bit ? .R32_UInt : .R16_UInt, _indexByteOffset);
|
||||||
NativeContext.InputAssembler.SetIndexBuffer(_indexBuffer.nativeBuffer, _indexBuffer.Format == .Index32Bit ? .R32_UInt : .R16_UInt, _indexByteOffset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Unbind()
|
public void Unbind(GraphicsContext context = null)
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileRendererFunction!();
|
var context;
|
||||||
|
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 = .();
|
||||||
|
|
||||||
NativeContext.InputAssembler.SetVertexBuffers(0, nativeBuffers.Count, &nullBuffers, &zeroStrides, &zeroOffsets);
|
context.nativeContext.InputAssembler.SetVertexBuffers(0, nativeBuffers.Count, &nullBuffers, &zeroStrides, &zeroOffsets);
|
||||||
NativeContext.InputAssembler.SetInputLayout(null);
|
context.nativeContext.InputAssembler.SetInputLayout(null);
|
||||||
NativeContext.InputAssembler.SetPrimitiveTopology(.Undefined);
|
context.nativeContext.InputAssembler.SetPrimitiveTopology(.Undefined);
|
||||||
|
|
||||||
NativeContext.InputAssembler.SetIndexBuffer(null, .R16_UNorm, 0);
|
context.nativeContext.InputAssembler.SetIndexBuffer(null, .R16_UNorm, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
#if GE_GRAPHICS_DX11
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using DirectX.Common;
|
using DirectX.Common;
|
||||||
@@ -8,11 +6,8 @@ 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 GlitchyEngine.Platform.DX11;
|
using internal GlitchyEngine.Renderer;
|
||||||
using internal GlitchyEngine.Platform.DX11;
|
|
||||||
|
|
||||||
namespace GlitchyEngine.Renderer
|
namespace GlitchyEngine.Renderer
|
||||||
{
|
{
|
||||||
@@ -23,12 +18,10 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
internal Windows.HWnd nativeWindowHandle;
|
internal Windows.HWnd nativeWindowHandle;
|
||||||
|
|
||||||
/// Gets whether or not the DX11 device is initialized.
|
internal ID3D11Device* nativeDevice;
|
||||||
//internal bool IsDx11Initialized => nativeDevice != null;
|
internal ID3D11DeviceContext* nativeContext;
|
||||||
//internal ID3D11Device* nativeDevice => NativeDevice;
|
|
||||||
//internal ID3D11DeviceContext* nativeContext => NativeContext;
|
|
||||||
|
|
||||||
//internal ID3D11Debug* debugDevice => DebugDevice;
|
private ID3D11Debug* _debugDevice;
|
||||||
|
|
||||||
public override SwapChain SwapChain => _swapChain;
|
public override SwapChain SwapChain => _swapChain;
|
||||||
|
|
||||||
@@ -38,29 +31,24 @@ 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;
|
||||||
|
|
||||||
Dx11Release();
|
nativeDevice?.Release();
|
||||||
|
nativeContext?.Release();
|
||||||
|
_debugDevice.ReportLiveDeviceObjects(.Detail);
|
||||||
|
_debugDevice?.Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Init()
|
public override void Init()
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileFunction!();
|
InitDevice();
|
||||||
|
|
||||||
Dx11Init();
|
|
||||||
|
|
||||||
SwapChain.Init();
|
SwapChain.Init();
|
||||||
}
|
}
|
||||||
@@ -68,11 +56,11 @@ namespace GlitchyEngine.Renderer
|
|||||||
/**
|
/**
|
||||||
* Initializes the Device and ImmediateContext.
|
* Initializes the Device and ImmediateContext.
|
||||||
*/
|
*/
|
||||||
/*
|
|
||||||
void InitDevice()
|
void InitDevice()
|
||||||
{
|
{
|
||||||
if(!IsDx11Initialized)
|
nativeDevice?.Release();
|
||||||
{
|
nativeContext?.Release();
|
||||||
|
|
||||||
Log.EngineLogger.Trace("Creating D3D11 Device and Context...");
|
Log.EngineLogger.Trace("Creating D3D11 Device and Context...");
|
||||||
|
|
||||||
DeviceCreationFlags deviceFlags = .None;
|
DeviceCreationFlags deviceFlags = .None;
|
||||||
@@ -84,10 +72,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);
|
||||||
Log.EngineLogger.Assert(deviceResult.Succeeded, scope $"Failed to create D3D11 Device. Message({(int32)deviceResult}): {deviceResult}");
|
Debug.Assert(deviceResult.Succeeded, scope $"Failed to create D3D11 Device. Message(0x{(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)
|
||||||
@@ -102,149 +90,104 @@ 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;
|
||||||
|
|
||||||
public override void SetDepthStencilTarget(DepthStencilTarget target)
|
internal void SetDepthStencilTarget(DepthStencilTarget target)
|
||||||
{
|
{
|
||||||
_depthStencilTarget = target?.nativeView;
|
_depthStencilTarget = target?.nativeView;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void SetRenderTarget(RenderTarget2D renderTarget, int slot, bool setDepthTarget)
|
public override void SetRenderTarget(RenderTarget renderTarget, int slot = 0)
|
||||||
{
|
{
|
||||||
_renderTargets[slot] = (renderTarget ?? _swapChain.BackBuffer)._nativeRenderTargetView;
|
if(renderTarget == null)
|
||||||
|
|
||||||
if(slot == 0 && setDepthTarget)
|
|
||||||
{
|
{
|
||||||
SetDepthStencilTarget((renderTarget ?? _swapChain.BackBuffer).DepthStencilTarget);
|
_renderTargets[slot] = _swapChain.nativeBackBufferTarget;
|
||||||
|
}
|
||||||
|
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(RenderTarget2D renderTarget, ColorRGBA color)
|
public override void ClearRenderTarget(RenderTarget renderTarget, ColorRGBA color)
|
||||||
{
|
{
|
||||||
NativeContext.ClearRenderTargetView((renderTarget ?? _swapChain.BackBuffer)._nativeRenderTargetView, color);
|
if(renderTarget == null)
|
||||||
|
{
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
BindShaderToStage(vertexShader);
|
//Todo: nativeContext.VertexShader.SetSamplers();
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
BindShaderToStage(pixelShader);
|
//Todo: nativeContext.PixelShader.SetSamplers();
|
||||||
|
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,12 +1,8 @@
|
|||||||
#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
|
||||||
{
|
{
|
||||||
@@ -16,23 +12,15 @@ 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,10 +1,6 @@
|
|||||||
#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
|
||||||
{
|
{
|
||||||
@@ -52,14 +48,12 @@ namespace GlitchyEngine.Renderer
|
|||||||
internal DirectX.D3D11.RasterizerStateDescription nativeDescription;
|
internal DirectX.D3D11.RasterizerStateDescription nativeDescription;
|
||||||
internal ID3D11RasterizerState* nativeRasterizerState ~ _?.Release();
|
internal ID3D11RasterizerState* nativeRasterizerState ~ _?.Release();
|
||||||
|
|
||||||
public override this(GlitchyEngine.Renderer.RasterizerStateDescription description)
|
public override this(GraphicsContext context, GlitchyEngine.Renderer.RasterizerStateDescription description) : this(context)
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileRendererFunction!();
|
|
||||||
|
|
||||||
_description = description;
|
_description = description;
|
||||||
nativeDescription = (.)_description;
|
nativeDescription = (.)_description;
|
||||||
|
|
||||||
var result = NativeDevice.CreateRasterizerState(ref nativeDescription, &nativeRasterizerState);
|
var result = context.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}");
|
||||||
@@ -67,5 +61,3 @@ namespace GlitchyEngine.Renderer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -1,125 +0,0 @@
|
|||||||
#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,141 +1,39 @@
|
|||||||
#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 ~ _?.ReleaseRef();
|
private GraphicsContext _context;
|
||||||
|
|
||||||
public GraphicsContext Context
|
public GraphicsContext Context
|
||||||
{
|
{
|
||||||
get => _context;
|
get => _context;
|
||||||
set => SetReference!(_context, value);
|
set => _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!();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private mixin RtOrBackbuffer(RenderTarget2D renderTarget)
|
public override void Clear(RenderTarget renderTarget, ColorRGBA clearColor)
|
||||||
{
|
{
|
||||||
renderTarget ?? _context.SwapChain.BackBuffer
|
_context.ClearRenderTarget(renderTarget, clearColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Clear(RenderTarget2D renderTarget, ColorRGBA color)
|
public override void Clear(DepthStencilTarget target, float depthValue, uint8 stencilValue, DepthStencilClearFlag clearFlags)
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileRendererFunction!();
|
_context.nativeContext.ClearDepthStencilView(target.nativeView, (.)clearFlags, depthValue, stencilValue);
|
||||||
|
|
||||||
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,11 +1,5 @@
|
|||||||
#if GE_GRAPHICS_DX11
|
|
||||||
|
|
||||||
using DirectX.Common;
|
|
||||||
using DirectX.D3D11;
|
using DirectX.D3D11;
|
||||||
using GlitchyEngine.Platform.DX11;
|
using DirectX.Common;
|
||||||
|
|
||||||
using internal GlitchyEngine.Renderer;
|
|
||||||
using internal GlitchyEngine.Platform.DX11;
|
|
||||||
|
|
||||||
namespace DirectX.D3D11
|
namespace DirectX.D3D11
|
||||||
{
|
{
|
||||||
@@ -79,6 +73,8 @@ namespace DirectX.D3D11
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using internal GlitchyEngine.Renderer;
|
||||||
|
|
||||||
namespace GlitchyEngine.Renderer
|
namespace GlitchyEngine.Renderer
|
||||||
{
|
{
|
||||||
extension SamplerStateDescription
|
extension SamplerStateDescription
|
||||||
@@ -111,21 +107,17 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
protected override void PlatformCreateSamplerState()
|
protected override void PlatformCreateSamplerState()
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileResourceFunction!();
|
|
||||||
|
|
||||||
_desc.ToNative(var nativeDesc);
|
_desc.ToNative(var nativeDesc);
|
||||||
|
|
||||||
HResult result = NativeDevice.CreateSamplerState(ref nativeDesc, &nativeSamplerState);
|
HResult result = _context.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)
|
||||||
{
|
{
|
||||||
NativeContext.VertexShader.SetSamplers(slot, 1, &nativeSamplerState);
|
_context.nativeContext.VertexShader.SetSamplers(slot, 1, &nativeSamplerState);
|
||||||
NativeContext.PixelShader.SetSamplers(slot, 1, &nativeSamplerState);
|
_context.nativeContext.PixelShader.SetSamplers(slot, 1, &nativeSamplerState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
#if GE_GRAPHICS_DX11
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using GlitchyEngine.Renderer;
|
using GlitchyEngine.Renderer;
|
||||||
using DirectX.Common;
|
using DirectX.Common;
|
||||||
@@ -18,7 +16,7 @@ namespace GlitchyEngine.Renderer
|
|||||||
*/
|
*/
|
||||||
internal ID3DBlob* nativeCode ~ _?.Release();
|
internal ID3DBlob* nativeCode ~ _?.Release();
|
||||||
|
|
||||||
protected const ShaderCompileFlags DefaultCompileFlags = .EnableStrictness |
|
protected const ShaderCompileFlags DefaultCompileFlags =
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
.Debug;
|
.Debug;
|
||||||
#else
|
#else
|
||||||
@@ -27,8 +25,6 @@ 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)
|
||||||
@@ -53,60 +49,65 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
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;
|
||||||
|
|
||||||
uint32 resourceCount = desc.BoundResources;
|
for(uint32 i < cBufferCount)
|
||||||
for (uint32 i < resourceCount)
|
|
||||||
{
|
{
|
||||||
var res = reflection.GetResourceBindingDescription(i, let bindDesc);
|
reflection.GetResourceBindingDescription(i, let bindDesc);
|
||||||
|
|
||||||
if (res.Failed)
|
var bufferReflection = reflection.GetConstantBufferByIndex(i);
|
||||||
{
|
|
||||||
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(bufferReflection);
|
let buffer = new ConstantBuffer(_context, bufferReflection);
|
||||||
|
|
||||||
_buffers.Add(bindDesc.BindPoint, buffer.Name, buffer);
|
_buffers.Add(bindDesc.BindPoint, buffer.Name, buffer);
|
||||||
|
|
||||||
buffer.ReleaseRef();
|
buffer.ReleaseRef();
|
||||||
}
|
}
|
||||||
case .Texture:
|
/*
|
||||||
_textures.Add(scope String(bindDesc.Name), bindDesc.BindPoint, null);
|
bufferReflection.GetDescription(let bufferDesc);
|
||||||
case .Sampler:
|
|
||||||
// TODO: do we have to do something for samplers?
|
// ConstantBuffer
|
||||||
default:
|
if(bufferDesc.Type == .D3D11_CT_CBUFFER)
|
||||||
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,24 +1,56 @@
|
|||||||
#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();
|
||||||
@@ -26,10 +58,9 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
public ~this()
|
public ~this()
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileFunction!();
|
|
||||||
|
|
||||||
nativeDxgiDevice?.Release();
|
nativeDxgiDevice?.Release();
|
||||||
nativeSwapChain?.Release();
|
nativeSwapChain?.Release();
|
||||||
|
nativeBackBufferTarget?.Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetResolutionFromWindow()
|
void SetResolutionFromWindow()
|
||||||
@@ -42,15 +73,11 @@ 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;
|
||||||
|
|
||||||
@@ -62,8 +89,6 @@ 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;
|
||||||
@@ -72,8 +97,7 @@ 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)
|
||||||
@@ -83,7 +107,7 @@ namespace GlitchyEngine.Renderer
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
NativeDevice.QueryInterface(out nativeDxgiDevice);
|
_context.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);
|
||||||
@@ -94,14 +118,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 | .ShaderInput;
|
swDesc.BufferUsage = .RenderTargetOutput;
|
||||||
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((.)NativeDevice, _context.nativeWindowHandle, ref swDesc, &fsSwapChainDesc, null, &nativeSwapChain);
|
var createResult = factory.CreateSwapChainForHwnd((.)_context.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}");
|
||||||
@@ -110,31 +134,19 @@ namespace GlitchyEngine.Renderer
|
|||||||
factory.Release();
|
factory.Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderTarget2DDescription desc = .(backBufferFormat, _width, _height);
|
nativeSwapChain.GetBuffer<ID3D11Texture2D>(0, let backBuffer);
|
||||||
desc.DepthStencilFormat = _depthStencilFormat;
|
|
||||||
desc.IsSwapchainTarget = true;
|
|
||||||
|
|
||||||
// Todo: perhaps just update the render target
|
RenderTargetViewDescription rtvDesc = .(backBuffer, .Texture2D, backBufferViewFormat);
|
||||||
_backBuffer = new RenderTarget2D(desc);
|
_context.nativeDevice.CreateRenderTargetView(backBuffer, &rtvDesc, &nativeBackBufferTarget);
|
||||||
|
|
||||||
_backBufferViewport = GlitchyEngine.Renderer.Viewport(0, 0, _width, _height, 0.0f, 1.0f);
|
_backBufferViewport = GlitchyEngine.Renderer.Viewport(0, 0, _width, _height, 0.0f, 1.0f);
|
||||||
}
|
|
||||||
|
|
||||||
internal void GetBackbuffer(out ID3D11Texture2D* texture)
|
backBuffer.Release();
|
||||||
{
|
|
||||||
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,58 +1,22 @@
|
|||||||
#if GE_GRAPHICS_DX11
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using DirectX.D3D11;
|
using DirectX.D3D11;
|
||||||
using DirectX.Common;
|
using DirectX.Common;
|
||||||
using DirectXTK;
|
using DirectXTK;
|
||||||
using GlitchyEngine.Math;
|
|
||||||
using System.Collections;
|
|
||||||
|
|
||||||
using internal GlitchyEngine.Renderer;
|
using internal GlitchyEngine.Renderer;
|
||||||
|
|
||||||
typealias NativeTex2DDesc = DirectX.D3D11.Texture2DDescription;
|
typealias NativeTex2DDesc = DirectX.D3D11.Texture2DDescription;
|
||||||
|
|
||||||
using GlitchyEngine.Platform.DX11;
|
|
||||||
using internal GlitchyEngine.Platform.DX11;
|
|
||||||
|
|
||||||
namespace GlitchyEngine.Renderer
|
namespace GlitchyEngine.Renderer
|
||||||
{
|
{
|
||||||
extension Texture
|
extension Texture
|
||||||
{
|
{
|
||||||
protected internal ID3D11ShaderResourceView* nativeResourceView ~ _?.Release();
|
protected internal ID3D11ShaderResourceView* nativeView ~ _?.Release();
|
||||||
|
|
||||||
protected override void ImplBind(uint32 slot)
|
protected override void ImplBind(uint32 slot)
|
||||||
{
|
{
|
||||||
// TODO: textures don't bind themselves!
|
_context.nativeContext.VertexShader.SetShaderResources(slot, 1, &nativeView);
|
||||||
NativeContext.VertexShader.SetShaderResources(slot, 1, &nativeResourceView);
|
_context.nativeContext.PixelShader.SetShaderResources(slot, 1, &nativeView);
|
||||||
NativeContext.PixelShader.SetShaderResources(slot, 1, &nativeResourceView);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \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 LoadResourcePlatform<T>(StringView path, ref T* texture) where T : ID3D11Resource
|
|
||||||
{
|
|
||||||
Debug.Profiler.ProfileResourceFunction!();
|
|
||||||
|
|
||||||
((ID3D11Resource*)texture)?.Release();
|
|
||||||
nativeResourceView?.Release();
|
|
||||||
|
|
||||||
HResult loadResult = DDSTextureLoader.CreateDDSTextureFromFile(NativeDevice, path.ToScopedNativeWChar!(),
|
|
||||||
(.)&texture, &nativeResourceView);
|
|
||||||
|
|
||||||
if(loadResult.Failed)
|
|
||||||
{
|
|
||||||
Log.EngineLogger.Error($"Failed to load texture \"{path}\". Error({(int)loadResult}): {loadResult}");
|
|
||||||
|
|
||||||
ReleaseAndNullify!(texture);
|
|
||||||
ReleaseAndNullify!(nativeResourceView);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,16 +34,15 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
// TODO: missing options
|
// TODO: missing options
|
||||||
desc.SampleDesc = .(1, 0);
|
desc.SampleDesc = .(1, 0);
|
||||||
desc.Usage = (.)Usage;
|
desc.Usage = .Immutable;
|
||||||
desc.BindFlags = .ShaderResource;
|
desc.BindFlags = .ShaderResource;
|
||||||
|
desc.CpuAccessFlags = .None;
|
||||||
desc.CpuAccessFlags = (.)CpuAccess;
|
|
||||||
desc.MiscFlags = .None;
|
desc.MiscFlags = .None;
|
||||||
|
|
||||||
return desc;
|
return desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static explicit operator NativeTex2DDesc(Self desc) => desc.ToNative();
|
public static implicit operator NativeTex2DDesc(Self desc) => desc.ToNative();
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Texture2D
|
extension Texture2D
|
||||||
@@ -94,9 +57,21 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
protected override void LoadTexturePlatform()
|
protected override void LoadTexturePlatform()
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileResourceFunction!();
|
nativeTexture?.Release();
|
||||||
|
nativeView?.Release();
|
||||||
|
|
||||||
LoadResourcePlatform(_path, ref nativeTexture);
|
HResult loadResult = DDSTextureLoader.CreateDDSTextureFromFile(_context.nativeDevice, _path.ToScopedNativeWChar!(),
|
||||||
|
(.)&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}).");
|
||||||
@@ -104,156 +79,22 @@ namespace GlitchyEngine.Renderer
|
|||||||
nativeTexture.GetDescription(out nativeDesc);
|
nativeTexture.GetDescription(out nativeDesc);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void CreateTexturePlatform(Texture2DDesc desc, bool isRenderTarget, void* data, uint32 linePitch)
|
protected override void CreateTexturePlatform(Texture2DDesc desc, void* data, uint32 linePitch)
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileResourceFunction!();
|
nativeTexture?.Release();
|
||||||
|
nativeView?.Release();
|
||||||
|
|
||||||
PrepareTexturePlatform(desc, isRenderTarget);
|
nativeDesc = desc;
|
||||||
InternalCreateTexture(data, linePitch, 0);
|
SubresourceData resData = .(data, linePitch, 0);
|
||||||
}
|
|
||||||
|
|
||||||
private void InternalCreateTexture(void* data, uint32 linePitch, uint32 slicePitch)
|
var result = _context.[Friend]nativeDevice.CreateTexture2D(ref nativeDesc, &resData, &nativeTexture);
|
||||||
{
|
|
||||||
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 = NativeDevice.CreateShaderResourceView(nativeTexture, null, &nativeResourceView);
|
result = _context.[Friend]nativeDevice.CreateShaderResourceView(nativeTexture, null, &nativeView);
|
||||||
|
|
||||||
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
|
||||||
@@ -268,9 +109,21 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
protected override void LoadTexturePlatform()
|
protected override void LoadTexturePlatform()
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileResourceFunction!();
|
nativeTexture?.Release();
|
||||||
|
nativeView?.Release();
|
||||||
|
|
||||||
LoadResourcePlatform(_path, ref nativeTexture);
|
HResult loadResult = DDSTextureLoader.CreateDDSTextureFromFile(_context.nativeDevice, _path.ToScopedNativeWChar!(),
|
||||||
|
(.)&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}).");
|
||||||
@@ -282,5 +135,3 @@ namespace GlitchyEngine.Renderer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
#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
|
||||||
{
|
{
|
||||||
@@ -17,12 +13,12 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
public ID3DBlob* nativeShaderCode ~ _?.Release();
|
public ID3DBlob* nativeShaderCode ~ _?.Release();
|
||||||
|
|
||||||
public this(VertexElement[] elements, bool ownsElements, VertexShader vertexShader)
|
public this(GraphicsContext context, VertexElement[] elements, VertexShader vertexShader)
|
||||||
{
|
{
|
||||||
nativeShaderCode = vertexShader.nativeCode..AddRef();
|
nativeShaderCode = vertexShader.nativeCode..AddRef();
|
||||||
|
|
||||||
|
_context = context..AddRef();
|
||||||
_elements = elements;
|
_elements = elements;
|
||||||
_ownsElements = ownsElements;
|
|
||||||
|
|
||||||
CreateNativeLayout();
|
CreateNativeLayout();
|
||||||
}
|
}
|
||||||
@@ -32,18 +28,16 @@ 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, input[i].InstanceDataStepRate);
|
output[i] = .(input[i].SemanticName, input[i].SemanticIndex, input[i].Format, input[i].InputSlot, input[i].AlignedByteOffset, (.)input[i].InputSlotClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
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 = NativeDevice.CreateInputLayout(nativeElements.CArray(), (.)nativeElements.Count, nativeShaderCode.GetBufferPointer(), nativeShaderCode.GetBufferSize(), &nativeLayout);
|
var result = _context.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}");
|
||||||
@@ -51,5 +45,3 @@ namespace GlitchyEngine.Renderer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
#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
|
||||||
{
|
{
|
||||||
@@ -17,23 +14,15 @@ 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
|
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
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,5 +1,3 @@
|
|||||||
#if BF_PLATFORM_WINDOWS
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using GlitchyEngine.Events;
|
using GlitchyEngine.Events;
|
||||||
using DirectX.Windows.VirtualKeyCodes;
|
using DirectX.Windows.VirtualKeyCodes;
|
||||||
@@ -9,21 +7,39 @@ 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[2] IputStates;
|
static WindowsInputState* CurrentState = new WindowsInputState() ~ delete _;
|
||||||
|
static WindowsInputState* LastState = new WindowsInputState() ~ delete _;
|
||||||
static WindowsInputState* CurrentState = &IputStates[0];
|
|
||||||
static WindowsInputState* LastState = &IputStates[1];
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Current Keyboard state
|
// Current Keyboard state
|
||||||
@@ -51,13 +67,13 @@ namespace GlitchyEngine
|
|||||||
//
|
//
|
||||||
public override static bool WasKeyPressed(Key keycode)
|
public override static bool WasKeyPressed(Key keycode)
|
||||||
{
|
{
|
||||||
int8 state = LastState.KeyStates[(int)keycode];
|
int8 state = CurrentState.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 = LastState.KeyStates[(int)keycode];
|
int8 state = CurrentState.KeyStates[(int)keycode];
|
||||||
return state >= 0;
|
return state >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,10 +166,24 @@ 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 IsMouseButtonReleasing(MouseButton button) => IsMouseButtonReleased(button) && WasMouseButtonPressed(button);
|
public override static bool IsMouseButtonReleasiong(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)]
|
||||||
@@ -161,11 +191,14 @@ 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()
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileFunction!();
|
// Switch last and current states
|
||||||
|
var buffer = LastState;
|
||||||
Swap!(CurrentState, LastState);
|
LastState = CurrentState;
|
||||||
|
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)
|
||||||
@@ -192,8 +225,9 @@ 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
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,48 +0,0 @@
|
|||||||
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,5 +1,4 @@
|
|||||||
#if BF_PLATFORM_WINDOWS
|
#if GE_WINDOWS
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using DirectX.Common;
|
using DirectX.Common;
|
||||||
using DirectX.Windows;
|
using DirectX.Windows;
|
||||||
@@ -10,10 +9,9 @@ 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
|
||||||
@@ -34,8 +32,6 @@ 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;
|
||||||
@@ -154,14 +150,10 @@ 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;
|
||||||
|
|
||||||
@@ -176,8 +168,6 @@ namespace GlitchyEngine
|
|||||||
|
|
||||||
public ~this()
|
public ~this()
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileFunction!();
|
|
||||||
|
|
||||||
if(!DestroyWindow(_windowHandle))
|
if(!DestroyWindow(_windowHandle))
|
||||||
{
|
{
|
||||||
HResult res = (.)GetLastError();
|
HResult res = (.)GetLastError();
|
||||||
@@ -187,13 +177,8 @@ 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);
|
||||||
@@ -204,11 +189,7 @@ 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;
|
||||||
|
|
||||||
@@ -223,12 +204,8 @@ 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();
|
||||||
@@ -240,8 +217,40 @@ namespace GlitchyEngine
|
|||||||
|
|
||||||
Log.EngineLogger.Trace($"Created window \"{Title}\" ({Width}, {Height})");
|
Log.EngineLogger.Trace($"Created window \"{Title}\" ({Width}, {Height})");
|
||||||
|
|
||||||
// Determine whether or not the window is currently active
|
if(Input.RawInput)
|
||||||
_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;
|
||||||
@@ -250,18 +259,6 @@ 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);
|
||||||
@@ -290,22 +287,27 @@ namespace GlitchyEngine
|
|||||||
// Window size changed
|
// Window size changed
|
||||||
case WM_SIZE:
|
case WM_SIZE:
|
||||||
{
|
{
|
||||||
window._isMinimized = wParam == (.)ResizingType.Minimized;
|
if (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:
|
||||||
{
|
{
|
||||||
@@ -339,39 +341,18 @@ 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, WM_SYSKEYDOWN:
|
case WM_KEYDOWN:
|
||||||
{
|
{
|
||||||
Key key = WindowMessageToKey(wParam, lParam);
|
var event = scope KeyPressedEvent((Key)wParam, (int32)lParam & 0xFFFF);
|
||||||
var event = scope KeyPressedEvent(key, (int32)lParam & 0xFFFF);
|
|
||||||
window._eventCallback(event);
|
window._eventCallback(event);
|
||||||
}
|
}
|
||||||
case WM_KEYUP, WM_SYSKEYUP:
|
case WM_KEYUP:
|
||||||
{
|
{
|
||||||
Key key = WindowMessageToKey(wParam, lParam);
|
var event = scope KeyReleasedEvent((Key)wParam);
|
||||||
var event = scope KeyReleasedEvent(key);
|
|
||||||
window._eventCallback(event);
|
window._eventCallback(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -493,38 +474,130 @@ 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)
|
|
||||||
{
|
{
|
||||||
Key key = Key.FromWindowsKeyCode((.)wParam);
|
LeftDown = 0x0001,
|
||||||
|
LeftUp = 0x0002,
|
||||||
var scancode = (lParam & 0x00ff0000) >> 16;
|
MiddleDown = 0x0010,
|
||||||
bool isExtended = (lParam & 0x01000000) > 0;
|
MiddleUp = 0x0020,
|
||||||
|
RightDown = 0x0004,
|
||||||
switch(key)
|
RightUp = 0x0008,
|
||||||
{
|
XButton1Down = 0x0040,
|
||||||
case .Shift:
|
XButton1Up = 0x0080,
|
||||||
return Key.FromWindowsKeyCode((.)MapVirtualKeyW((.)scancode, MAPVK_VSC_TO_VK_EX));
|
XButton2Down = 0x0100,
|
||||||
case .Control:
|
XButton2Up = 0x0200,
|
||||||
return isExtended ? .RightControl : .LeftControl;
|
MouseWheel = 0x0400,
|
||||||
case .Alt:
|
MouseHWheel = 0x0800
|
||||||
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))
|
||||||
{
|
{
|
||||||
@@ -568,5 +641,4 @@ namespace GlitchyEngine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using GlitchLog;
|
using GlitchLog;
|
||||||
using GlitchyEngine.Debug;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace GlitchyEngine
|
namespace GlitchyEngine
|
||||||
@@ -12,37 +11,24 @@ 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();
|
||||||
|
|
||||||
app = CreateApplication();
|
var 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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,279 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
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,7 +1,5 @@
|
|||||||
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
|
||||||
@@ -72,25 +70,23 @@ 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 : RefCounter
|
public class BlendState : RefCounted
|
||||||
{
|
{
|
||||||
|
protected GraphicsContext _context ~ _?.ReleaseRef();
|
||||||
|
|
||||||
protected BlendStateDescription _desc;
|
protected BlendStateDescription _desc;
|
||||||
|
|
||||||
public BlendStateDescription Description => _desc;
|
public BlendStateDescription Description => _desc;
|
||||||
|
|
||||||
public this(BlendStateDescription desc)
|
public this(GraphicsContext context, BlendStateDescription desc)
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileResourceFunction!();
|
_context = context..AddRef();
|
||||||
|
|
||||||
_desc = desc;
|
_desc = desc;
|
||||||
|
|
||||||
PlatformCreateBlendState();
|
PlatformCreateBlendState();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ~this()
|
public extern void Bind(ColorRGBA blendFactor = .White);
|
||||||
{
|
|
||||||
Debug.Profiler.ProfileResourceFunction!();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected extern void PlatformCreateBlendState();
|
protected extern void PlatformCreateBlendState();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,47 @@
|
|||||||
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.
|
||||||
*/
|
*/
|
||||||
@@ -81,19 +120,26 @@ namespace GlitchyEngine.Renderer
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Represents a buffer containing binary data on the GPU.
|
/// Represents a buffer containing binary data on the GPU.
|
||||||
public class Buffer : RefCounter
|
public class Buffer : RefCounted
|
||||||
{
|
{
|
||||||
|
internal GraphicsContext _context ~ _?.ReleaseRef();
|
||||||
|
|
||||||
protected BufferDescription _description;
|
protected BufferDescription _description;
|
||||||
|
|
||||||
|
public GraphicsContext Context => _context;
|
||||||
|
|
||||||
public BufferDescription Description => _description;
|
public BufferDescription Description => _description;
|
||||||
|
|
||||||
protected this() { }
|
protected this(GraphicsContext context)
|
||||||
|
{
|
||||||
|
_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(BufferDescription description)
|
public this(GraphicsContext context, BufferDescription description) : this(context)
|
||||||
{
|
{
|
||||||
_description = description;
|
_description = description;
|
||||||
}
|
}
|
||||||
@@ -155,9 +201,10 @@ 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(BufferDescription description)
|
public this(GraphicsContext context, BufferDescription description) : base(context)
|
||||||
{
|
{
|
||||||
_description = description;
|
_description = description;
|
||||||
_description.Size = (uint32)sizeof(T);
|
_description.Size = (uint32)sizeof(T);
|
||||||
|
|||||||
@@ -15,8 +15,6 @@ namespace GlitchyEngine.Renderer
|
|||||||
[AllowAppend]
|
[AllowAppend]
|
||||||
public this()
|
public this()
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileResourceFunction!();
|
|
||||||
|
|
||||||
// Todo: append allocate as soon as it's fixed
|
// Todo: append allocate as soon as it's fixed
|
||||||
let buffers = new List<BufferEntry>();
|
let buffers = new List<BufferEntry>();
|
||||||
let strToBuf = new Dictionary<String, BufferEntry*>();
|
let strToBuf = new Dictionary<String, BufferEntry*>();
|
||||||
@@ -27,11 +25,6 @@ namespace GlitchyEngine.Renderer
|
|||||||
_idxToBuf = idxToBuf;
|
_idxToBuf = idxToBuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ~this()
|
|
||||||
{
|
|
||||||
Debug.Profiler.ProfileResourceFunction!();
|
|
||||||
}
|
|
||||||
|
|
||||||
mixin DeleteBufferEntries(List<BufferEntry> entries)
|
mixin DeleteBufferEntries(List<BufferEntry> entries)
|
||||||
{
|
{
|
||||||
if(entries == null)
|
if(entries == null)
|
||||||
@@ -61,8 +54,6 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
public BufferEntry* TryGetBufferEntry(String name)
|
public BufferEntry* TryGetBufferEntry(String name)
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileResourceFunction!();
|
|
||||||
|
|
||||||
if(_strToBuf.TryGetValue(name, let buffer))
|
if(_strToBuf.TryGetValue(name, let buffer))
|
||||||
{
|
{
|
||||||
return buffer;
|
return buffer;
|
||||||
@@ -73,8 +64,6 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
public BufferEntry* TryGetBufferEntry(int index)
|
public BufferEntry* TryGetBufferEntry(int index)
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileResourceFunction!();
|
|
||||||
|
|
||||||
if(_idxToBuf.TryGetValue(index, let buffer))
|
if(_idxToBuf.TryGetValue(index, let buffer))
|
||||||
{
|
{
|
||||||
return buffer;
|
return buffer;
|
||||||
@@ -91,8 +80,6 @@ namespace GlitchyEngine.Renderer
|
|||||||
*/
|
*/
|
||||||
public bool TryReplaceBuffer(int idx, Buffer buffer)
|
public bool TryReplaceBuffer(int idx, Buffer buffer)
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileResourceFunction!();
|
|
||||||
|
|
||||||
if(_idxToBuf.TryGetValue(idx, let bufferEntry))
|
if(_idxToBuf.TryGetValue(idx, let bufferEntry))
|
||||||
{
|
{
|
||||||
Log.EngineLogger.Assert(idx == bufferEntry.Index);
|
Log.EngineLogger.Assert(idx == bufferEntry.Index);
|
||||||
@@ -118,8 +105,6 @@ namespace GlitchyEngine.Renderer
|
|||||||
*/
|
*/
|
||||||
public bool TryReplaceBuffer(String name, Buffer buffer)
|
public bool TryReplaceBuffer(String name, Buffer buffer)
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileResourceFunction!();
|
|
||||||
|
|
||||||
if(_strToBuf.TryGetValue(name, let bufferEntry))
|
if(_strToBuf.TryGetValue(name, let bufferEntry))
|
||||||
{
|
{
|
||||||
Log.EngineLogger.AssertDebug(name == bufferEntry.Name);
|
Log.EngineLogger.AssertDebug(name == bufferEntry.Name);
|
||||||
@@ -144,8 +129,6 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
public void Add(BufferEntry entry)
|
public void Add(BufferEntry entry)
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileResourceFunction!();
|
|
||||||
|
|
||||||
BufferEntry copy = (new String(entry.Name), entry.Index, entry.Buffer..AddRef());
|
BufferEntry copy = (new String(entry.Name), entry.Index, entry.Buffer..AddRef());
|
||||||
|
|
||||||
_buffers.Add(copy);
|
_buffers.Add(copy);
|
||||||
@@ -163,8 +146,6 @@ namespace GlitchyEngine.Renderer
|
|||||||
*/
|
*/
|
||||||
int GetIndexOfBuffer(Buffer buffer)
|
int GetIndexOfBuffer(Buffer buffer)
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileResourceFunction!();
|
|
||||||
|
|
||||||
for(int i < _buffers.Count)
|
for(int i < _buffers.Count)
|
||||||
{
|
{
|
||||||
// Only check for reference equality.
|
// Only check for reference equality.
|
||||||
@@ -184,8 +165,6 @@ namespace GlitchyEngine.Renderer
|
|||||||
*/
|
*/
|
||||||
String GetNameOfBuffer(Buffer buffer)
|
String GetNameOfBuffer(Buffer buffer)
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileResourceFunction!();
|
|
||||||
|
|
||||||
for(int i < _buffers.Count)
|
for(int i < _buffers.Count)
|
||||||
{
|
{
|
||||||
// Only check for reference equality.
|
// Only check for reference equality.
|
||||||
|
|||||||
@@ -12,12 +12,10 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
private ShaderVariableType _type;
|
private ShaderVariableType _type;
|
||||||
|
|
||||||
internal uint32 _columns;
|
private uint32 _columns;
|
||||||
internal uint32 _rows;
|
private uint32 _rows;
|
||||||
private uint32 _offset;
|
private uint32 _offset;
|
||||||
internal uint32 _sizeInBytes;
|
private uint32 _sizeInBytes;
|
||||||
// Number of elements in the array
|
|
||||||
internal uint32 _elements;
|
|
||||||
|
|
||||||
private bool _isUsed;
|
private bool _isUsed;
|
||||||
|
|
||||||
@@ -27,15 +25,13 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
public String Name => _name;
|
public String Name => _name;
|
||||||
|
|
||||||
public bool IsUsed => _isUsed;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a pointer to the start of the variable in the constant buffers backing data.
|
* Gets a pointer to the start of the variable in the constant buffers backing data.
|
||||||
*/
|
*/
|
||||||
[Inline]
|
[Inline]
|
||||||
internal uint8* firstByte => _constantBuffer.rawData.CArray() + _offset;
|
internal uint8* firstByte => _constantBuffer.rawData.CArray() + _offset;
|
||||||
|
|
||||||
public this(ConstantBuffer constantBuffer, ShaderVariableType type, uint32 columns, uint32 rows, uint32 offset, uint32 sizeInBytes, uint32 elements, bool isUsed)
|
public this(ConstantBuffer constantBuffer, ShaderVariableType type, uint32 columns, uint32 rows, uint32 offset, uint32 sizeInBytes, bool isUsed)
|
||||||
{
|
{
|
||||||
_constantBuffer = constantBuffer..AddRef();
|
_constantBuffer = constantBuffer..AddRef();
|
||||||
_type = type;
|
_type = type;
|
||||||
@@ -43,140 +39,97 @@ namespace GlitchyEngine.Renderer
|
|||||||
_rows = rows;
|
_rows = rows;
|
||||||
_offset = offset;
|
_offset = offset;
|
||||||
_sizeInBytes = sizeInBytes;
|
_sizeInBytes = sizeInBytes;
|
||||||
_elements = elements;
|
|
||||||
_isUsed = isUsed;
|
_isUsed = isUsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void EnsureTypeMatch(int rows, int cols, ShaderVariableType type)
|
public void EnsureTypeMatch(int rows, int cols, ShaderVariableType type)
|
||||||
{
|
{
|
||||||
#if GE_SHADER_MATRIX_MISMATCH_IS_ERROR
|
#if GE_ERROR_SHADER_MATRIX_MISMATCH
|
||||||
Log.EngineLogger.Assert(rows == _rows || cols == _columns, scope $"The matrix-dimensions do not match: Expected {_rows} rows and {_rows} columns but Received {rows} rows and {cols} columns instead. Variable: \"{_name}\" of buffer: \"{_constantBuffer.Name}\"");
|
Log.EngineLogger.Assert(rows == _rows || cols == _columns, scope $"The matrix-dimensions do not match: Expected {_rows} rows and {_rows} columns but Received {rows} rows and {cols} columns instead. Variable: \"{_name}\" of buffer: \"{_constantBuffer.Name}\"");
|
||||||
#elif GE_SHADER_MATRIX_MISMATCH_IS_WARNING
|
#elif GE_WARN_SHADER_MATRIX_MISMATCH
|
||||||
if (rows != _rows || cols != _columns)
|
if (rows != _rows || cols != _columns)
|
||||||
Log.EngineLogger.Warning($"The matrix-dimensions do not match: Expected {_rows} rows and {_rows} columns but Received {rows} rows and {cols} columns instead. Variable: \"{_name}\" of buffer: \"{_constantBuffer.Name}\"");
|
Log.EngineLogger.Warning($"The matrix-dimensions do not match: Expected {_rows} rows and {_rows} columns but Received {rows} rows and {cols} columns instead. Variable: \"{_name}\" of buffer: \"{_constantBuffer.Name}\"");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if GE_SHADER_VAR_TYPE_MISMATCH_IS_ERROR
|
#if GE_ERROR_SHADER_VAR_TYPE_MISMATCH
|
||||||
Log.EngineLogger.Assert(type == _type, scope $"The types do not match: Expected \"{_type}\" but Received \"{type}\" instead. Variable: \"{_name}\" of buffer: \"{_constantBuffer.Name}\"");
|
Log.EngineLogger.Assert(type == _type, scope $"The types do not match: Expected \"{_type}\" but Received \"{type}\" instead. Variable: \"{_name}\" of buffer: \"{_constantBuffer.Name}\"");
|
||||||
#elif GE_SHADER_VAR_TYPE_MISMATCH_IS_WARNING
|
#elif GE_WARN_SHADER_VAR_TYPE_MISMATCH
|
||||||
if (type != _type)
|
if (type != _type)
|
||||||
Log.EngineLogger.Warning($"The types do not match: Expected \"{_type}\" but Received \"{type}\" instead. Variable: \"{_name}\" of buffer: \"{_constantBuffer.Name}\"");
|
Log.EngineLogger.Warning($"The types do not match: Expected \"{_type}\" but Received \"{type}\" instead. Variable: \"{_name}\" of buffer: \"{_constantBuffer.Name}\"");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public void EnsureTypeMatch<T>()
|
public void SetData(float value)
|
||||||
{
|
{
|
||||||
switch(typeof(T))
|
|
||||||
{
|
|
||||||
case typeof(bool):
|
|
||||||
EnsureTypeMatch(1, 1, .Bool);
|
|
||||||
|
|
||||||
case typeof(float):
|
|
||||||
EnsureTypeMatch(1, 1, .Float);
|
EnsureTypeMatch(1, 1, .Float);
|
||||||
case typeof(Vector2):
|
|
||||||
|
*(float*)firstByte = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetData(Vector2 value)
|
||||||
|
{
|
||||||
EnsureTypeMatch(1, 2, .Float);
|
EnsureTypeMatch(1, 2, .Float);
|
||||||
case typeof(Vector3):
|
|
||||||
|
*(Vector2*)firstByte = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetData(Vector3 value)
|
||||||
|
{
|
||||||
EnsureTypeMatch(1, 3, .Float);
|
EnsureTypeMatch(1, 3, .Float);
|
||||||
case typeof(Vector4):
|
|
||||||
|
*(Vector3*)firstByte = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetData(Vector4 value)
|
||||||
|
{
|
||||||
EnsureTypeMatch(1, 4, .Float);
|
EnsureTypeMatch(1, 4, .Float);
|
||||||
|
|
||||||
case typeof(int32):
|
*(Vector4*)firstByte = value;
|
||||||
EnsureTypeMatch(1, 1, .Int);
|
}
|
||||||
case typeof(Int2):
|
|
||||||
EnsureTypeMatch(1, 2, .Int);
|
|
||||||
case typeof(Int3):
|
|
||||||
EnsureTypeMatch(1, 3, .Int);
|
|
||||||
case typeof(Int4):
|
|
||||||
EnsureTypeMatch(1, 4, .Int);
|
|
||||||
|
|
||||||
case typeof(Matrix4x3):
|
public void SetData(Matrix4x3 value)
|
||||||
|
{
|
||||||
|
// I think this is right
|
||||||
EnsureTypeMatch(4, 3, .Float);
|
EnsureTypeMatch(4, 3, .Float);
|
||||||
case typeof(Matrix3x3):
|
|
||||||
EnsureTypeMatch(3, 3, .Float);
|
|
||||||
case typeof(Matrix):
|
|
||||||
EnsureTypeMatch(4, 4, .Float);
|
|
||||||
|
|
||||||
case typeof(ColorRGB):
|
*(Matrix4x3*)firstByte = value;
|
||||||
EnsureTypeMatch(1, 3, .Float);
|
|
||||||
case typeof(ColorRGBA):
|
|
||||||
EnsureTypeMatch(1, 4, .Float);
|
|
||||||
case typeof(Color):
|
|
||||||
EnsureTypeMatch(1, 4, .Float);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Inline]
|
|
||||||
private void SetData<T>(T value)
|
|
||||||
{
|
|
||||||
EnsureTypeMatch<T>();
|
|
||||||
|
|
||||||
*(T*)firstByte = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Inline]
|
|
||||||
private T GetData<T>()
|
|
||||||
{
|
|
||||||
return *(T*)firstByte;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetData(bool value) => SetData<bool>(value);
|
|
||||||
|
|
||||||
public void SetData(float value) => SetData<float>(value);
|
|
||||||
public void SetData(Vector2 value) => SetData<Vector2>(value);
|
|
||||||
public void SetData(Vector3 value) => SetData<Vector3>(value);
|
|
||||||
public void SetData(Vector4 value) => SetData<Vector4>(value);
|
|
||||||
|
|
||||||
public void SetData(int32 value) => SetData<int32>(value);
|
|
||||||
public void SetData(Int2 value) => SetData<Int2>(value);
|
|
||||||
public void SetData(Int3 value) => SetData<Int3>(value);
|
|
||||||
public void SetData(Int4 value) => SetData<Int4>(value);
|
|
||||||
|
|
||||||
public void SetData(ColorRGB value) => SetData<ColorRGB>(value);
|
|
||||||
public void SetData(ColorRGBA value) => SetData<ColorRGBA>(value);
|
|
||||||
public void SetData(Color value) => SetData<ColorRGBA>((ColorRGBA)value);
|
|
||||||
|
|
||||||
|
|
||||||
public void SetData(Matrix4x3 value) => SetData<Matrix4x3>(value);
|
|
||||||
|
|
||||||
public void SetData(Matrix4x3[] value)
|
|
||||||
{
|
|
||||||
EnsureTypeMatch<Matrix4x3>();
|
|
||||||
|
|
||||||
// TODO: assert length
|
|
||||||
|
|
||||||
Internal.MemCpy(firstByte, value.Ptr, sizeof(Matrix4x3) * Math.Min(value.Count, _elements));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(Matrix3x3 value)
|
public void SetData(Matrix3x3 value)
|
||||||
{
|
{
|
||||||
EnsureTypeMatch<Matrix3x3>();
|
EnsureTypeMatch(3, 3, .Float);
|
||||||
|
|
||||||
*(Matrix4x3*)firstByte = Matrix4x3(value);
|
*(Matrix4x3*)firstByte = Matrix4x3(value);
|
||||||
|
|
||||||
// Todo: maybe manual copy
|
// Todo: maybe manual copy
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(Matrix3x3[] value)
|
public void SetData(Matrix value)
|
||||||
{
|
{
|
||||||
EnsureTypeMatch<Matrix3x3>();
|
EnsureTypeMatch(4, 4, .Float);
|
||||||
|
|
||||||
// TODO: assert length
|
*(Matrix*)firstByte = value;
|
||||||
|
|
||||||
for(int i < Math.Min(value.Count, _elements))
|
|
||||||
{
|
|
||||||
((Matrix4x3*)firstByte)[i] = Matrix4x3(value[i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(Matrix value) => SetData<Matrix>(value);
|
public void SetData(ColorRGB value)
|
||||||
|
|
||||||
public void SetData(Matrix[] value)
|
|
||||||
{
|
{
|
||||||
EnsureTypeMatch<Matrix>();
|
EnsureTypeMatch(1, 3, .Float);
|
||||||
|
|
||||||
// TODO: assert length
|
*(ColorRGB*)firstByte = value;
|
||||||
|
}
|
||||||
|
|
||||||
Internal.MemCpy(firstByte, value.Ptr, sizeof(Matrix) * Math.Min(value.Count, _elements));
|
public void SetData(ColorRGBA value)
|
||||||
|
{
|
||||||
|
EnsureTypeMatch(1, 4, .Float);
|
||||||
|
|
||||||
|
*(ColorRGBA*)firstByte = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetData(Color value)
|
||||||
|
{
|
||||||
|
EnsureTypeMatch(1, 4, .Float);
|
||||||
|
|
||||||
|
*(ColorRGBA*)firstByte = (ColorRGBA)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Todo: add all the other SetData-Methods
|
// Todo: add all the other SetData-Methods
|
||||||
@@ -187,9 +140,7 @@ namespace GlitchyEngine.Renderer
|
|||||||
*/
|
*/
|
||||||
internal void SetRawData(void* rawData)
|
internal void SetRawData(void* rawData)
|
||||||
{
|
{
|
||||||
#if GE_SHADER_UNUSED_VARIABLE_IS_ERROR
|
#if DEBUG && !GE_IGNORE_UNUSED_VARIABLE
|
||||||
Log.EngineLogger.Assert(_isUsed, scope $"Setting data for unused Variable \"{_name}\" of constant buffer \"{_constantBuffer.Name}\".");
|
|
||||||
#elif GE_SHADER_UNUSED_VARIABLE_IS_WARNING
|
|
||||||
if(!_isUsed)
|
if(!_isUsed)
|
||||||
{
|
{
|
||||||
Log.EngineLogger.Warning($"Setting data for unused Variable \"{_name}\" of constant buffer \"{_constantBuffer.Name}\".");
|
Log.EngineLogger.Warning($"Setting data for unused Variable \"{_name}\" of constant buffer \"{_constantBuffer.Name}\".");
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
namespace GlitchyEngine.Renderer
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
using GlitchyEngine.Math;
|
|
||||||
|
|
||||||
namespace GlitchyEngine.Renderer
|
|
||||||
{
|
|
||||||
public struct CameraComponent
|
|
||||||
{
|
|
||||||
public enum Projection
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* A perspective projection with near and far plane.
|
|
||||||
*/
|
|
||||||
Perspective,
|
|
||||||
/**
|
|
||||||
* A perspective projection with near and far plane,
|
|
||||||
* except that the closer a pixel is to the far plane the smaller its depth-value gets.
|
|
||||||
*/
|
|
||||||
PerspectiveReversed,
|
|
||||||
/**
|
|
||||||
* A perspective projection with a near plane and a far plane at infinite distance.
|
|
||||||
*/
|
|
||||||
PerspectiveInfinite,
|
|
||||||
/**
|
|
||||||
* A perspective projection with a near plane and a far plane at infinite distance,
|
|
||||||
* except that the closer a pixel is to the far plane the smaller its depth-value gets.
|
|
||||||
*/
|
|
||||||
PerspectiveReversedInfinite,
|
|
||||||
/**
|
|
||||||
* An orthographic projection.
|
|
||||||
*/
|
|
||||||
Orthographic
|
|
||||||
}
|
|
||||||
|
|
||||||
float _nearPlane;
|
|
||||||
float _farPlane;
|
|
||||||
Projection _projectionType;
|
|
||||||
float _fovY;
|
|
||||||
float _aspect;
|
|
||||||
|
|
||||||
public float NearPlane
|
|
||||||
{
|
|
||||||
get => _nearPlane;
|
|
||||||
set mut => _nearPlane = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float FarPlane
|
|
||||||
{
|
|
||||||
get => _farPlane;
|
|
||||||
set mut => _farPlane = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Projection ProjectionType
|
|
||||||
{
|
|
||||||
get => _projectionType;
|
|
||||||
set mut => _projectionType = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float FovY
|
|
||||||
{
|
|
||||||
get => _fovY;
|
|
||||||
set mut => _fovY = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float FovX
|
|
||||||
{
|
|
||||||
get => _fovY * _aspect;
|
|
||||||
set mut => _fovY = value / _aspect;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float Aspect
|
|
||||||
{
|
|
||||||
get => _aspect;
|
|
||||||
set mut => _aspect = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Matrix Projection => CalculateProjection();
|
|
||||||
|
|
||||||
public Matrix CalculateProjection()
|
|
||||||
{
|
|
||||||
Log.EngineLogger.Assert(_nearPlane < _farPlane, "The near plane must be smaller than the far plane.");
|
|
||||||
|
|
||||||
switch(_projectionType)
|
|
||||||
{
|
|
||||||
case .Perspective:
|
|
||||||
return Matrix.PerspectiveProjection(_fovY, _aspect, _nearPlane, _farPlane);
|
|
||||||
case .PerspectiveReversed:
|
|
||||||
return Matrix.ReversedPerspectiveProjection(_fovY, _aspect, _nearPlane, _farPlane);
|
|
||||||
case .PerspectiveInfinite:
|
|
||||||
return Matrix.InfinitePerspectiveProjection(_fovY, _aspect, _nearPlane);
|
|
||||||
case .PerspectiveReversedInfinite:
|
|
||||||
return Matrix.ReversedInfinitePerspectiveProjection(_fovY, _aspect, _nearPlane);
|
|
||||||
default:
|
|
||||||
Log.EngineLogger.Assert(false, "Unknown projection type.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return .Identity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -69,7 +69,7 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
public BufferVariableCollection Variables => _variables;
|
public BufferVariableCollection Variables => _variables;
|
||||||
|
|
||||||
protected this() {}
|
protected this(GraphicsContext context) : base(context) {}
|
||||||
|
|
||||||
protected internal void AddVariable(BufferVariable ownVariable)
|
protected internal void AddVariable(BufferVariable ownVariable)
|
||||||
{
|
{
|
||||||
@@ -99,9 +99,7 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
public enum ShaderVariableType
|
public enum ShaderVariableType
|
||||||
{
|
{
|
||||||
Bool,
|
|
||||||
Float,
|
Float,
|
||||||
Int,
|
|
||||||
// todo
|
// todo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,62 +0,0 @@
|
|||||||
using GlitchyEngine.Math;
|
|
||||||
using GlitchyEngine.World;
|
|
||||||
|
|
||||||
namespace GlitchyEngine.Renderer
|
|
||||||
{
|
|
||||||
/// Provides functionality for debugging
|
|
||||||
public static class DebugRenderer
|
|
||||||
{
|
|
||||||
private static GeometryBinding CoordinateCross;
|
|
||||||
|
|
||||||
public static bool DrawEntityTransforms = true;
|
|
||||||
|
|
||||||
public static void Init()
|
|
||||||
{
|
|
||||||
CreateCoordinateCross();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void CreateCoordinateCross()
|
|
||||||
{
|
|
||||||
CoordinateCross = new GeometryBinding();
|
|
||||||
//CoordinateCross.PrimitiveTopology
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Deinit()
|
|
||||||
{
|
|
||||||
CoordinateCross.ReleaseRef();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Draws a coordinate cross for the given matrix.
|
|
||||||
* @param transform The transform matrix.
|
|
||||||
* @param length Can be used to set a fixed length for the rendered lines that represent the axes.
|
|
||||||
* Set to 0 if you want transform to affect the length of the lines.
|
|
||||||
*/
|
|
||||||
public static void DrawCoordinateCross(Matrix transform, float length = 0.0f)
|
|
||||||
{
|
|
||||||
var transform;
|
|
||||||
|
|
||||||
if(length != 0.0f)
|
|
||||||
{
|
|
||||||
transform.Columns[0]..Normalize() *= length;
|
|
||||||
transform.Columns[1]..Normalize() *= length;
|
|
||||||
transform.Columns[2]..Normalize() *= length;
|
|
||||||
}
|
|
||||||
|
|
||||||
Renderer.DrawLine(.Zero, .Right, .Red, transform);
|
|
||||||
Renderer.DrawLine(.Zero, .Up, .Lime, transform);
|
|
||||||
Renderer.DrawLine(.Zero, .Forward, .Blue, transform);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Render(EcsWorld world)
|
|
||||||
{
|
|
||||||
if(DrawEntityTransforms)
|
|
||||||
{
|
|
||||||
for(var (entity, transform) in world.Enumerate<TransformComponent>())
|
|
||||||
{
|
|
||||||
DrawCoordinateCross(transform.WorldTransform);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
using GlitchyEngine.Core;
|
|
||||||
|
|
||||||
namespace GlitchyEngine.Renderer
|
|
||||||
{
|
|
||||||
/// The stencil operations that can be performed during depth-stencil testing.
|
|
||||||
public enum StencilOperation : uint32
|
|
||||||
{
|
|
||||||
/// Keep the existing stencil data.
|
|
||||||
Keep = 1,
|
|
||||||
/// Set the stencil data to 0.
|
|
||||||
Zero= 2,
|
|
||||||
/// Set the stencil data to the reference value set by calling ID3D11DeviceContext::OMSetDepthStencilState.
|
|
||||||
Replace = 3,
|
|
||||||
/// Increment the stencil value by 1, and clamp the result.
|
|
||||||
IncrementAndClamp = 4,
|
|
||||||
/// Decrement the stencil value by 1, and clamp the result.
|
|
||||||
DecrementAndClamp = 5,
|
|
||||||
/// Invert the stencil data.
|
|
||||||
Invert = 6,
|
|
||||||
/// Increment the stencil value by 1, and wrap the result if necessary.
|
|
||||||
Increment = 7,
|
|
||||||
/// Decrement the stencil value by 1, and wrap the result if necessary.
|
|
||||||
Decrement = 8
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct DepthStencilOperationDescription
|
|
||||||
{
|
|
||||||
/// The stencil operation to perform when stencil testing fails.
|
|
||||||
public StencilOperation StencilFailOperation = .Keep;
|
|
||||||
|
|
||||||
/// The stencil operation to perform when stencil testing passes and depth testing fails.
|
|
||||||
public StencilOperation StencilDepthFailOperation = .Keep;
|
|
||||||
|
|
||||||
/// The stencil operation to perform when stencil testing and depth testing both pass.
|
|
||||||
public StencilOperation StencilPassOperation = .Keep;
|
|
||||||
|
|
||||||
/// A function that compares stencil data against existing stencil data.
|
|
||||||
public ComparisonFunction StencilFunction = .Always;
|
|
||||||
|
|
||||||
public this(StencilOperation stencilFailOperation = .Keep, StencilOperation stencilDepthFailOperation = .Keep,
|
|
||||||
StencilOperation stencilPassOperation = .Keep, ComparisonFunction stencilFunction = .Always)
|
|
||||||
{
|
|
||||||
StencilFunction = stencilFunction;
|
|
||||||
}
|
|
||||||
|
|
||||||
public const Self Default = Self();
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct DepthStencilStateDescription
|
|
||||||
{
|
|
||||||
/// True if depth testing is enabled.
|
|
||||||
public bool DepthEnabled = true;
|
|
||||||
|
|
||||||
/// If true writing to the depth-stencil buffer is enabled.
|
|
||||||
public bool WriteDepth = true;
|
|
||||||
|
|
||||||
/// The function that is used to compare depth data against the existing depth data.
|
|
||||||
public ComparisonFunction DepthFunction = .Less;
|
|
||||||
|
|
||||||
/// True if stencil testing is enabled.
|
|
||||||
public bool StencilEnabled = false;
|
|
||||||
|
|
||||||
public uint8 StencilReadMask = 255;
|
|
||||||
public uint8 StencilWriteMask = 255;
|
|
||||||
|
|
||||||
public DepthStencilOperationDescription FrontFace = .();
|
|
||||||
public DepthStencilOperationDescription BackFace = .();
|
|
||||||
|
|
||||||
public this(bool depthEnabled = true, bool writeDepth = true, ComparisonFunction depthFunction = .Less,
|
|
||||||
bool stencilEnabled = false, uint8 stencilReadMask = 255, uint8 stencilWriteMask = 255,
|
|
||||||
DepthStencilOperationDescription frontFace = .(),
|
|
||||||
DepthStencilOperationDescription backFace = .())
|
|
||||||
{
|
|
||||||
DepthEnabled = depthEnabled;
|
|
||||||
WriteDepth = writeDepth;
|
|
||||||
DepthFunction = depthFunction;
|
|
||||||
StencilEnabled = stencilEnabled;
|
|
||||||
StencilReadMask = stencilReadMask;
|
|
||||||
StencilWriteMask = stencilWriteMask;
|
|
||||||
FrontFace = frontFace;
|
|
||||||
BackFace = backFace;
|
|
||||||
}
|
|
||||||
|
|
||||||
public const DepthStencilStateDescription Default = Self();
|
|
||||||
}
|
|
||||||
|
|
||||||
class DepthStencilState : RefCounter
|
|
||||||
{
|
|
||||||
public DepthStencilStateDescription _description;
|
|
||||||
|
|
||||||
public extern this(DepthStencilStateDescription description);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,37 +1,29 @@
|
|||||||
using GlitchyEngine.Core;
|
using System;
|
||||||
|
|
||||||
namespace GlitchyEngine.Renderer
|
namespace GlitchyEngine.Renderer
|
||||||
{
|
{
|
||||||
public enum DepthStencilFormat
|
|
||||||
{
|
|
||||||
D16_UNorm,
|
|
||||||
D24_UNorm_S8_UInt,
|
|
||||||
D32_Float,
|
|
||||||
D32_Float_S8X24_UInt,
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: add all features.
|
// TODO: add all features.
|
||||||
public class DepthStencilTarget : RefCounter
|
public class DepthStencilTarget : RefCounted
|
||||||
{
|
{
|
||||||
|
protected internal GraphicsContext _context ~ _?.ReleaseRef();
|
||||||
|
|
||||||
protected uint32 _width, _height;
|
protected uint32 _width, _height;
|
||||||
protected DepthStencilFormat _format;
|
|
||||||
|
|
||||||
public uint32 Width => _width;
|
public uint32 Width => _width;
|
||||||
public uint32 Height => _height;
|
public uint32 Height => _height;
|
||||||
public DepthStencilFormat Format => _format;
|
|
||||||
|
|
||||||
public this(uint32 width, uint32 height, DepthStencilFormat format = .D32_Float)
|
public this(GraphicsContext context, uint32 width, uint32 height)
|
||||||
{
|
{
|
||||||
Log.EngineLogger.Assert(format != .None, "DepthStencilFormat None is only valid for RenderTarget");
|
_context = context..AddRef();
|
||||||
|
|
||||||
_width = width;
|
_width = width;
|
||||||
_height = height;
|
_height = height;
|
||||||
_format = format;
|
|
||||||
|
|
||||||
PlatformCreate();
|
PlatformCreate();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected extern void PlatformCreate();
|
protected extern void PlatformCreate();
|
||||||
|
|
||||||
|
public extern void Bind();
|
||||||
|
|
||||||
|
public extern void Clear(float depthValue, uint8 stencilValue, DepthStencilClearFlag clearFlags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,19 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using GlitchyEngine.Core;
|
|
||||||
|
|
||||||
namespace GlitchyEngine.Renderer
|
namespace GlitchyEngine.Renderer
|
||||||
{
|
{
|
||||||
public class EffectLibrary
|
public class EffectLibrary
|
||||||
{
|
{
|
||||||
|
private GraphicsContext _context ~ _?.ReleaseRef();
|
||||||
private Dictionary<String, Effect> _effects = new .() ~ delete _;
|
private Dictionary<String, Effect> _effects = new .() ~ delete _;
|
||||||
|
|
||||||
private List<String> _ownedStrings = new .() ~ DeleteContainerAndItems!(_);
|
private List<String> _ownedStrings = new .() ~ DeleteContainerAndItems!(_);
|
||||||
|
|
||||||
public this()
|
public this(GraphicsContext context)
|
||||||
{
|
{
|
||||||
|
_context = context..AddRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ~this()
|
public ~this()
|
||||||
@@ -25,8 +26,6 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
public void Add(Effect effect, String effectName = null)
|
public void Add(Effect effect, String effectName = null)
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileResourceFunction!();
|
|
||||||
|
|
||||||
String name;
|
String name;
|
||||||
|
|
||||||
if(effectName == null)
|
if(effectName == null)
|
||||||
@@ -53,8 +52,6 @@ namespace GlitchyEngine.Renderer
|
|||||||
*/
|
*/
|
||||||
public Effect Load(String filepath, String effectName = null)
|
public Effect Load(String filepath, String effectName = null)
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileResourceFunction!();
|
|
||||||
|
|
||||||
String name = effectName;
|
String name = effectName;
|
||||||
|
|
||||||
if(name == null)
|
if(name == null)
|
||||||
@@ -65,7 +62,7 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
Log.EngineLogger.AssertDebug(!Exists(name), "Can't add two effects with the same name to library.");
|
Log.EngineLogger.AssertDebug(!Exists(name), "Can't add two effects with the same name to library.");
|
||||||
|
|
||||||
Effect effect = new Effect(filepath, name);
|
Effect effect = new Effect(_context, filepath, name);
|
||||||
Add(effect);
|
Add(effect);
|
||||||
|
|
||||||
return effect;
|
return effect;
|
||||||
@@ -84,8 +81,6 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
public Effect Get(String effectName)
|
public Effect Get(String effectName)
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileResourceFunction!();
|
|
||||||
|
|
||||||
Log.EngineLogger.AssertDebug(Exists(effectName), "Effect not found!");
|
Log.EngineLogger.AssertDebug(Exists(effectName), "Effect not found!");
|
||||||
|
|
||||||
return _effects.GetValue(effectName).Get()..AddRef();
|
return _effects.GetValue(effectName).Get()..AddRef();
|
||||||
@@ -94,8 +89,9 @@ namespace GlitchyEngine.Renderer
|
|||||||
public bool Exists(String effectName) => _effects.ContainsKey(effectName);
|
public bool Exists(String effectName) => _effects.ContainsKey(effectName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Effect : RefCounter
|
public class Effect : RefCounted
|
||||||
{
|
{
|
||||||
|
protected GraphicsContext _context ~ _?.ReleaseRef();
|
||||||
internal VertexShader _vs ~ _?.ReleaseRef();
|
internal VertexShader _vs ~ _?.ReleaseRef();
|
||||||
internal PixelShader _ps ~ _?.ReleaseRef();
|
internal PixelShader _ps ~ _?.ReleaseRef();
|
||||||
protected String _name ~ delete _;
|
protected String _name ~ delete _;
|
||||||
@@ -104,10 +100,7 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
BufferVariableCollection _variables ~ delete _;
|
BufferVariableCollection _variables ~ delete _;
|
||||||
|
|
||||||
typealias TextureEntry = (Texture Texture, ShaderTextureCollection.ResourceEntry* VsSlot, ShaderTextureCollection.ResourceEntry* PsSlot);
|
public GraphicsContext Context => _context;
|
||||||
Dictionary<String, TextureEntry> _textures ~ delete _;
|
|
||||||
|
|
||||||
public Dictionary<String, TextureEntry> Textures => _textures;
|
|
||||||
|
|
||||||
public VertexShader VertexShader
|
public VertexShader VertexShader
|
||||||
{
|
{
|
||||||
@@ -136,15 +129,33 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
public String Name => _name;
|
public String Name => _name;
|
||||||
|
|
||||||
|
public void ApplyChanges()
|
||||||
|
{
|
||||||
|
for(let buffer in _bufferCollection)
|
||||||
|
{
|
||||||
|
if(let cbuffer = buffer.Buffer as ConstantBuffer)
|
||||||
|
{
|
||||||
|
cbuffer.Update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Bind(GraphicsContext context)
|
||||||
|
{
|
||||||
|
ApplyChanges();
|
||||||
|
|
||||||
|
context.SetVertexShader(_vs);
|
||||||
|
context.SetPixelShader(_ps);
|
||||||
|
}
|
||||||
|
|
||||||
[Obsolete("Will be removed in the future", false)]
|
[Obsolete("Will be removed in the future", false)]
|
||||||
public this()
|
public this()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public this(String filename, String vsEntry, String psEntry, String shaderName = null)
|
public this(GraphicsContext context, String filename, String vsEntry, String psEntry, String shaderName = null)
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileResourceFunction!();
|
_context = context..AddRef();
|
||||||
|
|
||||||
CompileFromFile(filename, vsEntry, psEntry);
|
CompileFromFile(filename, vsEntry, psEntry);
|
||||||
|
|
||||||
if(shaderName == null)
|
if(shaderName == null)
|
||||||
@@ -158,16 +169,15 @@ namespace GlitchyEngine.Renderer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public this(String filename, String shaderName = null)
|
public this(GraphicsContext context, String filename, String shaderName = null)
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileResourceFunction!();
|
_context = context..AddRef();
|
||||||
|
|
||||||
String fileContent = scope String();
|
String fileContent = scope String();
|
||||||
String vsName = scope String();
|
String vsName = scope String();
|
||||||
String psName = scope String();
|
String psName = scope String();
|
||||||
|
|
||||||
ProcessFile(filename, fileContent, vsName, psName);
|
ProcessFile(filename, fileContent, vsName, psName);
|
||||||
|
|
||||||
Compile(fileContent, vsName, psName);
|
Compile(fileContent, vsName, psName);
|
||||||
|
|
||||||
MergeResources();
|
MergeResources();
|
||||||
@@ -185,97 +195,28 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
public this(String shaderName, String vsPath, String vsEntry, String psPath, String psEntry)
|
public this(String shaderName, String vsPath, String vsEntry, String psPath, String psEntry)
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileResourceFunction!();
|
|
||||||
|
|
||||||
Compile(vsPath, vsEntry, psPath, psEntry);
|
Compile(vsPath, vsEntry, psPath, psEntry);
|
||||||
|
|
||||||
_name = new String(shaderName);
|
_name = new String(shaderName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ~this()
|
|
||||||
{
|
|
||||||
Debug.Profiler.ProfileResourceFunction!();
|
|
||||||
|
|
||||||
for(let entry in _textures)
|
|
||||||
{
|
|
||||||
entry.value.Texture?.ReleaseRef();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetTexture(String name, Texture texture)
|
|
||||||
{
|
|
||||||
Debug.Profiler.ProfileRendererFunction!();
|
|
||||||
|
|
||||||
ref TextureEntry entry = ref _textures[name];
|
|
||||||
|
|
||||||
entry.Texture?.ReleaseRef();
|
|
||||||
entry.Texture = texture;
|
|
||||||
entry.Texture?.AddRef();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ApplyTextures()
|
|
||||||
{
|
|
||||||
Debug.Profiler.ProfileRendererFunction!();
|
|
||||||
|
|
||||||
for(let (name, entry) in _textures)
|
|
||||||
{
|
|
||||||
entry.VsSlot?.Texture?.ReleaseRef();
|
|
||||||
entry.VsSlot?.Texture = entry.Texture;
|
|
||||||
entry.VsSlot?.Texture?.AddRef();
|
|
||||||
|
|
||||||
entry.PsSlot?.Texture?.ReleaseRef();
|
|
||||||
entry.PsSlot?.Texture = entry.Texture;
|
|
||||||
entry.PsSlot?.Texture?.AddRef();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ApplyChanges()
|
|
||||||
{
|
|
||||||
Debug.Profiler.ProfileRendererFunction!();
|
|
||||||
|
|
||||||
for(let buffer in _bufferCollection)
|
|
||||||
{
|
|
||||||
if(let cbuffer = buffer.Buffer as ConstantBuffer)
|
|
||||||
{
|
|
||||||
cbuffer.Update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Bind(GraphicsContext context)
|
|
||||||
{
|
|
||||||
Debug.Profiler.ProfileRendererFunction!();
|
|
||||||
|
|
||||||
ApplyTextures();
|
|
||||||
ApplyChanges();
|
|
||||||
|
|
||||||
context.SetVertexShader(_vs);
|
|
||||||
context.SetPixelShader(_ps);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void CompileFromFile(String filename, String vsEntry, String psEntry)
|
private void CompileFromFile(String filename, String vsEntry, String psEntry)
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileResourceFunction!();
|
let vs = Shader.FromFile!<VertexShader>(_context, filename, vsEntry);
|
||||||
|
|
||||||
let vs = Shader.FromFile!<VertexShader>(filename, vsEntry);
|
|
||||||
VertexShader = vs;
|
VertexShader = vs;
|
||||||
vs.ReleaseRef();
|
vs.ReleaseRef();
|
||||||
let ps = Shader.FromFile!<PixelShader>(filename, psEntry);
|
let ps = Shader.FromFile!<PixelShader>(_context, filename, psEntry);
|
||||||
PixelShader = ps;
|
PixelShader = ps;
|
||||||
ps.ReleaseRef();
|
ps.ReleaseRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Compile(String fileContent, String vsEntry, String psEntry)
|
private void Compile(String fileContent, String vsEntry, String psEntry)
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileResourceFunction!();
|
|
||||||
|
|
||||||
// TODO: vsEntry and psEntry could be empty (which is a valid case.)
|
// TODO: vsEntry and psEntry could be empty (which is a valid case.)
|
||||||
let vs = new VertexShader(fileContent, vsEntry);
|
let vs = new VertexShader(_context, fileContent, vsEntry);
|
||||||
VertexShader = vs;
|
VertexShader = vs;
|
||||||
vs.ReleaseRef();
|
vs.ReleaseRef();
|
||||||
let ps = new PixelShader(fileContent, psEntry);
|
let ps = new PixelShader(_context, fileContent, psEntry);
|
||||||
PixelShader = ps;
|
PixelShader = ps;
|
||||||
ps.ReleaseRef();
|
ps.ReleaseRef();
|
||||||
}
|
}
|
||||||
@@ -291,8 +232,6 @@ namespace GlitchyEngine.Renderer
|
|||||||
*/
|
*/
|
||||||
private static void ProcessFile(String filename, String fileContent, String vsName, String psName)
|
private static void ProcessFile(String filename, String fileContent, String vsName, String psName)
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileResourceFunction!();
|
|
||||||
|
|
||||||
File.ReadAllText(filename, fileContent, true);
|
File.ReadAllText(filename, fileContent, true);
|
||||||
// append line ending just in case the file doesn't end with one.
|
// append line ending just in case the file doesn't end with one.
|
||||||
fileContent.Append('\n');
|
fileContent.Append('\n');
|
||||||
@@ -352,17 +291,12 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
private void MergeResources()
|
private void MergeResources()
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileResourceFunction!();
|
|
||||||
|
|
||||||
MergeConstantBuffers();
|
MergeConstantBuffers();
|
||||||
MergeBufferVariables();
|
MergeBufferVariables();
|
||||||
MergeTextures();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MergeConstantBuffers()
|
private void MergeConstantBuffers()
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileResourceFunction!();
|
|
||||||
|
|
||||||
_bufferCollection = new BufferCollection();
|
_bufferCollection = new BufferCollection();
|
||||||
|
|
||||||
HashSet<String> bufferNames = scope HashSet<String>();
|
HashSet<String> bufferNames = scope HashSet<String>();
|
||||||
@@ -406,8 +340,6 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
private void MergeBufferVariables()
|
private void MergeBufferVariables()
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileResourceFunction!();
|
|
||||||
|
|
||||||
_variables = new BufferVariableCollection(false);
|
_variables = new BufferVariableCollection(false);
|
||||||
|
|
||||||
for(let buffer in _bufferCollection)
|
for(let buffer in _bufferCollection)
|
||||||
@@ -424,8 +356,6 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
private void AddShaderBuffers(Shader shader, HashSet<String> bufferNames)
|
private void AddShaderBuffers(Shader shader, HashSet<String> bufferNames)
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileResourceFunction!();
|
|
||||||
|
|
||||||
if(shader != null)
|
if(shader != null)
|
||||||
{
|
{
|
||||||
for(let buffer in shader.Buffers)
|
for(let buffer in shader.Buffers)
|
||||||
@@ -434,58 +364,5 @@ namespace GlitchyEngine.Renderer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Merges the texture slots of all shaders into one dictionary.
|
|
||||||
private void MergeTextures()
|
|
||||||
{
|
|
||||||
Debug.Profiler.ProfileResourceFunction!();
|
|
||||||
|
|
||||||
delete _textures;
|
|
||||||
_textures = new .();
|
|
||||||
|
|
||||||
EnumerateShaderTextures(_vs);
|
|
||||||
EnumerateShaderTextures(_ps);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @brief Merges all textures of the given shader into the _textures dictionary.
|
|
||||||
* @param shader The shader whose textures will be merged into the dictionary.
|
|
||||||
*/
|
|
||||||
private void EnumerateShaderTextures<T>(T shader) where T : Shader
|
|
||||||
{
|
|
||||||
Debug.Profiler.ProfileResourceFunction!();
|
|
||||||
|
|
||||||
//for(var (name, index, texture) in shader.Resources)
|
|
||||||
for(var shaderEntry in ref shader.Textures)
|
|
||||||
{
|
|
||||||
TextureEntry entry;
|
|
||||||
|
|
||||||
// Get existing entry or create new
|
|
||||||
if(!_textures.TryGetValue(shaderEntry.Name, out entry))
|
|
||||||
{
|
|
||||||
entry = (shaderEntry.Texture, null, null);
|
|
||||||
entry.Texture?.AddRef();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the corresponding shader resource slot
|
|
||||||
if(typeof(T) == typeof(VertexShader))
|
|
||||||
{
|
|
||||||
entry.VsSlot = &shaderEntry;
|
|
||||||
}
|
|
||||||
else if(typeof(T) == typeof(PixelShader))
|
|
||||||
{
|
|
||||||
entry.PsSlot = &shaderEntry;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the entry has no texture but the shader has one -> set texture
|
|
||||||
if(entry.Texture == null && shaderEntry.Texture != null)
|
|
||||||
{
|
|
||||||
entry.Texture = shaderEntry.Texture;
|
|
||||||
entry.Texture?.AddRef();
|
|
||||||
}
|
|
||||||
|
|
||||||
// save entry
|
|
||||||
_textures[shaderEntry.Name] = entry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +1,22 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using GlitchyEngine.Core;
|
|
||||||
|
|
||||||
namespace GlitchyEngine.Renderer
|
namespace GlitchyEngine.Renderer
|
||||||
{
|
{
|
||||||
public class GeometryBinding : RefCounter
|
public class GeometryBinding : RefCounted
|
||||||
{
|
{
|
||||||
|
internal GraphicsContext _context ~ _?.ReleaseRef();
|
||||||
|
|
||||||
internal List<VertexBufferBinding> _vertexBuffers = new .() ~ delete _;
|
internal List<VertexBufferBinding> _vertexBuffers = new .() ~ delete _;
|
||||||
internal IndexBuffer _indexBuffer ~ _?.ReleaseRef();
|
internal IndexBuffer _indexBuffer;
|
||||||
internal VertexLayout _vertexLayout ~ _?.ReleaseRef();
|
internal VertexLayout _vertexLayout;
|
||||||
internal uint32 _indexByteOffset;
|
internal uint32 _indexByteOffset;
|
||||||
internal uint32 _indexCount;
|
internal uint32 _indexCount;
|
||||||
internal uint32 _instanceCount;
|
|
||||||
internal PrimitiveTopology _primitiveTopology;
|
internal PrimitiveTopology _primitiveTopology;
|
||||||
internal uint32 _vertexCount;
|
|
||||||
|
|
||||||
public bool IsIndexed => _indexBuffer != null;
|
public this(GraphicsContext context)
|
||||||
|
|
||||||
public this()
|
|
||||||
{
|
{
|
||||||
|
_context = context..AddRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ~this()
|
public ~this()
|
||||||
@@ -27,6 +25,8 @@ namespace GlitchyEngine.Renderer
|
|||||||
{
|
{
|
||||||
binding.Buffer?.ReleaseRef();
|
binding.Buffer?.ReleaseRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_indexBuffer?.ReleaseRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
public VertexBufferBinding GetVertexBuffer(uint32 slot)
|
public VertexBufferBinding GetVertexBuffer(uint32 slot)
|
||||||
@@ -50,22 +50,6 @@ namespace GlitchyEngine.Renderer
|
|||||||
[Inline]
|
[Inline]
|
||||||
public uint32 IndexCount => _indexCount;
|
public uint32 IndexCount => _indexCount;
|
||||||
|
|
||||||
public uint32 InstanceCount
|
|
||||||
{
|
|
||||||
[Inline]
|
|
||||||
get => _instanceCount;
|
|
||||||
[Inline]
|
|
||||||
set => _instanceCount = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public uint32 VertexCount
|
|
||||||
{
|
|
||||||
[Inline]
|
|
||||||
get => _vertexCount;
|
|
||||||
[Inline]
|
|
||||||
set => _vertexCount = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Inline]
|
[Inline]
|
||||||
public PrimitiveTopology PrimitiveTopology => _primitiveTopology;
|
public PrimitiveTopology PrimitiveTopology => _primitiveTopology;
|
||||||
|
|
||||||
@@ -81,8 +65,7 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
public void SetVertexLayout(VertexLayout vertexLayout)
|
public void SetVertexLayout(VertexLayout vertexLayout)
|
||||||
{
|
{
|
||||||
_vertexLayout?.ReleaseRef();
|
_vertexLayout = vertexLayout;
|
||||||
_vertexLayout = vertexLayout..AddRef();
|
|
||||||
PlatformSetVertexLayout(vertexLayout);
|
PlatformSetVertexLayout(vertexLayout);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,7 +82,8 @@ namespace GlitchyEngine.Renderer
|
|||||||
public void SetIndexBuffer(IndexBuffer indexBuffer, uint32 byteOffset = 0, uint32 indexCount = (.)-1)
|
public void SetIndexBuffer(IndexBuffer indexBuffer, uint32 byteOffset = 0, uint32 indexCount = (.)-1)
|
||||||
{
|
{
|
||||||
_indexBuffer?.ReleaseRef();
|
_indexBuffer?.ReleaseRef();
|
||||||
_indexBuffer = indexBuffer..AddRef();
|
_indexBuffer = indexBuffer;
|
||||||
|
_indexBuffer.AddRef();
|
||||||
|
|
||||||
_indexByteOffset = byteOffset;
|
_indexByteOffset = byteOffset;
|
||||||
|
|
||||||
@@ -117,8 +101,8 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
protected extern void PlatformSetIndexBuffer(IndexBuffer indexBuffer);
|
protected extern void PlatformSetIndexBuffer(IndexBuffer indexBuffer);
|
||||||
|
|
||||||
public extern void Bind();
|
public extern void Bind(GraphicsContext context = null);
|
||||||
|
|
||||||
public extern void Unbind();
|
public extern void Unbind(GraphicsContext context = null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,16 @@
|
|||||||
using System;
|
|
||||||
using GlitchyEngine.Core;
|
|
||||||
using GlitchyEngine.Math;
|
using GlitchyEngine.Math;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace GlitchyEngine.Renderer
|
namespace GlitchyEngine.Renderer
|
||||||
{
|
{
|
||||||
public class GraphicsContext : RefCounter
|
public class RenderTarget;
|
||||||
|
|
||||||
|
public class GraphicsContext : RefCounted
|
||||||
{
|
{
|
||||||
private static GraphicsContext s_GraphicsContext;
|
private RasterizerState _currentRasterizerState;
|
||||||
public static GraphicsContext Get() => s_GraphicsContext;
|
|
||||||
|
|
||||||
public extern SwapChain SwapChain {get;}
|
public extern SwapChain SwapChain {get;}
|
||||||
|
|
||||||
protected extern void PlatformConstruct();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The maximum number of simultaneous rendertargets supported.
|
* The maximum number of simultaneous rendertargets supported.
|
||||||
*/
|
*/
|
||||||
@@ -20,20 +18,14 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
public extern void Init();
|
public extern void Init();
|
||||||
|
|
||||||
/** @brief Sets a depthtarget.
|
/**
|
||||||
|
* Sets a rendertarget.
|
||||||
|
* @param renderTarget The render target.
|
||||||
|
* @param slot The slot to which the rendertarget will be bound.
|
||||||
|
* @remarks When @RenderTarget is null the backbuffer will be bound.
|
||||||
* @BindRenderTargets has to be called in order to bind the rendertargets.
|
* @BindRenderTargets has to be called in order to bind the rendertargets.
|
||||||
* @param renderTarget The render target to set. If null, the backbuffer will be set.
|
|
||||||
* @param slot The slot to which the rendertarget will be bound. If 0 the depth buffer of the current render target will be set. If it has no depthbuffer the current will be unset.
|
|
||||||
*/
|
*/
|
||||||
public extern void SetDepthStencilTarget(DepthStencilTarget target);
|
public extern void SetRenderTarget(RenderTarget renderTarget, int slot = 0);
|
||||||
|
|
||||||
/** @brief Sets a rendertarget to the given slot.
|
|
||||||
* @BindRenderTargets has to be called in order to bind the rendertargets.
|
|
||||||
* @param renderTarget The render target to set. If null, the backbuffer will be set.
|
|
||||||
* @param slot The slot to which the rendertarget will be bound. If 0 the depth buffer of the current render target will be set. If it has no depthbuffer the current will be unset.
|
|
||||||
* @param setDepthTarget If set to true the depth stencil target of the given renderTarget will be bound (only applies if slot is 0).
|
|
||||||
*/
|
|
||||||
public extern void SetRenderTarget(RenderTarget2D renderTarget, int slot = 0, bool setDepthTarget = true);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Binds all.
|
* Binds all.
|
||||||
@@ -49,7 +41,7 @@ namespace GlitchyEngine.Renderer
|
|||||||
* @param color The color to clear the render target with.
|
* @param color The color to clear the render target with.
|
||||||
* @remarks When @renderTarget is null the backbuffer will be cleared.
|
* @remarks When @renderTarget is null the backbuffer will be cleared.
|
||||||
*/
|
*/
|
||||||
public extern void ClearRenderTarget(RenderTarget2D renderTarget, ColorRGBA color);
|
public extern void ClearRenderTarget(RenderTarget renderTarget, ColorRGBA color);
|
||||||
|
|
||||||
//public abstract void SetViewport(Viewport viewport);
|
//public abstract void SetViewport(Viewport viewport);
|
||||||
|
|
||||||
@@ -82,9 +74,21 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
public extern void SetIndexBuffer(Buffer buffer, IndexFormat indexFormat = .Index16Bit, uint32 byteOffset = 0);
|
public extern void SetIndexBuffer(Buffer buffer, IndexFormat indexFormat = .Index16Bit, uint32 byteOffset = 0);
|
||||||
|
|
||||||
|
public void SetRasterizerState(RasterizerState rasterizerState)
|
||||||
|
{
|
||||||
|
_currentRasterizerState = rasterizerState;
|
||||||
|
SetRasterizerStateImpl();
|
||||||
|
}
|
||||||
|
|
||||||
protected extern void SetRasterizerStateImpl();
|
protected extern void SetRasterizerStateImpl();
|
||||||
|
|
||||||
internal void SetViewport(Viewport viewport)
|
public RasterizerState GetRasterizerState()
|
||||||
|
{
|
||||||
|
return _currentRasterizerState;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Inline]
|
||||||
|
public void SetViewport(Viewport viewport)
|
||||||
{
|
{
|
||||||
var viewport;
|
var viewport;
|
||||||
SetViewports(1, &viewport);
|
SetViewports(1, &viewport);
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user