30 Commits
Author SHA1 Message Date
Simon Lübeß 65e2248b30 Implemented basic ECS 2021-04-09 19:09:32 +02:00
Simon Lübeß a89657591f Removed epsilon value from camera
(bug fixed in DirectX-beef)
2021-04-09 19:08:23 +02:00
Simon Lübeß cd929080f4 Added TextureCube 2021-03-26 19:12:53 +01:00
Simon Lübeß 79e160348b Added larger epsilon to perspective camera 2021-03-26 19:12:41 +01:00
Simon Lübeß 5a6abc9b8b Added explicit conversion from float to Vector 2021-03-26 19:12:08 +01:00
Simon Lübeß 0f62637662 Generate fallback entries for missing block textures 2021-03-25 20:43:43 +01:00
Simon Lübeß 1d7029eb0f Made TextureAtlas platform independent 2021-03-25 16:33:33 +01:00
Simon Lübeß ceb4cef034 Added protected function to create Texture2D from raw data 2021-03-25 16:31:03 +01:00
Simon Lübeß 5873f12643 Added textures for Blocks 2021-03-24 14:44:02 +01:00
Simon Lübeß 1b00fa67a5 Added GE_D3D11 flag 2021-03-23 19:07:57 +01:00
Simon Lübeß dfeed4a5c9 Moved ImplBind implementation from Texture2D to Texture 2021-03-23 19:07:41 +01:00
Simon Lübeß ec83dfa21d Added lodepng-beef 2021-03-23 18:25:30 +01:00
Simon Lübeß d8f6be1358 Added refcounting to RasterizerState 2021-03-22 17:58:57 +01:00
Simon Lübeß 72400e873d Decoupled Chunk data loading/generation and geometry generation 2021-03-19 18:06:40 +01:00
Simon Lübeß a0373366f6 Workaround for CompTime crash 2021-03-18 17:23:05 +01:00
Simon Lübeß 8320689d3e Geometry Generation now in Block 2021-03-18 17:22:41 +01:00
Simon Lübeß 4e87f5f144 Blocks now represented by Objects instead of ints 2021-03-06 20:46:08 +01:00
Simon Lübeß 3449463282 Added EffectLibrary 2021-03-06 18:54:46 +01:00
Simon Lübeß 623ada4b2f Added chunk editing 2021-03-04 13:05:57 +01:00
Simon Lübeß 4e377bb117 Added basic raw input support 2021-03-04 13:05:26 +01:00
Simon Lübeß 08613b9e82 Overcomplicated chunk loading
Implemented an overly complicated mechanism into LoadChunk to be able to passively wait for chunks to be loaded by another thread.
2021-03-03 19:00:34 +01:00
Simon Lübeß 4b032d2c7e Added Semaphore and Mutex 2021-03-03 18:57:42 +01:00
Simon Lübeß 9d52f77b43 Switched to Int32 vector from Point 2021-03-03 16:34:25 +01:00
Simon Lübeß 7a777bb55e Added Int32 vectors 2021-03-03 16:33:58 +01:00
Simon Lübeß f87c0e2ecd Raycasting world now returns intersection location and face 2021-03-02 22:25:38 +01:00
Simon Lübeß 488d2a55c4 Added voxel raycasting and voxel chunk access 2021-03-02 22:07:21 +01:00
Simon Lübeß cbfbd449ff Start of block raycasting 2021-02-26 10:58:11 +01:00
Simon Lübeß 4dcf1b5bec Updated .gitignore and added Chunk loading and saving 2021-02-24 20:07:02 +01:00
Simon Lübeß afc7594df9 initial VoxelGame commit 2021-02-24 14:55:12 +01:00
Simon Lübeß 0461669e13 Added rudimentary DepthStencilTarget 2021-02-21 14:45:50 +01:00
253 changed files with 7139 additions and 17752 deletions
+2 -1
View File
@@ -4,4 +4,5 @@ build/
.vs/ .vs/
recovery/ recovery/
vendor/directx vendor/directx
imgui.ini Sandbox/imgui.ini
Sandbox/worlds
+6 -21
View File
@@ -1,27 +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/imgui-beef"]
path = GlitchyEngine/vendor/imgui-beef
url = https://github.com/aharabada/imgui-beef
[submodule ".\\GlitchyEngine\\vendor\\DirectXTK"]
path = .\\GlitchyEngine\\vendor\\DirectXTK
url = https://github.com/aharabada/DirectXTK-beef.git
[submodule "vendor/lodepng-beef"] [submodule "vendor/lodepng-beef"]
path = vendor/lodepng-beef path = vendor/lodepng-beef
url = https://github.com/aharabada/lodepng-beef.git url = https://github.com/aharabada/lodepng-beef.git
[submodule "GlitchyEngine/vendor/freetype"]
path = GlitchyEngine/vendor/freetype
url = https://github.com/aharabada/FreeType-beef.git
[submodule "GlitchyEngine/vendor/gltf"]
path = GlitchyEngine/vendor/gltf
url = https://github.com/aharabada/cgltf-beef.git
[submodule "GlitchyEngine/vendor/msdfgen"]
path = GlitchyEngine/vendor/msdfgen
url = https://github.com/aharabada/msdfgen-beef.git
[submodule "GlitchyEngine/vendor/imgui"]
path = GlitchyEngine/vendor/imgui
url = https://github.com/aharabada/ImGui_GlitchyEngine.git
[submodule "GlitchyEngineHelper/vendor/xxHash"]
path = GlitchyEngineHelper/vendor/xxHash
url = https://github.com/Cyan4973/xxHash.git
[submodule "GlitchyEngine/vendor/bon"]
path = GlitchyEngine/vendor/bon
url = https://github.com/EinScott/bon.git
[submodule "GlitchyEngineHelper/vendor/DirectXTK"]
path = GlitchyEngineHelper/vendor/DirectXTK
url = https://github.com/microsoft/DirectXTK.git
+2 -3
View File
@@ -1,6 +1,5 @@
FileVersion = 1 FileVersion = 1
Projects = {Sandbox = {Path = "Sandbox"}, GlitchyEngine = {Path = "GlitchyEngine"}, GlitchLog = {Path = "GlitchLog"}, DirectX = {Path = "GlitchyEngine/vendor/directx/DirectX"}, LodePng = {Path = "vendor/lodepng-beef/lodepng-beef"}, FreeType = {Path = "GlitchyEngine/vendor/freetype"}, cgltf-beef = {Path = "GlitchyEngine/vendor/gltf/cgltf-beef"}, GlitchyEditor = {Path = "GlitchyEditor"}, msdfgen-beef = {Path = "GlitchyEngine/vendor/msdfgen/msdfgen-beef"}, ImGui = {Path = "GlitchyEngine/vendor/imgui/ImGui"}, ImGuiImplDX11 = {Path = "GlitchyEngine/vendor/imgui/ImGuiImplDX11"}, ImGuiImplWin32 = {Path = "GlitchyEngine/vendor/imgui/ImGuiImplWin32"}, ImGuizmo = {Path = "GlitchyEngine/vendor/imgui/ImGuizmo"}, GlitchyEngineHelper = {Path = "GlitchyEngineHelper"}, bon = {Path = "GlitchyEngine/vendor/bon"}} 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"}}
WorkspaceFolders = {GlitchyEngine = ["GlitchyEngine", "GlitchLog", "GlitchyEngineHelper"], "GlitchyEngine/Dependencies" = ["cgltf-beef", "DirectX", "FreeType", "ImGui", "ImGuiImplDX11", "ImGuiImplWin32", "ImGuizmo", "LodePng", "msdfgen-beef", "bon"]}
[Workspace] [Workspace]
StartupProject = "GlitchyEditor" StartupProject = "Sandbox"
+6 -6
View File
@@ -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]
-7
View File
@@ -1,7 +0,0 @@
FileVersion = 1
Dependencies = {corlib = "*", GlitchLog = "*", GlitchyEngine = "*"}
[Project]
Name = "GlitchyEditor"
TargetType = "BeefGUIApplication"
StartupObject = "GlitchyEngine.Program"
Binary file not shown.
@@ -1,62 +0,0 @@
Texture2D Texture : register(t0);
SamplerState Sampler : register(s0);
cbuffer Constants : register(b0)
{
float4x4 ViewProjection;
};
struct VS_Input
{
float2 Position : POSITION;
float2 Texcoord : TEXCOORD0;
float4x4 Transform : TRANSFORM;
float4 Color : COLOR;
float4 UVTransform : TEXCOORD1;
float InnerRadius : TEXCOORD2;
};
struct PS_Input
{
float4 Position : SV_Position;
float2 RawPos : TEXCOORD0;
float2 Texcoord : TEXCOORD1;
float4 Color : COLOR;
float InnerRadius : TEXCOORD2;
};
PS_Input VS(VS_Input input)
{
PS_Input output;
output.Position = mul(ViewProjection, mul(input.Transform, float4(input.Position, 0.0f, 1.0f)));
output.Texcoord = input.UVTransform.xy + input.UVTransform.zw * input.Texcoord;
output.RawPos = input.Position;
output.Color = input.Color;
output.InnerRadius = input.InnerRadius;
return output;
}
float4 PS(PS_Input input) : SV_Target0
{
float2 uv = input.RawPos * 2;
float distance = 1.0f - length(uv);
// Smoothing edges based on derivative (not sure if RawPos is the best value for this)
float f = fwidth(input.RawPos.x) + fwidth(input.RawPos.y);
float amount = smoothstep(0.0f, f, distance);
amount *= smoothstep(input.InnerRadius + f, input.InnerRadius, distance);
// Discard invisible pixels
clip(amount - 0.5f);
float4 color = Texture.Sample(Sampler, input.Texcoord) * input.Color;
color.a *= amount;
return color;
}
#effect[VS=VS, PS=PS]
@@ -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,93 +0,0 @@
Texture2D<float3> Texture : register(t0);
SamplerState Sampler : register(s0);
cbuffer Constants
{
float4x4 ViewProjection;
float2 UnitRange;
float screenPixelRange = 2;
}
struct VS_Input
{
float2 Position : POSITION;
float2 Texcoord : TEXCOORD0;
float4x4 Tranform : TRANSFORM;
float4 Color : COLOR;
float4 UVTransform : TEXCOORD1;
};
struct PS_Input
{
float4 Position : SV_Position;
float2 TexCoord : TEXCOORD0;
float4 Color : COLOR;
};
PS_Input VS(VS_Input input)
{
PS_Input output;
output.Position = mul(ViewProjection, mul(input.Tranform, float4(input.Position, 0.0f, 1.0f)));
output.TexCoord = input.UVTransform.xy + input.UVTransform.zw * input.Texcoord;
output.Color = input.Color;
return output;
}
/*
in vec2 texCoord;
out vec4 color;
uniform sampler2D msdf;
uniform vec4 bgColor;
uniform vec4 fgColor;
float median(float r, float g, float b) {
return max(min(r, g), min(max(r, g), b));
}
void main() {
vec3 msd = texture(msdf, texCoord).rgb;
float sd = median(msd.r, msd.g, msd.b);
float screenPxDistance = screenPxRange()*(sd - 0.5);
float opacity = clamp(screenPxDistance + 0.5, 0.0, 1.0);
color = mix(bgColor, fgColor, opacity);
}
*/
float median(float r, float g, float b)
{
return max(min(r, g), min(max(r, g), b));
}
float ScreenPxRange(float2 texcoord)
{
float2 screenTexSize = 1.0f / fwidth(texcoord);
return max(0.5f * dot(UnitRange, screenTexSize), 1.0f);
}
float4 PS(PS_Input input) : SV_Target0
{
float3 msd = Texture.Sample(Sampler, input.TexCoord);
float sd = median(msd.r, msd.g, msd.b);
float screenPxDistance = ScreenPxRange(input.TexCoord) * (sd - 0.5);
float opacity = clamp(screenPxDistance + 0.5, 0.0, 1.0);
return float4(input.Color.rgb, opacity * input.Color.a);
}
/*
// 2D
float4 PS(PS_Input input) : SV_Target0
{
float3 msd = Texture.Sample(Sampler, input.TexCoord).rgb;
float sd = median(msd.r, msd.g, msd.b);
float screenPxDistance = screenPixelRange*(sd - 0.5);
float opacity = clamp(screenPxDistance + 0.5, 0.0, 1.0);
return float4(input.Color.rgb, opacity * input.Color.a);
}
*/
#effect[VS=VS, PS=PS]
@@ -1,41 +0,0 @@
Texture2D Texture : register(t0);
SamplerState Sampler : register(s0);
cbuffer Constants : register(b0)
{
float4x4 ViewProjection;
};
struct VS_Input
{
float2 Position : POSITION;
float2 Texcoord : TEXCOORD0;
float4x4 Transform : TRANSFORM;
float4 Color : COLOR;
float4 UVTransform : TEXCOORD1;
};
struct PS_Input
{
float4 Position : SV_Position;
float2 Texcoord : TEXCOORD;
float4 Color : COLOR;
};
PS_Input VS(VS_Input input)
{
PS_Input output;
output.Position = mul(ViewProjection, mul(input.Transform, float4(input.Position, 0.0f, 1.0f)));
output.Texcoord = input.UVTransform.xy + input.UVTransform.zw * input.Texcoord;
output.Color = input.Color;
return output;
}
float4 PS(PS_Input input) : SV_Target0
{
return Texture.Sample(Sampler, input.Texcoord) * input.Color;
}
#effect[VS=VS, PS=PS]
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 258 B

