8 Commits
Author SHA1 Message Date
Simon Lübeß 4874cfe511 Cleanup 2022-05-03 22:52:37 +02:00
Simon Lübeß 63b9270710 DotNet script changes transform 2022-04-27 23:58:50 +02:00
Simon Lübeß 2bac6a8d05 Cleanup + Attach scripts 2022-04-27 13:00:55 +02:00
Simon Lübeß e51fc77c3f Use Init for dotnet commandline 2022-04-27 12:22:53 +02:00
Simon Lübeß 8c53f21690 Even more DotNet stuff, help 2022-04-26 22:36:27 +02:00
Simon Lübeß ad1b37dc64 Some more dotnet stuff 2022-04-23 01:15:33 +02:00
Simon Lübeß 8e46945362 Improved makefile and nethost structure 2022-04-14 13:39:25 +02:00
Simon Lübeß 6a250d4927 DotNet hosting test 2022-04-14 02:24:36 +02:00
211 changed files with 4502 additions and 12536 deletions
-6
View File
@@ -25,9 +25,3 @@
[submodule "GlitchyEngineHelper/vendor/DirectXTK"]
path = GlitchyEngineHelper/vendor/DirectXTK
url = https://github.com/microsoft/DirectXTK.git
[submodule "GlitchyEngine/vendor/box2D"]
path = GlitchyEngine/vendor/box2D
url = https://github.com/jazzbre/box2d-beef.git
[submodule "GlitchyEngine/vendor/Beef.Linq"]
path = GlitchyEngine/vendor/Beef.Linq
url = https://github.com/aharabada/Beef.Linq.git
+2 -5
View File
@@ -1,9 +1,6 @@
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"}, box2d-beef = {Path = "GlitchyEngine/vendor/box2D"}, "Beef.Linq" = {Path = "GlitchyEngine/vendor/Beef.Linq/src"}}
WorkspaceFolders = {GlitchyEngine = ["GlitchyEngine", "GlitchLog", "GlitchyEngineHelper"], "GlitchyEngine/Dependencies" = ["cgltf-beef", "DirectX", "FreeType", "ImGui", "ImGuiImplDX11", "ImGuiImplWin32", "ImGuizmo", "LodePng", "msdfgen-beef", "bon", "box2d-beef", "Beef.Linq"]}
Projects = {Sandbox = {Path = "Sandbox"}, GlitchyEngine = {Path = "GlitchyEngine"}, GlitchLog = {Path = "GlitchLog"}, DirectX = {Path = "GlitchyEngine/vendor/directx/DirectX"}, LodePng = {Path = "vendor/lodepng-beef/lodepng-beef"}, FreeType = {Path = "GlitchyEngine/vendor/freetype"}, cgltf-beef = {Path = "GlitchyEngine/vendor/gltf/cgltf-beef"}, GlitchyEditor = {Path = "GlitchyEditor"}, msdfgen-beef = {Path = "GlitchyEngine/vendor/msdfgen/msdfgen-beef"}, ImGui = {Path = "GlitchyEngine/vendor/imgui/ImGui"}, ImGuiImplDX11 = {Path = "GlitchyEngine/vendor/imgui/ImGuiImplDX11"}, ImGuiImplWin32 = {Path = "GlitchyEngine/vendor/imgui/ImGuiImplWin32"}, ImGuizmo = {Path = "GlitchyEngine/vendor/imgui/ImGuizmo"}, GlitchyEngineHelper = {Path = "GlitchyEngineHelper"}, bon = {Path = "GlitchyEngine/vendor/bon"}}
WorkspaceFolders = {GlitchyEngine = ["GlitchyEngine", "GlitchLog", "GlitchyEngineHelper"], "GlitchyEngine/Dependencies" = ["cgltf-beef", "DirectX", "FreeType", "ImGui", "ImGuiImplDX11", "ImGuiImplWin32", "ImGuizmo", "LodePng", "msdfgen-beef", "bon"]}
[Workspace]
StartupProject = "GlitchyEditor"
[Configs.Debug.Win64]
AllocStackTraceDepth = 12
Binary file not shown.
@@ -1,4 +0,0 @@
{
AssetLoader = "ModelAssetLoader",
Config = (GlitchyEditor.Assets.ModelAssetLoaderConfig){}
}
Binary file not shown.
@@ -1,4 +0,0 @@
{
AssetLoader = "ModelAssetLoader",
Config = (GlitchyEditor.Assets.ModelAssetLoaderConfig){}
}
-154
View File
@@ -1,154 +0,0 @@
{
Name = "Scene name here pls!!!",
Entities = [
{
Id = 5169765174113462770,
NameComponent = {
Name = "Sphere"
},
TransformComponent = {
Position = {
X = 0,
Y = 0.5,
Z = 0
},
Rotation = {
X = 0,
Y = 0,
Z = 0,
W = 1
},
Scale = {
X = 1,
Y = 1,
Z = 1
},
EditorEulerRotation = {
X = 0,
Y = 0,
Z = 0
}
},
MeshComponent = {
Mesh = "Models\\sphere.glb"
},
MeshRendererComponent = {
Material = "Textures\\TestMaterial.mat"
}
},
{
Id = 17158420331978163131,
NameComponent = {
Name = "Light"
},
TransformComponent = {
Position = {
X = -1,
Y = 4,
Z = -4
},
Rotation = {
X = 0.614328,
Y = 0.239776,
Z = 0.031567,
W = 0.751074
},
Scale = {
X = 0.999999,
Y = 1,
Z = 1.000001
},
EditorEulerRotation = {
X = 1.308998,
Y = 0.349066,
Z = 0.349066
}
},
LightComponent = {
LightType = .Directional,
Illuminance = 10,
Color = {
R = 1,
G = 0.991772,
B = 0.740862
}
}
},
{
Id = 5556050645816939548,
NameComponent = {
Name = "Plane"
},
TransformComponent = {
Position = {
X = 0,
Y = 0,
Z = 0
},
Rotation = {
X = 0,
Y = 0,
Z = 0,
W = 1
},
Scale = {
X = 10,
Y = 1,
Z = 10
},
EditorEulerRotation = {
X = 0,
Y = 0,
Z = 0
}
},
MeshComponent = {
Mesh = "Models\\plane.glb"
},
MeshRendererComponent = {
Material = "Textures\\TestMaterial.mat"
}
},
{
Id = 3947673900993587516,
NameComponent = {
Name = "Camera"
},
TransformComponent = {
Position = {
X = 0,
Y = 2,
Z = -5
},
Rotation = {
X = 0.21644,
Y = 0,
Z = 0,
W = 0.976296
},
Scale = {
X = 1,
Y = 1,
Z = 1
},
EditorEulerRotation = {
X = 0.436332,
Y = 0,
Z = 0
}
},
CameraComponent = {
Primary = true,
ProjectionType = .InfinitePerspective,
PerspectiveFovY = 1.047198,
PerspectiveNearPlane = 0.1,
PerspectiveFarPlane = 10000,
OrthographicHeight = 10,
OrthographicNearPlane = 0,
OrthographicFarPlane = 10,
AspectRatio = 2.156692,
FixedAspectRatio = false
}
}
]
}
@@ -1,212 +0,0 @@
{
Name = "Scene name here pls!!!",
Entities = [
{
Id = 6000868443984780499,
NameComponent = {
Name = "Child"
},
SpriterRendererComponent = {
Color = {
R = 1,
G = 0.388184,
B = 0.090109,
A = 1
},
UvTransform = {
X = 0,
Y = 0,
Z = 1,
W = 1
}
},
TransformComponent = {
ParentId = 820806682740348099,
Position = {
X = 0,
Y = 0.75,
Z = 0
},
Rotation = {
X = 0,
Y = 0,
Z = 0,
W = 1
},
Scale = {
X = 0.5,
Y = 0.5,
Z = 1
},
EditorEulerRotation = {
X = 0,
Y = 0,
Z = 0
}
}
},
{
Id = 820806682740348099,
NameComponent = {
Name = "Quad"
},
SpriterRendererComponent = {
Color = {
R = 0,
G = 0.551178,
B = 0.328787,
A = 1
},
UvTransform = {
X = 0,
Y = 0,
Z = 1,
W = 1
}
},
TransformComponent = {
Position = {
X = 0,
Y = 2,
Z = 0
},
Rotation = {
X = 0,
Y = 0,
Z = 0,
W = 1
},
Scale = {
X = 1,
Y = 1,
Z = 1
},
EditorEulerRotation = {
X = 0,
Y = 0,
Z = 0
}
},
Rigidbody2D = {
BodyType = .Dynamic,
FixedRotation = false
},
BoxCollider2D = {
Offset = {
X = 0,
Y = 0
},
Size = {
X = 0.5,
Y = 0.5
},
Density = 1,
Friction = 0.5,
Restitution = 0,
RestitutionThreshold = 0.5
}
},
{
Id = 15398726361722237419,
NameComponent = {
Name = "Floor"
},
SpriterRendererComponent = {
Color = {
R = 1,
G = 0.941886,
B = 0.401485,
A = 1
},
UvTransform = {
X = 0,
Y = 0,
Z = 1,
W = 1
}
},
TransformComponent = {
Position = {
X = 0,
Y = -0.5,
Z = 0
},
Rotation = {
X = 0,
Y = 0,
Z = 0,
W = 1
},
Scale = {
X = 10,
Y = 1,
Z = 1
},
EditorEulerRotation = {
X = 0,
Y = 0,
Z = 0
}
},
Rigidbody2D = {
BodyType = .Static,
FixedRotation = false
},
BoxCollider2D = {
Offset = {
X = 0,
Y = 0
},
Size = {
X = 0.5,
Y = 0.5
},
Density = 1,
Friction = 0.5,
Restitution = 0,
RestitutionThreshold = 0.5
}
},
{
Id = 1491484622542812645,
NameComponent = {
Name = "Camera"
},
TransformComponent = {
Position = {
X = 0,
Y = 1,
Z = -5
},
Rotation = {
X = 0,
Y = 0,
Z = 0,
W = 1
},
Scale = {
X = 1,
Y = 1,
Z = 1
},
EditorEulerRotation = {
X = 0,
Y = 0,
Z = 0
}
},
CameraComponent = {
Primary = true,
ProjectionType = .InfinitePerspective,
PerspectiveFovY = 1.308997,
PerspectiveNearPlane = 0.1,
PerspectiveFarPlane = 10000,
OrthographicHeight = 10,
OrthographicNearPlane = 0,
OrthographicFarPlane = 10,
AspectRatio = 2.116827,
FixedAspectRatio = false
}
}
]
}
@@ -1,305 +0,0 @@
{
Name = "Scene name here pls!!!",
Entities = [
{
Id = 820806682740348099,
NameComponent = {
Name = "Quad"
},
SpriterRendererComponent = {
Color = {
R = 0,
G = 0.551178,
B = 0.328787,
A = 1
},
IsCircle = false,
Sprite = "\\Textures\\TestMat\\rustediron2_albedo.png",
UvTransform = {
X = 0,
Y = 0,
Z = 1,
W = 1
}
},
TransformComponent = {
Position = {
X = 0,
Y = 2,
Z = 0
},
Rotation = {
X = 0,
Y = 0,
Z = 0,
W = 1
},
Scale = {
X = 1,
Y = 1,
Z = 1
},
EditorEulerRotation = {
X = 0,
Y = 0,
Z = 0
}
},
Rigidbody2D = {
BodyType = .Dynamic,
FixedRotation = false
},
BoxCollider2D = {
Offset = {
X = 0,
Y = 0
},
Size = {
X = 0.5,
Y = 0.5
},
Density = 1,
Friction = 0.5,
Restitution = 0,
RestitutionThreshold = 0.5
}
},
{
Id = 15398726361722237419,
NameComponent = {
Name = "Floor"
},
SpriterRendererComponent = {
Color = {
R = 1,
G = 0.941886,
B = 0.401485,
A = 1
},
IsCircle = false,
Sprite = null,
UvTransform = {
X = 0,
Y = 0,
Z = 1,
W = 1
}
},
TransformComponent = {
Position = {
X = 0,
Y = -0.5,
Z = 0
},
Rotation = {
X = 0,
Y = 0,
Z = 0,
W = 1
},
Scale = {
X = 10,
Y = 1,
Z = 1
},
EditorEulerRotation = {
X = 0,
Y = 0,
Z = 0
}
},
Rigidbody2D = {
BodyType = .Static,
FixedRotation = false
},
BoxCollider2D = {
Offset = {
X = 0,
Y = 0
},
Size = {
X = 0.5,
Y = 0.5
},
Density = 1,
Friction = 0.5,
Restitution = 0,
RestitutionThreshold = 0.5
}
},
{
Id = 1491484622542812645,
NameComponent = {
Name = "Camera"
},
TransformComponent = {
Position = {
X = 0,
Y = 1,
Z = -5
},
Rotation = {
X = 0,
Y = 0,
Z = 0,
W = 1
},
Scale = {
X = 1,
Y = 1,
Z = 1
},
EditorEulerRotation = {
X = 0,
Y = 0,
Z = 0
}
},
CameraComponent = {
Primary = true,
ProjectionType = .InfinitePerspective,
PerspectiveFovY = 1.308997,
PerspectiveNearPlane = 0.1,
PerspectiveFarPlane = 10000,
OrthographicHeight = 10,
OrthographicNearPlane = 0,
OrthographicFarPlane = 10,
AspectRatio = 2.969697,
FixedAspectRatio = false
}
},
{
Id = 15710354273720487680,
NameComponent = {
Name = "Circle"
},
SpriterRendererComponent = {
Color = {
R = 1,
G = 1,
B = 1,
A = 1
},
IsCircle = true,
Sprite = "\\Textures\\rocket.png",
UvTransform = {
X = 0,
Y = 0,
Z = 1,
W = 1
}
},
TransformComponent = {
Position = {
X = -0.121203,
Y = 0.66016,
Z = 0
},
Rotation = {
X = 0,
Y = 0,
Z = 0,
W = 1
},
Scale = {
X = 1,
Y = 1,
Z = 1
},
EditorEulerRotation = {
X = 0,
Y = 0,
Z = 0
}
},
Rigidbody2D = {
BodyType = .Dynamic,
FixedRotation = false
},
CircleCollider2D = {
Offset = {
X = 0,
Y = 0
},
Radius = 0.5,
Density = 1,
Friction = 0.5,
Restitution = 0,
RestitutionThreshold = 0.5
}
},
{
Id = 935640822766280888,
NameComponent = {
Name = "Light"
},
TransformComponent = {
Position = {
X = 3.883276,
Y = 0,
Z = -0.808795
},
Rotation = {
X = 0.497987,
Y = -0.103421,
Z = 0.15538,
W = 0.846859
},
Scale = {
X = 0.999998,
Y = 1,
Z = 1
},
EditorEulerRotation = {
X = 1.090894,
Y = -0.340794,
Z = 0.160858
}
},
LightComponent = {
LightType = .Directional,
Illuminance = 12.9,
Color = {
R = 0.985467,
G = 1,
B = 0.569979
}
}
},
{
Id = 721949523193525565,
NameComponent = {
Name = "Sphere"
},
TransformComponent = {
Position = {
X = 0,
Y = 0,
Z = -1.523338
},
Rotation = {
X = 0,
Y = 0,
Z = 0,
W = 1
},
Scale = {
X = 1,
Y = 1,
Z = 1
},
EditorEulerRotation = {
X = 0,
Y = 0,
Z = 0
}
},
MeshComponent = {
Mesh = "\\Models\\sphere.glb"
},
MeshRendererComponent = {
Material = "\\Textures\\TestMaterial.mat"
}
}
]
}
-52
View File
@@ -1,52 +0,0 @@
//=================================================================================================
//
// Baking Lab
// by MJP and David Neubelt
// http://mynameismjp.wordpress.com/
//
// All code licensed under the MIT license
//
//=================================================================================================
// The code in this file was originally written by Stephen Hill (@self_shadow), who deserves all
// credit for coming up with this fit and implementing it. Buy him a beer next time you see him. :)
// Source: https://github.com/TheRealMJP/BakingLab/blob/master/BakingLab/ACES.hlsl
// sRGB => XYZ => D65_2_D60 => AP1 => RRT_SAT
static const float3x3 ACESInputMat =
{
{0.59719, 0.35458, 0.04823},
{0.07600, 0.90834, 0.01566},
{0.02840, 0.13383, 0.83777}
};
// ODT_SAT => XYZ => D60_2_D65 => sRGB
static const float3x3 ACESOutputMat =
{
{ 1.60475, -0.53108, -0.07367},
{-0.10208, 1.10813, -0.00605},
{-0.00327, -0.07276, 1.07602}
};
float3 RRTAndODTFit(float3 v)
{
float3 a = v * (v + 0.0245786f) - 0.000090537f;
float3 b = v * (0.983729f * v + 0.4329510f) + 0.238081f;
return a / b;
}
float3 ACESFitted(float3 color)
{
color = mul(ACESInputMat, color);
// Apply RRT and ODT
color = RRTAndODTFit(color);
color = mul(ACESOutputMat, color);
// Clamp to [0, 1]
color = saturate(color);
return color;
}
@@ -1,4 +0,0 @@
{
AssetLoader = "EffectAssetLoader",
Config = (GlitchyEditor.Assets.EffectAssetLoaderConfig){}
}
@@ -1,16 +0,0 @@
cbuffer Constants : register(b0)
{
uint ClearValue;
}
float4 VS(float2 input : POSITION) : SV_Position
{
return float4(input, 0.0f, 1.0f);
}
uint PS(float4 input : SV_Position) : SV_Target0
{
return ClearValue;
}
#pragma Effect[VS = VS; PS = PS]
@@ -1,4 +0,0 @@
{
AssetLoader = "EffectAssetLoader",
Config = (GlitchyEditor.Assets.EffectAssetLoaderConfig){}
}
@@ -1,33 +0,0 @@
Texture2D Texture : register(t0);
SamplerState TextureSampler : register(s0);
struct VS_IN
{
float2 Position : POSITION;
float2 TexCoord : TEXCOORD0;
};
struct PS_IN
{
float4 Position : SV_POSITION;
float2 TexCoord : TEXCOORD;
};
PS_IN VS(VS_IN input)
{
PS_IN output;
output.Position = float4(input.Position, 0, 1);
output.TexCoord = input.TexCoord;
return output;
}
float4 PS(PS_IN input) : SV_TARGET
{
float4 color = Texture.Sample(TextureSampler, input.TexCoord);
return float4(pow(color.rgb, 1.0f / 2.2f), color.a);
}
#pragma Effect[VS = VS; PS = PS]
@@ -1,4 +0,0 @@
{
AssetLoader = "EffectAssetLoader",
Config = (GlitchyEditor.Assets.EffectAssetLoaderConfig){}
}
@@ -1,28 +0,0 @@
#define PI 3.14159265358979323846f
/**
* Calculates the diffuse lighting of a lambertian surface
* @param diffuseColor (rho/ pi) * C_diffuse
* @param illuminanceColor The product of the "brightness" and the light color.
* @param n_dot_l The dot product of the surface normal and the light direction.
*/
float3 CalculateDiffuseReflection(float3 diffuseColor, float3 illuminanceColor, float3 n_dot_l)
{
float3 directColor = illuminanceColor * saturate(n_dot_l);
return (directColor * diffuseColor);
}
/**
* Calculates the blinn-phong-specular reflection
* @param n The normalized surface normal
* @param h The normalized half way vector (nrm(l + v))
* @param alpha The reflections alpha-value
* @param illuminanceColor The product of the "brightness" and the light color.
* @param n_dot_l The dot product of the surface normal and the light direction.
*/
float3 CalculateSpecularReflection(float3 n, float3 h, float alpha, float3 illuminanceColor, float n_dot_l)
{
float highlight = pow(saturate(dot(n, h)), alpha) * float(n_dot_l > 0.0);
return (illuminanceColor * highlight); // Todo: * SpecularColor
}
@@ -1,4 +0,0 @@
{
AssetLoader = "EffectAssetLoader",
Config = (GlitchyEditor.Assets.EffectAssetLoaderConfig){}
}
-78
View File
@@ -1,78 +0,0 @@
/*
* This File contains Function for PBR.
*/
#ifndef __PBR_HLSL__
#define __PBR_HLSL__
#include "ShaderHelpers.hlsl"
// #define PBR_IBL
/**
* Normal Distribution Function. (Trowbridge-Reits GGX)
* Calculates the relative surface area of microfacets exactly aligned to the halfway vector.
* @param normal The surface normal.
* @param halfway The halfway vector between the surface normal and the view direction.
* @param roughness Roughness value.
* @returns The relative surface area of microfacets exactly aligned to the halfway vector.
*/
float NormalDistributionGGX(float3 normal, float3 halfway, float roughness)
{
// Square roughness because it looks better
float a = roughness * roughness;
float aa = a * a;
float n_dot_h = max(dot(normal, halfway), 0.0f);
float denom = (n_dot_h * n_dot_h) * (aa - 1.0f) + 1.0f;
denom = PI * denom * denom;
return aa / denom;
}
/**
* Geometry Function calculating the overshadowing of microfacets based on roughness. (Schlick-Beckmann GGX).
* @param dot-product of normal vector and vector from surface to camera.
* @param k Roughness value.
*/
float GeometrySchlickGGX(float n_dot_v, float k)
{
return n_dot_v / (n_dot_v * (1 - k) + k);
}
/**
* Geometry Function calculating the overshadowing of microfacets based on roughness. (Smith)
* @param normal The surface normal.
* @param viewDir Vector from surface to viewer.
* @param lightDir Vector from surface to light source.
* @param roughness Roughness value.
*/
float GeometrySmith(float3 normal, float3 viewDir, float3 lightDir, float roughness)
{
#ifdef PBR_IBL
// IBL
float k = roughness * roughness / 2;
#else
// Direct lighting
float k = (roughness + 1.0f);
k = (k * k) / 8;
#endif
const float n_dot_v = max(dot(normal, viewDir), 0.0f);
float n_dot_l = max(dot(normal, lightDir), 0.0f);
return GeometrySchlickGGX(n_dot_v, k) * GeometrySchlickGGX(n_dot_l, k);
}
/**
* Calculates the fresnel value.
* @param n_dot_v Dot product of the normal and view direction
* @param F0 base reflectivity.
*/
float3 FresnelSchlick(float n_dot_v, float3 F0)
{
return F0 + (1.0 - F0) * pow(clamp(1.0 - n_dot_v, 0.0, 1.0), 5.0);
}
#endif // __PBR_HLSL__
@@ -1,4 +0,0 @@
{
AssetLoader = "EffectAssetLoader",
Config = (GlitchyEditor.Assets.EffectAssetLoaderConfig){}
}
@@ -1,90 +0,0 @@
#ifndef __SHADER_HELPERS_HLSL__
#define __SHADER_HELPERS_HLSL__
#define PI 3.14159265358979323846f
/*
* Calculates the weighted sum of two normal vectors.
* nrm1: The first normal vector
* nrm2: The second normal vector
* a: The weight factor for nrm1
* b: The weight factor for nrm2
*/
float3 BlendNormals(float3 nrm1, float3 nrm2, float a, float b)
{
return normalize(float3(a * nrm1.x / nrm1.z + b * nrm2.x / nrm2.z,
a * nrm1.y / nrm1.z + b * nrm2.y / nrm2.z,
1.0f));
}
/*
* Scales a normal vector by a factor where 0 results in the vector (0, 0, 1)
* nrm: The normal vector
* a: The scaling factor
*/
float3 ScaleNormal(float3 nrm1, float a)
{
return normalize(float3(a * nrm1.x / nrm1.z,
a * nrm1.y / nrm1.z,
1.0f));
}
/*
* Scales a normal vector by a factor where 0 results in the vector (0, 0, 1)
* nrm: The normal vector
* a: The scaling factor
*/
float3 ScaleNormal(float3 nrm1, float2 a)
{
return normalize(float3(a.x * nrm1.x / nrm1.z,
a.y * nrm1.y / nrm1.z,
1.0f));
}
/*
* Reconstructs the z-component of a normalized normal vector from a two-component value
* cnrm: The x- and y-components of a normalized normal vector
*/
float3 DecompressNormal(float2 cnrm)
{
return float3(cnrm, sqrt(1.0 - cnrm.x * cnrm.x - cnrm.y * cnrm.y));
}
/*
* Reconstructs the tangent space from a normal and a tangent
* normal: The surface normal
* tangent: The surface tangent
* sigma: Defines the handedness of the tangent space matrix. 1.0 if it is right handend. -1.0 if it is left handed
*/
float3x3 ConstructTangentSpace(float3 normal, float3 tangent, float3 sigma)
{
float3 n = normalize(normal);
float3 t = normalize(tangent - n * dot(tangent, n));
float3 b = cross(n, t) * sigma;
return float3x3(t, b, n);
}
/**
* Calculates the luminance of an rgb-value.
* @param rgb The rgb color.
* @return The luminance of the given rgb color.
*/
float ColorToLuminance(float3 rgb)
{
return rgb.r * 0.212639 + rgb.g * 0.715169 + rgb.b * 0.072192;
}
/**
* Extrancts the handedness of the bitangent that is encoded in the z-component of the tangent.
* @param tangentz The z-component of the tangent with the handedness encoded.
* @return The handedness of the bitangent (bitangent = handedness * tangent x normal)
*/
float GetBitangentHandedness(float tangentz)
{
// handedness is in least significant bit of tangent.z
uint z = asuint(tangentz);
return (z & 1) > 0 ? 1.0 : -1.0;
}
#endif // __SHADER_HELPERS_HLSL__
@@ -1,4 +0,0 @@
{
AssetLoader = "EffectAssetLoader",
Config = (GlitchyEditor.Assets.EffectAssetLoaderConfig){}
}
@@ -1,39 +0,0 @@
#include "ACES.hlsl"
Texture2D CameraTarget : register(t0);
SamplerState CameraTargetSampler : register(s0);
struct VS_IN
{
float2 Position : POSITION;
float2 TexCoord : TEXCOORD0;
};
struct PS_IN
{
float4 Position : SV_POSITION;
float2 TexCoord : TEXCOORD;
};
PS_IN VS(VS_IN input)
{
PS_IN output;
output.Position = float4(input.Position, 0, 1);
output.TexCoord = input.TexCoord;
return output;
}
float4 PS(PS_IN input) : SV_TARGET
{
float4 rawColor = CameraTarget.Sample(CameraTargetSampler, input.TexCoord);
// float3 color = rawColor.rgb / (rawColor.rgb + 1.0f);
float3 color = ACESFitted(rawColor.rgb);
return float4(color, 1);
}
#pragma Effect[VS = VS; PS = PS]
@@ -1,4 +0,0 @@
{
AssetLoader = "EffectAssetLoader",
Config = (GlitchyEditor.Assets.EffectAssetLoaderConfig){}
}
+5 -31
View File
@@ -1,5 +1,3 @@
#define EDITOR
Texture2D Texture : register(t0);
SamplerState Sampler : register(s0);
@@ -16,9 +14,6 @@ struct VS_Input
float4 Color : COLOR;
float4 UVTransform : TEXCOORD1;
float InnerRadius : TEXCOORD2;
#ifdef EDITOR
uint EntityId : ENTITYID;
#endif
};
struct PS_Input
@@ -27,9 +22,6 @@ struct PS_Input
float2 RawPos : TEXCOORD0;
float2 Texcoord : TEXCOORD1;
float4 Color : COLOR;
#ifdef EDITOR
nointerpolation uint EntityId : ENTITYID;
#endif
float InnerRadius : TEXCOORD2;
};
@@ -43,25 +35,11 @@ PS_Input VS(VS_Input input)
output.Color = input.Color;
output.InnerRadius = input.InnerRadius;
#ifdef EDITOR
output.EntityId = input.EntityId;
#endif
return output;
}
struct PS_Output
float4 PS(PS_Input input) : SV_Target0
{
float4 Color : SV_Target0;
#ifdef EDITOR
uint EntityId : SV_TARGET1;
#endif
};
PS_Output PS(PS_Input input)
{
PS_Output output;
float2 uv = input.RawPos * 2;
float distance = 1.0f - length(uv);
@@ -75,14 +53,10 @@ PS_Output PS(PS_Input input)
// Discard invisible pixels
clip(amount - 0.5f);
output.Color = Texture.Sample(Sampler, input.Texcoord) * input.Color;
output.Color.a *= amount;
float4 color = Texture.Sample(Sampler, input.Texcoord) * input.Color;
color.a *= amount;
#ifdef EDITOR
output.EntityId = input.EntityId;
#endif
return output;
return color;
}
#pragma Effect[VS=VS; PS=PS]
#effect[VS=VS, PS=PS]
@@ -1,4 +0,0 @@
{
AssetLoader = "EffectAssetLoader",
Config = (GlitchyEditor.Assets.EffectAssetLoaderConfig){}
}
@@ -28,4 +28,4 @@ float4 PS(PS_Input input) : SV_Target0
return Color;
}
#pragma Effect[VS=VS; PS=PS]
#effect[VS=VS, PS=PS]
@@ -1,4 +0,0 @@
{
AssetLoader = "EffectAssetLoader",
Config = (GlitchyEditor.Assets.EffectAssetLoaderConfig){}
}
@@ -90,4 +90,4 @@ float4 PS(PS_Input input) : SV_Target0
}
*/
#pragma Effect[VS=VS; PS=PS]
#effect[VS=VS, PS=PS]
@@ -1,4 +0,0 @@
{
AssetLoader = "EffectAssetLoader",
Config = (GlitchyEditor.Assets.EffectAssetLoaderConfig){}
}
-159
View File
@@ -1,159 +0,0 @@
#define OutputEntityId
#include "ShaderHelpers.hlsl"
Texture2D AlbedoTexture : register(t0);
SamplerState AlbedoSampler : register(s0);
Texture2D<float3> NormalTexture : register(t1);
SamplerState NormalSampler : register(s1);
Texture2D<float> MetallicTexture : register(t2);
SamplerState MetallicSampler : register(s2);
Texture2D<float> RoughnessTexture : register(t3);
SamplerState RoughnessSampler : register(s3);
// Texture2D<float> AmbientTexture : register(t4);
// SamplerState AmbientSampler : register(s4);
#pragma EngineBuffer[ Name = "SceneConstants"; Binding = "Scene" ]
cbuffer SceneConstants : register(b0)
{
float4x4 ViewProjection;
}
#pragma EngineBuffer[ Name = "ObjectConstants"; Binding = "Object" ]
cbuffer ObjectConstants : register(b1)
{
float4x4 Transform;
/**
* \brief Inverted and transposed transform matrix.
* \remarks This matrix is used in order to correctly transform normal vectors.
*/
float4x3 Transform_InvT;
#ifdef OutputEntityId
uint EntityId;
#endif
}
cbuffer MaterialConstants : register(b2)
{
#pragma EditorVariable[ Name = "AlbedoColor"; Preview = "Albedo Color"; Type="Color" ]
float4 AlbedoColor = float4(1.0, 1.0, 1.0, 1.0);
#pragma EditorVariable[ Name = "NormalScaling"; Preview = "Normal Scaling" ]
float2 NormalScaling = float2(1.0, 1.0);
#pragma EditorVariable[ Name = "MetallicFactor"; Preview = "Metallic Factor"; Min = 0.0f; Max = 1.0f ]
float MetallicFactor = 1.0;
#pragma EditorVariable[ Name = "RoughnessFactor"; Preview = "Rougness Factor"; Min = 0.0f; Max = 1.0f ]
float RoughnessFactor = 1.0;
// float AmbientFactor = 1.0;
}
struct VS_IN
{
float3 Position : POSITION;
float3 Normal : NORMAL;
// Todo: Tangent.w... handedness
float3 Tangent : TANGENT;
float2 TexCoord : TEXCOORD;
};
struct PS_IN
{
float4 Position : SV_POSITION;
float3 WorldPosition : WORLDPOSITION;
float3 Normal : NORMAL;
float3 Tangent : TANGENT;
float2 TexCoord : TEXCOORD;
//nointerpolation float Handedness : HANDEDNESS;
#ifdef OutputEntityId
nointerpolation uint EntityId : ENTITYID;
#endif
};
PS_IN VS(VS_IN input)
{
PS_IN output;
float4 worldPosition = mul(Transform, float4(input.Position, 1));
output.Position = mul(ViewProjection, worldPosition);
output.WorldPosition = worldPosition.xyz / worldPosition.w;
output.Normal = mul(Transform_InvT, input.Normal);
output.Tangent = mul((float3x3)Transform, input.Tangent);
// TODO: output.Handedness = input.Tangent.w
output.TexCoord = input.TexCoord;
output.EntityId = EntityId;
return output;
}
struct PS_OUT
{
float4 Albedo : SV_TARGET0;
// RG: TextureNormal.XY BA: GeoNrm.XY
float4 Normal : SV_TARGET1;
// R: GeoNrm.Z GBA: GeoTan.XYZ
float4 Tangent : SV_TARGET2;
float4 Position : SV_TARGET3;
// R: Metallicity G: Roughness B: Ambient
float4 Material : SV_TARGET4;
#ifdef OutputEntityId
uint EntityId : SV_TARGET5;
#endif
};
PS_OUT PS(PS_IN input)
{
// Build tangent space
float3 normal = normalize(input.Normal);
float3 tangent = normalize(input.Tangent - dot(input.Tangent, normal) * input.Normal);
// TODO: float3 bitangent = input.Handedness * cross(normal, tangent);
float3 bitangent = -cross(normal, tangent);
//float3x3 tangentTransform = float3x3(tangent, bitangent, normal);
//tangentTransform = transpose(tangentTransform);
float4 texAlbedo = AlbedoTexture.Sample(AlbedoSampler, input.TexCoord);
float3 texNormal = NormalTexture.Sample(NormalSampler, input.TexCoord);
texNormal.xy = texNormal.xy * 2.0 - 1.0;
float texMetallic = MetallicTexture.Sample(MetallicSampler, input.TexCoord);
float texRoughness = RoughnessTexture.Sample(RoughnessSampler, input.TexCoord);
//float3 objectNormal = mul(tangentTransform, texNormal);
//float3 worldNormal = mul(objectNormal, (float3x3)Transform);
float4 finalAlbedo = texAlbedo * AlbedoColor;
float3 finalNormal = ScaleNormal(texNormal, NormalScaling);
float finalMetallic = texMetallic * MetallicFactor;
float finalRoughness = texRoughness * RoughnessFactor;
/////////////TODO: REMOVEME
//worldNormal = max(worldNormal - 10000000, normal);
//texAlbedo = max(texAlbedo - 10000000, 1.0);
//texMetallic = max(texMetallic - 10000000, 0.0);
//texRoughness = max(texRoughness - 10000000, 0.1);
/////////////TODO: END_REMOVEME
PS_OUT output;
output.Albedo = finalAlbedo;
//output.Normal = float4(objectNormal, 1.0);
output.Normal = float4(finalNormal.xy, normal.xy);
output.Tangent = float4(normal.z, tangent.xyz);
output.Position = float4(input.WorldPosition, 1.0);
output.Material = float4(finalMetallic, finalRoughness, 1.0, 0);
#ifdef OutputEntityId
output.EntityId = input.EntityId;
#endif
return output;
}
#pragma Effect[VS = VS; PS = PS]
@@ -1,4 +0,0 @@
{
AssetLoader = "EffectAssetLoader",
Config = (GlitchyEditor.Assets.EffectAssetLoaderConfig){}
}
@@ -1,126 +0,0 @@
#include "ShaderHelpers.hlsl"
#include "PBR.hlsl"
#define Render 0
#define Inspect_NormalDistribution 1
#define Inspect_GeometryFunction 2
#define Inspect_Fresnel 3
#define Inspect_Normal 4
#define OUTPUT Render
SamplerState Sampler : register(s0);
Texture2D GBuffer_Albedo : register(t0);
Texture2D GBuffer_Normal : register(t1);
Texture2D GBuffer_Tangent : register(t2);
Texture2D GBuffer_Position : register(t3);
Texture2D GBuffer_Material : register(t4);
cbuffer Constants
{
float3 CameraPos;
float2 Scaling;
}
cbuffer LightConstants
{
float3 LightColor;
float Illuminance;
float3 LightDir;
}
struct VS_IN
{
float2 Position : POSITION;
float2 TexCoord : TEXCOORD0;
};
struct PS_IN
{
float4 Position : SV_POSITION;
float2 TexCoord : TEXCOORD;
};
PS_IN VS(VS_IN input)
{
PS_IN output;
output.Position = float4(input.Position, 0, 1);
output.TexCoord = input.TexCoord * Scaling;
return output;
}
float4 PS(PS_IN input) : SV_TARGET
{
// Load Data from GBuffer
float4 rawAlbedo = GBuffer_Albedo.Sample(Sampler, input.TexCoord);
float4 rawNormal = GBuffer_Normal.Sample(Sampler, input.TexCoord);
float4 rawTangent = GBuffer_Tangent.Sample(Sampler, input.TexCoord);
float4 rawPosition = GBuffer_Position.Sample(Sampler, input.TexCoord);
float4 rawMaterial = GBuffer_Material.Sample(Sampler, input.TexCoord);
// Extract data from GBuffer
float3 albedo = rawAlbedo.rgb;
//float3 surfaceNormal = normalize(rawNormal.xyz);
float3 worldPosition = rawPosition.xyz;
float metallic = rawMaterial.r;
float roughness = rawMaterial.g;
float3 textureNormal = DecompressNormal(rawNormal.rg);
float3 rawGeoNrm = float3(rawNormal.ba, rawTangent.r);
float3 rawGeoTan = rawTangent.gba;
// Reconstruct normal space
float3 normal = normalize(rawGeoNrm);
float3 tangent = normalize(rawGeoTan - dot(rawGeoTan, normal) * normal);
float3 bitangent = -cross(normal, tangent);
float3x3 tangentTransform = float3x3(tangent, bitangent, normal);
float3 surfaceNormal = mul(textureNormal, tangentTransform);
float3 lightDir = normalize(LightDir);
float3 viewDir = normalize(CameraPos - worldPosition.xyz);
float3 halfway = normalize(lightDir + viewDir);
float n_dot_v = max(dot(surfaceNormal, viewDir), 0.0f);
float n_dot_h = max(dot(surfaceNormal, halfway), 0.0f);
float n_dot_l = max(dot(surfaceNormal, lightDir), 0.0f);
float nrmDist = NormalDistributionGGX(surfaceNormal, halfway, roughness);
float geo = GeometrySmith(surfaceNormal, viewDir, lightDir, roughness);
float3 F0 = 0.04f;
F0 = lerp(F0, albedo, metallic);
float3 fresnel = FresnelSchlick(n_dot_h, F0);
float3 ks = fresnel;
float3 kd = 1.0f - ks;
// Metals have no diffuse light
kd *= 1.0f - metallic;
float3 diffuse = albedo / PI;
float3 specular = (nrmDist * fresnel * geo) / max(4 * n_dot_v * n_dot_l, 0.0001f);
float3 luminanceColor = LightColor * Illuminance;
float3 final = (kd * diffuse + specular) * luminanceColor * n_dot_l;
#if OUTPUT == Inspect_NormalDistribution
final = max(final - 10000000, nrmDist.xxx);
#elif OUTPUT == Inspect_GeometryFunction
final = max(final - 10000000, geo.xxx);
#elif OUTPUT == Inspect_Fresnel
final = max(final - 10000000, fresnel);
#elif OUTPUT == Inspect_Normal
final = max(final - 10000000, surfaceNormal / 2 + 0.5f);
#endif
return float4(final, 1);
}
#pragma Effect[VS = VS; PS = PS]
@@ -1,4 +0,0 @@
{
AssetLoader = "EffectAssetLoader",
Config = (GlitchyEditor.Assets.EffectAssetLoaderConfig){}
}
+3 -36
View File
@@ -1,5 +1,3 @@
#define EDITOR
Texture2D Texture : register(t0);
SamplerState Sampler : register(s0);
@@ -15,9 +13,6 @@ struct VS_Input
float4x4 Transform : TRANSFORM;
float4 Color : COLOR;
float4 UVTransform : TEXCOORD1;
#ifdef EDITOR
uint EntityId : ENTITYID;
#endif
};
struct PS_Input
@@ -25,9 +20,6 @@ struct PS_Input
float4 Position : SV_Position;
float2 Texcoord : TEXCOORD;
float4 Color : COLOR;
#ifdef EDITOR
nointerpolation uint EntityId : ENTITYID;
#endif
};
PS_Input VS(VS_Input input)
@@ -38,37 +30,12 @@ PS_Input VS(VS_Input input)
output.Texcoord = input.UVTransform.xy + input.UVTransform.zw * input.Texcoord;
output.Color = input.Color;
// Premultiply Alpha
output.Color.rgb *= output.Color.a;
#ifdef EDITOR
output.EntityId = input.EntityId;
#endif
return output;
}
struct PS_Output
float4 PS(PS_Input input) : SV_Target0
{
float4 Color : SV_Target0;
#ifdef EDITOR
uint EntityId : SV_TARGET1;
#endif
};
PS_Output PS(PS_Input input)
{
PS_Output output;
output.Color = Texture.Sample(Sampler, input.Texcoord) * input.Color;
clip(output.Color.a - 0.001f);
#ifdef EDITOR
output.EntityId = input.EntityId;
#endif
return output;
return Texture.Sample(Sampler, input.Texcoord) * input.Color;
}
#pragma Effect[VS = VS; PS = PS]
#effect[VS=VS, PS=PS]
@@ -1,4 +0,0 @@
{
AssetLoader = "EffectAssetLoader",
Config = (GlitchyEditor.Assets.EffectAssetLoaderConfig){}
}
@@ -1,52 +0,0 @@
Texture2D Texture : register(t0);
SamplerState Sampler : register(s0);
cbuffer Constants
{
float4x4 ViewProjection;
float ColorOffset = 0.5f;
float AlphaOffset = 0.0f;
float ColorScale = 0.5f;
float AlphaScale = 1.0f;
float2 TextureSizeInPixels;
}
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 : TEXCOORD0;
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
{
float4 color = Texture.Sample(Sampler, input.Texcoord);
float4 final = float4(ColorOffset.xxx, AlphaOffset) + color * float4(ColorScale.xxx, AlphaScale);
return final;
}
#pragma Effect[VS=VS; PS=PS]
@@ -1,4 +0,0 @@
{
AssetLoader = "EffectAssetLoader",
Config = (GlitchyEditor.Assets.EffectAssetLoaderConfig){}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 B

@@ -1,23 +0,0 @@
{
AssetLoader = "EditorTextureAssetLoader",
Config = (GlitchyEditor.Assets.EditorTextureAssetLoaderConfig){
_samplerStateDescription = {
MinFilter = .Linear,
MagFilter = .Linear,
MipFilter = .Linear,
ComparisonFunction = .Never,
AddressModeU = .Clamp,
AddressModeV = .Clamp,
AddressModeW = .Clamp,
MipMinLOD = -340282346638528859811704183484516925440,
MipMaxLOD = 340282346638528859811704183484516925440,
MaxAnisotropy = 1,
BorderColor = {
R = 1,
G = 1,
B = 1,
A = 1
}
}
}
}
Binary file not shown.
@@ -1,23 +0,0 @@
{
AssetLoader = "EditorTextureAssetLoader",
Config = (GlitchyEditor.Assets.EditorTextureAssetLoaderConfig){
_samplerStateDescription = {
MinFilter = .Linear,
MagFilter = .Linear,
MipFilter = .Linear,
ComparisonFunction = .Never,
AddressModeU = .Clamp,
AddressModeV = .Clamp,
AddressModeW = .Clamp,
MipMinLOD = -340282346638528859811704183484516925440,
MipMaxLOD = 340282346638528859811704183484516925440,
MaxAnisotropy = 1,
BorderColor = {
R = 1,
G = 1,
B = 1,
A = 1
}
}
}
}
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 B

@@ -1,23 +0,0 @@
{
AssetLoader = "EditorTextureAssetLoader",
Config = (GlitchyEditor.Assets.EditorTextureAssetLoaderConfig){
_samplerStateDescription = {
MinFilter = .Linear,
MagFilter = .Linear,
MipFilter = .Linear,
ComparisonFunction = .Never,
AddressModeU = .Clamp,
AddressModeV = .Clamp,
AddressModeW = .Clamp,
MipMinLOD = -340282346638528859811704183484516925440,
MipMaxLOD = 340282346638528859811704183484516925440,
MaxAnisotropy = 1,
BorderColor = {
R = 1,
G = 1,
B = 1,
A = 1
}
}
}
}
@@ -1,23 +0,0 @@
{
AssetLoader = "EditorTextureAssetLoader",
Config = (GlitchyEditor.Assets.EditorTextureAssetLoaderConfig){
_generateMipMaps = true,
_isSrgb = true,
_samplerStateDescription = {
MinFilter = .Anisotropic,
MagFilter = .Anisotropic,
MipFilter = .Anisotropic,
ComparisonFunction = .Never,
AddressModeU = .Wrap,
AddressModeV = .Border,
AddressModeW = .Clamp,
MipMaxLOD = 160,
MaxAnisotropy = 16,
BorderColor = {
R = 0.756863,
G = 0.2,
A = 0.956863
}
}
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 MiB

@@ -1,23 +0,0 @@
{
AssetLoader = "EditorTextureAssetLoader",
Config = (GlitchyEditor.Assets.EditorTextureAssetLoaderConfig){
_samplerStateDescription = {
MinFilter = .Linear,
MagFilter = .Linear,
MipFilter = .Linear,
ComparisonFunction = .Never,
AddressModeU = .Clamp,
AddressModeV = .Clamp,
AddressModeW = .Clamp,
MipMinLOD = -340282346638528859811704183484516925440,
MipMaxLOD = 340282346638528859811704183484516925440,
MaxAnisotropy = 1,
BorderColor = {
R = 1,
G = 1,
B = 1,
A = 1
}
}
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 MiB

@@ -1,23 +0,0 @@
{
AssetLoader = "EditorTextureAssetLoader",
Config = (GlitchyEditor.Assets.EditorTextureAssetLoaderConfig){
_samplerStateDescription = {
MinFilter = .Linear,
MagFilter = .Linear,
MipFilter = .Linear,
ComparisonFunction = .Never,
AddressModeU = .Clamp,
AddressModeV = .Clamp,
AddressModeW = .Clamp,
MipMinLOD = -340282346638528859811704183484516925440,
MipMaxLOD = 340282346638528859811704183484516925440,
MaxAnisotropy = 1,
BorderColor = {
R = 1,
G = 1,
B = 1,
A = 1
}
}
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

@@ -1,24 +0,0 @@
{
AssetLoader = "EditorTextureAssetLoader",
Config = (GlitchyEditor.Assets.EditorTextureAssetLoaderConfig){
_isSrgb = true,
_samplerStateDescription = {
MinFilter = .Linear,
MagFilter = .Linear,
MipFilter = .Linear,
ComparisonFunction = .Never,
AddressModeU = .Clamp,
AddressModeV = .Clamp,
AddressModeW = .Clamp,
MipMinLOD = -340282346638528859811704183484516925440,
MipMaxLOD = 340282346638528859811704183484516925440,
MaxAnisotropy = 1,
BorderColor = {
R = 1,
G = 1,
B = 1,
A = 1
}
}
}
}
@@ -1,28 +0,0 @@
{
Effect = "content/Shaders/myEffect.hlsl",
Textures = [
"AlbedoTexture": "Textures/TestMat/rustediron2_albedo.png"
],
Variables = [
"AlbedoColor": .ColorRGBA{
Value = {
R = 1,
G = 1,
B = 1,
A = 1
}
},
"NormalScaling": .Float2{
Value = {
X = 1,
Y = 1
}
},
"MetallicFactor": .Float{
Value = 1
},
"RoughnessFactor": .Float{
Value = 1
}
]
}
@@ -1,4 +0,0 @@
{
AssetLoader = "MaterialAssetLoader",
Config = (GlitchyEditor.Assets.ModelAssetLoaderConfig){}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 B

@@ -1,23 +0,0 @@
{
AssetLoader = "EditorTextureAssetLoader",
Config = (GlitchyEditor.Assets.EditorTextureAssetLoaderConfig){
_samplerStateDescription = {
MinFilter = .Linear,
MagFilter = .Linear,
MipFilter = .Linear,
ComparisonFunction = .Never,
AddressModeU = .Clamp,
AddressModeV = .Clamp,
AddressModeW = .Clamp,
MipMinLOD = -340282346638528859811704183484516925440,
MipMaxLOD = 340282346638528859811704183484516925440,
MaxAnisotropy = 1,
BorderColor = {
R = 1,
G = 1,
B = 1,
A = 1
}
}
}
}
@@ -1,23 +0,0 @@
{
AssetLoader = "EditorTextureAssetLoader",
Config = (GlitchyEditor.Assets.EditorTextureAssetLoaderConfig){
_isSrgb = true,
_samplerStateDescription = {
MinFilter = .Linear,
MipFilter = .Linear,
ComparisonFunction = .Never,
AddressModeU = .Clamp,
AddressModeV = .Clamp,
AddressModeW = .Clamp,
MipMinLOD = -340282346638528859811704183484516925440,
MipMaxLOD = 340282346638528859811704183484516925440,
MaxAnisotropy = 1,
BorderColor = {
R = 1,
G = 1,
B = 1,
A = 1
}
}
}
}
@@ -1,22 +0,0 @@
{
AssetLoader = "EditorTextureAssetLoader",
Config = (GlitchyEditor.Assets.EditorTextureAssetLoaderConfig){
_isSrgb = true,
_samplerStateDescription = {
MinFilter = .Linear,
ComparisonFunction = .Never,
AddressModeU = .Clamp,
AddressModeV = .Clamp,
AddressModeW = .Clamp,
MipMinLOD = -340282346638528859811704183484516925440,
MipMaxLOD = 340282346638528859811704183484516925440,
MaxAnisotropy = 1,
BorderColor = {
R = 1,
G = 1,
B = 1,
A = 1
}
}
}
}
-121
View File
@@ -1,121 +0,0 @@
using System;
using GlitchyEngine;
using System.IO;
using Bon;
using GlitchyEngine.Content;
namespace GlitchyEditor;
[BonTarget]
class AssetConfig
{
[BonIgnore]
public bool IgnoreFile = false;
[BonInclude]
public String AssetLoader ~ delete _;
[BonInclude]
public AssetLoaderConfig Config ~ delete _;
}
class AssetFile
{
private EditorContentManager _contentManager;
private String _path;
private String _identifier;
private String _assetConfigPath;
private AssetConfig _assetConfig ~ delete _;
private bool _isDirectory;
private Object _loadedAsset;
public bool IsDirectory => _isDirectory;
public StringView FilePath => _path;
public StringView Identifier => _identifier;
public const String ConfigFileExtension = ".ass";
public AssetConfig AssetConfig => _assetConfig;
public Object LoadedAsset => _loadedAsset;
[AllowAppend]
public this(EditorContentManager contentManager, StringView identifier, StringView path, bool isDirectory)
{
String identifierBuffer = append String(identifier);
String pathBuffer = append String(path);
String configPathBuffer = append String(path.Length + ConfigFileExtension.Length);
_identifier = identifierBuffer;
_path = pathBuffer;
configPathBuffer..Append(path).Append(ConfigFileExtension);
_assetConfigPath = configPathBuffer;
_contentManager = contentManager;
_isDirectory = isDirectory;
Log.EngineLogger.AssertDebug(File.Exists(_path), "File doesn't exist.");
FindAssetConfig();
}
// Loads the asset config (.ass) file or creates it.
private void FindAssetConfig()
{
if (File.Exists(_assetConfigPath))
{
LoadAssetConfig();
}
else
{
CreateDefaultAssetLoader();
}
}
private void CreateDefaultAssetLoader()
{
String fileExtension = Path.GetExtension(_path, .. scope .());
_assetConfig = new AssetConfig();
var assetLoader = _contentManager.GetDefaultAssetLoader(fileExtension);
// We don't have a loader -> we don't need a config
if (assetLoader == null)
return;
_assetConfig.AssetLoader = new String();
assetLoader.GetType().GetName(_assetConfig.AssetLoader);
_assetConfig.Config = assetLoader?.GetDefaultConfig();
_assetConfig.Config?.[Friend]_changed = true;
SaveAssetConfig();
}
private void LoadAssetConfig()
{
if (Bon.DeserializeFromFile(ref _assetConfig, _assetConfigPath) case .Err)
{
Log.EngineLogger.Error($"Failed to load asset config {_assetConfigPath}");
// TODO: Handle failure of asset config loading
Runtime.NotImplemented();
}
}
public void SaveAssetConfig()
{
gBonEnv.serializeFlags |= .Verbose;
Bon.SerializeIntoFile(_assetConfig, _assetConfigPath);
_assetConfig.Config.[Friend]_changed = false;
}
}
-343
View File
@@ -1,343 +0,0 @@
using GlitchyEngine;
using GlitchyEngine.Collections;
using GlitchyEngine.Renderer;
using System;
using System.Collections;
using System.IO;
using System.Linq;
namespace GlitchyEditor.Assets;
public class AssetNode
{
public String Name ~ delete _;
public String Path ~ delete _;
public bool IsDirectory;
public AssetFile AssetFile ~ delete _;
public List<SubAsset> SubAssets ~ {
SubAssets?.ClearAndDeleteItems();
delete SubAssets;
}
public Texture2D PreviewImage ~ _?.ReleaseRef();
}
public class SubAsset
{
public AssetNode Asset;
public String Name ~ delete _;
//public String AssetInternalPath ~ delete _;
public Texture2D PreviewImage ~ _?.ReleaseRef();
}
class AssetHierarchy
{
FileSystemWatcher fsw ~ {
_.StopRaisingEvents();
delete _;
};
bool _fileSystemDirty = false;
internal TreeNode<AssetNode> _assetHierarchy = null ~ DeleteTreeAndChildren!(_);
private append Dictionary<StringView, TreeNode<AssetNode>> _pathToAssetNode = .();
private append String _contentDirectory = .();
private EditorContentManager _contentManager;
public StringView ContentDirectory
{
get => _contentDirectory;
private set
{
_contentDirectory.Clear();
_contentDirectory.Append(value);
Path.Fixup(_contentDirectory);
}
}
public this(EditorContentManager contentManager)
{
_contentManager = contentManager;
}
public void SetContentDirectory(StringView contentDirectory)
{
ContentDirectory = contentDirectory;
_fileSystemDirty = true;
SetupFileSystemWatcher();
Update();
}
/// Initializes the FSW for the current ContentDirectory and registers the events.
private void SetupFileSystemWatcher()
{
delete fsw;
fsw = new FileSystemWatcher(_contentDirectory);
fsw.IncludeSubdirectories = true;
fsw.OnChanged.Add(new (filename) => {
// Note: Gets fired for a directory if a file inside it is created/removed
Log.EngineLogger.Trace($"File content changed (\"{filename}\")");
//_fileSystemDirty = true;
FileContentChanged(filename);
});
fsw.OnCreated.Add(new (filename) => {
Log.EngineLogger.Trace($"File created (\"{filename}\")");
_fileSystemDirty = true;
});
fsw.OnDeleted.Add(new (filename) => {
Log.EngineLogger.Trace($"File deleted (\"{filename}\")");
_fileSystemDirty = true;
});
fsw.OnRenamed.Add(new (oldName, newName) => {
Log.EngineLogger.Trace($"File renamed (From \"{oldName}\" to \"{newName}\")");
_fileSystemDirty = true;
/*String contentFilePath = scope String();
Path.InternalCombine(contentFilePath, ContentDirectory, oldName);
//_fileSystemDirty = true;
TreeNode<AssetNode> fileNode = GetNodeFromPath(contentFilePath);
fileNode->*/
});
fsw.StartRaisingEvents();
}
/// Gets the tree node for the given filePath or null, if the file/directory doesn't exist.
/// @param filePath the path for which to return the tree node.
/// @remarks Do not hold a reference to the TreeNode because it can become invalid when the file hierarchy changes.
public Result<TreeNode<AssetNode>> GetNodeFromPath(StringView filePath)
{
if (_pathToAssetNode.TryGetValue(filePath, let treeNode))
{
return treeNode;
}
return .Err;
}
public bool FileExists(StringView filePath)
{
return _pathToAssetNode.ContainsKey(filePath);
}
public void Update()
{
// TODO: do we really need to do this in the update loop?
if (_fileSystemDirty)
{
UpdateFiles();
}
}
/// Rebuilds the asset file hierarchy.
private void UpdateFiles()
{
Log.EngineLogger.Trace($"Updating asset hierarchy");
if (_assetHierarchy == null)
{
// TODO: move to init?
_assetHierarchy = new TreeNode<AssetNode>(new AssetNode());
_assetHierarchy->Path = new String(ContentDirectory);
_assetHierarchy->Name = new String("Content");
Log.EngineLogger.Trace($"Created directory node for: \"{_assetHierarchy->Path}\"");
_pathToAssetNode.Add(ContentDirectory, _assetHierarchy);
}
void HandleFile(AssetNode node)
{
String identifier = scope .(node.Path.Length);
Path.GetRelativePath(node.Path, _contentDirectory, identifier);
node.AssetFile = new AssetFile(_contentManager, identifier, node.Path, node.IsDirectory);
}
/// Determines the files that belong to the given directory and adds them to the tree.
void AddFilesOfDirectory(TreeNode<AssetNode> directory)
{
// Filter that accepts all files.
String filter = scope $"{directory->Path}/*";
// Buffer used to hold the path of the files iterated below.
String filepathBuffer = scope String(256);
// Buffer used to hold the file extension of the files iterated below.
String extensionBuffer = scope String(16);
for (var entry in Directory.Enumerate(filter, .Files))
{
entry.GetFilePath(filepathBuffer..Clear());
Path.GetExtension(filepathBuffer, .. extensionBuffer..Clear());
// Ignore meta files.
if (extensionBuffer.Equals(AssetFile.ConfigFileExtension, .OrdinalIgnoreCase))
continue;
TreeNode<AssetNode> treeNode = directory.Children.Where(scope (node) => node.Value.Path == filepathBuffer).FirstOrDefault();
if (treeNode == null)
{
AssetNode assetNode = new AssetNode();
assetNode.Name = new String();
Path.GetFileName(filepathBuffer, assetNode.Name);
filepathBuffer.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
assetNode.Path = new String(filepathBuffer);
assetNode.IsDirectory = false;
treeNode = directory.AddChild(assetNode);
_pathToAssetNode.Add(assetNode.Path, treeNode);
//GrabSubAssets(node);
HandleFile(treeNode.Value);
Log.EngineLogger.Trace($"Created file node for: \"{assetNode.Path}\"");
}
}
}
void RemoveOrphanedEntries(TreeNode<AssetNode> node)
{
/// Removes the node and its children from _pathToAssetNode
void RemoveSubtree(TreeNode<AssetNode> tree)
{
_pathToAssetNode.Remove(tree->Path);
for (var child in tree.Children)
{
RemoveSubtree(child);
}
}
for (TreeNode<AssetNode> child in node.Children)
{
if (!Directory.Exists(child->Path) && !File.Exists(child->Path))
{
Log.EngineLogger.Trace($"Removed orphaned node for: \"{child->Path}\"");
@child.Remove();
RemoveSubtree(child);
DeleteTreeAndChildren!(child);
}
}
}
/// Adds the given directory to the specified tree.
/// Recursively adds all Files and Subdirectories.
void AddDirectoryToTree(String path, TreeNode<AssetNode> parentNode)
{
path.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
// Try to find the node for the specified path in the given parent
TreeNode<AssetNode> treeNode = parentNode.Children.Where(scope (node) => node.Value.Path == path).FirstOrDefault();
// Create new Node for the Directory, if no TreeNode exists.
if (treeNode == null)
{
AssetNode assetNode = new AssetNode();
assetNode.Path = new String(path);
assetNode.Name = new String();
assetNode.IsDirectory = true;
Path.GetFileName(assetNode.Path, assetNode.Name);
treeNode = parentNode.AddChild(assetNode);
_pathToAssetNode.Add(assetNode.Path, treeNode);
Log.EngineLogger.Trace($"Created directory node for: \"{assetNode.Path}\"");
}
String directoryNameBuffer = scope String(256);
// Filter that finds all entries of a directory.
String filter = scope $"{path}/*";
for (var directory in Directory.Enumerate(filter, .Directories))
{
directory.GetFilePath(directoryNameBuffer..Clear());
AddDirectoryToTree(directoryNameBuffer, treeNode);
}
AddFilesOfDirectory(treeNode);
RemoveOrphanedEntries(treeNode);
}
String filter = scope $"{ContentDirectory}/*";
String directoryNameBuffer = scope String(256);
for (var directory in Directory.Enumerate(filter, .Directories))
{
directory.GetFilePath(directoryNameBuffer..Clear());
AddDirectoryToTree(directoryNameBuffer, _assetHierarchy);
}
RemoveOrphanedEntries(_assetHierarchy);
_fileSystemDirty = false;
}
private void FileContentChanged(StringView fileName)
{
var fileName;
// Config files aren't really tracked but changing them effectively changes the corresponding file
// so we fire the event for them.
if (fileName.EndsWith(AssetFile.ConfigFileExtension))
fileName.RemoveFromEnd(AssetFile.ConfigFileExtension.Length);
String fileNameWithContentRoot = scope .();
Path.InternalCombine(fileNameWithContentRoot, _contentDirectory, fileName);
var nodeResult = GetNodeFromPath(fileNameWithContentRoot);
TreeNode<AssetNode> node = null;
if (!(nodeResult case .Ok(out node)))
{
// This happens, when we create new files.
Log.EngineLogger.Trace($"Could not find node for file \"{fileNameWithContentRoot}\"");
return;
}
// Don't fire event for directories.
if (node->IsDirectory)
return;
OnFileContentChanged(node.Value);
// TODO: Handle file changes (reload asset, etc...)
}
public delegate void FileContentChangedFunc(AssetNode node);
public Event<FileContentChangedFunc> OnFileContentChanged ~ _.Dispose();
}
@@ -1,15 +0,0 @@
namespace GlitchyEditor.Assets;
abstract class AssetPropertiesEditor
{
private AssetFile _asset;
public AssetFile Asset => _asset;
public this(AssetFile asset)
{
_asset = asset;
}
public abstract void ShowEditor();
}
@@ -1,101 +0,0 @@
using Bon;
using GlitchyEngine.Content;
using System;
using System.Collections;
using System.IO;
using GlitchyEngine;
using GlitchyEngine.Renderer;
namespace GlitchyEditor.Assets;
class EffectAssetPropertiesEditor : AssetPropertiesEditor
{
public this(AssetFile asset) : base(asset)
{
}
public override void ShowEditor()
{
}
public static AssetPropertiesEditor Factory(AssetFile assetFile)
{
return new Self(assetFile);
}
}
[BonTarget, BonPolyRegister]
class EffectAssetLoaderConfig : AssetLoaderConfig
{
}
class EffectAssetLoader : IAssetLoader //, IReloadingAssetLoader
{
private static readonly List<StringView> _fileExtensions = new .(){".hlsl"} ~ delete _;
public static List<StringView> FileExtensions => _fileExtensions;
public AssetLoaderConfig GetDefaultConfig()
{
return new EffectAssetLoaderConfig();
}
public Asset LoadAsset(Stream file, AssetLoaderConfig config, StringView assetIdentifier, StringView? subAsset, IContentManager contentManager)
{
Effect effect = new Effect(file, assetIdentifier, contentManager);
return effect;
/*StreamReader reader = scope .(file);
String text = scope .();
reader.ReadToEnd(text);
MaterialFile materialFile = scope .();
var result = Bon.Deserialize<MaterialFile>(ref materialFile, text);
if (result case .Err)
{
Log.EngineLogger.Error("Failed to load material.");
return null;
// TODO: return error material
}
Effect fx = new Effect(materialFile.Effect);
Material material = new Material(fx);
for (let (slotName, textureIdentifier) in materialFile.Textures)
{
Texture texture = contentManager.LoadAsset(textureIdentifier) as Texture;
if (texture == null)
{
Log.EngineLogger.Error("Failed to load texture.");
// TODO: LoadAsset should return an error texture.
}
material.SetTexture(slotName, texture);
}
fx.ReleaseRef();
/*for (let (slotName, textureIdentifier) in materialFile.Variables)
{
if (texture == null)
{
Log.EngineLogger.Error("Failed to load texture.");
// TODO: LoadAsset should return an error texture.
}
material.SetVariable(slotName, );
}*/
return material; //ModelLoader.LoadMesh(file, subAsset.Value, 0);*/
}
}
-10
View File
@@ -1,10 +0,0 @@
using GlitchyEngine.Content;
using System;
using System.IO;
namespace GlitchyEditor.Assets;
interface IAssetSaver
{
Result<void> EditorSaveAsset(Stream file, Asset asset, AssetLoaderConfig config, StringView assetIdentifier, StringView? subAsset, IContentManager contentManager);
}
@@ -1,8 +0,0 @@
using System.IO;
namespace GlitchyEditor.Assets;
interface IReloadingAssetLoader
{
public void ReloadAsset(AssetFile assetFile, Stream data);
}
@@ -1,530 +0,0 @@
using Bon;
using GlitchyEngine.Content;
using System;
using System.Collections;
using System.IO;
using GlitchyEngine;
using GlitchyEngine.Renderer;
using ImGui;
using GlitchyEngine.Math;
using System.Diagnostics;
using Bon.Integrated;
namespace GlitchyEditor.Assets;
class MaterialAssetPropertiesEditor : AssetPropertiesEditor
{
public static bool TryGetValue(Dictionary<String, Variant> parameters, String name, out Variant value)
{
if (parameters.TryGetValue(name, let param))
{
value = param;
return true;
}
value = ?;
return false;
}
mixin DropAssetTarget<T>() where T : Asset
{
Asset asset = null;
if (ImGui.BeginDragDropTarget())
{
ImGui.Payload* payload = ImGui.AcceptDragDropPayload("CONTENT_BROWSER_ITEM");
if (payload != null)
{
StringView fullpath = .((char8*)payload.Data, (int)payload.DataSize);
asset = Content.LoadAsset<Asset>(fullpath);
}
ImGui.EndDragDropTarget();
}
asset
}
public this(AssetFile asset) : base(asset)
{
}
public override void ShowEditor()
{
Material material = Asset.LoadedAsset as Material;
if (material == null)
return;
Effect effect = material?.Effect;
if (effect == null)
return;
ShowTextures(material, effect);
ShowVariables(material, effect);
}
private void ShowTextures(Material material, Effect effect)
{
for (let texture in effect.Textures)
{
ImGui.Button(texture.key);
if (ImGui.BeginDragDropTarget())
{
ImGui.Payload* payload = ImGui.AcceptDragDropPayload("CONTENT_BROWSER_ITEM");
if (payload != null)
{
StringView path = .((char8*)payload.Data, (int)payload.DataSize);
using (Texture2D newTexture = Content.LoadAsset<Texture2D>(path))//new Texture2D(path, true))
{
newTexture.SamplerState = SamplerStateManager.AnisotropicWrap;
material.SetTexture(texture.key, newTexture);
}
}
ImGui.EndDragDropTarget();
}
}
}
private void ShowVariables(Material material, Effect effect)
{
for (let (name, arguments) in effect.[Friend]_variableDescriptions)
{
let variable = effect.Variables[name];
bool hasPreviewName = TryGetValue(arguments, "Preview", var previewName);
StringView displayName = hasPreviewName ? previewName.Get<String>() : name;
bool hasPreviewType = TryGetValue(arguments, "Type", var previewType);
if (hasPreviewType && previewType.Get<String>() == "Color")
{
Log.EngineLogger.AssertDebug(variable.Type == .Float && variable.Rows == 1);
if (variable.Columns == 3)
{
material.GetVariable<Vector3>(variable.Name, var value);
value = (Vector3)ColorRGB.LinearToSRGB((ColorRGB)value);
if (ImGui.ColorEdit3(displayName.Ptr, *(float[3]*)&value))
{
value = (Vector3)ColorRGB.SRgbToLinear((ColorRGB)value);
material.SetVariable(variable.Name, value);
}
}
else if (variable.Columns == 4)
{
material.GetVariable<Vector4>(variable.Name, var value);
value = (Vector4)ColorRGBA.LinearToSRGB((ColorRGBA)value);
if (ImGui.ColorEdit4(displayName.Ptr, *(float[4]*)&value))
{
value = (Vector4)ColorRGBA.SRgbToLinear((ColorRGBA)value);
material.SetVariable(variable.Name, value);
}
}
}
else if (variable.Type == .Float && variable.Rows == 1)
{
bool hasMin = TryGetValue(arguments, "Min", var min);
bool hasMax = TryGetValue(arguments, "Max", var max);
for (int r < variable.Rows)
{
switch (variable.Columns)
{
case 1:
material.GetVariable<float>(variable.Name, var value);
float[1] minV = hasMin ? min.Get<float[1]>() : .(float.MinValue);
float[1] maxV = hasMax ? max.Get<float[1]>() : .(float.MaxValue);
if (ImGui.EditVector<1>(displayName, ref *(float[1]*)&value, .(), 0.1f, 100.0f, minV, maxV))
material.SetVariable(variable.Name, value);
case 2:
material.GetVariable<Vector2>(variable.Name, var value);
Vector2 minV = hasMin ? min.Get<Vector2>() : .(float.MinValue);
Vector2 maxV = hasMax ? max.Get<Vector2>() : .(float.MaxValue);
if (ImGui.EditVector2(displayName, ref value, .Zero, 0.1f, 100.0f, minV, maxV))
material.SetVariable(variable.Name, value);
case 3:
material.GetVariable<Vector3>(variable.Name, var value);
Vector3 minV = hasMin ? min.Get<Vector3>() : .(float.MinValue);
Vector3 maxV = hasMax ? max.Get<Vector3>() : .(float.MaxValue);
if (ImGui.EditVector3(displayName, ref value, .Zero, 0.1f, 100.0f, minV, maxV))
material.SetVariable(variable.Name, value);
case 4:
material.GetVariable<Vector4>(variable.Name, var value);
Vector4 minV = hasMin ? min.Get<Vector4>() : .(float.MinValue);
Vector4 maxV = hasMax ? max.Get<Vector4>() : .(float.MaxValue);
if (ImGui.EditVector4(displayName, ref value, .Zero, 0.1f, 100.0f, minV, maxV))
material.SetVariable(variable.Name, value);
}
}
}
}
}
public static AssetPropertiesEditor Factory(AssetFile assetFile)
{
return new Self(assetFile);
}
}
[BonTarget, BonPolyRegister]
class MaterialAssetLoaderConfig : AssetLoaderConfig
{
}
[BonTarget]
public enum VariableValue
{
case Float(float Value);
case Float2(Vector2 Value);
case Float3(Vector3 Value);
case Float4(Vector4 Value);
case Int(int Value);
case Int2(Int2 Value);
case Int3(Int3 Value);
case Int4(Int4 Value);
case ColorRGB(ColorRGB Value);
case ColorRGBA(ColorRGBA Value);
case None;
/*static this()
{
gBonEnv.typeHandlers.Add(typeof(Self),
((.)new => VariableValueSerialize, (.)new => VariableValueDeserialize));
}
static void VariableValueSerialize(BonWriter writer, ValueView value, BonEnvironment env)
{
Log.EngineLogger.Assert(value.type == typeof(Self));
let variableValue = value.Get<Self>();
writer.Type(variableValue)
using (writer.ObjectBlock())
{
Serialize.Value(writer, nameof(MaterialFile.Effect), materialFile.Effect, env);
Serialize.Value(writer, nameof(MaterialFile.Textures), materialFile.Textures, env);
}
}
static Result<void> VariableValueDeserialize(BonReader reader, ValueView val, BonEnvironment env)
{
return .Ok;
}*/
}
[BonTarget]
class MaterialFile
{
public String Effect ~ delete _;
public Dictionary<String, String> Textures ~ DeleteDictionaryAndKeysAndValues!(_);
public Dictionary<String, VariableValue> Variables ~
{
if (_ != null)
{
for (var entry in _)
{
delete entry.key;
//delete entry.value;
/*if (entry.value.HasValue)
entry.value->Dispose();*/
}
delete _;
}
};
/*static this()
{
gBonEnv.typeHandlers.Add(typeof(Self),
((.)new => MaterialSerialize, (.)new => MaterialDeserialize));
}
static void MaterialSerialize(BonWriter writer, ValueView value, BonEnvironment env)
{
Log.EngineLogger.Assert(value.type == typeof(Self));
let materialFile = value.Get<Self>();
using (writer.ObjectBlock())
{
Serialize.Value(writer, nameof(MaterialFile.Effect), materialFile.Effect, env);
Serialize.Value(writer, nameof(MaterialFile.Textures), materialFile.Textures, env);
}
}
private static void SerializeVariablesDictionary(BonWriter writer, MaterialFile materialFile, BonEnvironment env)
{
using (writer.ArrayBlock())
{
for (let (name, value) in materialFile.Variables)
{
let keyVal = ValueView(typeof(String), name);
Serialize.Value(writer, keyVal, env);
writer.Pair();
ValueView valueVal;// = ValueView(, entriesPtr + (currentIndex * entryStride) + entryValueOffset);
switch(value.GetType())
{
case typeof(ColorRGBA):
writer.Identifier("ColorRGBA");
default:
}
Serialize.Value(writer, valueVal, env);
}
}
}
static Result<void> MaterialDeserialize(BonReader reader, ValueView val, BonEnvironment env)
{
return .Ok;
}*/
}
class MaterialAssetLoader : IAssetLoader, IAssetSaver //, IReloadingAssetLoader
{
private static readonly List<StringView> _fileExtensions = new .(){".mat"} ~ delete _;
public static List<StringView> FileExtensions => _fileExtensions;
public AssetLoaderConfig GetDefaultConfig()
{
return new ModelAssetLoaderConfig();
}
public Asset LoadAsset(Stream file, AssetLoaderConfig config, StringView assetIdentifier, StringView? subAsset, IContentManager contentManager)
{
StreamReader reader = scope .(file);
String text = scope .();
reader.ReadToEnd(text);
MaterialFile materialFile = scope .();
var result = Bon.Deserialize<MaterialFile>(ref materialFile, text);
if (result case .Err)
{
Log.EngineLogger.Error("Failed to load material.");
Debug.SafeBreak();
return null;
// TODO: return error material
}
Effect fx = new Effect(materialFile.Effect);
Material material = new Material(fx);
for (let (slotName, textureIdentifier) in materialFile.Textures)
{
using (Texture texture = contentManager.LoadAsset(textureIdentifier) as Texture)
{
if (texture == null)
{
Log.EngineLogger.Error($"Failed to load texture \"{textureIdentifier}\".");
// TODO: LoadAsset should return an error texture.
}
material.SetTexture(slotName, texture);
}
}
fx.ReleaseRef();
for (let (slotName, variableValue) in materialFile.Variables)
{
switch (variableValue)
{
case .ColorRGBA(let value):
material.SetVariable(slotName, value);
case .ColorRGB(let value):
material.SetVariable(slotName, value);
case .Float(let value):
material.SetVariable(slotName, value);
case .Float2(let value):
material.SetVariable(slotName, value);
case .Float3(let value):
material.SetVariable(slotName, value);
case .Float4(let value):
material.SetVariable(slotName, value);
case .None:
default:
Log.EngineLogger.Error("Errorre");
}
}
return material;
}
public Result<void> EditorSaveAsset(Stream file, Asset asset, AssetLoaderConfig config, StringView assetIdentifier, StringView? subAsset, IContentManager contentManager)
{
Material material = asset as Material;
if (material == null)
{
Log.EngineLogger.Error("Asset must be a Material!");
return .Err;
}
MaterialFile materialFile = scope .();
materialFile.Effect = new String(material.Effect.Identifier);
materialFile.Textures = new .();
materialFile.Variables = new .();
//material.SetTexture();
for (let (slotName, textureViewBinding) in material.[Friend]_textures)
{
//materialFile.Textures.Add(slotName, textureViewBinding.)
}
Effect effect = material.Effect;
if (effect == null)
return .Ok;
for (let (name, arguments) in effect.[Friend]_variableDescriptions)
{
VariableValue variableValue = .None;
//Object variantValue = null;
let variable = effect.Variables[name];
bool hasPreviewType = MaterialAssetPropertiesEditor.TryGetValue(arguments, "Type", var previewType);
if (hasPreviewType && previewType.Get<String>() == "Color")
{
Log.EngineLogger.AssertDebug(variable.Type == .Float && variable.Rows == 1);
if (variable.Columns == 3)
{
material.GetVariable<ColorRGB>(variable.Name, var value);
value = ColorRGB.LinearToSRGB((ColorRGB)value);
//variantValue = new box value;
variableValue = .ColorRGB(value);
}
else if (variable.Columns == 4)
{
material.GetVariable<ColorRGBA>(variable.Name, var value);
value = ColorRGBA.LinearToSRGB((ColorRGBA)value);
variableValue = .ColorRGBA(value);
//variantValue = new box value;
}
}
else if (variable.Type == .Float && variable.Rows == 1)
{
switch (variable.Columns)
{
case 1:
material.GetVariable<float>(variable.Name, let value);
variableValue = .Float(value);
case 2:
material.GetVariable<Vector2>(variable.Name, let value);
variableValue = .Float2(value);
case 3:
material.GetVariable<Vector3>(variable.Name, let value);
variableValue = .Float3(value);
case 4:
material.GetVariable<Vector4>(variable.Name, let value);
variableValue = .Float4(value);
}
/*bool hasMin = TryGetValue(arguments, "Min", var min);
bool hasMax = TryGetValue(arguments, "Max", var max);
for (int r < variable.Rows)
{
switch (variable.Columns)
{
case 1:
material.GetVariable<float>(variable.Name, var value);
float[1] minV = hasMin ? min.Get<float[1]>() : .(float.MinValue);
float[1] maxV = hasMax ? max.Get<float[1]>() : .(float.MaxValue);
if (ImGui.EditVector<1>(displayName, ref *(float[1]*)&value, .(), 0.1f, 100.0f, minV, maxV))
material.SetVariable(variable.Name, value);
case 2:
material.GetVariable<Vector2>(variable.Name, var value);
Vector2 minV = hasMin ? min.Get<Vector2>() : .(float.MinValue);
Vector2 maxV = hasMax ? max.Get<Vector2>() : .(float.MaxValue);
if (ImGui.EditVector2(displayName, ref value, .Zero, 0.1f, 100.0f, minV, maxV))
material.SetVariable(variable.Name, value);
case 3:
material.GetVariable<Vector3>(variable.Name, var value);
Vector3 minV = hasMin ? min.Get<Vector3>() : .(float.MinValue);
Vector3 maxV = hasMax ? max.Get<Vector3>() : .(float.MaxValue);
if (ImGui.EditVector3(displayName, ref value, .Zero, 0.1f, 100.0f, minV, maxV))
material.SetVariable(variable.Name, value);
case 4:
material.GetVariable<Vector4>(variable.Name, var value);
Vector4 minV = hasMin ? min.Get<Vector4>() : .(float.MinValue);
Vector4 maxV = hasMax ? max.Get<Vector4>() : .(float.MaxValue);
if (ImGui.EditVector4(displayName, ref value, .Zero, 0.1f, 100.0f, minV, maxV))
material.SetVariable(variable.Name, value);
}
}*/
}
materialFile.Variables.Add(name, variableValue);
}
String text = scope .();
gBonEnv.serializeFlags |= .IncludeDefault | .Verbose;
Bon.Serialize<MaterialFile>(materialFile, text);
StreamWriter writer = scope .(file, .UTF8, 1024);
writer.Write(text);
return .Ok;
}
}
@@ -1,51 +0,0 @@
using Bon;
using GlitchyEngine.Content;
using System;
using System.Collections;
using System.IO;
using GlitchyEngine;
namespace GlitchyEditor.Assets;
class ModelAssetPropertiesEditor : AssetPropertiesEditor
{
public this(AssetFile asset) : base(asset)
{
}
public override void ShowEditor()
{
}
public static AssetPropertiesEditor Factory(AssetFile assetFile)
{
return new ModelAssetPropertiesEditor(assetFile);
}
}
[BonTarget, BonPolyRegister]
class ModelAssetLoaderConfig : AssetLoaderConfig
{
}
class ModelAssetLoader : IAssetLoader //, IReloadingAssetLoader
{
private static readonly List<StringView> _fileExtensions = new .(){".gltf", ".glb"} ~ delete _;
public static List<StringView> FileExtensions => _fileExtensions;
public AssetLoaderConfig GetDefaultConfig()
{
return new ModelAssetLoaderConfig();
}
public Asset LoadAsset(Stream file, AssetLoaderConfig config, StringView assetIdentifier, StringView? subAsset, IContentManager contentManager)
{
Log.EngineLogger.Assert(subAsset != null);
return ModelLoader.LoadMesh(file, subAsset.Value, 0);
}
}
@@ -1,6 +0,0 @@
using System;
namespace Bon.Integrated;
extension Serialize
{
}
@@ -1,352 +0,0 @@
using System;
using System.Collections;
using Bon;
using System.IO;
using GlitchyEngine;
using GlitchyEngine.Content;
using GlitchyEngine.Renderer;
using GlitchyEngine.Math;
using DirectXTK;
using ImGui;
namespace GlitchyEditor.Assets;
class TextureAssetPropertiesEditor : AssetPropertiesEditor
{
EditorTextureAssetLoaderConfig _textureConfig;
public this(AssetFile asset) : base(asset)
{
_textureConfig = asset.AssetConfig.Config as EditorTextureAssetLoaderConfig;
}
static char8*[3] _filterFuncNames = char8*[]("Point", "Linear", "Anisotropic");
public override void ShowEditor()
{
if (_textureConfig == null)
return;
bool generateMips = _textureConfig.GenerateMipMaps;
if (ImGui.Checkbox("Generate Mip Maps", &generateMips))
_textureConfig.GenerateMipMaps = generateMips;
bool isSrgb = _textureConfig.IsSRGB;
if (ImGui.Checkbox("Is sRGB", &isSrgb))
_textureConfig.IsSRGB = isSrgb;
SamplerStateDescription samplerStateDescription = _textureConfig.SamplerStateDescription;
void ShowFilterCombo(String label, ref FilterFunction filterFunction)
{
int32 selectedFilter = filterFunction.Underlying;
if (ImGui.Combo(label, &selectedFilter, &_filterFuncNames, 3))
filterFunction = (.)selectedFilter;
}
ImGui.Separator();
ImGui.TextUnformatted("Texture Filtering:");
ImGui.Separator();
ImGui.EnumCombo("Min Filter", ref samplerStateDescription.MinFilter);
ImGui.AttachTooltip("""
Sampling method used for minification.
If set to "Anisotropic" all Filters are set to "Anisotropic" internally.
""");
ImGui.EnumCombo("Mag Filter", ref samplerStateDescription.MagFilter);
ImGui.AttachTooltip("""
Sampling method used for magnification.
If set to "Anisotropic" all Filters are set to "Anisotropic" internally.
""");
ImGui.EnumCombo("Mip Map Filter", ref samplerStateDescription.MipFilter);
ImGui.AttachTooltip("""
Method used for mip-level sampling.
If set to "Anisotropic" all Filters are set to "Anisotropic" internally.
""");
if (samplerStateDescription.MagFilter == .Anisotropic ||
samplerStateDescription.MinFilter == .Anisotropic ||
samplerStateDescription.MipFilter == .Anisotropic)
{
ImGui.SliderScalar("Anisotropy Level", ref samplerStateDescription.MaxAnisotropy, 1, 16);
}
ImGui.NewLine();
ImGui.EnumCombo("Filter Mode", ref samplerStateDescription.FilterMode);
ImGui.AttachTooltip("Filtering method to use when sampling a texture.");
if (samplerStateDescription.FilterMode == .Comparison)
{
ImGui.EnumCombo("Comparison Function", ref samplerStateDescription.ComparisonFunction);
ImGui.AttachTooltip("""
The function that is used to compare the sampled data against the existing sampled data.
Only applies if Filter Mode is set to FilterMode.Comparison.
""");
}
ImGui.Separator();
ImGui.TextUnformatted("Wrapping");
ImGui.Separator();
ImGui.EnumCombo("Wrap Mode U", ref samplerStateDescription.AddressModeU);
ImGui.AttachTooltip("Method to use for resolving a u texture coordinate that is outside the 0 to 1 range.");
ImGui.EnumCombo("Wrap Mode V", ref samplerStateDescription.AddressModeV);
ImGui.AttachTooltip("Method to use for resolving a v texture coordinate that is outside the 0 to 1 range.");
ImGui.EnumCombo("Wrap Mode W", ref samplerStateDescription.AddressModeW);
ImGui.AttachTooltip("Method to use for resolving a w texture coordinate that is outside the 0 to 1 range.");
if (samplerStateDescription.AddressModeU == .Border ||
samplerStateDescription.AddressModeV == .Border ||
samplerStateDescription.AddressModeW == .Border)
{
ImGui.ColorEdit4("Border Color", ref samplerStateDescription.BorderColor);
}
ImGui.Separator();
ImGui.TextUnformatted("Mip Maps");
ImGui.Separator();
ImGui.DragFloat("Mip LOD Bias", &samplerStateDescription.MipLODBias, 0.1f);
ImGui.AttachTooltip("""
Offset from the calculated mipmap level.
For example, if the GPU calculates that a texture should be sampled at mipmap level 3 and "Mip LOD Bias" is 2, then the texture will be sampled at mipmap level 5.
""");
ImGui.DragFloat("Min Mip LOD", &samplerStateDescription.MipMinLOD);
ImGui.AttachTooltip("Lower end of the mipmap range to clamp access to, where 0 is the largest and most detailed mipmap level and any level higher than that is less detailed.");
ImGui.DragFloat("Max LOD Bias", &samplerStateDescription.MipMaxLOD);
ImGui.AttachTooltip("""
Upper end of the mipmap range to clamp access to, where 0 is the largest and most detailed mipmap level and any level higher than that is less detailed.
This value must be greater than or equal to "Min Mip LOD". To have no upper limit on LOD set this to a large value.
""");
_textureConfig.SamplerStateDescription = samplerStateDescription;
}
public static AssetPropertiesEditor Factory(AssetFile assetFile)
{
return new TextureAssetPropertiesEditor(assetFile);
}
}
[BonTarget, BonPolyRegister]
class EditorTextureAssetLoaderConfig : AssetLoaderConfig
{
[BonInclude]
private bool _generateMipMaps;
[BonInclude]
private bool _isSrgb;
[BonInclude]
private SamplerStateDescription _samplerStateDescription = .();
public bool GenerateMipMaps
{
get => _generateMipMaps;
set => SetIfChanged(ref _generateMipMaps, value);
}
public bool IsSRGB
{
get => _isSrgb;
set => SetIfChanged(ref _isSrgb, value);
}
public SamplerStateDescription SamplerStateDescription
{
get => _samplerStateDescription;
set => SetIfChanged(ref _samplerStateDescription, value);
}
}
class EditorTextureAssetLoader : IAssetLoader, IReloadingAssetLoader
{
private static readonly List<StringView> _fileExtensions = new .(){".png", ".dds"} ~ delete _; // ".jpg", ".bmp"
public static List<StringView> FileExtensions => _fileExtensions;
public AssetLoaderConfig GetDefaultConfig()
{
return new EditorTextureAssetLoaderConfig();
}
public Asset LoadAsset(Stream data, AssetLoaderConfig config, StringView assetIdentifier, StringView? subAsset, IContentManager contentManager)
{
var config;
if (config == null)
{
config = GetDefaultConfig();
defer:: delete config;
}
Log.EngineLogger.AssertDebug(config is EditorTextureAssetLoaderConfig, "config has wrong type.");
return LoadTexture(data, (EditorTextureAssetLoaderConfig)config);
}
const String PngMagicWord = "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A";
const String DdsMagicWord = "DDS ";
enum TextureType
{
Unknown,
DDS,
PNG
}
private static TextureType GetTextureType(Stream data)
{
int64 position = data.Position;
var readResult = data.Read<char8[8]>();
data.Position = position;
char8[8] magicWord;
if (readResult case .Ok(out magicWord))
{
StringView strView = .(&magicWord, magicWord.Count);
if (strView.StartsWith(PngMagicWord))
{
return .PNG;
}
else if (strView.StartsWith(DdsMagicWord))
{
return .DDS;
}
else
{
Runtime.FatalError("Unknown image format.");
}
}
return .Unknown;
}
private static Texture LoadTexture(Stream data, EditorTextureAssetLoaderConfig config)
{
Debug.Profiler.ProfileResourceFunction!();
Texture texture = null;
switch(GetTextureType(data))
{
case .DDS:
texture = LoadDds(data, config);
case .PNG:
texture = LoadPng(data, config);
case .Unknown:
Runtime.FatalError("Unknown image format.");
}
Log.EngineLogger.AssertDebug(texture != null);
SetSampler(texture, config);
return texture;
}
public void ReloadAsset(AssetFile assetFile, Stream data)
{
Texture reloadingTexture = assetFile.LoadedAsset as Texture;
if (reloadingTexture == null)
{
Log.EngineLogger.Error($"{nameof(Self)}: Requested reload of \"{assetFile.FilePath}\" but it's not a Texture!");
return;
}
EditorTextureAssetLoaderConfig config = assetFile.AssetConfig.Config as EditorTextureAssetLoaderConfig;
if (config == null)
{
Log.EngineLogger.Error($"{nameof(Self)}: Config of asset \"{assetFile.FilePath}\" doesn't have the correct type!");
return;
}
switch(GetTextureType(data))
{
case .DDS:
ReloadDds(reloadingTexture as Texture2D, data, config);
case .PNG:
ReloadPng(reloadingTexture as Texture2D, data, config);
case .Unknown:
Runtime.FatalError("Unknown image format.");
}
SetSampler(reloadingTexture, config);
}
private static void SetSampler(Texture texture, EditorTextureAssetLoaderConfig config)
{
using (SamplerState samplerState = SamplerStateManager.GetSampler(config.SamplerStateDescription))
{
texture.SamplerState = samplerState;
}
}
private static void ReloadPng(Texture2D reloadingTexture, Stream data, EditorTextureAssetLoaderConfig config)
{
Debug.Profiler.ProfileResourceFunction!();
using (Texture2D newTexture = LoadPng(data, config))
{
reloadingTexture.[Friend]SneakySwappyTexture(newTexture);
}
}
private static Texture2D LoadPng(Stream data, EditorTextureAssetLoaderConfig config)
{
Debug.Profiler.ProfileResourceFunction!();
uint8[] pngData = new:ScopedAlloc! uint8[data.Length];
var result = data.TryRead(pngData);
if (result case .Err(let err))
{
Log.EngineLogger.Error($"Failed to read data from stream. Texture: Error: {err}");
}
uint8* rawData = ?;
uint32 width = 0, height = 0;
uint32 errorCode = LodePng.LodePng.Decode32(&rawData, &width, &height, pngData.Ptr, (.)pngData.Count);
Log.EngineLogger.Assert(errorCode == 0, "Failed to load png File");
// TODO: load as SRGB because PNGs are usually not stored as linear
//Texture2DDesc desc = .(width, height, srgb? .R8G8B8A8_UNorm_SRGB : .R8G8B8A8_UNorm, 1, 1, .Immutable);
Texture2DDesc desc = .(width, height, config.IsSRGB ? .R8G8B8A8_UNorm_SRGB : .R8G8B8A8_UNorm, 1, 1, .Immutable);
Texture2D texture = new Texture2D(desc);
texture.SetData<Color>((.)rawData);
// TODO: Generate mip maps
LodePng.LodePng.Free(rawData);
return texture;
}
private static void ReloadDds(Texture2D reloadingTexture, Stream data, EditorTextureAssetLoaderConfig config)
{
using (Texture2D newTexture = new [Friend]Texture2D(data))
{
reloadingTexture.[Friend]SneakySwappyTexture(newTexture);
}
}
private static Texture LoadDds(Stream data, EditorTextureAssetLoaderConfig config)
{
Texture2D texture = new [Friend]Texture2D(data);
return texture;
}
}
@@ -3,9 +3,6 @@ using GlitchyEngine.World;
using System;
using GlitchyEngine.Math;
using System.Collections;
using GlitchyEngine.Renderer;
using GlitchyEngine;
using GlitchyEngine.Content;
namespace GlitchyEditor.EditWindows
{
@@ -61,12 +58,6 @@ namespace GlitchyEditor.EditWindows
ShowComponentEditor<TransformComponent>("Transform", entity, => ShowTransformComponentEditor);
ShowComponentEditor<CameraComponent>("Camera", entity, => ShowCameraComponentEditor, => ShowComponentContextMenu<CameraComponent>);
ShowComponentEditor<SpriterRendererComponent>("Sprite Renderer", entity, => ShowSpriteRendererComponentEditor, => ShowComponentContextMenu<SpriterRendererComponent>);
ShowComponentEditor<MeshRendererComponent>("Mesh Renderer", entity, => ShowMeshRendererComponentEditor, => ShowComponentContextMenu<MeshRendererComponent>);
ShowComponentEditor<LightComponent>("Light", entity, => ShowLightComponentEditor, => ShowComponentContextMenu<LightComponent>);
ShowComponentEditor<MeshComponent>("Mesh", entity, => ShowMeshComponentEditor, => ShowComponentContextMenu<MeshComponent>);
ShowComponentEditor<Rigidbody2DComponent>("Rigidbody 2D", entity, => ShowRigidBody2DComponentEditor, => ShowComponentContextMenu<Rigidbody2DComponent>);
ShowComponentEditor<BoxCollider2DComponent>("Box collider 2D", entity, => ShowBoxCollider2DComponentEditor, => ShowComponentContextMenu<BoxCollider2DComponent>);
ShowComponentEditor<CircleCollider2DComponent>("Circle collider 2D", entity, => ShowCircleCollider2DComponentEditor, => ShowComponentContextMenu<CircleCollider2DComponent>);
ShowAddComponentButton(entity);
}
@@ -252,264 +243,7 @@ namespace GlitchyEditor.EditWindows
private static void ShowSpriteRendererComponentEditor(Entity entity, SpriterRendererComponent* spriteRendererComponent)
{
ColorRGBA spriteColor = ColorRGBA.LinearToSRGB(spriteRendererComponent.Color);
if (ImGui.ColorEdit4("Color", ref spriteColor))
spriteRendererComponent.Color = ColorRGBA.SRgbToLinear(spriteColor);
ImGui.Button("Texture");
if (ImGui.BeginDragDropTarget())
{
ImGui.Payload* payload = ImGui.AcceptDragDropPayload("CONTENT_BROWSER_ITEM");
if (payload != null)
{
Log.EngineLogger.Warning("");
StringView path = .((char8*)payload.Data, (int)payload.DataSize);
using (Texture2D texture = Content.LoadAsset<Texture2D>(path))
{
spriteRendererComponent.Sprite = texture;
}
}
ImGui.EndDragDropTarget();
}
ImGui.EditVector<4>("UV Transform", ref *(float[4]*)&spriteRendererComponent.UvTransform);
ImGui.Checkbox("Is Circle", &spriteRendererComponent.IsCircle);
}
private static void ShowMeshRendererComponentEditor(Entity entity, MeshRendererComponent* meshRendererComponent)
{
ImGui.TextUnformatted("Material:");
ImGui.SameLine();
Material material = meshRendererComponent.Material;
StringView identifier = material?.Identifier ?? "None";
ImGui.Button(identifier.ToScopeCStr!());
if (ImGui.BeginDragDropTarget())
{
ImGui.Payload* payload = ImGui.AcceptDragDropPayload("CONTENT_BROWSER_ITEM");
if (payload != null)
{
StringView fullpath = .((char8*)payload.Data, (int)payload.DataSize);
using (Material loadedMaterial = Content.LoadAsset<Material>(fullpath))
{
meshRendererComponent.Material = loadedMaterial;
}
}
ImGui.EndDragDropTarget();
}
/*Effect effect = material?.Effect;
if (effect == null)
return;*/
// Show a preview of the material here!
}
private static void ShowRigidBody2DComponentEditor(Entity entity, Rigidbody2DComponent* rigidBodyComponent)
{
const String[?] bodyTypeStrings = .("Static", "Dynamic", "Kinematic");
String bodyTypeName = bodyTypeStrings[rigidBodyComponent.BodyType.Underlying];
if (ImGui.BeginCombo("Type", bodyTypeName.CStr()))
{
for (int i = 0; i < 3; i++)
{
bool isSelected = (bodyTypeName == bodyTypeStrings[i]);
if (ImGui.Selectable(bodyTypeStrings[i], isSelected))
{
rigidBodyComponent.BodyType = (.)i;
}
if (isSelected)
ImGui.SetItemDefaultFocus();
}
ImGui.EndCombo();
}
ImGui.Checkbox("Fixed Rotation", &rigidBodyComponent.FixedRotation);
}
private static void ShowBoxCollider2DComponentEditor(Entity entity, BoxCollider2DComponent* boxCollider)
{
float textWidth = ImGui.CalcTextSize("Offset".CStr()).x;
textWidth += ImGui.GetStyle().FramePadding.x * 3.0f;
Vector2 offset = boxCollider.Offset;
if (ImGui.EditVector2("Offset", ref offset, .Zero, 0.1f, textWidth))
boxCollider.Offset = offset;
Vector2 size = boxCollider.Size;
if (ImGui.EditVector2("Size", ref size, .Zero, 0.1f, textWidth))
boxCollider.Size = size;
float density = boxCollider.Density;
if (ImGui.DragFloat("Density", &density, 0.0f, 0.1f, textWidth))
boxCollider.Density = density;
float friction = boxCollider.Friction;
if (ImGui.DragFloat("Friction", &friction, 0.0f, 0.1f, textWidth))
boxCollider.Friction = friction;
float restitution = boxCollider.Restitution;
if (ImGui.DragFloat("Restitution", &restitution, 0.0f, 0.1f, textWidth))
boxCollider.Restitution = restitution;
float restitutionThreshold = boxCollider.RestitutionThreshold;
if (ImGui.DragFloat("RestitutionThreshold", &restitutionThreshold, 0.0f, 0.1f, textWidth))
boxCollider.RestitutionThreshold = restitutionThreshold;
}
private static void ShowCircleCollider2DComponentEditor(Entity entity, CircleCollider2DComponent* circleCollider)
{
float textWidth = ImGui.CalcTextSize("Offset".CStr()).x;
textWidth += ImGui.GetStyle().FramePadding.x * 3.0f;
Vector2 offset = circleCollider.Offset;
if (ImGui.EditVector2("Offset", ref offset, .Zero, 0.1f, textWidth))
circleCollider.Offset = offset;
float radius = circleCollider.Radius;
if (ImGui.DragFloat("Radius", &radius, 0.0f, 0.1f, textWidth))
circleCollider.Radius = radius;
float density = circleCollider.Density;
if (ImGui.DragFloat("Density", &density, 0.0f, 0.1f, textWidth))
circleCollider.Density = density;
float friction = circleCollider.Friction;
if (ImGui.DragFloat("Friction", &friction, 0.0f, 0.1f, textWidth))
circleCollider.Friction = friction;
float restitution = circleCollider.Restitution;
if (ImGui.DragFloat("Restitution", &restitution, 0.0f, 0.1f, textWidth))
circleCollider.Restitution = restitution;
float restitutionThreshold = circleCollider.RestitutionThreshold;
if (ImGui.DragFloat("RestitutionThreshold", &restitutionThreshold, 0.0f, 0.1f, textWidth))
circleCollider.RestitutionThreshold = restitutionThreshold;
}
private static void LabelColumn(StringView label)
{
ImGui.TextUnformatted(label);
ImGui.NextColumn();
}
private static void ShowLightComponentEditor(Entity entity, LightComponent* lightComponent)
{
ImGui.Columns(2);
defer ImGui.Columns(1);
const String[?] strings = String[]("Directional", "Point", "Spot");
var light = ref lightComponent.SceneLight;
String typeName = strings[light.LightType.Underlying];
LabelColumn("Type");
if (ImGui.BeginCombo("##Type", typeName.CStr()))
{
for (int i = 0; i < 3; i++)
{
bool isSelected = (typeName == strings[i]);
if (ImGui.Selectable(strings[i], isSelected))
{
light.LightType = (.)i;
}
if (isSelected)
ImGui.SetItemDefaultFocus();
}
ImGui.EndCombo();
}
ImGui.NextColumn();
LabelColumn("Color");
ColorRGB color = ColorRGB.LinearToSRGB(light.Color);
if (ImGui.ColorEdit3("##Color", ref color))
light.Color = ColorRGB.SRgbToLinear(color);
ImGui.NextColumn();
LabelColumn("Illuminance");
float illuminance = light.Illuminance;
if (ImGui.DragFloat("##Illuminance", &illuminance, 0.1f, 0.0f, float.MaxValue))
light.Illuminance = illuminance;
}
private static void ShowMeshComponentEditor(Entity entity, MeshComponent* meshComponent)
{
ImGui.TextUnformatted("Mesh:");
ImGui.SameLine();
GeometryBinding mesh = meshComponent.Mesh;
StringView identifier = mesh?.Identifier ?? "None";
ImGui.Button(identifier.ToScopeCStr!());
if (ImGui.BeginDragDropTarget())
{
ImGui.Payload* payload = ImGui.AcceptDragDropPayload("CONTENT_BROWSER_ITEM");
if (payload != null)
{
StringView fullpath = .((char8*)payload.Data, (int)payload.DataSize);
/*int idx = fullpath.IndexOf('#');
if (idx == -1)
{
// Doesn't make sense here, we NEED a sub asset
Runtime.NotImplemented();
}
StringView filePath = fullpath.Substring(0, idx);
StringView meshName = fullpath.Substring(idx + 1);*/
using (GeometryBinding geometry = Content.LoadAsset<GeometryBinding>(fullpath))
{
meshComponent.Mesh = geometry;
}
// TODO: support multiple primitives (treat every primitive as a single mesh? or: mesh can have multiple primitives)
/*using (GeometryBinding binding = ModelLoader.LoadMesh(filePath, meshName, 0))
{
meshComponent.Mesh = binding;
}*/
//ModelLoader.LoadModel(scope .(path), )
/*using (Texture2D newTexture = new Texture2D(path, true))
{
newTexture.SamplerState = SamplerStateManager.AnisotropicWrap;
material.SetTexture(texture.key, newTexture);
}*/
}
ImGui.EndDragDropTarget();
}
ImGui.ColorEdit4("Color", ref spriteRendererComponent.Color);
}
private static void ShowAddComponentButton(Entity entity)
@@ -525,10 +259,6 @@ namespace GlitchyEditor.EditWindows
void ShowComponentButton<TComponent>(String name) where TComponent : struct, new
{
// If the entity already has this component, don't show the option to add it
if (entity.HasComponent<TComponent>())
return;
float textWidth = ImGui.CalcTextSize(name.CStr()).x;
buttonWidth = Math.Max(buttonWidth, textWidth + ImGui.GetStyle().FramePadding.x * 2);
@@ -558,12 +288,6 @@ namespace GlitchyEditor.EditWindows
ShowComponentButton<CameraComponent>("Camera");
ShowComponentButton<SpriterRendererComponent>("Sprite Renderer");
ShowComponentButton<LightComponent>("Light");
ShowComponentButton<Rigidbody2DComponent>("Rigidbody 2D");
ShowComponentButton<BoxCollider2DComponent>("Box collider 2D");
ShowComponentButton<CircleCollider2DComponent>("Circle collider 2D");
ShowComponentButton<MeshComponent>("Mesh");
ShowComponentButton<MeshRendererComponent>("Mesh Renderer");
ImGui.EndCombo();
}
@@ -1,338 +0,0 @@
using ImGui;
using System;
using System.IO;
using GlitchyEngine.Collections;
using System.Collections;
using GlitchyEngine.Renderer;
using GlitchyEngine.Math;
using GlitchyEngine;
using GlitchyEditor.Assets;
namespace GlitchyEditor.EditWindows
{
using internal GlitchyEditor.EditorContentManager;
class ContentBrowserWindow : EditorWindow
{
// TODO: Get from project
//const String ContentDirectory = "./content";
private append String _currentDirectory = .();
private append String _selectedFile = .();
public static SubTexture2D s_FolderTexture;
public static SubTexture2D s_FileTexture;
public EditorContentManager _manager;
public StringView SelectedFile => _selectedFile;
public this(EditorContentManager contentManager)
{
_manager = contentManager;
}
protected override void InternalShow()
{
_manager.Update();
// Make sure we are in an existing directory.
if (!_manager.AssetHierarchy.FileExists(_currentDirectory))
{
_currentDirectory.Set(_manager.ContentDirectory);
}
if(!ImGui.Begin("Content Browser", &_open, .None))
{
ImGui.End();
return;
}
// Context menu when clicking on the background.
if (ImGui.BeginPopupContextWindow())
{
ShowCurrentFolderContextMenu();
ImGui.EndPopup();
}
ImGui.Columns(2);
DrawDirectorySideBar();
ImGui.NextColumn();
DrawCurrentDirectory();
ImGui.Columns(1);
ImGui.End();
}
/// Renders the context menu that is shown when the user right clicks on the background of the file browser.
private void ShowCurrentFolderContextMenu()
{
if (ImGui.MenuItem("Open in file browser..."))
{
if (Path.OpenFolder(_currentDirectory) case .Err)
Log.EngineLogger.Error("Failed to open directory in file browser.");
}
}
/// Renders a sidebar that shows a tree of all directories in the asset folder.
private void DrawDirectorySideBar()
{
for(var child in _manager.AssetHierarchy.[Friend]_assetHierarchy.Children)
{
ImGuiPrintEntityTree(child);
}
}
/// Renders an ImGui tree of all directories in the given tree.
/// @param tree The file hierarchy of which to render all directories.
private void ImGuiPrintEntityTree(TreeNode<AssetNode> tree)
{
if (!tree->IsDirectory)
return;
String name = tree->Name;
ImGui.TreeNodeFlags flags = .OpenOnArrow | .SpanAvailWidth;
if(tree.Children.Count == 0)
flags |= .Leaf;
if (tree->Path == _currentDirectory)
{
flags |= .Selected;
}
bool isOpen = ImGui.TreeNodeEx(name, flags, $"{name}");
if (ImGui.IsItemClicked(.Left))
{
_currentDirectory.Set(tree->Path);
}
if(isOpen)
{
for(var child in tree.Children)
{
ImGuiPrintEntityTree(child);
}
ImGui.TreePop();
}
}
private static Vector2 DirectoryItemSize = .(110, 110);
const Vector2 padding = .(24, 24);
/// Renders the contents of _currentDirectory.
private void DrawCurrentDirectory()
{
if (_currentDirectory.IsEmpty)
return;
ImGui.Style* style = ImGui.GetStyle();
float window_visible_x2 = ImGui.GetWindowPos().x + ImGui.GetWindowContentRegionMax().x;
// Get the node of the current directory.
var currentDirectoryNode = _manager.AssetHierarchy.GetNodeFromPath(_currentDirectory);
if (currentDirectoryNode case .Err)
{
Log.EngineLogger.Error($"No node exists for {_currentDirectory}.");
ImGui.TextUnformatted("Failed to display contents of directory.");
return;
}
for (var entry in currentDirectoryNode->Children)
{
ImGui.PushID(entry->Name);
DrawDirectoryItem(entry);
// X-Coordinate of the right side of the current entry.
float currentButtonRight = ImGui.GetItemRectMax().x;
// Expected right-Coordinate if next entry was on the same line.
float expectedButtonRight = currentButtonRight + style.ItemSpacing.x + DirectoryItemSize.X;
// If we aren't the last entry and the next button won't fit on the same line we start a new line.
if (entry != currentDirectoryNode->Children.Back && expectedButtonRight < window_visible_x2)
ImGui.SameLine();
ImGui.PopID();
}
}
/// Renders the button for the given directory item.
private void DrawDirectoryItem(TreeNode<AssetNode> entry)
{
ImGui.BeginChild("item", (.)DirectoryItemSize);
if (entry->Path == _selectedFile)
{
var color = ImGui.GetStyleColorVec4(.ButtonHovered);
ImGui.PushStyleColor(.Button, *color);
}
else
{
ImGui.PushStyleColor(.Button, ImGui.Vec4(0, 0, 0, 0));
}
// TODO: preview images
SubTexture2D image = entry->IsDirectory ? s_FolderTexture : s_FileTexture;
ImGui.ImageButton(image, (.)(DirectoryItemSize - padding));
ImGui.PopStyleColor();
if (ImGui.BeginDragDropSource())
{
String fullpath = scope String(entry->Path);
// TODO: this is dirty
if (fullpath.StartsWith(_manager.ContentDirectory, .OrdinalIgnoreCase))
fullpath.Remove(0, _manager.ContentDirectory.Length);
Path.Fixup(fullpath);
ImGui.SetDragDropPayload("CONTENT_BROWSER_ITEM", fullpath.CStr(), (.)fullpath.Length, .Once);
ImGui.EndDragDropSource();
}
if (ImGui.IsItemHovered() && ImGui.IsMouseClicked(.Left))
{
if (_selectedFile != entry->Path)
{
_selectedFile.Set(entry->Path);
}
}
if (ImGui.IsItemHovered() && ImGui.IsMouseDoubleClicked(.Left))
{
EntryDoubleClicked(entry);
}
ImGui.TextUnformatted(entry->Name);
if (ImGui.BeginPopupContextWindow())
{
ShowItemContextMenu(entry);
ImGui.EndPopup();
}
if (entry->SubAssets?.Count > 0)
{
// Button for revealing sub assets (e.g. Meshes in 3D-Model)
ImGui.SameLine();
if (ImGui.Button(">"))
ImGui.OpenPopup("SubAssets");
}
if (ImGui.BeginPopup("SubAssets", .Popup))
{
for (var subAsset in entry->SubAssets)
{
ImGui.Button(subAsset.Name);
if (ImGui.BeginDragDropSource())
{
String fullpath = scope String(entry->Path);
fullpath.AppendF($"#{subAsset.Name}");
ImGui.SetDragDropPayload("CONTENT_BROWSER_ITEM", fullpath.CStr(), (.)fullpath.Length, .Once);
ImGui.EndDragDropSource();
}
}
ImGui.EndPopup();
}
DeleteItemPopup(entry);
ImGui.EndChild();
}
private void DeleteItemPopup(TreeNode<AssetNode> fileOrFolder)
{
// Always center this window when appearing
ImGui.Vec2 center = ImGui.GetMainViewport().GetCenter();
ImGui.SetNextWindowPos(center, .Appearing, ImGui.Vec2(0.5f, 0.5f));
// TODO: fix delete popup
if (ImGui.BeginPopupModal("Delete?", null, .AlwaysAutoResize))
{
ImGui.Text($"""
Delete "{fileOrFolder->Name}"?
""");
ImGui.Separator();
if (ImGui.Button("Yes", ImGui.Vec2(120, 0)))
{
ImGui.CloseCurrentPopup();
}
ImGui.SetItemDefaultFocus();
ImGui.SameLine();
if (ImGui.Button("Cancel", ImGui.Vec2(120, 0)))
{
ImGui.CloseCurrentPopup();
}
ImGui.EndPopup();
}
}
/// Shows the context menu for the given file/folder.
private void ShowItemContextMenu(TreeNode<AssetNode> fileOrFolder)
{
bool isFile = !fileOrFolder->IsDirectory;
if (ImGui.MenuItem("Show in file browser..."))
{
if (Path.OpenFolderAndSelectItem(fileOrFolder->Path) case .Err)
{
Log.EngineLogger.Error("Failed to show path in file browser.");
}
}
if (isFile && ImGui.MenuItem("Open file with..."))
{
if (Path.OpenWithDialog(fileOrFolder->Path) case .Err)
{
Log.EngineLogger.Error("Failed to show \"Open with...\" dialog.");
}
}
if (ImGui.MenuItem("Delete"))
{
ImGui.OpenPopup("Delete?");
}
}
private void EntryDoubleClicked(TreeNode<AssetNode> entry)
{
if (entry->IsDirectory)
{
_currentDirectory.Set(entry->Path);
}
else
{
if (Path.OpenFolder(entry->Path) case .Err)
Log.EngineLogger.Error("Failed to open directory in file browser.");
}
}
}
}
@@ -1,4 +1,3 @@
using System;
namespace GlitchyEditor.EditWindows
{
abstract class EditorWindow
@@ -23,58 +23,16 @@ namespace GlitchyEditor.EditWindows
public List<Entity> SelectedEntities => _selectedEntities;
public this(Editor editor, Scene scene)
public this(Scene scene)
{
_editor = editor;
SetContext(scene);
}
public void SetContext(Scene scene)
{
ClearEntitySelection();
_scene = scene;
}
/*public bool SelectEntityWithId(uint32 id, bool addToSelection = false)
{
if (!addToSelection)
_selectedEntities.Clear();
_scene.[Friend]_ecsWorld.IsValid(id);
_selectedEntities.Add();
}*/
/// Deselects all entities.
public void ClearEntitySelection()
{
_selectedEntities.Clear();
}
/// Selects the given entity.
/// @param entity The entity to select.
/// @param clearOldSelection If true the previously selected entities will be deselected. If false, the given entity will be added to the current selection.
public void SelectEntity(Entity entity, bool clearOldSelection = false)
{
if (clearOldSelection)
ClearEntitySelection();
_selectedEntities.Add(entity);
}
/// Deselects the given entity.
/// @param entity The entity to deselect.
public bool DeselectEntity(Entity entity)
{
return _selectedEntities.Remove(entity);
}
/// Returns whether or not the given entity is currently selected.
public bool IsEntitySelected(Entity entity)
{
return _selectedEntities.Contains(entity);
}
protected override void InternalShow()
{
if(!ImGui.Begin(s_WindowTitle, &_open, .MenuBar))
@@ -92,26 +50,10 @@ namespace GlitchyEditor.EditWindows
ImGui.EndPopup();
}
if (_editor.SceneViewportWindow.SelectionChanged)
{
var handle = _scene.[Friend]_ecsWorld.GetCurrentVersion(EcsEntity.[Friend]CreateEntityID(_editor.SceneViewportWindow.SelectedEntityId, 0));
if (handle case .Ok(let h))
{
Entity e = .(h, _scene);
SelectEntity(e, Input.IsKeyReleased(.Control));
}
else if (Input.IsKeyReleased(.Control))
{
ClearEntitySelection();
}
}
ShowEntityHierarchy();
if ((ImGui.IsMouseDown(.Left) || ImGui.IsMouseDown(.Right)) && !ImGui.IsAnyItemHovered() && !ImGui.GetIO().KeyCtrl && ImGui.IsWindowHovered(.AllowWhenBlockedByPopup))
ClearEntitySelection();
_selectedEntities.Clear();
ImGui.End();
}
@@ -160,8 +102,6 @@ namespace GlitchyEditor.EditWindows
{
_scene.DestroyEntity(entity, true);
}
_selectedEntities.Clear();
}
private void ShowEntityHierarchyMenuBar()
@@ -317,7 +257,7 @@ namespace GlitchyEditor.EditWindows
if(tree.Children.Count == 0)
flags |= .Leaf;
bool inSelectedList = IsEntitySelected(tree.Value);
bool inSelectedList = _selectedEntities.Contains(tree.Value);
if(inSelectedList)
flags |= .Selected;
@@ -410,12 +350,17 @@ namespace GlitchyEditor.EditWindows
{
if (inSelectedList && !clickedRight)
{
DeselectEntity(tree.Value);
_selectedEntities.Remove(tree.Value);
inSelectedList = false;
}
else
{
SelectEntity(tree.Value, !ImGui.GetIO().KeyCtrl && !clickedRight);
if (!ImGui.GetIO().KeyCtrl && !clickedRight)
{
_selectedEntities.Clear();
}
_selectedEntities.Add(tree.Value);
inSelectedList = true;
}
}
@@ -1,123 +0,0 @@
using ImGui;
using System;
using GlitchyEngine.Collections;
using GlitchyEngine.Content;
using System.Reflection;
using GlitchyEngine;
using GlitchyEditor.Assets;
namespace GlitchyEditor.EditWindows;
class PropertiesWindow : EditorWindow
{
private AssetPropertiesEditor _currentPropertiesEditor ~ delete _;
private bool _lockCurrentAsset;
private bool _selectedNewAsset;
private append String _selectedFileName = .();
private Asset _currentAsset ~ _?.ReleaseRef();
public this(Editor editor)
{
_editor = editor;
}
protected override void InternalShow()
{
defer { ImGui.End(); }
if(!ImGui.Begin("Properties", &_open, .None))
return;
// TODO: make a little button in title bar?
ImGui.Checkbox("Lock", &_lockCurrentAsset);
ImGui.Separator();
ShowAssetProperties();
}
/// Gets the AssetFile for the asset currently selected in the ContentBrowserWindow
/// @returns the AssetFile for the currently selected asset of null, if no file is selected.
private AssetFile GetCurrentAssetFile()
{
// Only grab the currently selected file if we aren't locked
if (!_lockCurrentAsset)
{
StringView selectedInFileBrowser = _editor.ContentBrowserWindow.SelectedFile;
if (_selectedFileName != selectedInFileBrowser)
{
_selectedFileName.Set(_editor.ContentBrowserWindow.SelectedFile);
}
}
Result<TreeNode<AssetNode>> treeNode = _editor.ContentManager.AssetHierarchy.GetNodeFromPath(_selectedFileName);
if (treeNode case .Ok(let assetNode))
return assetNode->AssetFile;
return null;
}
private void ShowAssetProperties()
{
AssetFile assetFile = GetCurrentAssetFile();
if (_currentPropertiesEditor?.Asset != assetFile)
{
delete _currentPropertiesEditor;
_currentPropertiesEditor = _editor.ContentManager.GetNewPropertiesEditor(assetFile);
}
if (assetFile == null)
return;
// We need the actual asset for preview and sometimes for editing
if (_currentAsset?.Identifier != assetFile.Identifier)
{
_currentAsset?.ReleaseRef();
_currentAsset = _editor.ContentManager.LoadAsset(assetFile.Identifier);
}
// TODO: allow changing AssetLoader
// assetFile.AssetConfig.AssetLoade
// TODO: ignore file
/*ImGui.Checkbox("Ignore", &assetFile.AssetConfig.IgnoreFile);
if (ImGui.IsItemHovered())
ImGui.SetTooltip("If checked this file will be ignored and not treated as an asset.");*/
ShowPropertiesEditor(assetFile);
ImGui.Separator();
// TODO: preview asset
}
private void ShowPropertiesEditor(AssetFile assetFile)
{
if (_currentPropertiesEditor == null)
return;
_currentPropertiesEditor.ShowEditor();
if (ImGui.Button("Save Asset"))
{
_editor.ContentManager.SaveAsset(_currentAsset);
}
if (!assetFile.AssetConfig.Config.Changed)
{
ImGui.BeginDisabled();
defer:: { ImGui.EndDisabled(); }
}
ImGui.Separator();
if (ImGui.Button("Apply"))
assetFile.SaveAssetConfig();
}
}
@@ -5,39 +5,20 @@ using GlitchyEngine.Math;
using GlitchyEngine;
using GlitchyEngine.World;
using ImGuizmo;
using GlitchyEngine.Events;
namespace GlitchyEditor.EditWindows
{
class SceneViewportWindow : EditorWindow
{
//public OldCamera _camera;
public const String s_WindowTitle = "Scene";
private ImGui.Vec2 _oldViewportSize = .(100, 100);
private bool _viewPortChanged;
private RenderTarget2D _renderTarget ~ _?.ReleaseRef();
/// True if the cursor wrapped from one side of the viewport to the other last frame.
private bool _wrappedCursor;
public Event<EventHandler<Vector2>> ViewportSizeChangedEvent ~ _.Dispose();
private RenderTargetGroup _renderTarget ~ _?.ReleaseRef();
private ImGuizmo.OPERATION _gizmoType = .TRANSLATE;
private ImGuizmo.MODE _gizmoMode = .LOCAL;
private float _snap = 0.5f;
private float _angleSnap = 45.0f;
private bool _doSnap = false;
public uint32 SelectedEntityId {get; private set; }
public bool SelectionChanged { get; private set; }
public Vector2 ViewportSize => (Vector2)_oldViewportSize;
// Occurs when the viewport is resized.
public Event<EventHandler<Vector2>> ViewportSizeChanged ~ _.Dispose();
// Occurs when an entity was clicked.
public Event<EventHandler<uint32>> EntityClicked ~ _.Dispose();
/// The render target that is shown in the viewport window.
public RenderTargetGroup RenderTarget
public RenderTarget2D RenderTarget
{
get => _renderTarget;
set
@@ -49,241 +30,56 @@ namespace GlitchyEditor.EditWindows
}
}
/// Gets or sets whether the editor functionality (gizmo, picking etc.) is enabled.
public bool EditorMode { get; set; } = true
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 | .MenuBar))
if(!ImGui.Begin(s_WindowTitle, &_open, .NoScrollbar))
{
ImGui.End();
return;
}
let viewportSize = ImGui.GetContentRegionAvail();
if(ImGui.IsWindowHovered() && Input.IsMouseButtonPressing(.RightButton))
{
let currentWindow = ImGui.GetCurrentWindow();
var currentWindow = ImGui.GetCurrentWindow();
ImGui.FocusWindow(currentWindow);
}
_hasFocus = ImGui.IsWindowFocused();
if (EditorMode)
{
ShowMenuBar();
if (_editor.CurrentCamera.[Friend]BindMouse && _hasFocus)
WrapMouseInViewport();
// If we wrapped this frame we weren't hovering because the cursor has to be be out of bounds to wrap
_editor.CurrentCamera.AllowMove = _hasFocus && (ImGui.IsWindowHovered() || _wrappedCursor);
if (_hasFocus && !_editor.CurrentCamera.InUse)
{
if (Input.IsKeyPressing(.Q))
_gizmoType = .TRANSLATE;
if (Input.IsKeyPressing(.W))
_gizmoType = .ROTATE;
if (Input.IsKeyPressing(.E))
_gizmoType = .SCALE;
if (Input.IsKeyPressing(.G))
_gizmoMode = .WORLD;
if (Input.IsKeyPressing(.L))
_gizmoMode = .LOCAL;
}
}
var viewportSize = ImGui.GetContentRegionAvail();
if(_renderTarget != null)
{
ImGui.Image(_renderTarget.GetViewBinding(0), viewportSize);
//ImGui.Image(_editor.CurrentCamera.RenderTarget.GetViewBinding(0), viewportSize);
//ImGui.Image(_editor.CurrentScene.[Friend]_compositeTarget.GetViewBinding(0), viewportSize);
ImGui.Image(_renderTarget, viewportSize);
}
if (EditorMode)
{
HandleDropTarget();
bool gizmoUsed = DrawImGuizmo(viewportSize);
MousePicking(viewportSize, gizmoUsed);
}
DrawImGuizmo(viewportSize);
ImGui.End();
if(_oldViewportSize != viewportSize)
if(oldViewportSize != viewportSize)
{
ViewportSizeChanged.Invoke(this, (Vector2)viewportSize);
_viewPortChanged = true;
_oldViewportSize = viewportSize;
ViewportSizeChangedEvent.Invoke(this, (Vector2)viewportSize);
viewPortChanged = true;
oldViewportSize = viewportSize;
}
}
/// Provides the ImGui Drop target and handles dropped payload.
private void HandleDropTarget()
private void DrawImGuizmo(ImGui.Vec2 viewportSize)
{
if (ImGui.BeginDragDropTarget())
{
ImGui.Payload* payload = ImGui.AcceptDragDropPayload("CONTENT_BROWSER_ITEM");
if (payload != null)
{
StringView path = .((char8*)payload.Data, (int)payload.DataSize);
_editor.RequestOpenScene(this, path);
}
ImGui.EndDragDropTarget();
}
}
/// Wraps the mouse, so that it always stays in the viewport.
private void WrapMouseInViewport()
{
_wrappedCursor = false;
let mousePos = (Vector2)ImGui.GetMousePos();
let winPos = (Vector2)ImGui.GetWindowPos();
let regionMin = winPos + (Vector2)ImGui.GetWindowContentRegionMin();
let regionMax = winPos + (Vector2)ImGui.GetWindowContentRegionMax();
Vector2 newMousePos = mousePos;
if (mousePos.X < regionMin.X)
{
newMousePos.X = regionMax.X - 1;
}
else if (mousePos.X > regionMax.X - 1)
{
newMousePos.X = regionMin.X + 1;
}
if (mousePos.Y < regionMin.Y)
{
newMousePos.Y = regionMax.Y - 1;
}
else if (mousePos.Y > regionMax.Y - 1)
{
newMousePos.Y = regionMin.Y + 1;
}
if (newMousePos != mousePos)
{
Input.SetMousePosition((Int2)newMousePos);
// After wrapping the cursor the the other side, the camera controller must not compare the positions,
// because the delta doesn't represent the correct movement of the cursor.
// TODO: can be solved by using direct mouse movement instead of comparing positions
_editor.CurrentCamera.[Friend]MouseCooldown = 2;
_wrappedCursor = true;
}
}
/// If the user clicks, the entity beneath the cursor will be selected.
private void MousePicking(ImGui.Vec2 viewportSize, bool gizmoUsed)
{
Vector2 relativeMouse = (Vector2)ImGui.GetMousePos() - (Vector2)ImGui.GetItemRectMin();
int rtWidth = _editor.CurrentScene.[Friend]_compositeTarget.Width;
int rtHeight = _editor.CurrentScene.[Friend]_compositeTarget.Height;
if (Input.IsMouseButtonPressing(.LeftButton) &&
ImGui.IsWindowHovered() && !gizmoUsed && !_editor.CurrentCamera.InUse &&
relativeMouse.X >= 0 && relativeMouse.Y >= 0 &&
relativeMouse.X < viewportSize.x && relativeMouse.Y < viewportSize.y &&
relativeMouse.X < rtWidth && relativeMouse.Y < rtHeight)
{
uint32 id = uint32.MaxValue;
_editor.CurrentScene.[Friend]_compositeTarget.GetData<uint32>(&id, 1, (.)relativeMouse.X, (.)relativeMouse.Y, 1, 1);
SelectionChanged = true;
SelectedEntityId = id;
EntityClicked(this, id);
}
else
{
SelectionChanged = false;
}
}
private void ShowMenuBar()
{
if(ImGui.BeginMenuBar())
{
if (ImGui.RadioButton("Position", _gizmoType.HasFlag(.TRANSLATE)))
{
if (Input.IsKeyPressed(Key.Control))
_gizmoType ^= .TRANSLATE;
else
_gizmoType = .TRANSLATE;
}
if (ImGui.RadioButton("Rotation", _gizmoType.HasFlag(.ROTATE)))
{
if (Input.IsKeyPressed(Key.Control))
_gizmoType ^= .ROTATE;
else
_gizmoType = .ROTATE;
}
if (ImGui.RadioButton("Scale", _gizmoType.HasFlag(.SCALE)))
{
if (Input.IsKeyPressed(Key.Control))
_gizmoType ^= .SCALE;
else
_gizmoType = .SCALE;
}
if (ImGui.RadioButton("All", _gizmoType == .TRANSLATE | .ROTATE | .SCALE))
_gizmoType = .TRANSLATE | .ROTATE | .SCALE;
// If we scale, the mode must be local otherwise we could skew the matrix.
if (_gizmoType.HasFlag(.SCALE))
_gizmoMode = .LOCAL;
if (ImGui.MenuItem(_gizmoMode == .WORLD ? "Global" : "Local", null, true, !_gizmoType.HasFlag(.SCALE)))
{
if (_gizmoMode == .WORLD)
_gizmoMode = .LOCAL;
else
_gizmoMode = .WORLD;
}
_doSnap = Input.IsKeyPressed(.Shift);
ImGui.PushItemWidth(100);
if (_gizmoType.HasFlag(.ROTATE))
{
ImGui.DragFloat("Angle Snap", &_angleSnap, 1.0f, 0.0f, 180.0f);
}
if (_gizmoType.HasFlag(.TRANSLATE) || _gizmoType.HasFlag(.SCALE))
{
ImGui.DragFloat("Snap", &_snap, 0.1f, 0.0f, float.MaxValue);
}
ImGui.PopItemWidth();
ImGui.EndMenuBar();
}
}
private bool DrawImGuizmo(ImGui.Vec2 viewportSize)
{
// TODO: Needed if we have a orthographic editor-camera (or support gizmos in the Play-Window, where we can also have ortho projections)
ImGuizmo.SetOrthographic(false);
ImGuizmo.SetDrawlist();
var topLeft = ImGui.GetWindowPos();
@@ -293,38 +89,29 @@ namespace GlitchyEditor.EditWindows
topLeft.y += cntMin.y;
ImGuizmo.SetRect(topLeft.x, topLeft.y, viewportSize.x, viewportSize.y);
var view = _editor.CurrentCamera.View;
var projection = _editor.CurrentCamera.Projection;
var cameraTransformCmp = CameraEntity.GetComponent<TransformComponent>();
var view = cameraTransformCmp.WorldTransform.Invert();
if(_editor.EntityHierarchyWindow.SelectedEntities.Count == 0)
return false;
var cameraCmp = CameraEntity.GetComponent<CameraComponent>();
var projection = cameraCmp.Camera.Projection;
var entity = _editor.EntityHierarchyWindow.SelectedEntities.Back;
Matrix mat = .Identity;
ImGuizmo.DrawGrid((.)&view, (.)&projection, (.)&mat, 10);
var transformCmp = entity.GetComponent<TransformComponent>();
var worldTransform = transformCmp.WorldTransform;
Matrix parentView = .Identity;
if (transformCmp.Parent != .InvalidEntity)
if(_editor.SelectedEntities.Count > 0)
{
var parentTransformCmp = Entity(transformCmp.Parent, entity.Scene).GetComponent<TransformComponent>();
parentView = parentTransformCmp.WorldTransform.Invert();
}
var entity = _editor.SelectedEntities.Front;
Vector3 snap = .(_snap);
if (_gizmoType.HasFlag(.ROTATE))
snap = .(_angleSnap);
var transformCmp = _editor.World.GetComponent<TransformComponent>(entity);
if (ImGuizmo.Manipulate((.)&view, (.)&projection, _gizmoType, _gizmoMode, (.)&worldTransform, null, _doSnap ? (.)&snap : null))
{
// TODO: Fix when parent is scaled
// Seems to work fine for parent rotation and translation but scaled parent ruins everything
// (probably because scaling a rotated matrix results in a skewed matrix, but unity can do it and so should we)
transformCmp.LocalTransform = parentView * worldTransform;
}
var transform = transformCmp.LocalTransform;
return ImGuizmo.IsUsing();
ImGuizmo.SetRect(topLeft.x, topLeft.y, viewportSize.x, viewportSize.y);
ImGuizmo.Manipulate((.)&view, (.)&projection, .TRANSLATE, .LOCAL, (.)&transform);
transformCmp.LocalTransform = transform;
}
}
}
}
+100 -37
View File
@@ -4,70 +4,133 @@ using System;
using System.Collections;
using GlitchyEngine.Collections;
using GlitchyEditor.EditWindows;
using GlitchyEngine;
using GlitchyEditor.Assets;
using GlitchyEngineHelper;
using System.IO;
using GlitchyEngineHelper.DotNet;
namespace GlitchyEditor
{
class Editor
{
private EcsWorld _ecsWorld;
private Scene _scene;
private EditorContentManager _contentManager;
private EntityHierarchyWindow _entityHierarchyWindow ~ delete _;
private ComponentEditWindow _componentEditWindow ~ delete _;
private SceneViewportWindow _sceneViewportWindow~ delete _;
private ContentBrowserWindow _contentBrowserWindow ~ delete _;
private PropertiesWindow _propertiesWindow ~ delete _;
private SceneViewportWindow _sceneViewportWindow = new .(this) ~ delete _;
public Scene CurrentScene
{
get => _scene;
set
{
_scene = value;
_entityHierarchyWindow.SetContext(_scene);
}
}
private List<EcsEntity> _selectedEntities = new .() ~ delete _;
public EditorContentManager ContentManager => _contentManager;
public EcsWorld World => _ecsWorld;
public List<EcsEntity> SelectedEntities => _selectedEntities;
public EntityHierarchyWindow EntityHierarchyWindow => _entityHierarchyWindow;
public ComponentEditWindow ComponentEditWindow => _componentEditWindow;
public SceneViewportWindow SceneViewportWindow => _sceneViewportWindow;
public ContentBrowserWindow ContentBrowserWindow => _contentBrowserWindow;
public PropertiesWindow PropertiesWindow => _propertiesWindow;
public EditorCamera* CurrentCamera { get; set; }
public Event<EventHandler<StringView>> RequestOpenScene ~ _.Dispose();
/// Creates a new editor for the given world
public this(Scene scene, EditorContentManager contentManager)
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;
_contentManager = contentManager;
_ecsWorld = _scene.[Friend]_ecsWorld;
InitWindows();
}
private void InitWindows()
{
_sceneViewportWindow = new SceneViewportWindow(this);
_entityHierarchyWindow = new EntityHierarchyWindow(this, _scene);
_entityHierarchyWindow = new EntityHierarchyWindow(_scene);
_componentEditWindow = new ComponentEditWindow(_entityHierarchyWindow);
_contentBrowserWindow = new ContentBrowserWindow((.)Application.Get().ContentManager);
_propertiesWindow = new PropertiesWindow(this);
}
public void Update()
{
_sceneViewportWindow.Show();
_entityHierarchyWindow.Show();
_componentEditWindow.Show();
_contentBrowserWindow.Show();
_propertiesWindow.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();
}
}
}
+1 -29
View File
@@ -1,41 +1,13 @@
using System;
using GlitchyEngine;
using GlitchyEngine.Content;
using GlitchyEditor.Assets;
namespace GlitchyEditor
{
class EditorApp : Application
{
EditorContentManager _contentManager;
public this()
{
PushLayer(new EditorLayer(_contentManager));
}
protected override IContentManager InitContentManager()
{
_contentManager = new EditorContentManager();
_contentManager.RegisterAssetLoader<EditorTextureAssetLoader>();
_contentManager.SetAsDefaultAssetLoader<EditorTextureAssetLoader>(".png", ".dds");
_contentManager.SetAssetPropertiesEditor<EditorTextureAssetLoader>(=> TextureAssetPropertiesEditor.Factory);
_contentManager.RegisterAssetLoader<ModelAssetLoader>();
_contentManager.SetAsDefaultAssetLoader<ModelAssetLoader>(".glb", ".gltf");
_contentManager.SetAssetPropertiesEditor<ModelAssetLoader>(=> ModelAssetPropertiesEditor.Factory);
_contentManager.RegisterAssetLoader<MaterialAssetLoader>();
_contentManager.SetAsDefaultAssetLoader<MaterialAssetLoader>(".mat");
_contentManager.SetAssetPropertiesEditor<MaterialAssetLoader>(=> MaterialAssetPropertiesEditor.Factory);
_contentManager.RegisterAssetLoader<EffectAssetLoader>();
_contentManager.SetAsDefaultAssetLoader<EffectAssetLoader>(".hlsl");
_contentManager.SetAssetPropertiesEditor<EffectAssetLoader>(=> EffectAssetPropertiesEditor.Factory);
_contentManager.SetContentDirectory("./content");
return _contentManager;
PushLayer(new EditorLayer());
}
[Export, LinkName("CreateApplication")]
@@ -0,0 +1,63 @@
using GlitchyEngine;
using GlitchyEngine.Math;
using GlitchyEngine.World;
namespace GlitchyEditor
{
class EditorCameraController : ScriptableEntity
{
private float _cameraTranslationSpeed = 2.0f;
private float _cameraRotationSpeedX = 0.001f;
private float _cameraRotationSpeedY = 0.001f;
public bool IsEnabled = false;
protected override void OnUpdate(GameTime gt)
{
if (!IsEnabled)
return;
Debug.Profiler.ProfileFunction!();
Vector3 movement = .();
if(Input.IsKeyPressed(Key.W))
movement.Z += 1;
if(Input.IsKeyPressed(Key.S))
movement.Z -= 1;
if(Input.IsKeyPressed(Key.A))
movement.X -= 1;
if(Input.IsKeyPressed(Key.D))
movement.X += 1;
if(Input.IsKeyPressed(Key.Space))
movement.Y += 1;
if(Input.IsKeyPressed(Key.Control))
movement.Y -= 1;
var transformComponent = transform;
if(movement != .Zero)
{
movement.Normalize();
movement *= (float)(gt.FrameTime.TotalSeconds) * _cameraTranslationSpeed;
Matrix view = transformComponent.WorldTransform.Invert();
Vector4 delta = Vector4(movement, 1.0f) * view;
transformComponent.Position = transformComponent.Position + delta.XYZ;
}
// Camera rotation
var mouseDelta = Input.GetMouseMovement();
float rotY = mouseDelta.X * _cameraRotationSpeedX;
float rotX = mouseDelta.Y * _cameraRotationSpeedY;
transformComponent.RotationEuler = transformComponent.RotationEuler + .(rotX, rotY, 0);
}
}
}
-449
View File
@@ -1,449 +0,0 @@
using System;
using System.IO;
using GlitchyEngine.Collections;
using System.Collections;
using GlitchyEngine.Renderer;
using System.Threading;
using GlitchyEngine.Content;
using GlitchyEditor.Assets;
using GlitchyEngine;
using System.Linq;
namespace GlitchyEditor;
/*class PreviewImageManager
{
/// Thread that loads/generates preview images in the background
//private Thread _loaderThread;
/// Set to true to notify the loader to stop
//private bool _stopLoader;
private append Dictionary<String, Texture2D> _previewImages = .() ~ {
for (var v in _)
{
delete v.key;
v.value.ReleaseRef();
}
delete _;
};
public Texture2D GetPreviewImage(String assetName)
{
if (_previewImages.TryGetValue(assetName, let image))
{
return image..AddRef();
}
if (assetName.EndsWith(".png", .OrdinalIgnoreCase))
{
/*using (Texture2D texture = new Texture2D(assetName, true))
{
Texture2DDesc desc = .(128, 128, .R8G8B8A8_UNorm_SRGB)
{
Usage = .Immutable
};
Texture2D myActualTexture = new Texture2D(desc);
// TODO: Scale down texture (on GPU?)
}*/
Texture2D texture = new Texture2D(assetName, true);
if (texture.Width <= 128 && texture.Height <= 128)
{
}
if ( texture.MipLevels > 1)
{
}
_previewImages.Add(new String(assetName), texture);
return texture..AddRef();
}
else
{
Runtime.NotImplemented();
}
}
}*/
class EditorContentManager : IContentManager
{
private append String _contentDirectory = .();
public StringView ContentDirectory => _contentDirectory;
//private append List<String> _identifiers = .() ~ _.ClearAndDeleteItems();
private append Dictionary<StringView, Asset> _loadedAssets = .(); // Check if all resources are unloaded
private append AssetHierarchy _assetHierarchy = .(this);
public AssetHierarchy AssetHierarchy => _assetHierarchy;
public this()
{
_assetHierarchy.OnFileContentChanged.Add(new => OnFileContentChanged);
}
public ~this()
{
UnmanageAllAssets();
}
private void OnFileContentChanged(AssetNode assetNode)
{
// TODO: Subassets break reloading because we can't find them when we only receive the file that changed...
// Asset isn't loaded so we don't need to reload it.
if (assetNode.AssetFile.LoadedAsset == null)
return;
String neededAssetLoaderName = assetNode.AssetFile.AssetConfig?.AssetLoader;
if (String.IsNullOrWhiteSpace(neededAssetLoaderName))
return;
IAssetLoader assetLoader = null;
String loaderNameBuffer = scope String(64);
for (IAssetLoader loader in _assetLoaders)
{
loader.GetType().GetName(loaderNameBuffer..Clear());
if (loaderNameBuffer == neededAssetLoaderName)
{
assetLoader = loader;
break;
}
}
if (assetLoader == null)
{
Log.EngineLogger.Error($"Could not find asset loader \"{neededAssetLoaderName}\"");
return;
}
if (var assetReloader = assetLoader as IReloadingAssetLoader)
{
Stream stream = GetStream(assetNode.Path);
assetReloader.ReloadAsset(assetNode.AssetFile, stream);
delete stream;
}
}
public void SetContentDirectory(StringView contentDirectory)
{
_contentDirectory.Clear();
_contentDirectory.Append(contentDirectory);
Path.Fixup(_contentDirectory);
_assetHierarchy.SetContentDirectory(contentDirectory);
}
public void Update()
{
_assetHierarchy.Update();
}
public IAssetLoader GetDefaultAssetLoader(StringView fileExtension)
{
if (_defaultAssetLoaders.TryGetValue(fileExtension, let value))
return value;
return null;
}
private append List<String> _supportedExtensions = .() ~ ClearAndDeleteItems!(_);
private append List<IAssetLoader> _assetLoaders = .() ~ ClearAndDeleteItems!(_);
private append Dictionary<StringView, IAssetLoader> _defaultAssetLoaders = .();
private append Dictionary<String, function AssetPropertiesEditor(AssetFile)> _assetPropertiesEditors = .() ~ {
for (String key in _.Keys)
{
delete key;
}
};
public void RegisterAssetLoader<T>() where T : new, class, IAssetLoader
{
//Log.EngineLogger.AssertDebug(!_assetLoaders.Any((l) => l.GetType() == typeof(T)), "Asset loader already registered.");
_assetLoaders.Add(new T());
for (StringView ext in T.FileExtensions)
_supportedExtensions.Add(new String(ext));
}
public void SetAsDefaultAssetLoader<T>(params Span<StringView> fileExtensions) where T : IAssetLoader
{
for (var ext in fileExtensions)
{
// Find file extension in registered file extensions
String foundExtension = null;
for (var supportedExt in _supportedExtensions)
{
if (supportedExt == ext)
{
foundExtension = supportedExt;
break;
}
}
Log.EngineLogger.Assert(foundExtension != null, "File Extension is not registered.");
for (var loader in _assetLoaders)
{
if (loader.GetType() == typeof(T))
{
_defaultAssetLoaders[foundExtension] = loader;
break;
}
}
}
}
public void SetAssetPropertiesEditor(Type assetLoaderType, function AssetPropertiesEditor(AssetFile) editorFactory)
{
String loaderTypeName = new String();
assetLoaderType.GetName(loaderTypeName);
_assetPropertiesEditors[loaderTypeName] = editorFactory;
}
public void SetAssetPropertiesEditor<TAssetLoader>(function AssetPropertiesEditor(AssetFile) editorFactory) where TAssetLoader : IAssetLoader
{
SetAssetPropertiesEditor(typeof(TAssetLoader), editorFactory);
}
public AssetPropertiesEditor GetNewPropertiesEditor(AssetFile assetFile)
{
if (assetFile?.AssetConfig.AssetLoader == null)
return null;
if (_assetPropertiesEditors.TryGetValue(assetFile.AssetConfig.AssetLoader, let propertiesEditorfactory))
return propertiesEditorfactory(assetFile);
return null;
}
public bool IsLoaded(StringView identifier)
{
return _loadedAssets.ContainsKey(identifier);
}
public Asset LoadAsset(StringView identifier)
{
if (_loadedAssets.TryGetValue(identifier, let asset))
{
return asset..AddRef();
}
// Find subasset name
int poundIndex = identifier.IndexOf('#');
StringView resourceName = poundIndex == -1 ? identifier : identifier.Substring(0, poundIndex);
StringView? subassetName = identifier.Substring(poundIndex + 1);
String filePath = scope String(resourceName.Length + _contentDirectory.Length + 2);
Path.Combine(filePath, _contentDirectory, resourceName);
Path.Fixup(filePath);
//filePath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
Result<TreeNode<AssetNode>> resultNode = AssetHierarchy.GetNodeFromPath(filePath);
if (resultNode case .Err)
{
Log.EngineLogger.Error($"Could not find asset \"{filePath}\".");
return null;
}
AssetFile file = resultNode->Value.AssetFile;
IAssetLoader assetLoader = null;
String loaderTypeName = scope .(128);
for (IAssetLoader loader in _assetLoaders)
{
loader.GetType().GetName(loaderTypeName..Clear());
if (loaderTypeName == file.AssetConfig.AssetLoader)
{
assetLoader = loader;
break;
}
}
Log.EngineLogger.AssertDebug(assetLoader != null);
Stream stream = GetStream(filePath);
Asset loadedAsset = assetLoader.LoadAsset(stream, file.AssetConfig.Config, resourceName, subassetName, this);
delete stream;
if (loadedAsset == null)
return null;
//String identifierString = new .(identifier);
//_identifiers.Add(identifierString);
//_loadedAssets[identifierString] = loadedAsset;
loadedAsset.Identifier = identifier;
ManageAsset(loadedAsset);
file.[Friend]_loadedAsset = loadedAsset;
return loadedAsset;
}
/// Saves the asset.
public Result<void> SaveAsset(Asset asset)
{
// Find subasset name
int poundIndex = asset.Identifier.IndexOf('#');
StringView resourceName = poundIndex == -1 ? asset.Identifier : asset.Identifier.Substring(0, poundIndex);
StringView? subassetName = asset.Identifier.Substring(poundIndex + 1);
String filePath = scope String(resourceName.Length + _contentDirectory.Length + 2);
Path.Combine(filePath, _contentDirectory, resourceName);
Path.Fixup(filePath);
//filePath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
TreeNode<AssetNode> assetNode = Try!(AssetHierarchy.GetNodeFromPath(filePath));
AssetFile file = assetNode->AssetFile;
IAssetLoader assetLoader = null;
String loaderTypeName = scope .(128);
for (IAssetLoader loader in _assetLoaders)
{
loader.GetType().GetName(loaderTypeName..Clear());
if (loaderTypeName == file.AssetConfig.AssetLoader)
{
assetLoader = loader;
break;
}
}
IAssetSaver assetSaver = assetLoader as IAssetSaver;
if (assetSaver == null)
{
Log.EngineLogger.Error("The asset loader can't save!");
return .Err;
}
Stream stream = OpenStream(filePath, false, true);
assetSaver.EditorSaveAsset(stream, asset, file.AssetConfig.Config, resourceName, subassetName, this);
delete stream;
return .Ok;
}
private Stream OpenStream(StringView assetIdentifier, bool openOnly, bool truncate = false)
{
var assetIdentifier;
if (!assetIdentifier.StartsWith(_contentDirectory))
{
String filePath = scope:: String(assetIdentifier.Length + _contentDirectory.Length + 2);
Path.Combine(filePath, _contentDirectory, assetIdentifier);
assetIdentifier = filePath;
}
FileStream fs = new FileStream();
FileMode fileMode = openOnly ? FileMode.Open : FileMode.OpenOrCreate;
if (truncate)
fileMode |= .Truncate;
var result = fs.Open(assetIdentifier, fileMode, openOnly ? .Read : .ReadWrite, .ReadWrite);
if (result case .Err)
return null;
return fs;
}
// TODO: probably not needed
public Stream GetStream(StringView assetIdentifier)
{
return OpenStream(assetIdentifier, true);
/*var assetIdentifier;
if (!assetIdentifier.StartsWith(_contentDirectory))
{
String filePath = scope:: String(assetIdentifier.Length + _contentDirectory.Length + 2);
Path.Combine(filePath, _contentDirectory, assetIdentifier);
assetIdentifier = filePath;
}
FileStream fs = new FileStream();
var result = fs.Open(assetIdentifier, .Open, .Read, .ReadWrite);
if (result case .Err)
return null;
return fs;*/
}
public void ManageAsset(Asset asset)
{
_loadedAssets.Add(asset.Identifier, asset);
asset.[Friend]_contentManager = this;
}
public void UnmanageAsset(Asset asset)
{
_loadedAssets.Remove(asset.Identifier);
asset.[Friend]_contentManager = null;
}
/// This will unregister all assets from this content manager.
/// Note: This will not release any assets.
private void UnmanageAllAssets()
{
for (let (_, asset) in _loadedAssets)
{
UnmanageAsset(asset);
}
}
public void UpdateAssetIdentifier(Asset asset, StringView oldIdentifier, StringView newIdentifier)
{
if (oldIdentifier == newIdentifier)
return;
Log.EngineLogger.Assert(_loadedAssets.ContainsKey(newIdentifier), "An asset with the same identifier is already managed by this content manager.");
// Since all we do in order to track assets is add them to a dictionary we can simply unmanage and manage it again.
UnmanageAsset(asset);
ManageAsset(asset);
}
}
-56
View File
@@ -1,56 +0,0 @@
using System;
using GlitchyEngine.Renderer;
using GlitchyEngine.Math;
using GlitchyEngine;
namespace GlitchyEditor
{
class EditorIcons : RefCounted
{
Texture2D _texture ~ _.ReleaseRef();
public SubTexture2D DirectionalLight ~ _.ReleaseRef();
public SubTexture2D Camera ~ _.ReleaseRef();
public SubTexture2D Folder ~ _.ReleaseRef();
public SubTexture2D File ~ _.ReleaseRef();
public SubTexture2D Play ~ _.ReleaseRef();
public SubTexture2D Stop ~ _.ReleaseRef();
public SamplerState SamplerState
{
get => _texture.SamplerState;
set => _texture.SamplerState = value;
}
public this(String texturePath, Vector2 iconSize)
{
_texture = Content.LoadAsset<Texture2D>(texturePath);//new Texture2D(texturePath);
Vector2 pen = .();
DirectionalLight = GetNextGridTexture(ref pen, iconSize);
Camera = GetNextGridTexture(ref pen, iconSize);
Folder = GetNextGridTexture(ref pen, iconSize);
File = GetNextGridTexture(ref pen, iconSize);
Play = GetNextGridTexture(ref pen, iconSize);
Stop = GetNextGridTexture(ref pen, iconSize);
}
private SubTexture2D GetNextGridTexture(ref Vector2 pen, Vector2 iconSize)
{
SubTexture2D subTexture = .CreateFromGrid(_texture, pen, iconSize);
pen.X += 1.0f;
if (pen.X >= (_texture.Width / iconSize.X))
{
pen.X = 0;
pen.Y += 1.0f;
}
Log.EngineLogger.AssertDebug(pen.Y <=(_texture.Height / iconSize.Y));
return subTexture;
}
}
}
+100 -522
View File
@@ -7,12 +7,6 @@ using GlitchyEngine.ImGui;
using GlitchyEngine.Math;
using GlitchyEngine.Renderer;
using GlitchyEngine.World;
using GlitchyEngine.Content;
using System.Collections;
using GlitchyEngine.Renderer.Animation;
using System.IO;
using GlitchyEngine.Core;
using GlitchyEditor.Assets;
namespace GlitchyEditor
{
@@ -27,91 +21,90 @@ namespace GlitchyEditor
BlendState _opaqueBlendState ~ _.ReleaseRef();
DepthStencilState _depthStencilState ~ _.ReleaseRef();
Scene _scene ~ delete _;
String _sceneFilePath = new String() ~ delete _;
public String SceneFilePath
{
get => _sceneFilePath;
set
{
_sceneFilePath.Clear();
if (value != null)
_sceneFilePath.Append(value);
}
}
Scene _scene = new Scene() ~ delete _;
Editor _editor ~ delete _;
RenderTargetGroup _cameraTarget ~ _.ReleaseRef();
RenderTargetGroup _viewportTarget ~ _.ReleaseRef();
RenderTarget2D _viewportTarget ~ _?.ReleaseRef();
SettingsWindow _settingsWindow = new .() ~ delete _;
EditorCamera _camera ~ _.Dispose();
Entity _cameraEntity;
Entity _otherCameraEntity;
/*Texture2D _editorIcons ~ _.ReleaseRef();
SubTexture2D _iconDirectionalLight ~ _.ReleaseRef();
SubTexture2D _iconCamera ~ _.ReleaseRef();*/
EditorIcons _editorIcons ~ _.ReleaseRef();
EditorContentManager _contentManager;
enum SceneState
class CameraController : ScriptableEntity
{
Edit,
Play,
// Pause,
// Simulate
protected override void OnCreate()
{
Log.EngineLogger.Trace("Cam controller created!");
}
SceneState _sceneState = .Edit;
protected override void OnUpdate(GameTime gameTime)
{
var transformCmp = GetComponent<TransformComponent>();
public this(EditorContentManager contentManager) : base("Example")
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;
//InitContentManager();
_contentManager = contentManager;
InitGraphics();
_scene = new Scene();
{
_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);
_camera = EditorCamera(Vector3(3.5f, 1.25f, 2.75f), Quaternion.FromEulerAngles(MathHelper.ToRadians(40), MathHelper.ToRadians(25), 0), MathHelper.ToRadians(75), 0.1f, 1);
_camera.RenderTarget = _cameraTarget;
InitEditor();
NewScene();
_cameraEntity.AddComponent<NativeScriptComponent>().Bind<EditorCameraController>();
_cameraEntity.AddComponent<EditorComponent>();
}
/*private void InitContentManager()
{
_contentManager = new EditorContentManager();
_contentManager.RegisterAssetLoader<EditorTextureAssetLoader>();
_contentManager.SetAsDefaultAssetLoader<EditorTextureAssetLoader>(".png", ".dds");
_contentManager.SetAssetPropertiesEditor<EditorTextureAssetLoader>(=> TextureAssetPropertiesEditor.Factory);
_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);
_contentManager.RegisterAssetLoader<ModelAssetLoader>();
_contentManager.SetAsDefaultAssetLoader<ModelAssetLoader>(".glb", ".gltf");
_contentManager.SetAssetPropertiesEditor<ModelAssetLoader>(=> ModelAssetPropertiesEditor.Factory);
_otherCameraEntity.AddComponent<NativeScriptComponent>().Bind<EditorCameraController>();
_otherCameraEntity.AddComponent<EditorComponent>();
}
_contentManager.RegisterAssetLoader<MaterialAssetLoader>();
_contentManager.SetAsDefaultAssetLoader<MaterialAssetLoader>(".mat");
_contentManager.SetAssetPropertiesEditor<MaterialAssetLoader>(=> MaterialAssetPropertiesEditor.Factory);
_contentManager.RegisterAssetLoader<EffectAssetLoader>();
_contentManager.SetAsDefaultAssetLoader<EffectAssetLoader>(".hlsl");
_contentManager.SetAssetPropertiesEditor<EffectAssetLoader>(=> EffectAssetPropertiesEditor.Factory);
_contentManager.SetContentDirectory("./content");
// Todo: Sketchy...
Application.Get().[Friend]_contentManager = _contentManager;
}*/
InitEditor();
}
private void InitGraphics()
{
@@ -131,156 +124,80 @@ namespace GlitchyEditor
DepthStencilStateDescription dsDesc = .();
_depthStencilState = new DepthStencilState(dsDesc);
_cameraTarget = new RenderTargetGroup(.(){
Width = 100,
Height = 100,
ColorTargetDescriptions = TargetDescription[](
.(.R16G16B16A16_Float),
.(.R32_UInt)
),
DepthTargetDescription = .(.D24_UNorm_S8_UInt)
});
_viewportTarget = new RenderTargetGroup(.()
{
Width = 100,
Height = 100,
ColorTargetDescriptions = TargetDescription[](
.(.R8G8B8A8_UNorm))
});
_editorIcons = new EditorIcons("Textures/EditorIcons.dds", .(64, 64));
_editorIcons.SamplerState = SamplerStateManager.AnisotropicClamp;
ContentBrowserWindow.s_FolderTexture = _editorIcons.Folder;
ContentBrowserWindow.s_FileTexture = _editorIcons.File;
/*_editorIcons = new Texture2D("Textures/EditorIcons.dds");
_editorIcons.SamplerState = SamplerStateManager.AnisotropicClamp;
_iconDirectionalLight = .CreateFromGrid(_editorIcons, .(0, 0), .(64, 64));
_iconCamera = .CreateFromGrid(_editorIcons, .(1, 0), .(64, 64));*/
_viewportTarget = new RenderTarget2D(RenderTarget2DDescription(.R8G8B8A8_UNorm, 100, 100) {DepthStencilFormat = .D32_Float});
_viewportTarget.SamplerState = SamplerStateManager.LinearClamp;
}
private void InitEditor()
{
_editor = new Editor(_scene, _contentManager);
_editor.SceneViewportWindow.ViewportSizeChanged.Add(new (s, e) => ViewportSizeChanged(s, e));
_editor.CurrentCamera = &_camera;
_editor = new Editor(_scene);
_editor.SceneViewportWindow.ViewportSizeChangedEvent.Add(new (s, e) => ViewportSizeChanged(s, e));
_editor.RequestOpenScene.Add(new (s, fileName) => {
LoadSceneFile(fileName);
});
//_editor.[Friend]CreateEntityWithTransform();
_editor.SceneViewportWindow.CameraEntity = _cameraEntity;
}
public override void Update(GameTime gameTime)
{
_camera.Update(gameTime);
var scriptComponent = _cameraEntity.GetComponent<NativeScriptComponent>();
// Clear the swapchain-buffer
RenderCommand.Clear(null, .Color | .Depth, .(0.2f, 0.2f, 0.2f), 1.0f, 0);
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);
if (_sceneState == .Edit)
_scene.UpdateEditor(gameTime, _camera, _viewportTarget, scope => DebugDraw3D, scope => DebugDraw2D);
else if (_sceneState == .Play)
_scene.UpdateRuntime(gameTime, _viewportTarget);
//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.UnbindRenderTargets();
RenderCommand.SetRenderTarget(null, 0, true);
RenderCommand.BindRenderTargets();
RenderCommand.SetViewport(_context.SwapChain.BackbufferViewport);
}
private void DebugDraw3D()
{
/*for (var (entity, transform, camera) in _scene.[Friend]_ecsWorld.Enumerate<TransformComponent, CameraComponent>())
{
if (_editor.EntityHierarchyWindow.SelectedEntities.Contains(.(entity, _scene)))
{
DebugRenderer.DrawViewFrustum(transform.WorldTransform, camera.Camera.Projection);
}
}*/
}
private void DebugDraw2D()
{
RenderCommand.SetBlendState(_alphaBlendState);
Matrix billboard = _camera.View.Invert();
billboard.Translation = .Zero;
Matrix Billboard(Matrix transform)
{
Vector3 worldPos = transform.Translation;
return Matrix.Translation(worldPos) * billboard;
}
float CalculateAlpha(Vector3 pos)
{
return Math.Clamp(1.5f - Vector3.Distance(_editor.CurrentCamera.Position, pos) / 50, 0, 1);
}
for (var (entity, transform, camera) in _scene.[Friend]_ecsWorld.Enumerate<TransformComponent, CameraComponent>())
{
if (_editor.EntityHierarchyWindow.SelectedEntities.Contains(.(entity, _scene)))
{
DebugRenderer.DrawViewFrustum(transform.WorldTransform, camera.Camera.Projection, _camera.Projection * _camera.View, .White);
}
Matrix world = Billboard(transform.WorldTransform);
float alpha = CalculateAlpha(transform.WorldTransform.Translation);
Renderer2D.DrawQuad(world, _editorIcons.Camera, ColorRGBA(alpha, alpha, alpha, alpha), .(0, 0, 1, 1), entity.Index);
//Renderer2D.DrawQuad(world, _iconCamera, .White, .(0, 0, 1, 1), entity.Index);
}
for (var (entity, transform, light) in _scene.[Friend]_ecsWorld.Enumerate<TransformComponent, LightComponent>())
{
if (_editor.EntityHierarchyWindow.SelectedEntities.Contains(.(entity, _scene)))
{
Renderer.DrawRay(.Zero, .(0, 0, 20), ColorRGBA(light.SceneLight.Color, 1.0f), transform.WorldTransform);
for (float angle = 0; angle < MathHelper.TwoPi; angle += MathHelper.TwoPi / 5.0f)
{
Vector2 pos = MathHelper.CirclePoint(angle, 0.5f);
Renderer.DrawRay(.(pos, 0), .(pos, 20), .White, transform.WorldTransform);
}
}
Matrix world = Billboard(transform.WorldTransform);
float alpha = CalculateAlpha(transform.WorldTransform.Translation);
Renderer2D.DrawQuad(world, _editorIcons.DirectionalLight, ColorRGBA(light.SceneLight.Color.R * alpha, light.SceneLight.Color.G * alpha, light.SceneLight.Color.B * alpha, alpha), .(0, 0, 1, 1), entity.Index);
//Renderer2D.DrawQuad(world, _iconDirectionalLight, ColorRGBA(light.SceneLight.Color, alpha), .(0, 0, 1, 1), entity.Index);
}
}
public override void OnEvent(Event event)
{
EventDispatcher dispatcher = EventDispatcher(event);
dispatcher.Dispatch<ImGuiRenderEvent>(scope (e) => OnImGuiRender(e));
dispatcher.Dispatch<WindowResizeEvent>(scope (e) => OnWindowResize(e));
dispatcher.Dispatch<KeyPressedEvent>(scope (e) => OnKeyPressed(e));
dispatcher.Dispatch<MouseScrolledEvent>(scope (e) => OnMouseScrolled(e));
}
ImGui.ID _mainDockspaceId;
TextureViewer viewer = new TextureViewer() ~ delete _;
private bool OnImGuiRender(ImGuiRenderEvent event)
{
Input.ImGuiDebugDraw();
ImGui.Begin("Test");
//viewer.ViewTexture(Renderer.[Friend]_gBuffer.Target);
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);
@@ -293,318 +210,18 @@ namespace GlitchyEditor
_settingsWindow.Show();
UI_Toolbar();
return false;
}
private void UI_Toolbar()
{
ImGui.PushStyleVar(.WindowPadding, ImGui.Vec2(0, 2));
ImGui.PushStyleVar(.ItemInnerSpacing, ImGui.Vec2(0, 0));
ImGui.PushStyleColor(.Button, ImGui.Vec4(0, 0, 0, 0));
let colors = ImGui.GetStyle().Colors;
ImGui.Vec4 hoveredColor = colors[(int)ImGui.Col.ButtonHovered];
hoveredColor.w = 0.5f;
ImGui.Vec4 activeColor = colors[(int)ImGui.Col.ButtonActive];
activeColor.w = 0.5f;
ImGui.PushStyleColor(.ButtonHovered, hoveredColor);
ImGui.PushStyleColor(.ButtonActive, activeColor);
ImGui.Begin("##toolbar", null, .NoDecoration | .NoScrollbar | .NoScrollWithMouse);
SubTexture2D icon = _sceneState == .Edit ? _editorIcons.Play : _editorIcons.Stop;
float size = ImGui.GetWindowHeight() - 4.0f;
ImGui.SameLine((ImGui.GetContentRegionMax().x / 2 - size / 2));
if (ImGui.ImageButton(icon, .(size, size), .Zero, .Ones, 0))
{
if (_sceneState == .Edit)
{
OnScenePlay();
}
else if (_sceneState == .Play)
{
OnSceneStop();
}
}
ImGui.End();
ImGui.PopStyleColor(3);
ImGui.PopStyleVar(2);
}
private void OnScenePlay()
{
_sceneState = .Play;
_editor.SceneViewportWindow.EditorMode = false;
_scene.OnRuntimeStart();
}
private void OnSceneStop()
{
_scene.OnRuntimeStop();
_editor.SceneViewportWindow.EditorMode = true;
_sceneState = .Edit;
}
// Just for testing
private void TestEntitiesWithModels()
{
/*{
var lightNtt = _scene.CreateEntity("My Sexy Sun 2");
let transform = lightNtt.GetComponent<TransformComponent>();
transform.Position = .(0, 0, 0);
transform.RotationEuler = .(MathHelper.ToRadians(70), MathHelper.ToRadians(-30), 0);
let light = lightNtt.AddComponent<LightComponent>();
light.SceneLight.Illuminance = 10.0f;
light.SceneLight.Color = .(1.0f, 0.95f, 0.8f);
}
{
var lightNtt = _scene.CreateEntity("My Sexy Sun 3");
let transform = lightNtt.GetComponent<TransformComponent>();
transform.Position = .(0, 0, 0);
transform.RotationEuler = .(MathHelper.ToRadians(20), MathHelper.ToRadians(-55), 0);
let light = lightNtt.AddComponent<LightComponent>();
light.SceneLight.Illuminance = 10.0f;
light.SceneLight.Color = .(1.0f, 0.95f, 0.8f);
}
{
var cameraNtt = _scene.CreateEntity("My Camera");
let transform = cameraNtt.GetComponent<TransformComponent>();
transform.Position = .(5, 5, -5);
transform.RotationEuler = .(MathHelper.ToRadians(45), MathHelper.ToRadians(-45), 0);
let camera = cameraNtt.AddComponent<CameraComponent>();
camera.Primary = true;
camera.Camera.SetPerspective(MathHelper.ToRadians(45), 0.1f, 10.0f);
camera.RenderTarget = _cameraTarget;
}
var fxLib = Application.Get().EffectLibrary;
using (Effect myEffect = fxLib.Load("content/Shaders/myEffect.hlsl"))
/*using (Texture2D albedo = new Texture2D("Textures/White.png", true))
using (Texture2D normal = new Texture2D("Textures/White.png"))
using (Texture2D rough = new Texture2D("Textures/White.png"))
using (Texture2D metal = new Texture2D("Textures/White.png"))*/
using (Texture2D albedo = new Texture2D("Textures/TestMat/rustediron2_albedo.png", true))
using (Texture2D normal = new Texture2D("Textures/TestMat/rustediron2_normal.png"))
using (Texture2D rough = new Texture2D("Textures/TestMat/rustediron2_roughness.png"))
using (Texture2D metal = new Texture2D("Textures/TestMat/rustediron2_metallic.png"))
{
albedo.SamplerState = SamplerStateManager.AnisotropicWrap;
normal.SamplerState = SamplerStateManager.AnisotropicWrap;
rough.SamplerState = SamplerStateManager.AnisotropicWrap;
metal.SamplerState = SamplerStateManager.AnisotropicWrap;
List<AnimationClip> clips = scope .();
using (Material mat = new .(myEffect))
{
mat.SetTexture("AlbedoTexture", albedo);
mat.SetTexture("NormalTexture", normal);
mat.SetTexture("MetallicTexture", metal);
mat.SetTexture("RoughnessTexture", rough);
mat.SetVariable("AlbedoColor", ColorRGBA.White);
mat.SetVariable("NormalScaling", Vector2.One);
mat.SetVariable("MetallicFactor", 1.0f);
mat.SetVariable("RoughnessFactor", 1.0f);
// TODO: completely wrong!
EcsEntity e = ModelLoader.LoadModel("content/Models/sphere.glb", mat, _scene.[Friend]_ecsWorld, clips, "Sphere 1");
Entity entity = .(e, _scene);
var transform = entity.GetComponent<TransformComponent>();
transform.Position = .(5, 0, 5);
}
/*using (Material mat = new .(myEffect))
{
mat.SetTexture("AlbedoTexture", albedo);
mat.SetTexture("NormalTexture", normal);
mat.SetTexture("MetallicTexture", metal);
mat.SetTexture("RoughnessTexture", rough);
//mat.SetVariable("BaseColor", Vector4(1, 1, 0, 1));
//mat.SetVariable("LightDir", Vector3(0, 1, 0).Normalized());
ModelLoader.LoadModel("content/Models/sphere.glb", myEffect, mat, _scene.[Friend]_ecsWorld, clips);
}*/
ClearAndReleaseItems!(clips);
}
using (Effect myEffect = fxLib.Get("myEffect"))
using (Texture2D white = new Texture2D("Textures/White.png"))
using (Texture2D normal = new Texture2D("Textures/DefaultNormal.png"))
{
white.SamplerState = SamplerStateManager.PointClamp;
normal.SamplerState = SamplerStateManager.PointClamp;
List<AnimationClip> clips = scope .();
for (int x < 10)
for (int y < 10)
{
using (Material mat = new .(myEffect))
{
mat.SetTexture("AlbedoTexture", white);
mat.SetTexture("NormalTexture", normal);
mat.SetTexture("MetallicTexture", white);
mat.SetTexture("RoughnessTexture", white);
mat.SetVariable("AlbedoColor", Vector4(1, 0, 0, 1));
mat.SetVariable("NormalScaling", Vector2(1.0f));
mat.SetVariable("RoughnessFactor", (x + 1) / 10.0f);
mat.SetVariable("MetallicFactor", y / 9.0f);
EcsEntity e = ModelLoader.LoadModel("content/Models/sphere.glb", mat, _scene.[Friend]_ecsWorld, clips, scope $"Sphere {x} {y}");
Entity entity = .(e, _scene);
var transform = entity.GetComponent<TransformComponent>();
transform.Position = .(x * 1.5f, y * 1.5f, 0);
}
}
ClearAndReleaseItems!(clips);
}*/
}
/// Creates a new scene.
private void NewScene()
{
SceneFilePath = null;
delete _scene;
_scene = new Scene();
_editor.CurrentScene = _scene;
var vpSize = _editor.SceneViewportWindow.ViewportSize;
_scene.OnViewportResize((.)vpSize.X, (.)vpSize.Y);
_camera.Position = .(-1.5f, 1.5f, -2.5f);
_camera.RotationEuler = .(MathHelper.ToRadians(25), MathHelper.ToRadians(35), 0);
// Create default camera
/*{
let camEntity = _scene.CreateEntity("Camera");
let transform = camEntity.Transform;
transform.Position =
}*/
/*// Create the default light source
{
let lightNtt = _scene.CreateEntity("Light");
let transform = lightNtt.Transform;
transform.Position = .(0, 0, 0);
transform.RotationEuler = .(MathHelper.ToRadians(45), MathHelper.ToRadians(-100), 0);
let light = lightNtt.AddComponent<LightComponent>();
light.SceneLight.Illuminance = 10.0f;
light.SceneLight.Color = .(1.0f, 0.95f, 0.8f);
}
TestEntitiesWithModels();*/
}
/// Saves the scene in the file that is was loaded from or saved to last. If there is no such path (i.e. it is a new scene) the save file dialog will open.
private void SaveScene()
{
if (String.IsNullOrWhiteSpace(SceneFilePath))
{
SaveSceneAs();
return;
}
SceneSerializer serializer = scope .(_scene);
serializer.Serialize(SceneFilePath);
}
/// Opens a save file dialog and saves the scene at the user specified location.
private void SaveSceneAs()
{
SaveFileDialog sfd = scope .();
if (sfd.ShowDialog() case .Ok(let val))
{
if (val == .OK)
{
SceneFilePath = sfd.FileNames[0];
SaveScene();
}
}
}
/// Opens a open file dialog and load the scene selected by the user specified.
private void OpenScene()
{
OpenFileDialog ofd = scope .();
if (ofd.ShowDialog() case .Ok(let val))
{
if (val == .OK)
{
LoadSceneFile(ofd.FileNames[0]);
}
}
}
/// Loads the given scene file.
private void LoadSceneFile(StringView filename)
{
SceneFilePath = scope String(filename);
delete _scene;
_scene = new Scene();
_editor.CurrentScene = _scene;
var vpSize = _editor.SceneViewportWindow.ViewportSize;
_scene.OnViewportResize((.)vpSize.X, (.)vpSize.Y);
SceneSerializer serializer = scope .(_scene);
serializer.Deserialize(SceneFilePath);
}
private void DrawMainMenuBar()
{
ImGui.BeginMainMenuBar();
if(ImGui.BeginMenu("File", true))
{
if (ImGui.MenuItem("New", "Ctrl+N"))
NewScene();
if (ImGui.MenuItem("Save", "Ctrl+S"))
SaveScene();
if (ImGui.MenuItem("Save as...", "Ctrl+Shift+N"))
SaveSceneAs();
if (ImGui.MenuItem("Open...", "Ctrl+O"))
OpenScene();
ImGui.Separator();
if (ImGui.MenuItem("Settings"))
_settingsWindow.Open = true;
ImGui.Separator();
if (ImGui.MenuItem("Exit"))
Application.Get().Close();
ImGui.EndMenu();
}
@@ -646,47 +263,8 @@ namespace GlitchyEditor
return;
_viewportTarget.Resize(sizeX, sizeY);
_cameraTarget.Resize(sizeX, sizeY);
_scene.OnViewportResize(sizeX, sizeY);
_camera.OnViewportResize(sizeX, sizeY);
}
private bool OnKeyPressed(KeyPressedEvent e)
{
bool control = Input.IsKeyPressed(Key.Control);
bool shift = Input.IsKeyPressed(Key.Shift);
if (!_camera.[Friend]BindMouse && control)
{
switch (e.KeyCode)
{
case .N:
NewScene();
return true;
case .O:
OpenScene();
return true;
case .S:
if (shift)
SaveSceneAs();
else
SaveScene();
return true;
default:
}
}
return false;
}
private bool OnMouseScrolled(MouseScrolledEvent e)
{
if (_camera.OnMouseScrolled(e))
return true;
return false;
}
}
}
-246
View File
@@ -1,246 +0,0 @@
using GlitchyEngine.Renderer;
using GlitchyEngine;
using ImGui;
using GlitchyEngine.Math;
using System;
namespace GlitchyEditor
{
class TextureViewer
{
enum BackgroundMode : int32
{
White,
Black,
Checkerboard
}
enum SampleMode : int32
{
Point,
Linear
}
GraphicsContext _context ~ _.ReleaseRef();
Effect _effect ~ _.ReleaseRef();
float _zoom = 1.0f;
BackgroundMode _backgroundMode = .Checkerboard;
SampleMode _sampleMode = .Linear;
RenderTarget2D _target ~ _?.ReleaseRef();
// TODO: we don't need depth!
DepthStencilTarget _depth ~ _?.ReleaseRef();
SamplerState _samplerPoint ~ _.ReleaseRef();
SamplerState _samplerLinear ~ _.ReleaseRef();
public this()
{
_context = Application.Get().Window.Context..AddRef();
InitEffect();
InitState();
// TODO: rasterizerstate and depthstencilstate
}
private void InitEffect()
{
_effect = new Effect("content\\Shaders\\textureViewerShader.hlsl");
}
private void InitState()
{
SamplerStateDescription desc = .();
desc.MagFilter = .Linear;
desc.MinFilter = .Linear;
_samplerLinear = SamplerStateManager.GetSampler(desc);
desc.MagFilter = .Point;
desc.MinFilter = .Point;
_samplerPoint = SamplerStateManager.GetSampler(desc);
}
Vector2 _position;
bool _moving;
float _colorOffset = 0;
float _colorScale = 1;
float _alphaOffset = 0;
float _alphaScale = 1;
public void ViewTexture(Texture viewedTexture)
{
ImGui.Begin("Texture Viewer");
ImGui.SliderFloat("Zoom", &_zoom, 0.01f, 100.0f);
char8*[] items = scope .("White", "Black", "Checkerboard");
ImGui.Combo("Background", (.)&_backgroundMode, items.Ptr, (.)items.Count);
items = scope .("Point", "Linear");
ImGui.Combo("Sampler", (.)&_sampleMode, items.Ptr, (.)items.Count);
ImGui.SliderFloat2("Color offset and scale", *(float[2]*)&_colorOffset, -1.0f, 1.0f);
ImGui.SliderFloat2("Alpha offset and scale", *(float[2]*)&_alphaOffset, -1.0f, 1.0f);
ImGui.SliderFloat2("Position", *(float[2]*)&_position, 2 * -Math.Max(viewedTexture.Width, viewedTexture.Height) * _zoom, 2 * Math.Max(viewedTexture.Width, viewedTexture.Height) * _zoom);
ImGui.BeginChild("imageChild");
UpdateInput();
var viewportSize = ImGui.GetContentRegionAvail();
viewportSize.x = Math.Max(viewportSize.x, 1);
viewportSize.y = Math.Max(viewportSize.y, 1);
if(_target == null || viewportSize.x != _target.Width || viewportSize.y != _target.Height)
{
_target?.ReleaseRef();
_target = new RenderTarget2D(.(.R8G8B8A8_UNorm, (.)viewportSize.x, (.)viewportSize.y));
_depth?.ReleaseRef();
_depth = new DepthStencilTarget((.)viewportSize.x, (.)viewportSize.y, .D16_UNorm);
}
RenderTexture(viewedTexture);
ImGui.Image(_target, viewportSize);
ImGui.EndChild();
ImGui.End();
}
float lastWheel;
private void UpdateInput()
{
var windowPos = ImGui.GetWindowPos();
var mousePos = ImGui.GetIO().MousePos;
Vector2 mouseInWindow = .(mousePos.x - windowPos.x, mousePos.y - windowPos.y);
bool windowHovered = ImGui.IsWindowHovered();
if(windowHovered && Input.IsMouseButtonPressing(.MiddleButton))
{
_moving = true;
}
else if(Input.IsMouseButtonReleased(.MiddleButton))
{
_moving = false;
}
if(windowHovered || _moving)
{
float mouseWheel = ImGui.GetIO().MouseWheel;
float delta = mouseWheel - lastWheel;
if(delta != 0)
{
_position -= mouseInWindow;
_position /= _zoom;
_zoom *= Math.Pow(1.1f, delta);
_position *= _zoom;
_position += mouseInWindow;
}
}
if(_moving)
{
Int2 movement = Input.GetMouseMovement();
_position.X += movement.X;
_position.Y += movement.Y;
}
}
OrthographicCamera _camera = new OrthographicCamera() ~ delete _;
private void RenderTexture(Texture viewedTexture)
{
Viewport vp = .(0, 0, _target.Width, _target.Height);
RenderCommand.SetViewport(vp);
// TODO: don't clear pink!
RenderCommand.Clear(_target, .Pink);
RenderCommand.Clear(_depth, .Depth, 1.0f, 0);
//_target.Bind();
_context.SetRenderTarget(_target);
_context.SetDepthStencilTarget(_depth);
_context.BindRenderTargets();
Vector2 textureSize = Vector2(viewedTexture.Width, viewedTexture.Height);
Vector2 zoomedTextureSize = textureSize * _zoom;
Vector2 targetSize = Vector2(_target.Width, _target.Height);
_effect.Variables["ColorOffset"].SetData(_colorOffset);
_effect.Variables["ColorScale"].SetData(_colorScale);
_effect.Variables["AlphaOffset"].SetData(_alphaOffset);
_effect.Variables["AlphaScale"].SetData(_alphaScale);
_camera.Left = 0;
_camera.Top = 0;
_camera.Right = targetSize.X;
_camera.Bottom = -targetSize.Y;
_camera.NearPlane = -5;
_camera.FarPlane = 5;
_camera.Update();
Renderer2D.BeginScene(_camera);
switch(_backgroundMode)
{
case .Black:
Renderer2D.DrawQuadPivotCorner(Vector3(0, 0, 1), targetSize, 0, .Black);
case .White:
Renderer2D.DrawQuadPivotCorner(Vector3(0, 0, 1), targetSize, 0, .White);
case .Checkerboard:
float quadSize = 50.0f;
Vector2 numQuads = (targetSize / 500f) * 10f;
for(float x = 0; x < numQuads.X; x++)
{
for(float y = 0; y < numQuads.Y; y++)
{
Renderer2D.DrawQuadPivotCorner(Vector3(x * quadSize, -y * quadSize, 1), quadSize.XX, 0, ((x + y) % 2 == 0) ? .White : .Gray);
}
}
break;
}
Renderer2D.EndScene();
var sampler = viewedTexture.SamplerState;
switch(_sampleMode)
{
case .Point:
viewedTexture.SamplerState = _samplerPoint;
case .Linear:
viewedTexture.SamplerState = _samplerLinear;
}
Renderer2D.BeginScene(_camera, .SortByTexture, _effect);
Renderer2D.DrawQuad(Vector3(_position * .(1, -1), 0), zoomedTextureSize, 0, viewedTexture);
Renderer2D.EndScene();
viewedTexture.SamplerState = sampler;
}
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
FileVersion = 1
Dependencies = {GlitchLog = "*", corlib = "*", DirectX = "*", FreeType = "*", cgltf-beef = "*", msdfgen-beef = "*", ImGui = "*", ImGuiImplDX11 = "*", ImGuiImplWin32 = "*", ImGuizmo = "*", Beefy2D = "*", LodePng = "*", GlitchyEngineHelper = "*", bon = "*", box2d-beef = "*", "Beef.Linq" = "*"}
Dependencies = {GlitchLog = "*", corlib = "*", DirectX = "*", FreeType = "*", cgltf-beef = "*", msdfgen-beef = "*", ImGui = "*", ImGuiImplDX11 = "*", ImGuiImplWin32 = "*", ImGuizmo = "*", Beefy2D = "*", LodePng = "*", GlitchyEngineHelper = "*", bon = "*"}
[Project]
Name = "GlitchyEngine"
+11 -21
View File
@@ -7,12 +7,13 @@ using GlitchyEngine.Content;
namespace GlitchyEngine
{
public abstract class Application
public class Application
{
static Application s_Instance = null;
private Window _window;
private RendererAPI _rendererApi;
private EffectLibrary _effectLibrary;
private bool _running = true;
private bool _isMinimized = false;
@@ -30,6 +31,8 @@ namespace GlitchyEngine
public bool IsRunning => _running;
public Window Window => _window;
public EffectLibrary EffectLibrary => _effectLibrary;
public IContentManager ContentManager => _contentManager;
public bool IsMinimized => _isMinimized;
@@ -52,20 +55,18 @@ namespace GlitchyEngine
_window = new Window(.Default);
_window.EventCallback = new => OnEvent;
Input.Init();
_contentManager = InitContentManager();
// TODO: RenderAPI in RenderCommand initialisieren?
_rendererApi = new RendererAPI();
_rendererApi.Context = _window.Context;
_contentManager = new ContentManager("./content");
SamplerStateManager.Init();
// TODO: Rendercommmand in Renderer initialisieren?
RenderCommand.RendererAPI = _rendererApi;
Renderer.Init();
_effectLibrary = new EffectLibrary();
Renderer.Init(_window.Context, _effectLibrary);
#if IMGUI
_imGuiLayer = new ImGuiLayer();
@@ -76,13 +77,6 @@ namespace GlitchyEngine
Settings.Apply();
}
/// Initializes the content manager.
protected abstract IContentManager InitContentManager();
//{
// TODO: init default content manager?
//_contentManager = new ContentManager("./content");
//}
public ~this()
{
Profiler.ProfileFunction!();
@@ -90,6 +84,8 @@ namespace GlitchyEngine
SamplerStateManager.Uninit();
Renderer.Deinit();
delete _effectLibrary;
delete _contentManager;
delete _rendererApi;
@@ -171,12 +167,6 @@ namespace GlitchyEngine
}
}
/// Closes the applcation.
public void Close()
{
_running = false;
}
public void PushLayer(Layer ownLayer)
{
Profiler.ProfileFunction!();
-32
View File
@@ -2,11 +2,6 @@ using System.Collections;
namespace GlitchyEngine.Collections
{
// TODO: TreeNode is very bare minimum
// Destructor?
// RemoveChild?
// Remove in enumerator?
public class TreeNode<T>
{
public T Value;
@@ -49,32 +44,5 @@ namespace GlitchyEngine.Collections
return null;
}
public static ref T operator ->(TreeNode<T> node)
{
return ref node.Value;
}
}
static
{
public static mixin DeleteTreeAndChildren<T>(TreeNode<T> tree) where T : class, delete
{
InternalDeleteTreeAndChildren(tree);
}
private static void InternalDeleteTreeAndChildren<T>(TreeNode<T> tree) where T : class, delete
{
for (var child in tree.Children)
{
InternalDeleteTreeAndChildren(child);
}
delete tree.Value;
tree.Children.Clear();
delete tree;
}
}
}
-83
View File
@@ -1,83 +0,0 @@
using GlitchyEngine.Core;
using System;
using Bon;
using Bon.Integrated;
using System.Reflection;
using System.IO;
namespace GlitchyEngine.Content;
[BonTarget]
class Asset : RefCounter
{
private append String _identifier;
internal IContentManager _contentManager;
/// Gets the identifier of this asset.
/// @remarks The identifier is the name with which the asset was registered in the content manager.
/// This identifier can be used to request the Asset from the content manager.
public StringView Identifier
{
get => _identifier;
set
{
_contentManager?.UpdateAssetIdentifier(this, _identifier, value);
_identifier.Set(value);
// TODO: do we need to tell the content manager, that the name changed?
}
}
// TODO: do we need unmanaged assets? Probably not...
/// Gets the content manager that manages this asset; or null if this asset isn't managed.
public IContentManager ContentManager => _contentManager;
static this
{
gBonEnv.typeHandlers.Add(typeof(Asset),
((.)new => AssetSerialize, new => AssetDeserialize));
}
protected ~this()
{
// TODO: crash when _contentManager is deleted first...
// TODO: unregister from content manager
_contentManager?.UnmanageAsset(this);
}
static void AssetSerialize(BonWriter writer, ValueView value, BonEnvironment environment, SerializeValueState state)
{
Log.EngineLogger.Assert(value.type == typeof(Asset));
let identifier = value.Get<Asset>().Identifier;
writer.String(identifier);
}
static Result<void> AssetDeserialize(BonReader reader, ValueView value, BonEnvironment environment, DeserializeValueState state)
{
Log.EngineLogger.Assert(value.type == typeof(Asset));
String identifier = scope .();
Deserialize.String!(reader, ref identifier, environment);
Asset asset = Application.Get().ContentManager.LoadAsset(identifier);
if (asset != null)
{
Asset oldAsset = value.Get<Asset>();
oldAsset.ReleaseRef();
value.Assign(asset);
return .Ok;
}
else
{
Deserialize.Error!("Invalid resource path", reader, value.type);
}
}
//gBonEnv.typeHandlers.Add(typeof(Resource<>),
// ((.)new => ResourceSerialize, (.)new => ResourceDeserialize));
}
+5 -118
View File
@@ -1,8 +1,6 @@
using System;
using System.IO;
using xxHash;
using System.Collections;
using Bon;
namespace GlitchyEngine.Content
{
@@ -25,125 +23,16 @@ namespace GlitchyEngine.Content
}
}
[BonTarget, BonPolyRegister]
abstract class AssetLoaderConfig
{
[BonIgnore]
protected bool _changed;
public bool Changed => _changed;
protected bool SetIfChanged<T>(ref T field, T value)
{
if (field == value)
return false;
field = value;
_changed = true;
return true;
}
}
interface IAssetLoader
{
static List<StringView> FileExtensions { get; }
AssetLoaderConfig GetDefaultConfig();
/// Loads the asset from the given data stream with the specified config.
/// @param file The stream containing the asset.
/// @param config The configuration which specifies the settings used to load the asset.
/// @param contentManager The content manager used to load the asset.
/// @returns The loaded asset.
Asset LoadAsset(Stream file, AssetLoaderConfig config, StringView assetIdentifier, StringView? subAsset, IContentManager contentManager);
}
static
{
/// Loads the specified asset with the given contentManager or the current applications content manager.
public static T LoadAsset<T>(StringView assetIdentifier, IContentManager contentManager = null) where T : Asset
{
var contentManager;
if (contentManager == null)
contentManager = Application.Get().ContentManager;
Asset asset = contentManager.LoadAsset(assetIdentifier);
Log.EngineLogger.AssertDebug(asset is T);
return (T)asset;
}
}
interface IContentManager
{
/// Loads the given asset.
Asset LoadAsset(StringView assetIdentifier);
void GetFilePath(String outFilename, String filename);
/// The content manager will manage the asset (e.g. provide it when LoadAsset is called with the assets identifier)
void ManageAsset(Asset asset);
/// The content manager will no longer manage the asset.
void UnmanageAsset(Asset asset);
// TODO: Maybe calling UnmanageAsset -> ManageAsset is enough....
/// Provides a method for the asset to tell its content manager that the identifer changed.
void UpdateAssetIdentifier(Asset asset, StringView oldIdentifier, StringView newIdentifier);
/// Returns a data stream for the given asset.
Stream GetStream(StringView assetIdentifier);
void RegisterAssetLoader<T>() where T : new, class, IAssetLoader;
void SetAsDefaultAssetLoader<T>(params Span<StringView> fileExtensions) where T : IAssetLoader;
//void GetFilePath(String outFilename, String filename);
//Stream GetFile(String filename);
Stream GetFile(String filename);
}
class RuntimeContentManager : IContentManager
class ContentManager : IContentManager
{
public this()
{
Runtime.NotImplemented();
}
public Asset LoadAsset(StringView assetIdentifier)
{
Runtime.NotImplemented();
}
public void ManageAsset(Asset asset)
{
Runtime.NotImplemented();
}
public void UnmanageAsset(Asset asset)
{
Runtime.NotImplemented();
}
public void UpdateAssetIdentifier(Asset asset, StringView oldIdentifier, StringView newIdentifier)
{
Runtime.NotImplemented();
}
public Stream GetStream(StringView assetIdentifier)
{
Runtime.NotImplemented();
}
public void RegisterAssetLoader<T>() where T : IAssetLoader where T : class where T : new
{
Runtime.NotImplemented();
}
public void SetAsDefaultAssetLoader<T>(params Span<StringView> fileExtensions) where T : IAssetLoader
{
Runtime.NotImplemented();
}
/*private String _contentRoot;
private String _contentRoot;
[AllowAppend]
public this(String contentRoot)
@@ -164,8 +53,6 @@ namespace GlitchyEngine.Content
String fullpath = scope .(_contentRoot.Length + 1 + filename.Length);
GetFilePath(fullpath, filename);
Log.EngineLogger.AssertDebug(File.Exists(fullpath), "File doesn't exist!");
FileStream stream = new FileStream();
var result = stream.Open(fullpath, .Read, .Read);
@@ -176,6 +63,6 @@ namespace GlitchyEngine.Content
}
return stream;
}*/
}
}
}
+20 -246
View File
@@ -5,7 +5,6 @@ using GlitchyEngine.Math;
using GlitchyEngine.Renderer;
using GlitchyEngine.Renderer.Animation;
using GlitchyEngine.World;
using System.IO;
namespace GlitchyEngine.Content
{
@@ -13,224 +12,8 @@ namespace GlitchyEngine.Content
{
static readonly Matrix RightToLeftHand = .Scaling(1, 1, -1);
public static Result<void> GetMeshNames(String filename, List<String> meshNames)
{
CGLTF.Options options = .();
CGLTF.Data* data;
CGLTF.Result result = CGLTF.ParseFile(options, filename, out data);
if (!(result case .Success))
return .Err;
for (var mesh in data.Meshes)
{
meshNames.Add(new String(mesh.Name));
}
CGLTF.Free(data);
return .Ok;
}
public static GeometryBinding LoadMesh(StringView fileName, StringView meshName, int primitiveIndex)
{
// TODO: add a context to remember which buffers were loaded before so that we don't load the same data multiple times.
char8* scopedFileName = fileName.ToScopeCStr!();
CGLTF.Options options = .();
CGLTF.Data* data;
CGLTF.Result result = CGLTF.ParseFile(options, scopedFileName, out data);
if (!(result case .Success))
return null;
result = CGLTF.LoadBuffers(options, data, scopedFileName);
GeometryBinding geoBinding = null;
for (var mesh in data.Meshes)
{
var name = StringView(mesh.Name);
if (name == meshName)
{
Log.EngineLogger.AssertDebug(primitiveIndex >= 0 && primitiveIndex < mesh.Primitives.Length);
geoBinding = PrimitiveToGeoBinding(mesh.Primitives[primitiveIndex]);
break;
}
}
CGLTF.Free(data);
return geoBinding;
}
public static GeometryBinding LoadMesh(Stream data, StringView meshName, int primitiveIndex)
{
// TODO: add a context to remember which buffers were loaded before so that we don't load the same data multiple times.
uint8[] rawData = new:ScopedAlloc! uint8[data.Length];
var dataReadResult = data.TryRead(rawData);
if (dataReadResult case .Err(let err))
{
Log.EngineLogger.Error($"Failed to read data from stream. Error: {err}");
}
CGLTF.Options options = .();
CGLTF.Data* modelData;
CGLTF.Result result = CGLTF.Parse(options, (Span<uint8>)rawData, out modelData);
if (!(result case .Success))
return null;
// TODO: one buffer can be used by multiple primitives, the content manager could manage the buffers
// TODO: load with content manager
result = CGLTF.LoadBuffers(options, modelData, (char8*)null);
//result = LoadBuffersWithContentManager(options, modelData, meshName, Application.Get().ContentManager);
GeometryBinding geoBinding = null;
for (var mesh in modelData.Meshes)
{
var name = StringView(mesh.Name);
//if (name == meshName)
{
Log.EngineLogger.AssertDebug(primitiveIndex >= 0 && primitiveIndex < mesh.Primitives.Length);
geoBinding = PrimitiveToGeoBinding(mesh.Primitives[primitiveIndex]);
break;
}
}
CGLTF.Free(modelData);
return geoBinding;
}
private static CGLTF.Result LoadBuffersWithContentManager(CGLTF.Options options, CGLTF.Data* data, StringView fileName, IContentManager contentManager)
{
if (data.Buffers.Length > 0 && data.Buffers[0].Data == null && data.Buffers[0].Uri == null && !data.Bin.IsEmpty)
{
if ((uint)data.Bin.Length < data.Buffers[0].Size)
return .DataTooShort;
data.Buffers[0].Data = data.Bin.Ptr;
data.Buffers[0].DataFreeMethod = .None;
}
for (ref CGLTF.Buffer buffer in ref data.Buffers)
{
if (buffer.Data != null)
continue;
if (buffer.Uri == null)
continue;
StringView uri = StringView(buffer.Uri);
if (uri.StartsWith("data:"))
{
int commaIndex = uri.IndexOf(',');
//char* comma = strchr(uri, ',');
if (commaIndex == -1 || commaIndex >= 7 || uri.StartsWith(";base64"))
return .UnknownFormat;
StringView dataView = uri.Substring(commaIndex + 1);
#unwarn
CGLTF.Result loadBufferResult = CGLTF.LoadBuffersBase64(&options, buffer.Size, dataView.Ptr, &buffer.Data);
buffer.DataFreeMethod = .MemoryFree;
return loadBufferResult;
}
else
{
Runtime.NotImplemented();
// TODO: Request Buffer from Content Manager
//int index = uri.IndexOf("://");
//if (index == -1)
// return .UnknownFormat;
// TODO: load buffer file...
//CGLTF.Result res = //cgltf_load_buffer_file(options, data->buffers[i].size, uri, gltf_path, &data->buffers[i].data);
//buffer.DataFreeMethod = cgltf_data_free_method_file_release;
/*if (res != cgltf_result_success)
{
return res;
}*/
}
}
/*
for (cgltf_size i = 0; i < data->buffers_count; ++i)
{
if (data->buffers[i].data)
{
continue;
}
const char* uri = data->buffers[i].uri;
if (uri == NULL)
{
continue;
}
if (strncmp(uri, "data:", 5) == 0)
{
const char* comma = strchr(uri, ',');
if (comma && comma - uri >= 7 && strncmp(comma - 7, ";base64", 7) == 0)
{
cgltf_result res = cgltf_load_buffer_base64(options, data->buffers[i].size, comma + 1, &data->buffers[i].data);
data->buffers[i].data_free_method = cgltf_data_free_method_memory_free;
if (res != cgltf_result_success)
{
return res;
}
}
else
{
return cgltf_result_unknown_format;
}
}
else if (strstr(uri, "://") == NULL && gltf_path)
{
cgltf_result res = cgltf_load_buffer_file(options, data->buffers[i].size, uri, gltf_path, &data->buffers[i].data);
data->buffers[i].data_free_method = cgltf_data_free_method_file_release;
if (res != cgltf_result_success)
{
return res;
}
}
else
{
return cgltf_result_unknown_format;
}
}
*/
return .Success;
}
public static EcsEntity LoadModel(String filename, Material material, EcsWorld world,
List<AnimationClip> outClips, StringView entityName = StringView())
public static void LoadModel(String filename, Effect validationEffect, Material material, EcsWorld world,
List<AnimationClip> outClips)
{
CGLTF.Options options = .();
CGLTF.Data* data;
@@ -242,47 +25,38 @@ namespace GlitchyEngine.Content
Log.EngineLogger.Assert(result == .Success, "Failed to load buffers");
(EcsEntity entity, ?) = CreateEntity(world, entityName, .InvalidEntity);
for(var node in data.Scenes[0].Nodes)
{
NodesToEntities(data, node, entity, world, material, outClips);
NodesToEntities(data, node, null, world, validationEffect, material, outClips);
}
CGLTF.Free(data);
return entity;
}
private static (EcsEntity Entity, TransformComponent* Transform) CreateEntity(EcsWorld world, StringView? name, EcsEntity parent)
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 (name != null && name.Value.Ptr != null)
if (node.Name != null)
{
nameComponent.SetName(name.Value);
nameComponent.SetName(StringView(node.Name));
}
else
{
nameComponent.SetName("Unnamed Node");
}
#endif
/////TODO: !!!!!!!!REPORT!!!!!!!!!!!!!
// This works
TransformComponent cmp = .();
var childTransform = world.AssignComponent<TransformComponent>(entity, cmp);
// This trashes the stack
//var childTransform = world.AssignComponent<TransformComponent>(entity);
childTransform.Parent = parent;
return (entity, childTransform);
if(parentEntity.HasValue)
{
var childParent = world.AssignComponent<ParentComponent>(entity);
childParent.Entity = parentEntity.Value;
}
private static void NodesToEntities(CGLTF.Data* data, CGLTF.Node* node, EcsEntity parentEntity, EcsWorld world, Material material, List<AnimationClip> clips)
{
(EcsEntity entity, TransformComponent* childTransform) = CreateEntity(world, node.Name == null ? null : StringView(node.Name), parentEntity);
var childTransform = world.AssignComponent<TransformComponent>(entity);
if(node.HasMatrix)
{
@@ -307,7 +81,7 @@ namespace GlitchyEngine.Content
}
// Invert the Z-Axis of the root Node to convert the coordinate system from right-handed to left-handed
if(parentEntity == .InvalidEntity)
if(parentEntity == null)
childTransform.Scale *= .(1, 1, -1);
Skeleton skeleton = null;
@@ -326,7 +100,7 @@ namespace GlitchyEngine.Content
{
var mesh = world.AssignComponent<MeshComponent>(entity);
using (var geo = PrimitiveToGeoBinding(node.Mesh.Primitives[0]))
using (var geo = PrimitiveToGeoBinding(node.Mesh.Primitives[0], validationEffect))
{
mesh.Mesh = geo;
}
@@ -354,7 +128,7 @@ namespace GlitchyEngine.Content
meshParent.Entity = entity;
var mesh = world.AssignComponent<MeshComponent>(meshEntity);
mesh.Mesh = PrimitiveToGeoBinding(primitive);
mesh.Mesh = PrimitiveToGeoBinding(primitive, validationEffect);
if(skeleton == null)
{
@@ -375,11 +149,11 @@ namespace GlitchyEngine.Content
for(var child in node.Children)
{
NodesToEntities(data, child, entity, world, material, clips);
NodesToEntities(data, child, entity, world, validationEffect, material, clips);
}
}
public static GeometryBinding PrimitiveToGeoBinding(CGLTF.Primitive primitive)
public static GeometryBinding PrimitiveToGeoBinding(CGLTF.Primitive primitive, Effect validationEffect)
{
GeometryBinding binding = new GeometryBinding();
@@ -491,7 +265,7 @@ namespace GlitchyEngine.Content
StringView strView = .(attribute.Name);
// Remove number from end of name
while((*(strView.EndPtr - 1)).IsDigit || (*(strView.EndPtr - 1)) == '_')
while((*(strView.EndPtr - 1)).IsDigit)
{
strView.Length--;
}
@@ -544,7 +318,7 @@ namespace GlitchyEngine.Content
vertexElements[i] = elements[i];
}
VertexLayout layout = new VertexLayout(vertexElements, true);
VertexLayout layout = new VertexLayout(vertexElements, true, validationEffect.VertexShader);
binding.SetVertexLayout(layout..ReleaseRefNoDelete());
}
-112
View File
@@ -1,112 +0,0 @@
using System;
using System.IO;
namespace GlitchyEngine.Core;
// TODO: make usable
class FilePath : IHashable
{
append String _path = .();
public bool IsRooted => Path.IsPathRooted(_path);
public this()
{
}
public this(StringView path)
{
Set(path);
}
public static implicit operator StringView(FilePath filePath) => filePath._path;
/// @param fixDirectorySeperators If true all alternative directory seperators will be replaced by the primary seperator.
/// @param resolveRelativeDirectories If true relative directories ('.' and '..') will be removed from the path.
public enum CanonicalizationFlags
{
FixDirectorySeperators = 1,
ResolveRelativeDirectories = _ << 1,
MakeFullPath = _ << 1
}
public void Set(StringView path, CanonicalizationFlags canonicalizationFlags = .FixDirectorySeperators | .ResolveRelativeDirectories)
{
_path.Append(path);
Canonicalize(canonicalizationFlags);
}
/// Converts the path to a canonicalized path.
public void Canonicalize(CanonicalizationFlags canonicalizationFlags = .FixDirectorySeperators | .ResolveRelativeDirectories)
{
if (canonicalizationFlags.HasFlag(.FixDirectorySeperators))
{
FixDirectorySeperators();
}
if (canonicalizationFlags.HasFlag(.ResolveRelativeDirectories))
{
ResolveRelativeDirectories();
}
if (canonicalizationFlags.HasFlag(.MakeFullPath))
{
MakeFullPath();
}
}
public void MakeFullPath()
{
if (IsRooted)
return;
String buffer = scope String(Path.[Friend]MaxPath);
Path.GetFullPath(_path, buffer);
_path..Clear().Append(buffer);
}
public void FixDirectorySeperators()
{
_path.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
}
public void ResolveRelativeDirectories()
{
// find .
// find entire entry name
// remove entry name (if its only .)
/*for (char32 c in _path.DecodedChars)
{
if (c == '.')
{
}
}
for (StringView component in _path.Split(Path.DirectorySeparatorChar))
{
if (component == ".")
{
// . can be removed without replacement
}
else if (component == "..")
{
// .. can only be removed when not at the start of after another ..
// e.g. "../foo" and "../../foo" can't be changed
// but "foo/.." can become "foo"
// "foo/../.." can become ".."
}
}*/
}
public void Append(StringView newPath)
{
}
public int GetHashCode() => _path.GetHashCode();
}
+1 -5
View File
@@ -7,12 +7,8 @@ namespace GlitchyEngine.Core
* 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 : RefCounted, IDisposable
public class RefCounter : System.RefCounted, IDisposable
{
protected ~this()
{
}
public void Dispose()
{
ReleaseRef();
-53
View File
@@ -1,53 +0,0 @@
using Bon;
using System;
using Bon.Integrated;
using System.Collections;
namespace GlitchyEngine.Core
{
[BonTarget]
struct UUID : IHashable
{
[BonInclude]
private uint64 _uuid;
private static Random s_Random = new .() ~ delete _;
static this()
{
gBonEnv.typeHandlers.Add(typeof(UUID),
((.)new => Serialize, (.)new => Deserialize));
}
/// Creates a new random UUID.
public this()
{
_uuid = s_Random.NextU64();
}
/// Creates a new UUID with the given value.
public this(uint64 uuid)
{
_uuid = uuid;
}
public int GetHashCode()
{
return (int)_uuid;
}
static void Serialize(BonWriter writer, ValueView val, BonEnvironment env, SerializeValueState state)
{
UUID uuid = *(UUID*)val.dataPtr;
Bon.Integrated.Serialize.[Friend]Integer(typeof(uint64), writer, ValueView(typeof(uint64), &uuid._uuid));
}
public static Result<void> Deserialize(BonReader reader, ValueView val, BonEnvironment env, DeserializeValueState state)
{
Bon.Integrated.Deserialize.[Friend]Integer!(typeof(uint64), reader, val);
return .Ok;
}
}
}
-27
View File
@@ -29,33 +29,6 @@ namespace GlitchyEngine.Events
}
}
public class RawMouseMovedEvent : Event, IEvent
{
private int32 _mouseX, _mouseY;
public override EventType EventType => .MouseMoved;
public override StringView Name => "RawMouseMoved";
public override EventCategory Category => .Input | .Mouse;
public static EventType StaticType => .MouseMoved;
public int32 PositionX => _mouseX;
public int32 PositionY => _mouseY;
public this(int32 x, int32 y)
{
_mouseX = x;
_mouseY = y;
}
public override void ToString(String strBuffer)
{
strBuffer.AppendF("RawMouseMovedEvent: Position: ({}, {})", _mouseX, _mouseY);
}
}
public class MouseScrolledEvent : Event, IEvent
{
private int32 _xOffset, _yOffset;
@@ -1,37 +0,0 @@
using System;
namespace Bon.Integrated
{
extension Serialize
{
public static void Value<T>(BonWriter writer, StringView identifier, in T value, BonEnvironment env = gBonEnv)
{
writer.Identifier(identifier);
Serialize.Value(writer, ValueView(typeof(T), &value), env);
}
public static void Value<T>(BonWriter writer, in T value, BonEnvironment env = gBonEnv)
{
Serialize.Value(writer, ValueView(typeof(T), &value), env);
}
}
extension Deserialize
{
public static Result<void> Value<T>(BonReader reader, StringView identifier, out T value, BonEnvironment env = gBonEnv)
{
value = ?;
if (Try!(reader.Identifier()) != identifier)
return .Err;
return Deserialize.Value(reader, ValueView(typeof(T), &value), env);
}
public static Result<void> Value<T>(BonReader reader, out T value, BonEnvironment env = gBonEnv)
{
value = ?;
return Deserialize.Value(reader, ValueView(typeof(T), &value), env);
}
}
}
@@ -1,47 +0,0 @@
using System.Diagnostics;
namespace System.IO;
extension Path
{
public static mixin GetScopedFullPath(String path)
{
String fullPath = scope:: String(Path.MaxPath);
Path.GetFullPath(path, fullPath);
fullPath
}
/// Opens the file browser and selects the specified file.
/// @param path The path of the file to select.
public static extern Result<void> OpenFolderAndSelectItem(String path);
/// Opens the file browser in the given directory.
/// @param directory The directory to show in the file browser.
public static extern Result<void> OpenFolder(String directory);
/// Shows a dialog in which the user can select which program to open the given file with.
/// @param The Path of the file to open.
public static extern Result<void> OpenWithDialog(String filePath);
public static void Fixup(String path)
{
path.Replace(AltDirectorySeparatorChar, DirectorySeparatorChar);
path.Replace(scope $".{DirectorySeparatorChar}", "");
path.Replace(scope $"{DirectorySeparatorChar}.", "");
if (path.StartsWith(DirectorySeparatorChar))
path.Remove(0, 1);
}
public static void Combine(String target, params StringView[] components)
{
for (var component in components)
{
if ((target.Length > 0) && (!target.EndsWith("\\")) && (!target.EndsWith("/")) &&
(!component.StartsWith("\\")) && (!component.StartsWith("/")))
target.Append(Path.DirectorySeparatorChar);
target.Append(component);
}
}
}
@@ -17,11 +17,5 @@ namespace System
target[copiedChars] = '\0';
}
/// Converts camel case and delimiter-separated words to normal words.
public void ToHumanReadable()
{
// TODO!
}
}
}
+45 -242
View File
@@ -1,21 +1,9 @@
using GlitchyEngine.Math;
using GlitchyEngine.Renderer;
using System;
using GlitchyEngine;
using System.Collections;
namespace GlitchyEngine.Math
{
extension ColorRGBA
{
internal uint32 ImGuiU32 => ImGui.ImGui.ColorConvertFloat4ToU32((.)(Vector4)this);
}
}
namespace ImGui
{
using internal GlitchyEngine.Math;
extension ImGui
{
extension Vec2
@@ -30,30 +18,6 @@ namespace ImGui
public static explicit operator Vec4(Vector4 v) => .(v.X, v.Y, v.Z, v.W);
}
/*public static bool IsItemJustDeactivated()
{
return IsItemDeactivatedAfterEdit();
}
public static bool IsItemActiveLastFrame()
{
Context* g = GetCurrentContext();
if (g.ActiveIdPreviousFrame != 0)
return g.ActiveIdPreviousFrame == g.CurrentWindow.DC.LastItemId;
return false;
}
public static bool IsItemJustActivated()
{
return IsItemActive() && !IsItemActiveLastFrame();
}
public static bool IsItemEditing()
{
return IsItemActive();
}*/
// 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 ColorRGBA col, ColorEditFlags flags = (ColorEditFlags) 0) => ColorEdit3Impl(label, *(float[3]*)&col, flags);
@@ -65,39 +29,9 @@ namespace ImGui
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 void Image(Texture2D texture, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, Vec4 tint_col = Vec4.Ones, Vec4 border_col = Vec4.Zero)
{
Image(texture.GetViewBinding(), size, uv0, uv1, tint_col, border_col);
}
public static void Image(SubTexture2D subTexture, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, Vec4 tint_col = Vec4.Ones, Vec4 border_col = Vec4.Zero)
{
if (uv0 != .Zero || uv1 != .Ones)
Runtime.NotImplemented();
Vector2 v = (.)subTexture.TexCoords.XY + subTexture.TexCoords.ZW;
Image(subTexture.Texture.GetViewBinding(), size, (.)subTexture.TexCoords.XY, (.)v, tint_col, border_col);
}
public static void Image(RenderTarget2D texture, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, Vec4 tint_col = Vec4.Ones, Vec4 border_col = Vec4.Zero)
{
Image(texture.GetViewBinding(), size, uv0, uv1, tint_col, border_col);
}
public static extern void Image(TextureViewBinding textureViewBinding, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, Vec4 tint_col = Vec4.Ones, Vec4 border_col = Vec4.Zero);
public static bool ImageButton(SubTexture2D subTexture, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, int32 frame_padding = -1, Vec4 bg_col = Vec4.Zero, Vec4 tint_col = Vec4.Ones)
{
if (uv0 != .Zero || uv1 != .Ones)
Runtime.NotImplemented();
Vector2 v = (.)subTexture.TexCoords.XY + subTexture.TexCoords.ZW;
return ImageButton(subTexture.Texture.GetViewBinding(), size, (.)subTexture.TexCoords.XY, (.)v, frame_padding, bg_col, tint_col);
}
public static extern bool ImageButton(TextureViewBinding textureViewBinding, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, int32 frame_padding = -1, Vec4 bg_col = Vec4.Zero, Vec4 tint_col = Vec4.Ones);
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);
@@ -106,45 +40,14 @@ namespace ImGui
/// Releases references that accumulated calls like ImGui::Image
protected internal static extern void CleanupFrame();
/// Control to edit a vector 2 with drag functionality and reset buttons
public static bool EditVector2(StringView label, ref Vector2 value, Vector2 resetValues = .Zero, float dragSpeed = 0.1f, float columnWidth = 100f, Vector2 minValue = .Zero, Vector2 maxValue = .Zero)
{
return EditVector<2>(label, ref *(float[2]*)&value, (float[2])resetValues, dragSpeed, columnWidth, (float[2])minValue, (float[2])maxValue);
}
/// 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, Vector3 minValue = .Zero, Vector3 maxValue = .Zero)
public static bool EditVector3(StringView label, ref Vector3 value, Vector3 resetValues = .Zero, float dragSpeed = 0.1f, float columnWidth = 100f)
{
return EditVector<3>(label, ref *(float[3]*)&value, (float[3])resetValues, dragSpeed, columnWidth, (float[3])minValue, (float[3])maxValue);
}
/// Control to edit a vector 4 with drag functionality and reset buttons
public static bool EditVector4(StringView label, ref Vector4 value, Vector4 resetValues = .Zero, float dragSpeed = 0.1f, float columnWidth = 100f, Vector4 minValue = .Zero, Vector4 maxValue = .Zero)
{
return EditVector<4>(label, ref *(float[4]*)&value, (float[4])resetValues, dragSpeed, columnWidth, (float[4])minValue, (float[4])maxValue);
}
static (ColorRGBA Default, ColorRGBA Hovered, ColorRGBA Active)[?] VectorButtonColors = .(
(.(230, 25, 45), .(150, 25, 45), .(230, 90, 90)),
(.(50, 190, 15), .(50, 120, 15), .(116, 190, 99)),
(.(55, 55, 230), .(55, 55, 150), .(90, 90, 230)),
(.(230, 25, 45), .(230, 25, 45), .(230, 25, 45)));
public static bool EditVector<NumComponents>(StringView label, ref float[NumComponents] value, float[NumComponents] resetValues = .(), float dragSpeed = 0.1f, float columnWidth = 100f, float[NumComponents] minValue = .(), float[NumComponents] maxValue = .()) where NumComponents : const int32
{
const String[?] componentNames = .("X", "Y", "Z", "W");
const String[?] componentIds = .("##X", "##Y", "##Z", "##W");
static int mouseLockId = 0;
bool changed = false;
bool deactivated = false;
PushID(label);
defer PopID();
int currentId = ImGui.GetID("");
Columns(2);
defer Columns(1);
SetColumnWidth(0, columnWidth);
@@ -153,171 +56,71 @@ namespace ImGui
NextColumn();
PushMultiItemsWidths(NumComponents, CalcItemWidth());
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);
PushStyleVar(.ItemSpacing, Vec2.Zero);
PushStyleColor(.Button, Color(230, 25, 45).Value);
PushStyleColor(.ButtonHovered, Color(150, 25, 45).Value);
PushStyleColor(.ButtonActive, Color(230, 120, 130).Value);
for (int i < NumComponents)
if (Button("X", buttonSize))
{
if (i > 0)
{
SameLine();
}
PushStyleColor(.Button, VectorButtonColors[i].Default.ImGuiU32);
PushStyleColor(.ButtonHovered, VectorButtonColors[i].Hovered.ImGuiU32);
PushStyleColor(.ButtonActive, VectorButtonColors[i].Active.ImGuiU32);
if (Button(componentNames[i], buttonSize))
{
value[i] = resetValues[i];
value.X = resetValues.X;
changed = true;
}
SameLine();
if (DragFloat(componentIds[i], &value[i], dragSpeed, minValue[i], maxValue[i]))
{
if (DragFloat("##X", &value.X, dragSpeed))
changed = true;
/*if (mouseLockId != currentId)
{
mouseLockId = currentId;
Mouse.LockCurrentPosition(mouseLockId);
}*/
}
/*if (IsItemDeactivatedAfterEdit())
{
deactivated = 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);
PopStyleVar();
/*if (mouseLockId == currentId && deactivated)
if (Button("Y", buttonSize))
{
Mouse.UnlockPosition(mouseLockId);
mouseLockId = 0;
}*/
return changed;
}
/// Draws a rectangle with the given color.
public static void DrawRect(Vec2 min, Vec2 max, Color color)
{
ImGui.GetForegroundDrawList().AddRect(min, max, ImGui.GetColorU32(color.Value));
}
/// Provides a combo Box to select an enum value.
public static bool EnumCombo<T>(StringView label, ref T selectedValue) where T : enum
{
String selectedValueString = scope .();
selectedValue.ToString(selectedValueString);
// TODO: make selectedValue human readable
bool changed = false;
if (ImGui.BeginCombo(label.ToScopeCStr!(), selectedValueString))
{
for (let (name, value) in Enum.GetEnumerator<T>())
{
ImGui.PushID(name);
if (ImGui.Selectable(name.ToScopeCStr!(), selectedValue == value))
{
selectedValue = value;
value.Y = resetValues.Y;
changed = true;
}
ImGui.PopID();
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;
}
ImGui.EndCombo();
}
SameLine();
if (DragFloat("##Z", &value.Z, dragSpeed))
changed = true;
PopItemWidth();
PopStyleColor(3);
return changed;
}
/// Provides a tooltip that will be show when the previously defined Widget is hovered.
public static void AttachTooltip(StringView tooltip)
{
if (!ImGui.IsItemHovered())
return;
ImGui.BeginTooltip();
ImGui.TextUnformatted(tooltip);
ImGui.EndTooltip();
}
[Comptime]
private static DataType GetDataType<T>()
{
DataType dataType = .COUNT;
switch (typeof(T))
{
case typeof(int8):
dataType = .S8;
case typeof(int16):
dataType = .S16;
case typeof(int32):
dataType = .S32;
case typeof(int64):
dataType = .S64;
case typeof(int):
if (sizeof(int) == 8)
dataType = .S64;
else if (sizeof(int) == 4)
dataType = .S32;
case typeof(uint8):
dataType = .U8;
case typeof(uint16):
dataType = .U16;
case typeof(uint32):
dataType = .U32;
case typeof(uint64):
dataType = .U64;
case typeof(uint):
if (sizeof(uint) == 8)
dataType = .U64;
else if (sizeof(uint) == 4)
dataType = .U32;
//default:
// Runtime.Assert(dataType != .COUNT);
//Log.EngineLogger.Assert(dataType != .COUNT, "Unknown data type.");
}
return dataType;
}
// TODO: Add support for floats
public static bool DragScalar<T>(char8* label, ref T value, float dragSpeed = (float) 1.0f, T minValue = typeof(T).MinValue, T maxValue = typeof(T).MaxValue, char8* format = null, SliderFlags sliderFlags = .None) where T : IInteger
{
DataType dataType = GetDataType<T>();
#unwarn
return DragScalar(label, dataType, &value, dragSpeed, &minValue, &maxValue, format, sliderFlags);
}
// TODO: Add support for floats
public static bool SliderScalar<T>(char8* label, ref T value, T minValue = typeof(T).MinValue, T maxValue = typeof(T).MaxValue, char8* format = null, SliderFlags sliderFlags = .None) where T : IInteger
{
DataType dataType = GetDataType<T>();
#unwarn
return SliderScalar(label, dataType, &value, &minValue, &maxValue, format, sliderFlags);
}
}
}
+4 -9
View File
@@ -96,19 +96,16 @@ namespace GlitchyEngine.ImGui
ImGui.GetIO().Fonts.Clear();
// TODO: Fix fonts
//String fullpath = scope String();
//Application.Get().ContentManager.GetFilePath(fullpath, settings.FontName);
/*Application.Get().ContentManager.GetStream(settings.FontName);
String fullpath = scope String();
Application.Get().ContentManager.GetFilePath(fullpath, settings.FontName);
if (File.Exists(fullpath))
{
ImGui.GetIO().Fonts.AddFontFromMemoryTTF();
ImGui.GetIO().Fonts.AddFontFromFileTTF(fullpath, settings.FontSize);
}
else
{*/
{
ImGui.GetIO().Fonts.AddFontDefault();
//}
}
#if GE_GRAPHICS_DX11
ImGuiImplDX11.CreateDeviceObjects();
@@ -119,8 +116,6 @@ namespace GlitchyEngine.ImGui
Begin();
ImGui.ShowDemoWindow();
{
Debug.Profiler.ProfileScope!("ImGuiRenderEvent");
+6 -137
View File
@@ -1,8 +1,6 @@
using System;
using GlitchyEngine.Events;
using GlitchyEngine.Math;
using System.Collections;
using ImGui;
namespace GlitchyEngine
{
@@ -27,151 +25,22 @@ namespace GlitchyEngine
*/
public static extern bool IsKeyReleasing(Key keycode);
// TODO: Should Input be able to set mousepos?
public static extern void SetMousePosition(Int2 pos);
public static extern bool IsMouseButtonPressed(MouseButton button);
public static extern bool IsMouseButtonReleased(MouseButton button);
public static extern bool IsMouseButtonPressing(MouseButton button);
public static extern bool IsMouseButtonReleasing(MouseButton button);
public static extern Int2 GetMousePosition();
public static extern Int2 GetMouseMovement();
public static extern Int2 GetRawMouseMovement();
public static extern Point GetMousePosition();
public static extern int32 GetMouseX();
public static extern int32 GetMouseY();
public static extern bool WasMouseButtonPressed(MouseButton button);
// public static extern bool WasMouseButtonPressing(MouseButton button);
public static extern bool WasMouseButtonReleased(MouseButton button);
//public static extern bool WasMouseButtonReleasing(MouseButton button);
public static extern Int2 GetLastMousePosition();
public static extern Int2 GetLastMouseMovement();
public static extern Int2 GetLastRawMouseMovement();
public static extern Point GetLastMousePosition();
public static extern int32 GetLastMouseX();
public static extern int32 GetLastMouseY();
public static extern void Init();
public static extern bool IsMouseButtonPressing(MouseButton button);
public static extern bool IsMouseButtonReleasing(MouseButton button);
public static extern Point GetMouseMovement();
public static void NewFrame()
{
[Inline]
Impl_NewFrame();
Mouse.NewFrame();
[Inline]
Impl_EndFrame();
}
public static extern void Impl_NewFrame();
public static extern void Impl_EndFrame();
public static void ImGuiDebugDraw()
{
if (ImGui.Begin("Input"))
{
ImGui.TextUnformatted("Last Mouse state");
ImGui.Columns(2);
ImGui.TextUnformatted("Position");
ImGui.NextColumn();
ImGui.Text($"{GetLastMousePosition()}");
ImGui.NextColumn();
ImGui.TextUnformatted("Movement");
ImGui.NextColumn();
ImGui.Text($"{GetLastMouseMovement()}");
ImGui.NextColumn();
ImGui.TextUnformatted("RawMovement");
ImGui.NextColumn();
ImGui.Text($"{GetLastRawMouseMovement()}");
ImGui.NextColumn();
ImGui.Columns(1);
ImGui.Separator();
ImGui.TextUnformatted("Current Mouse state");
ImGui.Columns(2);
ImGui.TextUnformatted("Position");
ImGui.NextColumn();
ImGui.Text($"{GetMousePosition()}");
ImGui.NextColumn();
ImGui.TextUnformatted("Movement");
ImGui.NextColumn();
ImGui.Text($"{GetMouseMovement()}");
ImGui.NextColumn();
ImGui.TextUnformatted("RawMovement");
ImGui.NextColumn();
ImGui.Text($"{GetRawMouseMovement()}");
ImGui.NextColumn();
ImGui.Columns(1);
}
ImGui.End();
}
}
public static class Mouse
{
private static append List<(Int2 Position, int Hash)> _lockPositions = .();
public static void LockCurrentPosition(int hash)
{
LockPosition(Input.GetMousePosition(), hash);
}
public static void LockPosition(Int2 pos, int hash)
{
for (var entry in _lockPositions)
{
if (entry.Hash == hash)
{
entry.Position = pos;
break;
}
}
_lockPositions.Add((pos, hash));
}
public static void UnlockPosition(int hash)
{
for (var entry in _lockPositions)
{
if (entry.Hash == hash)
{
@entry.Remove();
break;
}
}
//Log.EngineLogger.AssertDebug(false, "No mouse lock position with hash found.");
}
public static Int2? LockedPosition;
public static void NewFrame()
{
if (_lockPositions.Count > 0)
{
var position = _lockPositions.Back.Position;
LockedPosition = position;
Input.SetMousePosition(position);
}
else
{
LockedPosition = null;
}
}
public static extern void NewFrame();
}
}
-236
View File
@@ -1,236 +0,0 @@
using Bon;
using System;
namespace GlitchyEngine.Math
{
/// Represents a four component color with 8 bit per channel
[CRepr]
[BonTarget]
public struct Color
{
// from DirectXColors.h
// Todo: We probably loose some precision here... Could init them with the correct value
public const Color AliceBlue = .( 0.941176534f, 0.972549081f, 1.000000000f, 1.000000000f );
public const Color AntiqueWhite = .( 0.980392218f, 0.921568692f, 0.843137324f, 1.000000000f );
public const Color Aqua = .( 0.000000000f, 1.000000000f, 1.000000000f, 1.000000000f );
public const Color Aquamarine = .( 0.498039246f, 1.000000000f, 0.831372619f, 1.000000000f );
public const Color Azure = .( 0.941176534f, 1.000000000f, 1.000000000f, 1.000000000f );
public const Color Beige = .( 0.960784376f, 0.960784376f, 0.862745166f, 1.000000000f );
public const Color Bisque = .( 1.000000000f, 0.894117713f, 0.768627524f, 1.000000000f );
public const Color Black = .( 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f );
public const Color BlanchedAlmond = .( 1.000000000f, 0.921568692f, 0.803921640f, 1.000000000f );
public const Color Blue = .( 0.000000000f, 0.000000000f, 1.000000000f, 1.000000000f );
public const Color BlueViolet = .( 0.541176498f, 0.168627456f, 0.886274576f, 1.000000000f );
public const Color Brown = .( 0.647058845f, 0.164705887f, 0.164705887f, 1.000000000f );
public const Color BurlyWood = .( 0.870588303f, 0.721568644f, 0.529411793f, 1.000000000f );
public const Color CadetBlue = .( 0.372549027f, 0.619607866f, 0.627451003f, 1.000000000f );
public const Color Chartreuse = .( 0.498039246f, 1.000000000f, 0.000000000f, 1.000000000f );
public const Color Chocolate = .( 0.823529482f, 0.411764741f, 0.117647067f, 1.000000000f );
public const Color Coral = .( 1.000000000f, 0.498039246f, 0.313725501f, 1.000000000f );
public const Color CornflowerBlue = .( 0.392156899f, 0.584313750f, 0.929411829f, 1.000000000f );
public const Color Cornsilk = .( 1.000000000f, 0.972549081f, 0.862745166f, 1.000000000f );
public const Color Crimson = .( 0.862745166f, 0.078431375f, 0.235294133f, 1.000000000f );
public const Color Cyan = .( 0.000000000f, 1.000000000f, 1.000000000f, 1.000000000f );
public const Color DarkBlue = .( 0.000000000f, 0.000000000f, 0.545098066f, 1.000000000f );
public const Color DarkCyan = .( 0.000000000f, 0.545098066f, 0.545098066f, 1.000000000f );
public const Color DarkGoldenrod = .( 0.721568644f, 0.525490224f, 0.043137256f, 1.000000000f );
public const Color DarkGray = .( 0.662745118f, 0.662745118f, 0.662745118f, 1.000000000f );
public const Color DarkGreen = .( 0.000000000f, 0.392156899f, 0.000000000f, 1.000000000f );
public const Color DarkKhaki = .( 0.741176486f, 0.717647076f, 0.419607878f, 1.000000000f );
public const Color DarkMagenta = .( 0.545098066f, 0.000000000f, 0.545098066f, 1.000000000f );
public const Color DarkOliveGreen = .( 0.333333343f, 0.419607878f, 0.184313729f, 1.000000000f );
public const Color DarkOrange = .( 1.000000000f, 0.549019635f, 0.000000000f, 1.000000000f );
public const Color DarkOrchid = .( 0.600000024f, 0.196078449f, 0.800000072f, 1.000000000f );
public const Color DarkRed = .( 0.545098066f, 0.000000000f, 0.000000000f, 1.000000000f );
public const Color DarkSalmon = .( 0.913725555f, 0.588235319f, 0.478431404f, 1.000000000f );
public const Color DarkSeaGreen = .( 0.560784340f, 0.737254918f, 0.545098066f, 1.000000000f );
public const Color DarkSlateBlue = .( 0.282352954f, 0.239215702f, 0.545098066f, 1.000000000f );
public const Color DarkSlateGray = .( 0.184313729f, 0.309803933f, 0.309803933f, 1.000000000f );
public const Color DarkTurquoise = .( 0.000000000f, 0.807843208f, 0.819607913f, 1.000000000f );
public const Color DarkViolet = .( 0.580392182f, 0.000000000f, 0.827451050f, 1.000000000f );
public const Color DeepPink = .( 1.000000000f, 0.078431375f, 0.576470613f, 1.000000000f );
public const Color DeepSkyBlue = .( 0.000000000f, 0.749019623f, 1.000000000f, 1.000000000f );
public const Color DimGray = .( 0.411764741f, 0.411764741f, 0.411764741f, 1.000000000f );
public const Color DodgerBlue = .( 0.117647067f, 0.564705908f, 1.000000000f, 1.000000000f );
public const Color Firebrick = .( 0.698039234f, 0.133333340f, 0.133333340f, 1.000000000f );
public const Color FloralWhite = .( 1.000000000f, 0.980392218f, 0.941176534f, 1.000000000f );
public const Color ForestGreen = .( 0.133333340f, 0.545098066f, 0.133333340f, 1.000000000f );
public const Color Fuchsia = .( 1.000000000f, 0.000000000f, 1.000000000f, 1.000000000f );
public const Color Gainsboro = .( 0.862745166f, 0.862745166f, 0.862745166f, 1.000000000f );
public const Color GhostWhite = .( 0.972549081f, 0.972549081f, 1.000000000f, 1.000000000f );
public const Color Gold = .( 1.000000000f, 0.843137324f, 0.000000000f, 1.000000000f );
public const Color Goldenrod = .( 0.854902029f, 0.647058845f, 0.125490203f, 1.000000000f );
public const Color Gray = .( 0.501960814f, 0.501960814f, 0.501960814f, 1.000000000f );
public const Color Green = .( 0.000000000f, 0.501960814f, 0.000000000f, 1.000000000f );
public const Color GreenYellow = .( 0.678431392f, 1.000000000f, 0.184313729f, 1.000000000f );
public const Color Honeydew = .( 0.941176534f, 1.000000000f, 0.941176534f, 1.000000000f );
public const Color HotPink = .( 1.000000000f, 0.411764741f, 0.705882370f, 1.000000000f );
public const Color IndianRed = .( 0.803921640f, 0.360784322f, 0.360784322f, 1.000000000f );
public const Color Indigo = .( 0.294117659f, 0.000000000f, 0.509803951f, 1.000000000f );
public const Color Ivory = .( 1.000000000f, 1.000000000f, 0.941176534f, 1.000000000f );
public const Color Khaki = .( 0.941176534f, 0.901960850f, 0.549019635f, 1.000000000f );
public const Color Lavender = .( 0.901960850f, 0.901960850f, 0.980392218f, 1.000000000f );
public const Color LavenderBlush = .( 1.000000000f, 0.941176534f, 0.960784376f, 1.000000000f );
public const Color LawnGreen = .( 0.486274540f, 0.988235354f, 0.000000000f, 1.000000000f );
public const Color LemonChiffon = .( 1.000000000f, 0.980392218f, 0.803921640f, 1.000000000f );
public const Color LightBlue = .( 0.678431392f, 0.847058892f, 0.901960850f, 1.000000000f );
public const Color LightCoral = .( 0.941176534f, 0.501960814f, 0.501960814f, 1.000000000f );
public const Color LightCyan = .( 0.878431439f, 1.000000000f, 1.000000000f, 1.000000000f );
public const Color LightGoldenrodYellow = .( 0.980392218f, 0.980392218f, 0.823529482f, 1.000000000f );
public const Color LightGreen = .( 0.564705908f, 0.933333397f, 0.564705908f, 1.000000000f );
public const Color LightGray = .( 0.827451050f, 0.827451050f, 0.827451050f, 1.000000000f );
public const Color LightPink = .( 1.000000000f, 0.713725507f, 0.756862819f, 1.000000000f );
public const Color LightSalmon = .( 1.000000000f, 0.627451003f, 0.478431404f, 1.000000000f );
public const Color LightSeaGreen = .( 0.125490203f, 0.698039234f, 0.666666687f, 1.000000000f );
public const Color LightSkyBlue = .( 0.529411793f, 0.807843208f, 0.980392218f, 1.000000000f );
public const Color LightSlateGray = .( 0.466666698f, 0.533333361f, 0.600000024f, 1.000000000f );
public const Color LightSteelBlue = .( 0.690196097f, 0.768627524f, 0.870588303f, 1.000000000f );
public const Color LightYellow = .( 1.000000000f, 1.000000000f, 0.878431439f, 1.000000000f );
public const Color Lime = .( 0.000000000f, 1.000000000f, 0.000000000f, 1.000000000f );
public const Color LimeGreen = .( 0.196078449f, 0.803921640f, 0.196078449f, 1.000000000f );
public const Color Linen = .( 0.980392218f, 0.941176534f, 0.901960850f, 1.000000000f );
public const Color Magenta = .( 1.000000000f, 0.000000000f, 1.000000000f, 1.000000000f );
public const Color Maroon = .( 0.501960814f, 0.000000000f, 0.000000000f, 1.000000000f );
public const Color MediumAquamarine = .( 0.400000036f, 0.803921640f, 0.666666687f, 1.000000000f );
public const Color MediumBlue = .( 0.000000000f, 0.000000000f, 0.803921640f, 1.000000000f );
public const Color MediumOrchid = .( 0.729411781f, 0.333333343f, 0.827451050f, 1.000000000f );
public const Color MediumPurple = .( 0.576470613f, 0.439215720f, 0.858823597f, 1.000000000f );
public const Color MediumSeaGreen = .( 0.235294133f, 0.701960802f, 0.443137288f, 1.000000000f );
public const Color MediumSlateBlue = .( 0.482352972f, 0.407843173f, 0.933333397f, 1.000000000f );
public const Color MediumSpringGreen = .( 0.000000000f, 0.980392218f, 0.603921592f, 1.000000000f );
public const Color MediumTurquoise = .( 0.282352954f, 0.819607913f, 0.800000072f, 1.000000000f );
public const Color MediumVioletRed = .( 0.780392230f, 0.082352944f, 0.521568656f, 1.000000000f );
public const Color MidnightBlue = .( 0.098039225f, 0.098039225f, 0.439215720f, 1.000000000f );
public const Color MintCream = .( 0.960784376f, 1.000000000f, 0.980392218f, 1.000000000f );
public const Color MistyRose = .( 1.000000000f, 0.894117713f, 0.882353008f, 1.000000000f );
public const Color Moccasin = .( 1.000000000f, 0.894117713f, 0.709803939f, 1.000000000f );
public const Color NavajoWhite = .( 1.000000000f, 0.870588303f, 0.678431392f, 1.000000000f );
public const Color Navy = .( 0.000000000f, 0.000000000f, 0.501960814f, 1.000000000f );
public const Color OldLace = .( 0.992156923f, 0.960784376f, 0.901960850f, 1.000000000f );
public const Color Olive = .( 0.501960814f, 0.501960814f, 0.000000000f, 1.000000000f );
public const Color OliveDrab = .( 0.419607878f, 0.556862772f, 0.137254909f, 1.000000000f );
public const Color Orange = .( 1.000000000f, 0.647058845f, 0.000000000f, 1.000000000f );
public const Color OrangeRed = .( 1.000000000f, 0.270588249f, 0.000000000f, 1.000000000f );
public const Color Orchid = .( 0.854902029f, 0.439215720f, 0.839215755f, 1.000000000f );
public const Color PaleGoldenrod = .( 0.933333397f, 0.909803987f, 0.666666687f, 1.000000000f );
public const Color PaleGreen = .( 0.596078455f, 0.984313786f, 0.596078455f, 1.000000000f );
public const Color PaleTurquoise = .( 0.686274529f, 0.933333397f, 0.933333397f, 1.000000000f );
public const Color PaleVioletRed = .( 0.858823597f, 0.439215720f, 0.576470613f, 1.000000000f );
public const Color PapayaWhip = .( 1.000000000f, 0.937254965f, 0.835294187f, 1.000000000f );
public const Color PeachPuff = .( 1.000000000f, 0.854902029f, 0.725490212f, 1.000000000f );
public const Color Peru = .( 0.803921640f, 0.521568656f, 0.247058839f, 1.000000000f );
public const Color Pink = .( 1.000000000f, 0.752941251f, 0.796078503f, 1.000000000f );
public const Color Plum = .( 0.866666734f, 0.627451003f, 0.866666734f, 1.000000000f );
public const Color PowderBlue = .( 0.690196097f, 0.878431439f, 0.901960850f, 1.000000000f );
public const Color Purple = .( 0.501960814f, 0.000000000f, 0.501960814f, 1.000000000f );
public const Color Red = .( 1.000000000f, 0.000000000f, 0.000000000f, 1.000000000f );
public const Color RosyBrown = .( 0.737254918f, 0.560784340f, 0.560784340f, 1.000000000f );
public const Color RoyalBlue = .( 0.254901975f, 0.411764741f, 0.882353008f, 1.000000000f );
public const Color SaddleBrown = .( 0.545098066f, 0.270588249f, 0.074509807f, 1.000000000f );
public const Color Salmon = .( 0.980392218f, 0.501960814f, 0.447058856f, 1.000000000f );
public const Color SandyBrown = .( 0.956862807f, 0.643137276f, 0.376470625f, 1.000000000f );
public const Color SeaGreen = .( 0.180392161f, 0.545098066f, 0.341176480f, 1.000000000f );
public const Color SeaShell = .( 1.000000000f, 0.960784376f, 0.933333397f, 1.000000000f );
public const Color Sienna = .( 0.627451003f, 0.321568638f, 0.176470593f, 1.000000000f );
public const Color Silver = .( 0.752941251f, 0.752941251f, 0.752941251f, 1.000000000f );
public const Color SkyBlue = .( 0.529411793f, 0.807843208f, 0.921568692f, 1.000000000f );
public const Color SlateBlue = .( 0.415686309f, 0.352941185f, 0.803921640f, 1.000000000f );
public const Color SlateGray = .( 0.439215720f, 0.501960814f, 0.564705908f, 1.000000000f );
public const Color Snow = .( 1.000000000f, 0.980392218f, 0.980392218f, 1.000000000f );
public const Color SpringGreen = .( 0.000000000f, 1.000000000f, 0.498039246f, 1.000000000f );
public const Color SteelBlue = .( 0.274509817f, 0.509803951f, 0.705882370f, 1.000000000f );
public const Color Tan = .( 0.823529482f, 0.705882370f, 0.549019635f, 1.000000000f );
public const Color Teal = .( 0.000000000f, 0.501960814f, 0.501960814f, 1.000000000f );
public const Color Thistle = .( 0.847058892f, 0.749019623f, 0.847058892f, 1.000000000f );
public const Color Tomato = .( 1.000000000f, 0.388235331f, 0.278431386f, 1.000000000f );
public const Color Transparent = .( 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f );
public const Color Turquoise = .( 0.250980407f, 0.878431439f, 0.815686345f, 1.000000000f );
public const Color Violet = .( 0.933333397f, 0.509803951f, 0.933333397f, 1.000000000f );
public const Color Wheat = .( 0.960784376f, 0.870588303f, 0.701960802f, 1.000000000f );
public const Color White = .( 1.000000000f, 1.000000000f, 1.000000000f, 1.000000000f );
public const Color WhiteSmoke = .( 0.960784376f, 0.960784376f, 0.960784376f, 1.000000000f );
public const Color Yellow = .( 1.000000000f, 1.000000000f, 0.000000000f, 1.000000000f );
public const Color YellowGreen = .( 0.603921592f, 0.803921640f, 0.196078449f, 1.000000000f );
/// The red-component of the color
public uint8 R;
/// The green-component of the color
public uint8 G;
/// The blue-component of the color
public uint8 B;
/// The alpha-component of the color
public uint8 A;
/// Creates a new instance of Color with all components set to 0.
public this()
{
this = default;
}
/// Creates a new instance of Color with the RGB-values set to the specified values and alpha set to 255.
public this(uint8 r, uint8 g, uint8 b)
{
R = r;
G = g;
B = b;
A = 255;
}
/// Creates a new instance of Color with the RGB-values set to the specified values and alpha set to 255.
public this(float r, float g, float b) : this(r, g, b, 1.0f) { }
/// Creates a new instance of Color with the specified values.
public this(uint8 r, uint8 g, uint8 b, uint8 a)
{
R = r;
G = g;
B = b;
A = a;
}
const float f = Math.Clamp(12.0f, uint8.MinValue, uint8.MaxValue);
/// Creates a new instance of Color with the specified values.
public this(float r, float g, float b, float a)
{
R = (uint8)(int)Math.Clamp(r * 255.0f, uint8.MinValue, uint8.MaxValue);
G = (uint8)(int)Math.Clamp(g * 255.0f, uint8.MinValue, uint8.MaxValue);
B = (uint8)(int)Math.Clamp(b * 255.0f, uint8.MinValue, uint8.MaxValue);
A = (uint8)(int)Math.Clamp(a * 255.0f, uint8.MinValue, uint8.MaxValue);
}
public ref uint8 this[int index]
{
[Unchecked]
get mut
{
return ref (&R)[index];
}
[Checked]
get mut
{
Runtime.Assert(index < 0 || index > 3);
return ref (&R)[index];
}
}
[Inline]
public uint8* ToPtr() mut
{
return &R;
}
// Todo: mathematical operations
public static explicit operator Color(ColorRGBA col)
{
return .(col.R, col.G, col.B, col.A);
}
public static explicit operator ColorRGBA(Color col)
{
return .(col.R / 255.0f, col.G / 255.0f, col.B / 255.0f, col.A / 255.0f);
}
}
}
-62
View File
@@ -1,62 +0,0 @@
using Bon;
using System;
using internal GlitchyEngine.Math;
namespace GlitchyEngine.Math
{
/// Represents an RGB color.
[CRepr]
[BonTarget]
public struct ColorRGB
{
/**
* A value representing the color of the red component.
* The range of this value is between 0 and 1.
*/
public float R;
/**
* A value representing the color of the green component.
* The range of this value is between 0 and 1.
*/
public float G;
/**
* A value representing the color of the blue component.
* The range of this value is between 0 and 1.
*/
public float B;
public this()
{
this = default;
}
public this(float red, float green, float blue)
{
R = red;
G = green;
B = blue;
}
public this(ColorRGBA color)
{
R = color.R;
G = color.G;
B = color.B;
}
// Converts a Color from sRGB color space to Linear color space.
public static ColorRGB SRgbToLinear(ColorRGB sRGB) => ColorRGB(Math.Pow(sRGB.R, srgbToLin), Math.Pow(sRGB.G, srgbToLin), Math.Pow(sRGB.B, srgbToLin));
// Converts a Color from linear color space to sRGB color space.
public static ColorRGB LinearToSRGB(ColorRGB linear) => ColorRGB(Math.Pow(linear.R, linToSRGB), Math.Pow(linear.G, linToSRGB), Math.Pow(linear.B, linToSRGB));
[Inline]
#unwarn
public static explicit operator Vector3(ColorRGB color) => *(Vector3*)&color;
[Inline]
#unwarn
public static explicit operator ColorRGB(Vector3 color) => *(ColorRGB*)&color;
}
}
-338
View File
@@ -1,338 +0,0 @@
using System;
using Bon;
using internal GlitchyEngine.Math;
namespace GlitchyEngine.Math
{
static
{
internal const float srgbToLin = 2.2f;
internal const float linToSRGB = (float)(1.0 / 2.2);
}
/**
Represents a four component floating point color
*/
[BonTarget]
[CRepr]
struct ColorRGBA
{
// from DirectXColors.h
public const ColorRGBA AliceBlue = .( 0.941176534f, 0.972549081f, 1.000000000f, 1.000000000f );
public const ColorRGBA AntiqueWhite = .( 0.980392218f, 0.921568692f, 0.843137324f, 1.000000000f );
public const ColorRGBA Aqua = .( 0.000000000f, 1.000000000f, 1.000000000f, 1.000000000f );
public const ColorRGBA Aquamarine = .( 0.498039246f, 1.000000000f, 0.831372619f, 1.000000000f );
public const ColorRGBA Azure = .( 0.941176534f, 1.000000000f, 1.000000000f, 1.000000000f );
public const ColorRGBA Beige = .( 0.960784376f, 0.960784376f, 0.862745166f, 1.000000000f );
public const ColorRGBA Bisque = .( 1.000000000f, 0.894117713f, 0.768627524f, 1.000000000f );
public const ColorRGBA Black = .( 0.000000000f, 0.000000000f, 0.000000000f, 1.000000000f );
public const ColorRGBA BlanchedAlmond = .( 1.000000000f, 0.921568692f, 0.803921640f, 1.000000000f );
public const ColorRGBA Blue = .( 0.000000000f, 0.000000000f, 1.000000000f, 1.000000000f );
public const ColorRGBA BlueViolet = .( 0.541176498f, 0.168627456f, 0.886274576f, 1.000000000f );
public const ColorRGBA Brown = .( 0.647058845f, 0.164705887f, 0.164705887f, 1.000000000f );
public const ColorRGBA BurlyWood = .( 0.870588303f, 0.721568644f, 0.529411793f, 1.000000000f );
public const ColorRGBA CadetBlue = .( 0.372549027f, 0.619607866f, 0.627451003f, 1.000000000f );
public const ColorRGBA Chartreuse = .( 0.498039246f, 1.000000000f, 0.000000000f, 1.000000000f );
public const ColorRGBA Chocolate = .( 0.823529482f, 0.411764741f, 0.117647067f, 1.000000000f );
public const ColorRGBA Coral = .( 1.000000000f, 0.498039246f, 0.313725501f, 1.000000000f );
public const ColorRGBA CornflowerBlue = .( 0.392156899f, 0.584313750f, 0.929411829f, 1.000000000f );
public const ColorRGBA Cornsilk = .( 1.000000000f, 0.972549081f, 0.862745166f, 1.000000000f );
public const ColorRGBA Crimson = .( 0.862745166f, 0.078431375f, 0.235294133f, 1.000000000f );
public const ColorRGBA Cyan = .( 0.000000000f, 1.000000000f, 1.000000000f, 1.000000000f );
public const ColorRGBA DarkBlue = .( 0.000000000f, 0.000000000f, 0.545098066f, 1.000000000f );
public const ColorRGBA DarkCyan = .( 0.000000000f, 0.545098066f, 0.545098066f, 1.000000000f );
public const ColorRGBA DarkGoldenrod = .( 0.721568644f, 0.525490224f, 0.043137256f, 1.000000000f );
public const ColorRGBA DarkGray = .( 0.662745118f, 0.662745118f, 0.662745118f, 1.000000000f );
public const ColorRGBA DarkGreen = .( 0.000000000f, 0.392156899f, 0.000000000f, 1.000000000f );
public const ColorRGBA DarkKhaki = .( 0.741176486f, 0.717647076f, 0.419607878f, 1.000000000f );
public const ColorRGBA DarkMagenta = .( 0.545098066f, 0.000000000f, 0.545098066f, 1.000000000f );
public const ColorRGBA DarkOliveGreen = .( 0.333333343f, 0.419607878f, 0.184313729f, 1.000000000f );
public const ColorRGBA DarkOrange = .( 1.000000000f, 0.549019635f, 0.000000000f, 1.000000000f );
public const ColorRGBA DarkOrchid = .( 0.600000024f, 0.196078449f, 0.800000072f, 1.000000000f );
public const ColorRGBA DarkRed = .( 0.545098066f, 0.000000000f, 0.000000000f, 1.000000000f );
public const ColorRGBA DarkSalmon = .( 0.913725555f, 0.588235319f, 0.478431404f, 1.000000000f );
public const ColorRGBA DarkSeaGreen = .( 0.560784340f, 0.737254918f, 0.545098066f, 1.000000000f );
public const ColorRGBA DarkSlateBlue = .( 0.282352954f, 0.239215702f, 0.545098066f, 1.000000000f );
public const ColorRGBA DarkSlateGray = .( 0.184313729f, 0.309803933f, 0.309803933f, 1.000000000f );
public const ColorRGBA DarkTurquoise = .( 0.000000000f, 0.807843208f, 0.819607913f, 1.000000000f );
public const ColorRGBA DarkViolet = .( 0.580392182f, 0.000000000f, 0.827451050f, 1.000000000f );
public const ColorRGBA DeepPink = .( 1.000000000f, 0.078431375f, 0.576470613f, 1.000000000f );
public const ColorRGBA DeepSkyBlue = .( 0.000000000f, 0.749019623f, 1.000000000f, 1.000000000f );
public const ColorRGBA DimGray = .( 0.411764741f, 0.411764741f, 0.411764741f, 1.000000000f );
public const ColorRGBA DodgerBlue = .( 0.117647067f, 0.564705908f, 1.000000000f, 1.000000000f );
public const ColorRGBA Firebrick = .( 0.698039234f, 0.133333340f, 0.133333340f, 1.000000000f );
public const ColorRGBA FloralWhite = .( 1.000000000f, 0.980392218f, 0.941176534f, 1.000000000f );
public const ColorRGBA ForestGreen = .( 0.133333340f, 0.545098066f, 0.133333340f, 1.000000000f );
public const ColorRGBA Fuchsia = .( 1.000000000f, 0.000000000f, 1.000000000f, 1.000000000f );
public const ColorRGBA Gainsboro = .( 0.862745166f, 0.862745166f, 0.862745166f, 1.000000000f );
public const ColorRGBA GhostWhite = .( 0.972549081f, 0.972549081f, 1.000000000f, 1.000000000f );
public const ColorRGBA Gold = .( 1.000000000f, 0.843137324f, 0.000000000f, 1.000000000f );
public const ColorRGBA Goldenrod = .( 0.854902029f, 0.647058845f, 0.125490203f, 1.000000000f );
public const ColorRGBA Gray = .( 0.501960814f, 0.501960814f, 0.501960814f, 1.000000000f );
public const ColorRGBA Green = .( 0.000000000f, 0.501960814f, 0.000000000f, 1.000000000f );
public const ColorRGBA GreenYellow = .( 0.678431392f, 1.000000000f, 0.184313729f, 1.000000000f );
public const ColorRGBA Honeydew = .( 0.941176534f, 1.000000000f, 0.941176534f, 1.000000000f );
public const ColorRGBA HotPink = .( 1.000000000f, 0.411764741f, 0.705882370f, 1.000000000f );
public const ColorRGBA IndianRed = .( 0.803921640f, 0.360784322f, 0.360784322f, 1.000000000f );
public const ColorRGBA Indigo = .( 0.294117659f, 0.000000000f, 0.509803951f, 1.000000000f );
public const ColorRGBA Ivory = .( 1.000000000f, 1.000000000f, 0.941176534f, 1.000000000f );
public const ColorRGBA Khaki = .( 0.941176534f, 0.901960850f, 0.549019635f, 1.000000000f );
public const ColorRGBA Lavender = .( 0.901960850f, 0.901960850f, 0.980392218f, 1.000000000f );
public const ColorRGBA LavenderBlush = .( 1.000000000f, 0.941176534f, 0.960784376f, 1.000000000f );
public const ColorRGBA LawnGreen = .( 0.486274540f, 0.988235354f, 0.000000000f, 1.000000000f );
public const ColorRGBA LemonChiffon = .( 1.000000000f, 0.980392218f, 0.803921640f, 1.000000000f );
public const ColorRGBA LightBlue = .( 0.678431392f, 0.847058892f, 0.901960850f, 1.000000000f );
public const ColorRGBA LightCoral = .( 0.941176534f, 0.501960814f, 0.501960814f, 1.000000000f );
public const ColorRGBA LightCyan = .( 0.878431439f, 1.000000000f, 1.000000000f, 1.000000000f );
public const ColorRGBA LightGoldenrodYellow = .( 0.980392218f, 0.980392218f, 0.823529482f, 1.000000000f );
public const ColorRGBA LightGreen = .( 0.564705908f, 0.933333397f, 0.564705908f, 1.000000000f );
public const ColorRGBA LightGray = .( 0.827451050f, 0.827451050f, 0.827451050f, 1.000000000f );
public const ColorRGBA LightPink = .( 1.000000000f, 0.713725507f, 0.756862819f, 1.000000000f );
public const ColorRGBA LightSalmon = .( 1.000000000f, 0.627451003f, 0.478431404f, 1.000000000f );
public const ColorRGBA LightSeaGreen = .( 0.125490203f, 0.698039234f, 0.666666687f, 1.000000000f );
public const ColorRGBA LightSkyBlue = .( 0.529411793f, 0.807843208f, 0.980392218f, 1.000000000f );
public const ColorRGBA LightSlateGray = .( 0.466666698f, 0.533333361f, 0.600000024f, 1.000000000f );
public const ColorRGBA LightSteelBlue = .( 0.690196097f, 0.768627524f, 0.870588303f, 1.000000000f );
public const ColorRGBA LightYellow = .( 1.000000000f, 1.000000000f, 0.878431439f, 1.000000000f );
public const ColorRGBA Lime = .( 0.000000000f, 1.000000000f, 0.000000000f, 1.000000000f );
public const ColorRGBA LimeGreen = .( 0.196078449f, 0.803921640f, 0.196078449f, 1.000000000f );
public const ColorRGBA Linen = .( 0.980392218f, 0.941176534f, 0.901960850f, 1.000000000f );
public const ColorRGBA Magenta = .( 1.000000000f, 0.000000000f, 1.000000000f, 1.000000000f );
public const ColorRGBA Maroon = .( 0.501960814f, 0.000000000f, 0.000000000f, 1.000000000f );
public const ColorRGBA MediumAquamarine = .( 0.400000036f, 0.803921640f, 0.666666687f, 1.000000000f );
public const ColorRGBA MediumBlue = .( 0.000000000f, 0.000000000f, 0.803921640f, 1.000000000f );
public const ColorRGBA MediumOrchid = .( 0.729411781f, 0.333333343f, 0.827451050f, 1.000000000f );
public const ColorRGBA MediumPurple = .( 0.576470613f, 0.439215720f, 0.858823597f, 1.000000000f );
public const ColorRGBA MediumSeaGreen = .( 0.235294133f, 0.701960802f, 0.443137288f, 1.000000000f );
public const ColorRGBA MediumSlateBlue = .( 0.482352972f, 0.407843173f, 0.933333397f, 1.000000000f );
public const ColorRGBA MediumSpringGreen = .( 0.000000000f, 0.980392218f, 0.603921592f, 1.000000000f );
public const ColorRGBA MediumTurquoise = .( 0.282352954f, 0.819607913f, 0.800000072f, 1.000000000f );
public const ColorRGBA MediumVioletRed = .( 0.780392230f, 0.082352944f, 0.521568656f, 1.000000000f );
public const ColorRGBA MidnightBlue = .( 0.098039225f, 0.098039225f, 0.439215720f, 1.000000000f );
public const ColorRGBA MintCream = .( 0.960784376f, 1.000000000f, 0.980392218f, 1.000000000f );
public const ColorRGBA MistyRose = .( 1.000000000f, 0.894117713f, 0.882353008f, 1.000000000f );
public const ColorRGBA Moccasin = .( 1.000000000f, 0.894117713f, 0.709803939f, 1.000000000f );
public const ColorRGBA NavajoWhite = .( 1.000000000f, 0.870588303f, 0.678431392f, 1.000000000f );
public const ColorRGBA Navy = .( 0.000000000f, 0.000000000f, 0.501960814f, 1.000000000f );
public const ColorRGBA OldLace = .( 0.992156923f, 0.960784376f, 0.901960850f, 1.000000000f );
public const ColorRGBA Olive = .( 0.501960814f, 0.501960814f, 0.000000000f, 1.000000000f );
public const ColorRGBA OliveDrab = .( 0.419607878f, 0.556862772f, 0.137254909f, 1.000000000f );
public const ColorRGBA Orange = .( 1.000000000f, 0.647058845f, 0.000000000f, 1.000000000f );
public const ColorRGBA OrangeRed = .( 1.000000000f, 0.270588249f, 0.000000000f, 1.000000000f );
public const ColorRGBA Orchid = .( 0.854902029f, 0.439215720f, 0.839215755f, 1.000000000f );
public const ColorRGBA PaleGoldenrod = .( 0.933333397f, 0.909803987f, 0.666666687f, 1.000000000f );
public const ColorRGBA PaleGreen = .( 0.596078455f, 0.984313786f, 0.596078455f, 1.000000000f );
public const ColorRGBA PaleTurquoise = .( 0.686274529f, 0.933333397f, 0.933333397f, 1.000000000f );
public const ColorRGBA PaleVioletRed = .( 0.858823597f, 0.439215720f, 0.576470613f, 1.000000000f );
public const ColorRGBA PapayaWhip = .( 1.000000000f, 0.937254965f, 0.835294187f, 1.000000000f );
public const ColorRGBA PeachPuff = .( 1.000000000f, 0.854902029f, 0.725490212f, 1.000000000f );
public const ColorRGBA Peru = .( 0.803921640f, 0.521568656f, 0.247058839f, 1.000000000f );
public const ColorRGBA Pink = .( 1.000000000f, 0.752941251f, 0.796078503f, 1.000000000f );
public const ColorRGBA Plum = .( 0.866666734f, 0.627451003f, 0.866666734f, 1.000000000f );
public const ColorRGBA PowderBlue = .( 0.690196097f, 0.878431439f, 0.901960850f, 1.000000000f );
public const ColorRGBA Purple = .( 0.501960814f, 0.000000000f, 0.501960814f, 1.000000000f );
public const ColorRGBA Red = .( 1.000000000f, 0.000000000f, 0.000000000f, 1.000000000f );
public const ColorRGBA RosyBrown = .( 0.737254918f, 0.560784340f, 0.560784340f, 1.000000000f );
public const ColorRGBA RoyalBlue = .( 0.254901975f, 0.411764741f, 0.882353008f, 1.000000000f );
public const ColorRGBA SaddleBrown = .( 0.545098066f, 0.270588249f, 0.074509807f, 1.000000000f );
public const ColorRGBA Salmon = .( 0.980392218f, 0.501960814f, 0.447058856f, 1.000000000f );
public const ColorRGBA SandyBrown = .( 0.956862807f, 0.643137276f, 0.376470625f, 1.000000000f );
public const ColorRGBA SeaGreen = .( 0.180392161f, 0.545098066f, 0.341176480f, 1.000000000f );
public const ColorRGBA SeaShell = .( 1.000000000f, 0.960784376f, 0.933333397f, 1.000000000f );
public const ColorRGBA Sienna = .( 0.627451003f, 0.321568638f, 0.176470593f, 1.000000000f );
public const ColorRGBA Silver = .( 0.752941251f, 0.752941251f, 0.752941251f, 1.000000000f );
public const ColorRGBA SkyBlue = .( 0.529411793f, 0.807843208f, 0.921568692f, 1.000000000f );
public const ColorRGBA SlateBlue = .( 0.415686309f, 0.352941185f, 0.803921640f, 1.000000000f );
public const ColorRGBA SlateGray = .( 0.439215720f, 0.501960814f, 0.564705908f, 1.000000000f );
public const ColorRGBA Snow = .( 1.000000000f, 0.980392218f, 0.980392218f, 1.000000000f );
public const ColorRGBA SpringGreen = .( 0.000000000f, 1.000000000f, 0.498039246f, 1.000000000f );
public const ColorRGBA SteelBlue = .( 0.274509817f, 0.509803951f, 0.705882370f, 1.000000000f );
public const ColorRGBA Tan = .( 0.823529482f, 0.705882370f, 0.549019635f, 1.000000000f );
public const ColorRGBA Teal = .( 0.000000000f, 0.501960814f, 0.501960814f, 1.000000000f );
public const ColorRGBA Thistle = .( 0.847058892f, 0.749019623f, 0.847058892f, 1.000000000f );
public const ColorRGBA Tomato = .( 1.000000000f, 0.388235331f, 0.278431386f, 1.000000000f );
public const ColorRGBA Transparent = .( 0.000000000f, 0.000000000f, 0.000000000f, 0.000000000f );
public const ColorRGBA Turquoise = .( 0.250980407f, 0.878431439f, 0.815686345f, 1.000000000f );
public const ColorRGBA Violet = .( 0.933333397f, 0.509803951f, 0.933333397f, 1.000000000f );
public const ColorRGBA Wheat = .( 0.960784376f, 0.870588303f, 0.701960802f, 1.000000000f );
public const ColorRGBA White = .( 1.000000000f, 1.000000000f, 1.000000000f, 1.000000000f );
public const ColorRGBA WhiteSmoke = .( 0.960784376f, 0.960784376f, 0.960784376f, 1.000000000f );
public const ColorRGBA Yellow = .( 1.000000000f, 1.000000000f, 0.000000000f, 1.000000000f );
public const ColorRGBA YellowGreen = .( 0.603921592f, 0.803921640f, 0.196078449f, 1.000000000f );
/// The red-component of the color
public float R;
/// The green-component of the color
public float G;
/// The blue-component of the color
public float B;
/// The alpha-component of the color
public float A;
/// Creates a new instance of ColorRGBA with all components set to 0.
public this()
{
this = default;
}
/// Creates a new instance of ColorRGBA with the specified values.
public this(float r, float g, float b, float a = 1.0f)
{
R = r;
G = g;
B = b;
A = a;
}
/// Creates a new instance of ColorRGBA with the specified values.
public this(uint8 r, uint8 g, uint8 b, uint8 a = 255)
{
R = r / 255f;
G = g / 255f;
B = b / 255f;
A = a / 255f;
}
/// Creates a new instance of ColorRGBA with the specified values.
public this(ColorRGB color, float a = 1.0f)
{
R = color.R;
G = color.G;
B = color.B;
A = a;
}
public ref float this[int index]
{
[Unchecked]
get mut
{
return ref (&R)[index];
}
[Checked]
get mut
{
Runtime.Assert(index < 0 || index > 3);
return ref (&R)[index];
}
}
[Inline]
public float* ToPtr() mut
{
return &R;
}
///
/// Addition
///
public void operator +=(ColorRGBA value) mut
{
R += value.R;
G += value.G;
B += value.B;
A += value.A;
}
public static ColorRGBA operator +(ColorRGBA left, ColorRGBA right)
{
return .(left.R + right.R, left.G + right.G, left.B + right.B, left.A + right.A);
}
///
/// Subtraction
///
public void operator -=(ColorRGBA value) mut
{
R -= value.R;
G -= value.G;
B -= value.B;
A -= value.A;
}
public static ColorRGBA operator -(ColorRGBA left, ColorRGBA right)
{
return .(left.R - right.R, left.G - right.G, left.B - right.B, left.A - right.A);
}
///
/// Multiplication
///
public void operator *=(ColorRGBA value) mut
{
R *= value.R;
G *= value.G;
B *= value.B;
A *= value.A;
}
public void operator *=(float value) mut
{
R *= value;
G *= value;
B *= value;
A *= value;
}
public static ColorRGBA operator *(ColorRGBA left, ColorRGBA right)
{
return .(left.R * right.R, left.G * right.G, left.B * right.B, left.A * right.A);
}
public static ColorRGBA operator *(ColorRGBA left, float right)
{
return .(left.R * right, left.G * right, left.B * right, left.A * right);
}
public static ColorRGBA operator *(float left, ColorRGBA right)
{
return .(left * right.R, left * right.G, left * right.B, left * right.A);
}
///
/// Division
///
public void operator /=(float value) mut
{
R /= value;
G /= value;
B /= value;
A /= value;
}
public static ColorRGBA operator /(ColorRGBA left, float right)
{
return .(left.R / right, left.G / right, left.B / right, left.A / right);
}
public static ColorRGBA operator /(float left, ColorRGBA right)
{
return .(left / right.R, left / right.G, left / right.B, left / right.A);
}
public static implicit operator ColorRGB(ColorRGBA color)
{
return .(color.R, color.G, color.B);
}
// Converts a Color from sRGB color space to Linear color space.
public static ColorRGBA SRgbToLinear(ColorRGBA sRGB) => ColorRGBA(Math.Pow(sRGB.R, srgbToLin), Math.Pow(sRGB.G, srgbToLin), Math.Pow(sRGB.B, srgbToLin), sRGB.A);
// Converts a Color from linear color space to sRGB color space.
public static ColorRGBA LinearToSRGB(ColorRGBA linear) => ColorRGBA(Math.Pow(linear.R, linToSRGB), Math.Pow(linear.G, linToSRGB), Math.Pow(linear.B, linToSRGB), linear.A);
[Inline]
#unwarn
public static explicit operator Vector4(ColorRGBA color) => *(Vector4*)&color;
[Inline]
#unwarn
public static explicit operator ColorRGBA(Vector4 color) => *(ColorRGBA*)&color;
}
}
+4
View File
@@ -2,6 +2,10 @@ using System;
namespace GlitchyEngine.Math
{
typealias Color = DirectX.Color;
typealias ColorRGB = DirectX.ColorRGB;
typealias ColorRGBA = DirectX.ColorRGBA;
typealias Matrix3x3 = DirectX.Math.Matrix3x3;
typealias Matrix4x3 = DirectX.Math.Matrix4x3;
typealias Matrix = DirectX.Math.Matrix;

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