mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 13:01:52 +00:00
Compare commits
20
Commits
3d
...
asset_handle
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
81ae5f1135 | ||
|
|
b76d4cd558 | ||
|
|
5893cfb74a | ||
|
|
ed952155b6 | ||
|
|
d54cdf43ee | ||
|
|
f16fbc3984 | ||
|
|
184480243f | ||
|
|
fc1875ed96 | ||
|
|
5733166b74 | ||
|
|
2ba4b68e09 | ||
|
|
edcec02e94 | ||
|
|
c164aeecaa | ||
|
|
793aa40975 | ||
|
|
50714976e9 | ||
|
|
7b6662cbc4 | ||
|
|
cfa046d2ea | ||
|
|
b22f73a156 | ||
|
|
c3fb9bbd5d | ||
|
|
c22d122921 | ||
|
|
ad14c9f6ed |
@@ -1,5 +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"}}
|
||||
Unlocked = ["corlib"]
|
||||
WorkspaceFolders = {GlitchyEngine = ["GlitchyEngine", "GlitchLog", "GlitchyEngineHelper"], "GlitchyEngine/Dependencies" = ["cgltf-beef", "DirectX", "FreeType", "ImGui", "ImGuiImplDX11", "ImGuiImplWin32", "ImGuizmo", "LodePng", "msdfgen-beef", "bon", "box2d-beef", "Beef.Linq"]}
|
||||
|
||||
[Workspace]
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
///
|
||||
/// Loading and usage of an asset.
|
||||
///
|
||||
// Shows the usage of the Content Manager.
|
||||
// An asset is loaded with Content.LoadAsset(AssetName)
|
||||
// Loading an asset returns an AssetHandle.
|
||||
// Usually you want to hold on to the AssetHandle.
|
||||
// If you need the actual asset you can use Content.GetAsset<AssetType>(AssetHandle) to retrieve the actual asset.
|
||||
|
||||
/*
|
||||
* Only hold on to AssetHandle.
|
||||
* Do NOT hold actual Assets! The Asset might get invalidated
|
||||
* (e.g. reloading after the source-file changed).
|
||||
*/
|
||||
AssetHandle _lineEffect;
|
||||
|
||||
void Start()
|
||||
{
|
||||
/*
|
||||
* Loading an asset returns a handle to that asset.
|
||||
*/
|
||||
_lineEffect = Content.LoadAsset("Shaders\\LineEffect.hlsl");
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
// Use case 1:
|
||||
{
|
||||
// Retrieve the actual asset. Note that this Asset is only guaranteed to persist
|
||||
// for the current frame.
|
||||
Effect fx = Content.GetAsset<Effect>(_lineEffect);
|
||||
|
||||
// Note: Assets are ref counted, however since they are not inteded to be held GetAsset
|
||||
// does NOT increment the reference counter so you usually should NOT decrement it.
|
||||
// The exception is when you manually hold on to an asset (see Example below)
|
||||
|
||||
// Use asset
|
||||
fx.Variables["ViewProjection"].SetData(viewProjection * transform);
|
||||
fx.Variables["Color"].SetData(color);
|
||||
fx.ApplyChanges();
|
||||
fx.Bind();
|
||||
}
|
||||
|
||||
// Use case 2:
|
||||
{
|
||||
// Retrieve the actual asset.
|
||||
Effect fx = _lineEffect.Get<Effect>();
|
||||
|
||||
// ...
|
||||
// Same as case 1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///
|
||||
/// Holding on to an actual asset.
|
||||
///
|
||||
// Shows the usage of the Content Manager when you hold a reference to the actual Asset instead of the handle.
|
||||
// This should usually not be done. Eventhough it is technically fine, it has the implication, that if the
|
||||
// content manager decides to reload the asset the changes will not be reflected in the held reference
|
||||
// (which they would if you used GetAsset before every usage.)
|
||||
// Also the content manager can't unload the asset because the reference counter wouldn't be zero.
|
||||
// Though there currently is no way for the content manager to unload an asset unless it is specifically told to do so.
|
||||
|
||||
/*
|
||||
* Field to hold the asset.
|
||||
*/
|
||||
Effect _lineEffect;
|
||||
|
||||
void Start()
|
||||
{
|
||||
// Load the Asset.
|
||||
AssetHandle handle = Content.LoadAsset("Shaders\\LineEffect.hlsl");
|
||||
// Get the actual asset.
|
||||
_lineEffect = Content.GetAsset<Effect>(handle); // Alternative: _lineEffect = handle.Get<Effect>();
|
||||
// Increment the reference counter so that the asset doesn't get unloaded.
|
||||
_lineEffect.AddRef();
|
||||
}
|
||||
|
||||
void Destroy()
|
||||
{
|
||||
// Make sure to release the asset once you don't need it anymore. Otherwise it will leak.
|
||||
_lineEffect.Release();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
_lineEffect.Variables["ViewProjection"].SetData(viewProjection * transform);
|
||||
_lineEffect.Variables["Color"].SetData(color);
|
||||
_lineEffect.ApplyChanges();
|
||||
_lineEffect.Bind();
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
///
|
||||
/// This shows the usage of a smart/typed Asset Handle.
|
||||
///
|
||||
// In the basic usage-patterns the user has two options:
|
||||
// Either he/she holds a handle and has to query for the actual asset every time
|
||||
// or he/she hold the actual asset and loses reloading capabilities.
|
||||
// The idea of the auto asset is to provide a way that can provide both.
|
||||
|
||||
AssetHandle<Effect> _lineEffect;
|
||||
|
||||
void Start()
|
||||
{
|
||||
/*
|
||||
* Loading an asset returns a handle to that asset.
|
||||
* The asset handle is implicitly converted to a smart AssetHandle.
|
||||
*/
|
||||
_lineEffect = Content.LoadAsset("Shaders\\LineEffect.hlsl");
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
// Use case 1 (Convenience)
|
||||
{
|
||||
_lineEffect.Variables["ViewProjection"].SetData(viewProjection * transform);
|
||||
_lineEffect.Variables["Color"].SetData(color);
|
||||
_lineEffect.ApplyChanges();
|
||||
_lineEffect.Bind();
|
||||
}
|
||||
|
||||
// Use case 2 (Technically more efficient)
|
||||
{
|
||||
Effect fx = _lineEffect.Get();
|
||||
fx.Variables["ViewProjection"].SetData(viewProjection * transform);
|
||||
fx.Variables["Color"].SetData(color);
|
||||
fx.ApplyChanges();
|
||||
fx.Bind();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Auto Assets use comp time to expose all the fields, Methods and properties of the actual asset.
|
||||
// They will automatically check if the asset for the handle changed and update accordingly.
|
||||
// This means it is more convenient to use than both basic patterns and has all benefits of both.
|
||||
//
|
||||
@@ -0,0 +1,3 @@
|
||||
# Design Code Examples
|
||||
|
||||
This directory (and its subdirectories) contains non functional code snippets showing the intended usage of certain systems of the engine.
|
||||
@@ -30,10 +30,10 @@
|
||||
}
|
||||
},
|
||||
MeshComponent = {
|
||||
Mesh = "Models\\sphere.glb"
|
||||
Mesh = "Models/sphere.glb"
|
||||
},
|
||||
MeshRendererComponent = {
|
||||
Material = "Textures\\TestMaterial.mat"
|
||||
Material = "Textures/TestMaterial.mat"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -48,20 +48,20 @@
|
||||
Z = -4
|
||||
},
|
||||
Rotation = {
|
||||
X = 0.614328,
|
||||
Y = 0.239776,
|
||||
Z = 0.031567,
|
||||
W = 0.751074
|
||||
X = 0.614328027,
|
||||
Y = 0.239776045,
|
||||
Z = 0.0315669999,
|
||||
W = 0.751073837
|
||||
},
|
||||
Scale = {
|
||||
X = 0.999999,
|
||||
X = 0.999998868,
|
||||
Y = 1,
|
||||
Z = 1.000001
|
||||
Z = 1.00000095
|
||||
},
|
||||
EditorEulerRotation = {
|
||||
X = 1.308998,
|
||||
Y = 0.349066,
|
||||
Z = 0.349066
|
||||
X = 1.30899811,
|
||||
Y = 0.349065989,
|
||||
Z = 0.349065989
|
||||
}
|
||||
},
|
||||
LightComponent = {
|
||||
@@ -69,8 +69,8 @@
|
||||
Illuminance = 10,
|
||||
Color = {
|
||||
R = 1,
|
||||
G = 0.991772,
|
||||
B = 0.740862
|
||||
G = 0.991771996,
|
||||
B = 0.74086225
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -103,10 +103,10 @@
|
||||
}
|
||||
},
|
||||
MeshComponent = {
|
||||
Mesh = "Models\\plane.glb"
|
||||
Mesh = "Models/plane.glb"
|
||||
},
|
||||
MeshRendererComponent = {
|
||||
Material = "Textures\\TestMaterial.mat"
|
||||
Material = "Textures/TestMaterial.mat"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -121,10 +121,10 @@
|
||||
Z = -5
|
||||
},
|
||||
Rotation = {
|
||||
X = 0.21644,
|
||||
X = 0.216440007,
|
||||
Y = 0,
|
||||
Z = 0,
|
||||
W = 0.976296
|
||||
W = 0.976296008
|
||||
},
|
||||
Scale = {
|
||||
X = 1,
|
||||
@@ -132,7 +132,7 @@
|
||||
Z = 1
|
||||
},
|
||||
EditorEulerRotation = {
|
||||
X = 0.436332,
|
||||
X = 0.436332017,
|
||||
Y = 0,
|
||||
Z = 0
|
||||
}
|
||||
@@ -140,15 +140,85 @@
|
||||
CameraComponent = {
|
||||
Primary = true,
|
||||
ProjectionType = .InfinitePerspective,
|
||||
PerspectiveFovY = 1.047198,
|
||||
PerspectiveNearPlane = 0.1,
|
||||
PerspectiveFovY = 1.30899692,
|
||||
PerspectiveNearPlane = 0.100000001,
|
||||
PerspectiveFarPlane = 10000,
|
||||
OrthographicHeight = 10,
|
||||
OrthographicNearPlane = 0,
|
||||
OrthographicFarPlane = 10,
|
||||
AspectRatio = 2.156692,
|
||||
AspectRatio = 2.19888878,
|
||||
FixedAspectRatio = false
|
||||
}
|
||||
},
|
||||
{
|
||||
Id = 420718992779301759,
|
||||
NameComponent = {
|
||||
Name = "Entity"
|
||||
},
|
||||
TransformComponent = {
|
||||
Position = {
|
||||
X = 3,
|
||||
Y = 0.501076996,
|
||||
Z = -0.669378757
|
||||
},
|
||||
Rotation = {
|
||||
X = 0.18301262,
|
||||
Y = -0.683013558,
|
||||
Z = 0.683012128,
|
||||
W = 0.183013007
|
||||
},
|
||||
Scale = {
|
||||
X = 1,
|
||||
Y = 1,
|
||||
Z = 1
|
||||
},
|
||||
EditorEulerRotation = {
|
||||
X = 1.57079446,
|
||||
Y = -2.61799312,
|
||||
Z = 0
|
||||
}
|
||||
},
|
||||
MeshComponent = {
|
||||
Mesh = "Models/plane.glb"
|
||||
},
|
||||
MeshRendererComponent = {
|
||||
Material = ""
|
||||
}
|
||||
},
|
||||
{
|
||||
Id = 8080288871271083510,
|
||||
NameComponent = {
|
||||
Name = "Rocket"
|
||||
},
|
||||
TransformComponent = {
|
||||
Position = {
|
||||
X = 2.37353587,
|
||||
Y = 0.629615188,
|
||||
Z = -1.34831977
|
||||
},
|
||||
Rotation = {
|
||||
X = 0.270598024,
|
||||
Y = -0.65328145,
|
||||
Z = 0.65328151,
|
||||
W = 0.270598054
|
||||
},
|
||||
Scale = {
|
||||
X = 0.999999881,
|
||||
Y = 0.999999821,
|
||||
Z = 0.999999702
|
||||
},
|
||||
EditorEulerRotation = {
|
||||
X = 1.57079637,
|
||||
Y = -2.3561945,
|
||||
Z = 8.94069743e-08
|
||||
}
|
||||
},
|
||||
MeshComponent = {
|
||||
Mesh = "Models/plane.glb"
|
||||
},
|
||||
MeshRendererComponent = {
|
||||
Material = "Textures/RocketMaterial.mat"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -6,15 +6,14 @@
|
||||
NameComponent = {
|
||||
Name = "Quad"
|
||||
},
|
||||
SpriterRendererComponent = {
|
||||
SpriteRendererComponent = {
|
||||
Color = {
|
||||
R = 0,
|
||||
G = 0.551178,
|
||||
B = 0.328787,
|
||||
G = 0.55117774,
|
||||
B = 0.32878688,
|
||||
A = 1
|
||||
},
|
||||
IsCircle = false,
|
||||
Sprite = "\\Textures\\TestMat\\rustediron2_albedo.png",
|
||||
Sprite = "Textures/TestMat/rustediron2_albedo.png",
|
||||
UvTransform = {
|
||||
X = 0,
|
||||
Y = 0,
|
||||
@@ -69,15 +68,14 @@
|
||||
NameComponent = {
|
||||
Name = "Floor"
|
||||
},
|
||||
SpriterRendererComponent = {
|
||||
SpriteRendererComponent = {
|
||||
Color = {
|
||||
R = 1,
|
||||
G = 0.941886,
|
||||
B = 0.401485,
|
||||
G = 0.941886365,
|
||||
B = 0.401484847,
|
||||
A = 1
|
||||
},
|
||||
IsCircle = false,
|
||||
Sprite = null,
|
||||
Sprite = "",
|
||||
UvTransform = {
|
||||
X = 0,
|
||||
Y = 0,
|
||||
@@ -158,13 +156,13 @@
|
||||
CameraComponent = {
|
||||
Primary = true,
|
||||
ProjectionType = .InfinitePerspective,
|
||||
PerspectiveFovY = 1.308997,
|
||||
PerspectiveNearPlane = 0.1,
|
||||
PerspectiveFovY = 1.30899692,
|
||||
PerspectiveNearPlane = 0.100000001,
|
||||
PerspectiveFarPlane = 10000,
|
||||
OrthographicHeight = 10,
|
||||
OrthographicNearPlane = 0,
|
||||
OrthographicFarPlane = 10,
|
||||
AspectRatio = 2.969697,
|
||||
AspectRatio = 3.22169805,
|
||||
FixedAspectRatio = false
|
||||
}
|
||||
},
|
||||
@@ -173,15 +171,15 @@
|
||||
NameComponent = {
|
||||
Name = "Circle"
|
||||
},
|
||||
SpriterRendererComponent = {
|
||||
CircleRendererComponent = {
|
||||
Color = {
|
||||
R = 1,
|
||||
G = 1,
|
||||
B = 1,
|
||||
G = 0,
|
||||
B = 0,
|
||||
A = 1
|
||||
},
|
||||
IsCircle = true,
|
||||
Sprite = "\\Textures\\rocket.png",
|
||||
InnerRadius = 0.300000012,
|
||||
Sprite = "",
|
||||
UvTransform = {
|
||||
X = 0,
|
||||
Y = 0,
|
||||
@@ -191,8 +189,8 @@
|
||||
},
|
||||
TransformComponent = {
|
||||
Position = {
|
||||
X = -0.121203,
|
||||
Y = 0.66016,
|
||||
X = -0.12120308,
|
||||
Y = 0.660160363,
|
||||
Z = 0
|
||||
},
|
||||
Rotation = {
|
||||
@@ -235,34 +233,34 @@
|
||||
},
|
||||
TransformComponent = {
|
||||
Position = {
|
||||
X = 3.883276,
|
||||
X = 3.88327599,
|
||||
Y = 0,
|
||||
Z = -0.808795
|
||||
Z = -0.808795214
|
||||
},
|
||||
Rotation = {
|
||||
X = 0.497987,
|
||||
Y = -0.103421,
|
||||
Z = 0.15538,
|
||||
W = 0.846859
|
||||
X = 0.497987002,
|
||||
Y = -0.103420995,
|
||||
Z = 0.155380026,
|
||||
W = 0.846859217
|
||||
},
|
||||
Scale = {
|
||||
X = 0.999998,
|
||||
X = 0.999997795,
|
||||
Y = 1,
|
||||
Z = 1
|
||||
},
|
||||
EditorEulerRotation = {
|
||||
X = 1.090894,
|
||||
Y = -0.340794,
|
||||
Z = 0.160858
|
||||
X = 1.0908947,
|
||||
Y = -0.340793997,
|
||||
Z = 0.160857916
|
||||
}
|
||||
},
|
||||
LightComponent = {
|
||||
LightType = .Directional,
|
||||
Illuminance = 12.9,
|
||||
Illuminance = 12.8999996,
|
||||
Color = {
|
||||
R = 0.985467,
|
||||
R = 0.985467017,
|
||||
G = 1,
|
||||
B = 0.569979
|
||||
B = 0.569978654
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -275,7 +273,7 @@
|
||||
Position = {
|
||||
X = 0,
|
||||
Y = 0,
|
||||
Z = -1.523338
|
||||
Z = -1.47202551
|
||||
},
|
||||
Rotation = {
|
||||
X = 0,
|
||||
@@ -295,10 +293,10 @@
|
||||
}
|
||||
},
|
||||
MeshComponent = {
|
||||
Mesh = "\\Models\\sphere.glb"
|
||||
Mesh = "Models/sphere.glb"
|
||||
},
|
||||
MeshRendererComponent = {
|
||||
Material = "\\Textures\\TestMaterial.mat"
|
||||
Material = "Textures/TestMaterial.mat"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
#define EDITOR
|
||||
|
||||
cbuffer Constants : register(b0)
|
||||
{
|
||||
float4x4 ViewProjection;
|
||||
};
|
||||
|
||||
struct VS_Input
|
||||
{
|
||||
float4 Position : POSITION;
|
||||
float4 Color : COLOR;
|
||||
#ifdef EDITOR
|
||||
uint EntityId : ENTITYID;
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef struct PS_Input
|
||||
{
|
||||
float4 Position : SV_Position;
|
||||
float4 Color : COLOR;
|
||||
#ifdef EDITOR
|
||||
nointerpolation uint EntityId : ENTITYID;
|
||||
#endif
|
||||
} VS_Output;
|
||||
|
||||
VS_Output VS(VS_Input input)
|
||||
{
|
||||
VS_Output output;
|
||||
|
||||
output.Position = mul(ViewProjection, input.Position);
|
||||
output.Color = input.Color;
|
||||
|
||||
#ifdef EDITOR
|
||||
output.EntityId = input.EntityId;
|
||||
#endif
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
struct PS_Output
|
||||
{
|
||||
float4 Color : SV_TARGET0;
|
||||
#ifdef EDITOR
|
||||
uint EntityId : SV_TARGET1;
|
||||
#endif
|
||||
};
|
||||
|
||||
PS_Output PS(PS_Input input)
|
||||
{
|
||||
PS_Output output;
|
||||
|
||||
output.Color = input.Color;
|
||||
|
||||
#ifdef EDITOR
|
||||
output.EntityId = input.EntityId;
|
||||
#endif
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#pragma Effect[VS=VS; PS=PS]
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
AssetLoader = "EffectAssetLoader",
|
||||
Config = (GlitchyEditor.Assets.EffectAssetLoaderConfig){}/* No reflection data for GlitchyEditor.Assets.EffectAssetLoaderConfig. Add [BonTarget] or force it */
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,31 @@
|
||||
{
|
||||
Effect = "Shaders/myEffect.hlsl",
|
||||
Textures = [
|
||||
"AlbedoTexture": "Textures/rocket.png",
|
||||
"NormalTexture": "Textures/TestMat/rustediron2_normal.png",
|
||||
"MetallicTexture": "Textures/TestMat/rustediron2_metallic.png",
|
||||
"RoughnessTexture": "Textures/TestMat/rustediron2_roughness.png"
|
||||
],
|
||||
Variables = [
|
||||
"AlbedoColor": .ColorRGBA{
|
||||
Value = {
|
||||
R = 1,
|
||||
G = 1,
|
||||
B = 1,
|
||||
A = 1
|
||||
}
|
||||
},
|
||||
"NormalScaling": .Float2{
|
||||
Value = {
|
||||
X = 1,
|
||||
Y = 1
|
||||
}
|
||||
},
|
||||
"MetallicFactor": .Float{
|
||||
Value = 0
|
||||
},
|
||||
"RoughnessFactor": .Float{
|
||||
Value = 1
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
AssetLoader = "MaterialAssetLoader",
|
||||
Config = (GlitchyEditor.Assets.ModelAssetLoaderConfig){}/* No reflection data for GlitchyEditor.Assets.ModelAssetLoaderConfig. Add [BonTarget] or force it */
|
||||
}
|
||||
@@ -7,16 +7,20 @@
|
||||
MinFilter = .Anisotropic,
|
||||
MagFilter = .Anisotropic,
|
||||
MipFilter = .Anisotropic,
|
||||
FilterMode = .Default,
|
||||
ComparisonFunction = .Never,
|
||||
AddressModeU = .Wrap,
|
||||
AddressModeV = .Border,
|
||||
AddressModeW = .Clamp,
|
||||
MipMaxLOD = 160,
|
||||
AddressModeV = .Wrap,
|
||||
AddressModeW = .Wrap,
|
||||
MipLODBias = 0,
|
||||
MipMinLOD = 0,
|
||||
MipMaxLOD = 3,
|
||||
MaxAnisotropy = 16,
|
||||
BorderColor = {
|
||||
R = 0.756863,
|
||||
G = 0.2,
|
||||
A = 0.956863
|
||||
R = 1,
|
||||
G = 1,
|
||||
B = 1,
|
||||
A = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
{
|
||||
AssetLoader = "EditorTextureAssetLoader",
|
||||
Config = (GlitchyEditor.Assets.EditorTextureAssetLoaderConfig){
|
||||
_generateMipMaps = false,
|
||||
_isSrgb = false,
|
||||
_samplerStateDescription = {
|
||||
MinFilter = .Linear,
|
||||
MagFilter = .Linear,
|
||||
MipFilter = .Linear,
|
||||
FilterMode = .Default,
|
||||
ComparisonFunction = .Never,
|
||||
AddressModeU = .Clamp,
|
||||
AddressModeV = .Clamp,
|
||||
AddressModeU = .Wrap,
|
||||
AddressModeV = .Wrap,
|
||||
AddressModeW = .Clamp,
|
||||
MipMinLOD = -340282346638528859811704183484516925440,
|
||||
MipMaxLOD = 340282346638528859811704183484516925440,
|
||||
MipLODBias = 0,
|
||||
MipMinLOD = -3.40282347e+38,
|
||||
MipMaxLOD = 3.40282347e+38,
|
||||
MaxAnisotropy = 1,
|
||||
BorderColor = {
|
||||
R = 1,
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
{
|
||||
AssetLoader = "EditorTextureAssetLoader",
|
||||
Config = (GlitchyEditor.Assets.EditorTextureAssetLoaderConfig){
|
||||
_generateMipMaps = false,
|
||||
_isSrgb = false,
|
||||
_samplerStateDescription = {
|
||||
MinFilter = .Linear,
|
||||
MagFilter = .Linear,
|
||||
MipFilter = .Linear,
|
||||
FilterMode = .Default,
|
||||
ComparisonFunction = .Never,
|
||||
AddressModeU = .Clamp,
|
||||
AddressModeV = .Clamp,
|
||||
AddressModeU = .Wrap,
|
||||
AddressModeV = .Wrap,
|
||||
AddressModeW = .Clamp,
|
||||
MipMinLOD = -340282346638528859811704183484516925440,
|
||||
MipMaxLOD = 340282346638528859811704183484516925440,
|
||||
MipLODBias = 2.5999999,
|
||||
MipMinLOD = -Infinity,
|
||||
MipMaxLOD = Infinity,
|
||||
MaxAnisotropy = 1,
|
||||
BorderColor = {
|
||||
R = 1,
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
{
|
||||
AssetLoader = "EditorTextureAssetLoader",
|
||||
Config = (GlitchyEditor.Assets.EditorTextureAssetLoaderConfig){
|
||||
_generateMipMaps = false,
|
||||
_isSrgb = true,
|
||||
_samplerStateDescription = {
|
||||
MinFilter = .Linear,
|
||||
MagFilter = .Linear,
|
||||
MipFilter = .Linear,
|
||||
FilterMode = .Default,
|
||||
ComparisonFunction = .Never,
|
||||
AddressModeU = .Clamp,
|
||||
AddressModeV = .Clamp,
|
||||
AddressModeU = .Wrap,
|
||||
AddressModeV = .Wrap,
|
||||
AddressModeW = .Clamp,
|
||||
MipMinLOD = -340282346638528859811704183484516925440,
|
||||
MipMaxLOD = 340282346638528859811704183484516925440,
|
||||
MipLODBias = 0,
|
||||
MipMinLOD = -3.40282347e+38,
|
||||
MipMaxLOD = 3.40282347e+38,
|
||||
MaxAnisotropy = 1,
|
||||
BorderColor = {
|
||||
R = 1,
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
{
|
||||
Effect = "content/Shaders/myEffect.hlsl",
|
||||
Effect = "Shaders\\myEffect.hlsl",
|
||||
Textures = [
|
||||
"AlbedoTexture": "Textures/TestMat/rustediron2_albedo.png"
|
||||
"AlbedoTexture": "Textures\\TestMat\\rustediron2_albedo.png",
|
||||
"NormalTexture": "Textures\\TestMat\\rustediron2_normal.png",
|
||||
"MetallicTexture": "Textures\\TestMat\\rustediron2_metallic.png",
|
||||
"RoughnessTexture": "Textures\\TestMat\\rustediron2_roughness.png"
|
||||
],
|
||||
Variables = [
|
||||
"AlbedoColor": .ColorRGBA{
|
||||
|
||||
@@ -4,13 +4,14 @@
|
||||
_isSrgb = true,
|
||||
_samplerStateDescription = {
|
||||
MinFilter = .Linear,
|
||||
MagFilter = .Linear,
|
||||
MipFilter = .Linear,
|
||||
ComparisonFunction = .Never,
|
||||
AddressModeU = .Clamp,
|
||||
AddressModeV = .Clamp,
|
||||
AddressModeW = .Clamp,
|
||||
MipMinLOD = -340282346638528859811704183484516925440,
|
||||
MipMaxLOD = 340282346638528859811704183484516925440,
|
||||
MipMinLOD = -3.40282347e+38,
|
||||
MipMaxLOD = 3.40282347e+38,
|
||||
MaxAnisotropy = 1,
|
||||
BorderColor = {
|
||||
R = 1,
|
||||
|
||||
@@ -31,7 +31,7 @@ class AssetFile
|
||||
|
||||
private bool _isDirectory;
|
||||
|
||||
private Object _loadedAsset;
|
||||
private Asset _loadedAsset;
|
||||
|
||||
public bool IsDirectory => _isDirectory;
|
||||
|
||||
@@ -42,7 +42,7 @@ class AssetFile
|
||||
|
||||
public AssetConfig AssetConfig => _assetConfig;
|
||||
|
||||
public Object LoadedAsset => _loadedAsset;
|
||||
public Asset LoadedAsset => _loadedAsset;
|
||||
|
||||
[AllowAppend]
|
||||
public this(EditorContentManager contentManager, StringView identifier, StringView path, bool isDirectory)
|
||||
|
||||
@@ -34,6 +34,24 @@ public class SubAsset
|
||||
public Texture2D PreviewImage ~ _?.ReleaseRef();
|
||||
}
|
||||
|
||||
public static class AssetIdentifier
|
||||
{
|
||||
public const char8 DirectorySeparatorChar = '/';
|
||||
|
||||
public static void Fixup(String assetIdentifier)
|
||||
{
|
||||
const String DotSeperator = $".{DirectorySeparatorChar}";
|
||||
const String SeperatorDot = $"{DirectorySeparatorChar}.";
|
||||
|
||||
assetIdentifier.Replace('\\', DirectorySeparatorChar);
|
||||
assetIdentifier.Replace(DotSeperator, "");
|
||||
assetIdentifier.Replace(SeperatorDot, "");
|
||||
|
||||
if (assetIdentifier.StartsWith(DirectorySeparatorChar))
|
||||
assetIdentifier.Remove(0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
class AssetHierarchy
|
||||
{
|
||||
FileSystemWatcher fsw ~ {
|
||||
@@ -108,7 +126,8 @@ class AssetHierarchy
|
||||
fsw.OnRenamed.Add(new (oldName, newName) => {
|
||||
Log.EngineLogger.Trace($"File renamed (From \"{oldName}\" to \"{newName}\")");
|
||||
|
||||
_fileSystemDirty = true;
|
||||
//_fileSystemDirty = true;
|
||||
FileRenamed(oldName, newName);
|
||||
/*String contentFilePath = scope String();
|
||||
|
||||
Path.InternalCombine(contentFilePath, ContentDirectory, oldName);
|
||||
@@ -121,7 +140,7 @@ class AssetHierarchy
|
||||
fsw.StartRaisingEvents();
|
||||
}
|
||||
|
||||
/// Gets the tree node for the given filePath or null, if the file/directory doesn't exist.
|
||||
/// Gets the tree node for the given filePath or .Err, 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)
|
||||
@@ -161,6 +180,7 @@ class AssetHierarchy
|
||||
_assetHierarchy = new TreeNode<AssetNode>(new AssetNode());
|
||||
_assetHierarchy->Path = new String(ContentDirectory);
|
||||
_assetHierarchy->Name = new String("Content");
|
||||
_assetHierarchy->IsDirectory = true;
|
||||
|
||||
Log.EngineLogger.Trace($"Created directory node for: \"{_assetHierarchy->Path}\"");
|
||||
|
||||
@@ -171,6 +191,7 @@ class AssetHierarchy
|
||||
{
|
||||
String identifier = scope .(node.Path.Length);
|
||||
Path.GetRelativePath(node.Path, _contentDirectory, identifier);
|
||||
AssetIdentifier.Fixup(identifier);
|
||||
|
||||
node.AssetFile = new AssetFile(_contentManager, identifier, node.Path, node.IsDirectory);
|
||||
}
|
||||
@@ -333,11 +354,73 @@ class AssetHierarchy
|
||||
return;
|
||||
|
||||
OnFileContentChanged(node.Value);
|
||||
}
|
||||
|
||||
// TODO: Handle file changes (reload asset, etc...)
|
||||
private void FileRenamed(StringView oldFilePath, StringView newFilePath)
|
||||
{
|
||||
var oldFilePath;
|
||||
|
||||
// Ignore Config files.
|
||||
if (oldFilePath.EndsWith(AssetFile.ConfigFileExtension))
|
||||
return;
|
||||
|
||||
|
||||
String oldFileNameWithContentRoot = scope .();
|
||||
Path.InternalCombine(oldFileNameWithContentRoot, _contentDirectory, oldFilePath);
|
||||
|
||||
String newFileNameWithContentRoot = scope .();
|
||||
Path.InternalCombine(newFileNameWithContentRoot, _contentDirectory, newFilePath);
|
||||
|
||||
// Rename config file
|
||||
{
|
||||
String oldConfigFileName = scope $"{oldFileNameWithContentRoot}{AssetFile.ConfigFileExtension}";
|
||||
String newConfigFileName = scope $"{newFileNameWithContentRoot}{AssetFile.ConfigFileExtension}";
|
||||
|
||||
if (File.Exists(oldConfigFileName) && !File.Exists(newConfigFileName))
|
||||
{
|
||||
if (File.Move(oldConfigFileName, newConfigFileName) case .Err(let value))
|
||||
{
|
||||
Log.EngineLogger.Error($"Failed to move file {oldConfigFileName} to {newConfigFileName}. Code: {value}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var nodeResult = GetNodeFromPath(oldFileNameWithContentRoot);
|
||||
|
||||
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 \"{oldFileNameWithContentRoot}\"");
|
||||
return;
|
||||
}
|
||||
|
||||
_pathToAssetNode.Remove(oldFileNameWithContentRoot);
|
||||
|
||||
node->Path.Set(newFileNameWithContentRoot);
|
||||
_pathToAssetNode.Add(node->Path, node);
|
||||
|
||||
node->Name.Clear();
|
||||
Path.GetFileName(newFileNameWithContentRoot, node->Name);
|
||||
|
||||
String oldIdentifier = scope .(node->AssetFile.[Friend]_identifier);
|
||||
|
||||
node->AssetFile.[Friend]_path.Set(node->Path);
|
||||
|
||||
node->AssetFile.[Friend]_identifier.Set(newFilePath);
|
||||
AssetIdentifier.Fixup(node->AssetFile.[Friend]_identifier);
|
||||
|
||||
node->AssetFile.[Friend]_assetConfigPath..Set(node->Path).Append(AssetFile.ConfigFileExtension);
|
||||
|
||||
OnFileRenamed(node.Value, oldIdentifier);
|
||||
}
|
||||
|
||||
public delegate void FileContentChangedFunc(AssetNode node);
|
||||
|
||||
public Event<FileContentChangedFunc> OnFileContentChanged ~ _.Dispose();
|
||||
|
||||
public delegate void FileRenamedFunc(AssetNode node, StringView oldName);
|
||||
|
||||
public Event<FileRenamedFunc> OnFileRenamed ~ _.Dispose();
|
||||
}
|
||||
|
||||
@@ -48,54 +48,15 @@ class EffectAssetLoader : IAssetLoader //, IReloadingAssetLoader
|
||||
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)
|
||||
public Asset GetPlaceholderAsset(Type assetType)
|
||||
{
|
||||
Texture texture = contentManager.LoadAsset(textureIdentifier) as Texture;
|
||||
|
||||
if (texture == null)
|
||||
{
|
||||
Log.EngineLogger.Error("Failed to load texture.");
|
||||
// TODO: LoadAsset should return an error texture.
|
||||
return default;
|
||||
}
|
||||
|
||||
material.SetTexture(slotName, texture);
|
||||
}
|
||||
|
||||
fx.ReleaseRef();
|
||||
|
||||
/*for (let (slotName, textureIdentifier) in materialFile.Variables)
|
||||
public Asset GetErrorAsset(Type assetType)
|
||||
{
|
||||
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);*/
|
||||
return default;
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ class MaterialAssetPropertiesEditor : AssetPropertiesEditor
|
||||
|
||||
mixin DropAssetTarget<T>() where T : Asset
|
||||
{
|
||||
Asset asset = null;
|
||||
AssetHandle handle = .Invalid;
|
||||
|
||||
if (ImGui.BeginDragDropTarget())
|
||||
{
|
||||
@@ -39,13 +39,13 @@ class MaterialAssetPropertiesEditor : AssetPropertiesEditor
|
||||
{
|
||||
StringView fullpath = .((char8*)payload.Data, (int)payload.DataSize);
|
||||
|
||||
asset = Content.LoadAsset<Asset>(fullpath);
|
||||
handle = Content.LoadAsset(fullpath);
|
||||
}
|
||||
|
||||
ImGui.EndDragDropTarget();
|
||||
}
|
||||
|
||||
asset
|
||||
handle
|
||||
}
|
||||
|
||||
public this(AssetFile asset) : base(asset)
|
||||
@@ -84,11 +84,10 @@ class MaterialAssetPropertiesEditor : AssetPropertiesEditor
|
||||
{
|
||||
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);
|
||||
}
|
||||
AssetHandle<Texture2D> newTexture = Content.LoadAsset(path);
|
||||
|
||||
//newTexture.Get().SamplerState = SamplerStateManager.AnisotropicWrap;
|
||||
material.SetTexture(texture.key, newTexture.Cast<Texture>());
|
||||
}
|
||||
|
||||
ImGui.EndDragDropTarget();
|
||||
@@ -98,7 +97,6 @@ class MaterialAssetPropertiesEditor : AssetPropertiesEditor
|
||||
|
||||
private void ShowVariables(Material material, Effect effect)
|
||||
{
|
||||
|
||||
for (let (name, arguments) in effect.[Friend]_variableDescriptions)
|
||||
{
|
||||
let variable = effect.Variables[name];
|
||||
@@ -341,28 +339,23 @@ class MaterialAssetLoader : IAssetLoader, IAssetSaver //, IReloadingAssetLoader
|
||||
Log.EngineLogger.Error("Failed to load material.");
|
||||
Debug.SafeBreak();
|
||||
return null;
|
||||
// TODO: return error material
|
||||
}
|
||||
|
||||
Effect fx = new Effect(materialFile.Effect);
|
||||
Effect fx = Content.GetAsset<Effect>(contentManager.LoadAsset(materialFile.Effect, true), contentManager);
|
||||
|
||||
Material material = new Material(fx);
|
||||
|
||||
for (let (slotName, textureIdentifier) in materialFile.Textures)
|
||||
{
|
||||
using (Texture texture = contentManager.LoadAsset(textureIdentifier) as Texture)
|
||||
{
|
||||
if (texture == null)
|
||||
AssetHandle<Texture> texture = contentManager.LoadAsset(textureIdentifier);
|
||||
|
||||
if (texture.IsInvalid)
|
||||
{
|
||||
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)
|
||||
{
|
||||
@@ -382,7 +375,7 @@ class MaterialAssetLoader : IAssetLoader, IAssetSaver //, IReloadingAssetLoader
|
||||
material.SetVariable(slotName, value);
|
||||
case .None:
|
||||
default:
|
||||
Log.EngineLogger.Error("Errorre");
|
||||
Log.EngineLogger.Error($"Unknown variable type of variable {slotName}: {variableValue}");
|
||||
}
|
||||
|
||||
|
||||
@@ -407,12 +400,11 @@ class MaterialAssetLoader : IAssetLoader, IAssetSaver //, IReloadingAssetLoader
|
||||
materialFile.Textures = new .();
|
||||
materialFile.Variables = new .();
|
||||
|
||||
//material.SetTexture();
|
||||
|
||||
for (let (slotName, textureViewBinding) in material.[Friend]_textures)
|
||||
for (let (slotName, texture) in material.[Friend]_textures)
|
||||
{
|
||||
//materialFile.Textures.Add(slotName, textureViewBinding.)
|
||||
Texture textureAsset = texture.Get();
|
||||
|
||||
materialFile.Textures.Add(new String(slotName), new String(textureAsset?.Identifier ?? ""));
|
||||
}
|
||||
|
||||
Effect effect = material.Effect;
|
||||
@@ -423,7 +415,6 @@ class MaterialAssetLoader : IAssetLoader, IAssetSaver //, IReloadingAssetLoader
|
||||
for (let (name, arguments) in effect.[Friend]_variableDescriptions)
|
||||
{
|
||||
VariableValue variableValue = .None;
|
||||
//Object variantValue = null;
|
||||
|
||||
let variable = effect.Variables[name];
|
||||
|
||||
@@ -449,7 +440,6 @@ class MaterialAssetLoader : IAssetLoader, IAssetSaver //, IReloadingAssetLoader
|
||||
value = ColorRGBA.LinearToSRGB((ColorRGBA)value);
|
||||
|
||||
variableValue = .ColorRGBA(value);
|
||||
//variantValue = new box value;
|
||||
}
|
||||
}
|
||||
else if (variable.Type == .Float && variable.Rows == 1)
|
||||
@@ -469,51 +459,9 @@ class MaterialAssetLoader : IAssetLoader, IAssetSaver //, IReloadingAssetLoader
|
||||
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);
|
||||
materialFile.Variables.Add(new String(name), variableValue);
|
||||
}
|
||||
|
||||
String text = scope .();
|
||||
@@ -527,4 +475,17 @@ class MaterialAssetLoader : IAssetLoader, IAssetSaver //, IReloadingAssetLoader
|
||||
|
||||
return .Ok;
|
||||
}
|
||||
|
||||
Material _placeholder;
|
||||
Material _error;
|
||||
|
||||
public Asset GetPlaceholderAsset(Type assetType)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
public Asset GetErrorAsset(Type assetType)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
}
|
||||
@@ -44,8 +44,18 @@ class ModelAssetLoader : IAssetLoader //, IReloadingAssetLoader
|
||||
|
||||
public Asset LoadAsset(Stream file, AssetLoaderConfig config, StringView assetIdentifier, StringView? subAsset, IContentManager contentManager)
|
||||
{
|
||||
Log.EngineLogger.Assert(subAsset != null);
|
||||
//Log.EngineLogger.Assert(subAsset != null);
|
||||
|
||||
return ModelLoader.LoadMesh(file, subAsset.Value, 0);
|
||||
return ModelLoader.LoadMesh(file, subAsset ?? assetIdentifier, 0);
|
||||
}
|
||||
|
||||
public Asset GetPlaceholderAsset(Type assetType)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
public Asset GetErrorAsset(Type assetType)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
}
|
||||
@@ -164,7 +164,7 @@ class EditorTextureAssetLoaderConfig : AssetLoaderConfig
|
||||
}
|
||||
}
|
||||
|
||||
class EditorTextureAssetLoader : IAssetLoader, IReloadingAssetLoader
|
||||
class EditorTextureAssetLoader : IAssetLoader//, IReloadingAssetLoader
|
||||
{
|
||||
private static readonly List<StringView> _fileExtensions = new .(){".png", ".dds"} ~ delete _; // ".jpg", ".bmp"
|
||||
|
||||
@@ -243,65 +243,19 @@ class EditorTextureAssetLoader : IAssetLoader, IReloadingAssetLoader
|
||||
case .PNG:
|
||||
texture = LoadPng(data, config);
|
||||
case .Unknown:
|
||||
Runtime.FatalError("Unknown image format.");
|
||||
Log.EngineLogger.Error("Unknown texture format.");
|
||||
texture = null;
|
||||
}
|
||||
|
||||
Log.EngineLogger.AssertDebug(texture != null);
|
||||
|
||||
if (texture != null)
|
||||
{
|
||||
SetSampler(texture, config);
|
||||
texture.[Friend]Complete = true;
|
||||
}
|
||||
|
||||
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!();
|
||||
@@ -313,40 +267,105 @@ class EditorTextureAssetLoader : IAssetLoader, IReloadingAssetLoader
|
||||
if (result case .Err(let err))
|
||||
{
|
||||
Log.EngineLogger.Error($"Failed to read data from stream. Texture: Error: {err}");
|
||||
return null;
|
||||
}
|
||||
|
||||
uint8* rawData = null;
|
||||
defer
|
||||
{
|
||||
if (rawData != null)
|
||||
LodePng.LodePng.Free(rawData);
|
||||
}
|
||||
|
||||
uint8* rawData = ?;
|
||||
uint32 width = 0, height = 0;
|
||||
|
||||
{
|
||||
Debug.Profiler.ProfileResourceScope!("LodePng.LodePng.Decode32");
|
||||
uint32 errorCode = LodePng.LodePng.Decode32(&rawData, &width, &height, pngData.Ptr, (.)pngData.Count);
|
||||
if (errorCode != 0)
|
||||
{
|
||||
Log.EngineLogger.Error($"Failed to decode PNG file {errorCode}.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
// TODO: Move the loading of Dds files here.
|
||||
Texture2D texture = new [Friend]Texture2D(data);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
private static void SetSampler(Texture texture, EditorTextureAssetLoaderConfig config)
|
||||
{
|
||||
using (SamplerState samplerState = SamplerStateManager.GetSampler(config.SamplerStateDescription))
|
||||
{
|
||||
texture.SamplerState = samplerState;
|
||||
}
|
||||
}
|
||||
|
||||
private static Texture2D _placeholder2D;
|
||||
private static Texture2D _error2D;
|
||||
|
||||
public Asset GetPlaceholderAsset(Type assetType)
|
||||
{
|
||||
switch (assetType)
|
||||
{
|
||||
case typeof(Texture2D):
|
||||
fallthrough;
|
||||
default:
|
||||
if (_placeholder2D == null)
|
||||
{
|
||||
Texture2DDesc desc = .(1, 1, .R8G8B8A8_UNorm, 1, 1, .Immutable, .None);
|
||||
|
||||
_placeholder2D = new Texture2D(desc);
|
||||
_placeholder2D.SamplerState = SamplerStateManager.PointWrap;
|
||||
Color color = Color.Cyan;
|
||||
_placeholder2D.SetData<Color>(&color);
|
||||
|
||||
Content.ManageAsset(_placeholder2D);
|
||||
_placeholder2D.ReleaseRef();
|
||||
|
||||
_placeholder2D.[Friend]Complete = false;
|
||||
}
|
||||
|
||||
return _placeholder2D;
|
||||
}
|
||||
}
|
||||
|
||||
public Asset GetErrorAsset(Type assetType)
|
||||
{
|
||||
switch (assetType)
|
||||
{
|
||||
case typeof(Texture2D):
|
||||
fallthrough;
|
||||
default:
|
||||
if (_error2D == null)
|
||||
{
|
||||
Texture2DDesc desc = .(2, 2, .R8G8B8A8_UNorm, 1, 1, .Immutable, .None);
|
||||
|
||||
_error2D = new Texture2D(desc);
|
||||
_error2D.SamplerState = SamplerStateManager.PointWrap;
|
||||
Color[4] color = .(Color.HotPink, Color.Black, Color.Black, Color.HotPink);
|
||||
_error2D.SetData<Color>(&color);
|
||||
|
||||
Content.ManageAsset(_error2D);
|
||||
_error2D.ReleaseRef();
|
||||
|
||||
_placeholder2D.[Friend]Complete = true;
|
||||
}
|
||||
|
||||
return _error2D;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +60,8 @@ namespace GlitchyEditor.EditWindows
|
||||
|
||||
ShowComponentEditor<TransformComponent>("Transform", entity, => ShowTransformComponentEditor);
|
||||
ShowComponentEditor<CameraComponent>("Camera", entity, => ShowCameraComponentEditor, => ShowComponentContextMenu<CameraComponent>);
|
||||
ShowComponentEditor<SpriterRendererComponent>("Sprite Renderer", entity, => ShowSpriteRendererComponentEditor, => ShowComponentContextMenu<SpriterRendererComponent>);
|
||||
ShowComponentEditor<SpriteRendererComponent>("Sprite Renderer", entity, => ShowSpriteRendererComponentEditor, => ShowComponentContextMenu<SpriteRendererComponent>);
|
||||
ShowComponentEditor<CircleRendererComponent>("Circle Renderer", entity, => ShowCircleRendererComponentEditor, => ShowComponentContextMenu<CircleRendererComponent>);
|
||||
ShowComponentEditor<MeshRendererComponent>("Mesh Renderer", entity, => ShowMeshRendererComponentEditor, => ShowComponentContextMenu<MeshRendererComponent>);
|
||||
ShowComponentEditor<LightComponent>("Light", entity, => ShowLightComponentEditor, => ShowComponentContextMenu<LightComponent>);
|
||||
ShowComponentEditor<MeshComponent>("Mesh", entity, => ShowMeshComponentEditor, => ShowComponentContextMenu<MeshComponent>);
|
||||
@@ -117,18 +118,18 @@ namespace GlitchyEditor.EditWindows
|
||||
|
||||
private static void ShowNameComponentEditor(Entity entity)
|
||||
{
|
||||
if (!entity.HasComponent<DebugNameComponent>())
|
||||
if (!entity.HasComponent<NameComponent>())
|
||||
return;
|
||||
|
||||
char8[256] nameBuffer = default;
|
||||
|
||||
DebugNameComponent* component = entity.GetComponent<DebugNameComponent>();
|
||||
NameComponent* component = entity.GetComponent<NameComponent>();
|
||||
|
||||
String name = null;
|
||||
StringView name = null;
|
||||
|
||||
if(component != null)
|
||||
{
|
||||
name = component.DebugName;
|
||||
name = component.Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -142,11 +143,10 @@ namespace GlitchyEditor.EditWindows
|
||||
{
|
||||
if(component == null)
|
||||
{
|
||||
component = entity.AddComponent<DebugNameComponent>();
|
||||
component = entity.AddComponent<NameComponent>();
|
||||
}
|
||||
|
||||
component.DebugName.Clear();
|
||||
component.DebugName.Append(&nameBuffer);
|
||||
component.Name = StringView(&nameBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,7 +250,7 @@ namespace GlitchyEditor.EditWindows
|
||||
}
|
||||
}
|
||||
|
||||
private static void ShowSpriteRendererComponentEditor(Entity entity, SpriterRendererComponent* spriteRendererComponent)
|
||||
private static void ShowSpriteRendererComponentEditor(Entity entity, SpriteRendererComponent* spriteRendererComponent)
|
||||
{
|
||||
ColorRGBA spriteColor = ColorRGBA.LinearToSRGB(spriteRendererComponent.Color);
|
||||
if (ImGui.ColorEdit4("Color", ref spriteColor))
|
||||
@@ -268,10 +268,7 @@ namespace GlitchyEditor.EditWindows
|
||||
|
||||
StringView path = .((char8*)payload.Data, (int)payload.DataSize);
|
||||
|
||||
using (Texture2D texture = Content.LoadAsset<Texture2D>(path))
|
||||
{
|
||||
spriteRendererComponent.Sprite = texture;
|
||||
}
|
||||
spriteRendererComponent.Sprite = Content.LoadAsset(path);
|
||||
}
|
||||
|
||||
ImGui.EndDragDropTarget();
|
||||
@@ -279,8 +276,36 @@ namespace GlitchyEditor.EditWindows
|
||||
|
||||
|
||||
ImGui.EditVector<4>("UV Transform", ref *(float[4]*)&spriteRendererComponent.UvTransform);
|
||||
}
|
||||
|
||||
ImGui.Checkbox("Is Circle", &spriteRendererComponent.IsCircle);
|
||||
private static void ShowCircleRendererComponentEditor(Entity entity, CircleRendererComponent* circleRendererComponent)
|
||||
{
|
||||
ColorRGBA spriteColor = ColorRGBA.LinearToSRGB(circleRendererComponent.Color);
|
||||
if (ImGui.ColorEdit4("Color", ref spriteColor))
|
||||
circleRendererComponent.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);
|
||||
|
||||
circleRendererComponent.Sprite = Content.LoadAsset(path);
|
||||
}
|
||||
|
||||
ImGui.EndDragDropTarget();
|
||||
}
|
||||
|
||||
|
||||
ImGui.EditVector<4>("UV Transform", ref *(float[4]*)&circleRendererComponent.UvTransform);
|
||||
|
||||
ImGui.DragFloat("Inner Radius", &circleRendererComponent.InnerRadius, 0.1f, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
private static void ShowMeshRendererComponentEditor(Entity entity, MeshRendererComponent* meshRendererComponent)
|
||||
@@ -301,10 +326,7 @@ namespace GlitchyEditor.EditWindows
|
||||
{
|
||||
StringView fullpath = .((char8*)payload.Data, (int)payload.DataSize);
|
||||
|
||||
using (Material loadedMaterial = Content.LoadAsset<Material>(fullpath))
|
||||
{
|
||||
meshRendererComponent.Material = loadedMaterial;
|
||||
}
|
||||
meshRendererComponent.Material = Content.LoadAsset(fullpath);
|
||||
}
|
||||
|
||||
ImGui.EndDragDropTarget();
|
||||
@@ -488,10 +510,7 @@ namespace GlitchyEditor.EditWindows
|
||||
StringView filePath = fullpath.Substring(0, idx);
|
||||
StringView meshName = fullpath.Substring(idx + 1);*/
|
||||
|
||||
using (GeometryBinding geometry = Content.LoadAsset<GeometryBinding>(fullpath))
|
||||
{
|
||||
meshComponent.Mesh = geometry;
|
||||
}
|
||||
meshComponent.Mesh = Content.LoadAsset(fullpath);
|
||||
|
||||
// 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))
|
||||
@@ -557,7 +576,8 @@ namespace GlitchyEditor.EditWindows
|
||||
ImGui.Separator();
|
||||
|
||||
ShowComponentButton<CameraComponent>("Camera");
|
||||
ShowComponentButton<SpriterRendererComponent>("Sprite Renderer");
|
||||
ShowComponentButton<SpriteRendererComponent>("Sprite Renderer");
|
||||
ShowComponentButton<CircleRendererComponent>("Circle Renderer");
|
||||
ShowComponentButton<LightComponent>("Light");
|
||||
ShowComponentButton<Rigidbody2DComponent>("Rigidbody 2D");
|
||||
ShowComponentButton<BoxCollider2DComponent>("Box collider 2D");
|
||||
|
||||
@@ -14,8 +14,7 @@ namespace GlitchyEditor.EditWindows
|
||||
|
||||
class ContentBrowserWindow : EditorWindow
|
||||
{
|
||||
// TODO: Get from project
|
||||
//const String ContentDirectory = "./content";
|
||||
public const String s_WindowTitle = "Content Browser";
|
||||
|
||||
private append String _currentDirectory = .();
|
||||
|
||||
@@ -43,7 +42,7 @@ namespace GlitchyEditor.EditWindows
|
||||
_currentDirectory.Set(_manager.ContentDirectory);
|
||||
}
|
||||
|
||||
if(!ImGui.Begin("Content Browser", &_open, .None))
|
||||
if(!ImGui.Begin(s_WindowTitle, &_open, .None))
|
||||
{
|
||||
ImGui.End();
|
||||
return;
|
||||
@@ -58,12 +57,20 @@ namespace GlitchyEditor.EditWindows
|
||||
|
||||
ImGui.Columns(2);
|
||||
|
||||
ImGui.BeginChild("Sidebar");
|
||||
|
||||
DrawDirectorySideBar();
|
||||
|
||||
ImGui.EndChild();
|
||||
|
||||
ImGui.NextColumn();
|
||||
|
||||
ImGui.BeginChild("Files");
|
||||
|
||||
DrawCurrentDirectory();
|
||||
|
||||
ImGui.EndChild();
|
||||
|
||||
ImGui.Columns(1);
|
||||
|
||||
ImGui.End();
|
||||
@@ -149,6 +156,24 @@ namespace GlitchyEditor.EditWindows
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentDirectoryNode->Parent != null)
|
||||
{
|
||||
ImGui.PushID("Back");
|
||||
|
||||
DrawBackButton(currentDirectoryNode->Parent);
|
||||
|
||||
// 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 the next button won't fit on the same line we start a new line.
|
||||
if (expectedButtonRight < window_visible_x2)
|
||||
ImGui.SameLine();
|
||||
|
||||
ImGui.PopID();
|
||||
}
|
||||
|
||||
for (var entry in currentDirectoryNode->Children)
|
||||
{
|
||||
ImGui.PushID(entry->Name);
|
||||
@@ -168,6 +193,45 @@ namespace GlitchyEditor.EditWindows
|
||||
}
|
||||
}
|
||||
|
||||
/// Renders the button for the given directory item.
|
||||
private void DrawBackButton(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));
|
||||
}
|
||||
|
||||
SubTexture2D image = s_FolderTexture;
|
||||
|
||||
ImGui.ImageButton(image, (.)(DirectoryItemSize - padding));
|
||||
|
||||
ImGui.PopStyleColor();
|
||||
|
||||
if (ImGui.IsItemHovered() && ImGui.IsMouseClicked(.Left))
|
||||
{
|
||||
if (_selectedFile != entry->Path)
|
||||
{
|
||||
_selectedFile.Set(entry->Path);
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui.IsItemHovered() && ImGui.IsMouseDoubleClicked(.Left))
|
||||
{
|
||||
EntryDoubleClicked(entry);
|
||||
}
|
||||
|
||||
ImGui.TextUnformatted("..");
|
||||
|
||||
ImGui.EndChild();
|
||||
}
|
||||
|
||||
/// Renders the button for the given directory item.
|
||||
private void DrawDirectoryItem(TreeNode<AssetNode> entry)
|
||||
{
|
||||
|
||||
+20
-16
@@ -9,7 +9,7 @@ using GlitchyEngine.Events;
|
||||
|
||||
namespace GlitchyEditor.EditWindows
|
||||
{
|
||||
class SceneViewportWindow : EditorWindow
|
||||
class EditorViewportWindow : EditorWindow
|
||||
{
|
||||
public const String s_WindowTitle = "Scene";
|
||||
|
||||
@@ -27,6 +27,8 @@ namespace GlitchyEditor.EditWindows
|
||||
private float _angleSnap = 45.0f;
|
||||
private bool _doSnap = false;
|
||||
|
||||
private bool _visible;
|
||||
|
||||
public uint32 SelectedEntityId {get; private set; }
|
||||
public bool SelectionChanged { get; private set; }
|
||||
|
||||
@@ -52,6 +54,8 @@ namespace GlitchyEditor.EditWindows
|
||||
/// Gets or sets whether the editor functionality (gizmo, picking etc.) is enabled.
|
||||
public bool EditorMode { get; set; } = true
|
||||
|
||||
public bool Visible => _visible;
|
||||
|
||||
public this(Editor editor)
|
||||
{
|
||||
_editor = editor;
|
||||
@@ -65,9 +69,13 @@ namespace GlitchyEditor.EditWindows
|
||||
if(!ImGui.Begin(s_WindowTitle, &_open, .NoScrollbar | .MenuBar))
|
||||
{
|
||||
ImGui.End();
|
||||
|
||||
_visible = false;
|
||||
return;
|
||||
}
|
||||
|
||||
_visible = true;
|
||||
|
||||
let viewportSize = ImGui.GetContentRegionAvail();
|
||||
|
||||
if(ImGui.IsWindowHovered() && Input.IsMouseButtonPressing(.RightButton))
|
||||
@@ -78,8 +86,6 @@ namespace GlitchyEditor.EditWindows
|
||||
|
||||
_hasFocus = ImGui.IsWindowFocused();
|
||||
|
||||
if (EditorMode)
|
||||
{
|
||||
ShowMenuBar();
|
||||
|
||||
if (_editor.CurrentCamera.[Friend]BindMouse && _hasFocus)
|
||||
@@ -102,7 +108,6 @@ namespace GlitchyEditor.EditWindows
|
||||
if (Input.IsKeyPressing(.L))
|
||||
_gizmoMode = .LOCAL;
|
||||
}
|
||||
}
|
||||
|
||||
if(_renderTarget != null)
|
||||
{
|
||||
@@ -111,14 +116,11 @@ namespace GlitchyEditor.EditWindows
|
||||
//ImGui.Image(_editor.CurrentScene.[Friend]_compositeTarget.GetViewBinding(0), viewportSize);
|
||||
}
|
||||
|
||||
if (EditorMode)
|
||||
{
|
||||
HandleDropTarget();
|
||||
|
||||
bool gizmoUsed = DrawImGuizmo(viewportSize);
|
||||
|
||||
MousePicking(viewportSize, gizmoUsed);
|
||||
}
|
||||
|
||||
ImGui.End();
|
||||
|
||||
@@ -157,24 +159,26 @@ namespace GlitchyEditor.EditWindows
|
||||
let regionMin = winPos + (Vector2)ImGui.GetWindowContentRegionMin();
|
||||
let regionMax = winPos + (Vector2)ImGui.GetWindowContentRegionMax();
|
||||
|
||||
ImGui.DrawRect((.)regionMin, (.)regionMax, .(0, 255, 0));
|
||||
|
||||
Vector2 newMousePos = mousePos;
|
||||
|
||||
if (mousePos.X < regionMin.X)
|
||||
if (mousePos.X < regionMin.X + 1)
|
||||
{
|
||||
newMousePos.X = regionMax.X - 1;
|
||||
newMousePos.X = regionMax.X - 2;
|
||||
}
|
||||
else if (mousePos.X > regionMax.X - 1)
|
||||
{
|
||||
newMousePos.X = regionMin.X + 1;
|
||||
newMousePos.X = regionMin.X + 2;
|
||||
}
|
||||
|
||||
if (mousePos.Y < regionMin.Y)
|
||||
if (mousePos.Y < regionMin.Y + 1)
|
||||
{
|
||||
newMousePos.Y = regionMax.Y - 1;
|
||||
newMousePos.Y = regionMax.Y - 100;
|
||||
}
|
||||
else if (mousePos.Y > regionMax.Y - 1)
|
||||
{
|
||||
newMousePos.Y = regionMin.Y + 1;
|
||||
newMousePos.Y = regionMin.Y + 10;
|
||||
}
|
||||
|
||||
if (newMousePos != mousePos)
|
||||
@@ -193,8 +197,8 @@ namespace GlitchyEditor.EditWindows
|
||||
{
|
||||
Vector2 relativeMouse = (Vector2)ImGui.GetMousePos() - (Vector2)ImGui.GetItemRectMin();
|
||||
|
||||
int rtWidth = _editor.CurrentScene.[Friend]_compositeTarget.Width;
|
||||
int rtHeight = _editor.CurrentScene.[Friend]_compositeTarget.Height;
|
||||
int rtWidth = _editor.EditorSceneRenderer.CompositeTarget.Width;
|
||||
int rtHeight = _editor.EditorSceneRenderer.CompositeTarget.Height;
|
||||
|
||||
if (Input.IsMouseButtonPressing(.LeftButton) &&
|
||||
ImGui.IsWindowHovered() && !gizmoUsed && !_editor.CurrentCamera.InUse &&
|
||||
@@ -204,7 +208,7 @@ namespace GlitchyEditor.EditWindows
|
||||
{
|
||||
uint32 id = uint32.MaxValue;
|
||||
|
||||
_editor.CurrentScene.[Friend]_compositeTarget.GetData<uint32>(&id, 1, (.)relativeMouse.X, (.)relativeMouse.Y, 1, 1);
|
||||
_editor.EditorSceneRenderer.CompositeTarget.GetData<uint32>(&id, 1, (.)relativeMouse.X, (.)relativeMouse.Y, 1, 1);
|
||||
|
||||
SelectionChanged = true;
|
||||
SelectedEntityId = id;
|
||||
@@ -301,11 +301,11 @@ namespace GlitchyEditor.EditWindows
|
||||
{
|
||||
String name = null;
|
||||
|
||||
var nameComponent = tree.Value.GetComponent<DebugNameComponent>();
|
||||
var nameComponent = tree.Value.GetComponent<NameComponent>();
|
||||
|
||||
if(nameComponent != null)
|
||||
{
|
||||
name = nameComponent.DebugName;
|
||||
name = scope:: .(nameComponent.Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -501,13 +501,13 @@ namespace GlitchyEditor.EditWindows
|
||||
{
|
||||
Entity entity = .(entityId, _scene);
|
||||
|
||||
String name = null;
|
||||
StringView name = null;
|
||||
|
||||
var nameComponent = entity.GetComponent<DebugNameComponent>();
|
||||
var nameComponent = entity.GetComponent<NameComponent>();
|
||||
|
||||
if(nameComponent != null)
|
||||
{
|
||||
name = nameComponent.DebugName;
|
||||
name = nameComponent.Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
using System;
|
||||
using ImGui;
|
||||
using GlitchyEngine.Renderer;
|
||||
using GlitchyEngine.Math;
|
||||
using GlitchyEngine;
|
||||
using GlitchyEngine.World;
|
||||
using ImGuizmo;
|
||||
using GlitchyEngine.Events;
|
||||
|
||||
namespace GlitchyEditor.EditWindows
|
||||
{
|
||||
class GameViewportWindow : EditorWindow
|
||||
{
|
||||
public const String s_WindowTitle = "Game";
|
||||
|
||||
private ImGui.Vec2 _oldViewportSize = .(100, 100);
|
||||
private bool _viewPortChanged;
|
||||
|
||||
private bool _visible;
|
||||
|
||||
private RenderTargetGroup _renderTarget ~ _?.ReleaseRef();
|
||||
|
||||
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
|
||||
{
|
||||
get => _renderTarget;
|
||||
set
|
||||
{
|
||||
if(_renderTarget == value)
|
||||
return;
|
||||
|
||||
SetReference!(_renderTarget, value);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Visible => _visible;
|
||||
|
||||
public this(Editor editor)
|
||||
{
|
||||
_editor = editor;
|
||||
}
|
||||
|
||||
protected override void InternalShow()
|
||||
{
|
||||
ImGui.PushStyleVar(.WindowPadding, ImGui.Vec2(1, 1));
|
||||
defer ImGui.PopStyleVar();
|
||||
|
||||
if(!ImGui.Begin(s_WindowTitle, &_open, .NoScrollbar | .MenuBar))
|
||||
{
|
||||
ImGui.End();
|
||||
|
||||
_visible = false;
|
||||
return;
|
||||
}
|
||||
|
||||
_visible = true;
|
||||
|
||||
let viewportSize = ImGui.GetContentRegionAvail();
|
||||
|
||||
if(ImGui.IsWindowHovered() && Input.IsMouseButtonPressing(.RightButton))
|
||||
{
|
||||
let currentWindow = ImGui.GetCurrentWindow();
|
||||
ImGui.FocusWindow(currentWindow);
|
||||
}
|
||||
|
||||
_hasFocus = ImGui.IsWindowFocused();
|
||||
|
||||
if(_renderTarget != null)
|
||||
{
|
||||
ImGui.Image(_renderTarget.GetViewBinding(0), viewportSize);
|
||||
}
|
||||
|
||||
ImGui.End();
|
||||
|
||||
if(_oldViewportSize != viewportSize)
|
||||
{
|
||||
ViewportSizeChanged.Invoke(this, (Vector2)viewportSize);
|
||||
_viewPortChanged = true;
|
||||
_oldViewportSize = viewportSize;
|
||||
}
|
||||
}
|
||||
|
||||
/// Provides the ImGui Drop target and handles dropped payload.
|
||||
private void HandleDropTarget()
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,8 @@ namespace GlitchyEditor.EditWindows;
|
||||
|
||||
class PropertiesWindow : EditorWindow
|
||||
{
|
||||
public const String s_WindowTitle = "Properties";
|
||||
|
||||
private AssetPropertiesEditor _currentPropertiesEditor ~ delete _;
|
||||
|
||||
private bool _lockCurrentAsset;
|
||||
@@ -18,7 +20,7 @@ class PropertiesWindow : EditorWindow
|
||||
|
||||
private append String _selectedFileName = .();
|
||||
|
||||
private Asset _currentAsset ~ _?.ReleaseRef();
|
||||
private AssetHandle _currentAssetHandle;
|
||||
|
||||
public this(Editor editor)
|
||||
{
|
||||
@@ -28,7 +30,7 @@ class PropertiesWindow : EditorWindow
|
||||
protected override void InternalShow()
|
||||
{
|
||||
defer { ImGui.End(); }
|
||||
if(!ImGui.Begin("Properties", &_open, .None))
|
||||
if(!ImGui.Begin(s_WindowTitle, &_open, .None))
|
||||
return;
|
||||
|
||||
// TODO: make a little button in title bar?
|
||||
@@ -74,11 +76,12 @@ class PropertiesWindow : EditorWindow
|
||||
if (assetFile == null)
|
||||
return;
|
||||
|
||||
Asset asset = _editor.ContentManager.GetAsset(null, _currentAssetHandle);
|
||||
|
||||
// We need the actual asset for preview and sometimes for editing
|
||||
if (_currentAsset?.Identifier != assetFile.Identifier)
|
||||
if (asset?.Identifier != assetFile.Identifier)
|
||||
{
|
||||
_currentAsset?.ReleaseRef();
|
||||
_currentAsset = _editor.ContentManager.LoadAsset(assetFile.Identifier);
|
||||
_currentAssetHandle = _editor.ContentManager.LoadAsset(assetFile.Identifier);
|
||||
}
|
||||
|
||||
// TODO: allow changing AssetLoader
|
||||
@@ -106,7 +109,8 @@ class PropertiesWindow : EditorWindow
|
||||
|
||||
if (ImGui.Button("Save Asset"))
|
||||
{
|
||||
_editor.ContentManager.SaveAsset(_currentAsset);
|
||||
Asset asset = _editor.ContentManager.GetAsset(null, _currentAssetHandle);
|
||||
_editor.ContentManager.SaveAsset(asset);
|
||||
}
|
||||
|
||||
if (!assetFile.AssetConfig.Config.Changed)
|
||||
|
||||
@@ -17,7 +17,8 @@ namespace GlitchyEditor
|
||||
|
||||
private EntityHierarchyWindow _entityHierarchyWindow ~ delete _;
|
||||
private ComponentEditWindow _componentEditWindow ~ delete _;
|
||||
private SceneViewportWindow _sceneViewportWindow~ delete _;
|
||||
private EditorViewportWindow _sceneViewportWindow ~ delete _;
|
||||
private GameViewportWindow _gameViewportWindow ~ delete _;
|
||||
private ContentBrowserWindow _contentBrowserWindow ~ delete _;
|
||||
private PropertiesWindow _propertiesWindow ~ delete _;
|
||||
|
||||
@@ -26,6 +27,9 @@ namespace GlitchyEditor
|
||||
get => _scene;
|
||||
set
|
||||
{
|
||||
if (_scene == value)
|
||||
return;
|
||||
|
||||
_scene = value;
|
||||
_entityHierarchyWindow.SetContext(_scene);
|
||||
}
|
||||
@@ -35,7 +39,8 @@ namespace GlitchyEditor
|
||||
|
||||
public EntityHierarchyWindow EntityHierarchyWindow => _entityHierarchyWindow;
|
||||
public ComponentEditWindow ComponentEditWindow => _componentEditWindow;
|
||||
public SceneViewportWindow SceneViewportWindow => _sceneViewportWindow;
|
||||
public EditorViewportWindow SceneViewportWindow => _sceneViewportWindow;
|
||||
public GameViewportWindow GameViewportWindow => _gameViewportWindow;
|
||||
public ContentBrowserWindow ContentBrowserWindow => _contentBrowserWindow;
|
||||
public PropertiesWindow PropertiesWindow => _propertiesWindow;
|
||||
|
||||
@@ -43,6 +48,9 @@ namespace GlitchyEditor
|
||||
|
||||
public Event<EventHandler<StringView>> RequestOpenScene ~ _.Dispose();
|
||||
|
||||
public SceneRenderer GameSceneRenderer {get; set;}
|
||||
public SceneRenderer EditorSceneRenderer {get; set;}
|
||||
|
||||
/// Creates a new editor for the given world
|
||||
public this(Scene scene, EditorContentManager contentManager)
|
||||
{
|
||||
@@ -54,7 +62,8 @@ namespace GlitchyEditor
|
||||
|
||||
private void InitWindows()
|
||||
{
|
||||
_sceneViewportWindow = new SceneViewportWindow(this);
|
||||
_sceneViewportWindow = new EditorViewportWindow(this);
|
||||
_gameViewportWindow = new GameViewportWindow(this);
|
||||
_entityHierarchyWindow = new EntityHierarchyWindow(this, _scene);
|
||||
_componentEditWindow = new ComponentEditWindow(_entityHierarchyWindow);
|
||||
_contentBrowserWindow = new ContentBrowserWindow((.)Application.Get().ContentManager);
|
||||
@@ -64,6 +73,7 @@ namespace GlitchyEditor
|
||||
public void Update()
|
||||
{
|
||||
_sceneViewportWindow.Show();
|
||||
_gameViewportWindow.Show();
|
||||
_entityHierarchyWindow.Show();
|
||||
_componentEditWindow.Show();
|
||||
_contentBrowserWindow.Show();
|
||||
|
||||
@@ -8,71 +8,11 @@ using GlitchyEngine.Content;
|
||||
using GlitchyEditor.Assets;
|
||||
using GlitchyEngine;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using internal GlitchyEngine.Content.Asset;
|
||||
|
||||
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 = .();
|
||||
@@ -81,15 +21,20 @@ class EditorContentManager : IContentManager
|
||||
|
||||
//private append List<String> _identifiers = .() ~ _.ClearAndDeleteItems();
|
||||
|
||||
private append Dictionary<StringView, Asset> _loadedAssets = .(); // Check if all resources are unloaded
|
||||
private append Dictionary<StringView, AssetHandle> _identiferToHandle = .(); // TODO: Check if all resources are unloaded
|
||||
|
||||
private append Dictionary<AssetHandle, Asset> _handleToAsset = .();
|
||||
|
||||
private append AssetHierarchy _assetHierarchy = .(this);
|
||||
|
||||
public AssetHierarchy AssetHierarchy => _assetHierarchy;
|
||||
|
||||
private append List<AssetHandle> _reloadQueue = .();
|
||||
|
||||
public this()
|
||||
{
|
||||
_assetHierarchy.OnFileContentChanged.Add(new => OnFileContentChanged);
|
||||
_assetHierarchy.OnFileRenamed.Add(new => OnFileRenamed);
|
||||
}
|
||||
|
||||
public ~this()
|
||||
@@ -99,46 +44,24 @@ class EditorContentManager : IContentManager
|
||||
|
||||
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;
|
||||
_reloadQueue.Add(assetNode.AssetFile.LoadedAsset.Handle);
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(neededAssetLoaderName))
|
||||
public void OnFileRenamed(AssetNode assetNode, StringView oldIdentifier)
|
||||
{
|
||||
// Asset isn't loaded so we don't need to reload it.
|
||||
if (assetNode.AssetFile.LoadedAsset == null)
|
||||
return;
|
||||
|
||||
IAssetLoader assetLoader = null;
|
||||
Asset asset = assetNode.AssetFile.LoadedAsset;
|
||||
|
||||
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;
|
||||
}
|
||||
_identiferToHandle.Remove(oldIdentifier);
|
||||
asset.Identifier = assetNode.AssetFile.Identifier;
|
||||
_identiferToHandle.Add(asset.Identifier, asset.Handle);
|
||||
}
|
||||
|
||||
public void SetContentDirectory(StringView contentDirectory)
|
||||
@@ -152,9 +75,54 @@ class EditorContentManager : IContentManager
|
||||
|
||||
public void Update()
|
||||
{
|
||||
SwapInLoadedAssets();
|
||||
|
||||
if (!_reloadQueue.IsEmpty)
|
||||
{
|
||||
for (AssetHandle handle in _reloadQueue)
|
||||
{
|
||||
ReloadAsset(handle);
|
||||
}
|
||||
_reloadQueue.Clear();
|
||||
}
|
||||
|
||||
_assetHierarchy.Update();
|
||||
}
|
||||
|
||||
/// Replaces placeholders with the loaded assets
|
||||
private void SwapInLoadedAssets()
|
||||
{
|
||||
// Don't take the lock if we have nothing to do.
|
||||
if (_finishedEntries.Count == 0)
|
||||
return;
|
||||
|
||||
using (_finishedEntriesLock.Enter())
|
||||
{
|
||||
while (_finishedEntries.Count > 0)
|
||||
{
|
||||
let (placeholder, asset) = _finishedEntries[0];
|
||||
|
||||
delete placeholder.LoadingTask;
|
||||
|
||||
if (asset == null)
|
||||
placeholder.PlaceholderType = .Error;
|
||||
else
|
||||
{
|
||||
// TODO: I'm not sure whether AssetFiles are guaranteed to persist.
|
||||
// Get the reference here because placeholder wont survive SwapAsset.
|
||||
AssetFile file = placeholder.AssetFile;
|
||||
file.[Friend]_loadedAsset = asset;
|
||||
|
||||
SwapAsset(placeholder, asset);
|
||||
// SwapAsset increases RefCount, but this scope also holds a reference.
|
||||
asset.ReleaseRef();
|
||||
}
|
||||
|
||||
_finishedEntries.RemoveAtFast(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IAssetLoader GetDefaultAssetLoader(StringView fileExtension)
|
||||
{
|
||||
if (_defaultAssetLoaders.TryGetValue(fileExtension, let value))
|
||||
@@ -174,9 +142,11 @@ class EditorContentManager : IContentManager
|
||||
|
||||
public void RegisterAssetLoader<T>() where T : new, class, IAssetLoader
|
||||
{
|
||||
//Log.EngineLogger.AssertDebug(!_assetLoaders.Any((l) => l.GetType() == typeof(T)), "Asset loader already registered.");
|
||||
// Log.EngineLogger.AssertDebug(!_assetLoaders.Any((l) => l.GetType() == typeof(T)), "Asset loader already registered.");
|
||||
|
||||
_assetLoaders.Add(new T());
|
||||
T assetLoader = new T();
|
||||
|
||||
_assetLoaders.Add(assetLoader);
|
||||
|
||||
for (StringView ext in T.FileExtensions)
|
||||
_supportedExtensions.Add(new String(ext));
|
||||
@@ -237,99 +207,230 @@ class EditorContentManager : IContentManager
|
||||
|
||||
public bool IsLoaded(StringView identifier)
|
||||
{
|
||||
return _loadedAssets.ContainsKey(identifier);
|
||||
return _identiferToHandle.ContainsKey(identifier);
|
||||
}
|
||||
|
||||
public Asset LoadAsset(StringView identifier)
|
||||
public Asset GetAsset(Type assetType, AssetHandle handle)
|
||||
{
|
||||
if (_loadedAssets.TryGetValue(identifier, let asset))
|
||||
Asset asset = null;
|
||||
|
||||
_handleToAsset.TryGetValue(handle, out asset);
|
||||
|
||||
if (var placeholder = asset as PlaceholderAsset)
|
||||
{
|
||||
return asset..AddRef();
|
||||
if (placeholder.PlaceholderType == .Loading)
|
||||
return placeholder.AssetLoader.GetPlaceholderAsset(assetType);
|
||||
else if (placeholder.PlaceholderType == .Error)
|
||||
return placeholder.AssetLoader.GetErrorAsset(assetType);
|
||||
}
|
||||
|
||||
// Find subasset name
|
||||
int poundIndex = identifier.IndexOf('#');
|
||||
if (assetType == null)
|
||||
{
|
||||
return asset;
|
||||
}
|
||||
else if (asset?.GetType().IsSubtypeOf(assetType) ?? false)
|
||||
{
|
||||
return asset;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: get default asset
|
||||
|
||||
StringView resourceName = poundIndex == -1 ? identifier : identifier.Substring(0, poundIndex);
|
||||
StringView? subassetName = identifier.Substring(poundIndex + 1);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
String filePath = scope String(resourceName.Length + _contentDirectory.Length + 2);
|
||||
Path.Combine(filePath, _contentDirectory, resourceName);
|
||||
private void ReloadAsset(AssetHandle handle)
|
||||
{
|
||||
Debug.Profiler.ProfileResourceFunction!();
|
||||
|
||||
Path.Fixup(filePath);
|
||||
Asset oldAsset = null;
|
||||
|
||||
//filePath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
|
||||
if (!_handleToAsset.TryGetValue(handle, out oldAsset))
|
||||
{
|
||||
Log.EngineLogger.Error("Can't reload! No asset exists for handle.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Log.EngineLogger.AssertDebug(oldAsset != null);
|
||||
|
||||
StringView oldIdentifier = oldAsset.Identifier;
|
||||
|
||||
GetResourceAndSubassetName(oldIdentifier, let resourceName, let subassetName);
|
||||
|
||||
String filePath = scope .();
|
||||
GetResourceFilePath(resourceName, filePath);
|
||||
|
||||
Result<TreeNode<AssetNode>> resultNode = AssetHierarchy.GetNodeFromPath(filePath);
|
||||
|
||||
if (resultNode case .Err)
|
||||
{
|
||||
Log.EngineLogger.Error($"Could not find asset \"{filePath}\".");
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
AssetFile file = resultNode->Value.AssetFile;
|
||||
|
||||
IAssetLoader assetLoader = null;
|
||||
IAssetLoader assetLoader = GetAssetLoader(file);
|
||||
|
||||
String loaderTypeName = scope .(128);
|
||||
Stream stream = GetStream(filePath);
|
||||
|
||||
for (IAssetLoader loader in _assetLoaders)
|
||||
// TODO: Add async loading!
|
||||
Asset loadedAsset = assetLoader.LoadAsset(stream, file.AssetConfig.Config, resourceName, subassetName, this);
|
||||
|
||||
delete stream;
|
||||
|
||||
if (loadedAsset == null)
|
||||
return;
|
||||
|
||||
file.[Friend]_loadedAsset = loadedAsset;
|
||||
|
||||
SwapAsset(oldAsset, loadedAsset);
|
||||
// SwapAsset increases RefCount, but this scope also holds a reference.
|
||||
loadedAsset.ReleaseRef();
|
||||
}
|
||||
|
||||
/// Returns the resource name and, if it exists, the subasset name.
|
||||
private void GetResourceAndSubassetName(StringView identifier, out StringView resourceName, out StringView? subassetName)
|
||||
{
|
||||
loader.GetType().GetName(loaderTypeName..Clear());
|
||||
int poundIndex = identifier.IndexOf('#');
|
||||
|
||||
if (loaderTypeName == file.AssetConfig.AssetLoader)
|
||||
resourceName = (poundIndex != -1) ? identifier.Substring(0, poundIndex) : identifier;
|
||||
subassetName = (poundIndex != -1) ? identifier.Substring(poundIndex + 1) : null;
|
||||
}
|
||||
|
||||
private void GetResourceFilePath(StringView resourceName, String filePath)
|
||||
{
|
||||
assetLoader = loader;
|
||||
break;
|
||||
Path.Combine(filePath, _contentDirectory, resourceName);
|
||||
|
||||
Path.Fixup(filePath);
|
||||
}
|
||||
|
||||
private enum PlaceholderType
|
||||
{
|
||||
Loading,
|
||||
Error
|
||||
}
|
||||
|
||||
private class PlaceholderAsset : Asset
|
||||
{
|
||||
public AssetFile AssetFile {get; private set;}
|
||||
public Task LoadingTask {get;set;}
|
||||
public IAssetLoader AssetLoader {get; private set;}
|
||||
public PlaceholderType PlaceholderType {get; set;}
|
||||
|
||||
public this(AssetFile assetFile, IAssetLoader assetLoader, PlaceholderType placeholderType)
|
||||
{
|
||||
AssetFile = assetFile;
|
||||
AssetLoader = assetLoader;
|
||||
PlaceholderType = placeholderType;
|
||||
}
|
||||
}
|
||||
|
||||
private append Monitor _finishedEntriesLock = .();
|
||||
private append List<(PlaceholderAsset placeholder, Asset newAsset)> _finishedEntries = .();
|
||||
|
||||
private class MissingAsset : Asset {}
|
||||
|
||||
public AssetHandle LoadAsset(StringView identifier, bool blocking = false)
|
||||
{
|
||||
Debug.Profiler.ProfileResourceFunction!();
|
||||
|
||||
// Todo: How strict should we be on paths?
|
||||
String fixedIdentifier = scope String(identifier);
|
||||
AssetIdentifier.Fixup(fixedIdentifier);
|
||||
|
||||
if (_identiferToHandle.TryGetValue(fixedIdentifier, let asset))
|
||||
return asset;
|
||||
|
||||
GetResourceAndSubassetName(fixedIdentifier, let resourceName, let subassetName);
|
||||
|
||||
String filePath = scope .();
|
||||
GetResourceFilePath(resourceName, filePath);
|
||||
|
||||
Result<TreeNode<AssetNode>> resultNode = AssetHierarchy.GetNodeFromPath(filePath);
|
||||
|
||||
if (resultNode case .Err)
|
||||
{
|
||||
Log.EngineLogger.Error($"Could not find asset \"{filePath}\".");
|
||||
return .Invalid;
|
||||
}
|
||||
|
||||
AssetFile file = resultNode->Value.AssetFile;
|
||||
|
||||
IAssetLoader assetLoader = GetAssetLoader(file);
|
||||
|
||||
// TODO: what are we supposed to do if we don't find a loader? Sure not crash...
|
||||
Log.EngineLogger.AssertDebug(assetLoader != null);
|
||||
|
||||
Asset loadedAsset;
|
||||
|
||||
// TODO: Support lazy loading for all asset types
|
||||
if (!(assetLoader is EditorTextureAssetLoader) || blocking)
|
||||
{
|
||||
Stream stream = GetStream(filePath);
|
||||
|
||||
loadedAsset = assetLoader.LoadAsset(stream, file.AssetConfig.Config, resourceName, subassetName, this);
|
||||
|
||||
delete stream;
|
||||
|
||||
if (loadedAsset == null)
|
||||
return .Invalid;
|
||||
}
|
||||
else
|
||||
{
|
||||
PlaceholderAsset placeholder = new PlaceholderAsset(file, assetLoader, .Loading);
|
||||
|
||||
String filePath2 = new String(filePath);
|
||||
String newResourceName = new String(resourceName);
|
||||
String newSesourceName = subassetName == null ? null : new String(subassetName.Value);
|
||||
|
||||
placeholder.LoadingTask = new Task(new () => {
|
||||
AsyncLoadAsset(placeholder, filePath2, assetLoader, file,
|
||||
newResourceName, newSesourceName);
|
||||
});
|
||||
|
||||
ThreadPool.QueueUserWorkItem(placeholder.LoadingTask);
|
||||
|
||||
loadedAsset = placeholder;
|
||||
}
|
||||
|
||||
loadedAsset.Identifier = fixedIdentifier;
|
||||
AssetHandle handle = ManageAsset(loadedAsset);
|
||||
// ManageAsset increases RefCount, but this scope also holds a reference.
|
||||
loadedAsset.ReleaseRef();
|
||||
|
||||
// Add to Identifier -> Handle map
|
||||
_identiferToHandle.Add(loadedAsset.Identifier, handle);
|
||||
|
||||
file.[Friend]_loadedAsset = loadedAsset;
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
private void AsyncLoadAsset(PlaceholderAsset placeholder, String filePath, IAssetLoader assetLoader, AssetFile file, String resourceName, String subassetName)
|
||||
{
|
||||
Debug.Profiler.ProfileResourceFunction!();
|
||||
|
||||
Stream stream = GetStream(filePath);
|
||||
|
||||
Asset loadedAsset = assetLoader.LoadAsset(stream, file.AssetConfig.Config, resourceName, subassetName, this);
|
||||
|
||||
delete stream;
|
||||
delete filePath;
|
||||
delete resourceName;
|
||||
delete subassetName;
|
||||
|
||||
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;
|
||||
using (_finishedEntriesLock.Enter())
|
||||
{
|
||||
_finishedEntries.Add((placeholder, loadedAsset));
|
||||
}
|
||||
}
|
||||
|
||||
/// Saves the asset.
|
||||
public Result<void> SaveAsset(Asset asset)
|
||||
/// Gets the asset loader that has to be used for the given file.
|
||||
IAssetLoader GetAssetLoader(AssetFile file)
|
||||
{
|
||||
// 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);
|
||||
@@ -345,24 +446,67 @@ class EditorContentManager : IContentManager
|
||||
}
|
||||
}
|
||||
|
||||
return assetLoader;
|
||||
}
|
||||
|
||||
public enum SaveAssetError
|
||||
{
|
||||
case Unknown;
|
||||
case Unsavable;
|
||||
case PathNotFound;
|
||||
}
|
||||
|
||||
/// Saves the asset.
|
||||
public Result<void, SaveAssetError> SaveAsset(Asset asset)
|
||||
{
|
||||
if (asset == null)
|
||||
return .Err(.Unknown);
|
||||
|
||||
if (asset.Identifier.IsWhiteSpace)
|
||||
return .Err(.Unsavable);
|
||||
|
||||
GetResourceAndSubassetName(asset.Identifier, let resourceName, let subassetName);
|
||||
|
||||
if (subassetName != null)
|
||||
{
|
||||
// TODO: should this ever be allowed? Couldn't we just save the entire asset?
|
||||
// Would this ever be necessary?
|
||||
Runtime.NotImplemented("Saving subassets is not currently allowed");
|
||||
}
|
||||
|
||||
String filePath = scope String();
|
||||
GetResourceFilePath(resourceName, filePath);
|
||||
|
||||
Result<TreeNode<AssetNode>> assetNode = AssetHierarchy.GetNodeFromPath(filePath);
|
||||
|
||||
if (assetNode case .Err)
|
||||
return .Err(.PathNotFound);
|
||||
|
||||
AssetFile file = assetNode.Get()->AssetFile;
|
||||
|
||||
IAssetLoader assetLoader = GetAssetLoader(file);
|
||||
|
||||
IAssetSaver assetSaver = assetLoader as IAssetSaver;
|
||||
|
||||
if (assetSaver == null)
|
||||
{
|
||||
Log.EngineLogger.Error("The asset loader can't save!");
|
||||
return .Err;
|
||||
return .Err(.Unsavable);
|
||||
}
|
||||
|
||||
Stream stream = OpenStream(filePath, false, true);
|
||||
Stream stream = OpenStream(filePath, false);
|
||||
|
||||
assetSaver.EditorSaveAsset(stream, asset, file.AssetConfig.Config, resourceName, subassetName, this);
|
||||
|
||||
// Trim off the end of the file.
|
||||
stream.SetLength(stream.Position);
|
||||
|
||||
delete stream;
|
||||
|
||||
return .Ok;
|
||||
}
|
||||
|
||||
private Stream OpenStream(StringView assetIdentifier, bool openOnly, bool truncate = false)
|
||||
private Stream OpenStream(StringView assetIdentifier, bool openOnly)
|
||||
{
|
||||
var assetIdentifier;
|
||||
|
||||
@@ -378,9 +522,6 @@ class EditorContentManager : IContentManager
|
||||
|
||||
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)
|
||||
@@ -413,37 +554,86 @@ class EditorContentManager : IContentManager
|
||||
return fs;*/
|
||||
}
|
||||
|
||||
public void ManageAsset(Asset asset)
|
||||
public AssetHandle ManageAsset(Asset asset)
|
||||
{
|
||||
_loadedAssets.Add(asset.Identifier, asset);
|
||||
asset.[Friend]_contentManager = this;
|
||||
Log.EngineLogger.AssertDebug(asset.Handle == .Invalid, "Asset is already managed.");
|
||||
Log.EngineLogger.AssertDebug(asset.ContentManager == null, "Asset is already managed.");
|
||||
|
||||
AssetHandle handle = .();
|
||||
|
||||
// Generate until we find a unique key (shouldn't happen too often)
|
||||
while (handle.IsInvalid || _handleToAsset.ContainsKey(handle))
|
||||
{
|
||||
handle = .();
|
||||
Log.EngineLogger.Trace("Handle was invalid or already taken.");
|
||||
// TODO: perhaps test how often this happens.
|
||||
// If this happens too often we could use a different random generator
|
||||
}
|
||||
|
||||
public void UnmanageAsset(Asset asset)
|
||||
//_handles.Add(asset.Identifier, handle);
|
||||
_handleToAsset.Add(handle, asset);
|
||||
|
||||
asset.[Friend]_contentManager = this;
|
||||
asset.[Friend]_handle = handle;
|
||||
asset.AddRef();
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
private void SwapAsset(Asset oldAsset, Asset newAsset)
|
||||
{
|
||||
_loadedAssets.Remove(asset.Identifier);
|
||||
newAsset.Identifier = oldAsset.Identifier;
|
||||
newAsset._contentManager = this;
|
||||
newAsset._handle = oldAsset.Handle;
|
||||
|
||||
_handleToAsset[oldAsset.Handle] = newAsset;
|
||||
|
||||
if (_identiferToHandle.ContainsKey(oldAsset.Identifier))
|
||||
{
|
||||
_identiferToHandle.Remove(oldAsset.Identifier);
|
||||
_identiferToHandle.Add(newAsset.Identifier, newAsset.Handle);
|
||||
}
|
||||
|
||||
newAsset.AddRef();
|
||||
oldAsset.ReleaseRef();
|
||||
}
|
||||
|
||||
public void UnmanageAsset(AssetHandle handle)
|
||||
{
|
||||
Log.EngineLogger.AssertDebug(_handleToAsset.ContainsKey(handle), "Handle doesn't correspond to an asset.");
|
||||
|
||||
Asset asset = _handleToAsset[handle];
|
||||
|
||||
if (_identiferToHandle.ContainsKey(asset.Identifier))
|
||||
_identiferToHandle.Remove(asset.Identifier);
|
||||
|
||||
_handleToAsset.Remove(handle);
|
||||
asset.[Friend]_contentManager = null;
|
||||
|
||||
asset.ReleaseRef();
|
||||
}
|
||||
|
||||
/// This will unregister all assets from this content manager.
|
||||
/// Note: This will not release any assets.
|
||||
private void UnmanageAllAssets()
|
||||
{
|
||||
for (let (_, asset) in _loadedAssets)
|
||||
for (let (handle, _) in _handleToAsset)
|
||||
{
|
||||
UnmanageAsset(asset);
|
||||
UnmanageAsset(handle);
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateAssetIdentifier(Asset asset, StringView oldIdentifier, StringView newIdentifier)
|
||||
public void AssetMoved(Asset asset, StringView oldIdentifier, StringView newIdentifier)
|
||||
{
|
||||
Runtime.NotImplemented();
|
||||
|
||||
if (oldIdentifier == newIdentifier)
|
||||
return;
|
||||
|
||||
Log.EngineLogger.Assert(_loadedAssets.ContainsKey(newIdentifier), "An asset with the same identifier is already managed by this content manager.");
|
||||
Log.EngineLogger.Assert(_identiferToHandle.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);
|
||||
//UnmanageAsset(asset);
|
||||
//ManageAsset(asset);
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,13 @@ using System;
|
||||
using GlitchyEngine.Renderer;
|
||||
using GlitchyEngine.Math;
|
||||
using GlitchyEngine;
|
||||
using GlitchyEngine.Content;
|
||||
|
||||
namespace GlitchyEditor
|
||||
{
|
||||
class EditorIcons : RefCounted
|
||||
{
|
||||
Texture2D _texture ~ _.ReleaseRef();
|
||||
AssetHandle<Texture2D> _texture;
|
||||
|
||||
public SubTexture2D DirectionalLight ~ _.ReleaseRef();
|
||||
public SubTexture2D Camera ~ _.ReleaseRef();
|
||||
@@ -15,16 +16,18 @@ namespace GlitchyEditor
|
||||
public SubTexture2D File ~ _.ReleaseRef();
|
||||
public SubTexture2D Play ~ _.ReleaseRef();
|
||||
public SubTexture2D Stop ~ _.ReleaseRef();
|
||||
public SubTexture2D Simulate ~ _.ReleaseRef();
|
||||
public SubTexture2D Pause ~ _.ReleaseRef();
|
||||
|
||||
public SamplerState SamplerState
|
||||
{
|
||||
get => _texture.SamplerState;
|
||||
set => _texture.SamplerState = value;
|
||||
get => _texture.Get().SamplerState;
|
||||
set => _texture.Get().SamplerState = value;
|
||||
}
|
||||
|
||||
public this(String texturePath, Vector2 iconSize)
|
||||
{
|
||||
_texture = Content.LoadAsset<Texture2D>(texturePath);//new Texture2D(texturePath);
|
||||
_texture = Content.LoadAsset(texturePath, null, true);
|
||||
|
||||
Vector2 pen = .();
|
||||
|
||||
@@ -34,6 +37,8 @@ namespace GlitchyEditor
|
||||
File = GetNextGridTexture(ref pen, iconSize);
|
||||
Play = GetNextGridTexture(ref pen, iconSize);
|
||||
Stop = GetNextGridTexture(ref pen, iconSize);
|
||||
Simulate = GetNextGridTexture(ref pen, iconSize);
|
||||
Pause = GetNextGridTexture(ref pen, iconSize);
|
||||
}
|
||||
|
||||
private SubTexture2D GetNextGridTexture(ref Vector2 pen, Vector2 iconSize)
|
||||
|
||||
+320
-256
@@ -18,67 +18,84 @@ namespace GlitchyEditor
|
||||
{
|
||||
class EditorLayer : Layer
|
||||
{
|
||||
enum SceneState
|
||||
{
|
||||
Edit,
|
||||
Play,
|
||||
Simulate
|
||||
}
|
||||
|
||||
RasterizerState _rasterizerState ~ _?.ReleaseRef();
|
||||
RasterizerState _rasterizerStateClockWise ~ _?.ReleaseRef();
|
||||
|
||||
// TODO: we shouldn't hold a reference to the context
|
||||
GraphicsContext _context ~ _.ReleaseRef();
|
||||
|
||||
BlendState _alphaBlendState ~ _.ReleaseRef();
|
||||
BlendState _opaqueBlendState ~ _.ReleaseRef();
|
||||
DepthStencilState _depthStencilState ~ _.ReleaseRef();
|
||||
|
||||
Scene _scene ~ delete _;
|
||||
String _sceneFilePath = new String() ~ delete _;
|
||||
/// Reference to the scene that is currently being played and worked on.
|
||||
Scene _activeScene ~ _?.ReleaseRef();
|
||||
|
||||
public String SceneFilePath
|
||||
/**
|
||||
* Referece to the editor scene.
|
||||
* We hold a reference to the editor scene because we need it in order
|
||||
* to restore the original state once we stop the game/simulation.
|
||||
* Before starting the simulation the editor scene will be copied and
|
||||
* the reference in _activeScene will be replaced with the new scene.
|
||||
*/
|
||||
Scene _editorScene ~ _?.ReleaseRef();
|
||||
|
||||
SceneRenderer _gameSceneRenderer ~ delete _;
|
||||
SceneRenderer _editorSceneRenderer ~ delete _;
|
||||
|
||||
/// Path of the current scene.
|
||||
append String _sceneFilePath = .();
|
||||
|
||||
Editor _editor ~ delete _;
|
||||
|
||||
RenderTargetGroup _cameraTarget ~ _.ReleaseRef();
|
||||
RenderTargetGroup _editorViewportTarget ~ _.ReleaseRef();
|
||||
RenderTargetGroup _gameViewportTarget ~ _.ReleaseRef();
|
||||
|
||||
SettingsWindow _settingsWindow = new .() ~ delete _;
|
||||
|
||||
EditorCamera _camera ~ _.Dispose();
|
||||
|
||||
EditorIcons _editorIcons ~ _.ReleaseRef();
|
||||
|
||||
EditorContentManager _contentManager;
|
||||
|
||||
SceneState _sceneState = .Edit;
|
||||
bool _isPaused = false;
|
||||
|
||||
/// Gets or sets the path of the current scene.
|
||||
public StringView SceneFilePath
|
||||
{
|
||||
get => _sceneFilePath;
|
||||
set
|
||||
{
|
||||
_sceneFilePath.Clear();
|
||||
|
||||
if (value != null)
|
||||
if (!value.IsWhiteSpace)
|
||||
_sceneFilePath.Append(value);
|
||||
}
|
||||
}
|
||||
|
||||
Editor _editor ~ delete _;
|
||||
|
||||
RenderTargetGroup _cameraTarget ~ _.ReleaseRef();
|
||||
RenderTargetGroup _viewportTarget ~ _.ReleaseRef();
|
||||
|
||||
SettingsWindow _settingsWindow = new .() ~ delete _;
|
||||
|
||||
EditorCamera _camera ~ _.Dispose();
|
||||
|
||||
/*Texture2D _editorIcons ~ _.ReleaseRef();
|
||||
SubTexture2D _iconDirectionalLight ~ _.ReleaseRef();
|
||||
SubTexture2D _iconCamera ~ _.ReleaseRef();*/
|
||||
|
||||
EditorIcons _editorIcons ~ _.ReleaseRef();
|
||||
|
||||
EditorContentManager _contentManager;
|
||||
|
||||
enum SceneState
|
||||
{
|
||||
Edit,
|
||||
Play,
|
||||
// Pause,
|
||||
// Simulate
|
||||
}
|
||||
|
||||
SceneState _sceneState = .Edit;
|
||||
|
||||
public this(EditorContentManager contentManager) : base("Example")
|
||||
public this(EditorContentManager contentManager) : base("Editor")
|
||||
{
|
||||
Application.Get().Window.IsVSync = false;
|
||||
|
||||
//InitContentManager();
|
||||
_contentManager = contentManager;
|
||||
|
||||
InitGraphics();
|
||||
|
||||
_scene = new Scene();
|
||||
_editorScene = new Scene();
|
||||
SetReference!(_activeScene, _editorScene);
|
||||
|
||||
_gameSceneRenderer = new SceneRenderer();
|
||||
_editorSceneRenderer = new SceneRenderer();
|
||||
|
||||
_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;
|
||||
@@ -88,31 +105,6 @@ namespace GlitchyEditor
|
||||
NewScene();
|
||||
}
|
||||
|
||||
/*private void 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");
|
||||
|
||||
// Todo: Sketchy...
|
||||
Application.Get().[Friend]_contentManager = _contentManager;
|
||||
}*/
|
||||
|
||||
private void InitGraphics()
|
||||
{
|
||||
_context = Application.Get().Window.Context..AddRef();
|
||||
@@ -141,7 +133,15 @@ namespace GlitchyEditor
|
||||
DepthTargetDescription = .(.D24_UNorm_S8_UInt)
|
||||
});
|
||||
|
||||
_viewportTarget = new RenderTargetGroup(.()
|
||||
_editorViewportTarget = new RenderTargetGroup(.()
|
||||
{
|
||||
Width = 100,
|
||||
Height = 100,
|
||||
ColorTargetDescriptions = TargetDescription[](
|
||||
.(.R8G8B8A8_UNorm))
|
||||
});
|
||||
|
||||
_gameViewportTarget = new RenderTargetGroup(.()
|
||||
{
|
||||
Width = 100,
|
||||
Height = 100,
|
||||
@@ -154,18 +154,16 @@ namespace GlitchyEditor
|
||||
|
||||
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));*/
|
||||
}
|
||||
|
||||
private void InitEditor()
|
||||
{
|
||||
_editor = new Editor(_scene, _contentManager);
|
||||
_editor.SceneViewportWindow.ViewportSizeChanged.Add(new (s, e) => ViewportSizeChanged(s, e));
|
||||
_editor = new Editor(_editorScene, _contentManager);
|
||||
_editor.SceneViewportWindow.ViewportSizeChanged.Add(new (s, e) => EditorViewportSizeChanged(s, e));
|
||||
_editor.GameViewportWindow.ViewportSizeChanged.Add(new (s, e) => GameViewportSizeChanged(s, e));
|
||||
_editor.CurrentCamera = &_camera;
|
||||
_editor.GameSceneRenderer = _gameSceneRenderer;
|
||||
_editor.EditorSceneRenderer = _editorSceneRenderer;
|
||||
|
||||
_editor.RequestOpenScene.Add(new (s, fileName) => {
|
||||
LoadSceneFile(fileName);
|
||||
@@ -174,20 +172,54 @@ namespace GlitchyEditor
|
||||
|
||||
public override void Update(GameTime gameTime)
|
||||
{
|
||||
_camera.Update(gameTime);
|
||||
Debug.Profiler.ProfileFunction!();
|
||||
|
||||
_editor.CurrentScene = _activeScene;
|
||||
|
||||
Scene.UpdateMode updateMode;
|
||||
|
||||
switch (_sceneState)
|
||||
{
|
||||
case .Edit:
|
||||
updateMode = .Editor;
|
||||
case .Play:
|
||||
updateMode = .Runtime;
|
||||
case .Simulate:
|
||||
updateMode = .Physics;
|
||||
}
|
||||
|
||||
if (_sceneState != .Edit && _isPaused)
|
||||
updateMode = .None;
|
||||
|
||||
|
||||
_activeScene.Update(gameTime, updateMode);
|
||||
|
||||
// Clear the swapchain-buffer
|
||||
RenderCommand.Clear(null, .Color | .Depth, .(0.2f, 0.2f, 0.2f), 1.0f, 0);
|
||||
|
||||
RenderCommand.Clear(_viewportTarget, .Color | .Depth, .(0.2f, 0.2f, 0.2f), 1.0f, 0);
|
||||
RenderCommand.SetBlendState(_alphaBlendState);
|
||||
RenderCommand.SetDepthStencilState(_depthStencilState);
|
||||
|
||||
if (_editor.SceneViewportWindow.Visible)
|
||||
{
|
||||
_camera.Update(gameTime);
|
||||
|
||||
_editorSceneRenderer.Scene = _activeScene;
|
||||
|
||||
RenderCommand.Clear(_editorViewportTarget, .Color | .Depth, .(0.2f, 0.2f, 0.2f), 1.0f, 0);
|
||||
_editorSceneRenderer.RenderEditor(gameTime, _camera, _editorViewportTarget, scope => DebugDraw3D, scope => DebugDraw2D);
|
||||
}
|
||||
|
||||
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);
|
||||
if (_editor.GameViewportWindow.Visible)
|
||||
{
|
||||
_gameSceneRenderer.Scene = _activeScene;
|
||||
|
||||
RenderCommand.Clear(_gameViewportTarget, .Color | .Depth, .(0.2f, 0.2f, 0.2f), 1.0f, 0);
|
||||
_gameSceneRenderer.RenderRuntime(gameTime, _gameViewportTarget);
|
||||
}
|
||||
|
||||
RenderCommand.UnbindRenderTargets();
|
||||
RenderCommand.SetRenderTarget(null, 0, true);
|
||||
@@ -226,11 +258,11 @@ namespace GlitchyEditor
|
||||
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>())
|
||||
for (var (entity, transform, camera) in _activeScene.GetEntities<TransformComponent, CameraComponent>())
|
||||
{
|
||||
if (_editor.EntityHierarchyWindow.SelectedEntities.Contains(.(entity, _scene)))
|
||||
if (_editor.EntityHierarchyWindow.SelectedEntities.Contains(.(entity, _activeScene)))
|
||||
{
|
||||
DebugRenderer.DrawViewFrustum(transform.WorldTransform, camera.Camera.Projection, _camera.Projection * _camera.View, .White);
|
||||
DebugRenderer.DrawViewFrustum(transform.WorldTransform, camera.Camera.Projection, .White);
|
||||
}
|
||||
|
||||
Matrix world = Billboard(transform.WorldTransform);
|
||||
@@ -240,9 +272,9 @@ namespace GlitchyEditor
|
||||
//Renderer2D.DrawQuad(world, _iconCamera, .White, .(0, 0, 1, 1), entity.Index);
|
||||
}
|
||||
|
||||
for (var (entity, transform, light) in _scene.[Friend]_ecsWorld.Enumerate<TransformComponent, LightComponent>())
|
||||
for (var (entity, transform, light) in _activeScene.GetEntities<TransformComponent, LightComponent>())
|
||||
{
|
||||
if (_editor.EntityHierarchyWindow.SelectedEntities.Contains(.(entity, _scene)))
|
||||
if (_editor.EntityHierarchyWindow.SelectedEntities.Contains(.(entity, _activeScene)))
|
||||
{
|
||||
Renderer.DrawRay(.Zero, .(0, 0, 20), ColorRGBA(light.SceneLight.Color, 1.0f), transform.WorldTransform);
|
||||
|
||||
@@ -258,7 +290,16 @@ namespace GlitchyEditor
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
for (var (entity, transform, collider) in _activeScene.GetEntities<TransformComponent, BoxCollider2DComponent>())
|
||||
{
|
||||
Renderer2D.DrawRect(transform.WorldTransform * Matrix.Translation(collider.Offset.X, collider.Offset.Y, 0) * Matrix.Scaling(collider.Size.X * 2, collider.Size.Y * 2, 0));
|
||||
}
|
||||
|
||||
for (var (entity, transform, collider) in _activeScene.GetEntities<TransformComponent, CircleCollider2DComponent>())
|
||||
{
|
||||
Renderer2D.DrawCircle(transform.WorldTransform * Matrix.Translation(collider.Offset.X, collider.Offset.Y, 0) * Matrix.Scaling(collider.Radius * 2), (Texture2D)null, ColorRGBA(0f, 1f, 0f), 0.01f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -287,7 +328,8 @@ namespace GlitchyEditor
|
||||
|
||||
DrawMainMenuBar();
|
||||
|
||||
_editor.SceneViewportWindow.RenderTarget = _viewportTarget;
|
||||
_editor.SceneViewportWindow.RenderTarget = _editorViewportTarget;
|
||||
_editor.GameViewportWindow.RenderTarget = _gameViewportTarget;
|
||||
|
||||
_editor.Update();
|
||||
|
||||
@@ -317,22 +359,87 @@ namespace GlitchyEditor
|
||||
|
||||
ImGui.Begin("##toolbar", null, .NoDecoration | .NoScrollbar | .NoScrollWithMouse);
|
||||
|
||||
SubTexture2D icon = _sceneState == .Edit ? _editorIcons.Play : _editorIcons.Stop;
|
||||
float padding = 2.0f;
|
||||
|
||||
float size = ImGui.GetWindowHeight() - 4.0f;
|
||||
float size = ImGui.GetWindowHeight() - 2 * padding;
|
||||
|
||||
float centerX = ImGui.GetContentRegionMax().x / 2;
|
||||
|
||||
ImGui.SameLine((ImGui.GetContentRegionMax().x / 2 - size / 2));
|
||||
|
||||
if (ImGui.ImageButton(icon, .(size, size), .Zero, .Ones, 0))
|
||||
{
|
||||
if (_sceneState == .Edit)
|
||||
EditorButtons:
|
||||
{
|
||||
// Display the buttons for edit state
|
||||
|
||||
float totalWidth = size * 3 + padding * 4;
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.SetCursorPosX(centerX - totalWidth / 2);
|
||||
|
||||
if (ImGui.ImageButton(_editorIcons.Play, .(size, size), .Zero, .Ones, 0))
|
||||
OnScenePlay();
|
||||
}
|
||||
else if (_sceneState == .Play)
|
||||
|
||||
ImGui.AttachTooltip("Play the game.");
|
||||
|
||||
ImGui.SameLine();
|
||||
|
||||
ImGui.PushID(1);
|
||||
|
||||
if (ImGui.ImageButton(_editorIcons.Simulate, .(size, size), .Zero, .Ones, 0))
|
||||
OnSceneSimulate();
|
||||
|
||||
ImGui.PopID();
|
||||
|
||||
ImGui.AttachTooltip("Enter simulation mode.\nThis only runs the physics engine.");
|
||||
|
||||
if (_isPaused)
|
||||
{
|
||||
OnSceneStop();
|
||||
ImGui.PushStyleColor(.Button, *ImGui.GetStyleColorVec4(.ButtonActive));
|
||||
|
||||
defer:EditorButtons { ImGui.PopStyleColor(); }
|
||||
}
|
||||
|
||||
ImGui.PushID(2);
|
||||
|
||||
//ImGui.SameLine(penX += size + 2 * padding);
|
||||
ImGui.SameLine();
|
||||
|
||||
if (ImGui.ImageButton(_editorIcons.Pause, .(size, size), .Zero, .Ones, 0))
|
||||
_isPaused = !_isPaused;
|
||||
|
||||
ImGui.PopID();
|
||||
|
||||
ImGui.AttachTooltip("If enabled the game or simulation will be started in paused state.");
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// Display the buttons for play/simulation state
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.SetCursorPosX(centerX - size - padding);
|
||||
|
||||
SubTexture2D pauseButtonIcon = _isPaused ? _editorIcons.Play : _editorIcons.Pause;
|
||||
|
||||
if (ImGui.ImageButton(pauseButtonIcon, .(size, size), .Zero, .Ones, 0))
|
||||
{
|
||||
if (_isPaused)
|
||||
OnSceneResume();
|
||||
else
|
||||
OnScenePause();
|
||||
}
|
||||
|
||||
ImGui.AttachTooltip(_isPaused ? "Resume" : "Pause");
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.PushID(1);
|
||||
|
||||
if (ImGui.ImageButton(_editorIcons.Stop, .(size, size), .Zero, .Ones, 0))
|
||||
OnSceneStop();
|
||||
|
||||
ImGui.PopID();
|
||||
|
||||
ImGui.AttachTooltip("Stop");
|
||||
}
|
||||
|
||||
ImGui.End();
|
||||
@@ -343,194 +450,129 @@ namespace GlitchyEditor
|
||||
|
||||
private void OnScenePlay()
|
||||
{
|
||||
_sceneState = .Play;
|
||||
_editor.SceneViewportWindow.EditorMode = false;
|
||||
_sceneState = .Play;
|
||||
|
||||
_scene.OnRuntimeStart();
|
||||
using (Scene runtimeScene = new Scene())
|
||||
{
|
||||
_editorScene.CopyTo(runtimeScene);
|
||||
|
||||
runtimeScene.OnRuntimeStart();
|
||||
|
||||
SetReference!(_activeScene, runtimeScene);
|
||||
}
|
||||
|
||||
_editor.CurrentScene = _activeScene;
|
||||
}
|
||||
|
||||
private void OnSceneSimulate()
|
||||
{
|
||||
_editor.SceneViewportWindow.EditorMode = false;
|
||||
_sceneState = .Simulate;
|
||||
|
||||
using (Scene simulationScene = new Scene())
|
||||
{
|
||||
_editorScene.CopyTo(simulationScene);
|
||||
|
||||
simulationScene.OnSimulationStart();
|
||||
|
||||
SetReference!(_activeScene, simulationScene);
|
||||
}
|
||||
|
||||
_editor.CurrentScene = _activeScene;
|
||||
}
|
||||
|
||||
private void OnScenePause()
|
||||
{
|
||||
_isPaused = true;
|
||||
}
|
||||
|
||||
private void OnSceneResume()
|
||||
{
|
||||
_isPaused = false;
|
||||
}
|
||||
|
||||
private void OnSceneStop()
|
||||
{
|
||||
_scene.OnRuntimeStop();
|
||||
if (_sceneState == .Play)
|
||||
_activeScene.OnRuntimeStop();
|
||||
else
|
||||
_activeScene.OnSimulationStop();
|
||||
|
||||
SetReference!(_activeScene, _editorScene);
|
||||
|
||||
_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);
|
||||
_editor.CurrentScene = _activeScene;
|
||||
|
||||
let light = lightNtt.AddComponent<LightComponent>();
|
||||
light.SceneLight.Illuminance = 10.0f;
|
||||
light.SceneLight.Color = .(1.0f, 0.95f, 0.8f);
|
||||
}
|
||||
_isPaused = false;
|
||||
|
||||
{
|
||||
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);
|
||||
}*/
|
||||
/*
|
||||
* Update the viewport size because if the game windows size changed in
|
||||
* "Game"-mode the updated aspect-rations will reset once we go back
|
||||
* into "Editor"-mode (because Game-Mode works on a copy of the scene).
|
||||
*/
|
||||
GameViewportSizeChanged(null, _editor.GameViewportWindow.ViewportSize);
|
||||
}
|
||||
|
||||
/// Creates a new scene.
|
||||
private void NewScene()
|
||||
{
|
||||
OnSceneStop();
|
||||
|
||||
SceneFilePath = null;
|
||||
|
||||
delete _scene;
|
||||
_scene = new Scene();
|
||||
_editor.CurrentScene = _scene;
|
||||
var vpSize = _editor.SceneViewportWindow.ViewportSize;
|
||||
_scene.OnViewportResize((.)vpSize.X, (.)vpSize.Y);
|
||||
Scene newScene = new Scene();
|
||||
|
||||
_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
|
||||
// Create a default camera
|
||||
{
|
||||
let lightNtt = _scene.CreateEntity("Light");
|
||||
let transform = lightNtt.Transform;
|
||||
transform.Position = .(0, 0, 0);
|
||||
transform.RotationEuler = .(MathHelper.ToRadians(45), MathHelper.ToRadians(-100), 0);
|
||||
let cameraEntity = newScene.CreateEntity("Camera");
|
||||
let transform = cameraEntity.Transform;
|
||||
transform.Position = Vector3(0, 2, -5);
|
||||
transform.RotationEuler = Vector3(0, MathHelper.ToRadians(25), 0);
|
||||
|
||||
let light = lightNtt.AddComponent<LightComponent>();
|
||||
let camera = cameraEntity.AddComponent<CameraComponent>();
|
||||
camera.Primary = true;
|
||||
camera.Camera.ProjectionType = .InfinitePerspective;
|
||||
camera.Camera.PerspectiveFovY = MathHelper.ToRadians(75);
|
||||
camera.Camera.PerspectiveNearPlane = 0.1f;
|
||||
}
|
||||
|
||||
// Create a default light source
|
||||
{
|
||||
let lightEntity = newScene.CreateEntity("Light");
|
||||
let transform = lightEntity.Transform;
|
||||
transform.Position = .(-3, 4, -1.5f);
|
||||
transform.RotationEuler = .(MathHelper.ToRadians(20), MathHelper.ToRadians(75), MathHelper.ToRadians(20));
|
||||
|
||||
let light = lightEntity.AddComponent<LightComponent>();
|
||||
light.SceneLight.Illuminance = 10.0f;
|
||||
light.SceneLight.Color = .(1.0f, 0.95f, 0.8f);
|
||||
}
|
||||
|
||||
TestEntitiesWithModels();*/
|
||||
_editorScene.ReleaseRef();
|
||||
_editorScene = newScene;
|
||||
_editor.CurrentScene = _editorScene;
|
||||
var vpSize = _editor.SceneViewportWindow.ViewportSize;
|
||||
_editorScene.OnViewportResize((.)vpSize.X, (.)vpSize.Y);
|
||||
|
||||
SetReference!(_activeScene, _editorScene);
|
||||
}
|
||||
|
||||
/// 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))
|
||||
if (SceneFilePath.IsWhiteSpace)
|
||||
{
|
||||
SaveSceneAs();
|
||||
return;
|
||||
}
|
||||
|
||||
SceneSerializer serializer = scope .(_scene);
|
||||
SceneSerializer serializer = scope .(_editorScene);
|
||||
serializer.Serialize(SceneFilePath);
|
||||
}
|
||||
|
||||
@@ -565,16 +607,20 @@ namespace GlitchyEditor
|
||||
/// Loads the given scene file.
|
||||
private void LoadSceneFile(StringView filename)
|
||||
{
|
||||
OnSceneStop();
|
||||
|
||||
SceneFilePath = scope String(filename);
|
||||
|
||||
delete _scene;
|
||||
_scene = new Scene();
|
||||
_editor.CurrentScene = _scene;
|
||||
_editorScene.ReleaseRef();
|
||||
_editorScene = new Scene();
|
||||
_editor.CurrentScene = _editorScene;
|
||||
var vpSize = _editor.SceneViewportWindow.ViewportSize;
|
||||
_scene.OnViewportResize((.)vpSize.X, (.)vpSize.Y);
|
||||
_editorScene.OnViewportResize((.)vpSize.X, (.)vpSize.Y);
|
||||
|
||||
SceneSerializer serializer = scope .(_scene);
|
||||
SceneSerializer serializer = scope .(_editorScene);
|
||||
serializer.Deserialize(SceneFilePath);
|
||||
|
||||
SetReference!(_activeScene, _editorScene);
|
||||
}
|
||||
|
||||
private void DrawMainMenuBar()
|
||||
@@ -610,25 +656,27 @@ namespace GlitchyEditor
|
||||
|
||||
if(ImGui.BeginMenu("View", true))
|
||||
{
|
||||
if(ImGui.MenuItem(EntityHierarchyWindow.s_WindowTitle))
|
||||
{
|
||||
_editor.EntityHierarchyWindow.Open = true;
|
||||
}
|
||||
|
||||
if(ImGui.MenuItem(ComponentEditWindow.s_WindowTitle))
|
||||
{
|
||||
_editor.ComponentEditWindow.Open = true;
|
||||
}
|
||||
|
||||
if(ImGui.MenuItem(SceneViewportWindow.s_WindowTitle))
|
||||
{
|
||||
if(ImGui.MenuItem(ContentBrowserWindow.s_WindowTitle))
|
||||
_editor.ComponentEditWindow.Open = true;
|
||||
|
||||
if(ImGui.MenuItem(EditorViewportWindow.s_WindowTitle))
|
||||
_editor.SceneViewportWindow.Open = true;
|
||||
}
|
||||
|
||||
if(ImGui.MenuItem(EntityHierarchyWindow.s_WindowTitle))
|
||||
_editor.EntityHierarchyWindow.Open = true;
|
||||
|
||||
if(ImGui.MenuItem(GameViewportWindow.s_WindowTitle))
|
||||
_editor.GameViewportWindow.Open = true;
|
||||
|
||||
if(ImGui.MenuItem(PropertiesWindow.s_WindowTitle))
|
||||
_editor.PropertiesWindow.Open = true;
|
||||
|
||||
ImGui.EndMenu();
|
||||
}
|
||||
|
||||
|
||||
ImGui.EndMainMenuBar();
|
||||
}
|
||||
|
||||
@@ -637,7 +685,7 @@ namespace GlitchyEditor
|
||||
return false;
|
||||
}
|
||||
|
||||
private void ViewportSizeChanged(Object sender, Vector2 viewportSize)
|
||||
private void EditorViewportSizeChanged(Object sender, Vector2 viewportSize)
|
||||
{
|
||||
uint32 sizeX = (uint32)viewportSize.X;
|
||||
uint32 sizeY = (uint32)viewportSize.Y;
|
||||
@@ -645,11 +693,27 @@ namespace GlitchyEditor
|
||||
if(sizeX == 0 || sizeY == 0)
|
||||
return;
|
||||
|
||||
_viewportTarget.Resize(sizeX, sizeY);
|
||||
_editorViewportTarget.Resize(sizeX, sizeY);
|
||||
_cameraTarget.Resize(sizeX, sizeY);
|
||||
|
||||
_scene.OnViewportResize(sizeX, sizeY);
|
||||
_camera.OnViewportResize(sizeX, sizeY);
|
||||
|
||||
_editorSceneRenderer.OnViewportResize(sizeX, sizeY);
|
||||
}
|
||||
|
||||
private void GameViewportSizeChanged(Object sender, Vector2 viewportSize)
|
||||
{
|
||||
uint32 sizeX = (uint32)viewportSize.X;
|
||||
uint32 sizeY = (uint32)viewportSize.Y;
|
||||
|
||||
if(sizeX == 0 || sizeY == 0)
|
||||
return;
|
||||
|
||||
_gameViewportTarget.Resize(sizeX, sizeY);
|
||||
|
||||
_activeScene.OnViewportResize(sizeX, sizeY);
|
||||
|
||||
_gameSceneRenderer.OnViewportResize(sizeX, sizeY);
|
||||
}
|
||||
|
||||
private bool OnKeyPressed(KeyPressedEvent e)
|
||||
|
||||
@@ -34,6 +34,8 @@ namespace GlitchyEngine
|
||||
|
||||
public bool IsMinimized => _isMinimized;
|
||||
|
||||
public GameTime GameTime => _gameTime;
|
||||
|
||||
[Inline]
|
||||
public static Application Get() => s_Instance;
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace GlitchyEngine.Collections
|
||||
{
|
||||
public T Value;
|
||||
|
||||
public Self Parent;
|
||||
public List<Self> Children = new .() ~ DeleteContainerAndItems!(_);
|
||||
|
||||
public this() {}
|
||||
@@ -29,6 +30,7 @@ namespace GlitchyEngine.Collections
|
||||
}
|
||||
|
||||
Self newChild = new .(value);
|
||||
newChild.Parent = this;
|
||||
|
||||
Children.Add(newChild);
|
||||
|
||||
|
||||
@@ -8,8 +8,10 @@ using System.IO;
|
||||
namespace GlitchyEngine.Content;
|
||||
|
||||
[BonTarget]
|
||||
class Asset : RefCounter
|
||||
abstract class Asset : RefCounter
|
||||
{
|
||||
internal AssetHandle _handle = .Invalid;
|
||||
|
||||
private append String _identifier;
|
||||
|
||||
internal IContentManager _contentManager;
|
||||
@@ -20,19 +22,18 @@ class Asset : RefCounter
|
||||
public StringView Identifier
|
||||
{
|
||||
get => _identifier;
|
||||
set
|
||||
{
|
||||
_contentManager?.UpdateAssetIdentifier(this, _identifier, value);
|
||||
internal set => _identifier.Set(value);
|
||||
}
|
||||
|
||||
_identifier.Set(value);
|
||||
// TODO: do we need to tell the content manager, that the name changed?
|
||||
}
|
||||
}
|
||||
/// If true the asset is completely loaded. If false it is only partially loaded (if at all).
|
||||
public bool Complete { get; internal set; }
|
||||
|
||||
// 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;
|
||||
|
||||
public AssetHandle Handle => _handle;
|
||||
|
||||
static this
|
||||
{
|
||||
gBonEnv.typeHandlers.Add(typeof(Asset),
|
||||
@@ -43,7 +44,7 @@ class Asset : RefCounter
|
||||
{
|
||||
// TODO: crash when _contentManager is deleted first...
|
||||
// TODO: unregister from content manager
|
||||
_contentManager?.UnmanageAsset(this);
|
||||
//_contentManager?.UnmanageAsset(this);
|
||||
}
|
||||
|
||||
static void AssetSerialize(BonWriter writer, ValueView value, BonEnvironment environment, SerializeValueState state)
|
||||
@@ -62,7 +63,15 @@ class Asset : RefCounter
|
||||
|
||||
Deserialize.String!(reader, ref identifier, environment);
|
||||
|
||||
Asset asset = Application.Get().ContentManager.LoadAsset(identifier);
|
||||
AssetHandle handle = Content.LoadAsset(identifier);
|
||||
|
||||
if (handle == .Invalid)
|
||||
{
|
||||
value.Assign<Asset>(null);
|
||||
return .Ok;
|
||||
}
|
||||
|
||||
Asset asset = Content.GetAsset<Asset>(handle);
|
||||
|
||||
if (asset != null)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,336 @@
|
||||
using Bon;
|
||||
using Bon.Integrated;
|
||||
using System;
|
||||
using xxHash;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using System.Diagnostics;
|
||||
using GlitchyEngine.Core;
|
||||
|
||||
namespace GlitchyEngine.Content;
|
||||
|
||||
struct AssetHandle : IHashable
|
||||
{
|
||||
private UUID _uuid;
|
||||
|
||||
/// Defines an asset that is invalid.
|
||||
public const AssetHandle Invalid = .(UUID(0));
|
||||
|
||||
public bool IsValid => this != .Invalid;
|
||||
public bool IsInvalid => this == .Invalid;
|
||||
|
||||
/// Create a new random AssetHandle
|
||||
public this()
|
||||
{
|
||||
_uuid = UUID();
|
||||
}
|
||||
|
||||
private this(UUID uuid)
|
||||
{
|
||||
_uuid = uuid;
|
||||
}
|
||||
|
||||
static this
|
||||
{
|
||||
gBonEnv.typeHandlers.Add(typeof(AssetHandle),
|
||||
((.)new => AssetSerialize, new => AssetDeserialize));
|
||||
}
|
||||
|
||||
[Inline]
|
||||
public T Get<T>(IContentManager contentManager = null) where T : Asset
|
||||
{
|
||||
return Content.GetAsset<T>(this, contentManager);
|
||||
}
|
||||
|
||||
public int GetHashCode() => _uuid.GetHashCode();
|
||||
|
||||
static void AssetSerialize(BonWriter writer, ValueView value, BonEnvironment environment, SerializeValueState state)
|
||||
{
|
||||
Log.EngineLogger.Assert(value.type == typeof(AssetHandle));
|
||||
|
||||
AssetHandle handle = value.Get<AssetHandle>();
|
||||
|
||||
if (handle.IsInvalid)
|
||||
writer.String("");
|
||||
else
|
||||
{
|
||||
let identifier = handle.Get<Asset>().Identifier;
|
||||
writer.String(identifier);
|
||||
}
|
||||
}
|
||||
|
||||
static Result<void> AssetDeserialize(BonReader reader, ValueView value, BonEnvironment environment, DeserializeValueState state)
|
||||
{
|
||||
Log.EngineLogger.Assert(value.type == typeof(AssetHandle));
|
||||
|
||||
String identifier = scope .();
|
||||
|
||||
Deserialize.String!(reader, ref identifier, environment);
|
||||
|
||||
AssetHandle handle = Content.LoadAsset(identifier);
|
||||
|
||||
value.Assign<AssetHandle>(handle);
|
||||
|
||||
return .Ok;
|
||||
}
|
||||
}
|
||||
|
||||
struct AssetHandle<T> where T : Asset
|
||||
{
|
||||
private AssetHandle _handle;
|
||||
private IContentManager _contentManager;
|
||||
/*
|
||||
* We don't increment/decrement the reference counter since we guarantee that we query for the asset every frame.
|
||||
*/
|
||||
private T _asset;
|
||||
//private uint8 _currentFrame;
|
||||
//private uint64 _actualCurrentFrame = 0;
|
||||
|
||||
public const Self Invalid = .();
|
||||
|
||||
public bool IsValid => this != .Invalid;
|
||||
public bool IsInvalid => this == .Invalid;
|
||||
|
||||
public this(AssetHandle handle, IContentManager contentManager = null)
|
||||
{
|
||||
_handle = handle;
|
||||
|
||||
_asset = handle.Get<T>(contentManager);
|
||||
_contentManager = _asset?.ContentManager;
|
||||
if (_contentManager == null)
|
||||
_contentManager = contentManager;
|
||||
//_currentFrame = (uint8)Application.Get().GameTime.FrameCount;
|
||||
}
|
||||
|
||||
// Creates a new invalid asset handle
|
||||
private this()
|
||||
{
|
||||
_handle = .Invalid;
|
||||
//_currentFrame = 0;
|
||||
_contentManager = null;
|
||||
_asset = null;
|
||||
}
|
||||
|
||||
static this
|
||||
{
|
||||
gBonEnv.typeHandlers.Add(typeof(AssetHandle<T>),
|
||||
((.)new => AssetSerialize, new => AssetDeserialize));
|
||||
}
|
||||
|
||||
public static implicit operator Self(AssetHandle handle)
|
||||
{
|
||||
return Self(handle);
|
||||
}
|
||||
|
||||
public static implicit operator AssetHandle(Self handle)
|
||||
{
|
||||
return handle._handle;
|
||||
}
|
||||
|
||||
public static implicit operator T(ref Self handle)
|
||||
{
|
||||
return handle.Get();
|
||||
}
|
||||
|
||||
public T Get(IContentManager contentManager = null)
|
||||
{
|
||||
return Content.GetAsset<T>(_handle, contentManager == null ? _contentManager : contentManager);
|
||||
}
|
||||
|
||||
[Comptime, OnCompile(.TypeInit)]
|
||||
static void Init()
|
||||
{
|
||||
for (var field in typeof(T).GetFields(BindingFlags.FlattenHierarchy))
|
||||
{
|
||||
if (field.IsStatic || !field.IsPublic)
|
||||
continue;
|
||||
|
||||
String modifier = field.IsPublic ? "public" : "private";
|
||||
|
||||
String code = scope $"""
|
||||
{modifier} {field.FieldType} {field.Name}
|
||||
{{
|
||||
get mut
|
||||
{{
|
||||
return Get().{field.Name};
|
||||
}}
|
||||
set mut
|
||||
{{
|
||||
Get().{field.Name} = value;
|
||||
}}
|
||||
}}
|
||||
|
||||
|
||||
""";
|
||||
|
||||
Compiler.EmitTypeBody(typeof(Self), code);
|
||||
}
|
||||
|
||||
Dictionary<StringView, (MethodInfo? Getter, MethodInfo? Setter)> properties = scope .();
|
||||
|
||||
for (var method in typeof(T).GetMethods(BindingFlags.FlattenHierarchy | BindingFlags.Public))
|
||||
{
|
||||
if (method.IsStatic || !method.IsPublic || method.IsConstructor || method.IsDestructor)
|
||||
continue;
|
||||
|
||||
// Filter out destructors
|
||||
if (method.Name == "~this")
|
||||
continue;
|
||||
|
||||
if (method.Name.StartsWith("get__"))
|
||||
{
|
||||
StringView name = method.Name;
|
||||
name.RemoveFromStart(5);
|
||||
|
||||
if (!properties.TryGetValue(name, var propertyInfo))
|
||||
{
|
||||
propertyInfo = default;
|
||||
}
|
||||
|
||||
propertyInfo.Getter = method;
|
||||
|
||||
properties[name] = propertyInfo;
|
||||
|
||||
continue;
|
||||
}
|
||||
if (method.Name.StartsWith("set__"))
|
||||
{
|
||||
StringView name = method.Name;
|
||||
name.RemoveFromStart(5);
|
||||
|
||||
if (!properties.TryGetValue(name, var propertyInfo))
|
||||
{
|
||||
propertyInfo = default;
|
||||
}
|
||||
|
||||
propertyInfo.Setter = method;
|
||||
|
||||
properties[name] = propertyInfo;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
String modifier = method.IsPublic ? "public" : "private";
|
||||
|
||||
String parameters = scope String();
|
||||
String arguments = scope String();
|
||||
|
||||
for (int param < method.ParamCount)
|
||||
{
|
||||
Type paramType = method.GetParamType(param);
|
||||
StringView paramName = method.GetParamName(param);
|
||||
/*String buffer = scope .();
|
||||
method.GetParamsDecl(buffer);*/
|
||||
|
||||
if (param != 0)
|
||||
{
|
||||
parameters.Append(", ");
|
||||
arguments.Append(", ");
|
||||
}
|
||||
|
||||
// TODO: Default value
|
||||
parameters.AppendF($"{paramType} {paramName}");
|
||||
|
||||
/*if (!buffer.IsEmpty)
|
||||
{
|
||||
parameters.AppendF($"/*{buffer}*/");
|
||||
}*/
|
||||
|
||||
arguments.AppendF($" {paramName}");
|
||||
}
|
||||
|
||||
String code = scope $"""
|
||||
{modifier} {method.ReturnType} {method.Name}({parameters}) mut
|
||||
{{
|
||||
return Get().{method.Name}({arguments});
|
||||
}}
|
||||
|
||||
|
||||
""";
|
||||
|
||||
Compiler.EmitTypeBody(typeof(Self), code);
|
||||
}
|
||||
|
||||
for (var (propertyName, property) in properties)
|
||||
{
|
||||
Type propertyType = property.Getter?.ReturnType ?? property.Setter?.GetParamType(0);
|
||||
|
||||
String getter = scope .();
|
||||
String setter = scope .();
|
||||
|
||||
if (property.Getter != null)
|
||||
{
|
||||
getter.AppendF($"""
|
||||
get mut
|
||||
{{
|
||||
return Get().{propertyName};
|
||||
}}
|
||||
""");
|
||||
}
|
||||
if (property.Setter != null)
|
||||
{
|
||||
getter.AppendF($"""
|
||||
|
||||
set mut
|
||||
{{
|
||||
Get().{propertyName} = value;
|
||||
}}
|
||||
""");
|
||||
}
|
||||
|
||||
String code = scope $"""
|
||||
public {propertyType} {propertyName}
|
||||
{{
|
||||
{getter}{setter}
|
||||
}}
|
||||
|
||||
|
||||
""";
|
||||
|
||||
Compiler.EmitTypeBody(typeof(Self), code);
|
||||
}
|
||||
}
|
||||
|
||||
public AssetHandle<NewT> Cast<NewT>()
|
||||
where NewT : Asset
|
||||
where T : NewT
|
||||
{
|
||||
return AssetHandle<NewT>(this._handle, this._contentManager);
|
||||
}
|
||||
|
||||
// TODO: Cast up?
|
||||
public AssetHandle<NewT> Cast<NewT>() where NewT : T
|
||||
{
|
||||
return AssetHandle<NewT>(this._handle, this._contentManager);
|
||||
}
|
||||
|
||||
static void AssetSerialize(BonWriter writer, ValueView value, BonEnvironment environment, SerializeValueState state)
|
||||
{
|
||||
Log.EngineLogger.Assert(value.type == typeof(AssetHandle<T>));
|
||||
|
||||
AssetHandle handle = value.Get<AssetHandle<T>>();
|
||||
|
||||
if (handle.IsInvalid)
|
||||
writer.String("");
|
||||
else
|
||||
{
|
||||
let identifier = handle.Get<Asset>().Identifier;
|
||||
writer.String(identifier);
|
||||
}
|
||||
}
|
||||
|
||||
static Result<void> AssetDeserialize(BonReader reader, ValueView value, BonEnvironment environment, DeserializeValueState state)
|
||||
{
|
||||
Log.EngineLogger.Assert(value.type == typeof(AssetHandle<T>));
|
||||
|
||||
String identifier = scope .();
|
||||
|
||||
Deserialize.String!(reader, ref identifier, environment);
|
||||
|
||||
AssetHandle<T> handle = Content.LoadAsset(identifier);
|
||||
|
||||
value.Assign<AssetHandle<T>>(handle);
|
||||
|
||||
return .Ok;
|
||||
}
|
||||
}
|
||||
@@ -57,40 +57,82 @@ namespace GlitchyEngine.Content
|
||||
/// @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);
|
||||
|
||||
/// Returns the placeholder asset.
|
||||
Asset GetPlaceholderAsset(Type assetType);
|
||||
|
||||
/// Returns the error asset.
|
||||
Asset GetErrorAsset(Type assetType);
|
||||
}
|
||||
|
||||
static
|
||||
static class Content
|
||||
{
|
||||
/// 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
|
||||
public static AssetHandle LoadAsset(StringView assetIdentifier, IContentManager contentManager = null, bool blocking = false)
|
||||
{
|
||||
var contentManager;
|
||||
|
||||
if (contentManager == null)
|
||||
contentManager = Application.Get().ContentManager;
|
||||
|
||||
Asset asset = contentManager.LoadAsset(assetIdentifier);
|
||||
AssetHandle handle = contentManager.LoadAsset(assetIdentifier, blocking);
|
||||
|
||||
Log.EngineLogger.AssertDebug(asset is T);
|
||||
return handle;
|
||||
}
|
||||
|
||||
/// Loads the specified asset with the given contentManager or the current applications content manager.
|
||||
public static T GetAsset<T>(AssetHandle handle, IContentManager contentManager = null) where T : Asset
|
||||
{
|
||||
var contentManager;
|
||||
|
||||
if (contentManager == null)
|
||||
contentManager = Application.Get().ContentManager;
|
||||
|
||||
Asset asset = contentManager.GetAsset(typeof(T), handle);
|
||||
|
||||
return (T)asset;
|
||||
}
|
||||
|
||||
public static AssetHandle ManageAsset(Asset asset, IContentManager contentManager = null)
|
||||
{
|
||||
var contentManager;
|
||||
|
||||
if (contentManager == null)
|
||||
contentManager = Application.Get().ContentManager;
|
||||
|
||||
return contentManager.ManageAsset(asset);
|
||||
}
|
||||
|
||||
/*public static AssetHandle<T> ManageAsset<T>(T asset, IContentManager contentManager = null) where T : Asset
|
||||
{
|
||||
var contentManager;
|
||||
|
||||
if (contentManager == null)
|
||||
contentManager = Application.Get().ContentManager;
|
||||
|
||||
contentManager.ManageAsset(asset);
|
||||
}*/
|
||||
}
|
||||
|
||||
interface IContentManager
|
||||
{
|
||||
/// Loads the given asset.
|
||||
Asset LoadAsset(StringView assetIdentifier);
|
||||
/// Loads the Asset with the given handle and returns the handle.
|
||||
AssetHandle LoadAsset(StringView assetIdentifier, bool blocking = false);
|
||||
|
||||
/// Returns the asset for the given handle or null, if it isn't loaded.
|
||||
Asset GetAsset(AssetHandle handle)
|
||||
{
|
||||
return GetAsset(null, handle);
|
||||
}
|
||||
|
||||
/// Returns the asset for the given handle or the default asset of the given type.
|
||||
Asset GetAsset(Type assetType, AssetHandle handle);
|
||||
|
||||
/// The content manager will manage the asset (e.g. provide it when LoadAsset is called with the assets identifier)
|
||||
void ManageAsset(Asset asset);
|
||||
AssetHandle 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);
|
||||
void UnmanageAsset(AssetHandle asset);
|
||||
|
||||
/// Returns a data stream for the given asset.
|
||||
Stream GetStream(StringView assetIdentifier);
|
||||
@@ -109,22 +151,22 @@ namespace GlitchyEngine.Content
|
||||
Runtime.NotImplemented();
|
||||
}
|
||||
|
||||
public Asset LoadAsset(StringView assetIdentifier)
|
||||
public AssetHandle LoadAsset(StringView assetIdentifier, bool blocking = false)
|
||||
{
|
||||
Runtime.NotImplemented();
|
||||
}
|
||||
|
||||
public void ManageAsset(Asset asset)
|
||||
public Asset GetAsset(Type assetType, AssetHandle handle)
|
||||
{
|
||||
Runtime.NotImplemented();
|
||||
}
|
||||
|
||||
public void UnmanageAsset(Asset asset)
|
||||
public AssetHandle ManageAsset(Asset asset)
|
||||
{
|
||||
Runtime.NotImplemented();
|
||||
}
|
||||
|
||||
public void UpdateAssetIdentifier(Asset asset, StringView oldIdentifier, StringView newIdentifier)
|
||||
public void UnmanageAsset(AssetHandle asset)
|
||||
{
|
||||
Runtime.NotImplemented();
|
||||
}
|
||||
|
||||
@@ -229,156 +229,6 @@ namespace GlitchyEngine.Content
|
||||
return .Success;
|
||||
}
|
||||
|
||||
public static EcsEntity LoadModel(String filename, Material material, EcsWorld world,
|
||||
List<AnimationClip> outClips, StringView entityName = StringView())
|
||||
{
|
||||
CGLTF.Options options = .();
|
||||
CGLTF.Data* data;
|
||||
CGLTF.Result result = CGLTF.ParseFile(options, filename, out data);
|
||||
|
||||
Log.EngineLogger.Assert(result == .Success, "Failed to load model.");
|
||||
|
||||
result = CGLTF.LoadBuffers(options, data, filename);
|
||||
|
||||
Log.EngineLogger.Assert(result == .Success, "Failed to load buffers");
|
||||
|
||||
(EcsEntity entity, ?) = CreateEntity(world, entityName, .InvalidEntity);
|
||||
|
||||
for(var node in data.Scenes[0].Nodes)
|
||||
{
|
||||
NodesToEntities(data, node, entity, world, material, outClips);
|
||||
}
|
||||
|
||||
CGLTF.Free(data);
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
private static (EcsEntity Entity, TransformComponent* Transform) CreateEntity(EcsWorld world, StringView? name, EcsEntity parent)
|
||||
{
|
||||
EcsEntity entity = world.NewEntity();
|
||||
|
||||
var nameComponent = world.AssignComponent<DebugNameComponent>(entity);
|
||||
|
||||
if (name != null && name.Value.Ptr != null)
|
||||
{
|
||||
nameComponent.SetName(name.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
nameComponent.SetName("Unnamed Node");
|
||||
}
|
||||
|
||||
/////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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if(node.HasMatrix)
|
||||
{
|
||||
childTransform.LocalTransform = *(Matrix*)&node.Matrix;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(node.HasTranslation)
|
||||
childTransform.Position = *(Vector3*)&node.Translation;
|
||||
else
|
||||
childTransform.Position = .Zero;
|
||||
|
||||
if(node.HasRotation)
|
||||
childTransform.Rotation = *(Quaternion*)&node.Rotation;
|
||||
else
|
||||
childTransform.Rotation = .Identity;
|
||||
|
||||
if(node.HasScale)
|
||||
childTransform.Scale = *(Vector3*)&node.Scale;
|
||||
else
|
||||
childTransform.Scale = .(1, 1, 1);
|
||||
}
|
||||
|
||||
// Invert the Z-Axis of the root Node to convert the coordinate system from right-handed to left-handed
|
||||
if(parentEntity == .InvalidEntity)
|
||||
childTransform.Scale *= .(1, 1, -1);
|
||||
|
||||
Skeleton skeleton = null;
|
||||
|
||||
if(node.Skin != null)
|
||||
{
|
||||
skeleton = ExtractSkeleton(node.Skin);
|
||||
|
||||
LoadAnimationClips(data, node.Skin, skeleton, clips);
|
||||
}
|
||||
|
||||
if(node.Mesh != null)
|
||||
{
|
||||
// If we have only one primitive, add it directly to the entity
|
||||
if(node.Mesh.Primitives.Length == 1)
|
||||
{
|
||||
var mesh = world.AssignComponent<MeshComponent>(entity);
|
||||
|
||||
using (var geo = PrimitiveToGeoBinding(node.Mesh.Primitives[0]))
|
||||
{
|
||||
mesh.Mesh = geo;
|
||||
}
|
||||
|
||||
if(skeleton == null)
|
||||
{
|
||||
var meshRenderer = world.AssignComponent<MeshRendererComponent>(entity);
|
||||
meshRenderer.Material = material;
|
||||
}
|
||||
else
|
||||
{
|
||||
var meshRenderer = world.AssignComponent<SkinnedMeshRendererComponent>(entity);
|
||||
meshRenderer.Material = material;
|
||||
meshRenderer.Skeleton = skeleton;
|
||||
}
|
||||
}
|
||||
// otherwise one child-entity per primitive
|
||||
else
|
||||
{
|
||||
for(var primitive in node.Mesh.Primitives)
|
||||
{
|
||||
EcsEntity meshEntity = world.NewEntity();
|
||||
|
||||
var meshParent = world.AssignComponent<ParentComponent>(meshEntity);
|
||||
meshParent.Entity = entity;
|
||||
|
||||
var mesh = world.AssignComponent<MeshComponent>(meshEntity);
|
||||
mesh.Mesh = PrimitiveToGeoBinding(primitive);
|
||||
|
||||
if(skeleton == null)
|
||||
{
|
||||
var meshRenderer = world.AssignComponent<MeshRendererComponent>(meshEntity);
|
||||
meshRenderer.Material = material;
|
||||
}
|
||||
else
|
||||
{
|
||||
var meshRenderer = world.AssignComponent<SkinnedMeshRendererComponent>(meshEntity);
|
||||
meshRenderer.Material = material;
|
||||
meshRenderer.Skeleton = skeleton;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
skeleton?.ReleaseRef();
|
||||
|
||||
for(var child in node.Children)
|
||||
{
|
||||
NodesToEntities(data, child, entity, world, material, clips);
|
||||
}
|
||||
}
|
||||
|
||||
public static GeometryBinding PrimitiveToGeoBinding(CGLTF.Primitive primitive)
|
||||
{
|
||||
GeometryBinding binding = new GeometryBinding();
|
||||
|
||||
@@ -20,12 +20,11 @@ namespace GlitchyEngine.Generators
|
||||
outFileName.Append(name);
|
||||
outText.AppendF(
|
||||
$"""
|
||||
namespace {Namespace}
|
||||
{{
|
||||
namespace {Namespace};
|
||||
|
||||
struct {name}
|
||||
{{
|
||||
}}
|
||||
}}
|
||||
""");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,5 +4,4 @@ namespace GlitchyEngine.Math
|
||||
{
|
||||
typealias Matrix3x3 = DirectX.Math.Matrix3x3;
|
||||
typealias Matrix4x3 = DirectX.Math.Matrix4x3;
|
||||
typealias Matrix = DirectX.Math.Matrix;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,877 @@
|
||||
using System;
|
||||
|
||||
namespace GlitchyEngine.Math;
|
||||
|
||||
/**
|
||||
* Represents a 4 by 4 column-major matrix.
|
||||
*/
|
||||
[Union]
|
||||
public struct Matrix
|
||||
{
|
||||
public struct Values
|
||||
{
|
||||
public float _11, _21, _31, _41,
|
||||
_12, _22, _32, _42,
|
||||
_13, _23, _33, _43,
|
||||
_14, _24, _34, _44;
|
||||
}
|
||||
|
||||
public const Matrix Zero = .();
|
||||
public const Matrix Identity = .(.UnitX, .UnitY, .UnitZ, .UnitW);
|
||||
|
||||
public using Values V;
|
||||
public float[4][4] Values;
|
||||
public Vector4[4] Columns;
|
||||
|
||||
/// Creates a new zero-matrix.
|
||||
public this() => this = default;
|
||||
|
||||
/**
|
||||
* Initializes a new Matrix.
|
||||
* @param value The value that will be assigned to all components.
|
||||
*/
|
||||
/// Creates a new matrix.
|
||||
public this(float value)
|
||||
{
|
||||
this = ?;
|
||||
_11 = _12 = _13 = _14 =
|
||||
_21 = _22 = _23 = _24 =
|
||||
_31 = _32 = _33 = _34 =
|
||||
_41 = _42 = _43 = _44 = value;
|
||||
}
|
||||
|
||||
/// Creates a new matrix and initializes it with the given entries.
|
||||
public this(float m00, float m01, float m02, float m03,
|
||||
float m10, float m11, float m12, float m13,
|
||||
float m20, float m21, float m22, float m23,
|
||||
float m30, float m31, float m32, float m33)
|
||||
{
|
||||
Values[0][0] = m00; Values[0][1] = m10; Values[0][2] = m20; Values[0][3] = m30;
|
||||
Values[1][0] = m01; Values[1][1] = m11; Values[1][2] = m21; Values[1][3] = m31;
|
||||
Values[2][0] = m02; Values[2][1] = m12; Values[2][2] = m22; Values[2][3] = m32;
|
||||
Values[3][0] = m03; Values[3][1] = m13; Values[3][2] = m23; Values[3][3] = m33;
|
||||
}
|
||||
|
||||
/// Creates a new matrix and initializes it with the given column-vectors.
|
||||
public this(Vector4 c0, Vector4 c1, Vector4 c2, Vector4 c3)
|
||||
{
|
||||
Columns[0] = c0;
|
||||
Columns[1] = c1;
|
||||
Columns[2] = c2;
|
||||
Columns[3] = c3;
|
||||
}
|
||||
|
||||
public ref Vector3 Right
|
||||
{
|
||||
[Inline]
|
||||
get
|
||||
{
|
||||
#unwarn
|
||||
return ref *(Vector3*)&Columns[0];
|
||||
}
|
||||
}
|
||||
|
||||
public ref Vector3 Up
|
||||
{
|
||||
[Inline]
|
||||
get
|
||||
{
|
||||
#unwarn
|
||||
return ref *(Vector3*)&Columns[1];
|
||||
}
|
||||
}
|
||||
|
||||
public ref Vector3 Forward
|
||||
{
|
||||
[Inline]
|
||||
get
|
||||
{
|
||||
#unwarn
|
||||
return ref *(Vector3*)&Columns[2];
|
||||
}
|
||||
}
|
||||
|
||||
public ref Vector3 Translation
|
||||
{
|
||||
[Inline]
|
||||
get
|
||||
{
|
||||
#unwarn
|
||||
return ref *(Vector3*)&Columns[3];
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 Scale
|
||||
{
|
||||
[Inline]
|
||||
get => .(_11, _22, _33);
|
||||
|
||||
[Inline]
|
||||
set mut
|
||||
{
|
||||
_11 = value.X;
|
||||
_22 = value.Y;
|
||||
_33 = value.Z;
|
||||
}
|
||||
}
|
||||
|
||||
public ref float this[int row, int column]
|
||||
{
|
||||
get
|
||||
{
|
||||
#unwarn
|
||||
return ref *(float*)&Values[column][row];
|
||||
}
|
||||
|
||||
[Checked]
|
||||
get
|
||||
{
|
||||
if(column < 0 || column > 3 || row < 0 || row > 3)
|
||||
Internal.ThrowIndexOutOfRange();
|
||||
|
||||
#unwarn
|
||||
return ref *(float*)&Values[column][row];
|
||||
}
|
||||
}
|
||||
|
||||
public ref Vector4 this[int column]
|
||||
{
|
||||
get
|
||||
{
|
||||
#unwarn
|
||||
return ref *(Vector4*)&Columns[column];
|
||||
}
|
||||
|
||||
|
||||
[Checked]
|
||||
get
|
||||
{
|
||||
if(column < 0 || column > 3)
|
||||
Internal.ThrowIndexOutOfRange();
|
||||
|
||||
#unwarn
|
||||
return ref *(Vector4*)&Columns[column];
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Assignment Operators
|
||||
//
|
||||
|
||||
// Addition
|
||||
|
||||
public void operator +=(Matrix value) mut
|
||||
{
|
||||
Columns[0] += value.Columns[0];
|
||||
Columns[1] += value.Columns[1];
|
||||
Columns[2] += value.Columns[2];
|
||||
Columns[3] += value.Columns[3];
|
||||
}
|
||||
|
||||
// Matrix + Scalar : Matrix + Scalar * Identity
|
||||
public void operator +=(float scalar) mut
|
||||
{
|
||||
_11 += scalar;
|
||||
_22 += scalar;
|
||||
_33 += scalar;
|
||||
_44 += scalar;
|
||||
}
|
||||
|
||||
// Subtraction
|
||||
|
||||
public void operator -=(Matrix value) mut
|
||||
{
|
||||
Columns[0] -= value.Columns[0];
|
||||
Columns[1] -= value.Columns[1];
|
||||
Columns[2] -= value.Columns[2];
|
||||
Columns[3] -= value.Columns[3];
|
||||
}
|
||||
|
||||
// Matrix - Scalar : Matrix - Scalar * Identity
|
||||
public void operator -=(float scalar) mut
|
||||
{
|
||||
_11 -= scalar;
|
||||
_22 -= scalar;
|
||||
_33 -= scalar;
|
||||
_44 -= scalar;
|
||||
}
|
||||
|
||||
// Multiplication
|
||||
|
||||
public void operator *=(float scalar) mut
|
||||
{
|
||||
Columns[0] *= scalar;
|
||||
Columns[1] *= scalar;
|
||||
Columns[2] *= scalar;
|
||||
Columns[3] *= scalar;
|
||||
}
|
||||
|
||||
public void operator *=(Matrix value) mut
|
||||
{
|
||||
this = this * value;
|
||||
}
|
||||
|
||||
// Divide
|
||||
|
||||
public void operator /=(float scalar) mut
|
||||
{
|
||||
float inv = 1.0f / scalar;
|
||||
Columns[0] *= inv;
|
||||
Columns[1] *= inv;
|
||||
Columns[2] *= inv;
|
||||
Columns[3] *= inv;
|
||||
}
|
||||
|
||||
//
|
||||
// Operators
|
||||
//
|
||||
|
||||
// Addition
|
||||
|
||||
public static Matrix operator +(Matrix left, Matrix right)
|
||||
{
|
||||
return .(left.Columns[0] + right.Columns[0],
|
||||
left.Columns[1] + right.Columns[1],
|
||||
left.Columns[2] + right.Columns[2],
|
||||
left.Columns[3] + right.Columns[3]);
|
||||
}
|
||||
|
||||
public static Matrix operator +(Matrix left, float right)
|
||||
{
|
||||
Matrix result = left;
|
||||
result._11 += right;
|
||||
result._22 += right;
|
||||
result._33 += right;
|
||||
result._44 += right;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Matrix operator +(float left, Matrix right)
|
||||
{
|
||||
Matrix result = right;
|
||||
result._11 += left;
|
||||
result._22 += left;
|
||||
result._33 += left;
|
||||
result._44 += left;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Subtraction
|
||||
|
||||
public static Matrix operator -(Matrix left, Matrix right)
|
||||
{
|
||||
return .(left.Columns[0] - right.Columns[0],
|
||||
left.Columns[1] - right.Columns[1],
|
||||
left.Columns[2] - right.Columns[2],
|
||||
left.Columns[3] - right.Columns[3]);
|
||||
}
|
||||
|
||||
public static Matrix operator -(Matrix value, float scalar)
|
||||
{
|
||||
Matrix result = value;
|
||||
result._11 -= scalar;
|
||||
result._22 -= scalar;
|
||||
result._33 -= scalar;
|
||||
result._44 -= scalar;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Matrix operator -(float scalar, Matrix value)
|
||||
{
|
||||
Matrix result = value;
|
||||
result._11 -= scalar;
|
||||
result._22 -= scalar;
|
||||
result._33 -= scalar;
|
||||
result._44 -= scalar;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Matrix operator -(Matrix value)
|
||||
{
|
||||
return .(-value.Columns[0],
|
||||
-value.Columns[1],
|
||||
-value.Columns[2],
|
||||
-value.Columns[3]);
|
||||
}
|
||||
|
||||
// Multiplication
|
||||
|
||||
public static Matrix operator *(Matrix left, Matrix right)
|
||||
{
|
||||
#unwarn
|
||||
var l = &left.V;
|
||||
#unwarn
|
||||
var r = &right.V;
|
||||
|
||||
Matrix result = ?;
|
||||
|
||||
result._11 = (l._11 * r._11) + (l._12 * r._21) + (l._13 * r._31) + (l._14 * r._41);
|
||||
result._12 = (l._11 * r._12) + (l._12 * r._22) + (l._13 * r._32) + (l._14 * r._42);
|
||||
result._13 = (l._11 * r._13) + (l._12 * r._23) + (l._13 * r._33) + (l._14 * r._43);
|
||||
result._14 = (l._11 * r._14) + (l._12 * r._24) + (l._13 * r._34) + (l._14 * r._44);
|
||||
|
||||
result._21 = (l._21 * r._11) + (l._22 * r._21) + (l._23 * r._31) + (l._24 * r._41);
|
||||
result._22 = (l._21 * r._12) + (l._22 * r._22) + (l._23 * r._32) + (l._24 * r._42);
|
||||
result._23 = (l._21 * r._13) + (l._22 * r._23) + (l._23 * r._33) + (l._24 * r._43);
|
||||
result._24 = (l._21 * r._14) + (l._22 * r._24) + (l._23 * r._34) + (l._24 * r._44);
|
||||
|
||||
result._31 = (l._31 * r._11) + (l._32 * r._21) + (l._33 * r._31) + (l._34 * r._41);
|
||||
result._32 = (l._31 * r._12) + (l._32 * r._22) + (l._33 * r._32) + (l._34 * r._42);
|
||||
result._33 = (l._31 * r._13) + (l._32 * r._23) + (l._33 * r._33) + (l._34 * r._43);
|
||||
result._34 = (l._31 * r._14) + (l._32 * r._24) + (l._33 * r._34) + (l._34 * r._44);
|
||||
|
||||
result._41 = (l._41 * r._11) + (l._42 * r._21) + (l._43 * r._31) + (l._44 * r._41);
|
||||
result._42 = (l._41 * r._12) + (l._42 * r._22) + (l._43 * r._32) + (l._44 * r._42);
|
||||
result._43 = (l._41 * r._13) + (l._42 * r._23) + (l._43 * r._33) + (l._44 * r._43);
|
||||
result._44 = (l._41 * r._14) + (l._42 * r._24) + (l._43 * r._34) + (l._44 * r._44);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Matrix operator *(Matrix value, float scalar)
|
||||
{
|
||||
return .(value.Columns[0] * scalar,
|
||||
value.Columns[1] * scalar,
|
||||
value.Columns[2] * scalar,
|
||||
value.Columns[3] * scalar);
|
||||
}
|
||||
|
||||
public static Matrix operator *(float scalar, Matrix value)
|
||||
{
|
||||
return .(value.Columns[0] * scalar,
|
||||
value.Columns[1] * scalar,
|
||||
value.Columns[2] * scalar,
|
||||
value.Columns[3] * scalar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies a matrix and a column-vector resulting in a column vector.
|
||||
*/
|
||||
public static Vector4 operator *(Matrix matrix, Vector4 columnVector)
|
||||
{
|
||||
#unwarn
|
||||
var m = &matrix.V;
|
||||
|
||||
Vector4 result = ?;
|
||||
result.X = (m._11 * columnVector.X) + (m._12 * columnVector.Y) + (m._13 * columnVector.Z) + (m._14 * columnVector.W);
|
||||
result.Y = (m._21 * columnVector.X) + (m._22 * columnVector.Y) + (m._23 * columnVector.Z) + (m._24 * columnVector.W);
|
||||
result.Z = (m._31 * columnVector.X) + (m._32 * columnVector.Y) + (m._33 * columnVector.Z) + (m._34 * columnVector.W);
|
||||
result.W = (m._41 * columnVector.X) + (m._42 * columnVector.Y) + (m._43 * columnVector.Z) + (m._44 * columnVector.W);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies a row-vector and a matrix resulting in a row vector.
|
||||
*/
|
||||
public static Vector4 operator *(Vector4 rowVector, Matrix matrix)
|
||||
{
|
||||
#unwarn
|
||||
var m = &matrix.V;
|
||||
|
||||
Vector4 result = ?;
|
||||
result.X = (rowVector.X * m._11) + (rowVector.Y * m._21) + (rowVector.Z * m._31) + (rowVector.W * m._41);
|
||||
result.Y = (rowVector.X * m._12) + (rowVector.Y * m._22) + (rowVector.Z * m._32) + (rowVector.W * m._42);
|
||||
result.Z = (rowVector.X * m._13) + (rowVector.Y * m._23) + (rowVector.Z * m._33) + (rowVector.W * m._43);
|
||||
result.W = (rowVector.X * m._14) + (rowVector.Y * m._24) + (rowVector.Z * m._34) + (rowVector.W * m._44);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Divison
|
||||
|
||||
public static Matrix operator /(Matrix m, float s)
|
||||
{
|
||||
float f = 1 / s;
|
||||
Matrix M = m;
|
||||
|
||||
return .(M.Columns[0] * f, M.Columns[1] * f, M.Columns[2] * f, M.Columns[3] * f);
|
||||
}
|
||||
|
||||
public static Matrix Scaling(float scale)
|
||||
{
|
||||
return .(scale, 0, 0, 0,
|
||||
0, scale, 0, 0,
|
||||
0, 0, scale, 0,
|
||||
0, 0, 0, 1);
|
||||
}
|
||||
|
||||
public static Matrix Scaling(float scaleX, float scaleY, float scaleZ)
|
||||
{
|
||||
return .(scaleX, 0, 0, 0,
|
||||
0, scaleY, 0, 0,
|
||||
0, 0, scaleZ, 0,
|
||||
0, 0, 0, 1);
|
||||
}
|
||||
|
||||
public static Matrix Scaling(Vector3 scale)
|
||||
{
|
||||
return .(scale.X, 0, 0, 0,
|
||||
0, scale.Y, 0, 0,
|
||||
0, 0, scale.Z, 0,
|
||||
0, 0, 0, 1);
|
||||
}
|
||||
|
||||
public static Matrix Translation(float x, float y, float z)
|
||||
{
|
||||
return .(1, 0, 0, x,
|
||||
0, 1, 0, y,
|
||||
0, 0, 1, z,
|
||||
0, 0, 0, 1);
|
||||
}
|
||||
|
||||
public static Matrix Translation(Vector3 translation)
|
||||
{
|
||||
return .(1, 0, 0, translation.X,
|
||||
0, 1, 0, translation.Y,
|
||||
0, 0, 1, translation.Z,
|
||||
0, 0, 0, 1);
|
||||
}
|
||||
|
||||
public static Matrix RotationX(float rot)
|
||||
{
|
||||
float sin = Math.Sin(rot);
|
||||
float cos = Math.Cos(rot);
|
||||
|
||||
return .(1, 0, 0, 0,
|
||||
0, cos, -sin, 0,
|
||||
0, sin, cos, 0,
|
||||
0, 0, 0, 1);
|
||||
}
|
||||
|
||||
public static Matrix RotationY(float rot)
|
||||
{
|
||||
float sin = Math.Sin(rot);
|
||||
float cos = Math.Cos(rot);
|
||||
|
||||
return .(cos, 0, sin, 0,
|
||||
0, 1, 0, 0,
|
||||
-sin, 0, cos, 0,
|
||||
0, 0, 0, 1);
|
||||
}
|
||||
|
||||
public static Matrix RotationZ(float rot)
|
||||
{
|
||||
float sin = Math.Sin(rot);
|
||||
float cos = Math.Cos(rot);
|
||||
|
||||
return .(cos, -sin, 0, 0,
|
||||
sin, cos, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates a view Matrix that is located at specified postion and looks at the given target.
|
||||
* @param position The cameras position.
|
||||
* @param target The point the camera looks at.
|
||||
* @param up A vector defining the up direction of the camera.
|
||||
* @returns a view matrix.
|
||||
*/
|
||||
public static Matrix LookAt(Vector3 position, Vector3 target, Vector3 up)
|
||||
{
|
||||
Vector3 forward = target - position;
|
||||
forward.Normalize();
|
||||
|
||||
Vector3 right = Vector3.Cross(up, forward);
|
||||
right.Normalize();
|
||||
|
||||
Vector3 newUp = Vector3.Cross(forward, right);
|
||||
newUp.Normalize();
|
||||
|
||||
Matrix result = .Identity;
|
||||
|
||||
result.Forward = forward;
|
||||
result.Up = up;
|
||||
result.Right = right;
|
||||
result.Translation.X = -Vector3.Dot(position, right);
|
||||
result.Translation.Y = -Vector3.Dot(position, up);
|
||||
result.Translation.Z = -Vector3.Dot(position, forward);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Returns the transpose of this matrix
|
||||
[DisableChecks]
|
||||
public Matrix Transpose()
|
||||
{
|
||||
return .(_11, _21, _31, _41,
|
||||
_12, _22, _32, _42,
|
||||
_13, _23, _33, _43,
|
||||
_14, _24, _34, _44);
|
||||
}
|
||||
|
||||
/**
|
||||
Calculates the inverse of the matrix.
|
||||
*/
|
||||
[DisableChecks]
|
||||
public float Determinant() mut
|
||||
{
|
||||
// From: Lengyel, Eric. Foundations of Game Engine Development, Volume 1: Mathematics (S.61). Kindle-Version.
|
||||
|
||||
Vector3 a = *(Vector3*)&Columns[0];
|
||||
Vector3 b = *(Vector3*)&Columns[1];
|
||||
Vector3 c = *(Vector3*)&Columns[2];
|
||||
Vector3 d = *(Vector3*)&Columns[3];
|
||||
|
||||
float x = this[3, 0];
|
||||
float y = this[3, 1];
|
||||
float z = this[3, 2];
|
||||
float w = this[3, 3];
|
||||
|
||||
Vector3 s = Vector3.Cross(a, b);
|
||||
Vector3 t = Vector3.Cross(c, d);
|
||||
Vector3 u = y * a - x * b;
|
||||
Vector3 v = w * c - z * d;
|
||||
|
||||
return Vector3.Dot(s, v) + Vector3.Dot(t, u);
|
||||
}
|
||||
|
||||
/**
|
||||
Calculates the inverse of the matrix.
|
||||
*/
|
||||
public Matrix Invert()
|
||||
{
|
||||
// From: Lengyel, Eric. Foundations of Game Engine Development, Volume 1: Mathematics (S.61). Kindle-Version.
|
||||
|
||||
#unwarn
|
||||
Vector3 a = *(Vector3*)&Columns[0];
|
||||
#unwarn
|
||||
Vector3 b = *(Vector3*)&Columns[1];
|
||||
#unwarn
|
||||
Vector3 c = *(Vector3*)&Columns[2];
|
||||
#unwarn
|
||||
Vector3 d = *(Vector3*)&Columns[3];
|
||||
|
||||
float x = this[3, 0];
|
||||
float y = this[3, 1];
|
||||
float z = this[3, 2];
|
||||
float w = this[3, 3];
|
||||
|
||||
Vector3 s = Vector3.Cross(a, b);
|
||||
Vector3 t = Vector3.Cross(c, d);
|
||||
Vector3 u = y * a - x * b;
|
||||
Vector3 v = w * c - z * d;
|
||||
|
||||
float invDet = 1.0f / (Vector3.Dot(s, v) + Vector3.Dot(t, u));
|
||||
|
||||
s *= invDet;
|
||||
t *= invDet;
|
||||
u *= invDet;
|
||||
v *= invDet;
|
||||
|
||||
Vector3 r0 = Vector3.Cross(b, v) + t * y;
|
||||
Vector3 r1 = Vector3.Cross(v, a) - t * x;
|
||||
Vector3 r2 = Vector3.Cross(d, u) + s * w;
|
||||
Vector3 r3 = Vector3.Cross(u, c) - s * z;
|
||||
return .(r0.X, r0.Y, r0.Z, -Vector3.Dot(b, t),
|
||||
r1.X, r1.Y, r1.Z, Vector3.Dot(a, t),
|
||||
r2.X, r2.Y, r2.Z, -Vector3.Dot(d, s),
|
||||
r3.X, r3.Y, r3.Z, Vector3.Dot(c, s));
|
||||
}
|
||||
|
||||
/// Calculates the inverse of the matrix.
|
||||
public static Matrix Invert(in Matrix matrix)
|
||||
{
|
||||
// From: Lengyel, Eric. Foundations of Game Engine Development, Volume 1: Mathematics (S.61). Kindle-Version.
|
||||
|
||||
#unwarn
|
||||
Vector3 a = *(Vector3*)&matrix.Columns[0];
|
||||
#unwarn
|
||||
Vector3 b = *(Vector3*)&matrix.Columns[1];
|
||||
#unwarn
|
||||
Vector3 c = *(Vector3*)&matrix.Columns[2];
|
||||
#unwarn
|
||||
Vector3 d = *(Vector3*)&matrix.Columns[3];
|
||||
|
||||
float x = matrix[3, 0];
|
||||
float y = matrix[3, 1];
|
||||
float z = matrix[3, 2];
|
||||
float w = matrix[3, 3];
|
||||
|
||||
Vector3 s = Vector3.Cross(a, b);
|
||||
Vector3 t = Vector3.Cross(c, d);
|
||||
Vector3 u = y * a - x * b;
|
||||
Vector3 v = w * c - z * d;
|
||||
|
||||
float invDet = 1.0f / (Vector3.Dot(s, v) + Vector3.Dot(t, u));
|
||||
|
||||
s *= invDet;
|
||||
t *= invDet;
|
||||
u *= invDet;
|
||||
v *= invDet;
|
||||
|
||||
Vector3 r0 = Vector3.Cross(b, v) + t * y;
|
||||
Vector3 r1 = Vector3.Cross(v, a) - t * x;
|
||||
Vector3 r2 = Vector3.Cross(d, u) + s * w;
|
||||
Vector3 r3 = Vector3.Cross(u, c) - s * z;
|
||||
return .(r0.X, r0.Y, r0.Z, -Vector3.Dot(b, t),
|
||||
r1.X, r1.Y, r1.Z, Vector3.Dot(a, t),
|
||||
r2.X, r2.Y, r2.Z, -Vector3.Dot(d, s),
|
||||
r3.X, r3.Y, r3.Z, Vector3.Dot(c, s));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a perspective projection matrix.
|
||||
* @param fovY The vertical field of view.
|
||||
* @param aspectRation The aspect ratio of the viewport.
|
||||
* @param nearPlane The distance to the near plane.
|
||||
* @param farPlane The distance to the far plane.
|
||||
*/
|
||||
public static Matrix PerspectiveProjection(float fovY, float aspectRatio, float nearPlane, float farPlane)
|
||||
{
|
||||
// Lengyel, Eric. Foundations of Game Engine Development, Volume 2: Rendering (Seite82). . Kindle-Version.
|
||||
|
||||
float g = 1.0f / Math.Tan(fovY * 0.5f);
|
||||
float k = farPlane / (farPlane - nearPlane);
|
||||
|
||||
return .(g / aspectRatio, 0, 0, 0,
|
||||
0, g, 0, 0,
|
||||
0, 0, k, -nearPlane * k,
|
||||
0, 0, 1, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a perspective projection matrix with reversed near- and far plane.
|
||||
* (i.e. Points on near plane have z-value of 1 and points of far plane have z-value of 0)
|
||||
* @param fovY The vertical field of view.
|
||||
* @param aspectRation The aspect ratio of the viewport.
|
||||
* @param nearPlane The distance to the near plane.
|
||||
* @param farPlane The distance to the far plane.
|
||||
*/
|
||||
public static Matrix ReversedPerspectiveProjection(float fovY, float aspectRatio, float nearPlane, float farPlane)
|
||||
{
|
||||
// Lengyel, Eric. Foundations of Game Engine Development, Volume 2: Rendering (Seite86). . Kindle-Version.
|
||||
|
||||
float g = 1.0f / Math.Tan(fovY * 0.5f);
|
||||
float k = nearPlane / (nearPlane - farPlane);
|
||||
|
||||
return .(g / aspectRatio, 0, 0, 0,
|
||||
0, g, 0, 0,
|
||||
0, 0, k, -farPlane * k,
|
||||
0, 0, 1, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a perspective projection matrix with a far plane at infinity.
|
||||
* @param fovY The vertical field of view.
|
||||
* @param aspectRation The aspect ratio of the viewport.
|
||||
* @param nearPlane The distance to the near plane.
|
||||
* @param ε An offset to account for floating point round-off errors at infinity.
|
||||
* Note: Use a tiny value significant compared to the floating-point value of one.
|
||||
*/
|
||||
public static Matrix InfinitePerspectiveProjection(float fovY, float aspectRatio, float nearPlane, float ε = 1e-6f)
|
||||
{
|
||||
// Lengyel, Eric. Foundations of Game Engine Development, Volume 2: Rendering (Seite83). . Kindle-Version.
|
||||
|
||||
float g = 1.0f / Math.Tan(fovY * 0.5f);
|
||||
|
||||
float f = 1 - ε;
|
||||
|
||||
return .(g / aspectRatio, 0, 0, 0,
|
||||
0, g, 0, 0,
|
||||
0, 0, f, -nearPlane * f,
|
||||
0, 0, 1, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a perspective projection matrix with a far plane at infinity with reversed near- and far plane.
|
||||
* (i.e. Points on near plane have z-value of 1 and points of far plane have z-value of 0)
|
||||
* @param fovY The vertical field of view.
|
||||
* @param aspectRation The aspect ratio of the viewport.
|
||||
* @param nearPlane The distance to the near plane.
|
||||
* @param ε An offset to account for floating point round-off errors at infinity.
|
||||
* Note: Use a tiny value significant compared to the floating-point value of one.
|
||||
*/
|
||||
public static Matrix ReversedInfinitePerspectiveProjection(float fovY, float aspectRatio, float nearPlane, float ε = 1e-6f)
|
||||
{
|
||||
// Lengyel, Eric. Foundations of Game Engine Development, Volume 2: Rendering (Seite88). . Kindle-Version.
|
||||
|
||||
float g = 1.0f / Math.Tan(fovY * 0.5f);
|
||||
|
||||
return .(g / aspectRatio, 0, 0, 0,
|
||||
0, g, 0, 0,
|
||||
0, 0, ε, nearPlane * (1 - ε),
|
||||
0, 0, 1, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an orthographic projection matrix with the camera centered at the near-plane.
|
||||
* @param width The width of the view volume.
|
||||
* @param height The height of the view volume.
|
||||
* @param depth The depth of the view volume.
|
||||
*/
|
||||
public static Matrix OrthographicProjection(float width, float height, float depth)
|
||||
{
|
||||
// Lengyel, Eric. Foundations of Game Engine Development, Volume 2: Rendering (Seite91). . Kindle-Version.
|
||||
return .(2.0f / width, 0, 0, 0,
|
||||
0, 2.0f/height, 0, 0,
|
||||
0, 0, 1.0f / depth, 0,
|
||||
0, 0, 0, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an orthographic projection matrix.
|
||||
* @param left The left side of the view volume.
|
||||
* @param right The right side of the view volume.
|
||||
* @param top The top side of the view volume.
|
||||
* @param bottom The bottom side of the view volume.
|
||||
* @param near The near plane of the view volume.
|
||||
* @param far The far plane of the view volume.
|
||||
*/
|
||||
public static Matrix OrthographicProjectionOffCenter(float left, float right, float top, float bottom, float near, float far)
|
||||
{
|
||||
// Lengyel, Eric. Foundations of Game Engine Development, Volume 2: Rendering (Seite91). . Kindle-Version.
|
||||
|
||||
float w_inv = 1.0f / (right - left);
|
||||
float h_inv = 1.0f / (top - bottom);
|
||||
float d_inv = 1.0f / (far - near);
|
||||
|
||||
return .(2.0f * w_inv, 0.0f, 0.0f, -(right + left) * w_inv,
|
||||
0.0f, 2.0f * h_inv, 0.0f, -(bottom + top) * h_inv,
|
||||
0.0f, 0.0f, d_inv, -near * d_inv,
|
||||
0.0f, 0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
public static bool operator ==(Matrix left, Matrix right)
|
||||
{
|
||||
return Matrix.Equals(left, right);
|
||||
}
|
||||
|
||||
public static bool operator !=(Matrix left, Matrix right)
|
||||
{
|
||||
return !Matrix.Equals(left, right);
|
||||
}
|
||||
|
||||
public static bool Equals(Matrix left, Matrix right)
|
||||
{
|
||||
return left.Values == right.Values;
|
||||
}
|
||||
|
||||
public static explicit operator Matrix3x3(Matrix value)
|
||||
{
|
||||
return .(value.Right, value.Up, value.Forward);
|
||||
}
|
||||
|
||||
public static void Exponent(ref Matrix matrix, int exponent, out Matrix result)
|
||||
{
|
||||
if(exponent == 0)
|
||||
result = .Identity;
|
||||
else if(exponent == 1)
|
||||
result = matrix;
|
||||
else if(exponent > 1)
|
||||
{
|
||||
result = .Identity;
|
||||
Matrix b = matrix;
|
||||
|
||||
var exponent;
|
||||
|
||||
for(;exponent > 0;)
|
||||
{
|
||||
if(exponent & 1 > 0)
|
||||
result *= b;
|
||||
|
||||
exponent >>= 1;
|
||||
|
||||
if(exponent > 0)
|
||||
b *= b;
|
||||
}
|
||||
|
||||
}
|
||||
else // Exponent < 0
|
||||
{
|
||||
Matrix m = matrix.Invert();
|
||||
Exponent(ref m, -exponent, out result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Orthogonalizes the matrix.
|
||||
*/
|
||||
public void Orthogonalize() mut
|
||||
{
|
||||
Columns[1] -= .Project(Columns[1], Columns[0]);
|
||||
Columns[2] -= .Project(Columns[2], Columns[0]) + .Project(Columns[2], Columns[1]);
|
||||
Columns[3] -= .Project(Columns[3], Columns[0]) + .Project(Columns[3], Columns[1]) + .Project(Columns[3], Columns[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Orthonormalizes the matrix.
|
||||
*/
|
||||
public void Orthonormalize() mut
|
||||
{
|
||||
Columns[0].Normalize();
|
||||
Columns[1] = .Normalize(.Reject(Columns[1], Columns[0]));
|
||||
Columns[2] = .Normalize(.Reject(.Reject(Columns[2], Columns[0]), Columns[1]));
|
||||
Columns[3] = .Normalize(.Reject(.Reject(.Reject(Columns[2], Columns[0]), Columns[1]), Columns[2]));
|
||||
}
|
||||
public static Self RotationQuaternion(Quaternion rotation)
|
||||
{
|
||||
float xSq = 2 * rotation.X * rotation.X;
|
||||
float ySq = 2 * rotation.Y * rotation.Y;
|
||||
float zSq = 2 * rotation.Z * rotation.Z;
|
||||
|
||||
float xy = 2 * rotation.X * rotation.Y;
|
||||
float xz = 2 * rotation.X * rotation.Z;
|
||||
float xw = 2 * rotation.X * rotation.W;
|
||||
float yz = 2 * rotation.Y * rotation.Z;
|
||||
float yw = 2 * rotation.Y * rotation.W;
|
||||
float zw = 2 * rotation.Z * rotation.W;
|
||||
|
||||
Self result = ?;
|
||||
|
||||
result._11 = 1 - ySq - zSq;
|
||||
result._21 = xy + zw;
|
||||
result._31 = xz - yw;
|
||||
result._41 = 0;
|
||||
|
||||
result._12 = xy - zw;
|
||||
result._22 = 1 - xSq - zSq;
|
||||
result._32 = yz + xw;
|
||||
result._42 = 0;
|
||||
|
||||
result._13 = xz + yw;
|
||||
result._23 = yz - xw;
|
||||
result._33 = 1 - xSq - ySq;
|
||||
result._43 = 0;
|
||||
|
||||
result._14 = 0;
|
||||
result._24 = 0;
|
||||
result._34 = 0;
|
||||
result._44 = 1;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void Decompose(Self matrix, out Vector3 position, out Quaternion rotation, out Vector3 scale)
|
||||
{
|
||||
var matrix;
|
||||
|
||||
// Translation -> get last column
|
||||
position = matrix.Translation;
|
||||
// Zero translation for next step
|
||||
matrix.Translation = .Zero;
|
||||
|
||||
// TODO: this doesn't detect mirroring
|
||||
|
||||
// Extract scaling from matrix
|
||||
scale.X = (*(Vector3*)&matrix.Columns[0]).Magnitude();
|
||||
scale.Y = (*(Vector3*)&matrix.Columns[1]).Magnitude();
|
||||
scale.Z = (*(Vector3*)&matrix.Columns[2]).Magnitude();
|
||||
|
||||
if(MathHelper.IsZero(scale.X) || MathHelper.IsZero(scale.Y) || MathHelper.IsZero(scale.Z))
|
||||
{
|
||||
rotation = .Identity;
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove scale from matrix (normalize the columns)
|
||||
matrix.Columns[0] /= scale.X;
|
||||
matrix.Columns[1] /= scale.Y;
|
||||
matrix.Columns[2] /= scale.Z;
|
||||
|
||||
rotation = Quaternion.FromMatrix(matrix);
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
using System;
|
||||
using GlitchyEngine.Math;
|
||||
using GlitchyEngine;
|
||||
|
||||
namespace DirectX.Math
|
||||
{
|
||||
extension Matrix
|
||||
{
|
||||
typealias Vec3 = GlitchyEngine.Math.Vector3;
|
||||
|
||||
public static Self RotationQuaternion(Quaternion rotation)
|
||||
{
|
||||
float xSq = 2 * rotation.X * rotation.X;
|
||||
float ySq = 2 * rotation.Y * rotation.Y;
|
||||
float zSq = 2 * rotation.Z * rotation.Z;
|
||||
|
||||
float xy = 2 * rotation.X * rotation.Y;
|
||||
float xz = 2 * rotation.X * rotation.Z;
|
||||
float xw = 2 * rotation.X * rotation.W;
|
||||
float yz = 2 * rotation.Y * rotation.Z;
|
||||
float yw = 2 * rotation.Y * rotation.W;
|
||||
float zw = 2 * rotation.Z * rotation.W;
|
||||
|
||||
Self result = ?;
|
||||
|
||||
result.V._11 = 1 - ySq - zSq;
|
||||
result.V._21 = xy + zw;
|
||||
result.V._31 = xz - yw;
|
||||
result.V._41 = 0;
|
||||
|
||||
result.V._12 = xy - zw;
|
||||
result.V._22 = 1 - xSq - zSq;
|
||||
result.V._32 = yz + xw;
|
||||
result.V._42 = 0;
|
||||
|
||||
result.V._13 = xz + yw;
|
||||
result.V._23 = yz - xw;
|
||||
result.V._33 = 1 - xSq - ySq;
|
||||
result.V._43 = 0;
|
||||
|
||||
result.V._14 = 0;
|
||||
result.V._24 = 0;
|
||||
result.V._34 = 0;
|
||||
result.V._44 = 1;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void Decompose(Self matrix, out Vec3 position, out Quaternion rotation, out Vec3 scale)
|
||||
{
|
||||
var matrix;
|
||||
|
||||
// Translation -> get last column
|
||||
position = matrix.Translation;
|
||||
// Zero translation for next step
|
||||
matrix.Translation = .Zero;
|
||||
|
||||
// TODO: this doesn't detect mirroring
|
||||
|
||||
// Extract scaling from matrix
|
||||
scale.X = (*(Vec3*)&matrix.Columns[0]).Magnitude();
|
||||
scale.Y = (*(Vec3*)&matrix.Columns[1]).Magnitude();
|
||||
scale.Z = (*(Vec3*)&matrix.Columns[2]).Magnitude();
|
||||
|
||||
if(MathHelper.IsZero(scale.X) || MathHelper.IsZero(scale.Y) || MathHelper.IsZero(scale.Z))
|
||||
{
|
||||
rotation = .Identity;
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove scale from matrix (normalize the columns)
|
||||
matrix.Columns[0] /= scale.X;
|
||||
matrix.Columns[1] /= scale.Y;
|
||||
matrix.Columns[2] /= scale.Z;
|
||||
|
||||
rotation = Quaternion.FromMatrix(matrix);
|
||||
}
|
||||
|
||||
/*[Test]
|
||||
static void TestQuaternionToMatrix()
|
||||
{
|
||||
// Rotation around Z-Axis by 90°
|
||||
Quaternion quat = .(0, 0, 0.707107f, 0.707107f);
|
||||
quat.Normalize();
|
||||
|
||||
|
||||
}*/
|
||||
}
|
||||
}
|
||||
@@ -144,7 +144,7 @@ namespace GlitchyEngine.Math
|
||||
{
|
||||
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/
|
||||
|
||||
var m = matrix.V;
|
||||
var m = matrix;
|
||||
|
||||
Quaternion result = ?;
|
||||
|
||||
|
||||
@@ -85,6 +85,7 @@ namespace GlitchyEngine.Renderer
|
||||
SetBlendState(_nonblendingState);
|
||||
|
||||
_clearUintFx.Variables["ClearValue"].SetData(value);
|
||||
_clearUintFx.ApplyChanges();
|
||||
_clearUintFx.Bind();
|
||||
|
||||
FullscreenQuad.Draw();
|
||||
|
||||
@@ -101,7 +101,7 @@ namespace GlitchyEngine.Renderer
|
||||
LoadDdsResourcePlatform(stream, ref nativeTexture);
|
||||
|
||||
let resType = nativeTexture.GetResourceType();
|
||||
Log.EngineLogger.Assert(resType == .Texture2D, scope $"The texture \"{_path}\" is not a 2D texture (it is {resType}).");
|
||||
Log.EngineLogger.Assert(resType == .Texture2D, scope $"The texture is not a 2D texture (it is {resType}).");
|
||||
|
||||
nativeTexture.GetDescription(out nativeDesc);
|
||||
}
|
||||
@@ -261,13 +261,6 @@ namespace GlitchyEngine.Renderer
|
||||
{
|
||||
return .(_nativeResourceView, _samplerState?.nativeSamplerState);
|
||||
}
|
||||
|
||||
protected override void PlatformSneakySwappyTexture(Texture2D otherTexture)
|
||||
{
|
||||
Swap!(nativeDesc, otherTexture.nativeDesc);
|
||||
Swap!(nativeTexture, otherTexture.nativeTexture);
|
||||
Swap!(_nativeResourceView, otherTexture._nativeResourceView);
|
||||
}
|
||||
}
|
||||
|
||||
extension TextureCube
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace GlitchyEngine.Renderer
|
||||
* @param observerVP The view projection of the rendering camera.
|
||||
* @param color The color of the frustum.
|
||||
*/
|
||||
public static void DrawViewFrustum(Matrix worldTransform, Matrix projection, Matrix observerVP, ColorRGBA color = .Red)
|
||||
public static void DrawViewFrustum(Matrix worldTransform, Matrix projection, ColorRGBA color = .Red)
|
||||
{
|
||||
/*if (_frustumGeometry == null)
|
||||
{
|
||||
@@ -111,15 +111,15 @@ namespace GlitchyEngine.Renderer
|
||||
|
||||
Vector4[8] corners;
|
||||
// Perspective
|
||||
if(projection.V._43 != 0.0f)
|
||||
if(projection._43 != 0.0f)
|
||||
{
|
||||
// near plane for perspective projection, far plane if reversed
|
||||
float d1 = -projection.V._34 / projection.V._33;
|
||||
float d1 = -projection._34 / projection._33;
|
||||
|
||||
float d2 = projection.V._34 / (1.0f - projection.V._33);
|
||||
float d2 = projection._34 / (1.0f - projection._33);
|
||||
|
||||
float gOverS = projection.V._11;
|
||||
float g = projection.V._22;
|
||||
float gOverS = projection._11;
|
||||
float g = projection._22;
|
||||
|
||||
//var corners = //(Vector4*)&_vbFrustum.Data;
|
||||
|
||||
@@ -158,14 +158,14 @@ namespace GlitchyEngine.Renderer
|
||||
}
|
||||
else
|
||||
{
|
||||
float l = -(projection.V._14 + 1.0f) / projection.V._11;
|
||||
float r = (1.0f - projection.V._14) / projection.V._11;
|
||||
float l = -(projection._14 + 1.0f) / projection._11;
|
||||
float r = (1.0f - projection._14) / projection._11;
|
||||
|
||||
float t = -(projection.V._24 + 1.0f) / projection.V._22;
|
||||
float b = (1.0f - projection.V._24) / projection.V._22;
|
||||
float t = -(projection._24 + 1.0f) / projection._22;
|
||||
float b = (1.0f - projection._24) / projection._22;
|
||||
|
||||
float n = -projection.V._34 / projection.V._33;
|
||||
float f = (1 - projection.V._34) / projection.V._33;
|
||||
float n = -projection._34 / projection._33;
|
||||
float f = (1 - projection._34) / projection._33;
|
||||
|
||||
//var corners = (Vector4*)&_vbFrustum.Data;
|
||||
corners[0] = .(r, t, n, 1.0f);
|
||||
@@ -184,7 +184,7 @@ namespace GlitchyEngine.Renderer
|
||||
uint16 index0 = indices[i];
|
||||
uint16 index1 = indices[i + 1];
|
||||
|
||||
Renderer.DrawLine(corners[index0], corners[index1], color, worldTransform, observerVP);
|
||||
Renderer2D.DrawLine(worldTransform * corners[index0], worldTransform * corners[index1], color);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -134,7 +134,20 @@ public class Effect : Asset
|
||||
|
||||
BufferVariableCollection _variables ~ delete _;
|
||||
|
||||
typealias TextureEntry = (TextureViewBinding BoundTexture, ShaderTextureCollection.ResourceEntry* VsSlot, ShaderTextureCollection.ResourceEntry* PsSlot);
|
||||
public struct TextureEntry
|
||||
{
|
||||
public TextureViewBinding BoundTexture;
|
||||
public ShaderTextureCollection.ResourceEntry* VsSlot;
|
||||
public ShaderTextureCollection.ResourceEntry* PsSlot;
|
||||
|
||||
public this(TextureViewBinding boundTexture, ShaderTextureCollection.ResourceEntry* vsSlot, ShaderTextureCollection.ResourceEntry* psSlot)
|
||||
{
|
||||
BoundTexture = boundTexture;
|
||||
VsSlot = vsSlot;
|
||||
PsSlot = psSlot;
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary<String, TextureEntry> _textures ~ delete _;
|
||||
|
||||
public Dictionary<String, TextureEntry> Textures => _textures;
|
||||
@@ -199,6 +212,9 @@ public class Effect : Asset
|
||||
{
|
||||
Debug.Profiler.ProfileRendererFunction!();
|
||||
|
||||
if (texture == null)
|
||||
return;
|
||||
|
||||
[Inline]InternalSetTexture(name, texture.GetViewBinding());
|
||||
}
|
||||
|
||||
@@ -725,7 +741,7 @@ public class Effect : Asset
|
||||
// Get existing entry or create new
|
||||
if(!_textures.TryGetValue(shaderEntry.Name, out entry))
|
||||
{
|
||||
entry = (shaderEntry.BoundTexture, null, null);
|
||||
entry = .(shaderEntry.BoundTexture, null, null);
|
||||
entry.BoundTexture.AddRef();
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ public class Material : Asset
|
||||
|
||||
private uint8[] _rawVariables ~ delete _;
|
||||
|
||||
private Dictionary<String, TextureViewBinding> _textures = new .();
|
||||
private Dictionary<String, AssetHandle<Texture>> _textures = new .() ~ delete _;
|
||||
|
||||
private Dictionary<String, (uint32 Offset, BufferVariable Variable)> _variables = new .() ~ delete _;
|
||||
|
||||
@@ -26,26 +26,20 @@ public class Material : Asset
|
||||
|
||||
// TODO: get variables from effect
|
||||
|
||||
// Get texture slots from effect
|
||||
for(let (name, entry) in _effect.Textures)
|
||||
{
|
||||
var texture = entry.BoundTexture;
|
||||
texture.AddRef();
|
||||
// TODO: We need to be able to define default textures in the shader.
|
||||
// At least things like "Black", "White", "Normal"
|
||||
// At best whole paths. Shouldn't be that hard to do...
|
||||
/*var texture = entry.BoundTexture;*/
|
||||
|
||||
_textures.Add(name, texture);
|
||||
_textures.Add(name, .Invalid);
|
||||
}
|
||||
|
||||
InitRawData();
|
||||
}
|
||||
|
||||
public ~this()
|
||||
{
|
||||
for(let (name, texture) in _textures)
|
||||
{
|
||||
texture.Release();
|
||||
}
|
||||
|
||||
delete _textures;
|
||||
}
|
||||
|
||||
/** @brief Initializes the raw data array for the variables.
|
||||
*/
|
||||
@@ -88,12 +82,12 @@ public class Material : Asset
|
||||
* @param name The name of the texture to set.
|
||||
* @param texture The texture to bind to the effect.
|
||||
*/
|
||||
public void SetTexture(String name, Texture texture)
|
||||
public void SetTexture(String name, AssetHandle<Texture> texture)
|
||||
{
|
||||
if(_textures.TryGetValue(name, var entry))
|
||||
{
|
||||
entry.Release();
|
||||
_textures[name] = texture.GetViewBinding();
|
||||
//entry?.ReleaseRef();
|
||||
_textures[name] = texture;
|
||||
//texture?.AddRef();
|
||||
}
|
||||
else
|
||||
|
||||
@@ -1,27 +1,11 @@
|
||||
using System;
|
||||
using GlitchyEngine.World;
|
||||
using GlitchyEngine.Content;
|
||||
|
||||
namespace GlitchyEngine.Renderer
|
||||
{
|
||||
public struct MeshComponent : IDisposableComponent
|
||||
public struct MeshComponent
|
||||
{
|
||||
private GeometryBinding _mesh;
|
||||
public GeometryBinding Mesh
|
||||
{
|
||||
[Inline]
|
||||
get => _mesh;
|
||||
set mut
|
||||
{
|
||||
if(_mesh == value)
|
||||
return;
|
||||
|
||||
SetReference!(_mesh, value);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose() mut
|
||||
{
|
||||
ReleaseRefAndNullify!(_mesh);
|
||||
}
|
||||
public AssetHandle<GeometryBinding> Mesh = .Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ using GlitchyEngine.Math;
|
||||
using GlitchyEngine.World;
|
||||
using System.Collections;
|
||||
using System;
|
||||
using GlitchyEngine.Content;
|
||||
|
||||
namespace GlitchyEngine.Renderer
|
||||
{
|
||||
@@ -79,13 +80,13 @@ namespace GlitchyEngine.Renderer
|
||||
|
||||
static SceneConstants _sceneConstants;
|
||||
|
||||
static Effect LineEffect;
|
||||
//static AssetHandle<Effect> LineEffect;
|
||||
static VertexBuffer LineVertices;
|
||||
static GeometryBinding LineGeometry;
|
||||
|
||||
static GBuffer _gBuffer;
|
||||
static Effect TestFullscreenEffect;
|
||||
static Effect s_tonemappingEffect;
|
||||
static AssetHandle<Effect> TestFullscreenEffect;
|
||||
static AssetHandle<Effect> s_tonemappingEffect;
|
||||
|
||||
static BlendState _gBufferBlend;
|
||||
static BlendState _lightBlend;
|
||||
@@ -132,7 +133,7 @@ namespace GlitchyEngine.Renderer
|
||||
{
|
||||
Debug.Profiler.ProfileFunction!();
|
||||
|
||||
LineEffect = Content.LoadAsset<Effect>("Shaders\\lineShader.hlsl");
|
||||
//LineEffect = Content.LoadAsset("Shaders\\lineShader.hlsl");
|
||||
|
||||
LineGeometry = new GeometryBinding();
|
||||
LineGeometry.SetPrimitiveTopology(.LineList);
|
||||
@@ -158,13 +159,12 @@ namespace GlitchyEngine.Renderer
|
||||
{
|
||||
LineVertices.ReleaseRef();
|
||||
LineGeometry.ReleaseRef();
|
||||
LineEffect.ReleaseRef();
|
||||
}
|
||||
|
||||
static void InitDeferredRenderer()
|
||||
{
|
||||
TestFullscreenEffect = Content.LoadAsset<Effect>("Shaders\\simpleLight.hlsl");
|
||||
s_tonemappingEffect = Content.LoadAsset<Effect>("Shaders\\SimpleTonemapping.hlsl");
|
||||
TestFullscreenEffect = Content.LoadAsset("Shaders\\simpleLight.hlsl");
|
||||
s_tonemappingEffect = Content.LoadAsset("Shaders\\SimpleTonemapping.hlsl");
|
||||
|
||||
_gBuffer = new GBuffer();
|
||||
BlendStateDescription gBufferBlendDesc = .Default;
|
||||
@@ -203,9 +203,6 @@ namespace GlitchyEngine.Renderer
|
||||
_lightBlend.ReleaseRef();
|
||||
_gBufferBlend.ReleaseRef();
|
||||
delete _gBuffer;
|
||||
|
||||
s_tonemappingEffect.ReleaseRef();
|
||||
TestFullscreenEffect.ReleaseRef();
|
||||
}
|
||||
|
||||
// [Obsolete("", false)]
|
||||
@@ -346,22 +343,23 @@ namespace GlitchyEngine.Renderer
|
||||
|
||||
Vector3 lightDir = -light.Transform.Forward;
|
||||
|
||||
TestFullscreenEffect.SetTexture("GBuffer_Albedo", _gBuffer.Target, 0);
|
||||
TestFullscreenEffect.SetTexture("GBuffer_Normal", _gBuffer.Target, 1);
|
||||
TestFullscreenEffect.SetTexture("GBuffer_Tangent", _gBuffer.Target, 2);
|
||||
TestFullscreenEffect.SetTexture("GBuffer_Position", _gBuffer.Target, 3);
|
||||
TestFullscreenEffect.SetTexture("GBuffer_Material", _gBuffer.Target, 4);
|
||||
Effect fsEffect = TestFullscreenEffect.Get();
|
||||
fsEffect.SetTexture("GBuffer_Albedo", _gBuffer.Target, 0);
|
||||
fsEffect.SetTexture("GBuffer_Normal", _gBuffer.Target, 1);
|
||||
fsEffect.SetTexture("GBuffer_Tangent", _gBuffer.Target, 2);
|
||||
fsEffect.SetTexture("GBuffer_Position", _gBuffer.Target, 3);
|
||||
fsEffect.SetTexture("GBuffer_Material", _gBuffer.Target, 4);
|
||||
|
||||
TestFullscreenEffect.Variables["LightColor"].SetData(light.Light.Color);
|
||||
TestFullscreenEffect.Variables["Illuminance"].SetData(light.Light.Illuminance);
|
||||
TestFullscreenEffect.Variables["LightDir"].SetData(lightDir);
|
||||
fsEffect.Variables["LightColor"].SetData(light.Light.Color);
|
||||
fsEffect.Variables["Illuminance"].SetData(light.Light.Illuminance);
|
||||
fsEffect.Variables["LightDir"].SetData(lightDir);
|
||||
|
||||
TestFullscreenEffect.Variables["CameraPos"].SetData(_sceneConstants.CameraPosition);
|
||||
fsEffect.Variables["CameraPos"].SetData(_sceneConstants.CameraPosition);
|
||||
|
||||
TestFullscreenEffect.Variables["Scaling"].SetData(scaling);
|
||||
fsEffect.Variables["Scaling"].SetData(scaling);
|
||||
|
||||
TestFullscreenEffect.ApplyChanges();
|
||||
TestFullscreenEffect.Bind();
|
||||
fsEffect.ApplyChanges();
|
||||
fsEffect.Bind();
|
||||
|
||||
//RenderCommand.BindEffect(TestFullscreenEffect);
|
||||
|
||||
@@ -379,10 +377,11 @@ namespace GlitchyEngine.Renderer
|
||||
RenderCommand.BindRenderTargets();
|
||||
RenderCommand.SetRenderTargetGroup(_sceneConstants.CompositionTarget, true);
|
||||
|
||||
Effect toneMappingFx = s_tonemappingEffect.Get();
|
||||
// TODO: Postprocessing effects
|
||||
s_tonemappingEffect.SetTexture("CameraTarget", _sceneConstants.CameraTarget, 0);
|
||||
s_tonemappingEffect.ApplyChanges();
|
||||
s_tonemappingEffect.Bind();
|
||||
toneMappingFx.SetTexture("CameraTarget", _sceneConstants.CameraTarget, 0);
|
||||
toneMappingFx.ApplyChanges();
|
||||
toneMappingFx.Bind();
|
||||
|
||||
RenderCommand.BindRenderTargets();
|
||||
//RenderCommand.BindEffect(s_tonemappingEffect);
|
||||
@@ -470,6 +469,9 @@ namespace GlitchyEngine.Renderer
|
||||
{
|
||||
Debug.Profiler.ProfileRendererFunction!();
|
||||
|
||||
if (geometry == null || material == null)
|
||||
return;
|
||||
|
||||
_queue.Add(SubmittedMesh(geometry, material, transform, entity.[Friend]Index));
|
||||
}
|
||||
|
||||
@@ -485,9 +487,10 @@ namespace GlitchyEngine.Renderer
|
||||
* @param end The end point of the line.
|
||||
* @param color The color of the line.
|
||||
*/
|
||||
public static void DrawLine(Vector3 start, Vector3 end, Color color)
|
||||
public static void DrawLine(Vector3 start, Vector3 end, ColorRGBA color)
|
||||
{
|
||||
DrawLine(Vector4(start, 1.0f), Vector4(end, 1.0f), (ColorRGBA)color, .Identity);
|
||||
Renderer2D.DrawLine(start, end, color);
|
||||
//DrawLine(Vector4(start, 1.0f), Vector4(end, 1.0f), (ColorRGBA)color, .Identity);
|
||||
}
|
||||
|
||||
/** @brief Draws a line.
|
||||
@@ -498,7 +501,7 @@ namespace GlitchyEngine.Renderer
|
||||
*/
|
||||
public static void DrawLine(Vector3 start, Vector3 end, ColorRGBA color, Matrix transform)
|
||||
{
|
||||
DrawLine(Vector4(start, 1.0f), Vector4(end, 1.0f), color, transform);
|
||||
Renderer2D.DrawLine(transform * Vector4(start, 1.0f), transform * Vector4(end, 1.0f), color);
|
||||
}
|
||||
|
||||
/** @brief Draws a ray.
|
||||
@@ -508,7 +511,7 @@ namespace GlitchyEngine.Renderer
|
||||
*/
|
||||
public static void DrawRay(Vector3 start, Vector3 direction, ColorRGBA color)
|
||||
{
|
||||
DrawLine(Vector4(start, 1.0f), Vector4(direction, 0.0f), color, .Identity);
|
||||
Renderer2D.DrawRay(start, direction, color);
|
||||
}
|
||||
|
||||
/** @brief Draws a ray.
|
||||
@@ -519,50 +522,7 @@ namespace GlitchyEngine.Renderer
|
||||
*/
|
||||
public static void DrawRay(Vector3 start, Vector3 direction, ColorRGBA color, Matrix transform)
|
||||
{
|
||||
DrawLine(Vector4(start, 1.0f), Vector4(direction, 0.0f), color, transform);
|
||||
}
|
||||
|
||||
/** @brief Draws a line.
|
||||
* @param start The start point of the line.
|
||||
* @param end The end point of the line.
|
||||
* @param color The color of the line.
|
||||
* @param transform A transform matrix transforming the line.
|
||||
*/
|
||||
public static void DrawLine(Vector4 start, Vector4 end, ColorRGBA color, Matrix transform)
|
||||
{
|
||||
Debug.Profiler.ProfileRendererFunction!();
|
||||
|
||||
LineVertices.SetData(Vector4[2](start, end), 0, .WriteDiscard);
|
||||
LineEffect.Variables["ViewProjection"].SetData(_sceneConstants.ViewProjection * transform);
|
||||
LineEffect.Variables["Color"].SetData(color);
|
||||
|
||||
LineEffect.ApplyChanges();
|
||||
LineEffect.Bind();
|
||||
|
||||
LineGeometry.Bind();
|
||||
RenderCommand.DrawIndexed(LineGeometry);
|
||||
}
|
||||
|
||||
/** @brief Draws a line.
|
||||
* @param start The start point of the line.
|
||||
* @param end The end point of the line.
|
||||
* @param color The color of the line.
|
||||
* @param transform A transform matrix transforming the line.
|
||||
* @param viewProjection The observing cameras viewprojection
|
||||
*/
|
||||
public static void DrawLine(Vector4 start, Vector4 end, ColorRGBA color, Matrix transform, Matrix viewProjection)
|
||||
{
|
||||
Debug.Profiler.ProfileRendererFunction!();
|
||||
|
||||
LineVertices.SetData(Vector4[2](start, end), 0, .WriteDiscard);
|
||||
LineEffect.Variables["ViewProjection"].SetData(viewProjection * transform);
|
||||
LineEffect.Variables["Color"].SetData(color);
|
||||
|
||||
LineEffect.ApplyChanges();
|
||||
LineEffect.Bind();
|
||||
|
||||
LineGeometry.Bind();
|
||||
RenderCommand.DrawIndexed(LineGeometry);
|
||||
Renderer2D.DrawLine(transform * Vector4(start, 1.0f), transform * Vector4(direction, 0.0f), color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,23 @@ namespace GlitchyEngine.Renderer
|
||||
}
|
||||
|
||||
[CRepr]
|
||||
struct BatchVertex
|
||||
struct LineBatchVertex
|
||||
{
|
||||
public Vector4 Position;
|
||||
public ColorRGBA Color;
|
||||
|
||||
public uint32 EntityId;
|
||||
|
||||
public this(Vector4 position, ColorRGBA color, uint32 entityId)
|
||||
{
|
||||
Position = position;
|
||||
Color = color;
|
||||
EntityId = entityId;
|
||||
}
|
||||
}
|
||||
|
||||
[CRepr]
|
||||
struct QuadBatchVertex
|
||||
{
|
||||
public Matrix Transform;
|
||||
public ColorRGBA Color;
|
||||
@@ -62,7 +78,7 @@ namespace GlitchyEngine.Renderer
|
||||
}
|
||||
|
||||
[CRepr]
|
||||
struct CircleBatchVertex : BatchVertex
|
||||
struct CircleBatchVertex : QuadBatchVertex
|
||||
{
|
||||
public float InnerRadius;
|
||||
|
||||
@@ -94,6 +110,8 @@ namespace GlitchyEngine.Renderer
|
||||
FrontToBack
|
||||
}
|
||||
|
||||
struct QueueLine: this(Vector4 Start, Vector4 End, ColorRGBA Color, float Depth, uint32 entityId = uint32.MaxValue) { }
|
||||
|
||||
struct QueueQuad: this(Matrix Transform, ColorRGBA Color, Texture Texture, float Depth, Vector4 uvTransform, uint32 entityId = uint32.MaxValue) { }
|
||||
|
||||
struct QueueCircle : QueueQuad
|
||||
@@ -112,8 +130,9 @@ namespace GlitchyEngine.Renderer
|
||||
private static bool s_sceneRunning;
|
||||
#endif
|
||||
|
||||
private static Effect s_batchEffect;
|
||||
private static Effect s_quadBatchEffect;
|
||||
private static Effect s_circleBatchEffect;
|
||||
private static Effect s_lineBatchEffect;
|
||||
|
||||
private static GeometryBinding s_quadGeometry;
|
||||
|
||||
@@ -121,23 +140,30 @@ namespace GlitchyEngine.Renderer
|
||||
|
||||
private static GeometryBinding s_quadBatchBinding;
|
||||
private static GeometryBinding s_circleBatchBinding;
|
||||
private static GeometryBinding s_lineBatchBinding;
|
||||
private static VertexBuffer s_quadInstanceBuffer;
|
||||
private static VertexBuffer s_circleInstanceBuffer;
|
||||
private static VertexBuffer s_lineInstanceBuffer;
|
||||
|
||||
private static uint32 s_maxInstancesPerBatch = 8192;
|
||||
|
||||
private static BatchVertex[] s_rawQuadInstances;
|
||||
private static QuadBatchVertex[] s_rawQuadInstances;
|
||||
private static CircleBatchVertex[] s_rawCircleInstances;
|
||||
private static uint32 s_setInstances = 0;
|
||||
private static LineBatchVertex[] s_rawLineVertices;
|
||||
private static uint32 s_setQuadInstances = 0;
|
||||
private static uint32 s_setCircleInstances = 0;
|
||||
private static uint32 s_setLineInstances = 0;
|
||||
|
||||
private static List<QueueQuad> s_QuadinstanceQueue;
|
||||
private static List<QueueCircle> s_circleInstanceQueue;
|
||||
private static List<QueueLine> s_lineInstanceQueue;
|
||||
|
||||
private static DrawOrder s_drawOrder;
|
||||
|
||||
/// The effect that is currently used to draw the sprites.
|
||||
private static Effect s_currentEffect;
|
||||
private static Effect s_currentQuadEffect;
|
||||
private static Effect s_currentCircleEffect;
|
||||
private static Effect s_currentLineEffect;
|
||||
|
||||
public static uint32 MaxInstancesPerBatch
|
||||
{
|
||||
@@ -157,8 +183,9 @@ namespace GlitchyEngine.Renderer
|
||||
{
|
||||
Debug.Profiler.ProfileFunction!();
|
||||
|
||||
s_batchEffect = new Effect("content\\Shaders\\spritebatch.hlsl");
|
||||
s_quadBatchEffect = new Effect("content\\Shaders\\spritebatch.hlsl");
|
||||
s_circleBatchEffect = new Effect("content\\Shaders\\circlebatch.hlsl");
|
||||
s_lineBatchEffect = new Effect("content\\Shaders\\linebatch.hlsl");
|
||||
}
|
||||
|
||||
private static void InitGeometry()
|
||||
@@ -252,6 +279,23 @@ namespace GlitchyEngine.Renderer
|
||||
s_circleBatchBinding.SetIndexBuffer(s_quadGeometry.GetIndexBuffer(), 0);
|
||||
}
|
||||
|
||||
// Line
|
||||
{
|
||||
VertexElement[] vertexElements = new .(
|
||||
VertexElement(.R32G32B32A32_Float, "POSITION", false, 0, 0, 0, .PerVertexData, 0),
|
||||
VertexElement(.R32G32B32A32_Float, "COLOR", false, 0, 0, (.)-1, .PerVertexData, 0),
|
||||
VertexElement(.R32_UInt, "ENTITYID", false, 0, 0, (.)-1, .PerVertexData, 0)
|
||||
);
|
||||
|
||||
s_lineBatchBinding = new GeometryBinding();
|
||||
s_lineBatchBinding.SetPrimitiveTopology(.LineList);
|
||||
|
||||
using (var lineBatchLayout = new VertexLayout(vertexElements, true))
|
||||
{
|
||||
s_lineBatchBinding.SetVertexLayout(lineBatchLayout);
|
||||
}
|
||||
}
|
||||
|
||||
ApplyInstanceCount();
|
||||
}
|
||||
|
||||
@@ -262,7 +306,7 @@ namespace GlitchyEngine.Renderer
|
||||
|
||||
// Quads
|
||||
{
|
||||
VertexBuffer quadInstanceBuffer = new VertexBuffer(typeof(BatchVertex), s_maxInstancesPerBatch, .Dynamic, .Write);
|
||||
VertexBuffer quadInstanceBuffer = new VertexBuffer(typeof(QuadBatchVertex), s_maxInstancesPerBatch, .Dynamic, .Write);
|
||||
quadInstanceBuffer.SetData(0);
|
||||
|
||||
s_quadInstanceBuffer?.ReleaseRef();
|
||||
@@ -271,7 +315,7 @@ namespace GlitchyEngine.Renderer
|
||||
|
||||
delete s_rawQuadInstances;
|
||||
delete s_QuadinstanceQueue;
|
||||
s_rawQuadInstances = new BatchVertex[s_maxInstancesPerBatch];
|
||||
s_rawQuadInstances = new QuadBatchVertex[s_maxInstancesPerBatch];
|
||||
s_QuadinstanceQueue = new List<QueueQuad>(s_maxInstancesPerBatch);
|
||||
|
||||
}
|
||||
@@ -290,6 +334,21 @@ namespace GlitchyEngine.Renderer
|
||||
s_rawCircleInstances = new CircleBatchVertex[s_maxInstancesPerBatch];
|
||||
s_circleInstanceQueue = new List<QueueCircle>(s_maxInstancesPerBatch);
|
||||
}
|
||||
|
||||
// Lines
|
||||
{
|
||||
VertexBuffer lineInstanceBuffer = new VertexBuffer(typeof(LineBatchVertex), s_maxInstancesPerBatch, .Dynamic, .Write);
|
||||
lineInstanceBuffer.SetData(0);
|
||||
|
||||
s_lineInstanceBuffer?.ReleaseRef();
|
||||
s_lineInstanceBuffer = lineInstanceBuffer;
|
||||
s_lineBatchBinding.SetVertexBufferSlot(s_lineInstanceBuffer, 0);
|
||||
|
||||
delete s_rawLineVertices;
|
||||
delete s_lineInstanceQueue;
|
||||
s_rawLineVertices = new LineBatchVertex[s_maxInstancesPerBatch];
|
||||
s_lineInstanceQueue = new List<QueueLine>(s_maxInstancesPerBatch);
|
||||
}
|
||||
}
|
||||
|
||||
private static void InitWhitetexture()
|
||||
@@ -366,8 +425,9 @@ namespace GlitchyEngine.Renderer
|
||||
|
||||
FontRenderer.Deinit();
|
||||
|
||||
s_batchEffect.ReleaseRef();
|
||||
s_quadBatchEffect.ReleaseRef();
|
||||
s_circleBatchEffect.ReleaseRef();
|
||||
s_lineBatchEffect.ReleaseRef();
|
||||
|
||||
s_quadGeometry.ReleaseRef();
|
||||
|
||||
@@ -375,16 +435,21 @@ namespace GlitchyEngine.Renderer
|
||||
|
||||
s_quadBatchBinding.ReleaseRef();
|
||||
s_circleBatchBinding.ReleaseRef();
|
||||
s_lineBatchBinding.ReleaseRef();
|
||||
s_quadInstanceBuffer.ReleaseRef();
|
||||
s_circleInstanceBuffer.ReleaseRef();
|
||||
s_lineInstanceBuffer.ReleaseRef();
|
||||
|
||||
delete s_rawQuadInstances;
|
||||
delete s_rawCircleInstances;
|
||||
delete s_rawLineVertices;
|
||||
delete s_QuadinstanceQueue;
|
||||
delete s_circleInstanceQueue;
|
||||
delete s_lineInstanceQueue;
|
||||
|
||||
s_currentEffect?.ReleaseRef();
|
||||
s_currentQuadEffect?.ReleaseRef();
|
||||
s_currentCircleEffect?.ReleaseRef();
|
||||
s_currentLineEffect?.ReleaseRef();
|
||||
|
||||
s_opaqueBlendState.ReleaseRef();
|
||||
s_transparentBlendState.ReleaseRef();
|
||||
@@ -405,14 +470,14 @@ namespace GlitchyEngine.Renderer
|
||||
|
||||
//s_textureColorEffect.Bind(Renderer._context);
|
||||
|
||||
s_currentEffect?.ReleaseRef();
|
||||
s_currentQuadEffect?.ReleaseRef();
|
||||
if(effect != null)
|
||||
{
|
||||
s_currentEffect = effect..AddRef();
|
||||
s_currentQuadEffect = effect..AddRef();
|
||||
}
|
||||
else
|
||||
{
|
||||
s_currentEffect = s_batchEffect..AddRef();
|
||||
s_currentQuadEffect = s_quadBatchEffect..AddRef();
|
||||
}
|
||||
|
||||
s_currentCircleEffect?.ReleaseRef();
|
||||
@@ -425,7 +490,7 @@ namespace GlitchyEngine.Renderer
|
||||
s_currentCircleEffect = s_circleBatchEffect..AddRef();
|
||||
}
|
||||
|
||||
s_currentEffect.Variables["ViewProjection"].SetData(camera.ViewProjection);
|
||||
s_currentQuadEffect.Variables["ViewProjection"].SetData(camera.ViewProjection);
|
||||
s_currentCircleEffect.Variables["ViewProjection"].SetData(camera.ViewProjection);
|
||||
|
||||
s_drawOrder = drawOrder;
|
||||
@@ -445,14 +510,14 @@ namespace GlitchyEngine.Renderer
|
||||
|
||||
//s_textureColorEffect.Bind(Renderer._context);
|
||||
|
||||
s_currentEffect?.ReleaseRef();
|
||||
s_currentQuadEffect?.ReleaseRef();
|
||||
if(effect != null)
|
||||
{
|
||||
s_currentEffect = effect..AddRef();
|
||||
s_currentQuadEffect = effect..AddRef();
|
||||
}
|
||||
else
|
||||
{
|
||||
s_currentEffect = s_batchEffect..AddRef();
|
||||
s_currentQuadEffect = s_quadBatchEffect..AddRef();
|
||||
}
|
||||
|
||||
s_currentCircleEffect?.ReleaseRef();
|
||||
@@ -465,10 +530,21 @@ namespace GlitchyEngine.Renderer
|
||||
s_currentCircleEffect = s_circleBatchEffect..AddRef();
|
||||
}
|
||||
|
||||
s_currentLineEffect?.ReleaseRef();
|
||||
/*if(circleEffect != null)
|
||||
{
|
||||
s_currentLineEffect = effect..AddRef();
|
||||
}
|
||||
else
|
||||
{*/
|
||||
s_currentLineEffect = s_lineBatchEffect..AddRef();
|
||||
//}
|
||||
|
||||
Matrix viewProjection = camera.Projection * Matrix.Invert(transform);
|
||||
|
||||
s_currentEffect.Variables["ViewProjection"].SetData(viewProjection);
|
||||
s_currentQuadEffect.Variables["ViewProjection"].SetData(viewProjection);
|
||||
s_currentCircleEffect.Variables["ViewProjection"].SetData(viewProjection);
|
||||
s_currentLineEffect.Variables["ViewProjection"].SetData(viewProjection);
|
||||
|
||||
s_drawOrder = drawOrder;
|
||||
|
||||
@@ -487,14 +563,14 @@ namespace GlitchyEngine.Renderer
|
||||
|
||||
//s_textureColorEffect.Bind(Renderer._context);
|
||||
|
||||
s_currentEffect?.ReleaseRef();
|
||||
s_currentQuadEffect?.ReleaseRef();
|
||||
if(effect != null)
|
||||
{
|
||||
s_currentEffect = effect..AddRef();
|
||||
s_currentQuadEffect = effect..AddRef();
|
||||
}
|
||||
else
|
||||
{
|
||||
s_currentEffect = s_batchEffect..AddRef();
|
||||
s_currentQuadEffect = s_quadBatchEffect..AddRef();
|
||||
}
|
||||
|
||||
s_currentCircleEffect?.ReleaseRef();
|
||||
@@ -507,10 +583,21 @@ namespace GlitchyEngine.Renderer
|
||||
s_currentCircleEffect = s_circleBatchEffect..AddRef();
|
||||
}
|
||||
|
||||
s_currentLineEffect?.ReleaseRef();
|
||||
/*if(circleEffect != null)
|
||||
{
|
||||
s_currentLineEffect = effect..AddRef();
|
||||
}
|
||||
else
|
||||
{*/
|
||||
s_currentLineEffect = s_lineBatchEffect..AddRef();
|
||||
//}
|
||||
|
||||
Matrix viewProjection = camera.Projection * camera.View;
|
||||
|
||||
s_currentEffect.Variables["ViewProjection"].SetData(viewProjection);
|
||||
s_currentQuadEffect.Variables["ViewProjection"].SetData(viewProjection);
|
||||
s_currentCircleEffect.Variables["ViewProjection"].SetData(viewProjection);
|
||||
s_currentLineEffect.Variables["ViewProjection"].SetData(viewProjection);
|
||||
|
||||
s_drawOrder = drawOrder;
|
||||
|
||||
@@ -559,22 +646,30 @@ namespace GlitchyEngine.Renderer
|
||||
s_statistics.CircleCount++;
|
||||
}
|
||||
|
||||
private static void FlushInstances()
|
||||
/// Adds a line instance to the instance queue.
|
||||
[Inline]
|
||||
private static void QueueLineInstance(Vector4 start, Vector4 end, ColorRGBA color, uint32 id = uint32.MaxValue)
|
||||
{
|
||||
s_lineInstanceQueue.Add(QueueLine(start, end, color, id));
|
||||
s_statistics.LineCount++;
|
||||
}
|
||||
|
||||
private static void FlushQuadInstances()
|
||||
{
|
||||
Debug.Profiler.ProfileRendererFunction!();
|
||||
|
||||
if(s_setInstances == 0)
|
||||
if(s_setQuadInstances == 0)
|
||||
return;
|
||||
|
||||
s_quadInstanceBuffer.SetData<BatchVertex>(s_rawQuadInstances.Ptr, s_setInstances, 0, .WriteDiscard);
|
||||
s_quadInstanceBuffer.SetData<QuadBatchVertex>(s_rawQuadInstances.Ptr, s_setQuadInstances, 0, .WriteDiscard);
|
||||
|
||||
s_currentEffect.ApplyChanges();
|
||||
s_currentEffect.Bind();
|
||||
s_quadBatchBinding.InstanceCount = s_setInstances;
|
||||
s_currentQuadEffect.ApplyChanges();
|
||||
s_currentQuadEffect.Bind();
|
||||
s_quadBatchBinding.InstanceCount = s_setQuadInstances;
|
||||
s_quadBatchBinding.Bind();
|
||||
RenderCommand.DrawIndexedInstanced(s_quadBatchBinding);
|
||||
|
||||
s_setInstances = 0;
|
||||
s_setQuadInstances = 0;
|
||||
|
||||
s_statistics.QuadDrawCalls++;
|
||||
}
|
||||
@@ -583,22 +678,42 @@ namespace GlitchyEngine.Renderer
|
||||
{
|
||||
Debug.Profiler.ProfileRendererFunction!();
|
||||
|
||||
if(s_setInstances == 0)
|
||||
if(s_setCircleInstances == 0)
|
||||
return;
|
||||
|
||||
s_circleInstanceBuffer.SetData<CircleBatchVertex>(s_rawCircleInstances.Ptr, s_setInstances, 0, .WriteDiscard);
|
||||
s_circleInstanceBuffer.SetData<CircleBatchVertex>(s_rawCircleInstances.Ptr, s_setCircleInstances, 0, .WriteDiscard);
|
||||
|
||||
s_currentCircleEffect.ApplyChanges();
|
||||
s_currentCircleEffect.Bind();
|
||||
s_circleBatchBinding.InstanceCount = s_setInstances;
|
||||
s_circleBatchBinding.InstanceCount = s_setCircleInstances;
|
||||
s_circleBatchBinding.Bind();
|
||||
RenderCommand.DrawIndexedInstanced(s_circleBatchBinding);
|
||||
|
||||
s_setInstances = 0;
|
||||
s_setCircleInstances = 0;
|
||||
|
||||
s_statistics.CircleDrawCalls++;
|
||||
}
|
||||
|
||||
private static void FlushLineInstances()
|
||||
{
|
||||
Debug.Profiler.ProfileRendererFunction!();
|
||||
|
||||
if(s_setLineInstances == 0)
|
||||
return;
|
||||
|
||||
s_lineInstanceBuffer.SetData<LineBatchVertex>(s_rawLineVertices.Ptr, s_setLineInstances, 0, .WriteDiscard);
|
||||
|
||||
s_currentLineEffect.ApplyChanges();
|
||||
s_currentLineEffect.Bind();
|
||||
s_lineBatchBinding.VertexCount = (.)s_setLineInstances;
|
||||
s_lineBatchBinding.Bind();
|
||||
RenderCommand.DrawIndexed(s_lineBatchBinding);
|
||||
|
||||
s_setLineInstances = 0;
|
||||
|
||||
s_statistics.LineDrawCalls++;
|
||||
}
|
||||
|
||||
// Quad comparison
|
||||
private static int TextureComparison(QueueQuad lhs, QueueQuad rhs)
|
||||
{
|
||||
@@ -627,6 +742,20 @@ namespace GlitchyEngine.Renderer
|
||||
return lhs.Depth <=> rhs.Depth;
|
||||
}
|
||||
|
||||
// Line comparison
|
||||
/*private static int TextureComparison(QueueLine lhs, QueueLine rhs)
|
||||
{
|
||||
return (int)Internal.UnsafeCastToPtr(lhs.Texture) - (int)Internal.UnsafeCastToPtr(rhs.Texture);
|
||||
}*/
|
||||
private static int BackToFrontComparison(QueueLine lhs, QueueLine rhs)
|
||||
{
|
||||
return rhs.Depth <=> lhs.Depth;
|
||||
}
|
||||
private static int FrontToBackComparison(QueueLine lhs, QueueLine rhs)
|
||||
{
|
||||
return lhs.Depth <=> rhs.Depth;
|
||||
}
|
||||
|
||||
private static void SortInstances()
|
||||
{
|
||||
Debug.Profiler.ProfileRendererFunction!();
|
||||
@@ -636,12 +765,16 @@ namespace GlitchyEngine.Renderer
|
||||
case .SortByTexture:
|
||||
s_QuadinstanceQueue.Sort(scope => TextureComparison);
|
||||
s_circleInstanceQueue.Sort(scope => TextureComparison);
|
||||
/*Lines cant be sorted by texture*/
|
||||
s_lineInstanceQueue.Sort(scope => BackToFrontComparison);
|
||||
case .BackToFront:
|
||||
s_QuadinstanceQueue.Sort(scope => BackToFrontComparison);
|
||||
s_circleInstanceQueue.Sort(scope => BackToFrontComparison);
|
||||
s_lineInstanceQueue.Sort(scope => BackToFrontComparison);
|
||||
case .FrontToBack:
|
||||
s_QuadinstanceQueue.Sort(scope => FrontToBackComparison);
|
||||
s_circleInstanceQueue.Sort(scope => FrontToBackComparison);
|
||||
s_lineInstanceQueue.Sort(scope => FrontToBackComparison);
|
||||
case .Immediate:
|
||||
default:
|
||||
Log.EngineLogger.Error("Unknown instance draw order.");
|
||||
@@ -652,13 +785,14 @@ namespace GlitchyEngine.Renderer
|
||||
{
|
||||
Debug.Profiler.ProfileRendererFunction!();
|
||||
|
||||
if(s_QuadinstanceQueue.IsEmpty && s_circleInstanceQueue.IsEmpty)
|
||||
if(s_QuadinstanceQueue.IsEmpty && s_circleInstanceQueue.IsEmpty && s_lineInstanceQueue.IsEmpty)
|
||||
return;
|
||||
|
||||
SortInstances();
|
||||
|
||||
DrawDeferredQuads();
|
||||
DrawDeferredCircles();
|
||||
DrawDeferredLines();
|
||||
}
|
||||
|
||||
private static void DrawDeferredQuads()
|
||||
@@ -672,9 +806,9 @@ namespace GlitchyEngine.Renderer
|
||||
RenderCommand.SetBlendState(s_transparentBlendState);
|
||||
|
||||
Texture texture = s_QuadinstanceQueue[0].Texture;
|
||||
s_currentEffect.SetTexture("Texture", texture);
|
||||
s_currentQuadEffect.SetTexture("Texture", texture);
|
||||
|
||||
s_setInstances = 0;
|
||||
s_setQuadInstances = 0;
|
||||
|
||||
for(int i < s_QuadinstanceQueue.Count)
|
||||
{
|
||||
@@ -683,21 +817,21 @@ namespace GlitchyEngine.Renderer
|
||||
// flush every time the texture changes
|
||||
if(quad.Texture != texture)
|
||||
{
|
||||
FlushInstances();
|
||||
FlushQuadInstances();
|
||||
|
||||
texture = quad.Texture;
|
||||
s_currentEffect.SetTexture("Texture", texture);
|
||||
s_currentQuadEffect.SetTexture("Texture", texture);
|
||||
}
|
||||
|
||||
s_rawQuadInstances[s_setInstances++] = .(quad.Transform, quad.Color, quad.uvTransform, quad.entityId);
|
||||
s_rawQuadInstances[s_setQuadInstances++] = .(quad.Transform, quad.Color, quad.uvTransform, quad.entityId);
|
||||
|
||||
if(s_setInstances == s_rawQuadInstances.Count)
|
||||
if(s_setQuadInstances == s_rawQuadInstances.Count)
|
||||
{
|
||||
FlushInstances();
|
||||
FlushQuadInstances();
|
||||
}
|
||||
}
|
||||
|
||||
FlushInstances();
|
||||
FlushQuadInstances();
|
||||
|
||||
s_QuadinstanceQueue.Clear();
|
||||
}
|
||||
@@ -715,7 +849,7 @@ namespace GlitchyEngine.Renderer
|
||||
Texture texture = s_circleInstanceQueue[0].Texture;
|
||||
s_currentCircleEffect.SetTexture("Texture", texture);
|
||||
|
||||
s_setInstances = 0;
|
||||
s_setCircleInstances = 0;
|
||||
|
||||
for(int i < s_circleInstanceQueue.Count)
|
||||
{
|
||||
@@ -730,9 +864,9 @@ namespace GlitchyEngine.Renderer
|
||||
s_currentCircleEffect.SetTexture("Texture", texture);
|
||||
}
|
||||
|
||||
s_rawCircleInstances[s_setInstances++] = .(circle.Transform, circle.Color, circle.uvTransform, circle.InnerRadius, circle.entityId);
|
||||
s_rawCircleInstances[s_setCircleInstances++] = .(circle.Transform, circle.Color, circle.uvTransform, circle.InnerRadius, circle.entityId);
|
||||
|
||||
if(s_setInstances == s_rawCircleInstances.Count)
|
||||
if(s_setCircleInstances == s_rawCircleInstances.Count)
|
||||
{
|
||||
FlushCircleInstances();
|
||||
}
|
||||
@@ -743,6 +877,36 @@ namespace GlitchyEngine.Renderer
|
||||
s_circleInstanceQueue.Clear();
|
||||
}
|
||||
|
||||
private static void DrawDeferredLines()
|
||||
{
|
||||
Debug.Profiler.ProfileRendererFunction!();
|
||||
|
||||
if(s_lineInstanceQueue.IsEmpty)
|
||||
return;
|
||||
|
||||
// TODO: per object blendstate
|
||||
RenderCommand.SetBlendState(s_transparentBlendState);
|
||||
|
||||
s_setLineInstances = 0;
|
||||
|
||||
for(int i < s_lineInstanceQueue.Count)
|
||||
{
|
||||
let line = ref s_lineInstanceQueue[i];
|
||||
|
||||
s_rawLineVertices[s_setLineInstances++] = .(line.Start, line.Color, line.entityId);
|
||||
s_rawLineVertices[s_setLineInstances++] = .(line.End, line.Color, line.entityId);
|
||||
|
||||
if(s_setLineInstances == s_rawLineVertices.Count)
|
||||
{
|
||||
FlushLineInstances();
|
||||
}
|
||||
}
|
||||
|
||||
FlushLineInstances();
|
||||
|
||||
s_lineInstanceQueue.Clear();
|
||||
}
|
||||
|
||||
/// A specialized function that calculates the 2D transform matrix
|
||||
private static Matrix Calculate2DTransform(Vector3 translation, Vector2 scale, float rotation)
|
||||
{
|
||||
@@ -763,6 +927,85 @@ namespace GlitchyEngine.Renderer
|
||||
|
||||
// Primitives
|
||||
|
||||
/** @brief Draws a line.
|
||||
* @param start The start point of the line.
|
||||
* @param end The end point of the line.
|
||||
* @param color The color of the line.
|
||||
* @param entityId The optional ID of the entity that belongs to this line (for picking).
|
||||
*/
|
||||
public static void DrawLine(Vector3 start, Vector3 end, ColorRGBA color = .White, uint32 entityId = uint32.MaxValue)
|
||||
{
|
||||
DrawLine(Vector4(start, 1.0f), Vector4(end, 1.0f), color, entityId);
|
||||
}
|
||||
|
||||
/** @brief Draws a ray.
|
||||
* @param start The start point of the ray.
|
||||
* @param direction The direction of the ray.
|
||||
* @param color The color of the ray.
|
||||
* @param entityId The optional ID of the entity that belongs to this ray (for picking).
|
||||
*/
|
||||
public static void DrawRay(Vector3 start, Vector3 direction, ColorRGBA color = .White, uint32 entityId = uint32.MaxValue)
|
||||
{
|
||||
DrawLine(Vector4(start, 1.0f), Vector4(direction, 0.0f), color, entityId);
|
||||
}
|
||||
|
||||
/** @brief Draws a rectangle.
|
||||
* @param position The center of the rectangle.
|
||||
* @param size The size of the rectangle.
|
||||
* @param color The color of the rectangle.
|
||||
* @param entityId The optional ID of the entity that belongs to this rectangle (for picking).
|
||||
*/
|
||||
public static void DrawRect(Vector2 position, Vector2 size, ColorRGBA color = .White, uint32 entityId = uint32.MaxValue)
|
||||
{
|
||||
Vector2 halfSize = size / 2;
|
||||
|
||||
Vector4 p0 = Vector4(position + Vector2(-halfSize.X, -halfSize.Y), 0.0f, 1.0f);
|
||||
Vector4 p1 = Vector4(position + Vector2(halfSize.X, -halfSize.Y), 0.0f, 1.0f);
|
||||
Vector4 p2 = Vector4(position + Vector2(halfSize.X, halfSize.Y), 0.0f, 1.0f);
|
||||
Vector4 p3 = Vector4(position + Vector2(-halfSize.X, halfSize.Y), 0.0f, 1.0f);
|
||||
|
||||
DrawLine(p0, p1, color, entityId);
|
||||
DrawLine(p1, p2, color, entityId);
|
||||
DrawLine(p2, p3, color, entityId);
|
||||
DrawLine(p3, p0, color, entityId);
|
||||
}
|
||||
|
||||
/** @brief Draws a rectangle.
|
||||
* @param transform The transform of the rectangle.
|
||||
* @param color The color of the rectangle.
|
||||
* @param entityId The optional ID of the entity that belongs to this rectangle (for picking).
|
||||
*/
|
||||
public static void DrawRect(Matrix transform, ColorRGBA color = .White, uint32 entityId = uint32.MaxValue)
|
||||
{
|
||||
Vector2 halfSize = Vector2.One / 2.0f;
|
||||
|
||||
Vector4 p0 = transform * Vector4(-halfSize.X, -halfSize.Y, 0.0f, 1.0f);
|
||||
Vector4 p1 = transform * Vector4(halfSize.X, -halfSize.Y, 0.0f, 1.0f);
|
||||
Vector4 p2 = transform * Vector4(halfSize.X, halfSize.Y, 0.0f, 1.0f);
|
||||
Vector4 p3 = transform * Vector4(-halfSize.X, halfSize.Y, 0.0f, 1.0f);
|
||||
|
||||
DrawLine(p0, p1, color, entityId);
|
||||
DrawLine(p1, p2, color, entityId);
|
||||
DrawLine(p2, p3, color, entityId);
|
||||
DrawLine(p3, p0, color, entityId);
|
||||
}
|
||||
|
||||
public static void DrawLine(Vector4 start, Vector4 end, ColorRGBA color = .White, uint32 entityId = uint32.MaxValue)
|
||||
{
|
||||
Debug.Profiler.ProfileRendererFunction!();
|
||||
|
||||
#if DEBUG
|
||||
Log.EngineLogger.AssertDebug(s_sceneRunning, "Missing call of BeginScene.");
|
||||
#endif
|
||||
|
||||
QueueLineInstance(start, end, color, entityId);
|
||||
|
||||
if(s_drawOrder == .Immediate)
|
||||
{
|
||||
DrawDeferred();
|
||||
}
|
||||
}
|
||||
|
||||
// Colored Quad
|
||||
|
||||
public static void DrawQuad(Vector2 position, Vector2 size, float rotation, ColorRGBA color)
|
||||
@@ -873,12 +1116,14 @@ namespace GlitchyEngine.Renderer
|
||||
}
|
||||
}
|
||||
|
||||
public static void DrawSprite(Matrix transform, SpriterRendererComponent* spriteRenderer, uint32 entityId)
|
||||
public static void DrawSprite(Matrix transform, SpriteRendererComponent* spriteRenderer, uint32 entityId)
|
||||
{
|
||||
if (spriteRenderer.IsCircle)
|
||||
DrawCircle(transform, spriteRenderer.Sprite ?? s_whiteTexture, spriteRenderer.Color, 1.0f, spriteRenderer.UvTransform, entityId);
|
||||
else
|
||||
DrawQuad(transform, spriteRenderer.Sprite ?? s_whiteTexture, spriteRenderer.Color, spriteRenderer.UvTransform, entityId);
|
||||
DrawQuad(transform, spriteRenderer.Sprite.Get() ?? s_whiteTexture, spriteRenderer.Color, spriteRenderer.UvTransform, entityId);
|
||||
}
|
||||
|
||||
public static void DrawCircle(Matrix transform, CircleRendererComponent* spriteRenderer, uint32 entityId)
|
||||
{
|
||||
DrawCircle(transform, spriteRenderer.Sprite.Get() ?? s_whiteTexture, spriteRenderer.Color, spriteRenderer.InnerRadius, spriteRenderer.UvTransform, entityId);
|
||||
}
|
||||
|
||||
// Textured quad pivot
|
||||
@@ -937,21 +1182,26 @@ namespace GlitchyEngine.Renderer
|
||||
{
|
||||
public uint32 QuadDrawCalls = 0;
|
||||
public uint32 CircleDrawCalls = 0;
|
||||
public uint32 LineDrawCalls = 0;
|
||||
|
||||
public uint32 QuadCount = 0;
|
||||
public uint32 CircleCount = 0;
|
||||
public uint32 LineCount = 0;
|
||||
|
||||
public uint32 TotalDrawCalls => QuadDrawCalls + CircleDrawCalls;
|
||||
public uint32 TotalInstanceCount => QuadCount + CircleCount;
|
||||
public uint32 TotalVertexCount => TotalInstanceCount * 4;
|
||||
public uint32 TotalTriangleCount => TotalInstanceCount * 2;
|
||||
public uint32 TotalIndexCount => TotalInstanceCount * 6;
|
||||
public uint32 TotalDrawCalls => QuadDrawCalls + CircleDrawCalls + LineDrawCalls;
|
||||
public uint32 TotalInstanceCount => QuadCount + CircleCount + LineCount;
|
||||
public uint32 TotalVertexCount => (QuadCount + CircleCount) * 4 + LineCount * 2;
|
||||
public uint32 TotalTriangleCount => (QuadCount + CircleCount) * 2;
|
||||
public uint32 TotalIndexCount => (QuadCount + CircleCount) * 6;
|
||||
|
||||
public void Reset() mut
|
||||
{
|
||||
QuadDrawCalls = 0;
|
||||
CircleDrawCalls = 0;
|
||||
LineDrawCalls = 0;
|
||||
QuadCount = 0;
|
||||
CircleCount = 0;
|
||||
LineCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -333,8 +333,8 @@ namespace GlitchyEngine.Renderer.Text
|
||||
Renderer2D.Flush();
|
||||
|
||||
// TODO: this is very not good!
|
||||
var lastEffect = Renderer2D.[Friend]s_currentEffect;
|
||||
Renderer2D.[Friend]s_currentEffect = _msdfEffect..AddRef();
|
||||
var lastEffect = Renderer2D.[Friend]s_currentQuadEffect;
|
||||
Renderer2D.[Friend]s_currentQuadEffect = _msdfEffect..AddRef();
|
||||
// TODO: oh no....
|
||||
// Copy viewProjection from current effect
|
||||
Matrix viewProjection = lastEffect.Variables["ViewProjection"].[Friend]GetData<Matrix>();
|
||||
@@ -410,7 +410,7 @@ namespace GlitchyEngine.Renderer.Text
|
||||
// TODO: not good!
|
||||
// Change back effect
|
||||
_msdfEffect.ReleaseRef();
|
||||
Renderer2D.[Friend]s_currentEffect = lastEffect;
|
||||
Renderer2D.[Friend]s_currentQuadEffect = lastEffect;
|
||||
|
||||
// release all atlas textures
|
||||
for(int i < atlasses.Count)
|
||||
@@ -439,8 +439,8 @@ namespace GlitchyEngine.Renderer.Text
|
||||
Renderer2D.Flush();
|
||||
|
||||
// TODO: this is very not good!
|
||||
var lastEffect = Renderer2D.[Friend]s_currentEffect;
|
||||
Renderer2D.[Friend]s_currentEffect = _msdfEffect..AddRef();
|
||||
var lastEffect = Renderer2D.[Friend]s_currentQuadEffect;
|
||||
Renderer2D.[Friend]s_currentQuadEffect = _msdfEffect..AddRef();
|
||||
// TODO: oh no....
|
||||
// Copy viewProjection from current effect
|
||||
Matrix viewProjection = lastEffect.Variables["ViewProjection"].[Friend]GetData<Matrix>();
|
||||
@@ -664,7 +664,7 @@ namespace GlitchyEngine.Renderer.Text
|
||||
// TODO: not good!
|
||||
// Change back effect
|
||||
_msdfEffect.ReleaseRef();
|
||||
Renderer2D.[Friend]s_currentEffect = lastEffect;
|
||||
Renderer2D.[Friend]s_currentQuadEffect = lastEffect;
|
||||
|
||||
// release all atlas textures
|
||||
for(int i < atlasses.Count)
|
||||
|
||||
@@ -63,92 +63,18 @@ namespace GlitchyEngine.Renderer
|
||||
|
||||
public class Texture2D : Texture
|
||||
{
|
||||
protected String _path ~ delete _;
|
||||
|
||||
//public override extern uint32 Width {get;}
|
||||
//public override extern uint32 Height {get;}
|
||||
public override uint32 Depth => 1;
|
||||
//public override extern uint32 ArraySize {get;}
|
||||
//public override extern uint32 MipLevels {get;}
|
||||
|
||||
private this(StringView path, bool pngSrgb = false)
|
||||
{
|
||||
_path = new String(path);
|
||||
LoadTexture(pngSrgb);
|
||||
}
|
||||
|
||||
// TODO: remove
|
||||
private this(Stream data)
|
||||
{
|
||||
LoadDds(data);
|
||||
}
|
||||
|
||||
const String PngMagicWord = "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A";
|
||||
const String DdsMagicWord = "DDS ";
|
||||
|
||||
private void LoadTexture(bool pngSrgb)
|
||||
{
|
||||
Debug.Profiler.ProfileResourceFunction!();
|
||||
|
||||
Stream data = Application.Get().ContentManager.GetStream(_path);
|
||||
defer delete data;
|
||||
|
||||
var readResult = data.Read<char8[8]>();
|
||||
|
||||
data.Position = 0;
|
||||
|
||||
char8[8] magicWord;
|
||||
|
||||
if (readResult case .Ok(out magicWord))
|
||||
{
|
||||
StringView strView = .(&magicWord, magicWord.Count);
|
||||
|
||||
if (strView.StartsWith(PngMagicWord))
|
||||
{
|
||||
LoadPng(data, pngSrgb);
|
||||
}
|
||||
else if (strView.StartsWith(DdsMagicWord))
|
||||
{
|
||||
LoadDds(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
Runtime.FatalError("Unknown image format.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void LoadPng(Stream stream, bool srgb)
|
||||
{
|
||||
Debug.Profiler.ProfileResourceFunction!();
|
||||
|
||||
uint8[] pngData = new:ScopedAlloc! uint8[stream.Length];
|
||||
|
||||
var result = stream.TryRead(pngData);
|
||||
|
||||
if (result case .Err(let err))
|
||||
{
|
||||
Log.EngineLogger.Error($"Failed to read data from stream. Texture: \"{_path}\", Error: {err}");
|
||||
}
|
||||
|
||||
uint8* rawData = ?;
|
||||
uint32 width = 0, height = 0;
|
||||
|
||||
uint32 errorCode = LodePng.LodePng.Decode32(&rawData, &width, &height, pngData.Ptr, (.)pngData.Count);
|
||||
|
||||
Debug.Assert(errorCode == 0, "Failed to load png File");
|
||||
|
||||
// TODO: load as SRGB because PNGs are usually not stored as linear
|
||||
//Texture2DDesc desc = .(width, height, .R8G8B8A8_UNorm_SRGB, 1, 1, .Immutable);
|
||||
Texture2DDesc desc = .(width, height, srgb? .R8G8B8A8_UNorm_SRGB : .R8G8B8A8_UNorm, 1, 1, .Immutable);
|
||||
|
||||
PrepareTexturePlatform(desc, false);
|
||||
|
||||
SetData<Color>((.)rawData);
|
||||
|
||||
LodePng.LodePng.Free(rawData);
|
||||
}
|
||||
|
||||
protected void LoadDds(Stream stream)
|
||||
{
|
||||
LoadDdsPlatform(stream);
|
||||
|
||||
+21
-19
@@ -3,6 +3,7 @@ using GlitchyEngine.Math;
|
||||
using GlitchyEngine.Renderer;
|
||||
using GlitchyEngine.Core;
|
||||
using Box2D;
|
||||
using GlitchyEngine.Content;
|
||||
|
||||
namespace GlitchyEngine.World
|
||||
{
|
||||
@@ -21,7 +22,7 @@ namespace GlitchyEngine.World
|
||||
{
|
||||
public readonly UUID ID;
|
||||
|
||||
/// Create aa new IDComponent with a random UUID.
|
||||
/// Create a new IDComponent with a random UUID.
|
||||
public this()
|
||||
{
|
||||
ID = UUID();
|
||||
@@ -44,27 +45,13 @@ namespace GlitchyEngine.World
|
||||
}
|
||||
|
||||
[Component("Sprite Renderer")]
|
||||
struct SpriterRendererComponent : IDisposableComponent
|
||||
struct SpriteRendererComponent
|
||||
{
|
||||
private Texture2D _sprite = null;
|
||||
|
||||
public Texture2D Sprite
|
||||
{
|
||||
get => _sprite;
|
||||
set mut
|
||||
{
|
||||
if (_sprite == value)
|
||||
return;
|
||||
|
||||
SetReference!(_sprite, value);
|
||||
}
|
||||
}
|
||||
public AssetHandle<Texture2D> Sprite = .Invalid;
|
||||
|
||||
public ColorRGBA Color = .White;
|
||||
public Vector4 UvTransform = .(0, 0, 1, 1);
|
||||
|
||||
public bool IsCircle = false;
|
||||
|
||||
public this()
|
||||
{
|
||||
}
|
||||
@@ -73,10 +60,25 @@ namespace GlitchyEngine.World
|
||||
{
|
||||
Color = color;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
[Component("Circle Renderer")]
|
||||
struct CircleRendererComponent
|
||||
{
|
||||
_sprite?.ReleaseRef();
|
||||
public AssetHandle<Texture2D> Sprite = .Invalid;
|
||||
|
||||
public ColorRGBA Color = .White;
|
||||
public Vector4 UvTransform = .(0, 0, 1, 1);
|
||||
|
||||
public float InnerRadius = 0.0f;
|
||||
|
||||
public this()
|
||||
{
|
||||
}
|
||||
|
||||
public this(ColorRGBA color)
|
||||
{
|
||||
Color = color;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
using GlitchyEngine.Renderer;
|
||||
using System;
|
||||
using GlitchyEngine.Content;
|
||||
|
||||
namespace GlitchyEngine.World
|
||||
{
|
||||
/// A component that allows to render a mesh.
|
||||
public struct MeshRendererComponent
|
||||
{
|
||||
public AssetHandle<Material> Material = .Invalid;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
namespace GlitchyEngine.World
|
||||
{
|
||||
struct NameComponent : IDisposableComponent
|
||||
{
|
||||
private String _name;
|
||||
|
||||
public StringView Name
|
||||
{
|
||||
get => _name;
|
||||
set mut
|
||||
{
|
||||
if (_name == null)
|
||||
_name = new String(value);
|
||||
else
|
||||
_name.Set(value);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose() mut
|
||||
{
|
||||
DeleteAndNullify!(_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
@@ -20,6 +20,7 @@ namespace GlitchyEngine.World
|
||||
/// The frame when the transform was recalculated
|
||||
public uint Frame;
|
||||
|
||||
// TODO: probably use UUID
|
||||
public EcsEntity Parent
|
||||
{
|
||||
get => _parent;
|
||||
@@ -1,26 +0,0 @@
|
||||
using System;
|
||||
namespace GlitchyEngine.World
|
||||
{
|
||||
struct DebugNameComponent : IDisposableComponent
|
||||
{
|
||||
private String _debugName;
|
||||
|
||||
public String DebugName
|
||||
{
|
||||
get => _debugName;
|
||||
set mut => SetName(value);
|
||||
}
|
||||
|
||||
public void SetName(StringView name) mut
|
||||
{
|
||||
delete _debugName;
|
||||
|
||||
_debugName = new String(name);
|
||||
}
|
||||
|
||||
public void Dispose() mut
|
||||
{
|
||||
DeleteAndNullify!(_debugName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -66,6 +66,12 @@ namespace GlitchyEngine.World
|
||||
|
||||
public UUID UUID => GetComponent<IDComponent>().ID;
|
||||
|
||||
public StringView Name
|
||||
{
|
||||
get => GetComponent<NameComponent>().Name;
|
||||
set => GetComponent<NameComponent>().Name = value;
|
||||
}
|
||||
|
||||
public TransformComponent* Transform => GetComponent<TransformComponent>();
|
||||
|
||||
public T* AddComponent<T>(T value = T()) where T: struct, new
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
using GlitchyEngine.Renderer;
|
||||
using System;
|
||||
|
||||
namespace GlitchyEngine.World
|
||||
{
|
||||
/// A component that allows to render a mesh.
|
||||
public struct MeshRendererComponent : IDisposableComponent
|
||||
{
|
||||
private Material _material;
|
||||
|
||||
public Material Material
|
||||
{
|
||||
[Inline]
|
||||
get => _material;
|
||||
set mut
|
||||
{
|
||||
if(_material == value)
|
||||
return;
|
||||
|
||||
_material?.ReleaseRef();
|
||||
_material = value;
|
||||
_material?.AddRef();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose() mut
|
||||
{
|
||||
_material?.ReleaseRef();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
namespace GlitchyEngine.World
|
||||
{
|
||||
/**
|
||||
* A Component that allows to specify a parent entity.
|
||||
*/
|
||||
public struct ParentComponent
|
||||
{
|
||||
public EcsEntity Entity;
|
||||
}
|
||||
}
|
||||
+112
-332
@@ -11,7 +11,7 @@ namespace GlitchyEngine.World
|
||||
using internal ScriptableEntity;
|
||||
using internal GlitchyEngine.World;
|
||||
|
||||
class Scene
|
||||
class Scene : RefCounter
|
||||
{
|
||||
internal EcsWorld _ecsWorld = new .() ~ delete _;
|
||||
|
||||
@@ -19,12 +19,7 @@ namespace GlitchyEngine.World
|
||||
|
||||
private Dictionary<Type, function void(Entity entity, Type componentType, void* component)> _onComponentAddedHandlers = new .() ~ delete _;
|
||||
|
||||
private RenderTargetGroup _compositeTarget ~ _.ReleaseRef();
|
||||
|
||||
// Temporary target for camera. Needs to change as soon as we support multiple cameras
|
||||
private RenderTargetGroup _cameraTarget ~ _.ReleaseRef();
|
||||
|
||||
private Effect _gammaCorrectEffect ~ _.ReleaseRef();
|
||||
private uint32 _viewportWidth, _viewportHeight;
|
||||
|
||||
// Maps ids to the entities they represent.
|
||||
private Dictionary<UUID, EcsEntity> _idToEntity = new .() ~ delete _;
|
||||
@@ -45,44 +40,72 @@ namespace GlitchyEngine.World
|
||||
|
||||
public this()
|
||||
{
|
||||
/*Entity entity = CreateEntity("Green Quad");
|
||||
entity.AddComponent<SpriterRendererComponent>(.(ColorRGBA.SRgbToLinear(.(0.2f, 0.9f, 0.15f))));
|
||||
|
||||
Entity entity2 = CreateEntity("Red Square");
|
||||
var v = entity2.AddComponent<SpriterRendererComponent>(.(ColorRGBA.SRgbToLinear(.(0.95f, 0.1f, 0.3f))));
|
||||
v.Sprite = new Texture2D("Textures/rocket.dds");
|
||||
v.Sprite.SamplerState = SamplerStateManager.PointClamp;*/
|
||||
|
||||
_onComponentAddedHandlers.Add(typeof(CameraComponent), (e, t, c) => {
|
||||
CameraComponent* cameraComponent = (.)c;
|
||||
|
||||
cameraComponent.Camera.SetViewportSize(e.Scene.ViewportWidth, e.Scene.ViewportHeight);
|
||||
cameraComponent.Camera.SetViewportSize(e.Scene._viewportWidth, e.Scene._viewportHeight);
|
||||
});
|
||||
|
||||
RenderTargetGroupDescription desc = .(100, 100,
|
||||
TargetDescription[](
|
||||
RenderTargetFormat.R16G16B16A16_Float,
|
||||
.(RenderTargetFormat.R32_UInt) {ClearColor = .UInt(uint32.MaxValue)}),
|
||||
RenderTargetFormat.D24_UNorm_S8_UInt);
|
||||
_compositeTarget = new RenderTargetGroup(desc);
|
||||
|
||||
_cameraTarget = new RenderTargetGroup(.(){
|
||||
Width = 100,
|
||||
Height = 100,
|
||||
ColorTargetDescriptions = TargetDescription[](
|
||||
.(.R16G16B16A16_Float),
|
||||
.(.R32_UInt)
|
||||
),
|
||||
DepthTargetDescription = .(.D24_UNorm_S8_UInt)
|
||||
});
|
||||
|
||||
_gammaCorrectEffect = Content.LoadAsset<Effect>("Shaders/GammaCorrect.hlsl");//Application.Get().EffectLibrary.Load("content/Shaders/GammaCorrect.hlsl");
|
||||
}
|
||||
|
||||
public ~this()
|
||||
{
|
||||
}
|
||||
|
||||
public void CopyTo(Scene target)
|
||||
{
|
||||
// Copy entities
|
||||
for (let sourceHandle in _ecsWorld.Enumerate())
|
||||
{
|
||||
Entity sourceEntity = .(sourceHandle, this);
|
||||
|
||||
target.CreateEntity(sourceEntity.Name, sourceEntity.UUID);
|
||||
}
|
||||
|
||||
// TODO: perhaps use reflection and comptime
|
||||
// Copy components
|
||||
//CopyComponents<TransformComponent>(this, target); /* Parent will be copied below*/
|
||||
CopyComponents<MeshRendererComponent>(this, target);
|
||||
CopyComponents<MeshComponent>(this, target);
|
||||
CopyComponents<EditorComponent>(this, target);
|
||||
CopyComponents<SpriteRendererComponent>(this, target);
|
||||
CopyComponents<CircleRendererComponent>(this, target);
|
||||
CopyComponents<CameraComponent>(this, target);
|
||||
CopyComponents<NativeScriptComponent>(this, target);
|
||||
CopyComponents<LightComponent>(this, target);
|
||||
CopyComponents<Rigidbody2DComponent>(this, target);
|
||||
CopyComponents<BoxCollider2DComponent>(this, target);
|
||||
CopyComponents<CircleCollider2DComponent>(this, target);
|
||||
|
||||
// Copy transforms
|
||||
for (let (sourceHandle, sourceTransform) in _ecsWorld.Enumerate<TransformComponent>())
|
||||
{
|
||||
Entity sourceEntity = Entity(sourceHandle, this);
|
||||
Entity sourceParent = Entity(sourceTransform.Parent, this);
|
||||
|
||||
Entity targetEntity = target.GetEntityByID(sourceEntity.UUID);
|
||||
*targetEntity.Transform = *sourceTransform;
|
||||
|
||||
if (sourceParent.IsValid)
|
||||
{
|
||||
Entity targetParent = target.GetEntityByID(sourceParent.UUID);
|
||||
targetEntity.Parent = targetParent;
|
||||
}
|
||||
}
|
||||
|
||||
target.OnViewportResize(_viewportWidth, _viewportHeight);
|
||||
}
|
||||
|
||||
private static void CopyComponents<TComponent>(Scene source, Scene target) where TComponent : struct, new
|
||||
{
|
||||
for (let (sourceHandle, sourceComponent) in source._ecsWorld.Enumerate<TComponent>())
|
||||
{
|
||||
Entity sourceEntity = .(sourceHandle, source);
|
||||
|
||||
Entity targetEntity = target.GetEntityByID(sourceEntity.UUID);
|
||||
targetEntity.AddComponent<TComponent>(*sourceComponent);
|
||||
}
|
||||
}
|
||||
|
||||
b2Vec2 _gravity2D = .(0.0f, -9.8f);
|
||||
|
||||
static b2BodyType GetBox2DBodyType(Rigidbody2DComponent.BodyType bodyType)
|
||||
@@ -102,6 +125,16 @@ namespace GlitchyEngine.World
|
||||
}
|
||||
|
||||
public void OnRuntimeStart()
|
||||
{
|
||||
OnSimulationStart();
|
||||
}
|
||||
|
||||
public void OnRuntimeStop()
|
||||
{
|
||||
OnSimulationStop();
|
||||
}
|
||||
|
||||
public void OnSimulationStart()
|
||||
{
|
||||
_physicsWorld2D = Box2D.World.Create(ref _gravity2D);
|
||||
|
||||
@@ -160,20 +193,32 @@ namespace GlitchyEngine.World
|
||||
}
|
||||
}
|
||||
|
||||
public void OnRuntimeStop()
|
||||
public void OnSimulationStop()
|
||||
{
|
||||
Box2D.World.Delete(_physicsWorld2D);
|
||||
_physicsWorld2D = null;
|
||||
}
|
||||
|
||||
public void UpdateRuntime(GameTime gameTime, RenderTargetGroup finalTarget)
|
||||
public enum UpdateMode
|
||||
{
|
||||
/// No special update configuration (this does NOT mean nothing will be updated!)
|
||||
None = 0x00,
|
||||
/// Update editor-specific stuff
|
||||
Editor = 0x01,
|
||||
/// Update the physics related stuff
|
||||
Physics = 0x02,
|
||||
/// Update the runtume related stuff (e.g. execute scripts). Also run physics!
|
||||
Runtime = 0x04 | Physics,
|
||||
}
|
||||
|
||||
public void Update(GameTime gameTime, UpdateMode mode)
|
||||
{
|
||||
Debug.Profiler.ProfileRendererFunction!();
|
||||
|
||||
finalTarget.AddRef();
|
||||
|
||||
TransformSystem.Update(_ecsWorld);
|
||||
|
||||
if (mode.HasFlag(.Runtime))
|
||||
{
|
||||
// Run scripts
|
||||
for (var (entity, script) in _ecsWorld.Enumerate<NativeScriptComponent>())
|
||||
{
|
||||
@@ -186,7 +231,10 @@ namespace GlitchyEngine.World
|
||||
|
||||
script.Instance.[Friend]OnUpdate(gameTime);
|
||||
}
|
||||
}
|
||||
|
||||
if (mode.HasFlag(.Physics))
|
||||
{
|
||||
// Update 2D physics
|
||||
{
|
||||
const int32 velocityIterations = 6;
|
||||
@@ -211,300 +259,17 @@ namespace GlitchyEngine.World
|
||||
transform.RotationEuler = .(transform.RotationEuler.XY, angle);
|
||||
}
|
||||
}
|
||||
|
||||
// Find camera
|
||||
Camera* primaryCamera = null;
|
||||
Matrix primaryCameraTransform = default;
|
||||
RenderTargetGroup renderTarget = null;
|
||||
|
||||
for (var (entity, transform, camera) in _ecsWorld.Enumerate<TransformComponent, CameraComponent>())
|
||||
{
|
||||
if (camera.Primary)// && camera.RenderTarget != null)
|
||||
{
|
||||
primaryCamera = &camera.Camera;
|
||||
primaryCameraTransform = transform.WorldTransform;
|
||||
// TODO: bind render targets to cameras
|
||||
// renderTarget = camera.RenderTarget..AddRef();
|
||||
}
|
||||
}
|
||||
|
||||
renderTarget = _cameraTarget..AddRef();
|
||||
|
||||
// 3D render
|
||||
Renderer.BeginScene(*primaryCamera, primaryCameraTransform, renderTarget, _compositeTarget);
|
||||
|
||||
for (var (entity, transform, mesh, meshRenderer) in _ecsWorld.Enumerate<TransformComponent, MeshComponent, MeshRendererComponent>())
|
||||
{
|
||||
Renderer.Submit(mesh.Mesh, meshRenderer.Material, entity, transform.WorldTransform);
|
||||
}
|
||||
|
||||
for (var (entity, transform, light) in _ecsWorld.Enumerate<TransformComponent, LightComponent>())
|
||||
{
|
||||
Renderer.Submit(light.SceneLight, transform.WorldTransform);
|
||||
}
|
||||
|
||||
Renderer.EndScene();
|
||||
|
||||
renderTarget.ReleaseRef();
|
||||
|
||||
// TODO: alphablending (handle in Renderer2D)
|
||||
// TODO: 2D-Postprocessing requires rendering into separate target instead of directly into compositeTarget
|
||||
|
||||
RenderCommand.SetRenderTargetGroup(_compositeTarget);
|
||||
RenderCommand.BindRenderTargets();
|
||||
|
||||
// Sprite renderer
|
||||
Renderer2D.BeginScene(*primaryCamera, primaryCameraTransform, .BackToFront);
|
||||
|
||||
for (var (entity, transform, sprite) in _ecsWorld.Enumerate<TransformComponent, SpriterRendererComponent>())
|
||||
{
|
||||
Renderer2D.DrawSprite(transform.WorldTransform, sprite, entity.Index);
|
||||
}
|
||||
|
||||
Renderer2D.EndScene();
|
||||
|
||||
// Gamma correct composit target and draw it into viewport
|
||||
{
|
||||
RenderCommand.UnbindRenderTargets();
|
||||
RenderCommand.SetRenderTargetGroup(finalTarget, false);
|
||||
RenderCommand.BindRenderTargets();
|
||||
|
||||
_gammaCorrectEffect.SetTexture("Texture", _compositeTarget, 0);
|
||||
// TODO: iiihhh
|
||||
_gammaCorrectEffect.ApplyChanges();
|
||||
_gammaCorrectEffect.Bind();
|
||||
|
||||
FullscreenQuad.Draw();
|
||||
}
|
||||
|
||||
finalTarget.ReleaseRef();
|
||||
|
||||
|
||||
/*Debug.Profiler.ProfileRendererFunction!();
|
||||
|
||||
finalTarget.AddRef();
|
||||
|
||||
TransformSystem.Update(_ecsWorld);
|
||||
|
||||
// Run scripts
|
||||
for (var (entity, script) in _ecsWorld.Enumerate<NativeScriptComponent>())
|
||||
{
|
||||
if (script.Instance == null)
|
||||
{
|
||||
script.Instance = script.InstantiateFunction();
|
||||
script.Instance._entity = Entity(entity, this);
|
||||
script.Instance.[Friend]OnCreate();
|
||||
}
|
||||
|
||||
script.Instance.[Friend]OnUpdate(gameTime);
|
||||
}
|
||||
|
||||
// Find camera
|
||||
Camera* primaryCamera = null;
|
||||
Matrix primaryCameraTransform = default;
|
||||
RenderTargetGroup renderTarget = null;
|
||||
|
||||
for (var (entity, transform, camera) in _ecsWorld.Enumerate<TransformComponent, CameraComponent>())
|
||||
{
|
||||
if (camera.Primary)// && camera.RenderTarget != null)
|
||||
{
|
||||
primaryCamera = &camera.Camera;
|
||||
primaryCameraTransform = transform.WorldTransform;
|
||||
//renderTarget = camera.RenderTarget..AddRef();
|
||||
}
|
||||
}
|
||||
|
||||
if (primaryCamera != null)
|
||||
{
|
||||
// 3D render
|
||||
Renderer.BeginScene(*primaryCamera, primaryCameraTransform, _compositeTarget, finalTarget);
|
||||
|
||||
for (var (entity, transform, mesh, meshRenderer) in _ecsWorld.Enumerate<TransformComponent, MeshComponent, MeshRendererComponent>())
|
||||
{
|
||||
Renderer.Submit(mesh.Mesh, meshRenderer.Material, entity, transform.WorldTransform);
|
||||
}
|
||||
|
||||
for (var (entity, transform, light) in _ecsWorld.Enumerate<TransformComponent, LightComponent>())
|
||||
{
|
||||
Renderer.Submit(light.SceneLight, transform.WorldTransform);
|
||||
}
|
||||
|
||||
Renderer.EndScene();
|
||||
|
||||
// TODO: alphablending (handle in Renderer2D)
|
||||
// TODO: 2D-Postprocessing requires rendering into separate target instead of directly into compositeTarget
|
||||
|
||||
RenderCommand.SetRenderTargetGroup(_compositeTarget);
|
||||
RenderCommand.BindRenderTargets();
|
||||
|
||||
// Sprite renderer
|
||||
Renderer2D.BeginScene(*primaryCamera, primaryCameraTransform, .BackToFront);
|
||||
|
||||
for (var (entity, transform, sprite) in _ecsWorld.Enumerate<TransformComponent, SpriterRendererComponent>())
|
||||
{
|
||||
Renderer2D.DrawSprite(transform.WorldTransform, sprite, entity.Index);
|
||||
}
|
||||
|
||||
Renderer2D.EndScene();
|
||||
|
||||
// Gamma correct composit target and draw it into viewport
|
||||
{
|
||||
RenderCommand.UnbindRenderTargets();
|
||||
RenderCommand.SetRenderTargetGroup(finalTarget, false);
|
||||
RenderCommand.BindRenderTargets();
|
||||
|
||||
_gammaCorrectEffect.SetTexture("Texture", _compositeTarget, 0);
|
||||
// TODO: iiihhh
|
||||
_gammaCorrectEffect.Bind(Application.Get().Window.Context);
|
||||
|
||||
FullscreenQuad.Draw();
|
||||
}
|
||||
}
|
||||
|
||||
finalTarget.ReleaseRef();*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Debug.Profiler.ProfileRendererFunction!();
|
||||
|
||||
TransformSystem.Update(_ecsWorld);
|
||||
|
||||
for (var (entity, script) in _ecsWorld.Enumerate<NativeScriptComponent>())
|
||||
{
|
||||
if (script.Instance == null)
|
||||
{
|
||||
script.Instance = script.InstantiateFunction();
|
||||
script.Instance._entity = Entity(entity, this);
|
||||
script.Instance.[Friend]OnCreate();
|
||||
}
|
||||
|
||||
script.Instance.[Friend]OnUpdate(gameTime);
|
||||
}
|
||||
|
||||
Camera* primaryCamera = null;
|
||||
Matrix primaryCameraTransform = default;
|
||||
RenderTargetGroup renderTarget = null;
|
||||
|
||||
for (var (entity, transform, camera) in _ecsWorld.Enumerate<TransformComponent, CameraComponent>())
|
||||
{
|
||||
if (camera.Primary && camera.RenderTarget != null)
|
||||
{
|
||||
primaryCamera = &camera.Camera;
|
||||
primaryCameraTransform = transform.WorldTransform;
|
||||
renderTarget = camera.RenderTarget..AddRef();
|
||||
}
|
||||
}
|
||||
|
||||
if (primaryCamera != null)
|
||||
{
|
||||
// 3D render
|
||||
Renderer.BeginScene(*primaryCamera, primaryCameraTransform, renderTarget, finalTarget);
|
||||
|
||||
for (var (entity, transform, mesh, meshRenderer) in _ecsWorld.Enumerate<TransformComponent, MeshComponent, MeshRendererComponent>())
|
||||
{
|
||||
Renderer.Submit(mesh.Mesh, meshRenderer.Material, transform.WorldTransform);
|
||||
}
|
||||
|
||||
for (var (entity, transform, light) in _ecsWorld.Enumerate<TransformComponent, LightComponent>())
|
||||
{
|
||||
Renderer.Submit(light.SceneLight, transform.WorldTransform);
|
||||
}
|
||||
|
||||
Renderer.EndScene();
|
||||
|
||||
// Sprite renderer
|
||||
Renderer2D.BeginScene(*primaryCamera, primaryCameraTransform);
|
||||
|
||||
for (var (entity, transform, sprite) in _ecsWorld.Enumerate<TransformComponent, SpriterRendererComponent>())
|
||||
{
|
||||
Renderer2D.DrawQuad(transform.WorldTransform, sprite.Sprite, sprite.Color);
|
||||
}
|
||||
|
||||
Renderer2D.EndScene();
|
||||
|
||||
renderTarget?.ReleaseRef();
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
public void UpdateEditor(GameTime gameTime, EditorCamera camera, RenderTargetGroup viewportTarget, delegate void() DebugDraw3D, delegate void() DrawDebug2D)
|
||||
{
|
||||
Debug.Profiler.ProfileRendererFunction!();
|
||||
|
||||
viewportTarget.AddRef();
|
||||
|
||||
TransformSystem.Update(_ecsWorld);
|
||||
|
||||
// 3D render
|
||||
Renderer.BeginScene(camera, _compositeTarget);
|
||||
|
||||
for (var (entity, transform, mesh, meshRenderer) in _ecsWorld.Enumerate<TransformComponent, MeshComponent, MeshRendererComponent>())
|
||||
{
|
||||
if (mesh.Mesh == null || meshRenderer.Material == null)
|
||||
continue;
|
||||
|
||||
Renderer.Submit(mesh.Mesh, meshRenderer.Material, entity, transform.WorldTransform);
|
||||
}
|
||||
|
||||
for (var (entity, transform, light) in _ecsWorld.Enumerate<TransformComponent, LightComponent>())
|
||||
{
|
||||
Renderer.Submit(light.SceneLight, transform.WorldTransform);
|
||||
}
|
||||
|
||||
DebugDraw3D();
|
||||
|
||||
Renderer.EndScene();
|
||||
|
||||
// TODO: alphablending (handle in Renderer2D)
|
||||
// TODO: 2D-Postprocessing requires rendering into separate target instead of directly into compositeTarget
|
||||
|
||||
RenderCommand.SetRenderTargetGroup(_compositeTarget);
|
||||
RenderCommand.BindRenderTargets();
|
||||
|
||||
// Sprite renderer
|
||||
Renderer2D.BeginScene(camera, .BackToFront);
|
||||
|
||||
for (var (entity, transform, sprite) in _ecsWorld.Enumerate<TransformComponent, SpriterRendererComponent>())
|
||||
{
|
||||
Renderer2D.DrawSprite(transform.WorldTransform, sprite, entity.Index);
|
||||
}
|
||||
|
||||
Renderer2D.EndScene();
|
||||
|
||||
Renderer2D.BeginScene(camera, .BackToFront);
|
||||
|
||||
DrawDebug2D();
|
||||
|
||||
Renderer2D.EndScene();
|
||||
|
||||
// Gamma correct composit target and draw it into viewport
|
||||
{
|
||||
RenderCommand.UnbindRenderTargets();
|
||||
RenderCommand.SetRenderTargetGroup(viewportTarget, false);
|
||||
RenderCommand.BindRenderTargets();
|
||||
|
||||
_gammaCorrectEffect.SetTexture("Texture", _compositeTarget, 0);
|
||||
// TODO: iiihhh
|
||||
_gammaCorrectEffect.ApplyChanges();
|
||||
_gammaCorrectEffect.Bind();
|
||||
|
||||
FullscreenQuad.Draw();
|
||||
}
|
||||
|
||||
viewportTarget.ReleaseRef();
|
||||
}
|
||||
|
||||
/// Creates a new Entity with the given name.
|
||||
public Entity CreateEntity(String name = "", UUID id = default)
|
||||
public Entity CreateEntity(StringView name = "", UUID id = default)
|
||||
{
|
||||
Entity entity = Entity(_ecsWorld.NewEntity(), this);
|
||||
entity.AddComponent<TransformComponent>();
|
||||
|
||||
let nameComponent = entity.AddComponent<DebugNameComponent>();
|
||||
nameComponent.SetName(name.IsEmpty ? "Entity" : name);
|
||||
let nameComponent = entity.AddComponent<NameComponent>();
|
||||
nameComponent.Name = (name.IsEmpty ? "Entity" : name);
|
||||
|
||||
// If no id is given generate a random one.
|
||||
IDComponent idComponent = (id == default) ? IDComponent() : IDComponent(id);
|
||||
@@ -545,13 +310,11 @@ namespace GlitchyEngine.World
|
||||
return .Err;
|
||||
}
|
||||
|
||||
private uint32 ViewportWidth, ViewportHeight;
|
||||
|
||||
/// Sets the size of the viewport into which the scene will be rendered.
|
||||
public void OnViewportResize(uint32 width, uint32 height)
|
||||
{
|
||||
ViewportWidth = width;
|
||||
ViewportHeight = height;
|
||||
_viewportWidth = width;
|
||||
_viewportHeight = height;
|
||||
|
||||
for (var (entity, cameraComponent) in _ecsWorld.Enumerate<CameraComponent>())
|
||||
{
|
||||
@@ -560,9 +323,6 @@ namespace GlitchyEngine.World
|
||||
cameraComponent.Camera.SetViewportSize(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
_compositeTarget.Resize(ViewportWidth, ViewportHeight);
|
||||
_cameraTarget.Resize(ViewportWidth, ViewportHeight);
|
||||
}
|
||||
|
||||
private void OnComponentAdded(Entity entity, Type componentType, void* component)
|
||||
@@ -572,5 +332,25 @@ namespace GlitchyEngine.World
|
||||
handler(entity, componentType, component);
|
||||
}
|
||||
}
|
||||
|
||||
public WorldEnumerator<TComponent> GetEntities<TComponent>() where TComponent : struct
|
||||
{
|
||||
return _ecsWorld.Enumerate<TComponent>();
|
||||
}
|
||||
|
||||
public WorldEnumerator<TComponent1, TComponent2> GetEntities<TComponent1, TComponent2>()
|
||||
where TComponent1 : struct
|
||||
where TComponent2 : struct
|
||||
{
|
||||
return _ecsWorld.Enumerate<TComponent1, TComponent2>();
|
||||
}
|
||||
|
||||
public WorldEnumerator<TComponent1, TComponent2, TComponent3> GetEntities<TComponent1, TComponent2, TComponent3>()
|
||||
where TComponent1 : struct
|
||||
where TComponent2 : struct
|
||||
where TComponent3 : struct
|
||||
{
|
||||
return _ecsWorld.Enumerate<TComponent1, TComponent2, TComponent3>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
using GlitchyEngine.Renderer;
|
||||
using GlitchyEngine.Content;
|
||||
using GlitchyEngine.Math;
|
||||
|
||||
namespace GlitchyEngine.World;
|
||||
|
||||
using internal GlitchyEngine.World;
|
||||
|
||||
class SceneRenderer
|
||||
{
|
||||
public Scene Scene { get; set; }
|
||||
|
||||
private RenderTargetGroup _compositeTarget ~ _.ReleaseRef();
|
||||
|
||||
// Temporary target for camera. Needs to change as soon as we support multiple cameras
|
||||
private RenderTargetGroup _cameraTarget ~ _.ReleaseRef();
|
||||
|
||||
private uint32 _viewportWidth;
|
||||
private uint32 _viewportHeight;
|
||||
|
||||
private AssetHandle _gammaCorrectEffect;
|
||||
|
||||
public RenderTargetGroup CompositeTarget => _compositeTarget;
|
||||
|
||||
public this()
|
||||
{
|
||||
RenderTargetGroupDescription desc = .(100, 100,
|
||||
TargetDescription[](
|
||||
RenderTargetFormat.R16G16B16A16_Float,
|
||||
.(RenderTargetFormat.R32_UInt) {ClearColor = .UInt(uint32.MaxValue)}),
|
||||
RenderTargetFormat.D24_UNorm_S8_UInt);
|
||||
_compositeTarget = new RenderTargetGroup(desc);
|
||||
|
||||
_cameraTarget = new RenderTargetGroup(.(){
|
||||
Width = 100,
|
||||
Height = 100,
|
||||
ColorTargetDescriptions = TargetDescription[](
|
||||
.(.R16G16B16A16_Float),
|
||||
.(.R32_UInt)
|
||||
),
|
||||
DepthTargetDescription = .(.D24_UNorm_S8_UInt)
|
||||
});
|
||||
|
||||
_gammaCorrectEffect = Content.LoadAsset("Shaders/GammaCorrect.hlsl");//Application.Get().EffectLibrary.Load("content/Shaders/GammaCorrect.hlsl");
|
||||
}
|
||||
|
||||
/// Sets the size of the viewport into which the scene will be rendered.
|
||||
public void OnViewportResize(uint32 width, uint32 height)
|
||||
{
|
||||
_viewportWidth = width;
|
||||
_viewportHeight = height;
|
||||
|
||||
_compositeTarget.Resize(_viewportWidth, _viewportHeight);
|
||||
_cameraTarget.Resize(_viewportWidth, _viewportHeight);
|
||||
}
|
||||
|
||||
public void RenderRuntime(GameTime gameTime, RenderTargetGroup finalTarget)
|
||||
{
|
||||
Debug.Profiler.ProfileRendererFunction!();
|
||||
|
||||
// Find camera
|
||||
Camera* primaryCamera = null;
|
||||
Matrix primaryCameraTransform = default;
|
||||
RenderTargetGroup renderTarget = null;
|
||||
|
||||
for (var (entity, transform, camera) in Scene._ecsWorld.Enumerate<TransformComponent, CameraComponent>())
|
||||
{
|
||||
if (camera.Primary)// && camera.RenderTarget != null)
|
||||
{
|
||||
primaryCamera = &camera.Camera;
|
||||
primaryCameraTransform = transform.WorldTransform;
|
||||
// TODO: bind render targets to cameras
|
||||
// renderTarget = camera.RenderTarget..AddRef();
|
||||
}
|
||||
}
|
||||
|
||||
if (primaryCamera == null)
|
||||
return;
|
||||
|
||||
finalTarget.AddRef();
|
||||
|
||||
renderTarget = _cameraTarget..AddRef();
|
||||
|
||||
// 3D render
|
||||
Renderer.BeginScene(*primaryCamera, primaryCameraTransform, renderTarget, _compositeTarget);
|
||||
|
||||
for (var (entity, transform, mesh, meshRenderer) in Scene._ecsWorld.Enumerate<TransformComponent, MeshComponent, MeshRendererComponent>())
|
||||
{
|
||||
Renderer.Submit(mesh.Mesh, meshRenderer.Material, entity, transform.WorldTransform);
|
||||
}
|
||||
|
||||
for (var (entity, transform, light) in Scene._ecsWorld.Enumerate<TransformComponent, LightComponent>())
|
||||
{
|
||||
Renderer.Submit(light.SceneLight, transform.WorldTransform);
|
||||
}
|
||||
|
||||
Renderer.EndScene();
|
||||
|
||||
renderTarget.ReleaseRef();
|
||||
|
||||
// TODO: alphablending (handle in Renderer2D)
|
||||
// TODO: 2D-Postprocessing requires rendering into separate target instead of directly into compositeTarget
|
||||
|
||||
RenderCommand.SetRenderTargetGroup(_compositeTarget);
|
||||
RenderCommand.BindRenderTargets();
|
||||
|
||||
// Sprite renderer
|
||||
Renderer2D.BeginScene(*primaryCamera, primaryCameraTransform, .BackToFront);
|
||||
|
||||
for (var (entity, transform, sprite) in Scene._ecsWorld.Enumerate<TransformComponent, SpriteRendererComponent>())
|
||||
{
|
||||
Renderer2D.DrawSprite(transform.WorldTransform, sprite, entity.Index);
|
||||
}
|
||||
|
||||
for (var (entity, transform, circle) in Scene._ecsWorld.Enumerate<TransformComponent, CircleRendererComponent>())
|
||||
{
|
||||
Renderer2D.DrawCircle(transform.WorldTransform, circle, entity.Index);
|
||||
}
|
||||
|
||||
Renderer2D.EndScene();
|
||||
|
||||
// Gamma correct composit target and draw it into viewport
|
||||
{
|
||||
RenderCommand.UnbindRenderTargets();
|
||||
RenderCommand.SetRenderTargetGroup(finalTarget, false);
|
||||
RenderCommand.BindRenderTargets();
|
||||
|
||||
Effect gammaEffect = Content.GetAsset<Effect>(_gammaCorrectEffect);
|
||||
|
||||
gammaEffect.SetTexture("Texture", _compositeTarget, 0);
|
||||
// TODO: iiihhh
|
||||
gammaEffect.ApplyChanges();
|
||||
gammaEffect.Bind();
|
||||
|
||||
FullscreenQuad.Draw();
|
||||
}
|
||||
|
||||
finalTarget.ReleaseRef();
|
||||
}
|
||||
|
||||
public void RenderEditor(GameTime gameTime, EditorCamera camera, RenderTargetGroup viewportTarget, delegate void() DebugDraw3D, delegate void() DrawDebug2D)
|
||||
{
|
||||
Debug.Profiler.ProfileRendererFunction!();
|
||||
|
||||
viewportTarget.AddRef();
|
||||
|
||||
// 3D render
|
||||
Renderer.BeginScene(camera, _compositeTarget);
|
||||
|
||||
for (var (entity, transform, mesh, meshRenderer) in Scene._ecsWorld.Enumerate<TransformComponent, MeshComponent, MeshRendererComponent>())
|
||||
{
|
||||
if (mesh.Mesh == .Invalid || meshRenderer.Material == .Invalid)
|
||||
continue;
|
||||
|
||||
Renderer.Submit(mesh.Mesh, meshRenderer.Material, entity, transform.WorldTransform);
|
||||
}
|
||||
|
||||
for (var (entity, transform, light) in Scene._ecsWorld.Enumerate<TransformComponent, LightComponent>())
|
||||
{
|
||||
Renderer.Submit(light.SceneLight, transform.WorldTransform);
|
||||
}
|
||||
|
||||
DebugDraw3D();
|
||||
|
||||
Renderer.EndScene();
|
||||
|
||||
// TODO: alphablending (handle in Renderer2D)
|
||||
// TODO: 2D-Postprocessing requires rendering into separate target instead of directly into compositeTarget
|
||||
|
||||
RenderCommand.SetRenderTargetGroup(_compositeTarget);
|
||||
RenderCommand.BindRenderTargets();
|
||||
|
||||
// Sprite renderer
|
||||
Renderer2D.BeginScene(camera, .BackToFront);
|
||||
|
||||
for (var (entity, transform, sprite) in Scene._ecsWorld.Enumerate<TransformComponent, SpriteRendererComponent>())
|
||||
{
|
||||
Renderer2D.DrawSprite(transform.WorldTransform, sprite, entity.Index);
|
||||
}
|
||||
|
||||
for (var (entity, transform, circle) in Scene._ecsWorld.Enumerate<TransformComponent, CircleRendererComponent>())
|
||||
{
|
||||
Renderer2D.DrawCircle(transform.WorldTransform, circle, entity.Index);
|
||||
}
|
||||
|
||||
Renderer2D.EndScene();
|
||||
|
||||
Renderer2D.BeginScene(camera, .BackToFront);
|
||||
|
||||
DrawDebug2D();
|
||||
|
||||
Renderer2D.EndScene();
|
||||
|
||||
// Gamma correct composit target and draw it into viewport
|
||||
{
|
||||
RenderCommand.UnbindRenderTargets();
|
||||
RenderCommand.SetRenderTargetGroup(viewportTarget, false);
|
||||
RenderCommand.BindRenderTargets();
|
||||
|
||||
Effect gammaEffect = Content.GetAsset<Effect>(_gammaCorrectEffect);
|
||||
|
||||
gammaEffect.SetTexture("Texture", _compositeTarget, 0);
|
||||
// TODO: iiihhh
|
||||
gammaEffect.ApplyChanges();
|
||||
gammaEffect.Bind();
|
||||
|
||||
FullscreenQuad.Draw();
|
||||
}
|
||||
|
||||
viewportTarget.ReleaseRef();
|
||||
}
|
||||
}
|
||||
@@ -9,12 +9,12 @@ using System.Collections;
|
||||
using GlitchyEngine.Renderer;
|
||||
using GlitchyEngine.Content;
|
||||
|
||||
namespace GlitchyEngine.World
|
||||
{
|
||||
using internal GlitchyEngine.World;
|
||||
namespace GlitchyEngine.World;
|
||||
|
||||
class SceneSerializer
|
||||
{
|
||||
using internal GlitchyEngine.World;
|
||||
|
||||
class SceneSerializer
|
||||
{
|
||||
private Scene _scene;
|
||||
|
||||
// Maps from ParentID to ChildEntity
|
||||
@@ -79,16 +79,22 @@ namespace GlitchyEngine.World
|
||||
|
||||
SerializeComponent<EditorComponent>(writer, entity, "EditorComponent", scope (component) => {});
|
||||
|
||||
SerializeComponent<DebugNameComponent>(writer, entity, "NameComponent", scope (component) =>
|
||||
SerializeComponent<NameComponent>(writer, entity, "NameComponent", scope (component) =>
|
||||
{
|
||||
Serialize.Value(writer, "Name", component.DebugName);
|
||||
Serialize.Value(writer, "Name", component.Name);
|
||||
});
|
||||
|
||||
SerializeComponent<SpriterRendererComponent>(writer, entity, "SpriterRendererComponent", scope (component) =>
|
||||
SerializeComponent<SpriteRendererComponent>(writer, entity, "SpriteRendererComponent", scope (component) =>
|
||||
{
|
||||
Serialize.Value(writer, "Color", component.Color);
|
||||
Serialize.Value(writer, "IsCircle", component.IsCircle);
|
||||
Serialize.Value(writer, "Sprite", component.Sprite?.Identifier);
|
||||
Serialize.Value(writer, "Sprite", component.Sprite);
|
||||
Serialize.Value(writer, "UvTransform", component.UvTransform);
|
||||
});
|
||||
SerializeComponent<CircleRendererComponent>(writer, entity, "CircleRendererComponent", scope (component) =>
|
||||
{
|
||||
Serialize.Value(writer, "Color", component.Color);
|
||||
Serialize.Value(writer, "InnerRadius", component.InnerRadius);
|
||||
Serialize.Value(writer, "Sprite", component.Sprite);
|
||||
Serialize.Value(writer, "UvTransform", component.UvTransform);
|
||||
});
|
||||
|
||||
@@ -172,12 +178,12 @@ namespace GlitchyEngine.World
|
||||
|
||||
SerializeComponent<MeshComponent>(writer, entity, "MeshComponent", scope (component) =>
|
||||
{
|
||||
Serialize.Value(writer, "Mesh", component.Mesh.Identifier);
|
||||
Serialize.Value(writer, "Mesh", component.Mesh);
|
||||
});
|
||||
|
||||
SerializeComponent<MeshRendererComponent>(writer, entity, "MeshRendererComponent", scope (component) =>
|
||||
{
|
||||
Serialize.Value(writer, "Material", component.Material.Identifier);
|
||||
Serialize.Value(writer, "Material", component.Material);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -270,7 +276,7 @@ namespace GlitchyEngine.World
|
||||
|
||||
private Result<void> DeserializeEntity(BonReader reader)
|
||||
{
|
||||
mixin DeserializeAsset<T>(StringView identifier) where T : Asset
|
||||
/*mixin DeserializeAsset<T>(StringView identifier) where T : Asset
|
||||
{
|
||||
Asset asset = null;
|
||||
|
||||
@@ -283,6 +289,21 @@ namespace GlitchyEngine.World
|
||||
}
|
||||
|
||||
(T)asset
|
||||
}*/
|
||||
|
||||
mixin DeserializeAssetHandle<T>(StringView identifier) where T : Asset
|
||||
{
|
||||
Asset asset = null;
|
||||
|
||||
Try!(Deserialize.Value(reader, identifier, out asset));
|
||||
|
||||
if (asset != null && !(asset is T))
|
||||
{
|
||||
Log.EngineLogger.Error($"Asset {asset.Identifier} is not a {nameof(T)}.");
|
||||
return .Err;
|
||||
}
|
||||
|
||||
asset?.Handle ?? .Invalid
|
||||
}
|
||||
|
||||
Try!(reader.ObjectBlock());
|
||||
@@ -302,32 +323,38 @@ namespace GlitchyEngine.World
|
||||
case "EditorComponent":
|
||||
Try!(DeserializeComponent<EditorComponent>(reader, entity, scope (component) => { return .Ok; }));
|
||||
case "NameComponent":
|
||||
Try!(DeserializeComponent<DebugNameComponent>(reader, entity, scope (component) =>
|
||||
Try!(DeserializeComponent<NameComponent>(reader, entity, scope (component) =>
|
||||
{
|
||||
String name;
|
||||
|
||||
Deserialize.Value(reader, "Name", out name);
|
||||
|
||||
component.SetName(name);
|
||||
component.Name = name;
|
||||
|
||||
delete name;
|
||||
|
||||
return .Ok;
|
||||
}));
|
||||
case "SpriterRendererComponent":
|
||||
Try!(DeserializeComponent<SpriterRendererComponent>(reader, entity, scope (component) =>
|
||||
case "SpriteRendererComponent":
|
||||
Try!(DeserializeComponent<SpriteRendererComponent>(reader, entity, scope (component) =>
|
||||
{
|
||||
Try!(Deserialize.Value(reader, "Color", out component.Color));
|
||||
reader.EntryEnd();
|
||||
Try!(Deserialize.Value(reader, "IsCircle", out component.IsCircle));
|
||||
Try!(Deserialize.Value(reader, "Sprite", out component.Sprite));
|
||||
reader.EntryEnd();
|
||||
Try!(Deserialize.Value(reader, "UvTransform", out component.UvTransform));
|
||||
|
||||
using (Texture2D sprite = DeserializeAsset!<Texture2D>("Sprite"))
|
||||
return .Ok;
|
||||
}));
|
||||
case "CircleRendererComponent":
|
||||
Try!(DeserializeComponent<CircleRendererComponent>(reader, entity, scope (component) =>
|
||||
{
|
||||
component.Sprite = (Texture2D)sprite;
|
||||
}
|
||||
Try!(Deserialize.Value(reader, "Color", out component.Color));
|
||||
reader.EntryEnd();
|
||||
Try!(Deserialize.Value(reader, "InnerRadius", out component.InnerRadius));
|
||||
reader.EntryEnd();
|
||||
Try!(Deserialize.Value(reader, "Sprite", out component.Sprite));
|
||||
reader.EntryEnd();
|
||||
|
||||
Try!(Deserialize.Value(reader, "UvTransform", out component.UvTransform));
|
||||
|
||||
return .Ok;
|
||||
@@ -474,20 +501,14 @@ namespace GlitchyEngine.World
|
||||
case "MeshComponent":
|
||||
Try!(DeserializeComponent<MeshComponent>(reader, entity, scope (component) =>
|
||||
{
|
||||
using (GeometryBinding mesh = DeserializeAsset!<GeometryBinding>("Mesh"))
|
||||
{
|
||||
component.Mesh = mesh;
|
||||
}
|
||||
Try!(Deserialize.Value(reader, "Mesh", out component.Mesh));
|
||||
|
||||
return .Ok;
|
||||
}));
|
||||
case "MeshRendererComponent":
|
||||
Try!(DeserializeComponent<MeshRendererComponent>(reader, entity, scope (component) =>
|
||||
{
|
||||
using (Material material = DeserializeAsset!<Material>("Material"))
|
||||
{
|
||||
component.Material = material;
|
||||
}
|
||||
Try!(Deserialize.Value(reader, "Material", out component.Material));
|
||||
|
||||
return .Ok;
|
||||
}));
|
||||
@@ -595,5 +616,4 @@ namespace GlitchyEngine.World
|
||||
{
|
||||
Runtime.NotImplemented();
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+1
-1
Submodule GlitchyEngine/vendor/bon updated: 0c80e365cd...515b606cf3
Vendored
+1
-1
Submodule GlitchyEngine/vendor/directx updated: 4b9d0c5d7b...d1a21b6b88
Vendored
+1
-1
Submodule GlitchyEngine/vendor/gltf updated: 60b0a1be16...d881f985c2
Vendored
+1
-1
Submodule GlitchyEngine/vendor/imgui updated: 827764b98c...b1d891368e
+13
-10
@@ -1,4 +1,4 @@
|
||||
using GlitchyEngine.Renderer;
|
||||
/*using GlitchyEngine.Renderer;
|
||||
using GlitchyEngine.Events;
|
||||
using GlitchyEngine.ImGui;
|
||||
using GlitchyEngine.Math;
|
||||
@@ -63,8 +63,8 @@ namespace Sandbox
|
||||
|
||||
Material _checkerMaterial ~ _?.ReleaseRef();
|
||||
Material _logoMaterial ~ _?.ReleaseRef();
|
||||
Texture2D _texture ~ _?.ReleaseRef();
|
||||
Texture2D _ge_logo ~ _?.ReleaseRef();
|
||||
AssetHandle _texture;
|
||||
AssetHandle _ge_logo;
|
||||
|
||||
BlendState _alphaBlendState ~ _?.ReleaseRef();
|
||||
BlendState _opaqueBlendState ~ _?.ReleaseRef();
|
||||
@@ -91,7 +91,7 @@ namespace Sandbox
|
||||
|
||||
//effectLibrary.LoadNoRefInc("content\\Shaders\\testShader.hlsl");
|
||||
|
||||
Effect textureEffect = Content.LoadAsset<Effect>("Shaders\\textureShader.hlsl");
|
||||
Effect textureEffect = Content.GetAsset<Effect>(Content.LoadAsset("Shaders\\textureShader.hlsl"));
|
||||
|
||||
_depthTarget = new DepthStencilTarget(_context.SwapChain.Width, _context.SwapChain.Height);
|
||||
|
||||
@@ -99,7 +99,7 @@ namespace Sandbox
|
||||
|
||||
VertexLayout vertexLayout = new VertexLayout(VertexColorTexture.VertexElements, false);
|
||||
|
||||
textureEffect.ReleaseRef();
|
||||
//textureEffect.ReleaseRef();
|
||||
|
||||
// Create hexagon
|
||||
{
|
||||
@@ -174,8 +174,11 @@ namespace Sandbox
|
||||
rsDesc.FrontCounterClockwise = false;
|
||||
_rasterizerStateClockWise = new RasterizerState(rsDesc);
|
||||
|
||||
_texture = Content.LoadAsset<Texture2D>("content/Textures/Checkerboard.dds");//new Texture2D("content/Textures/Checkerboard.dds");
|
||||
_ge_logo = Content.LoadAsset<Texture2D>("content/Textures/GE_Logo.dds");//new Texture2D("content/Textures/GE_Logo.dds");
|
||||
_texture = Content.LoadAsset("content/Textures/Checkerboard.dds");//new Texture2D("content/Textures/Checkerboard.dds");
|
||||
_ge_logo = Content.LoadAsset("content/Textures/GE_Logo.dds");//new Texture2D("content/Textures/GE_Logo.dds");
|
||||
|
||||
Texture2D texture = Content.GetAsset<Texture2D>(_texture);
|
||||
Texture2D ge_logo = Content.GetAsset<Texture2D>(_ge_logo);
|
||||
|
||||
let sampler = SamplerStateManager.GetSampler(
|
||||
SamplerStateDescription()
|
||||
@@ -183,8 +186,8 @@ namespace Sandbox
|
||||
MagFilter = .Point
|
||||
});
|
||||
|
||||
_texture.SamplerState = sampler;
|
||||
_ge_logo.SamplerState = sampler;
|
||||
texture.SamplerState = sampler;
|
||||
ge_logo.SamplerState = sampler;
|
||||
|
||||
sampler.ReleaseRef();
|
||||
|
||||
@@ -518,4 +521,4 @@ namespace Sandbox
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}*/
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
/*using System;
|
||||
using GlitchyEngine;
|
||||
using GlitchyEngine.Events;
|
||||
using System.Diagnostics;
|
||||
@@ -12,6 +12,7 @@ using GlitchyEngine.Renderer.Text;
|
||||
using System.IO;
|
||||
using msdfgen;
|
||||
using System.Collections;
|
||||
using GlitchyEngine.Content;
|
||||
|
||||
namespace Sandbox
|
||||
{
|
||||
@@ -282,4 +283,4 @@ namespace Sandbox
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
@@ -21,7 +21,7 @@ namespace Sandbox
|
||||
#if GAMMA_TEST
|
||||
PushLayer(new GammaTestLayer());
|
||||
#elif SANDBOX_2D
|
||||
PushLayer(new ExampleLayer2D());
|
||||
//PushLayer(new ExampleLayer2D());
|
||||
#else
|
||||
PushLayer(new ExampleLayer());
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user