@@ -1,298 +0,0 @@
using ImGui;
using GlitchyEngine.World;
using System;
using GlitchyEngine.Math;
using System.Collections;
namespace GlitchyEditor.EditWindows
{
using internal GlitchyEngine.World.TransformComponent;
class ComponentEditWindow : EditorWindow
{
public const String s_WindowTitle = "Components";
private EntityHierarchyWindow _entityHierarchyWindow;
private List<(Type, ComponentAttribute attribute)> _componentTypes = new .() ~ delete _;
public this(EntityHierarchyWindow entityHierarchyWindow)
{
_entityHierarchyWindow = entityHierarchyWindow;
for (let type in Type.Types)
{
if (let componentAttribute = type.GetCustomAttribute<ComponentAttribute>())
{
_componentTypes.Add((type, componentAttribute));
}
}
}
protected override void InternalShow()
{
ImGui.PushStyleVar(.WindowMinSize, ImGui.Vec2(1000, 100));
if(!ImGui.Begin(s_WindowTitle, &_open, .None))
{
ImGui.PopStyleVar();
ImGui.End();
return;
}
if(_entityHierarchyWindow.SelectedEntities.Count == 1)
{
Entity entity = _entityHierarchyWindow.SelectedEntities.Front;
ShowComponents(entity);
}
ImGui.PopStyleVar();
ImGui.End();
}
private void ShowComponents(Entity entity)
{
ShowNameComponentEditor(entity);
ShowComponentEditor<TransformComponent>("Transform", entity, => ShowTransformComponentEditor);
ShowComponentEditor<CameraComponent>("Camera", entity, => ShowCameraComponentEditor, => ShowComponentContextMenu<CameraComponent>);
ShowComponentEditor<SpriterRendererComponent>("Sprite Renderer", entity, => ShowSpriteRendererComponentEditor, => ShowComponentContextMenu<SpriterRendererComponent>);
ShowAddComponentButton(entity);
}
private static void ShowComponentContextMenu<TComponent>(Entity entity, TComponent* component) where TComponent: struct, new
{
if (ImGui.Selectable("Remove Component"))
entity.RemoveComponent<TComponent>();
}
private static void ShowComponentEditor<TComponent>(String header, Entity entity, function void(Entity, TComponent*) showComponentEditor, function void(Entity, TComponent*) showComponentContextMenu = null) where TComponent: struct, new
{
if (!entity.HasComponent<TComponent>())
return;
TComponent* component = entity.GetComponent<TComponent>();
ImGui.PushID(header);
bool nodeOpen = ImGui.TreeNodeEx(header.CStr(), .DefaultOpen | .AllowItemOverlap | .Framed | .SpanFullWidth);
if (showComponentContextMenu != null)
{
ImGui.SameLine(ImGui.GetWindowContentRegionMax().x - ImGui.CalcTextSize("...").x - 2 * ImGui.GetStyle().FramePadding.x);
if (ImGui.SmallButton("..."))
{
ImGui.OpenPopup("component_popup");
}
if (ImGui.BeginPopup("component_popup"))
{
showComponentContextMenu(entity, component);
ImGui.EndPopup();
}
}
if (nodeOpen)
{
showComponentEditor(entity, component);
ImGui.TreePop();
}
ImGui.PopID();
}
private static void ShowNameComponentEditor(Entity entity)
{
if (!entity.HasComponent<DebugNameComponent>())
return;
char8[256] nameBuffer = default;
DebugNameComponent* component = entity.GetComponent<DebugNameComponent>();
String name = null;
if(component != null)
{
name = component.DebugName;
}
else
{
name = scope:: $"Entity {entity.Handle.[Friend]Index}";
}
// Copy name to buffer
Internal.MemCpy(&nameBuffer, name.Ptr, Math.Min(nameBuffer.Count, name.Length));
if(ImGui.InputText("Name", &nameBuffer, nameBuffer.Count))
{
if(component == null)
{
component = entity.AddComponent<DebugNameComponent>();
}
component.DebugName.Clear();
component.DebugName.Append(&nameBuffer);
}
}
private static void ShowTransformComponentEditor(Entity entity, TransformComponent* transform)
{
float textWidth = ImGui.CalcTextSize("Position".CStr()).x;
textWidth = Math.Max(textWidth, ImGui.CalcTextSize("Rotation".CStr()).x);
textWidth = Math.Max(textWidth, ImGui.CalcTextSize("Scale".CStr()).x);
textWidth += ImGui.GetStyle().FramePadding.x * 3.0f;
Vector3 position = transform.Position;
if (ImGui.EditVector3("Position", ref position, .Zero, 0.1f, textWidth))
transform.Position = position;
Vector3 rotationEuler = MathHelper.ToDegrees(transform.EditorRotationEuler);
if (ImGui.EditVector3("Rotation", ref rotationEuler, .Zero, 0.1f, textWidth))
transform.EditorRotationEuler = MathHelper.ToRadians(rotationEuler);
Vector3 scale = transform.Scale;
if (ImGui.EditVector3("Scale", ref scale, .One, 0.1f, textWidth))
transform.Scale = scale;
}
static String[] strings = new String[]("Orthographic", "Perspective", "Perspective (Infinite)") ~ delete _;
private static void ShowCameraComponentEditor(Entity entity, CameraComponent* cameraComponent)
{
ImGui.Checkbox("Primary", &cameraComponent.Primary);
var camera = ref cameraComponent.Camera;
String typeName = strings[camera.ProjectionType.Underlying];
if (ImGui.BeginCombo("Projection", typeName.CStr()))
{
for (int i = 0; i < 3; i++)
{
bool isSelected = (typeName == strings[i]);
if (ImGui.Selectable(strings[i], isSelected))
{
camera.ProjectionType = (.)i;
}
if (isSelected)
ImGui.SetItemDefaultFocus();
}
ImGui.EndCombo();
}
if (camera.ProjectionType == .Perspective)
{
float fovY = MathHelper.ToDegrees(camera.PerspectiveFovY);
if (ImGui.DragFloat("Fov Y", &fovY, 0.1f))
camera.PerspectiveFovY = MathHelper.ToRadians(fovY);
float near = camera.PerspectiveNearPlane;
if (ImGui.DragFloat("Near", &near, 0.1f))
camera.PerspectiveNearPlane = near;
float far = camera.PerspectiveFarPlane;
if (ImGui.DragFloat("Far", &far, 0.1f))
camera.PerspectiveFarPlane = far;
}
else if (camera.ProjectionType == .InfinitePerspective)
{
float fovY = MathHelper.ToDegrees(camera.PerspectiveFovY);
if (ImGui.DragFloat("Vertical FOV", &fovY, 0.1f))
camera.PerspectiveFovY = MathHelper.ToRadians(fovY);
float near = camera.PerspectiveNearPlane;
if (ImGui.DragFloat("Near", &near, 0.1f))
camera.PerspectiveNearPlane = near;
}
else if (camera.ProjectionType == .Orthographic)
{
float size = camera.OrthographicHeight;
if (ImGui.DragFloat("Size", &size, 0.1f))
camera.OrthographicHeight = size;
float near = camera.OrthographicNearPlane;
if (ImGui.DragFloat("Near", &near, 0.1f))
camera.OrthographicNearPlane = near;
float far = camera.OrthographicFarPlane;
if (ImGui.DragFloat("Far", &far, 0.1f))
camera.OrthographicFarPlane = far;
}
bool fixedAspectRatio = camera.FixedAspectRatio;
if (ImGui.Checkbox("Fixed Aspect Ratio", &fixedAspectRatio))
camera.FixedAspectRatio = fixedAspectRatio;
if (fixedAspectRatio)
{
float aspect = camera.AspectRatio;
if (ImGui.DragFloat("Aspect Ratio", &aspect, 0.1f))
camera.AspectRatio = aspect;
}
}
private static void ShowSpriteRendererComponentEditor(Entity entity, SpriterRendererComponent* spriteRendererComponent)
{
ImGui.ColorEdit4("Color", ref spriteRendererComponent.Color);
}
private static void ShowAddComponentButton(Entity entity)
{
static char8[128] searchBuffer = .();
static StringView searchFilter = .();
static float buttonWidth = 100;
ImGui.NewLine();
ImGui.Separator();
ImGui.NewLine();
void ShowComponentButton<TComponent>(String name) where TComponent : struct, new
{
float textWidth = ImGui.CalcTextSize(name.CStr()).x;
buttonWidth = Math.Max(buttonWidth, textWidth + ImGui.GetStyle().FramePadding.x * 2);
if (name.Contains(searchFilter, true) && ImGui.Selectable(name))
{
if (!entity.HasComponent<TComponent>())
entity.AddComponent<TComponent>();
}
}
float textWidth = ImGui.CalcTextSize("Add Component...").x;
buttonWidth = Math.Max(buttonWidth, textWidth + ImGui.GetStyle().FramePadding.x * 2);
ImGui.PushItemWidth(buttonWidth);
ImGui.NewLine();
ImGui.SameLine(ImGui.GetContentRegionMax().x / 2 - buttonWidth / 2);
if (ImGui.BeginCombo("##add_component_combo", "Add Component...", .NoArrowButton))
{
if (ImGui.InputText("##search_component_name", &searchBuffer, (.)searchBuffer.Count))
{
searchFilter = .(&searchBuffer);
}
ImGui.Separator();
ShowComponentButton<CameraComponent>("Camera");
ShowComponentButton<SpriterRendererComponent>("Sprite Renderer");
ImGui.EndCombo();
}
ImGui.PopItemWidth();
}
}
}
@@ -1,31 +0,0 @@
namespace GlitchyEditor.EditWindows
{
abstract class EditorWindow
{
protected Editor _editor;
protected bool _open = true;
protected bool _hasFocus;
public bool Open
{
get => _open;
set => _open = value;
}
public bool HasFocus
{
get => _hasFocus;
}
public void Show()
{
if(!_open)
return;
InternalShow();
}
protected abstract void InternalShow();
}
}
@@ -1,477 +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 : EditorWindow
{
public const String s_WindowTitle = "Entity Hierarchy";
/// Buffer for the entity search string.
private char8[64] _entitySearchChars;
private Scene _scene;
private List<Entity> _selectedEntities = new .() ~ delete _;
public List<Entity> SelectedEntities => _selectedEntities;
public this(Scene scene)
{
SetContext(scene);
}
public void SetContext(Scene scene)
{
_scene = scene;
}
protected override void InternalShow()
{
if(!ImGui.Begin(s_WindowTitle, &_open, .MenuBar))
{
ImGui.End();
return;
}
ShowEntityHierarchyMenuBar();
if (ImGui.BeginPopupContextWindow(s_WindowTitle))
{
Show_ContextMenu_Create(true, false, false);
ImGui.EndPopup();
}
ShowEntityHierarchy();
if ((ImGui.IsMouseDown(.Left) || ImGui.IsMouseDown(.Right)) && !ImGui.IsAnyItemHovered() && !ImGui.GetIO().KeyCtrl && ImGui.IsWindowHovered(.AllowWhenBlockedByPopup))
_selectedEntities.Clear();
ImGui.End();
}
/// Returns whether or not all selected entities have the same parent.
internal bool AllSelectionsOnSameLevel()
{
EcsEntity? parent = .InvalidEntity;
for(var selectedEntity in _selectedEntities)
{
var transformComponent = selectedEntity.GetComponent<TransformComponent>();
if(parent == .InvalidEntity)
{
parent = transformComponent.Parent;
}
else if(transformComponent.Parent != parent)
{
return false;
}
}
return true;
}
/// Finds all children of the given entity and stores their IDs in the given list.
internal void FindChildren(EcsEntity entity, List<EcsEntity> entities)
{
for(var (child, childTransform) in _scene.[Friend]_ecsWorld.Enumerate<TransformComponent>())
{
if(childTransform.Parent == entity)
{
if(!entities.Contains(child))
entities.Add(child);
FindChildren(child, entities);
}
}
}
/// Deletes all selected entities and their children.
internal void DeleteSelectedEntities()
{
for (var entity in _selectedEntities)
{
_scene.DestroyEntity(entity, true);
}
}
private void ShowEntityHierarchyMenuBar()
{
if(ImGui.BeginMenuBar())
{
Show_ContextMenu_Create(true, true, true);
Show_ContextMenu_Delete();
if(ImGui.MenuItem("Delete", null, false, !_selectedEntities.IsEmpty) ||
(Input.IsKeyPressed(.Delete) && ImGui.IsWindowHovered()))
{
DeleteSelectedEntities();
}
if(ImGui.IsItemHovered())
ImGui.SetTooltip("Deletes the selected Entities and their children.");
ImGui.Text("Search:");
ImGui.InputText(String.Empty, &_entitySearchChars, (.)_entitySearchChars.Count);
ImGui.EndMenuBar();
}
}
/// Creates a new entity that is a child of the given entity.
private void CreateChild(Entity? entity)
{
var newEntity = _scene.CreateEntity();
var transformCmp = newEntity.GetComponent<TransformComponent>();
// Last entity in list is the entity that has been selected last.
transformCmp.Parent = entity?.Handle ?? .InvalidEntity;
}
/// Creates a new entity that is a parent of the selected entities.
private void CreateParent()
{
if (_selectedEntities.IsEmpty || !AllSelectionsOnSameLevel())
{
Log.EngineLogger.Error("Cannot create parent entity.");
return;
}
var commonParent = _selectedEntities.Front.GetComponent<TransformComponent>();
var newEntity = _scene.CreateEntity();
if(commonParent != null)
{
// parent of selected entities is parent of the new entity.
// (which is why this doesn't work if the entities don't have the same parent)
var newEntityTransform = newEntity.GetComponent<TransformComponent>();
newEntityTransform.Parent = commonParent.Parent;
}
// new entity is parent of all selected entities.
for(var selectedEntity in _selectedEntities)
{
var selectedTransform = selectedEntity.GetComponent<TransformComponent>();
selectedTransform.Parent = newEntity.Handle;
}
}
private void Show_ContextMenu_Create(bool allowEmpty = true, bool allowChild = true, bool allowParent = true)
{
if (ImGui.BeginMenu("Create"))
{
if (allowEmpty)
{
if(ImGui.MenuItem("Empty Entity"))
{
if (_selectedEntities.IsEmpty)
_scene.CreateEntity();
else
{
Entity? parent = _selectedEntities.Back.Parent;
CreateChild(parent);
}
}
if(ImGui.IsItemHovered())
{
ImGui.SetTooltip("Create a new Entity.");
}
}
if (allowChild)
{
if(ImGui.MenuItem("Empty Child", null, false, !_selectedEntities.IsEmpty))
{
CreateChild(_selectedEntities.Back);
}
if(ImGui.IsItemHovered())
ImGui.SetTooltip("Create a new Entity that is a child of the selected entity.");
}
if (allowParent)
{
if(ImGui.MenuItem("Parent", null, false, !_selectedEntities.IsEmpty && AllSelectionsOnSameLevel()))
{
CreateParent();
}
if(ImGui.IsItemHovered())
ImGui.SetTooltip("Create a new Entity that is the parent of the selected entities.");
}
ImGui.EndMenu();
}
if(ImGui.IsItemHovered())
ImGui.SetTooltip("Create a new Entity.");
}
private bool Show_ContextMenu_Delete()
{
bool deleted = false;
if(ImGui.MenuItem("Delete", null, false, !_selectedEntities.IsEmpty))
{
DeleteSelectedEntities();
deleted = true;
}
if(ImGui.IsItemHovered())
ImGui.SetTooltip("Deletes the selected Entities and their children.");
return deleted;
}
private void ImGuiPrintEntityTree(TreeNode<Entity> tree)
{
String name = null;
var nameComponent = tree.Value.GetComponent<DebugNameComponent>();
if(nameComponent != null)
{
name = nameComponent.DebugName;
}
else
{
name = scope:: $"Entity {(tree.Value.Handle.[Friend]Index)}";
}
ImGui.TreeNodeFlags flags = .OpenOnArrow | .DefaultOpen | .SpanAvailWidth;
if(tree.Children.Count == 0)
flags |= .Leaf;
bool inSelectedList = _selectedEntities.Contains(tree.Value);
if(inSelectedList)
flags |= .Selected;
bool isOpen = ImGui.TreeNodeEx((void*)(uint)tree.Value.Handle.[Friend]Index, flags, $"{name}");
ImGui.PushID((void*)(uint)tree.Value.Handle.[Friend]Index);
bool deleted = false;
if (ImGui.BeginPopupContextItem("treeNodePopup"))
{
Show_ContextMenu_Create(true, true, true);
deleted = Show_ContextMenu_Delete();
ImGui.EndPopup();
}
ImGui.PopID();
if (deleted)
return;
if(ImGui.BeginDragDropSource())
{
ImGui.SetDragDropPayload("DND_Entity", &tree.Value, sizeof(Entity));
ImGui.Text(name);
ImGui.EndDragDropSource();
}
if(ImGui.BeginDragDropTarget())
{
ImGui.Payload* payload = ImGui.AcceptDragDropPayload("DND_Entity");
if(payload != null)
{
Log.ClientLogger.AssertDebug(payload.DataSize == sizeof(Entity));
Entity movedEntity = *(Entity*)payload.Data;
bool dropLegal = true;
Entity walker = tree.Value;
// make sure the dropped entity is not a parent of the entity we dropped it on.
while(true)
{
var parentTransform = walker.GetComponent<TransformComponent>();
if(parentTransform.Parent == .InvalidEntity)
{
dropLegal = true;
break;
}
else if(parentTransform.Parent == movedEntity.Handle)
{
dropLegal = false;
break;
}
walker = .(parentTransform.Parent, _scene);
}
if(dropLegal)
{
var movedEntityTransform = movedEntity.GetComponent<TransformComponent>();
movedEntityTransform.Parent = tree.Value.Handle;
}
}
ImGui.EndDragDropTarget();
}
bool clicked = ImGui.IsItemClicked(.Left);
bool clickedRight = ImGui.IsItemClicked(.Right);
if(isOpen)
{
for(var child in tree.Children)
{
ImGuiPrintEntityTree(child);
}
ImGui.TreePop();
}
if (clicked || clickedRight)
{
if (inSelectedList && !clickedRight)
{
_selectedEntities.Remove(tree.Value);
inSelectedList = false;
}
else
{
if (!ImGui.GetIO().KeyCtrl && !clickedRight)
{
_selectedEntities.Clear();
}
_selectedEntities.Add(tree.Value);
inSelectedList = true;
}
}
}
private void ShowEntityHierarchy()
{
StringView searchString = StringView(&_entitySearchChars);
if(searchString.IsWhiteSpace)
{
// Show entity hierarchy as tree
TreeNode<Entity> root = scope .(Entity(.InvalidEntity, _scene));
TreeNode<Entity> InsertIntoTree(Entity entity)
{
var transform = entity.GetComponent<TransformComponent>();
if(transform == null)
{
return root.AddChild(entity);
}
else
{
var parentEntity = Entity(transform.Parent, _scene);
var parentNode = root.FindNode(parentEntity);
if(parentNode == null)
parentNode = InsertIntoTree(parentEntity);
return parentNode.AddChild(entity);
}
}
for(var entityId in _scene.[Friend]_ecsWorld.Enumerate())
{
Entity entity = .(entityId, _scene);
//if (!entity.HasComponent<EditorComponent>())
InsertIntoTree(entity);
}
if(ImGui.TreeNodeEx("Scene", .DefaultOpen))
{
if(ImGui.BeginDragDropTarget())
{
ImGui.Payload* payload = ImGui.AcceptDragDropPayload("DND_Entity");
if(payload != null)
{
Log.ClientLogger.AssertDebug(payload.DataSize == sizeof(Entity));
Entity movedEntity = *(Entity*)payload.Data;
// Also mark transform as dirty
var transformComponent = movedEntity.GetComponent<TransformComponent>();
transformComponent.Parent = .InvalidEntity;
//transformComponent?.IsDirty = true;
}
ImGui.EndDragDropTarget();
}
for(var child in root.Children)
{
ImGuiPrintEntityTree(child);
}
ImGui.TreePop();
}
}
// Otherwise
else
{
// Show search results as flat list
List<StringView> searchTokens = new:ScopedAlloc! .(searchString.Split(' ', .RemoveEmptyEntries));
worldEnumeration:
for(var entityId in _scene.[Friend]_ecsWorld.Enumerate())
{
Entity entity = .(entityId, _scene);
String name = null;
var nameComponent = entity.GetComponent<DebugNameComponent>();
if(nameComponent != null)
{
name = nameComponent.DebugName;
}
else
{
name = scope:worldEnumeration $"Entity {entityId.[Friend]Index}";
}
StringView nameView = StringView(name);
for(var token in searchTokens)
{
if(nameView.IndexOf(token, true) == -1)
{
continue worldEnumeration;
}
}
ImGuiPrintEntityTree(scope .(entity));
}
}
}
}
}
@@ -1,117 +0,0 @@
using System;
using ImGui;
using GlitchyEngine.Renderer;
using GlitchyEngine.Math;
using GlitchyEngine;
using GlitchyEngine.World;
using ImGuizmo;
namespace GlitchyEditor.EditWindows
{
class SceneViewportWindow : EditorWindow
{
//public OldCamera _camera;
public const String s_WindowTitle = "Scene";
private RenderTarget2D _renderTarget ~ _?.ReleaseRef();
public Event<EventHandler<Vector2>> ViewportSizeChangedEvent ~ _.Dispose();
public RenderTarget2D RenderTarget
{
get => _renderTarget;
set
{
if(_renderTarget == value)
return;
SetReference!(_renderTarget, value);
}
}
public this(Editor editor)
{
_editor = editor;
}
private ImGui.Vec2 oldViewportSize;
private bool viewPortChanged;
public Entity CameraEntity { get; set; }
protected override void InternalShow()
{
ImGui.PushStyleVar(.WindowPadding, ImGui.Vec2(1, 1));
defer ImGui.PopStyleVar();
if(!ImGui.Begin(s_WindowTitle, &_open, .NoScrollbar))
{
ImGui.End();
return;
}
if(ImGui.IsWindowHovered() && Input.IsMouseButtonPressing(.RightButton))
{
var currentWindow = ImGui.GetCurrentWindow();
ImGui.FocusWindow(currentWindow);
}
_hasFocus = ImGui.IsWindowFocused();
var viewportSize = ImGui.GetContentRegionAvail();
if(_renderTarget != null)
{
ImGui.Image(_renderTarget, viewportSize);
}
DrawImGuizmo(viewportSize);
ImGui.End();
if(oldViewportSize != viewportSize)
{
ViewportSizeChangedEvent.Invoke(this, (Vector2)viewportSize);
viewPortChanged = true;
oldViewportSize = viewportSize;
}
}
private void DrawImGuizmo(ImGui.Vec2 viewportSize)
{
ImGuizmo.SetDrawlist();
var topLeft = ImGui.GetWindowPos();
var cntMin = ImGui.GetWindowContentRegionMin();
topLeft.x += cntMin.x;
topLeft.y += cntMin.y;
ImGuizmo.SetRect(topLeft.x, topLeft.y, viewportSize.x, viewportSize.y);
var cameraTransformCmp = CameraEntity.GetComponent<TransformComponent>();
var view = cameraTransformCmp.WorldTransform.Invert();
var cameraCmp = CameraEntity.GetComponent<CameraComponent>();
var projection = cameraCmp.Camera.Projection;
Matrix mat = .Identity;
ImGuizmo.DrawGrid((.)&view, (.)&projection, (.)&mat, 10);
if(_editor.SelectedEntities.Count > 0)
{
var entity = _editor.SelectedEntities.Front;
var transformCmp = _editor.World.GetComponent<TransformComponent>(entity);
var transform = transformCmp.LocalTransform;
ImGuizmo.SetRect(topLeft.x, topLeft.y, viewportSize.x, viewportSize.y);
ImGuizmo.Manipulate((.)&view, (.)&projection, .TRANSLATE, .LOCAL, (.)&transform);
transformCmp.LocalTransform = transform;
}
}
}
}
-136
View File
@@ -1,136 +0,0 @@
using GlitchyEngine.World;
using ImGui;
using System;
using System.Collections;
using GlitchyEngine.Collections;
using GlitchyEditor.EditWindows;
using GlitchyEngineHelper;
using System.IO;
using GlitchyEngineHelper.DotNet;
namespace GlitchyEditor
{
class Editor
{
private EcsWorld _ecsWorld;
private Scene _scene;
private EntityHierarchyWindow _entityHierarchyWindow ~ delete _;
private ComponentEditWindow _componentEditWindow ~ delete _;
private SceneViewportWindow _sceneViewportWindow = new .(this) ~ delete _;
private List<EcsEntity> _selectedEntities = new .() ~ delete _;
public EcsWorld World => _ecsWorld;
public List<EcsEntity> SelectedEntities => _selectedEntities;
public EntityHierarchyWindow EntityHierarchyWindow => _entityHierarchyWindow;
public ComponentEditWindow ComponentEditWindow => _componentEditWindow;
public SceneViewportWindow SceneViewportWindow => _sceneViewportWindow;
/// Creates a new editor for the given world
public this(Scene scene)
{
String exePath = Environment.GetExecutableFilePath(.. scope String());
String exeDir = Path.GetDirectoryPath(exePath, .. scope String());
String assemblyPath = scope String(exeDir, "/DotNetScriptingHelper.dll");
DotNetContext dotty = new DotNetContext(assemblyPath);
defer delete dotty;
dotty.Init();
dotty.GetFunctionPointerUnmanagedCallersOnly("DotNetScriptingHelper.ScriptableEntity, DotNetScriptingHelper", "CreateInstance", out DotNetScriptComponent.CreateInstanceFn);
dotty.GetFunctionPointerUnmanagedCallersOnly("DotNetScriptingHelper.ScriptableEntity, DotNetScriptingHelper", "UpdateEntity", out DotNetScriptComponent.UpdateInstanceFn);
dotty.GetFunctionPointerUnmanagedCallersOnly("DotNetScriptingHelper.ScriptableEntity, DotNetScriptingHelper", "DestroyEntity", out DotNetScriptComponent.DestroyInstanceFn);
_scene = scene;
_ecsWorld = _scene.[Friend]_ecsWorld;
_entityHierarchyWindow = new EntityHierarchyWindow(_scene);
_componentEditWindow = new ComponentEditWindow(_entityHierarchyWindow);
}
public void Update()
{
_entityHierarchyWindow.Show();
_componentEditWindow.Show();
_sceneViewportWindow.Show();
}
/// Creates a new entity with a transform component.
internal EcsEntity CreateEntityWithTransform()
{
var entity = _ecsWorld.NewEntity();
var transformComponent = ref *_ecsWorld.AssignComponent<TransformComponent>(entity);
transformComponent = TransformComponent();
var nameComponent = ref *_ecsWorld.AssignComponent<DebugNameComponent>(entity);
nameComponent.SetName("Entity");
return entity;
}
/// Returns whether or not all selected entities have the same parent.
internal bool AllSelectionsOnSameLevel()
{
EcsEntity? parent = .InvalidEntity;
for(var selectedEntity in _selectedEntities)
{
var parentComponent = _ecsWorld.GetComponent<ParentComponent>(selectedEntity);
if(parent == .InvalidEntity)
{
parent = parentComponent?.Entity;
}
else if(parentComponent?.Entity != parent)
{
return false;
}
}
return true;
}
/// Finds all children of the given entity and stores their IDs in the given list.
internal void FindChildren(EcsEntity entity, List<EcsEntity> entities)
{
for(var (child, childParent) in _ecsWorld.Enumerate<ParentComponent>())
{
if(childParent.Entity == entity)
{
if(!entities.Contains(child))
entities.Add(child);
FindChildren(child, entities);
}
}
}
/// Deletes all selected entities and their children.
internal void DeleteSelectedEntities()
{
List<EcsEntity> entities = scope .();
for(var entity in _selectedEntities)
{
entities.Add(entity);
FindChildren(entity, entities);
}
for(var entity in entities)
{
_ecsWorld.RemoveEntity(entity);
}
_selectedEntities.Clear();
}
}
}
-19
View File
@@ -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,63 +0,0 @@
using GlitchyEngine;
using GlitchyEngine.Math;
using GlitchyEngine.World;
namespace GlitchyEditor
{
class EditorCameraController : ScriptableEntity
{
private float _cameraTranslationSpeed = 2.0f;
private float _cameraRotationSpeedX = 0.001f;
private float _cameraRotationSpeedY = 0.001f;
public bool IsEnabled = false;
protected override void OnUpdate(GameTime gt)
{
if (!IsEnabled)
return;
Debug.Profiler.ProfileFunction!();
Vector3 movement = .();
if(Input.IsKeyPressed(Key.W))
movement.Z += 1;
if(Input.IsKeyPressed(Key.S))
movement.Z -= 1;
if(Input.IsKeyPressed(Key.A))
movement.X -= 1;
if(Input.IsKeyPressed(Key.D))
movement.X += 1;
if(Input.IsKeyPressed(Key.Space))
movement.Y += 1;
if(Input.IsKeyPressed(Key.Control))
movement.Y -= 1;
var transformComponent = transform;
if(movement != .Zero)
{
movement.Normalize();
movement *= (float)(gt.FrameTime.TotalSeconds) * _cameraTranslationSpeed;
Matrix view = transformComponent.WorldTransform.Invert();
Vector4 delta = Vector4(movement, 1.0f) * view;
transformComponent.Position = transformComponent.Position + delta.XYZ;
}
// Camera rotation
var mouseDelta = Input.GetMouseMovement();
float rotY = mouseDelta.X * _cameraRotationSpeedX;
float rotX = mouseDelta.Y * _cameraRotationSpeedY;
transformComponent.RotationEuler = transformComponent.RotationEuler + .(rotX, rotY, 0);
}
}
}
-270
View File
@@ -1,270 +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();
BlendState _alphaBlendState ~ _.ReleaseRef();
BlendState _opaqueBlendState ~ _.ReleaseRef();
DepthStencilState _depthStencilState ~ _.ReleaseRef();
Scene _scene = new Scene() ~ delete _;
Editor _editor ~ delete _;
RenderTarget2D _viewportTarget ~ _?.ReleaseRef();
SettingsWindow _settingsWindow = new .() ~ delete _;
Entity _cameraEntity;
Entity _otherCameraEntity;
class CameraController : ScriptableEntity
{
protected override void OnCreate()
{
Log.EngineLogger.Trace("Cam controller created!");
}
protected override void OnUpdate(GameTime gameTime)
{
var transformCmp = GetComponent<TransformComponent>();
Vector3 position = transformCmp.Position;
if (Input.IsKeyPressed(Key.A))
{
position.X -= gameTime.DeltaTime;
}
if (Input.IsKeyPressed(Key.D))
{
position.X += gameTime.DeltaTime;
}
if (Input.IsKeyPressed(Key.W))
{
position.Y += gameTime.DeltaTime;
}
if (Input.IsKeyPressed(Key.S))
{
position.Y -= gameTime.DeltaTime;
}
transformCmp.Position = position;
}
protected override void OnDestroy()
{
Log.EngineLogger.Trace("Cam controller destroyed!");
}
}
public this() : base("Example")
{
Application.Get().Window.IsVSync = false;
InitGraphics();
{
_cameraEntity = _scene.CreateEntity("Camera Entity");
let camera = _cameraEntity.AddComponent<CameraComponent>();
camera.Camera.SetPerspective(MathHelper.ToRadians(75), 0.1f, 10000.0f);
camera.Primary = true;
camera.FixedAspectRatio = false;
let transform = _cameraEntity.GetComponent<TransformComponent>();
transform.Position = .(0, 0, -5);
_cameraEntity.AddComponent<NativeScriptComponent>().Bind<EditorCameraController>();
_cameraEntity.AddComponent<EditorComponent>();
}
{
_otherCameraEntity = _scene.CreateEntity("Other Camera Entity");
let camera = _otherCameraEntity.AddComponent<CameraComponent>();
camera.Camera.SetPerspective(MathHelper.ToRadians(45), 0.1f, 1000.0f);
camera.Primary = false;
camera.FixedAspectRatio = false;
let transform = _otherCameraEntity.GetComponent<TransformComponent>();
transform.Position = .(0, 0, -5);
_otherCameraEntity.AddComponent<NativeScriptComponent>().Bind<EditorCameraController>();
_otherCameraEntity.AddComponent<EditorComponent>();
}
InitEditor();
}
private void InitGraphics()
{
_context = Application.Get().Window.Context..AddRef();
RasterizerStateDescription rsDesc = .(.Solid, .Back, true);
_rasterizerState = new RasterizerState(rsDesc);
rsDesc.FrontCounterClockwise = false;
_rasterizerStateClockWise = new RasterizerState(rsDesc);
BlendStateDescription blendDesc = .();
blendDesc.RenderTarget[0] = .(true, .SourceAlpha, .InvertedSourceAlpha, .Add, .SourceAlpha, .InvertedSourceAlpha, .Add, .All);
_alphaBlendState = new BlendState(blendDesc);
_opaqueBlendState = new BlendState(.Default);
DepthStencilStateDescription dsDesc = .();
_depthStencilState = new DepthStencilState(dsDesc);
_viewportTarget = new RenderTarget2D(RenderTarget2DDescription(.R8G8B8A8_UNorm, 100, 100) {DepthStencilFormat = .D32_Float});
_viewportTarget.SamplerState = SamplerStateManager.LinearClamp;
}
private void InitEditor()
{
_editor = new Editor(_scene);
_editor.SceneViewportWindow.ViewportSizeChangedEvent.Add(new (s, e) => ViewportSizeChanged(s, e));
//_editor.[Friend]CreateEntityWithTransform();
_editor.SceneViewportWindow.CameraEntity = _cameraEntity;
}
public override void Update(GameTime gameTime)
{
var scriptComponent = _cameraEntity.GetComponent<NativeScriptComponent>();
if (var camController = scriptComponent.Instance as EditorCameraController)
{
camController.IsEnabled = (_editor.SceneViewportWindow.HasFocus && Input.IsMouseButtonPressed(.RightButton));
}
//TransformSystem.Update(_world);
RenderCommand.Clear(_viewportTarget, .Color | .Depth, .(0.2f, 0.2f, 0.2f), 1.0f, 0);
RenderCommand.SetRenderTarget(_viewportTarget, 0, true);
RenderCommand.BindRenderTargets();
RenderCommand.SetViewport(Viewport(0, 0, _viewportTarget.Width, _viewportTarget.Height));
RenderCommand.SetBlendState(_alphaBlendState);
RenderCommand.SetDepthStencilState(_depthStencilState);
//Renderer.BeginScene(_cameraController.Camera);
//DebugRenderer.Render(_scene.[Friend]_ecsWorld);
//Renderer.EndScene();
_scene.Update(gameTime);
RenderCommand.Clear(null, .Color | .Depth, .(0.2f, 0.2f, 0.2f), 1.0f, 0);
RenderCommand.SetRenderTarget(null, 0, true);
RenderCommand.BindRenderTargets();
RenderCommand.SetViewport(_context.SwapChain.BackbufferViewport);
}
public override void OnEvent(Event event)
{
EventDispatcher dispatcher = EventDispatcher(event);
dispatcher.Dispatch<ImGuiRenderEvent>(scope (e) => OnImGuiRender(e));
dispatcher.Dispatch<WindowResizeEvent>(scope (e) => OnWindowResize(e));
}
ImGui.ID _mainDockspaceId;
private bool OnImGuiRender(ImGuiRenderEvent event)
{
ImGui.Begin("Test");
static bool cameraA = true;
if (ImGui.Checkbox("Camera A", &cameraA))
{
_cameraEntity.GetComponent<CameraComponent>().Primary = cameraA;
_otherCameraEntity.GetComponent<CameraComponent>().Primary = !cameraA;
}
ImGui.End();
ImGui.Viewport* viewport = ImGui.GetMainViewport();
ImGui.DockSpaceOverViewport(viewport);
DrawMainMenuBar();
_editor.SceneViewportWindow.RenderTarget = _viewportTarget;
_editor.Update();
_settingsWindow.Show();
return false;
}
private void DrawMainMenuBar()
{
ImGui.BeginMainMenuBar();
if(ImGui.BeginMenu("File", true))
{
if (ImGui.MenuItem("Settings"))
_settingsWindow.Open = true;
ImGui.EndMenu();
}
if(ImGui.BeginMenu("View", true))
{
if(ImGui.MenuItem(EntityHierarchyWindow.s_WindowTitle))
{
_editor.EntityHierarchyWindow.Open = true;
}
if(ImGui.MenuItem(ComponentEditWindow.s_WindowTitle))
{
_editor.ComponentEditWindow.Open = true;
}
if(ImGui.MenuItem(SceneViewportWindow.s_WindowTitle))
{
_editor.SceneViewportWindow.Open = true;
}
ImGui.EndMenu();
}
ImGui.EndMainMenuBar();
}
private bool OnWindowResize(WindowResizeEvent e)
{
return false;
}
private void ViewportSizeChanged(Object sender, Vector2 viewportSize)
{
uint32 sizeX = (uint32)viewportSize.X;
uint32 sizeY = (uint32)viewportSize.Y;
if(sizeX == 0 || sizeY == 0)
return;
_viewportTarget.Resize(sizeX, sizeY);
_scene.OnViewportResize(sizeX, sizeY);
}
}
}
-253
View File
@@ -1,253 +0,0 @@
using GlitchyEditor.EditWindows;
using ImGui;
using GlitchyEngine;
using System;
using System.Collections;
using System.Reflection;
namespace GlitchyEditor
{
class SettingsWindow : EditorWindow
{
class Binding
{
public Object SettingsObject;
public String Name ~ delete _;
public String FieldName ~ delete _;
public this(StringView name, StringView fieldName, Object settingsObject)
{
Name = new String(name);
FieldName = new String(fieldName);
SettingsObject = settingsObject;
}
}
class Category
{
public List<Binding> _bindings = new .() ~ DeleteContainerAndItems!(_);
public String Header ~ delete _;
public Object SettingsObject;
public this(String header)
{
Header = new String(header);
}
public void AddSetting(StringView name, StringView fieldName, Object settingsObject = null)
{
Binding binding = new .(name, fieldName, settingsObject ?? SettingsObject);
_bindings.Add(binding);
}
}
Settings _settings;
bool _settingsChanged = false;
private Dictionary<String, Category> _categories = new .() ~ DeleteDictionaryAndValues!(_);
public this()
{
_open = false;
_settings = Application.Get().Settings;
Create();
}
void Create()
{
ScanForSettings(_settings);
/*for (ISettings settings in _settings.[Friend]_userSettings)
{
ScanForSettings(settings);
}*/
}
Category AddCategory(String header)
{
if (_categories.TryGetValue(header, let category))
return category;
Category newCat = new Category(header);
_categories.Add(newCat.Header, newCat);
return newCat;
}
void ScanForSettings(Object container)
{
Type type = container.GetType();
for (var field in type.GetFields())
{
Result<SettingAttribute> settingResult = field.GetCustomAttribute<SettingAttribute>();
if (settingResult case .Ok(let settingInfo))
{
AddSetting(settingInfo.Category, settingInfo.Name, field.Name, container);
}
Result<SettingContainerAttribute> containerResult = field.GetCustomAttribute<SettingContainerAttribute>();
if (containerResult case .Ok(let containerInfo))
{
var res = field.GetValue<Object>(container, let childContainer);
if (res case .Err(let error))
{
Log.EngineLogger.Error($"Failed to get settings container. Error: {error}");
continue;
}
ScanForSettings(childContainer);
}
}
}
void AddSetting(String categoryName, String name, StringView fieldName, Object container)
{
Category category = AddCategory(categoryName);
category.AddSetting(name, fieldName, container);
}
protected override void InternalShow()
{
ImGui.Begin("Settings", &_open, .NoDocking);
defer ImGui.End();
// Leave room for 1 line below us
ImGui.BeginChild("item view", ImGui.Vec2(0, -ImGui.GetFrameHeightWithSpacing()));
ImGui.BeginTabBar("##Tabs");
for (Category category in _categories.Values)
{
if (ImGui.BeginTabItem(category.Header))
{
ImGui.Columns(2);
defer ImGui.Columns(1);
ImGui.SetColumnWidth(0, 100);
for (Binding setting in category._bindings)
{
ImGui.TextUnformatted(setting.Name);
ImGui.NextColumn();
Type settingsObjectType = setting.SettingsObject.GetType();
Result<FieldInfo> result = settingsObjectType.GetField(setting.FieldName);
if (result case .Err)
{
ImGui.PushStyleColor(.Text, ImGui.Vec4(1f, 0f, 0f, 1f));
ImGui.Text($"Field {setting.FieldName} not found.");
ImGui.PopStyleColor();
continue;
}
FieldInfo fieldInfo = result.Get();
Type fieldType = fieldInfo.FieldType;
mixin GetSettingValue<T>()
{
var error = fieldInfo.GetValue<T>(setting.SettingsObject, var value);
if (error case .Err(let err))
{
Log.EngineLogger.Error($"Could not get value of setting {setting.FieldName}. Error: {err}");
ImGui.PushStyleColor(.Text, ImGui.Vec4(1f, 0f, 0f, 1f));
ImGui.Text($"Could not get value of setting {setting.FieldName}. Error: {err}");
ImGui.PopStyleColor();
break;
}
value
}
mixin SetSettingValue<T>(T value)
{
var error = fieldInfo.SetValue(setting.SettingsObject, value);
if (error case .Err(let err))
{
Log.EngineLogger.Error($"Could not set value of setting {setting.FieldName}. Error: {err}");
}
}
switch (fieldType)
{
case typeof(int32):
int32 value = GetSettingValue!<int32>();
if (!ImGui.InputInt(scope $"##{setting.Name}", &value))
break;
SetSettingValue!(value);
_settingsChanged = true;
case typeof(String):
String value = GetSettingValue!<String>();
char8[256] buffer = .();
value.CopyTo(buffer);
if (ImGui.InputText(scope $"##{setting.Name}", &buffer, buffer.Count))
{
value..Clear().Append(&buffer);
_settingsChanged = true;
}
}
ImGui.NextColumn();
}
ImGui.EndTabItem();
}
}
ImGui.EndTabBar();
ImGui.EndChild();
ImGui.BeginDisabled(!_settingsChanged);
if (ImGui.Button("Save"))
{
_settings.Save();
_settings.Apply();
_open = false;
}
ImGui.SameLine();
if (ImGui.Button("Apply"))
{
_settings.Apply();
}
ImGui.EndDisabled();
ImGui.SameLine();
if (ImGui.Button("Cancel"))
{
Settings.Load();
_open = false;
}
}
}
}
-7
View File
@@ -1,7 +0,0 @@
FileVersion = 1
Dependencies = {corlib = "*", GlitchyEngine = "*"}
[Project]
Name = "GlitchyEngine.Test"
TargetType = "BeefTest"
StartupObject = "GlitchyEngine.Test.Program"
-5
View File
@@ -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
View File
@@ -1,9 +1,22 @@
FileVersion = 1 FileVersion = 1
Dependencies = {GlitchLog = "*", corlib = "*", DirectX = "*", FreeType = "*", cgltf-beef = "*", msdfgen-beef = "*", ImGui = "*", ImGuiImplDX11 = "*", ImGuiImplWin32 = "*", ImGuizmo = "*", Beefy2D = "*", LodePng = "*", GlitchyEngineHelper = "*", bon = "*"} 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 = ["IMGUI", "RELEASE", "GE_PROFILE"]
[Configs.Test.Win32] [Configs.Test.Win32]
PreprocessorMacros = ["TEST", "GE_WINDOWS"] PreprocessorMacros = ["TEST", "GE_WINDOWS"]
[Configs.Test.Win64] [Configs.Test.Win64]
PreprocessorMacros = ["TEST", "GE_WINDOWS"] PreprocessorMacros = ["TEST", "GE_WINDOWS"]
[Configs.Debug.Win64]
PreprocessorMacros = ["DEBUG", "GE_PROFILE", "GE_PROFILE_RENDERER", "GE_PROFILE_RESOURCES", "IMGUI"]
+9 -118
View File
@@ -2,8 +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;
using GlitchyEngine.Content;
namespace GlitchyEngine namespace GlitchyEngine
{ {
@@ -11,102 +9,53 @@ namespace GlitchyEngine
{ {
static Application s_Instance = null; static Application s_Instance = null;
private Window _window; private Window _window ~ delete _;
private RendererAPI _rendererApi; private RendererAPI _rendererApi ~ delete _;
private EffectLibrary _effectLibrary;
private bool _running = true; private bool _running = true;
private bool _isMinimized = false;
private LayerStack _layerStack; private LayerStack _layerStack = new LayerStack() ~ delete _;
#if IMGUI
private ImGuiLayer _imGuiLayer; private ImGuiLayer _imGuiLayer;
#endif
private GameTime _gameTime; private GameTime _gameTime = new GameTime(true) ~ delete _;
private IContentManager _contentManager;
public bool IsRunning => _running; public bool IsRunning => _running;
public Window Window => _window; public Window Window => _window;
public EffectLibrary EffectLibrary => _effectLibrary;
public IContentManager ContentManager => _contentManager;
public bool IsMinimized => _isMinimized;
[Inline] [Inline]
public static Application Get() => s_Instance; public static Application Get() => s_Instance;
public Settings Settings {get; private set;} = new .() ~ delete _;
public this() public this()
{ {
Profiler.ProfileFunction!();
Log.EngineLogger.Assert(s_Instance == null, "Tried to create a second application."); Log.EngineLogger.Assert(s_Instance == null, "Tried to create a second application.");
s_Instance = this; s_Instance = this;
_layerStack = new LayerStack();
_gameTime = new GameTime(true);
_window = new Window(.Default); _window = new Window(.Default);
_window.EventCallback = new => OnEvent; _window.EventCallback = new => OnEvent;
_rendererApi = new RendererAPI(); _rendererApi = new RendererAPI();
_rendererApi.Context = _window.Context; _rendererApi.Context = _window.Context;
_contentManager = new ContentManager("./content"); SamplerStateManager.Init(_window.Context);
SamplerStateManager.Init();
RenderCommand.RendererAPI = _rendererApi; RenderCommand.RendererAPI = _rendererApi;
_effectLibrary = new EffectLibrary(); Renderer.Init(_window.Context);
Renderer.Init(_window.Context, _effectLibrary);
#if IMGUI
_imGuiLayer = new ImGuiLayer(); _imGuiLayer = new ImGuiLayer();
PushOverlay(_imGuiLayer); PushOverlay(_imGuiLayer);
#endif
GlitchyEngine.Settings.Load();
Settings.Apply();
} }
public ~this() public ~this()
{ {
Profiler.ProfileFunction!();
SamplerStateManager.Uninit(); SamplerStateManager.Uninit();
Renderer.Deinit();
delete _effectLibrary;
delete _contentManager;
delete _rendererApi;
delete _window;
delete _gameTime;
delete _layerStack;
} }
public void OnEvent(Event e) public void OnEvent(Event e)
{ {
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);
@@ -115,91 +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)
{
#if IMGUI
_imGuiLayer.ImGuiRender(); _imGuiLayer.ImGuiRender();
#endif
_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;
}
} }
} }
-48
View File
@@ -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,68 +0,0 @@
using System;
using System.IO;
using xxHash;
namespace GlitchyEngine.Content
{
class ContentId
{
private readonly String _string;
private readonly XXH64_hash _hash;
public String String => _string;
public XXH64_hash Hash => _hash;
[AllowAppend]
public this(StringView id)
{
String str = append String(id);
_string = str;
_hash = xxHash.ComputeHash(id);
}
}
interface IContentManager
{
void GetFilePath(String outFilename, String filename);
Stream GetFile(String filename);
}
class ContentManager : IContentManager
{
private String _contentRoot;
[AllowAppend]
public this(String contentRoot)
{
String cntRoot = append String(contentRoot);
_contentRoot = cntRoot;
Runtime.Assert(Directory.Exists(contentRoot), "Content root directory doesn't exist.");
}
public void GetFilePath(String outFilename, String filename)
{
Path.InternalCombine(outFilename, _contentRoot, filename);
}
public Stream GetFile(String filename)
{
String fullpath = scope .(_contentRoot.Length + 1 + filename.Length);
GetFilePath(fullpath, filename);
FileStream stream = new FileStream();
var result = stream.Open(fullpath, .Read, .Read);
if (result case .Err(let error))
{
Log.EngineLogger.Error($"Failed to open file \"{fullpath}\". Error: {error}");
return null;
}
return stream;
}
}
}
-635
View File
@@ -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, EcsEntity? parentEntity, EcsWorld world, Effect validationEffect, Material material, List<AnimationClip> clips)
{
EcsEntity entity = world.NewEntity();
#if DEBUG
var nameComponent = world.AssignComponent<DebugNameComponent>(entity);
if (node.Name != null)
{
nameComponent.SetName(StringView(node.Name));
}
else
{
nameComponent.SetName("Unnamed Node");
}
#endif
if(parentEntity.HasValue)
{
var childParent = world.AssignComponent<ParentComponent>(entity);
childParent.Entity = parentEntity.Value;
}
var childTransform = world.AssignComponent<TransformComponent>(entity);
if(node.HasMatrix)
{
childTransform.LocalTransform = *(Matrix*)&node.Matrix;
}
else
{
if(node.HasTranslation)
childTransform.Position = *(Vector3*)&node.Translation;
else
childTransform.Position = .Zero;
if(node.HasRotation)
childTransform.Rotation = *(Quaternion*)&node.Rotation;
else
childTransform.Rotation = .Identity;
if(node.HasScale)
childTransform.Scale = *(Vector3*)&node.Scale;
else
childTransform.Scale = .(1, 1, 1);
}
// Invert the Z-Axis of the root Node to convert the coordinate system from right-handed to left-handed
if(parentEntity == null)
childTransform.Scale *= .(1, 1, -1);
Skeleton skeleton = null;
if(node.Skin != null)
{
skeleton = ExtractSkeleton(node.Skin);
LoadAnimationClips(data, node.Skin, skeleton, clips);
}
if(node.Mesh != null)
{
// If we have only one primitive, add it directly to the entity
if(node.Mesh.Primitives.Length == 1)
{
var mesh = world.AssignComponent<MeshComponent>(entity);
using (var geo = PrimitiveToGeoBinding(node.Mesh.Primitives[0], validationEffect))
{
mesh.Mesh = geo;
}
if(skeleton == null)
{
var meshRenderer = world.AssignComponent<MeshRendererComponent>(entity);
meshRenderer.Material = material;
}
else
{
var meshRenderer = world.AssignComponent<SkinnedMeshRendererComponent>(entity);
meshRenderer.Material = material;
meshRenderer.Skeleton = skeleton;
}
}
// otherwise one child-entity per primitive
else
{
for(var primitive in node.Mesh.Primitives)
{
EcsEntity meshEntity = world.NewEntity();
var meshParent = world.AssignComponent<ParentComponent>(meshEntity);
meshParent.Entity = entity;
var mesh = world.AssignComponent<MeshComponent>(meshEntity);
mesh.Mesh = PrimitiveToGeoBinding(primitive, validationEffect);
if(skeleton == null)
{
var meshRenderer = world.AssignComponent<MeshRendererComponent>(meshEntity);
meshRenderer.Material = material;
}
else
{
var meshRenderer = world.AssignComponent<SkinnedMeshRendererComponent>(meshEntity);
meshRenderer.Material = material;
meshRenderer.Skeleton = skeleton;
}
}
}
}
skeleton?.ReleaseRef();
for(var child in node.Children)
{
NodesToEntities(data, child, entity, world, validationEffect, material, clips);
}
}
public static GeometryBinding PrimitiveToGeoBinding(CGLTF.Primitive primitive, Effect validationEffect)
{
GeometryBinding binding = new GeometryBinding();
// primitive topology
switch(primitive.Type)
{
case .Points:
binding.SetPrimitiveTopology(.PointList);
case .Lines:
binding.SetPrimitiveTopology(.LineList);
case .LineStrip:
binding.SetPrimitiveTopology(.LineStrip);
case .Triangles:
binding.SetPrimitiveTopology(.TriangleList);
case .TriangleStrip:
binding.SetPrimitiveTopology(.TriangleStrip);
default:
Log.EngineLogger.Assert(false, scope $"{primitive.Type} not supported.");
}
// indices
{
CGLTF.Accessor* indices = primitive.Indices;
if(indices != null)
{
bool is16bit = indices.ComponentType == .R_16u || indices.ComponentType == .R_16;
IndexBuffer ib = new IndexBuffer((.)indices.Count, .Immutable, .None, is16bit ? .Index16Bit : .Index32Bit);
uint8* bufferData = (uint8*)indices.BufferView.Buffer.Data;
bufferData += indices.BufferView.Offset;
// TODO: this is a mess
ib.SetData<uint8>(bufferData, (.)indices.BufferView.Size);
binding.SetIndexBuffer(ib);
ib.ReleaseRef();
}
}
bool hasNormals = false;
bool hasTangents = false;
// vertices
{
List<VertexElement> elements = scope .(primitive.Attributes.Length);
Dictionary<void*, VertexBuffer> buffers = scope .();
List<VertexBufferBinding> bindings = scope .();
for(var attribute in primitive.Attributes)
{
{
StringView attributeName = StringView(attribute.Name);
if(attributeName.Equals("NORMAL"))
{
hasNormals = true;
}
else if(attributeName.Equals("TANGENT"))
{
hasTangents = true;
}
}
// Get Input Element format
Format format = FormatFromVectorComponent(attribute.Data.Type, attribute.Data.ComponentType);
Log.EngineLogger.AssertDebug(format != .Unknown, "Vertex element format must not be \"Unknown.\"");
VertexBuffer vertexBuffer = null;
binding.VertexCount = (uint32)attribute.Data.Count;
// Get vertex buffer
{
CGLTF.BufferView* bufferView = attribute.Data.BufferView;
// if buffer doesn't exist -> create
if(!buffers.TryGetValue(bufferView, out vertexBuffer))
{
vertexBuffer = new VertexBuffer(1, (uint32)bufferView.Size, .Immutable)..ReleaseRefNoDelete();
uint8* bufferData = (uint8*)bufferView.Buffer.Data;
bufferData += bufferView.Offset;
vertexBuffer.SetData(bufferData, (.)bufferView.Size);
buffers.Add(attribute.Data.BufferView, vertexBuffer);
}
Log.EngineLogger.AssertDebug(vertexBuffer != null);
}
VertexBufferBinding bufferBinding = .(vertexBuffer, (.)attribute.Data.Stride, (.)attribute.Data.Offset);
// get slot of bufferBinding
int bindingSlot = bindings.IndexOf(bufferBinding);
// binding has no slot -> add to list
if(bindingSlot == -1)
{
bindingSlot = bindings.Count;
bindings.Add(bufferBinding);
binding.SetVertexBufferSlot(bufferBinding, (.)bindingSlot);
}
StringView strView = .(attribute.Name);
// Remove number from end of name
while((*(strView.EndPtr - 1)).IsDigit)
{
strView.Length--;
}
VertexElement element = .(format, new String(strView), true, (.)attribute.Index, (.)bindingSlot);
elements.Add(element);
}
// Generate normals if missing
if(!hasNormals)
{
CGLTF.Accessor* positions = null;
// Find position accessor
for(var attribute in primitive.Attributes)
{
if(StringView(attribute.Name).Equals("POSITION"))
{
positions = attribute.Data;
break;
}
}
Log.EngineLogger.AssertDebug(positions != null, "The model appears to have no position data?!");
Vector3[] normals = new Vector3[positions.Count];
if(primitive.Indices != null)
GenerateNormals(primitive.Indices, positions, normals);
else
GenerateNormals(positions, normals);
VertexBuffer vertexBuffer = new VertexBuffer((uint32)sizeof(Vector3), (uint32)normals.Count, .Immutable);
vertexBuffer.SetData<Vector3>(normals);
bindings.Add(vertexBuffer.Binding);
uint32 bindingSlot = (.)bindings.Count - 1;
binding.SetVertexBufferSlot(vertexBuffer.Binding, (.)bindingSlot);
VertexElement element = .(.R32G32B32_Float, "NORMAL", false, 0, bindingSlot);
elements.Add(element);
}
// TODO: validate vertex layout somewhere else
VertexElement[] vertexElements = new VertexElement[elements.Count];
for(int i < elements.Count)
{
vertexElements[i] = elements[i];
}
VertexLayout layout = new VertexLayout(vertexElements, true, validationEffect.VertexShader);
binding.SetVertexLayout(layout..ReleaseRefNoDelete());
}
// TODO: calculate tangents if missing (MikkTSpace algorithm)
// Note: Bitangent = cross(normal, tangent.xyz) * tangent.w
return binding;
}
/// Generates the normals for one triangle
static mixin GenerateTriangleNormals(int index0, int index1, int index2, CGLTF.Accessor* positions, Vector3[] normals)
{
Vector3 position0 = GetEntry<Vector3>(positions, (.)index0);
Vector3 position1 = GetEntry<Vector3>(positions, (.)index1);
Vector3 position2 = GetEntry<Vector3>(positions, (.)index2);
ref Vector3 normal0 = ref normals[(.)index0];
ref Vector3 normal1 = ref normals[(.)index1];
ref Vector3 normal2 = ref normals[(.)index2];
Vector3 e0 = position1 - position0;
Vector3 e1 = position2 - position0;
Vector3 normal = Vector3.Cross(e0, e1);
normal0 += normal;
normal1 += normal;
normal2 += normal;
}
[Inline]
static void NormalizeNormals(Vector3[] normals)
{
for(int i < normals.Count)
{
normals[i].Normalize();
}
}
/// Generates normals for the given model using indexed geometry
static void GenerateNormals(CGLTF.Accessor* indices, CGLTF.Accessor* positions, Vector3[] normals)
{
/// Enumerate triangle-wise
for(uint t = 0; t < indices.Count; t += 3)
{
int index0 = (.)CGLTF.AccessorReadIndex(indices, t);
int index1 = (.)CGLTF.AccessorReadIndex(indices, t + 1);
int index2 = (.)CGLTF.AccessorReadIndex(indices, t + 2);
GenerateTriangleNormals!(index0, index1, index2, positions, normals);
}
NormalizeNormals(normals);
}
/// Generates normals for the given model using nonindexed geometry
static void GenerateNormals(CGLTF.Accessor* positions, Vector3[] normals)
{
/// Enumerate triangle-wise
for(int i = 0; i < (.)positions.Count; i += 3)
{
GenerateTriangleNormals!(i, i + 1, i + 2, positions, normals);
}
NormalizeNormals(normals);
}
static Skeleton ExtractSkeleton(CGLTF.Skin* skin)
{
Skeleton skeleton = new Skeleton();
skeleton.Joints = new Joint[skin.Joints.Length];
for(int i < skin.Joints.Length)
{
ref Joint joint = ref skeleton.Joints[i];
joint.InverseBindPose = GetEntry<Matrix>(skin.InverseBindMatrices, i);
if (skin.Joints[i].Name != null)
joint.Name = new String(skin.Joints[i].Name);
int parentId = skin.Joints.IndexOf(skin.Joints[i].Parent);
Log.EngineLogger.AssertDebug(parentId < uint8.MaxValue, scope $"A skeleton must not have more than {uint8.MaxValue - 1} bones.");
if(parentId == -1)
joint.ParentID = uint8.MaxValue;
else
joint.ParentID = (uint8)parentId;
}
return skeleton;
}
static bool AnimationBelongsToSkeleton(CGLTF.Animation animation, CGLTF.Skin* skin)
{
for(var channel in animation.Channels)
{
if(skin.Joints.IndexOf(channel.TargetNode) == -1)
{
return false;
}
}
return true;
}
static void LoadAnimationClips(CGLTF.Data* data, CGLTF.Skin* skin, Skeleton skeleton, List<AnimationClip> clips)
{
for(var animation in data.Animations)
{
if(!AnimationBelongsToSkeleton(animation, skin))
continue;
AnimationClip clip = new AnimationClip(skeleton);
clips.Add(clip);
clip.IsLooping = true;
for(var channel in animation.Channels)
{
int nodeIndex = skin.Joints.IndexOf(channel.TargetNode);
Log.EngineLogger.AssertDebug(nodeIndex != -1);
ref JointAnimation jointAnimation = ref clip.JointAnimations[nodeIndex];
if(jointAnimation == null)
jointAnimation = new JointAnimation();
Log.EngineLogger.AssertDebug(channel.Sampler.Input.Count == channel.Sampler.Output.Count);
int samples = (int)channel.Sampler.Input.Count;
Log.EngineLogger.AssertDebug(channel.Sampler.Input.ComponentType == .R_32f);
Log.EngineLogger.AssertDebug(channel.Sampler.Input.Type == .Scalar);
InterpolationMode interpolationMode;
switch(channel.Sampler.Interpolation)
{
case .Step:
interpolationMode = .Step;
case .Linear:
interpolationMode = .Linear;
case .CubicSpline:
interpolationMode = .CubicSpline;
}
switch(channel.TargetPath)
{
case .Translation:
jointAnimation.TranslationChannel = new .(samples, interpolationMode);
Log.EngineLogger.AssertDebug(channel.Sampler.Output.ComponentType == .R_32f);
Log.EngineLogger.AssertDebug(channel.Sampler.Output.Type == .Vec3);
for(int i < samples)
{
float timeStamp = GetEntry<float>(channel.Sampler.Input, i);
Vector3 sample = GetEntry<Vector3>(channel.Sampler.Output, i);
jointAnimation.TranslationChannel.TimeStamps[i] = timeStamp;
jointAnimation.TranslationChannel.Values[i] = sample;
}
case .Rotation:
jointAnimation.RotationChannel = new .(samples, interpolationMode);
Log.EngineLogger.AssertDebug(channel.Sampler.Output.ComponentType == .R_32f);
Log.EngineLogger.AssertDebug(channel.Sampler.Output.Type == .Vec4);
for(int i < samples)
{
float timeStamp = GetEntry<float>(channel.Sampler.Input, i);
Quaternion sample = GetEntry<Quaternion>(channel.Sampler.Output, i);
jointAnimation.RotationChannel.TimeStamps[i] = timeStamp;
jointAnimation.RotationChannel.Values[i] = sample;
}
case .Scale:
jointAnimation.ScaleChannel = new .(samples, interpolationMode);
Log.EngineLogger.AssertDebug(channel.Sampler.Output.ComponentType == .R_32f);
Log.EngineLogger.AssertDebug(channel.Sampler.Output.Type == .Vec3);
for(int i < samples)
{
float timeStamp = GetEntry<float>(channel.Sampler.Input, i);
Vector3 sample = GetEntry<Vector3>(channel.Sampler.Output, i);
jointAnimation.ScaleChannel.TimeStamps[i] = timeStamp;
jointAnimation.ScaleChannel.Values[i] = sample;
}
default:
Log.EngineLogger.Error($"Unknown channel target path \"{channel.TargetPath}\"");
}
clip.Duration = Math.Max(clip.Duration, jointAnimation.Duration);
}
}
}
static T GetEntry<T>(CGLTF.Accessor* accessor, int index)
{
Log.EngineLogger.AssertDebug((uint)index < accessor.Count);
T result = ?;
switch(typeof(T))
{
case typeof(float):
CGLTF.AccessorReadFloat(accessor, (uint)index, (float*)&result, 1);
case typeof(Vector2):
CGLTF.AccessorReadFloat(accessor, (uint)index, (float*)&result, 2);
case typeof(Vector3):
CGLTF.AccessorReadFloat(accessor, (uint)index, (float*)&result, 3);
case typeof(Vector4), typeof(Quaternion):
CGLTF.AccessorReadFloat(accessor, (uint)index, (float*)&result, 4);
case typeof(Matrix):
CGLTF.AccessorReadFloat(accessor, (uint)index, (float*)&result, 16);
case typeof(uint16):
CGLTF.AccessorReadUint(accessor, (uint)index, (uint32*)&result, 2);
case default:
uint8* data = (uint8*)accessor.BufferView.Buffer.Data;
data += accessor.BufferView.Offset;
data += accessor.Offset;
data += accessor.Stride * (uint)index;
result = *(T*)data;
}
return result;
/*
uint8* data = (uint8*)accessor.BufferView.Buffer.Data;
data += accessor.BufferView.Offset;
data += accessor.Offset;
data += accessor.Stride * (uint)index;
return *(T*)data;
*/
}
/**
* Converts the vector and component type to the corresponding Format.
*/
static Format FormatFromVectorComponent(CGLTF.Type vectorType, CGLTF.ComponentType componentType)
{
switch((vectorType, componentType))
{
case (.Scalar, .R_8):
return .R8_SInt;
case (.Scalar, .R_8u):
return .R8_UInt;
case (.Scalar, .R_16):
return .R16_SInt;
case (.Scalar, .R_16u):
return .R16_UInt;
case (.Scalar, .R_32u):
return .R32_UInt;
case (.Scalar, .R_32f):
return .R32_Float;
case (.Vec2, .R_8):
return .R8G8_SInt;
case (.Vec2, .R_8u):
return .R8G8_UInt;
case (.Vec2, .R_16):
return .R16G16_SInt;
case (.Vec2, .R_16u):
return .R16G16_UInt;
case (.Vec2, .R_32u):
return .R32G32_UInt;
case (.Vec2, .R_32f):
return .R32G32_Float;
//case (.Vec3, .R_8):
//case (.Vec3, .R_8u):
//case (.Vec3, .R_16):
//case (.Vec3, .R_16u):
case (.Vec3, .R_32u):
return .R32G32B32_UInt;
case (.Vec3, .R_32f):
return .R32G32B32_Float;
case (.Vec4, .R_8):
return .R8G8B8A8_SInt;
case (.Vec4, .R_8u):
return .R8G8B8A8_UInt;
case (.Vec4, .R_16):
return .R16G16B16A16_SInt;
case (.Vec4, .R_16u):
return .R16G16B16A16_UInt;
case (.Vec4, .R_32u):
return .R32G32B32A32_UInt;
case (.Vec4, .R_32f):
return .R32G32B32A32_Float;
case (.Mat4, .R_32f):
return .R32G32B32A32_Float;
default:
Log.EngineLogger.Assert(false, scope $"Unhandled vector - componenttype combination. ({vectorType}, {componentType})");
}
return .Unknown;
}
}
}
-17
View File
@@ -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();
}
}
}
-95
View File
@@ -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
}
}
}
+2 -42
View File
@@ -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");
}
}
} }
+2 -2
View File
@@ -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;
}
}
}
@@ -1,13 +0,0 @@
namespace System
{
extension Runtime
{
[NoReturn, Warn("The method is not implemented.")]
#unwarn
public static void NotImplemented(String filePath = Compiler.CallerFilePath, int line = Compiler.CallerLineNum)
{
String failStr = scope .()..AppendF("Not Implemented at line {} in {}", line, filePath);
Internal.FatalError(failStr, 1);
}
}
}
@@ -1,21 +0,0 @@
namespace System
{
extension String
{
[Inline]
public void CopyTo(Span<char8> target)
{
CopyTo(target.Ptr, target.Length);
}
[Inline]
public void CopyTo(char8* target, int targetLength)
{
int copiedChars = Math.Min(targetLength - 1, Length);
Internal.MemCpy(target, Ptr, copiedChars);
target[copiedChars] = '\0';
}
}
}
+1 -4
View File
@@ -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}
{{
}}
}}
""");
}
}
}
-41
View File
@@ -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 -109
View File
@@ -1,24 +1,10 @@
using GlitchyEngine.Math; using GlitchyEngine.Math;
using GlitchyEngine.Renderer;
using System;
namespace ImGui namespace ImGui
{ {
extension ImGui extension ImGui
{ {
extension Vec2
{
public static explicit operator Vector2(Vec2 v) => .(v.x, v.y);
public static explicit operator Vec2(Vector2 v) => .(v.X, v.Y);
}
extension Vec4
{
public static explicit operator Vector4(Vec4 v) => .(v.x, v.y, v.z, v.w);
public static explicit operator Vec4(Vector4 v) => .(v.X, v.Y, v.Z, v.W);
}
// TODO: Color-functions // TODO: Color-functions
public static bool ColorEdit3(char* label, ref ColorRGB col, ColorEditFlags flags = (ColorEditFlags) 0) => ColorEdit3Impl(label, *(float[3]*)&col, flags); public static bool ColorEdit3(char* label, ref ColorRGB col, ColorEditFlags flags = (ColorEditFlags) 0) => ColorEdit3Impl(label, *(float[3]*)&col, flags);
public static bool ColorEdit3(char* label, ref ColorRGBA col, ColorEditFlags flags = (ColorEditFlags) 0) => ColorEdit3Impl(label, *(float[3]*)&col, flags); public static bool ColorEdit3(char* label, ref ColorRGBA col, ColorEditFlags flags = (ColorEditFlags) 0) => ColorEdit3Impl(label, *(float[3]*)&col, flags);
@@ -28,99 +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);
public static void TextUnformatted(StringView text) => TextUnformattedImpl(text.Ptr, text.Ptr + text.Length);
public static void PushID(StringView id) => PushID(id.Ptr, id.Ptr + id.Length);
/// Releases references that accumulated calls like ImGui::Image
protected internal static extern void CleanupFrame();
/// Control to edit a vector 3 with drag functionality and reset buttons
public static bool EditVector3(StringView label, ref Vector3 value, Vector3 resetValues = .Zero, float dragSpeed = 0.1f, float columnWidth = 100f)
{
bool changed = false;
PushID(label);
defer PopID();
Columns(2);
defer Columns(1);
SetColumnWidth(0, columnWidth);
TextUnformatted(label);
NextColumn();
PushMultiItemsWidths(3, CalcItemWidth());
PushStyleVar(.ItemSpacing, Vec2.Zero);
defer PopStyleVar();
float lineHeight = GetFont().FontSize + GetStyle().FramePadding.y * 2.0f;
ImGui.Vec2 buttonSize = .(lineHeight + 3.0f, lineHeight);
PushStyleColor(.Button, Color(230, 25, 45).Value);
PushStyleColor(.ButtonHovered, Color(150, 25, 45).Value);
PushStyleColor(.ButtonActive, Color(230, 120, 130).Value);
if (Button("X", buttonSize))
{
value.X = resetValues.X;
changed = true;
}
SameLine();
if (DragFloat("##X", &value.X, dragSpeed))
changed = true;
PopItemWidth();
SameLine();
PopStyleColor(3);
PushStyleColor(.Button, Color(50, 190, 15).Value);
PushStyleColor(.ButtonHovered, Color(50, 120, 15).Value);
PushStyleColor(.ButtonActive, Color(116, 190, 99).Value);
if (Button("Y", buttonSize))
{
value.Y = resetValues.Y;
changed = true;
}
SameLine();
if (DragFloat("##Y", &value.Y, dragSpeed))
changed = true;
PopItemWidth();
SameLine();
PopStyleColor(3);
PushStyleColor(.Button, Color(55, 55, 230).Value);
PushStyleColor(.ButtonHovered, Color(55, 55, 150).Value);
PushStyleColor(.ButtonActive, Color(90, 90, 230).Value);
if (Button("Z", buttonSize))
{
value.Z = resetValues.Z;
changed = true;
}
SameLine();
if (DragFloat("##Z", &value.Z, dragSpeed))
changed = true;
PopItemWidth();
PopStyleColor(3);
return changed;
}
} }
} }
+147 -81
View File
@@ -1,33 +1,15 @@
using System; using System;
using ImGui; using ImGui;
using GlitchyEngine.Events; using GlitchyEngine.Events;
using ImGuizmo;
using GlitchyEngine.Renderer;
using System.IO;
using internal ImGui;
#if GE_GRAPHICS_DX11
using GlitchyEngine.Platform.DX11;
using internal GlitchyEngine.Platform.DX11;
#endif
namespace GlitchyEngine.ImGui namespace GlitchyEngine.ImGui
{ {
public class ImGuiLayer : Layer public class ImGuiLayer : Layer
{ {
ImGui.IO* _io;
public bool SettingsInvalid;
public this() : base("ImGuiLayer") { } public this() : base("ImGuiLayer") { }
public override void OnAttach() public override void OnAttach()
{ {
Debug.Profiler.ProfileFunction!();
//ImGuiImplWin32.EnableDpiAwareness(); //ImGuiImplWin32.EnableDpiAwareness();
Log.EngineLogger.Trace("Initializing ImGui..."); Log.EngineLogger.Trace("Initializing ImGui...");
@@ -35,114 +17,198 @@ namespace GlitchyEngine.ImGui
ImGui.CreateContext(); ImGui.CreateContext();
ImGui.StyleColorsDark(); ImGui.StyleColorsDark();
_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;
// Todo: currently broken in ImGui // Todo: currently broken in ImGui
//io.ConfigFlags |= .DpiEnableScaleFonts; //io.ConfigFlags |= .DpiEnableScaleFonts;
//io.ConfigFlags |= .DpiEnableScaleViewports; //io.ConfigFlags |= .DpiEnableScaleViewports;
// When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones. // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
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
ImGuiImplWin32.Init(Application.Get().Window.NativeWindow); // Todo: temporary, needs to be platform independent
ImGuiImplWin32.Init((Windows.HWnd)(int)Application.Get().Window.NativeWindow);
var context = Application.Get().Window.Context;
ImGuiImplDX11.Init(context.[Friend]nativeDevice, context.[Friend]nativeContext);
#endif #endif
#if GE_GRAPHICS_DX11
ImGuiImplDX11.Init(NativeDevice, NativeContext);
#endif
} }
public override void OnDetach() public override void OnDetach()
{ {
Debug.Profiler.ProfileFunction!();
#if GE_GRAPHICS_DX11
ImGuiImplDX11.Shutdown(); ImGuiImplDX11.Shutdown();
#endif
#if BF_PLATFORM_WINDOWS
ImGuiImplWin32.Shutdown(); ImGuiImplWin32.Shutdown();
#endif
ImGui.DestroyContext(); ImGui.DestroyContext();
} }
public override void OnEvent(Event event)
{
/*
EventDispatcher dispatcher = scope EventDispatcher(event);
dispatcher.Dispatch<WindowResizeEvent>(scope (e) =>
{
//ref ImGui.IO io = ref ImGui.GetIO();
//io.DisplaySize = .(e.Width, e.Height);
//io.DisplayFramebufferScale = .(1.0f, 1.0f);
return false;
});
dispatcher.Dispatch<MouseMovedEvent>(scope (e) =>
{
ref ImGui.IO io = ref ImGui.GetIO();
io.MousePos = ImGui.Vec2(e.PositionX, e.PositionY);
return false;
});
dispatcher.Dispatch<MouseButtonPressedEvent>(scope (e) =>
{
int button = 0;
switch(e.MouseButton)
{
case .LeftButton:
button = (uint)ImGui.MouseButton.Left;
case .RightButton:
button = (uint)ImGui.MouseButton.Right;
case .MiddleButton:
button = (uint)ImGui.MouseButton.Middle;
case .XButton1:
button = (uint)3;
case .XButton2:
button = (uint)4;
default:
}
ref ImGui.IO io = ref ImGui.GetIO();
io.MouseDown[button] = true;
return false;
});
dispatcher.Dispatch<MouseButtonReleasedEvent>(scope (e) =>
{
int button = 0;
switch(e.MouseButton)
{
case .LeftButton:
button = (uint)ImGui.MouseButton.Left;
case .RightButton:
button = (uint)ImGui.MouseButton.Right;
case .MiddleButton:
button = (uint)ImGui.MouseButton.Middle;
case .XButton1:
button = (uint)3;
case .XButton2:
button = (uint)4;
default:
}
ref ImGui.IO io = ref ImGui.GetIO();
io.MouseDown[button] = false;
return false;
});
dispatcher.Dispatch<MouseScrolledEvent>(scope (e) =>
{
ref ImGui.IO io = ref ImGui.GetIO();
io.MouseWheel += e.YOffset;
io.MouseWheelH += e.XOffset; // Todo: horizontal mousewheel inverted?!
return false;
});
dispatcher.Dispatch<KeyPressedEvent>(scope (e) =>
{
if(e.KeyCode >= (.)256)
return false;
ref ImGui.IO io = ref ImGui.GetIO();
io.KeysDown[(int32)e.KeyCode] = true;
io.KeyCtrl = io.KeysDown[(int32)Key.Control];
io.KeyShift = io.KeysDown[(int32)Key.Shift];
io.KeyAlt = io.KeysDown[(int32)Key.Alt];
io.KeySuper = io.KeysDown[(int32)Key.LeftSuper] || io.KeysDown[(int32)Key.RightSuper];
return false;
});
dispatcher.Dispatch<KeyReleasedEvent>(scope (e) =>
{
if(e.KeyCode >= (.)256)
return false;
ref ImGui.IO io = ref ImGui.GetIO();
io.KeysDown[(int32)e.KeyCode] = false;
io.KeyCtrl = io.KeysDown[(int32)Key.Control];
io.KeyShift = io.KeysDown[(int32)Key.Shift];
io.KeyAlt = io.KeysDown[(int32)Key.Alt];
io.KeySuper = io.KeysDown[(int32)Key.LeftSuper] || io.KeysDown[(int32)Key.RightSuper];
return false;
});
dispatcher.Dispatch<KeyTypedEvent>(scope (e) =>
{
ref ImGui.IO io = ref ImGui.GetIO();
io.AddInputCharacterUTF16((uint16)e.Char);
return false;
});
*/
}
public void Begin() public void Begin()
{ {
Debug.Profiler.ProfileFunction!(); // Todo:
//var v = DirectX.ImmediateContext;
//v.OutputMerger.SetRenderTargets(1, &DirectX.BackBufferTarget, null);
Application.Get().Window.Context.SetRenderTarget(null);
ImGuiImplDX11.NewFrame(); ImGuiImplDX11.NewFrame();
ImGuiImplWin32.NewFrame(); ImGuiImplWin32.NewFrame();
ImGui.NewFrame(); ImGui.NewFrame();
ImGuizmo.BeginFrame();
} }
bool showDemo = true;
public void ImGuiRender() public void ImGuiRender()
{ {
Debug.Profiler.ProfileFunction!();
if (SettingsInvalid)
{
var settings = Application.Get().Settings.ImGuiSettings;
ImGui.GetIO().Fonts.Clear();
String fullpath = scope String();
Application.Get().ContentManager.GetFilePath(fullpath, settings.FontName);
if (File.Exists(fullpath))
{
ImGui.GetIO().Fonts.AddFontFromFileTTF(fullpath, settings.FontSize);
}
else
{
ImGui.GetIO().Fonts.AddFontDefault();
}
#if GE_GRAPHICS_DX11
ImGuiImplDX11.CreateDeviceObjects();
#endif
SettingsInvalid = false;
}
Begin(); Begin();
{
Debug.Profiler.ProfileScope!("ImGuiRenderEvent");
var event = scope ImGuiRenderEvent(); var event = scope ImGuiRenderEvent();
Application.Get().OnEvent(event); Application.Get().OnEvent(event);
}
ImGui.ShowDemoWindow(&showDemo);
End(); End();
} }
public void End() public void End()
{ {
Debug.Profiler.ProfileFunction!(); ref ImGui.IO io = ref ImGui.GetIO();
let window = Application.Get().Window;
io.DisplaySize = .(window.Width, window.Height);
ImGui.Render(); ImGui.Render();
ImGuiImplDX11.RenderDrawData(ref ImGui.GetDrawData());
RenderCommand.SetDepthStencilTarget(null); if(io.ConfigFlags.HasFlag(.ViewportsEnable))
RenderCommand.SetRenderTarget(null);
RenderCommand.BindRenderTargets();
#if GE_GRAPHICS_DX11
ImGuiImplDX11.RenderDrawData(ImGui.GetDrawData());
#endif
ImGui.CleanupFrame();
if(_io.ConfigFlags.HasFlag(.ViewportsEnable))
{ {
ImGui.UpdatePlatformWindows(); ImGui.UpdatePlatformWindows();
ImGui.RenderPlatformWindowsDefault(); ImGui.RenderPlatformWindowsDefault();
+9 -1
View File
@@ -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();
} }
} }
-1
View File
@@ -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
+2
View File
@@ -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();
} }
/** /**
-5
View File
@@ -18,11 +18,6 @@ namespace GlitchyEngine.Math
public this(int initialCapacity = sizeof(uint)) public this(int initialCapacity = sizeof(uint))
{ {
var initialCapacity;
if (initialCapacity < sizeof(uint))
initialCapacity = sizeof(uint);
EnsureCapacity(initialCapacity); EnsureCapacity(initialCapacity);
} }
+3 -3
View File
@@ -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);
} }
} }
-81
View File
@@ -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
public const float RadToDeg = 180.0f / Pi;
/// Converts radians to degrees
public const float DegToRad = Pi / 180.0f;
// Converts the given radians to degrees
public static float ToDegrees(float radians)
{
return radians * RadToDeg;
}
// Converts the given radians to degrees
public static Vector2 ToDegrees(Vector2 radians)
{
return radians * RadToDeg;
}
// Converts the given radians to degrees
public static Vector3 ToDegrees(Vector3 radians)
{
return radians * RadToDeg;
}
// Converts the given radians to degrees
public static Vector4 ToDegrees(Vector4 radians)
{
return radians * RadToDeg;
}
// Converts the given degrees to radians
public static float ToRadians(float degrees)
{
return degrees * DegToRad;
}
// Converts the given degrees to radians
public static Vector2 ToRadians(Vector2 degrees)
{
return degrees * DegToRad;
}
// Converts the given degrees to radians
public static Vector3 ToRadians(Vector3 degrees)
{
return degrees * DegToRad;
}
// Converts the given degrees to radians
public static Vector4 ToRadians(Vector4 degrees)
{
return degrees * DegToRad;
}
const float epsilon = 0.0000001f;
public static bool IsZero(float value)
{
return Math.Abs(value) < epsilon;
}
}
}
-89
View File
@@ -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();
}*/
}
}
-378
View File
@@ -1,378 +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 q)
{
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/
Vector3 result;
float sqw = q.W*q.W;
float sqx = q.X*q.X;
float sqy = q.Y*q.Y;
float sqz = q.Z*q.Z;
float unit = sqx + sqy + sqz + sqw; // if normalised is one, otherwise is correction factor
float test = q.X*q.Y + q.Z*q.W;
if (test > 0.4999f*unit) { // singularity at north pole
result.Y = 2.0f * Math.Atan2(q.X,q.W);
result.Z = Math.PI_f / 2.0f;
result.X = 0.0f;
return result;
}
if (test < -0.4999f*unit) { // singularity at south pole
result.Y = -2.0f * Math.Atan2(q.X,q.W);
result.Z = -Math.PI_f / 2.0f;
result.X = 0.0f;
return result;
}
result.Y = Math.Atan2(2*q.Y*q.W-2*q.X*q.Z , sqx - sqy - sqz + sqw);
result.Z = Math.Asin(2*test/unit);
result.X = Math.Atan2(2*q.X*q.W-2*q.Y*q.Z , -sqx + sqy - sqz + sqw);
return result;
//return .(q.Pitch(), q.Yaw(), q.Roll());
}
/*
public float Pitch()
{
float y = 2.0f * (Y * Z + W * X);
float x = W * W - X * X - Y * Y + Z * Z;
if (Vector2(x, y).Equals(.Zero)) //avoid atan2(0,0) - handle singularity - Matiis
return 2.0f * Math.Atan2(X, W);
return Math.Atan2(y, x);
}
public float Yaw()
{
return Math.Asin(Math.Clamp(-2.0f * (X * Z - W * Y), -1.0f, 1.0f));
}
public float Roll()
{
float y = 2.0f * (X * Y + W * Z);
float x = W * W + X * X - Y * Y - Z * Z;
if (Vector2(x, y).Equals(.Zero)) //avoid atan2(0,0) - handle singularity - Matiis
return 0;
return Math.Atan2(y, x);
}
*/
}
}
+16
View File
@@ -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;
}
}
}
-62
View File
@@ -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);
}
}
}
@@ -21,9 +21,9 @@ namespace GlitchyEngine.Math
} }
/** /**
* Returns true if the swizzle operator is invalid (same component assigned twice). * Determines whether or not a swizzle operator can have a valid setter (e.g. no component assigned twice)
*/ */
static bool IsSetterValid(int[4] cmp, int vecSize) static bool invalidSetter(int[4] cmp, int vecSize)
{ {
return cmp[0] == cmp[1] || (vecSize >= 3 && cmp[0] == cmp[2]) || (vecSize == 4 && cmp[0] == cmp[3]) || return cmp[0] == cmp[1] || (vecSize >= 3 && cmp[0] == cmp[2]) || (vecSize == 4 && cmp[0] == cmp[3]) ||
(vecSize >= 3 && cmp[1] == cmp[2]) || (vecSize == 4 && cmp[1] == cmp[3]) || (vecSize >= 3 && cmp[1] == cmp[2]) || (vecSize == 4 && cmp[1] == cmp[3]) ||
@@ -49,18 +49,9 @@ 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 = IsSetterValid(cmp, swizzleCount); bool setterInvalid = invalidSetter(cmp, swizzleCount);
if (!setterInvalid)
{
setter.Append(
"""
set mut
{
""");
}
for(int c = 0; c < swizzleCount; c++) for(int c = 0; c < swizzleCount; c++)
{ {
@@ -78,20 +69,15 @@ namespace GlitchyEngine.Math
} }
} }
if (!setterInvalid) //{(setterInvalid ? "[Error(\"Cannot assign multiple values to same component.\")]" : String.Empty)}
{
setter.Append(
"""
}
""");
}
String swizzleString = scope $""" String swizzleString = scope $"""
public {_vectorTypeName}{swizzleCount} {swizzleName} public {_vectorTypeName}{swizzleCount} {swizzleName}
{{ {{
get => .({swizzleConstructor}); get => .({swizzleConstructor});
{setter} set mut
{{{setter}
}}
}} }}
"""; """;
+16 -79
View File
@@ -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,12 +217,14 @@ namespace GlitchyEngine.Math
public override void ToString(String strBuffer) => strBuffer.AppendF("X:{0} Y:{1}", X, Y); public override void ToString(String strBuffer) => strBuffer.AppendF("X:{0} Y:{1}", X, Y);
// Todo: move to extension
[Inline]
public static implicit operator DirectX.Math.Vector2(in Self value) => *(DirectX.Math.Vector2*)&value;
[Inline]
public static implicit operator Self(in DirectX.Math.Vector2 value) => *(Self*)&value;
[Inline] [Inline]
public static explicit operator Self(float value) => Self(value); public static explicit operator Self(float value) => Self(value);
public bool Equals(Vector2 v, float epsilon = Math.[Friend]sMachineEpsilonFloat)
{
return (Math.Abs(v.X - X) < epsilon) && (Math.Abs(v.Y - Y) < epsilon);
}
} }
} }
+15 -55
View File
@@ -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);
} }
+15 -58
View File
@@ -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);
} }
-162
View File
@@ -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;
}
}
}
-206
View File
@@ -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;
}
}
}
+162
View File
@@ -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;
}
}
}
+206
View File
@@ -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;
}
}
}
+234
View File
@@ -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;
}
}
}
-234
View File
@@ -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,108 +0,0 @@
#if GE_GRAPHICS_DX11
#if !BF_PLATFORM_WINDOWS
#error DirectX 11 (GE_GRAPHICS_DX11) can only be used on Windows.
#endif
using DirectX.Common;
using DirectX.D3D11;
using DirectX.D3D11.SDKLayers;
using System.Diagnostics;
namespace GlitchyEngine.Platform.DX11
{
static
{
/// Gets whether or not the DX11 device is initialized.
protected internal static bool IsDx11Initialized => NativeDevice != null;
protected internal static ID3D11Device* NativeDevice;
protected internal static ID3D11DeviceContext* NativeContext;
#if DEBUG
protected internal static ID3D11Debug* DebugDevice;
#endif
internal static void Dx11Init()
{
Debug.Profiler.ProfileFunction!();
if(!IsDx11Initialized)
{
Log.EngineLogger.Trace("Creating D3D11 Device and Context...");
DeviceCreationFlags deviceFlags = .None;
#if DEBUG
deviceFlags |= .Debug;
#endif
FeatureLevel[] levels = scope .(.Level_11_0);
FeatureLevel deviceLevel = ?;
HResult deviceResult;
{
Debug.Profiler.ProfileScope!("D3D11.CreateDevice");
deviceResult = D3D11.CreateDevice(null, .Hardware, 0, deviceFlags, levels, &NativeDevice, &deviceLevel, &NativeContext);
}
Log.EngineLogger.Assert(deviceResult.Succeeded, scope $"Failed to create D3D11 Device. Message({(int32)deviceResult}): {deviceResult}");
#if DEBUG
{
Debug.Profiler.ProfileScope!("Query for ID3D11Debug");
if(NativeDevice.QueryInterface<ID3D11Debug>(out DebugDevice).Succeeded)
{
ID3D11InfoQueue* infoQueue;
if(NativeDevice.QueryInterface<ID3D11InfoQueue>(out infoQueue).Succeeded)
{
infoQueue.SetBreakOnSeverity(.Corruption, true);
infoQueue.SetBreakOnSeverity(.Error, true);
infoQueue.Release();
}
}
}
#endif
Log.EngineLogger.Trace($"D3D11 Device and Context created (Feature level: {deviceLevel})");
}
else
{
// We created a second GraphicsContext (for some reason?) just increment references.
NativeDevice.AddRef();
NativeContext.AddRef();
#if DEBUG
DebugDevice.AddRef();
#endif
}
}
internal static void Dx11Release()
{
Debug.Profiler.ProfileFunction!();
NativeDevice.Release();
NativeContext.Release();
#if DEBUG
Debug.WriteLine("""
-------------------------
Live DX Objects Report:
""");
DebugDevice.ReportLiveDeviceObjects(.Detail | .IgnoreInternal);
Debug.WriteLine("""
-------------------------
""");
DebugDevice.Release();
#endif
}
}
}
#endif
@@ -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)
@@ -46,67 +42,72 @@ namespace GlitchyEngine.Renderer
var result = D3DCompiler.D3DCompile(code.CStr(), (.)code.Length, null, nativeMacros, null, entryPoint, target, compileFlags, .None, &shaderBlob, &errorBlob); var result = D3DCompiler.D3DCompile(code.CStr(), (.)code.Length, null, nativeMacros, null, entryPoint, target, compileFlags, .None, &shaderBlob, &errorBlob);
if(result.Failed) if(result.Failed)
{ {
StringView str = StringView((char8*)errorBlob.GetBufferPointer(), (int)errorBlob.GetBufferSize()); StringView str = StringView((char8*)errorBlob.GetBufferPointer(), errorBlob.GetBufferSize());
Log.EngineLogger.Error($"Failed to compile Shader: Error Code({(int)result}): {result} | Error Message: {str}"); Log.EngineLogger.Error($"Failed to compile Shader: Error Code({(int)result}): {result} | Error Message: {str}");
} }
} }
protected internal void Reflect(ID3DBlob* shaderCode) protected internal void Reflect(ID3DBlob* shaderCode)
{ {
Debug.Profiler.ProfileResourceFunction!();
ID3D11ShaderReflection* reflection = null; ID3D11ShaderReflection* reflection = null;
{
Debug.Profiler.ProfileResourceScope!("D3DReflect");
var result = D3DCompiler.D3DReflect(shaderCode.GetBufferPointer(), shaderCode.GetBufferSize(), &reflection); var result = D3DCompiler.D3DReflect(shaderCode.GetBufferPointer(), shaderCode.GetBufferSize(), &reflection);
if(result.Failed) if(result.Failed)
{ {
Log.EngineLogger.Error($"Failed to reflect shader: Message ({(int)result}): {result}"); Log.EngineLogger.Error($"Failed to reflect shader: Message ({(int)result}): {result}");
} }
}
reflection.GetDescription(let desc); reflection.GetDescription(let desc);
uint32 cBufferCount = desc.ConstantBuffers;
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,60 +1,22 @@
#if GE_GRAPHICS_DX11
using System; using System;
using System.IO;
using DirectX.D3D11; using DirectX.D3D11;
using DirectX.Common; using DirectX.Common;
using DirectXTK; using DirectXTK;
using GlitchyEngine.Math;
using GlitchyEngine.Platform.DX11;
using System.Collections;
using internal GlitchyEngine.Renderer; using internal GlitchyEngine.Renderer;
using internal GlitchyEngine.Platform.DX11;
typealias NativeTex2DDesc = DirectX.D3D11.Texture2DDescription;
namespace GlitchyEngine.Renderer namespace GlitchyEngine.Renderer
{ {
internal typealias NativeTex2DDesc = DirectX.D3D11.Texture2DDescription;
extension Texture extension Texture
{ {
protected internal ID3D11ShaderResourceView* nativeResourceView ~ _?.Release(); protected internal ID3D11ShaderResourceView* nativeView ~ _?.Release();
/** \brief Loads the texture from the specified path. protected override void ImplBind(uint32 slot)
* @param path The path of the texture to load.
* @param texture The reference to the pointer that will hold the texture.
* @returns true if the texture was loaded successfully; false otherwise.
*/
protected bool LoadDdsResourcePlatform<T>(Stream stream, ref T* texture) where T : ID3D11Resource
{ {
Debug.Profiler.ProfileResourceFunction!(); _context.nativeContext.VertexShader.SetShaderResources(slot, 1, &nativeView);
_context.nativeContext.PixelShader.SetShaderResources(slot, 1, &nativeView);
uint8[] ddsData = new:ScopedAlloc! uint8[stream.Length];
var result = stream.TryRead(ddsData);
if (result case .Err(let err))
{
Log.EngineLogger.Error($"Failed to read texture data from stream. Error: {err}");
}
((ID3D11Resource*)texture)?.Release();
nativeResourceView?.Release();
HResult loadResult = DDSTextureLoader.CreateDDSTextureFromMemory(NativeDevice,
ddsData.Ptr, (uint)ddsData.Count, (.)&texture, &nativeResourceView);
if(loadResult.Failed)
{
Log.EngineLogger.Error($"Failed to load texture. Error({(int)loadResult}): {loadResult}");
ReleaseAndNullify!(texture);
ReleaseAndNullify!(nativeResourceView);
return false;
}
return true;
} }
} }
@@ -72,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,11 +55,23 @@ namespace GlitchyEngine.Renderer
public override uint32 ArraySize => nativeDesc.ArraySize; public override uint32 ArraySize => nativeDesc.ArraySize;
public override uint32 MipLevels => nativeDesc.MipLevels; public override uint32 MipLevels => nativeDesc.MipLevels;
protected override void LoadDdsPlatform(Stream stream) protected override void LoadTexturePlatform()
{ {
Debug.Profiler.ProfileResourceFunction!(); nativeTexture?.Release();
nativeView?.Release();
LoadDdsResourcePlatform(stream, 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}).");
@@ -106,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,11 +107,23 @@ namespace GlitchyEngine.Renderer
public override uint32 ArraySize => nativeDesc.ArraySize / 6; public override uint32 ArraySize => nativeDesc.ArraySize / 6;
public override uint32 MipLevels => nativeDesc.MipLevels; public override uint32 MipLevels => nativeDesc.MipLevels;
protected override void LoadTexturePlatform(Stream stream) protected override void LoadTexturePlatform()
{ {
Debug.Profiler.ProfileResourceFunction!(); nativeTexture?.Release();
nativeView?.Release();
LoadDdsResourcePlatform(stream, 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}).");
@@ -284,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 -16
View File
@@ -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,38 +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];
}
}
}
+6 -10
View File
@@ -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();
} }
+52 -5
View File
@@ -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);

Some files were not shown because too many files have changed in this diff Show More