mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 13:01:52 +00:00
Compare commits
65
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
499ca0311c | ||
|
|
62c85e9e1f | ||
|
|
8296f1c5cd | ||
|
|
457b43352a | ||
|
|
cc7fb7311f | ||
|
|
5f27b8001a | ||
|
|
0cbb8a4966 | ||
|
|
79adc70f01 | ||
|
|
78ba016b03 | ||
|
|
3e55a1614a | ||
|
|
f0de874572 | ||
|
|
6e02a04a4f | ||
|
|
cd1562f372 | ||
|
|
e8505f6bdb | ||
|
|
66d66d3308 | ||
|
|
88b393157a | ||
|
|
28155ec92c | ||
|
|
1641bafd06 | ||
|
|
76bff3a6c1 | ||
|
|
a507eeb1cd | ||
|
|
77c45db122 | ||
|
|
e12fcaacff | ||
|
|
b31d43820a | ||
|
|
334c2c0366 | ||
|
|
bb520b43ec | ||
|
|
46693666aa | ||
|
|
9e1f648aa0 | ||
|
|
5f5da2ed35 | ||
|
|
fa2277cd99 | ||
|
|
54936d5744 | ||
|
|
04d69717a3 | ||
|
|
3becc1e25b | ||
|
|
e8e6207bc1 | ||
|
|
f4c5bf9c2d | ||
|
|
f4607a6210 | ||
|
|
6a59deb9e2 | ||
|
|
ac1817fe33 | ||
|
|
5855b13873 | ||
|
|
ef5e4ba64f | ||
|
|
4fd9a924a0 | ||
|
|
e60d74fccd | ||
|
|
5e5134a607 | ||
|
|
fd6826785a | ||
|
|
43bcf01299 | ||
|
|
81ae5f1135 | ||
|
|
0ee2f5fa9e | ||
|
|
b76d4cd558 | ||
|
|
5893cfb74a | ||
|
|
ed952155b6 | ||
|
|
d54cdf43ee | ||
|
|
f16fbc3984 | ||
|
|
184480243f | ||
|
|
fc1875ed96 | ||
|
|
5733166b74 | ||
|
|
2ba4b68e09 | ||
|
|
edcec02e94 | ||
|
|
c164aeecaa | ||
|
|
793aa40975 | ||
|
|
50714976e9 | ||
|
|
7b6662cbc4 | ||
|
|
cfa046d2ea | ||
|
|
b22f73a156 | ||
|
|
c3fb9bbd5d | ||
|
|
c22d122921 | ||
|
|
ad14c9f6ed |
@@ -5,3 +5,6 @@ build/
|
|||||||
recovery/
|
recovery/
|
||||||
vendor/directx
|
vendor/directx
|
||||||
imgui.ini
|
imgui.ini
|
||||||
|
GlitchyEditor/resources/scripts/ScriptCore.dll
|
||||||
|
GlitchyEditor/resources/scripts/ScriptCore.pdb
|
||||||
|
GlitchyEditor/settings.bon
|
||||||
|
|||||||
@@ -31,3 +31,6 @@
|
|||||||
[submodule "GlitchyEngine/vendor/Beef.Linq"]
|
[submodule "GlitchyEngine/vendor/Beef.Linq"]
|
||||||
path = GlitchyEngine/vendor/Beef.Linq
|
path = GlitchyEngine/vendor/Beef.Linq
|
||||||
url = https://github.com/aharabada/Beef.Linq.git
|
url = https://github.com/aharabada/Beef.Linq.git
|
||||||
|
[submodule "GlitchyEngine/vendor/NetHostBeef"]
|
||||||
|
path = GlitchyEngine/vendor/NetHostBeef
|
||||||
|
url = https://github.com/aharabada/NetHostBeef.git
|
||||||
|
|||||||
+3
-2
@@ -1,6 +1,7 @@
|
|||||||
FileVersion = 1
|
FileVersion = 1
|
||||||
Projects = {Sandbox = {Path = "Sandbox"}, GlitchyEngine = {Path = "GlitchyEngine"}, GlitchLog = {Path = "GlitchLog"}, DirectX = {Path = "GlitchyEngine/vendor/directx/DirectX"}, LodePng = {Path = "vendor/lodepng-beef/lodepng-beef"}, FreeType = {Path = "GlitchyEngine/vendor/freetype"}, cgltf-beef = {Path = "GlitchyEngine/vendor/gltf/cgltf-beef"}, GlitchyEditor = {Path = "GlitchyEditor"}, msdfgen-beef = {Path = "GlitchyEngine/vendor/msdfgen/msdfgen-beef"}, ImGui = {Path = "GlitchyEngine/vendor/imgui/ImGui"}, ImGuiImplDX11 = {Path = "GlitchyEngine/vendor/imgui/ImGuiImplDX11"}, ImGuiImplWin32 = {Path = "GlitchyEngine/vendor/imgui/ImGuiImplWin32"}, ImGuizmo = {Path = "GlitchyEngine/vendor/imgui/ImGuizmo"}, GlitchyEngineHelper = {Path = "GlitchyEngineHelper"}, bon = {Path = "GlitchyEngine/vendor/bon"}, box2d-beef = {Path = "GlitchyEngine/vendor/box2D"}, "Beef.Linq" = {Path = "GlitchyEngine/vendor/Beef.Linq/src"}}
|
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"}, ScriptCore = {Path = "ScriptCore"}, NetHostBeef = {Path = "GlitchyEngine/vendor/NetHostBeef/NetHostBeef"}}
|
||||||
WorkspaceFolders = {GlitchyEngine = ["GlitchyEngine", "GlitchLog", "GlitchyEngineHelper"], "GlitchyEngine/Dependencies" = ["cgltf-beef", "DirectX", "FreeType", "ImGui", "ImGuiImplDX11", "ImGuiImplWin32", "ImGuizmo", "LodePng", "msdfgen-beef", "bon", "box2d-beef", "Beef.Linq"]}
|
Unlocked = ["corlib"]
|
||||||
|
WorkspaceFolders = {GlitchyEngine = ["GlitchyEngine", "GlitchLog", "GlitchyEngineHelper", "ScriptCore"], "GlitchyEngine/Dependencies" = ["cgltf-beef", "DirectX", "FreeType", "ImGui", "ImGuiImplDX11", "ImGuiImplWin32", "ImGuizmo", "LodePng", "msdfgen-beef", "bon", "box2d-beef", "Beef.Linq", "NetHostBeef"]}
|
||||||
|
|
||||||
[Workspace]
|
[Workspace]
|
||||||
StartupProject = "GlitchyEditor"
|
StartupProject = "GlitchyEditor"
|
||||||
|
|||||||
@@ -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.
|
||||||
@@ -5,3 +5,6 @@ Dependencies = {corlib = "*", GlitchLog = "*", GlitchyEngine = "*"}
|
|||||||
Name = "GlitchyEditor"
|
Name = "GlitchyEditor"
|
||||||
TargetType = "BeefGUIApplication"
|
TargetType = "BeefGUIApplication"
|
||||||
StartupObject = "GlitchyEngine.Program"
|
StartupObject = "GlitchyEngine.Program"
|
||||||
|
|
||||||
|
[Configs.Debug.Win64]
|
||||||
|
DebugCommandArguments = "\"content\\Scenes\\physics2D.scene\""
|
||||||
|
|||||||
@@ -0,0 +1,398 @@
|
|||||||
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
##
|
||||||
|
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.rsuser
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
# Mono auto generated files
|
||||||
|
mono_crash.*
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
[Ww][Ii][Nn]32/
|
||||||
|
[Aa][Rr][Mm]/
|
||||||
|
[Aa][Rr][Mm]64/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
[Ll]og/
|
||||||
|
[Ll]ogs/
|
||||||
|
|
||||||
|
# Visual Studio 2015/2017 cache/options directory
|
||||||
|
.vs/
|
||||||
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
|
#wwwroot/
|
||||||
|
|
||||||
|
# Visual Studio 2017 auto generated files
|
||||||
|
Generated\ Files/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
# NUnit
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
nunit-*.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
|
||||||
|
# Benchmark Results
|
||||||
|
BenchmarkDotNet.Artifacts/
|
||||||
|
|
||||||
|
# .NET Core
|
||||||
|
project.lock.json
|
||||||
|
project.fragment.lock.json
|
||||||
|
artifacts/
|
||||||
|
|
||||||
|
# ASP.NET Scaffolding
|
||||||
|
ScaffoldingReadMe.txt
|
||||||
|
|
||||||
|
# StyleCop
|
||||||
|
StyleCopReport.xml
|
||||||
|
|
||||||
|
# Files built by Visual Studio
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_h.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.iobj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.ipdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*_wpftmp.csproj
|
||||||
|
*.log
|
||||||
|
*.tlog
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Chutzpah Test files
|
||||||
|
_Chutzpah*
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opendb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
*.VC.db
|
||||||
|
*.VC.VC.opendb
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
*.sap
|
||||||
|
|
||||||
|
# Visual Studio Trace Files
|
||||||
|
*.e2e
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# AxoCover is a Code Coverage Tool
|
||||||
|
.axoCover/*
|
||||||
|
!.axoCover/settings.json
|
||||||
|
|
||||||
|
# Coverlet is a free, cross platform Code Coverage Tool
|
||||||
|
coverage*.json
|
||||||
|
coverage*.xml
|
||||||
|
coverage*.info
|
||||||
|
|
||||||
|
# Visual Studio code coverage results
|
||||||
|
*.coverage
|
||||||
|
*.coveragexml
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
_NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
nCrunchTemp_*
|
||||||
|
|
||||||
|
# MightyMoose
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
|
||||||
|
# Web workbench (sass)
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||||
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
|
*.pubxml
|
||||||
|
*.publishproj
|
||||||
|
|
||||||
|
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||||
|
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||||
|
# in these scripts will be unencrypted
|
||||||
|
PublishScripts/
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
|
*.nupkg
|
||||||
|
# NuGet Symbol Packages
|
||||||
|
*.snupkg
|
||||||
|
# The packages folder can be ignored because of Package Restore
|
||||||
|
**/[Pp]ackages/*
|
||||||
|
# except build/, which is used as an MSBuild target.
|
||||||
|
!**/[Pp]ackages/build/
|
||||||
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
|
#!**/[Pp]ackages/repositories.config
|
||||||
|
# NuGet v3's project.json files produces more ignorable files
|
||||||
|
*.nuget.props
|
||||||
|
*.nuget.targets
|
||||||
|
|
||||||
|
# Microsoft Azure Build Output
|
||||||
|
csx/
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
|
# Microsoft Azure Emulator
|
||||||
|
ecf/
|
||||||
|
rcf/
|
||||||
|
|
||||||
|
# Windows Store app package directories and files
|
||||||
|
AppPackages/
|
||||||
|
BundleArtifacts/
|
||||||
|
Package.StoreAssociation.xml
|
||||||
|
_pkginfo.txt
|
||||||
|
*.appx
|
||||||
|
*.appxbundle
|
||||||
|
*.appxupload
|
||||||
|
|
||||||
|
# Visual Studio cache files
|
||||||
|
# files ending in .cache can be ignored
|
||||||
|
*.[Cc]ache
|
||||||
|
# but keep track of directories ending in .cache
|
||||||
|
!?*.[Cc]ache/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
ClientBin/
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.jfm
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
orleans.codegen.cs
|
||||||
|
|
||||||
|
# Including strong name files can present a security risk
|
||||||
|
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||||
|
#*.snk
|
||||||
|
|
||||||
|
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||||
|
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||||
|
#bower_components/
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file
|
||||||
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
|
# because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
ServiceFabricBackup/
|
||||||
|
*.rptproj.bak
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
*.ndf
|
||||||
|
|
||||||
|
# Business Intelligence projects
|
||||||
|
*.rdl.data
|
||||||
|
*.bim.layout
|
||||||
|
*.bim_*.settings
|
||||||
|
*.rptproj.rsuser
|
||||||
|
*- [Bb]ackup.rdl
|
||||||
|
*- [Bb]ackup ([0-9]).rdl
|
||||||
|
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||||
|
|
||||||
|
# Microsoft Fakes
|
||||||
|
FakesAssemblies/
|
||||||
|
|
||||||
|
# GhostDoc plugin setting file
|
||||||
|
*.GhostDoc.xml
|
||||||
|
|
||||||
|
# Node.js Tools for Visual Studio
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Visual Studio 6 build log
|
||||||
|
*.plg
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace options file
|
||||||
|
*.opt
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||||
|
*.vbw
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
|
||||||
|
*.vbp
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
|
||||||
|
*.dsw
|
||||||
|
*.dsp
|
||||||
|
|
||||||
|
# Visual Studio 6 technical files
|
||||||
|
*.ncb
|
||||||
|
*.aps
|
||||||
|
|
||||||
|
# Visual Studio LightSwitch build output
|
||||||
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/ModelManifest.xml
|
||||||
|
**/*.Server/GeneratedArtifacts
|
||||||
|
**/*.Server/ModelManifest.xml
|
||||||
|
_Pvt_Extensions
|
||||||
|
|
||||||
|
# Paket dependency manager
|
||||||
|
.paket/paket.exe
|
||||||
|
paket-files/
|
||||||
|
|
||||||
|
# FAKE - F# Make
|
||||||
|
.fake/
|
||||||
|
|
||||||
|
# CodeRush personal settings
|
||||||
|
.cr/personal
|
||||||
|
|
||||||
|
# Python Tools for Visual Studio (PTVS)
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Cake - Uncomment if you are using it
|
||||||
|
# tools/**
|
||||||
|
# !tools/packages.config
|
||||||
|
|
||||||
|
# Tabs Studio
|
||||||
|
*.tss
|
||||||
|
|
||||||
|
# Telerik's JustMock configuration file
|
||||||
|
*.jmconfig
|
||||||
|
|
||||||
|
# BizTalk build output
|
||||||
|
*.btp.cs
|
||||||
|
*.btm.cs
|
||||||
|
*.odx.cs
|
||||||
|
*.xsd.cs
|
||||||
|
|
||||||
|
# OpenCover UI analysis results
|
||||||
|
OpenCover/
|
||||||
|
|
||||||
|
# Azure Stream Analytics local run output
|
||||||
|
ASALocalRun/
|
||||||
|
|
||||||
|
# MSBuild Binary and Structured Log
|
||||||
|
*.binlog
|
||||||
|
|
||||||
|
# NVidia Nsight GPU debugger configuration file
|
||||||
|
*.nvuser
|
||||||
|
|
||||||
|
# MFractors (Xamarin productivity tool) working folder
|
||||||
|
.mfractor/
|
||||||
|
|
||||||
|
# Local History for Visual Studio
|
||||||
|
.localhistory/
|
||||||
|
|
||||||
|
# Visual Studio History (VSHistory) files
|
||||||
|
.vshistory/
|
||||||
|
|
||||||
|
# BeatPulse healthcheck temp database
|
||||||
|
healthchecksdb
|
||||||
|
|
||||||
|
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||||
|
MigrationBackup/
|
||||||
|
|
||||||
|
# Ionide (cross platform F# VS Code tools) working folder
|
||||||
|
.ionide/
|
||||||
|
|
||||||
|
# Fody - auto-generated XML schema
|
||||||
|
FodyWeavers.xsd
|
||||||
|
|
||||||
|
# VS Code files for those working on multiple tools
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
*.code-workspace
|
||||||
|
|
||||||
|
# Local History for Visual Studio Code
|
||||||
|
.history/
|
||||||
|
|
||||||
|
# Windows Installer files from build outputs
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msix
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
|
|
||||||
|
# JetBrains Rider
|
||||||
|
*.sln.iml
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using GlitchyEngine;
|
||||||
|
using GlitchyEngine.Math;
|
||||||
|
|
||||||
|
using static GlitchyEngine.Math.Math;
|
||||||
|
|
||||||
|
namespace Sandbox;
|
||||||
|
public class Camera : Entity
|
||||||
|
{
|
||||||
|
public float DistanceFromPlayer = 5.0f;
|
||||||
|
|
||||||
|
public float DontFollowRadius = 3.0f;
|
||||||
|
|
||||||
|
void OnCreate()
|
||||||
|
{
|
||||||
|
Log.Info("Camera Create");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnUpdate(float deltaTime)
|
||||||
|
{
|
||||||
|
Log.Info($"Camera Update {deltaTime}");
|
||||||
|
|
||||||
|
//Entity player = FindEntityWithName("Player");
|
||||||
|
|
||||||
|
//if (player != null)
|
||||||
|
//{
|
||||||
|
// float2 playerPosition = player.Transform.Translation.XY;
|
||||||
|
|
||||||
|
// float2 cameraPosition = Transform.Translation.XY;
|
||||||
|
|
||||||
|
// float2 distanceVector = playerPosition - cameraPosition;
|
||||||
|
|
||||||
|
// float distance = length(distanceVector);
|
||||||
|
|
||||||
|
// float2 neededMovement = float2.Zero;
|
||||||
|
|
||||||
|
// if (distance > DontFollowRadius)
|
||||||
|
// {
|
||||||
|
// neededMovement = distanceVector - (distanceVector / distance) * DontFollowRadius;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Transform.Translation = new float3(cameraPosition + neededMovement, DistanceFromPlayer);
|
||||||
|
//}
|
||||||
|
//else
|
||||||
|
//{
|
||||||
|
// Log.Error("Player not found!");
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
using System;
|
||||||
|
using GlitchyEngine;
|
||||||
|
using GlitchyEngine.Editor;
|
||||||
|
using GlitchyEngine.Math;
|
||||||
|
|
||||||
|
using static GlitchyEngine.Math.Math;
|
||||||
|
|
||||||
|
namespace Sandbox
|
||||||
|
{
|
||||||
|
|
||||||
|
public enum MyEnum
|
||||||
|
{
|
||||||
|
Yes,
|
||||||
|
No,
|
||||||
|
Maybe
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct MyStruct
|
||||||
|
{
|
||||||
|
public float TheFloat;
|
||||||
|
public float2 TheVector;
|
||||||
|
public MyEnum TheEnum;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyTestEntity : Entity
|
||||||
|
{
|
||||||
|
//[ShowInEditor]
|
||||||
|
RigidBody2D _rigidBody;
|
||||||
|
|
||||||
|
public bool Bo;
|
||||||
|
|
||||||
|
public byte By;
|
||||||
|
public ushort Us;
|
||||||
|
public uint Ui;
|
||||||
|
public ulong Ul;
|
||||||
|
|
||||||
|
public sbyte Sb;
|
||||||
|
public short Sh;
|
||||||
|
public int In;
|
||||||
|
public long Lo;
|
||||||
|
|
||||||
|
public float Fl;
|
||||||
|
public double Do;
|
||||||
|
public float2 V2;
|
||||||
|
public float3 V3;
|
||||||
|
public float4 V4;
|
||||||
|
|
||||||
|
public Entity TheEntity;
|
||||||
|
|
||||||
|
public float JumpForce = 2000;
|
||||||
|
[ShowInEditor] float MoveForce = 1000;
|
||||||
|
[ShowInEditor] private int MyNumber = 1337;
|
||||||
|
[ShowInEditor] public double MyDouble = 1000.0f;
|
||||||
|
|
||||||
|
public MyStruct AStruct;
|
||||||
|
|
||||||
|
public Camera Camera;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called after the script component was created. (The entity might not be fully created yet)
|
||||||
|
/// </summary>
|
||||||
|
void OnCreate()
|
||||||
|
{
|
||||||
|
Log.Info($"Create! {UUID}");
|
||||||
|
|
||||||
|
Log.Info($"Jump Force: {JumpForce}");
|
||||||
|
|
||||||
|
//_rigidBody ??= GetComponent<RigidBody2D>() ?? AddComponent<RigidBody2D>();
|
||||||
|
|
||||||
|
//Camera = FindEntityWithName("Camera").As<Camera>();
|
||||||
|
|
||||||
|
//if (Camera == null)
|
||||||
|
//{
|
||||||
|
// Log.Error("Camera not found.");
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called every frame.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="deltaTime"></param>
|
||||||
|
void OnUpdate(float deltaTime)
|
||||||
|
{
|
||||||
|
Log.Info($"On update: {deltaTime}");
|
||||||
|
|
||||||
|
//float2 force = float2.Zero;
|
||||||
|
|
||||||
|
//if (Input.IsKeyPressed(Key.A))
|
||||||
|
//{
|
||||||
|
// force.X -= MoveForce * deltaTime;
|
||||||
|
//}
|
||||||
|
|
||||||
|
//if (Input.IsKeyPressed(Key.D))
|
||||||
|
//{
|
||||||
|
// force.X += MoveForce * deltaTime;
|
||||||
|
//}
|
||||||
|
|
||||||
|
//if (Input.IsKeyPressed(Key.Q))
|
||||||
|
// Camera.DistanceFromPlayer -= deltaTime;
|
||||||
|
|
||||||
|
//if (Input.IsKeyPressed(Key.E))
|
||||||
|
// Camera.DistanceFromPlayer += deltaTime;
|
||||||
|
|
||||||
|
//if (Input.IsKeyPressing(Key.Space))
|
||||||
|
//{
|
||||||
|
// force.Y += JumpForce;
|
||||||
|
//}
|
||||||
|
|
||||||
|
//_rigidBody.ApplyForceToCenter(force);
|
||||||
|
|
||||||
|
//if (Input.IsMouseButtonReleasing(MouseButton.MiddleButton))
|
||||||
|
//{
|
||||||
|
// Log.Info($"Ouha! {MyNumber}");
|
||||||
|
// Physics2D.Gravity *= new float2(1, -1);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called before the component is being destroyed.
|
||||||
|
/// </summary>
|
||||||
|
void OnDestroy()
|
||||||
|
{
|
||||||
|
Log.Trace("Destroy");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"profiles": {
|
||||||
|
"Start Editor": {
|
||||||
|
"commandName": "Executable",
|
||||||
|
"executablePath": "D:\\Development\\Projects\\Beef\\GlitchyEngine\\build\\Debug_Win64\\GlitchyEditor\\GlitchyEditor.exe",
|
||||||
|
"commandLineArgs": "\"content\\Scenes\\physics2D.scene\"",
|
||||||
|
"workingDirectory": "D:\\Development\\Projects\\Beef\\GlitchyEngine\\GlitchyEditor",
|
||||||
|
"nativeDebugging": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{7A70819C-5317-402A-8553-95C5A001E370}</ProjectGuid>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>Sandbox</RootNamespace>
|
||||||
|
<AssemblyName>Sandbox</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<Deterministic>true</Deterministic>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<LangVersion>default</LangVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<LangVersion>default</LangVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Net.Http" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Camera.cs" />
|
||||||
|
<Compile Include="MyTestEntity.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\..\ScriptCore\ScriptCore.csproj">
|
||||||
|
<Project>{6222c226-fc78-498c-80ba-5cf10ac9123c}</Project>
|
||||||
|
<Name>ScriptCore</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
<OutputPath>bin</OutputPath>
|
||||||
|
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
|
||||||
|
|
||||||
|
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
|
||||||
|
<EnableDynamicLoading>true</EnableDynamicLoading>
|
||||||
|
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\..\ScriptCore\ScriptCore.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.4.33205.214
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sandbox", "Sandbox.csproj", "{7A70819C-5317-402A-8553-95C5A001E370}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ScriptCore", "..\..\..\..\ScriptCore\ScriptCore.csproj", "{6222C226-FC78-498C-80BA-5CF10AC9123C}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptCoreGenerator", "..\..\..\..\ScriptCoreGenerator\ScriptCoreGenerator.csproj", "{5D662996-1E1E-4170-A08A-B26CDB63A0DE}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{7A70819C-5317-402A-8553-95C5A001E370}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{7A70819C-5317-402A-8553-95C5A001E370}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{7A70819C-5317-402A-8553-95C5A001E370}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{7A70819C-5317-402A-8553-95C5A001E370}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{6222C226-FC78-498C-80BA-5CF10AC9123C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{6222C226-FC78-498C-80BA-5CF10AC9123C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{6222C226-FC78-498C-80BA-5CF10AC9123C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{6222C226-FC78-498C-80BA-5CF10AC9123C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{5D662996-1E1E-4170-A08A-B26CDB63A0DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{5D662996-1E1E-4170-A08A-B26CDB63A0DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{5D662996-1E1E-4170-A08A-B26CDB63A0DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{5D662996-1E1E-4170-A08A-B26CDB63A0DE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {B5D43D8D-D80B-41AA-BE40-1DC507D87148}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using GlitchyEngine;
|
||||||
|
|
||||||
|
namespace Sandbox;
|
||||||
|
|
||||||
|
public static class TestClass
|
||||||
|
{
|
||||||
|
[UnmanagedCallersOnly]
|
||||||
|
public static void TestFunction()
|
||||||
|
{
|
||||||
|
Console.WriteLine("Hello from the second Assembly!");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void InternalTest()
|
||||||
|
{
|
||||||
|
Console.WriteLine("Ja, ich existiere in der Tat");
|
||||||
|
|
||||||
|
Log.Info("Yeah!");
|
||||||
|
//Console.WriteLine("Und nun bin ich anders");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int Test(IntPtr arg, int sizeofArg)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"YUPPYPLASDPASDOIUZASD");
|
||||||
|
return 7;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,10 +30,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
MeshComponent = {
|
MeshComponent = {
|
||||||
Mesh = "Models\\sphere.glb"
|
Mesh = "Models/sphere.glb"
|
||||||
},
|
},
|
||||||
MeshRendererComponent = {
|
MeshRendererComponent = {
|
||||||
Material = "Textures\\TestMaterial.mat"
|
Material = "Textures/TestMaterial.mat"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -48,20 +48,20 @@
|
|||||||
Z = -4
|
Z = -4
|
||||||
},
|
},
|
||||||
Rotation = {
|
Rotation = {
|
||||||
X = 0.614328,
|
X = 0.614328027,
|
||||||
Y = 0.239776,
|
Y = 0.239776045,
|
||||||
Z = 0.031567,
|
Z = 0.0315669999,
|
||||||
W = 0.751074
|
W = 0.751073837
|
||||||
},
|
},
|
||||||
Scale = {
|
Scale = {
|
||||||
X = 0.999999,
|
X = 0.999998868,
|
||||||
Y = 1,
|
Y = 1,
|
||||||
Z = 1.000001
|
Z = 1.00000095
|
||||||
},
|
},
|
||||||
EditorEulerRotation = {
|
EditorEulerRotation = {
|
||||||
X = 1.308998,
|
X = 1.30899811,
|
||||||
Y = 0.349066,
|
Y = 0.349065989,
|
||||||
Z = 0.349066
|
Z = 0.349065989
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
LightComponent = {
|
LightComponent = {
|
||||||
@@ -69,8 +69,8 @@
|
|||||||
Illuminance = 10,
|
Illuminance = 10,
|
||||||
Color = {
|
Color = {
|
||||||
R = 1,
|
R = 1,
|
||||||
G = 0.991772,
|
G = 0.991771996,
|
||||||
B = 0.740862
|
B = 0.74086225
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -103,10 +103,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
MeshComponent = {
|
MeshComponent = {
|
||||||
Mesh = "Models\\plane.glb"
|
Mesh = "Models/plane.glb"
|
||||||
},
|
},
|
||||||
MeshRendererComponent = {
|
MeshRendererComponent = {
|
||||||
Material = "Textures\\TestMaterial.mat"
|
Material = "Textures/TestMaterial.mat"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -121,10 +121,10 @@
|
|||||||
Z = -5
|
Z = -5
|
||||||
},
|
},
|
||||||
Rotation = {
|
Rotation = {
|
||||||
X = 0.21644,
|
X = 0.216440007,
|
||||||
Y = 0,
|
Y = 0,
|
||||||
Z = 0,
|
Z = 0,
|
||||||
W = 0.976296
|
W = 0.976296008
|
||||||
},
|
},
|
||||||
Scale = {
|
Scale = {
|
||||||
X = 1,
|
X = 1,
|
||||||
@@ -132,7 +132,7 @@
|
|||||||
Z = 1
|
Z = 1
|
||||||
},
|
},
|
||||||
EditorEulerRotation = {
|
EditorEulerRotation = {
|
||||||
X = 0.436332,
|
X = 0.436332017,
|
||||||
Y = 0,
|
Y = 0,
|
||||||
Z = 0
|
Z = 0
|
||||||
}
|
}
|
||||||
@@ -140,15 +140,85 @@
|
|||||||
CameraComponent = {
|
CameraComponent = {
|
||||||
Primary = true,
|
Primary = true,
|
||||||
ProjectionType = .InfinitePerspective,
|
ProjectionType = .InfinitePerspective,
|
||||||
PerspectiveFovY = 1.047198,
|
PerspectiveFovY = 1.30899692,
|
||||||
PerspectiveNearPlane = 0.1,
|
PerspectiveNearPlane = 0.100000001,
|
||||||
PerspectiveFarPlane = 10000,
|
PerspectiveFarPlane = 10000,
|
||||||
OrthographicHeight = 10,
|
OrthographicHeight = 10,
|
||||||
OrthographicNearPlane = 0,
|
OrthographicNearPlane = 0,
|
||||||
OrthographicFarPlane = 10,
|
OrthographicFarPlane = 10,
|
||||||
AspectRatio = 2.156692,
|
AspectRatio = 2.19888878,
|
||||||
FixedAspectRatio = false
|
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 = {
|
NameComponent = {
|
||||||
Name = "Quad"
|
Name = "Quad"
|
||||||
},
|
},
|
||||||
SpriterRendererComponent = {
|
SpriteRendererComponent = {
|
||||||
Color = {
|
Color = {
|
||||||
R = 0,
|
R = 0,
|
||||||
G = 0.551178,
|
G = 0.55117774,
|
||||||
B = 0.328787,
|
B = 0.32878688,
|
||||||
A = 1
|
A = 1
|
||||||
},
|
},
|
||||||
IsCircle = false,
|
Sprite = "Textures/TestMat/rustediron2_albedo.png",
|
||||||
Sprite = "\\Textures\\TestMat\\rustediron2_albedo.png",
|
|
||||||
UvTransform = {
|
UvTransform = {
|
||||||
X = 0,
|
X = 0,
|
||||||
Y = 0,
|
Y = 0,
|
||||||
@@ -24,7 +23,7 @@
|
|||||||
},
|
},
|
||||||
TransformComponent = {
|
TransformComponent = {
|
||||||
Position = {
|
Position = {
|
||||||
X = 0,
|
X = -0.72789681,
|
||||||
Y = 2,
|
Y = 2,
|
||||||
Z = 0
|
Z = 0
|
||||||
},
|
},
|
||||||
@@ -69,15 +68,14 @@
|
|||||||
NameComponent = {
|
NameComponent = {
|
||||||
Name = "Floor"
|
Name = "Floor"
|
||||||
},
|
},
|
||||||
SpriterRendererComponent = {
|
SpriteRendererComponent = {
|
||||||
Color = {
|
Color = {
|
||||||
R = 1,
|
R = 1,
|
||||||
G = 0.941886,
|
G = 0.941886961,
|
||||||
B = 0.401485,
|
B = 0.401484549,
|
||||||
A = 1
|
A = 1
|
||||||
},
|
},
|
||||||
IsCircle = false,
|
Sprite = "",
|
||||||
Sprite = null,
|
|
||||||
UvTransform = {
|
UvTransform = {
|
||||||
X = 0,
|
X = 0,
|
||||||
Y = 0,
|
Y = 0,
|
||||||
@@ -158,30 +156,36 @@
|
|||||||
CameraComponent = {
|
CameraComponent = {
|
||||||
Primary = true,
|
Primary = true,
|
||||||
ProjectionType = .InfinitePerspective,
|
ProjectionType = .InfinitePerspective,
|
||||||
PerspectiveFovY = 1.308997,
|
PerspectiveFovY = 1.30899692,
|
||||||
PerspectiveNearPlane = 0.1,
|
PerspectiveNearPlane = 0.100000001,
|
||||||
PerspectiveFarPlane = 10000,
|
PerspectiveFarPlane = 10000,
|
||||||
OrthographicHeight = 10,
|
OrthographicHeight = 10,
|
||||||
OrthographicNearPlane = 0,
|
OrthographicNearPlane = 0,
|
||||||
OrthographicFarPlane = 10,
|
OrthographicFarPlane = 10,
|
||||||
AspectRatio = 2.969697,
|
AspectRatio = 0.884925187,
|
||||||
FixedAspectRatio = false
|
FixedAspectRatio = false
|
||||||
}
|
},
|
||||||
|
ScriptComponent = {
|
||||||
|
ScriptClass = "Sandbox.Camera",
|
||||||
|
Fields = [
|
||||||
|
DistanceFromPlayer = (Float)-7,
|
||||||
|
DontFollowRadius = (Float)3
|
||||||
|
] }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Id = 15710354273720487680,
|
Id = 15710354273720487680,
|
||||||
NameComponent = {
|
NameComponent = {
|
||||||
Name = "Circle"
|
Name = "Player"
|
||||||
},
|
},
|
||||||
SpriterRendererComponent = {
|
CircleRendererComponent = {
|
||||||
Color = {
|
Color = {
|
||||||
R = 1,
|
R = 1,
|
||||||
G = 1,
|
G = 0,
|
||||||
B = 1,
|
B = 0,
|
||||||
A = 1
|
A = 1
|
||||||
},
|
},
|
||||||
IsCircle = true,
|
InnerRadius = 0.300000012,
|
||||||
Sprite = "\\Textures\\rocket.png",
|
Sprite = "",
|
||||||
UvTransform = {
|
UvTransform = {
|
||||||
X = 0,
|
X = 0,
|
||||||
Y = 0,
|
Y = 0,
|
||||||
@@ -191,8 +195,8 @@
|
|||||||
},
|
},
|
||||||
TransformComponent = {
|
TransformComponent = {
|
||||||
Position = {
|
Position = {
|
||||||
X = -0.121203,
|
X = -0.121203184,
|
||||||
Y = 0.66016,
|
Y = 0.660160959,
|
||||||
Z = 0
|
Z = 0
|
||||||
},
|
},
|
||||||
Rotation = {
|
Rotation = {
|
||||||
@@ -226,7 +230,42 @@
|
|||||||
Friction = 0.5,
|
Friction = 0.5,
|
||||||
Restitution = 0,
|
Restitution = 0,
|
||||||
RestitutionThreshold = 0.5
|
RestitutionThreshold = 0.5
|
||||||
}
|
},
|
||||||
|
ScriptComponent = {
|
||||||
|
ScriptClass = "Sandbox.MyTestEntity",
|
||||||
|
Fields = [
|
||||||
|
Bo = (Bool)false,
|
||||||
|
By = (Byte)0,
|
||||||
|
Us = (UShort)57,
|
||||||
|
Ui = (UInt)54,
|
||||||
|
Ul = (ULong)53,
|
||||||
|
Sb = (SByte)-128,
|
||||||
|
Sh = (Short)95,
|
||||||
|
In = (Int)-149,
|
||||||
|
Lo = (Long)82,
|
||||||
|
Fl = (Float)-98.122963,
|
||||||
|
Do = (Double)118,
|
||||||
|
V2 = (float2){
|
||||||
|
X = 11,
|
||||||
|
Y = 12
|
||||||
|
},
|
||||||
|
V3 = (float3){
|
||||||
|
X = 13,
|
||||||
|
Y = 14,
|
||||||
|
Z = 15
|
||||||
|
},
|
||||||
|
V4 = (float4){
|
||||||
|
X = 14,
|
||||||
|
Y = 17,
|
||||||
|
Z = 18,
|
||||||
|
W = 19
|
||||||
|
},
|
||||||
|
TheEntity = (Entity)0,
|
||||||
|
JumpForce = (Float)200,
|
||||||
|
MoveForce = (Float)148,
|
||||||
|
MyNumber = (Int)22,
|
||||||
|
MyDouble = (Double)23
|
||||||
|
] }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Id = 935640822766280888,
|
Id = 935640822766280888,
|
||||||
@@ -235,34 +274,34 @@
|
|||||||
},
|
},
|
||||||
TransformComponent = {
|
TransformComponent = {
|
||||||
Position = {
|
Position = {
|
||||||
X = 3.883276,
|
X = 3.88327599,
|
||||||
Y = 0,
|
Y = 0,
|
||||||
Z = -0.808795
|
Z = -0.808795214
|
||||||
},
|
},
|
||||||
Rotation = {
|
Rotation = {
|
||||||
X = 0.497987,
|
X = 0.497987002,
|
||||||
Y = -0.103421,
|
Y = -0.103420995,
|
||||||
Z = 0.15538,
|
Z = 0.155380026,
|
||||||
W = 0.846859
|
W = 0.846859217
|
||||||
},
|
},
|
||||||
Scale = {
|
Scale = {
|
||||||
X = 0.999998,
|
X = 0.999997795,
|
||||||
Y = 1,
|
Y = 1,
|
||||||
Z = 1
|
Z = 1
|
||||||
},
|
},
|
||||||
EditorEulerRotation = {
|
EditorEulerRotation = {
|
||||||
X = 1.090894,
|
X = 1.09089541,
|
||||||
Y = -0.340794,
|
Y = -0.340793997,
|
||||||
Z = 0.160858
|
Z = 0.160857871
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
LightComponent = {
|
LightComponent = {
|
||||||
LightType = .Directional,
|
LightType = .Directional,
|
||||||
Illuminance = 12.9,
|
Illuminance = 12.8999996,
|
||||||
Color = {
|
Color = {
|
||||||
R = 0.985467,
|
R = 0.985467017,
|
||||||
G = 1,
|
G = 1,
|
||||||
B = 0.569979
|
B = 0.569978058
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -275,7 +314,7 @@
|
|||||||
Position = {
|
Position = {
|
||||||
X = 0,
|
X = 0,
|
||||||
Y = 0,
|
Y = 0,
|
||||||
Z = -1.523338
|
Z = 2.56930423
|
||||||
},
|
},
|
||||||
Rotation = {
|
Rotation = {
|
||||||
X = 0,
|
X = 0,
|
||||||
@@ -295,10 +334,196 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
MeshComponent = {
|
MeshComponent = {
|
||||||
Mesh = "\\Models\\sphere.glb"
|
Mesh = "Models/sphere.glb"
|
||||||
},
|
},
|
||||||
MeshRendererComponent = {
|
MeshRendererComponent = {
|
||||||
Material = "\\Textures\\TestMaterial.mat"
|
Material = "Textures/TestMaterial.mat"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Id = 2241063100006479259,
|
||||||
|
NameComponent = {
|
||||||
|
Name = "Floor 2"
|
||||||
|
},
|
||||||
|
SpriteRendererComponent = {
|
||||||
|
Color = {
|
||||||
|
R = 0.425658971,
|
||||||
|
G = 0.855207562,
|
||||||
|
B = 0.0558161102,
|
||||||
|
A = 1
|
||||||
|
},
|
||||||
|
Sprite = "",
|
||||||
|
UvTransform = {
|
||||||
|
X = 0,
|
||||||
|
Y = 0,
|
||||||
|
Z = 1,
|
||||||
|
W = 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
TransformComponent = {
|
||||||
|
Position = {
|
||||||
|
X = 6.74610233,
|
||||||
|
Y = -2.03225899,
|
||||||
|
Z = 0
|
||||||
|
},
|
||||||
|
Rotation = {
|
||||||
|
X = 0,
|
||||||
|
Y = 0,
|
||||||
|
Z = -0.331792623,
|
||||||
|
W = 0.943352342
|
||||||
|
},
|
||||||
|
Scale = {
|
||||||
|
X = 5.29557419,
|
||||||
|
Y = 1,
|
||||||
|
Z = 1
|
||||||
|
},
|
||||||
|
EditorEulerRotation = {
|
||||||
|
X = 0,
|
||||||
|
Y = 0,
|
||||||
|
Z = -0.676406503
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Rigidbody2D = {
|
||||||
|
BodyType = .Static,
|
||||||
|
FixedRotation = false
|
||||||
|
},
|
||||||
|
BoxCollider2D = {
|
||||||
|
Offset = {
|
||||||
|
X = 0,
|
||||||
|
Y = 0
|
||||||
|
},
|
||||||
|
Size = {
|
||||||
|
X = 0.5,
|
||||||
|
Y = 0.5
|
||||||
|
},
|
||||||
|
Density = 1,
|
||||||
|
Friction = 0.5,
|
||||||
|
Restitution = 0,
|
||||||
|
RestitutionThreshold = 0.5
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Id = 5126705881069187728,
|
||||||
|
NameComponent = {
|
||||||
|
Name = "Floor 3"
|
||||||
|
},
|
||||||
|
SpriteRendererComponent = {
|
||||||
|
Color = {
|
||||||
|
R = 0.666116953,
|
||||||
|
G = 0.0600316115,
|
||||||
|
B = 1,
|
||||||
|
A = 1
|
||||||
|
},
|
||||||
|
Sprite = "",
|
||||||
|
UvTransform = {
|
||||||
|
X = 0,
|
||||||
|
Y = 0,
|
||||||
|
Z = 1,
|
||||||
|
W = 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
TransformComponent = {
|
||||||
|
Position = {
|
||||||
|
X = 15.2321301,
|
||||||
|
Y = -1.98709249,
|
||||||
|
Z = 0
|
||||||
|
},
|
||||||
|
Rotation = {
|
||||||
|
X = 0,
|
||||||
|
Y = 0,
|
||||||
|
Z = 0.134986058,
|
||||||
|
W = 0.990847468
|
||||||
|
},
|
||||||
|
Scale = {
|
||||||
|
X = 13.9764566,
|
||||||
|
Y = 1,
|
||||||
|
Z = 1
|
||||||
|
},
|
||||||
|
EditorEulerRotation = {
|
||||||
|
X = 0,
|
||||||
|
Y = 0,
|
||||||
|
Z = 0.270798802
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Rigidbody2D = {
|
||||||
|
BodyType = .Static,
|
||||||
|
FixedRotation = false
|
||||||
|
},
|
||||||
|
BoxCollider2D = {
|
||||||
|
Offset = {
|
||||||
|
X = 0,
|
||||||
|
Y = 0
|
||||||
|
},
|
||||||
|
Size = {
|
||||||
|
X = 0.5,
|
||||||
|
Y = 0.5
|
||||||
|
},
|
||||||
|
Density = 1,
|
||||||
|
Friction = 0.5,
|
||||||
|
Restitution = 0.800000012,
|
||||||
|
RestitutionThreshold = 0.5
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Id = 6861260438693901700,
|
||||||
|
NameComponent = {
|
||||||
|
Name = "Floor 4"
|
||||||
|
},
|
||||||
|
SpriteRendererComponent = {
|
||||||
|
Color = {
|
||||||
|
R = 0.176544324,
|
||||||
|
G = 0.666713238,
|
||||||
|
B = 0.687030852,
|
||||||
|
A = 1
|
||||||
|
},
|
||||||
|
Sprite = "",
|
||||||
|
UvTransform = {
|
||||||
|
X = 0,
|
||||||
|
Y = 0,
|
||||||
|
Z = 1,
|
||||||
|
W = 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
TransformComponent = {
|
||||||
|
Position = {
|
||||||
|
X = -6.27842855,
|
||||||
|
Y = 2.62550211,
|
||||||
|
Z = 0
|
||||||
|
},
|
||||||
|
Rotation = {
|
||||||
|
X = 0,
|
||||||
|
Y = 0,
|
||||||
|
Z = 0.187087834,
|
||||||
|
W = 0.982343197
|
||||||
|
},
|
||||||
|
Scale = {
|
||||||
|
X = 0.999999523,
|
||||||
|
Y = 6.49634314,
|
||||||
|
Z = 1
|
||||||
|
},
|
||||||
|
EditorEulerRotation = {
|
||||||
|
X = 0,
|
||||||
|
Y = 0,
|
||||||
|
Z = 0.376393586
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Rigidbody2D = {
|
||||||
|
BodyType = .Static,
|
||||||
|
FixedRotation = false
|
||||||
|
},
|
||||||
|
BoxCollider2D = {
|
||||||
|
Offset = {
|
||||||
|
X = 0,
|
||||||
|
Y = 0
|
||||||
|
},
|
||||||
|
Size = {
|
||||||
|
X = 0.5,
|
||||||
|
Y = 0.5
|
||||||
|
},
|
||||||
|
Density = 1,
|
||||||
|
Friction = 0.5,
|
||||||
|
Restitution = 0.899999976,
|
||||||
|
RestitutionThreshold = 0.5
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
#pragma EngineBuffer[ Name = "SceneConstants"; Binding = "Scene" ]
|
||||||
|
cbuffer SceneConstants : register(b0)
|
||||||
|
{
|
||||||
|
float4x4 ViewProjection;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma EngineBuffer[ Name = "ObjectConstants"; Binding = "Object" ]
|
||||||
|
cbuffer ObjectConstants : register(b1)
|
||||||
|
{
|
||||||
|
float4x4 Transform;
|
||||||
|
/**
|
||||||
|
* \brief Inverted and transposed transform matrix.
|
||||||
|
* \remarks This matrix is used in order to correctly transform normal vectors.
|
||||||
|
*/
|
||||||
|
float4x3 Transform_InvT;
|
||||||
|
#ifdef OutputEntityId
|
||||||
|
uint EntityId;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Pixel Shader output for lit surfaces.
|
||||||
|
*/
|
||||||
|
struct PS_OUT_Lit
|
||||||
|
{
|
||||||
|
/** RGB: Albedo A: Transparency */
|
||||||
|
float4 Albedo : SV_TARGET0;
|
||||||
|
/** RG: TextureNormal.XY | BA: GeoNrm.XY */
|
||||||
|
float4 Normal : SV_TARGET1;
|
||||||
|
/** R: GeoNrm.Z | GBA: GeoTan.XYZ */
|
||||||
|
float4 Tangent : SV_TARGET2;
|
||||||
|
/** RGB: world position XYZ | A: 1.0 */
|
||||||
|
float4 Position : SV_TARGET3;
|
||||||
|
/** RGB: emissive light and color | A: unused */
|
||||||
|
float4 Emissive : SV_TARGET4;
|
||||||
|
/** R: Metallicity | G: Roughness | B: Ambient | A: Unused */
|
||||||
|
float4 Material : SV_TARGET5;
|
||||||
|
#ifdef OutputEntityId
|
||||||
|
/** Needed for editor picking. Simply pass through the EntityId. */
|
||||||
|
uint EntityId : SV_TARGET6;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Pixel Shader output for unlit surfaces.
|
||||||
|
*/
|
||||||
|
struct PS_OUT_Unlit
|
||||||
|
{
|
||||||
|
/** RGB: Color A: Transparency */
|
||||||
|
float4 Color : SV_TARGET0;
|
||||||
|
/** RGB: emissive light and color | A: unused */
|
||||||
|
float4 Emissive : SV_TARGET1;
|
||||||
|
/** RGB: world position XYZ | A: 1.0 */
|
||||||
|
float4 Position : SV_TARGET2;
|
||||||
|
|
||||||
|
#ifdef OutputEntityId
|
||||||
|
uint EntityId : SV_TARGET5;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
AssetLoader = "EffectAssetLoader",
|
||||||
|
Config = (GlitchyEditor.Assets.EffectAssetLoaderConfig){}/* No reflection data for GlitchyEditor.Assets.EffectAssetLoaderConfig. Add [BonTarget] or force it */
|
||||||
|
}
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
Texture2DArray Texture : register(t0);
|
||||||
|
SamplerState Sampler : register(s0);
|
||||||
|
|
||||||
|
Texture2DArray<int4> IntTexture : register(t1);
|
||||||
|
SamplerState IntSampler : register(s1);
|
||||||
|
|
||||||
|
Texture2DArray<uint4> UIntTexture : register(t2);
|
||||||
|
SamplerState UIntSampler : register(s2);
|
||||||
|
|
||||||
|
#define SWIZZLE_NONE 0
|
||||||
|
#define SWIZZLE_R 1
|
||||||
|
#define SWIZZLE_G 2
|
||||||
|
#define SWIZZLE_B 3
|
||||||
|
#define SWIZZLE_A 4
|
||||||
|
|
||||||
|
cbuffer Constants
|
||||||
|
{
|
||||||
|
float ColorOffset = 0.5;
|
||||||
|
float AlphaOffset = 0.0;
|
||||||
|
float ColorScale = 0.5;
|
||||||
|
float AlphaScale = 1.0;
|
||||||
|
|
||||||
|
float MipLevel = 0.0;
|
||||||
|
float ArraySlice = 0.0;
|
||||||
|
|
||||||
|
// 0: Float | 1: Int | 2: Uint
|
||||||
|
int Mode = 0;
|
||||||
|
|
||||||
|
int4 Swizzle = int4(SWIZZLE_R, SWIZZLE_G, SWIZZLE_B, SWIZZLE_A);
|
||||||
|
|
||||||
|
float2 Texels;
|
||||||
|
|
||||||
|
float4x4 WorldViewProjection;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct VS_Input
|
||||||
|
{
|
||||||
|
float2 Position : POSITION;
|
||||||
|
float2 Texcoord : TEXCOORD0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PS_Input
|
||||||
|
{
|
||||||
|
float4 Position : SV_Position;
|
||||||
|
float2 Texcoord : TEXCOORD0;
|
||||||
|
};
|
||||||
|
|
||||||
|
PS_Input VS(VS_Input input)
|
||||||
|
{
|
||||||
|
PS_Input output;
|
||||||
|
|
||||||
|
output.Position = mul(WorldViewProjection, float4(input.Position, 0.0f, 1.0f));
|
||||||
|
output.Texcoord = input.Texcoord;
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwizzleColor(int swizzleMode, float4 colorToSwizzle, inout float output)
|
||||||
|
{
|
||||||
|
switch (swizzleMode)
|
||||||
|
{
|
||||||
|
case SWIZZLE_R:
|
||||||
|
output = colorToSwizzle.r;
|
||||||
|
break;
|
||||||
|
case SWIZZLE_G:
|
||||||
|
output = colorToSwizzle.g;
|
||||||
|
break;
|
||||||
|
case SWIZZLE_B:
|
||||||
|
output = colorToSwizzle.b;
|
||||||
|
break;
|
||||||
|
case SWIZZLE_A:
|
||||||
|
output = colorToSwizzle.a;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float4 PS(PS_Input input) : SV_Target0
|
||||||
|
{
|
||||||
|
float4 outputColor;
|
||||||
|
|
||||||
|
if (Mode == 0)
|
||||||
|
{
|
||||||
|
//float4 color = Texture.SampleLevel(Sampler, float3(input.Texcoord, ArraySlice), MipLevel);
|
||||||
|
// Quasi next neighbor
|
||||||
|
float4 color = Texture.Load(int4(input.Texcoord * Texels, ArraySlice, MipLevel));
|
||||||
|
outputColor = float4(ColorOffset.xxx, AlphaOffset) + color * float4(ColorScale.xxx, AlphaScale);
|
||||||
|
}
|
||||||
|
else if (Mode == 1)
|
||||||
|
{
|
||||||
|
int4 color = IntTexture.Load(int4(input.Texcoord * Texels, ArraySlice, MipLevel));
|
||||||
|
outputColor = float4(ColorOffset.xxx, AlphaOffset) + color * float4(ColorScale.xxx, AlphaScale);
|
||||||
|
}
|
||||||
|
else if (Mode == 2)
|
||||||
|
{
|
||||||
|
uint4 color = UIntTexture.Load(int4(input.Texcoord * Texels, ArraySlice, MipLevel));
|
||||||
|
outputColor = float4(ColorOffset.xxx, AlphaOffset) + color * float4(ColorScale.xxx, AlphaScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
float4 swizzledOutput = float4(0, 0, 0, 1);
|
||||||
|
|
||||||
|
SwizzleColor(Swizzle.r, outputColor, swizzledOutput.r);
|
||||||
|
SwizzleColor(Swizzle.g, outputColor, swizzledOutput.g);
|
||||||
|
SwizzleColor(Swizzle.b, outputColor, swizzledOutput.b);
|
||||||
|
SwizzleColor(Swizzle.a, outputColor, swizzledOutput.a);
|
||||||
|
|
||||||
|
return swizzledOutput;
|
||||||
|
}
|
||||||
|
|
||||||
|
#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 */
|
||||||
|
}
|
||||||
@@ -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 */
|
||||||
|
}
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#include "ShaderHelpers.hlsl"
|
#include "ShaderHelpers.hlsl"
|
||||||
|
|
||||||
|
#include "GlitchyEngine.hlsl"
|
||||||
|
|
||||||
Texture2D AlbedoTexture : register(t0);
|
Texture2D AlbedoTexture : register(t0);
|
||||||
SamplerState AlbedoSampler : register(s0);
|
SamplerState AlbedoSampler : register(s0);
|
||||||
|
|
||||||
@@ -14,28 +16,11 @@ SamplerState MetallicSampler : register(s2);
|
|||||||
Texture2D<float> RoughnessTexture : register(t3);
|
Texture2D<float> RoughnessTexture : register(t3);
|
||||||
SamplerState RoughnessSampler : register(s3);
|
SamplerState RoughnessSampler : register(s3);
|
||||||
|
|
||||||
// Texture2D<float> AmbientTexture : register(t4);
|
Texture2D<float3> EmissiveTexture : register(t4);
|
||||||
// SamplerState AmbientSampler : register(s4);
|
SamplerState EmissiveSampler : register(s4);
|
||||||
|
|
||||||
#pragma EngineBuffer[ Name = "SceneConstants"; Binding = "Scene" ]
|
// Texture2D<float> AmbientTexture : register(t5);
|
||||||
cbuffer SceneConstants : register(b0)
|
// SamplerState AmbientSampler : register(s5);
|
||||||
{
|
|
||||||
float4x4 ViewProjection;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma EngineBuffer[ Name = "ObjectConstants"; Binding = "Object" ]
|
|
||||||
cbuffer ObjectConstants : register(b1)
|
|
||||||
{
|
|
||||||
float4x4 Transform;
|
|
||||||
/**
|
|
||||||
* \brief Inverted and transposed transform matrix.
|
|
||||||
* \remarks This matrix is used in order to correctly transform normal vectors.
|
|
||||||
*/
|
|
||||||
float4x3 Transform_InvT;
|
|
||||||
#ifdef OutputEntityId
|
|
||||||
uint EntityId;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
cbuffer MaterialConstants : register(b2)
|
cbuffer MaterialConstants : register(b2)
|
||||||
{
|
{
|
||||||
@@ -44,9 +29,12 @@ cbuffer MaterialConstants : register(b2)
|
|||||||
#pragma EditorVariable[ Name = "NormalScaling"; Preview = "Normal Scaling" ]
|
#pragma EditorVariable[ Name = "NormalScaling"; Preview = "Normal Scaling" ]
|
||||||
float2 NormalScaling = float2(1.0, 1.0);
|
float2 NormalScaling = float2(1.0, 1.0);
|
||||||
#pragma EditorVariable[ Name = "MetallicFactor"; Preview = "Metallic Factor"; Min = 0.0f; Max = 1.0f ]
|
#pragma EditorVariable[ Name = "MetallicFactor"; Preview = "Metallic Factor"; Min = 0.0f; Max = 1.0f ]
|
||||||
float MetallicFactor = 1.0;
|
float MetallicFactor = 0.0;
|
||||||
#pragma EditorVariable[ Name = "RoughnessFactor"; Preview = "Rougness Factor"; Min = 0.0f; Max = 1.0f ]
|
#pragma EditorVariable[ Name = "RoughnessFactor"; Preview = "Rougness Factor"; Min = 0.0f; Max = 1.0f ]
|
||||||
float RoughnessFactor = 1.0;
|
float RoughnessFactor = 0.6;
|
||||||
|
#pragma EditorVariable[ Name = "EmissiveColor"; Preview = "Emissive Factor"; Type="ColorHDR" ]
|
||||||
|
float3 EmissiveColor = float3(0.0, 0.0, 0.0);
|
||||||
|
// # pra gma Editor Variable[ Name = "AmbientFactor"; Preview = "Ambient Factor" ]
|
||||||
// float AmbientFactor = 1.0;
|
// float AmbientFactor = 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,7 +47,7 @@ struct VS_IN
|
|||||||
float2 TexCoord : TEXCOORD;
|
float2 TexCoord : TEXCOORD;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PS_IN
|
typedef struct PS_IN
|
||||||
{
|
{
|
||||||
float4 Position : SV_POSITION;
|
float4 Position : SV_POSITION;
|
||||||
float3 WorldPosition : WORLDPOSITION;
|
float3 WorldPosition : WORLDPOSITION;
|
||||||
@@ -70,11 +58,11 @@ struct PS_IN
|
|||||||
#ifdef OutputEntityId
|
#ifdef OutputEntityId
|
||||||
nointerpolation uint EntityId : ENTITYID;
|
nointerpolation uint EntityId : ENTITYID;
|
||||||
#endif
|
#endif
|
||||||
};
|
} VS_OUT;
|
||||||
|
|
||||||
PS_IN VS(VS_IN input)
|
VS_OUT VS(VS_IN input)
|
||||||
{
|
{
|
||||||
PS_IN output;
|
VS_OUT output;
|
||||||
|
|
||||||
float4 worldPosition = mul(Transform, float4(input.Position, 1));
|
float4 worldPosition = mul(Transform, float4(input.Position, 1));
|
||||||
|
|
||||||
@@ -92,22 +80,22 @@ PS_IN VS(VS_IN input)
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PS_OUT
|
//struct PS_OUT
|
||||||
{
|
//{
|
||||||
float4 Albedo : SV_TARGET0;
|
// float4 Albedo : SV_TARGET0;
|
||||||
// RG: TextureNormal.XY BA: GeoNrm.XY
|
// // RG: TextureNormal.XY BA: GeoNrm.XY
|
||||||
float4 Normal : SV_TARGET1;
|
// float4 Normal : SV_TARGET1;
|
||||||
// R: GeoNrm.Z GBA: GeoTan.XYZ
|
// // R: GeoNrm.Z GBA: GeoTan.XYZ
|
||||||
float4 Tangent : SV_TARGET2;
|
// float4 Tangent : SV_TARGET2;
|
||||||
float4 Position : SV_TARGET3;
|
// float4 Position : SV_TARGET3;
|
||||||
// R: Metallicity G: Roughness B: Ambient
|
// // R: Metallicity G: Roughness B: Ambient
|
||||||
float4 Material : SV_TARGET4;
|
// float4 Material : SV_TARGET4;
|
||||||
#ifdef OutputEntityId
|
//#ifdef OutputEntityId
|
||||||
uint EntityId : SV_TARGET5;
|
// uint EntityId : SV_TARGET5;
|
||||||
#endif
|
//#endif
|
||||||
};
|
//};
|
||||||
|
|
||||||
PS_OUT PS(PS_IN input)
|
PS_OUT_Lit PS(PS_IN input)
|
||||||
{
|
{
|
||||||
// Build tangent space
|
// Build tangent space
|
||||||
float3 normal = normalize(input.Normal);
|
float3 normal = normalize(input.Normal);
|
||||||
@@ -124,6 +112,9 @@ PS_OUT PS(PS_IN input)
|
|||||||
float texMetallic = MetallicTexture.Sample(MetallicSampler, input.TexCoord);
|
float texMetallic = MetallicTexture.Sample(MetallicSampler, input.TexCoord);
|
||||||
float texRoughness = RoughnessTexture.Sample(RoughnessSampler, input.TexCoord);
|
float texRoughness = RoughnessTexture.Sample(RoughnessSampler, input.TexCoord);
|
||||||
|
|
||||||
|
|
||||||
|
float3 texEmissive = EmissiveTexture.Sample(EmissiveSampler, input.TexCoord);
|
||||||
|
|
||||||
//float3 objectNormal = mul(tangentTransform, texNormal);
|
//float3 objectNormal = mul(tangentTransform, texNormal);
|
||||||
//float3 worldNormal = mul(objectNormal, (float3x3)Transform);
|
//float3 worldNormal = mul(objectNormal, (float3x3)Transform);
|
||||||
|
|
||||||
@@ -131,6 +122,7 @@ PS_OUT PS(PS_IN input)
|
|||||||
float3 finalNormal = ScaleNormal(texNormal, NormalScaling);
|
float3 finalNormal = ScaleNormal(texNormal, NormalScaling);
|
||||||
float finalMetallic = texMetallic * MetallicFactor;
|
float finalMetallic = texMetallic * MetallicFactor;
|
||||||
float finalRoughness = texRoughness * RoughnessFactor;
|
float finalRoughness = texRoughness * RoughnessFactor;
|
||||||
|
float3 finalEmissive = texEmissive * EmissiveColor;
|
||||||
|
|
||||||
/////////////TODO: REMOVEME
|
/////////////TODO: REMOVEME
|
||||||
|
|
||||||
@@ -141,12 +133,13 @@ PS_OUT PS(PS_IN input)
|
|||||||
|
|
||||||
/////////////TODO: END_REMOVEME
|
/////////////TODO: END_REMOVEME
|
||||||
|
|
||||||
PS_OUT output;
|
PS_OUT_Lit output;
|
||||||
output.Albedo = finalAlbedo;
|
output.Albedo = finalAlbedo;
|
||||||
//output.Normal = float4(objectNormal, 1.0);
|
//output.Normal = float4(objectNormal, 1.0);
|
||||||
output.Normal = float4(finalNormal.xy, normal.xy);
|
output.Normal = float4(finalNormal.xy, normal.xy);
|
||||||
output.Tangent = float4(normal.z, tangent.xyz);
|
output.Tangent = float4(normal.z, tangent.xyz);
|
||||||
output.Position = float4(input.WorldPosition, 1.0);
|
output.Position = float4(input.WorldPosition, 1.0);
|
||||||
|
output.Emissive = float4(finalEmissive, 0.0);
|
||||||
output.Material = float4(finalMetallic, finalRoughness, 1.0, 0);
|
output.Material = float4(finalMetallic, finalRoughness, 1.0, 0);
|
||||||
|
|
||||||
#ifdef OutputEntityId
|
#ifdef OutputEntityId
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ Texture2D GBuffer_Albedo : register(t0);
|
|||||||
Texture2D GBuffer_Normal : register(t1);
|
Texture2D GBuffer_Normal : register(t1);
|
||||||
Texture2D GBuffer_Tangent : register(t2);
|
Texture2D GBuffer_Tangent : register(t2);
|
||||||
Texture2D GBuffer_Position : register(t3);
|
Texture2D GBuffer_Position : register(t3);
|
||||||
Texture2D GBuffer_Material : register(t4);
|
Texture2D GBuffer_Emissive : register(t4);
|
||||||
|
Texture2D GBuffer_Material : register(t5);
|
||||||
|
|
||||||
cbuffer Constants
|
cbuffer Constants
|
||||||
{
|
{
|
||||||
@@ -58,7 +59,8 @@ float4 PS(PS_IN input) : SV_TARGET
|
|||||||
float4 rawAlbedo = GBuffer_Albedo.Sample(Sampler, input.TexCoord);
|
float4 rawAlbedo = GBuffer_Albedo.Sample(Sampler, input.TexCoord);
|
||||||
float4 rawNormal = GBuffer_Normal.Sample(Sampler, input.TexCoord);
|
float4 rawNormal = GBuffer_Normal.Sample(Sampler, input.TexCoord);
|
||||||
float4 rawTangent = GBuffer_Tangent.Sample(Sampler, input.TexCoord);
|
float4 rawTangent = GBuffer_Tangent.Sample(Sampler, input.TexCoord);
|
||||||
float4 rawPosition = GBuffer_Position.Sample(Sampler, input.TexCoord);
|
float4 rawPosition = GBuffer_Position.Sample(Sampler, input.TexCoord);
|
||||||
|
float4 rawEmissive = GBuffer_Emissive.Sample(Sampler, input.TexCoord);
|
||||||
float4 rawMaterial = GBuffer_Material.Sample(Sampler, input.TexCoord);
|
float4 rawMaterial = GBuffer_Material.Sample(Sampler, input.TexCoord);
|
||||||
|
|
||||||
// Extract data from GBuffer
|
// Extract data from GBuffer
|
||||||
@@ -108,7 +110,7 @@ float4 PS(PS_IN input) : SV_TARGET
|
|||||||
|
|
||||||
float3 luminanceColor = LightColor * Illuminance;
|
float3 luminanceColor = LightColor * Illuminance;
|
||||||
|
|
||||||
float3 final = (kd * diffuse + specular) * luminanceColor * n_dot_l;
|
float3 final = (kd * diffuse + specular) * luminanceColor * n_dot_l + rawEmissive;
|
||||||
|
|
||||||
#if OUTPUT == Inspect_NormalDistribution
|
#if OUTPUT == Inspect_NormalDistribution
|
||||||
final = max(final - 10000000, nrmDist.xxx);
|
final = max(final - 10000000, nrmDist.xxx);
|
||||||
|
|||||||
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,
|
MinFilter = .Anisotropic,
|
||||||
MagFilter = .Anisotropic,
|
MagFilter = .Anisotropic,
|
||||||
MipFilter = .Anisotropic,
|
MipFilter = .Anisotropic,
|
||||||
|
FilterMode = .Default,
|
||||||
ComparisonFunction = .Never,
|
ComparisonFunction = .Never,
|
||||||
AddressModeU = .Wrap,
|
AddressModeU = .Wrap,
|
||||||
AddressModeV = .Border,
|
AddressModeV = .Wrap,
|
||||||
AddressModeW = .Clamp,
|
AddressModeW = .Wrap,
|
||||||
MipMaxLOD = 160,
|
MipLODBias = 0,
|
||||||
|
MipMinLOD = 0,
|
||||||
|
MipMaxLOD = 3,
|
||||||
MaxAnisotropy = 16,
|
MaxAnisotropy = 16,
|
||||||
BorderColor = {
|
BorderColor = {
|
||||||
R = 0.756863,
|
R = 1,
|
||||||
G = 0.2,
|
G = 1,
|
||||||
A = 0.956863
|
B = 1,
|
||||||
|
A = 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,15 +2,15 @@
|
|||||||
AssetLoader = "EditorTextureAssetLoader",
|
AssetLoader = "EditorTextureAssetLoader",
|
||||||
Config = (GlitchyEditor.Assets.EditorTextureAssetLoaderConfig){
|
Config = (GlitchyEditor.Assets.EditorTextureAssetLoaderConfig){
|
||||||
_samplerStateDescription = {
|
_samplerStateDescription = {
|
||||||
MinFilter = .Linear,
|
MinFilter = .Anisotropic,
|
||||||
MagFilter = .Linear,
|
MagFilter = .Anisotropic,
|
||||||
MipFilter = .Linear,
|
MipFilter = .Anisotropic,
|
||||||
ComparisonFunction = .Never,
|
ComparisonFunction = .Never,
|
||||||
AddressModeU = .Clamp,
|
AddressModeU = .Wrap,
|
||||||
AddressModeV = .Clamp,
|
AddressModeV = .Wrap,
|
||||||
AddressModeW = .Clamp,
|
AddressModeW = .Clamp,
|
||||||
MipMinLOD = -340282346638528859811704183484516925440,
|
MipMinLOD = -Infinity,
|
||||||
MipMaxLOD = 340282346638528859811704183484516925440,
|
MipMaxLOD = Infinity,
|
||||||
MaxAnisotropy = 1,
|
MaxAnisotropy = 1,
|
||||||
BorderColor = {
|
BorderColor = {
|
||||||
R = 1,
|
R = 1,
|
||||||
|
|||||||
@@ -1,16 +1,20 @@
|
|||||||
{
|
{
|
||||||
AssetLoader = "EditorTextureAssetLoader",
|
AssetLoader = "EditorTextureAssetLoader",
|
||||||
Config = (GlitchyEditor.Assets.EditorTextureAssetLoaderConfig){
|
Config = (GlitchyEditor.Assets.EditorTextureAssetLoaderConfig){
|
||||||
|
_generateMipMaps = false,
|
||||||
|
_isSrgb = false,
|
||||||
_samplerStateDescription = {
|
_samplerStateDescription = {
|
||||||
MinFilter = .Linear,
|
MinFilter = .Linear,
|
||||||
MagFilter = .Linear,
|
MagFilter = .Linear,
|
||||||
MipFilter = .Linear,
|
MipFilter = .Linear,
|
||||||
|
FilterMode = .Default,
|
||||||
ComparisonFunction = .Never,
|
ComparisonFunction = .Never,
|
||||||
AddressModeU = .Clamp,
|
AddressModeU = .Wrap,
|
||||||
AddressModeV = .Clamp,
|
AddressModeV = .Wrap,
|
||||||
AddressModeW = .Clamp,
|
AddressModeW = .Clamp,
|
||||||
MipMinLOD = -340282346638528859811704183484516925440,
|
MipLODBias = 2.5999999,
|
||||||
MipMaxLOD = 340282346638528859811704183484516925440,
|
MipMinLOD = -Infinity,
|
||||||
|
MipMaxLOD = Infinity,
|
||||||
MaxAnisotropy = 1,
|
MaxAnisotropy = 1,
|
||||||
BorderColor = {
|
BorderColor = {
|
||||||
R = 1,
|
R = 1,
|
||||||
|
|||||||
@@ -1,17 +1,20 @@
|
|||||||
{
|
{
|
||||||
AssetLoader = "EditorTextureAssetLoader",
|
AssetLoader = "EditorTextureAssetLoader",
|
||||||
Config = (GlitchyEditor.Assets.EditorTextureAssetLoaderConfig){
|
Config = (GlitchyEditor.Assets.EditorTextureAssetLoaderConfig){
|
||||||
|
_generateMipMaps = false,
|
||||||
_isSrgb = true,
|
_isSrgb = true,
|
||||||
_samplerStateDescription = {
|
_samplerStateDescription = {
|
||||||
MinFilter = .Linear,
|
MinFilter = .Linear,
|
||||||
MagFilter = .Linear,
|
MagFilter = .Linear,
|
||||||
MipFilter = .Linear,
|
MipFilter = .Linear,
|
||||||
|
FilterMode = .Default,
|
||||||
ComparisonFunction = .Never,
|
ComparisonFunction = .Never,
|
||||||
AddressModeU = .Clamp,
|
AddressModeU = .Wrap,
|
||||||
AddressModeV = .Clamp,
|
AddressModeV = .Wrap,
|
||||||
AddressModeW = .Clamp,
|
AddressModeW = .Clamp,
|
||||||
MipMinLOD = -340282346638528859811704183484516925440,
|
MipLODBias = 0,
|
||||||
MipMaxLOD = 340282346638528859811704183484516925440,
|
MipMinLOD = -3.40282347e+38,
|
||||||
|
MipMaxLOD = 3.40282347e+38,
|
||||||
MaxAnisotropy = 1,
|
MaxAnisotropy = 1,
|
||||||
BorderColor = {
|
BorderColor = {
|
||||||
R = 1,
|
R = 1,
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
{
|
{
|
||||||
Effect = "content/Shaders/myEffect.hlsl",
|
Effect = "Shaders/myEffect.hlsl",
|
||||||
Textures = [
|
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",
|
||||||
|
"EmissiveTexture": "Textures/rocket.png"
|
||||||
],
|
],
|
||||||
Variables = [
|
Variables = [
|
||||||
"AlbedoColor": .ColorRGBA{
|
"AlbedoColor": .ColorRGBA{
|
||||||
@@ -23,6 +27,13 @@
|
|||||||
},
|
},
|
||||||
"RoughnessFactor": .Float{
|
"RoughnessFactor": .Float{
|
||||||
Value = 1
|
Value = 1
|
||||||
|
},
|
||||||
|
"EmissiveColor": .ColorRGB{
|
||||||
|
Value = {
|
||||||
|
R = 1,
|
||||||
|
G = 0,
|
||||||
|
B = 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -4,13 +4,14 @@
|
|||||||
_isSrgb = true,
|
_isSrgb = true,
|
||||||
_samplerStateDescription = {
|
_samplerStateDescription = {
|
||||||
MinFilter = .Linear,
|
MinFilter = .Linear,
|
||||||
|
MagFilter = .Linear,
|
||||||
MipFilter = .Linear,
|
MipFilter = .Linear,
|
||||||
ComparisonFunction = .Never,
|
ComparisonFunction = .Never,
|
||||||
AddressModeU = .Clamp,
|
AddressModeU = .Clamp,
|
||||||
AddressModeV = .Clamp,
|
AddressModeV = .Clamp,
|
||||||
AddressModeW = .Clamp,
|
AddressModeW = .Clamp,
|
||||||
MipMinLOD = -340282346638528859811704183484516925440,
|
MipMinLOD = -3.40282347e+38,
|
||||||
MipMaxLOD = 340282346638528859811704183484516925440,
|
MipMaxLOD = 3.40282347e+38,
|
||||||
MaxAnisotropy = 1,
|
MaxAnisotropy = 1,
|
||||||
BorderColor = {
|
BorderColor = {
|
||||||
R = 1,
|
R = 1,
|
||||||
|
|||||||
Binary file not shown.
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
AssetLoader = "EditorTextureAssetLoader",
|
||||||
|
Config = (GlitchyEditor.Assets.EditorTextureAssetLoaderConfig){
|
||||||
|
_isSrgb = true,
|
||||||
|
_samplerStateDescription = {
|
||||||
|
MinFilter = .Linear,
|
||||||
|
MagFilter = .Linear,
|
||||||
|
MipFilter = .Linear,
|
||||||
|
ComparisonFunction = .Never,
|
||||||
|
AddressModeU = .Clamp,
|
||||||
|
AddressModeV = .Clamp,
|
||||||
|
AddressModeW = .Clamp,
|
||||||
|
MipMinLOD = -Infinity,
|
||||||
|
MipMaxLOD = Infinity,
|
||||||
|
MaxAnisotropy = 1,
|
||||||
|
BorderColor = {
|
||||||
|
R = 1,
|
||||||
|
G = 1,
|
||||||
|
B = 1,
|
||||||
|
A = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
4.5/
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Install mono and copy the folder `lib/mono/4.5` here!
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"runtimeTarget": {
|
||||||
|
"name": ".NETCoreApp,Version=v7.0",
|
||||||
|
"signature": ""
|
||||||
|
},
|
||||||
|
"compilationOptions": {},
|
||||||
|
"targets": {
|
||||||
|
".NETCoreApp,Version=v7.0": {
|
||||||
|
"ScriptCore/1.0.0": {
|
||||||
|
"runtime": {
|
||||||
|
"ScriptCore.dll": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"libraries": {
|
||||||
|
"ScriptCore/1.0.0": {
|
||||||
|
"type": "project",
|
||||||
|
"serviceable": false,
|
||||||
|
"sha512": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"runtimeOptions": {
|
||||||
|
"additionalProbingPaths": [
|
||||||
|
"C:\\Users\\Simon\\.dotnet\\store\\|arch|\\|tfm|",
|
||||||
|
"C:\\Users\\Simon\\.nuget\\packages",
|
||||||
|
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"runtimeOptions": {
|
||||||
|
"tfm": "net7.0",
|
||||||
|
"rollForward": "LatestMinor",
|
||||||
|
"framework": {
|
||||||
|
"name": "Microsoft.NETCore.App",
|
||||||
|
"version": "7.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,7 +31,7 @@ class AssetFile
|
|||||||
|
|
||||||
private bool _isDirectory;
|
private bool _isDirectory;
|
||||||
|
|
||||||
private Object _loadedAsset;
|
private Asset _loadedAsset;
|
||||||
|
|
||||||
public bool IsDirectory => _isDirectory;
|
public bool IsDirectory => _isDirectory;
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ class AssetFile
|
|||||||
|
|
||||||
public AssetConfig AssetConfig => _assetConfig;
|
public AssetConfig AssetConfig => _assetConfig;
|
||||||
|
|
||||||
public Object LoadedAsset => _loadedAsset;
|
public Asset LoadedAsset => _loadedAsset;
|
||||||
|
|
||||||
[AllowAppend]
|
[AllowAppend]
|
||||||
public this(EditorContentManager contentManager, StringView identifier, StringView path, bool isDirectory)
|
public this(EditorContentManager contentManager, StringView identifier, StringView path, bool isDirectory)
|
||||||
|
|||||||
@@ -34,6 +34,24 @@ public class SubAsset
|
|||||||
public Texture2D PreviewImage ~ _?.ReleaseRef();
|
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
|
class AssetHierarchy
|
||||||
{
|
{
|
||||||
FileSystemWatcher fsw ~ {
|
FileSystemWatcher fsw ~ {
|
||||||
@@ -108,7 +126,8 @@ class AssetHierarchy
|
|||||||
fsw.OnRenamed.Add(new (oldName, newName) => {
|
fsw.OnRenamed.Add(new (oldName, newName) => {
|
||||||
Log.EngineLogger.Trace($"File renamed (From \"{oldName}\" to \"{newName}\")");
|
Log.EngineLogger.Trace($"File renamed (From \"{oldName}\" to \"{newName}\")");
|
||||||
|
|
||||||
_fileSystemDirty = true;
|
//_fileSystemDirty = true;
|
||||||
|
FileRenamed(oldName, newName);
|
||||||
/*String contentFilePath = scope String();
|
/*String contentFilePath = scope String();
|
||||||
|
|
||||||
Path.InternalCombine(contentFilePath, ContentDirectory, oldName);
|
Path.InternalCombine(contentFilePath, ContentDirectory, oldName);
|
||||||
@@ -121,7 +140,7 @@ class AssetHierarchy
|
|||||||
fsw.StartRaisingEvents();
|
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.
|
/// @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.
|
/// @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)
|
public Result<TreeNode<AssetNode>> GetNodeFromPath(StringView filePath)
|
||||||
@@ -161,6 +180,7 @@ class AssetHierarchy
|
|||||||
_assetHierarchy = new TreeNode<AssetNode>(new AssetNode());
|
_assetHierarchy = new TreeNode<AssetNode>(new AssetNode());
|
||||||
_assetHierarchy->Path = new String(ContentDirectory);
|
_assetHierarchy->Path = new String(ContentDirectory);
|
||||||
_assetHierarchy->Name = new String("Content");
|
_assetHierarchy->Name = new String("Content");
|
||||||
|
_assetHierarchy->IsDirectory = true;
|
||||||
|
|
||||||
Log.EngineLogger.Trace($"Created directory node for: \"{_assetHierarchy->Path}\"");
|
Log.EngineLogger.Trace($"Created directory node for: \"{_assetHierarchy->Path}\"");
|
||||||
|
|
||||||
@@ -171,6 +191,7 @@ class AssetHierarchy
|
|||||||
{
|
{
|
||||||
String identifier = scope .(node.Path.Length);
|
String identifier = scope .(node.Path.Length);
|
||||||
Path.GetRelativePath(node.Path, _contentDirectory, identifier);
|
Path.GetRelativePath(node.Path, _contentDirectory, identifier);
|
||||||
|
AssetIdentifier.Fixup(identifier);
|
||||||
|
|
||||||
node.AssetFile = new AssetFile(_contentManager, identifier, node.Path, node.IsDirectory);
|
node.AssetFile = new AssetFile(_contentManager, identifier, node.Path, node.IsDirectory);
|
||||||
}
|
}
|
||||||
@@ -333,11 +354,73 @@ class AssetHierarchy
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
OnFileContentChanged(node.Value);
|
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 delegate void FileContentChangedFunc(AssetNode node);
|
||||||
|
|
||||||
public Event<FileContentChangedFunc> OnFileContentChanged ~ _.Dispose();
|
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);
|
Effect effect = new Effect(file, assetIdentifier, contentManager);
|
||||||
|
|
||||||
return effect;
|
return effect;
|
||||||
|
}
|
||||||
|
|
||||||
/*StreamReader reader = scope .(file);
|
public Asset GetPlaceholderAsset(Type assetType)
|
||||||
|
{
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
String text = scope .();
|
public Asset GetErrorAsset(Type assetType)
|
||||||
|
{
|
||||||
reader.ReadToEnd(text);
|
return default;
|
||||||
|
|
||||||
MaterialFile materialFile = scope .();
|
|
||||||
|
|
||||||
var result = Bon.Deserialize<MaterialFile>(ref materialFile, text);
|
|
||||||
|
|
||||||
if (result case .Err)
|
|
||||||
{
|
|
||||||
Log.EngineLogger.Error("Failed to load material.");
|
|
||||||
return null;
|
|
||||||
// TODO: return error material
|
|
||||||
}
|
|
||||||
|
|
||||||
Effect fx = new Effect(materialFile.Effect);
|
|
||||||
|
|
||||||
Material material = new Material(fx);
|
|
||||||
|
|
||||||
for (let (slotName, textureIdentifier) in materialFile.Textures)
|
|
||||||
{
|
|
||||||
Texture texture = contentManager.LoadAsset(textureIdentifier) as Texture;
|
|
||||||
|
|
||||||
if (texture == null)
|
|
||||||
{
|
|
||||||
Log.EngineLogger.Error("Failed to load texture.");
|
|
||||||
// TODO: LoadAsset should return an error texture.
|
|
||||||
}
|
|
||||||
|
|
||||||
material.SetTexture(slotName, texture);
|
|
||||||
}
|
|
||||||
|
|
||||||
fx.ReleaseRef();
|
|
||||||
|
|
||||||
/*for (let (slotName, textureIdentifier) in materialFile.Variables)
|
|
||||||
{
|
|
||||||
if (texture == null)
|
|
||||||
{
|
|
||||||
Log.EngineLogger.Error("Failed to load texture.");
|
|
||||||
// TODO: LoadAsset should return an error texture.
|
|
||||||
}
|
|
||||||
|
|
||||||
material.SetVariable(slotName, );
|
|
||||||
}*/
|
|
||||||
|
|
||||||
return material; //ModelLoader.LoadMesh(file, subAsset.Value, 0);*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,748 @@
|
|||||||
|
using System.IO;
|
||||||
|
using System;
|
||||||
|
using GlitchyEngine;
|
||||||
|
using System.Collections;
|
||||||
|
|
||||||
|
namespace GlitchyEditor.Assets.Importers;
|
||||||
|
|
||||||
|
// Based on https://github.com/Diron-P/DDSReader/blob/main/dds_loader.h
|
||||||
|
|
||||||
|
public struct LoadedSurface
|
||||||
|
{
|
||||||
|
public Span<uint8> Data;
|
||||||
|
public uint32 Pitch;
|
||||||
|
public uint32 SlicePitch;
|
||||||
|
|
||||||
|
public int ArrayIndex;
|
||||||
|
public int CubeFace;
|
||||||
|
public int MipLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct LoadedTextureInfo
|
||||||
|
{
|
||||||
|
public enum Dimension
|
||||||
|
{
|
||||||
|
Unknown,
|
||||||
|
Texture1D,
|
||||||
|
Texture2D,
|
||||||
|
Texture3D
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint8[] PixelData = null;
|
||||||
|
public DirectX.DXGI.Format PixelFormat = .Unknown;
|
||||||
|
public int MipMapCount = 0;
|
||||||
|
public int ArraySize = 0;
|
||||||
|
public Dimension Dimension = .Unknown;
|
||||||
|
public bool IsCubeMap;
|
||||||
|
|
||||||
|
public int Width;
|
||||||
|
public int Height;
|
||||||
|
public int Depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class DdsImporter
|
||||||
|
{
|
||||||
|
private const uint32 MagicWord = 0x20534444; // 'DDS
|
||||||
|
|
||||||
|
public enum LoadError
|
||||||
|
{
|
||||||
|
Unknown,
|
||||||
|
WrongMagicWord,
|
||||||
|
StreamReadFailed,
|
||||||
|
InvalidArraySize,
|
||||||
|
WrongDimensions,
|
||||||
|
IncompleteCubemap
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum HeaderFlags : uint32
|
||||||
|
{
|
||||||
|
/// Required in every .dds file.
|
||||||
|
DDSD_CAPS = 0x1,
|
||||||
|
/// Required in every .dds file.
|
||||||
|
DDSD_HEIGHT = 0x2,
|
||||||
|
/// Required in every .dds file.
|
||||||
|
DDSD_WIDTH = 0x4,
|
||||||
|
/// Required in every .dds file.
|
||||||
|
DDSD_PITCH = 0x8,
|
||||||
|
/// Required in every .dds file.
|
||||||
|
DDSD_PIXELFORMAT = 0x1000,
|
||||||
|
/// Required in a mipmapped texture.
|
||||||
|
DDSD_MIPMAPCOUNT = 0x20000,
|
||||||
|
/// Required when pitch is provided for a compressed texture.
|
||||||
|
DDSD_LINEARSIZE = 0x80000,
|
||||||
|
/// Required in a depth texture.
|
||||||
|
DDSD_DEPTH = 0x800000
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum Caps1 : uint32
|
||||||
|
{
|
||||||
|
/// Should be set, when the file contains multiple surfaces (e.g. Cubemaps or Mipmaps).
|
||||||
|
Complex = 0x8,
|
||||||
|
/// Should be set, if the file contains mipmaps.
|
||||||
|
MipMap = 0x400000,
|
||||||
|
/// Should always be set.
|
||||||
|
Texture = 0x1000
|
||||||
|
}
|
||||||
|
|
||||||
|
[AllowDuplicates]
|
||||||
|
private enum Caps2 : uint32
|
||||||
|
{
|
||||||
|
Cubemap = 0x200,
|
||||||
|
Cubemap_PositiveX = 0x400,
|
||||||
|
Cubemap_NegativeX = 0x800,
|
||||||
|
Cubemap_X = Cubemap_PositiveX | Cubemap_NegativeX,
|
||||||
|
Cubemap_PositiveY = 0x1000,
|
||||||
|
Cubemap_NegativeY = 0x2000,
|
||||||
|
Cubemap_Y = Cubemap_PositiveY | Cubemap_NegativeY,
|
||||||
|
Cubemap_PositiveZ = 0x4000,
|
||||||
|
Cubemap_NegativeZ = 0x8000,
|
||||||
|
Cubemap_Z = Cubemap_PositiveZ | Cubemap_NegativeZ,
|
||||||
|
/// This is the flag that should be set for Cubemaps in DX10+
|
||||||
|
Cubemap_AllFaces = Cubemap | Cubemap_X | Cubemap_Y | Cubemap_Z,
|
||||||
|
|
||||||
|
Volume = 0x200000,
|
||||||
|
}
|
||||||
|
|
||||||
|
[CRepr]
|
||||||
|
private struct DdsHeader
|
||||||
|
{
|
||||||
|
/// Size of this structure. This member must be set to 124.
|
||||||
|
private uint32 Size;
|
||||||
|
/// Flags to indicate which members contain valid data.
|
||||||
|
public HeaderFlags Flags;
|
||||||
|
/// Surface height (in pixels).
|
||||||
|
public uint32 Height;
|
||||||
|
/// Surface width (in pixels).
|
||||||
|
public uint32 Width;
|
||||||
|
public uint32 PitchOrLinearSize;
|
||||||
|
/// Depth of a volume texture (in pixels), otherwise unused.
|
||||||
|
public uint32 Depth;
|
||||||
|
/// Number of mipmap levels, otherwise unused.
|
||||||
|
public uint32 MipMapCount;
|
||||||
|
/// Unused.
|
||||||
|
private uint32[11] Reserved1;
|
||||||
|
/// The pixel format.
|
||||||
|
public DdsPixelFormat PixelFormat;
|
||||||
|
public Caps1 Caps;
|
||||||
|
public Caps2 Caps2;
|
||||||
|
/// Unused.
|
||||||
|
private uint32 dwCaps3;
|
||||||
|
/// Unused.
|
||||||
|
private uint32 dwCaps4;
|
||||||
|
/// Unused.
|
||||||
|
private uint32 dwReserved2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum SurfaceType : uint32
|
||||||
|
{
|
||||||
|
/// Texture contains alpha data; dwRGBAlphaBitMask contains valid data.
|
||||||
|
AlphaPixels = 0x1,
|
||||||
|
/// Used in some older DDS files for alpha channel only uncompressed data (dwRGBBitCount contains the alpha channel bitcount; dwABitMask contains valid data)
|
||||||
|
Alpha = 0x2,
|
||||||
|
|
||||||
|
/// Texture contains compressed RGB data; dwFourCC contains valid data.
|
||||||
|
FourCC = 0x4,
|
||||||
|
/// Texture contains uncompressed RGB data; dwRGBBitCount and the RGB masks (dwRBitMask, dwGBitMask, dwBBitMask) contain valid data.
|
||||||
|
RGB = 0x40,
|
||||||
|
|
||||||
|
RGBA = RGB | AlphaPixels,
|
||||||
|
|
||||||
|
/// Used in some older DDS files for YUV uncompressed data (dwRGBBitCount contains the YUV bit count;
|
||||||
|
/// dwRBitMask contains the Y mask, dwGBitMask contains the U mask, dwBBitMask contains the V mask)
|
||||||
|
YUV = 0x200,
|
||||||
|
|
||||||
|
/// Used in some older DDS files for single channel color uncompressed data (dwRGBBitCount contains the luminance channel bit count;
|
||||||
|
/// dwRBitMask contains the channel mask). Can be combined with DDPF_ALPHAPIXELS for a two channel DDS file.
|
||||||
|
Luminance = 0x20000
|
||||||
|
}
|
||||||
|
|
||||||
|
private static uint32 MakeFourCC(char8 c0, char8 c1, char8 c2, char8 c3)
|
||||||
|
{
|
||||||
|
return ((uint32)c3 << 24 | (uint32) c2 << 16 | (uint32) c1 << 8 | (uint32) c0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*private enum FourCC : uint32
|
||||||
|
{
|
||||||
|
DXT1 = MakeFourCC('D', 'X', 'T', '1'),
|
||||||
|
DXT2 = MakeFourCC('D', 'X', 'T', '2'),
|
||||||
|
DXT3 = MakeFourCC('D', 'X', 'T', '3'),
|
||||||
|
DXT4 = MakeFourCC('D', 'X', 'T', '4'),
|
||||||
|
DXT5 = MakeFourCC('D', 'X', 'T', '5'),
|
||||||
|
/// indicates the prescense of the DDS_HEADER_DXT10 extended header
|
||||||
|
DX10 = MakeFourCC('D', 'X', '1', '0'),
|
||||||
|
}*/
|
||||||
|
|
||||||
|
[CRepr]
|
||||||
|
private struct DdsPixelFormat
|
||||||
|
{
|
||||||
|
/// Structure size; set to 32 (bytes).
|
||||||
|
private uint32 Size;
|
||||||
|
/// Values which indicate what type of data is in the surface.
|
||||||
|
public SurfaceType SurfaceType;
|
||||||
|
public uint32 FourCC;
|
||||||
|
/// Number of bits in an RGB (possibly including alpha) format. Valid when dwFlags includes DDPF_RGB, DDPF_LUMINANCE, or DDPF_YUV.
|
||||||
|
public uint32 RGBBitCount;
|
||||||
|
/// Red (or luminance or Y) mask for reading color data. For instance, given the A8R8G8B8 format, the red mask would be 0x00ff0000.
|
||||||
|
public uint32 RBitMask;
|
||||||
|
/// Green (or U) mask for reading color data. For instance, given the A8R8G8B8 format, the green mask would be 0x0000ff00.
|
||||||
|
public uint32 GBitMask;
|
||||||
|
/// Blue (or V) mask for reading color data. For instance, given the A8R8G8B8 format, the blue mask would be 0x000000ff.
|
||||||
|
public uint32 BBitMask;
|
||||||
|
/// Alpha mask for reading alpha data. dwFlags must include DDPF_ALPHAPIXELS or DDPF_ALPHA. For instance, given the A8R8G8B8 format, the alpha mask would be 0xff000000.
|
||||||
|
public uint32 ABitMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ResourceDimensions : uint32
|
||||||
|
{
|
||||||
|
Texture1D = 2,
|
||||||
|
Texture2D = 3,
|
||||||
|
Texture3D = 4
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum MiscFlags : uint32
|
||||||
|
{
|
||||||
|
TextureCube = 0x4,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum AlphaMode : uint32
|
||||||
|
{
|
||||||
|
Unknown = 0x0,
|
||||||
|
Straight = 0x1,
|
||||||
|
Premultiplied = 0x2,
|
||||||
|
Opaque = 0x3,
|
||||||
|
/// Any alpha channel content is being used as a 4th channel and is not intended to represent transparency (straight or premultiplied).
|
||||||
|
Custom = 0x4
|
||||||
|
}
|
||||||
|
|
||||||
|
/// DDS header extension to handle resource arrays, DXGI pixel formats that don't map to the legacy Microsoft DirectDraw pixel format structures, and additional metadata.
|
||||||
|
[CRepr]
|
||||||
|
private struct DdsDxt10Header
|
||||||
|
{
|
||||||
|
public DirectX.DXGI.Format PixelFormat;
|
||||||
|
public ResourceDimensions ResourceDimension;
|
||||||
|
public MiscFlags MiscFlags;
|
||||||
|
/// Number of elements in the array. For a 2D cubemap this is the number of cubes, so the file contains ArraySize * 6 2D textures.
|
||||||
|
/// For a 3D Texture this must be 1.
|
||||||
|
public uint32 ArraySize;
|
||||||
|
|
||||||
|
public AlphaMode AlphaMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Result<void, LoadError> DecodeHeader(Stream data, out DdsHeader header, out DdsDxt10Header? extendedHeader)
|
||||||
|
{
|
||||||
|
header = ?;
|
||||||
|
extendedHeader = null;
|
||||||
|
|
||||||
|
// Check the magic word
|
||||||
|
Result<uint32> magicWord = data.Read<uint32>();
|
||||||
|
|
||||||
|
if (magicWord case .Err)
|
||||||
|
return .Err(.StreamReadFailed);
|
||||||
|
|
||||||
|
if (magicWord != MagicWord)
|
||||||
|
return .Err(.WrongMagicWord);
|
||||||
|
|
||||||
|
// Load the header
|
||||||
|
Result<DdsHeader> headerResult = data.Read<DdsHeader>();
|
||||||
|
|
||||||
|
if (headerResult case .Err)
|
||||||
|
return .Err(.StreamReadFailed);
|
||||||
|
|
||||||
|
header = headerResult;
|
||||||
|
|
||||||
|
// If available, load the extended header
|
||||||
|
if (header.PixelFormat.SurfaceType.HasFlag(.FourCC) && header.PixelFormat.FourCC == MakeFourCC('D', 'X', '1', '0'))
|
||||||
|
{
|
||||||
|
Result<DdsDxt10Header> extendedHeaderResult = data.Read<DdsDxt10Header>();
|
||||||
|
|
||||||
|
if (headerResult case .Err)
|
||||||
|
return .Err(.StreamReadFailed);
|
||||||
|
|
||||||
|
extendedHeader = extendedHeaderResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
return .Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsBitMask(DdsPixelFormat ddspf, uint32 rBitMask, uint32 gBitMask, uint32 bBitMask, uint32 aBitMask)
|
||||||
|
{
|
||||||
|
return ddspf.RBitMask == rBitMask && ddspf.GBitMask == gBitMask && ddspf.BBitMask == bBitMask && ddspf.ABitMask == aBitMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DirectX.DXGI.Format GetFormat(in DdsHeader header, in DdsDxt10Header? extendedheader, bool isSrgb)
|
||||||
|
{
|
||||||
|
if (extendedheader != null)
|
||||||
|
return extendedheader.Value.PixelFormat;
|
||||||
|
|
||||||
|
DdsPixelFormat pixelFormat = header.PixelFormat;
|
||||||
|
|
||||||
|
// Currently supports only basic dxgi formats.
|
||||||
|
//if (pixelFormat.SurfaceType.HasFlag(.RGBA))
|
||||||
|
if (pixelFormat.SurfaceType.HasFlag(.RGB))
|
||||||
|
{
|
||||||
|
switch (pixelFormat.RGBBitCount)
|
||||||
|
{
|
||||||
|
case 32:
|
||||||
|
if (IsBitMask(pixelFormat, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000))
|
||||||
|
return isSrgb ? .R8G8B8A8_UNorm_SRGB : .R8G8B8A8_UNorm;
|
||||||
|
|
||||||
|
if (IsBitMask(pixelFormat, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000))
|
||||||
|
return isSrgb ? .B8G8R8A8_UNorm_SRGB : .B8G8R8A8_UNorm;
|
||||||
|
|
||||||
|
if (IsBitMask(pixelFormat, 0x00FF0000, 0x0000FF00, 0x000000FF, 0))
|
||||||
|
return isSrgb ? .B8G8R8X8_UNorm_SRGB : .B8G8R8X8_UNorm;
|
||||||
|
|
||||||
|
if (IsBitMask(pixelFormat, 0x000003FF, 0x000FFc00, 0x3FF00000, 0))
|
||||||
|
return .R10G10B10A2_UNorm;
|
||||||
|
|
||||||
|
if (IsBitMask(pixelFormat, 0x3FF00000, 0x000FFc00, 0x000003FF, 0))
|
||||||
|
return .R10G10B10A2_UNorm;
|
||||||
|
|
||||||
|
if (IsBitMask(pixelFormat, 0x0000FFFF, 0xFFFF0000, 0, 0))
|
||||||
|
return .R16G16_UNorm;
|
||||||
|
|
||||||
|
if (IsBitMask(pixelFormat, 0xFFFFFFFF, 0, 0, 0))
|
||||||
|
return .R32_Float;
|
||||||
|
|
||||||
|
case 24:
|
||||||
|
// NO 24 bit formats
|
||||||
|
return .Unknown;
|
||||||
|
|
||||||
|
case 16:
|
||||||
|
if (IsBitMask(pixelFormat, 0x7C00, 0x03E0, 0x001F, 0x8000))
|
||||||
|
return .B5G5R5A1_UNorm;
|
||||||
|
|
||||||
|
if (IsBitMask(pixelFormat, 0xF800, 0x07E0, 0x001F, 0))
|
||||||
|
return .B5G6R5_UNorm;
|
||||||
|
|
||||||
|
if (IsBitMask(pixelFormat, 0x0F00, 0x00F0, 0x000F, 0xF000))
|
||||||
|
return .B4G4R4A4_UNORM;
|
||||||
|
|
||||||
|
if (IsBitMask(pixelFormat, 0x00FF, 0, 0, 0xFF00))
|
||||||
|
return .R8G8_UNorm;
|
||||||
|
|
||||||
|
if (IsBitMask(pixelFormat, 0xFFFF, 0, 0, 0))
|
||||||
|
return .R16_UNorm;
|
||||||
|
|
||||||
|
case 8:
|
||||||
|
if (IsBitMask(pixelFormat, 0xFF, 0, 0, 0))
|
||||||
|
return .R8_UNorm;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return .Unknown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (pixelFormat.SurfaceType.HasFlag(.Luminance))
|
||||||
|
{
|
||||||
|
switch (pixelFormat.RGBBitCount)
|
||||||
|
{
|
||||||
|
case 16:
|
||||||
|
if (IsBitMask(pixelFormat, 0xFFFF, 0, 0, 0))
|
||||||
|
return .R16_UNorm;
|
||||||
|
|
||||||
|
if (IsBitMask(pixelFormat, 0x00FF, 0, 0, 0xFF00))
|
||||||
|
return .R8G8_UNorm;
|
||||||
|
|
||||||
|
case 8:
|
||||||
|
if (IsBitMask(pixelFormat, 0xFF, 0, 0, 0))
|
||||||
|
return .R8_UNorm;
|
||||||
|
|
||||||
|
if (IsBitMask(pixelFormat, 0x00FF, 0, 0, 0xFF00))
|
||||||
|
return .R8G8_UNorm; // Some DDS writers assume the bitcount should be 8 instead of 16
|
||||||
|
|
||||||
|
default:
|
||||||
|
return .Unknown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (pixelFormat.SurfaceType.HasFlag(.Luminance))
|
||||||
|
{
|
||||||
|
if (pixelFormat.RGBBitCount == 8)
|
||||||
|
{
|
||||||
|
return .A8_UNorm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (pixelFormat.SurfaceType.HasFlag(.FourCC))
|
||||||
|
{
|
||||||
|
switch (pixelFormat.FourCC)
|
||||||
|
{
|
||||||
|
case MakeFourCC('D', 'X', 'T', '1'):
|
||||||
|
return isSrgb ? .BC1_UNorm_SRGB : .BC1_UNorm;
|
||||||
|
case MakeFourCC('D', 'X', 'T', '3'):
|
||||||
|
return isSrgb ? .BC2_UNorm_SRGB : .BC2_UNorm;
|
||||||
|
case MakeFourCC('D', 'X', 'T', '5'):
|
||||||
|
return isSrgb ? .BC3_UNorm_SRGB : .BC3_UNorm;
|
||||||
|
|
||||||
|
// Legacy compression formats.
|
||||||
|
case MakeFourCC('D', 'X', 'T', '2'):
|
||||||
|
return isSrgb ? .BC2_UNorm_SRGB : .BC2_UNorm;
|
||||||
|
case MakeFourCC('D', 'X', 'T', '4'):
|
||||||
|
return isSrgb ? .BC3_UNorm_SRGB : .BC3_UNorm;
|
||||||
|
|
||||||
|
case MakeFourCC('B', 'C', '4', 'U'), MakeFourCC('A', 'T', 'I', '1'):
|
||||||
|
return .BC4_UNorm;
|
||||||
|
case MakeFourCC('B', 'C', '4', 'S'):
|
||||||
|
return .BC4_SNorm;
|
||||||
|
case MakeFourCC('B', 'C', '5', 'U'), MakeFourCC('A', 'T', 'I', '2'):
|
||||||
|
return .BC5_UNorm;
|
||||||
|
case MakeFourCC('B', 'C', '5', 'S'):
|
||||||
|
return .BC5_SNorm;
|
||||||
|
|
||||||
|
case MakeFourCC('R', 'G', 'B', 'G'):
|
||||||
|
return .R8G8_B8G8_UNorm;
|
||||||
|
case MakeFourCC('G', 'R', 'G', 'B'):
|
||||||
|
return .G8R8_G8B8_UNorm;
|
||||||
|
|
||||||
|
case MakeFourCC('Y', 'U', 'Y', '2'):
|
||||||
|
return .YUY2;
|
||||||
|
|
||||||
|
case 36:
|
||||||
|
return .R16G16B16A16_UNorm;
|
||||||
|
case 111:
|
||||||
|
return .R16_Float;
|
||||||
|
case 112:
|
||||||
|
return .R16G16_Float;
|
||||||
|
case 113:
|
||||||
|
return .R16G16B16A16_Float;
|
||||||
|
case 114:
|
||||||
|
return .R32_Float;
|
||||||
|
case 115:
|
||||||
|
return .R32G32_Float;
|
||||||
|
case 116:
|
||||||
|
return .R32G32B32A32_Float;
|
||||||
|
default:
|
||||||
|
return .Unknown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return .Unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void GetPitch(uint32 width, uint32 height, DirectX.DXGI.Format format, out uint32 rowBytes, out uint32 numRows, out uint64 numBytes)
|
||||||
|
{
|
||||||
|
rowBytes = 0;
|
||||||
|
numRows = 0;
|
||||||
|
numBytes = 0;
|
||||||
|
|
||||||
|
bool bc = false;
|
||||||
|
bool packed = false;
|
||||||
|
bool planar = false;
|
||||||
|
uint32 bpe = 0;
|
||||||
|
|
||||||
|
switch (format)
|
||||||
|
{
|
||||||
|
case .BC1_Typeless, .BC1_UNorm, .BC1_UNorm_SRGB,
|
||||||
|
.BC4_Typeless, .BC4_UNorm, .BC4_SNorm:
|
||||||
|
bc = true;
|
||||||
|
bpe = 8;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case .BC2_Typeless, .BC2_UNorm, .BC2_UNorm_SRGB,
|
||||||
|
.BC3_Typeless, .BC3_UNorm, .BC3_UNorm_SRGB,
|
||||||
|
.BC5_Typeless, .BC5_UNorm, .BC5_SNorm,
|
||||||
|
.BC6H_Typeless, .BC6H_UF16, .BC6H_SF16,
|
||||||
|
.BC7_Typeless, .BC7_UNorm, .BC7_UNorm_SRGB:
|
||||||
|
bc = true;
|
||||||
|
bpe = 16;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case .R8G8_B8G8_UNorm, .G8R8_G8B8_UNorm, .YUY2:
|
||||||
|
packed = true;
|
||||||
|
bpe = 4;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case .Y210, .Y216:
|
||||||
|
packed = true;
|
||||||
|
bpe = 8;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case .NV12, .P208, .OPAQUE_420:
|
||||||
|
planar = true;
|
||||||
|
bpe = 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case .P010, .P016:
|
||||||
|
planar = true;
|
||||||
|
bpe = 4;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/*
|
||||||
|
case .D16_UNORM_S8_UINT:
|
||||||
|
case .R16_UNORM_X8_TYPELESS:
|
||||||
|
case .X16_TYPELESS_G8_UINT:
|
||||||
|
planar = true;
|
||||||
|
bpe = 4;
|
||||||
|
break;
|
||||||
|
*/
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bc)
|
||||||
|
{
|
||||||
|
uint32 numBlocksWide = 0;
|
||||||
|
if (width > 0)
|
||||||
|
{
|
||||||
|
numBlocksWide = Math.Max(1, (width + 3u) / 4u);
|
||||||
|
}
|
||||||
|
uint32 numBlocksHigh = 0;
|
||||||
|
if (height > 0)
|
||||||
|
{
|
||||||
|
numBlocksHigh = Math.Max(1, (height + 3u) / 4u);
|
||||||
|
}
|
||||||
|
rowBytes = numBlocksWide * bpe;
|
||||||
|
numRows = numBlocksHigh;
|
||||||
|
numBytes = rowBytes * numBlocksHigh;
|
||||||
|
}
|
||||||
|
else if (packed)
|
||||||
|
{
|
||||||
|
rowBytes = (((uint32)width + 1u) >> 1) * bpe;
|
||||||
|
numRows = height;
|
||||||
|
numBytes = rowBytes * height;
|
||||||
|
}
|
||||||
|
else if (format == .NV11)
|
||||||
|
{
|
||||||
|
rowBytes = ((width + 3u) >> 2) * 4u;
|
||||||
|
numRows = height * 2u; // Direct3D makes this simplifying assumption, although it is larger than the 4:1:1 data
|
||||||
|
numBytes = rowBytes * numRows;
|
||||||
|
}
|
||||||
|
else if (planar)
|
||||||
|
{
|
||||||
|
rowBytes = ((width + 1u) >> 1) * bpe;
|
||||||
|
numBytes = (rowBytes * height) + ((rowBytes * height + 1u) >> 1);
|
||||||
|
numRows = height + ((height + 1u) >> 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint32 bpp = format.BitsPerPixel();// BitsPerPixel(format);
|
||||||
|
if (bpp == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
rowBytes = (width * bpp + 7u) / 8u; // round up to nearest byte
|
||||||
|
numRows = height;
|
||||||
|
numBytes = rowBytes * height;
|
||||||
|
}
|
||||||
|
|
||||||
|
//#if defined(_M_IX86) || defined(_M_ARM) || defined(_M_HYBRID_X86_ARM64)
|
||||||
|
/*static_assert(sizeof(size_t) == 4, "Not a 32-bit platform!");
|
||||||
|
if (numBytes > UINT32_MAX || rowBytes > UINT32_MAX || numRows > UINT32_MAX)
|
||||||
|
return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);*/
|
||||||
|
/*#else
|
||||||
|
static_assert(sizeof(size_t) == 8, "Not a 64-bit platform!");
|
||||||
|
#endif*/
|
||||||
|
|
||||||
|
/*if (outNumBytes)
|
||||||
|
{
|
||||||
|
*outNumBytes = static_cast<size_t>(numBytes);
|
||||||
|
}
|
||||||
|
if (outRowBytes)
|
||||||
|
{
|
||||||
|
*outRowBytes = static_cast<size_t>(rowBytes);
|
||||||
|
}
|
||||||
|
if (outNumRows)
|
||||||
|
{
|
||||||
|
*outNumRows = static_cast<size_t>(numRows);
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Result<void, LoadError> LoadDds(Stream data, bool isSrgb, List<LoadedSurface> surfaces, out LoadedTextureInfo textureInfo)
|
||||||
|
{
|
||||||
|
// TODO: Care about alpha mode
|
||||||
|
|
||||||
|
textureInfo = .();
|
||||||
|
|
||||||
|
var headerResult = DecodeHeader(data, let header, let extendedHeader);
|
||||||
|
|
||||||
|
if (headerResult case .Err)
|
||||||
|
return headerResult;
|
||||||
|
|
||||||
|
int surfaceCount = 1;
|
||||||
|
|
||||||
|
if (header.Flags.HasFlag(.DDSD_MIPMAPCOUNT) || header.MipMapCount != 0)
|
||||||
|
{
|
||||||
|
if (header.MipMapCount == 0)
|
||||||
|
Log.EngineLogger.Warning("Mipmap count is zero, even though the flags say it shouldn't.");
|
||||||
|
|
||||||
|
if (!header.Flags.HasFlag(.DDSD_MIPMAPCOUNT))
|
||||||
|
Log.EngineLogger.Warning("Mipmap count is not zero, even though the mipmap count flag isn't set.");
|
||||||
|
|
||||||
|
textureInfo.MipMapCount = header.MipMapCount;
|
||||||
|
surfaceCount *= textureInfo.MipMapCount;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
textureInfo.MipMapCount = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extendedHeader != null)
|
||||||
|
{
|
||||||
|
textureInfo.ArraySize = extendedHeader.Value.ArraySize;
|
||||||
|
surfaceCount *= textureInfo.ArraySize;
|
||||||
|
|
||||||
|
if (textureInfo.ArraySize == 0)
|
||||||
|
return .Err(.InvalidArraySize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
textureInfo.ArraySize = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header.Caps2.HasFlag(.Cubemap))
|
||||||
|
{
|
||||||
|
if (!header.Caps2.HasFlag(.Cubemap_AllFaces))
|
||||||
|
Log.EngineLogger.Warning("Texture might only contains partial cubemap, this is not allowed. (Defined Cubemap-Flag, but not all cubemap faces)");
|
||||||
|
|
||||||
|
surfaceCount *= 6;
|
||||||
|
textureInfo.IsCubeMap = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
textureInfo.PixelFormat = GetFormat(header, extendedHeader, isSrgb);
|
||||||
|
|
||||||
|
textureInfo.Width = header.Width;
|
||||||
|
textureInfo.Height = header.Height;
|
||||||
|
textureInfo.Depth = header.Depth;
|
||||||
|
|
||||||
|
switch (extendedHeader?.ResourceDimension)
|
||||||
|
{
|
||||||
|
case .Texture1D:
|
||||||
|
textureInfo.Dimension = .Texture1D;
|
||||||
|
|
||||||
|
if (header.Flags.HasFlag(.DDSD_HEIGHT) && header.Height != 1)
|
||||||
|
return .Err(.WrongDimensions);
|
||||||
|
|
||||||
|
textureInfo.Height = 1;
|
||||||
|
textureInfo.Depth = 1;
|
||||||
|
|
||||||
|
case .Texture2D:
|
||||||
|
textureInfo.Dimension = .Texture2D;
|
||||||
|
|
||||||
|
textureInfo.Depth = 1;
|
||||||
|
|
||||||
|
case .Texture3D:
|
||||||
|
textureInfo.Dimension = .Texture3D;
|
||||||
|
case null:
|
||||||
|
if (header.Flags.HasFlag(.DDSD_DEPTH))
|
||||||
|
textureInfo.Dimension = .Texture3D;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
textureInfo.Dimension = .Texture2D;
|
||||||
|
textureInfo.Depth = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we have enough space in the list (avoid allocations later)
|
||||||
|
surfaces.Reserve(surfaceCount);
|
||||||
|
|
||||||
|
uint32 scanLineSize = 0;
|
||||||
|
uint32 slicePitch = 0;
|
||||||
|
uint64 numBytes = 0;
|
||||||
|
uint32 blockSize = 0; // Block size in bytes.
|
||||||
|
|
||||||
|
switch (textureInfo.PixelFormat)
|
||||||
|
{
|
||||||
|
case .BC1_UNorm, .BC1_UNorm_SRGB, .BC1_Typeless,
|
||||||
|
.BC4_UNorm, .BC4_SNorm, .BC4_Typeless:
|
||||||
|
blockSize = 8;
|
||||||
|
case .BC2_UNorm, .BC2_UNorm_SRGB, .BC2_Typeless,
|
||||||
|
.BC3_UNorm, .BC3_UNorm_SRGB, .BC3_Typeless,
|
||||||
|
.BC5_UNorm, .BC5_SNorm, .BC5_Typeless,
|
||||||
|
.BC7_UNorm, .BC7_UNorm_SRGB, .BC7_Typeless:
|
||||||
|
blockSize = 16;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 width = 0;
|
||||||
|
uint32 height = 0;
|
||||||
|
uint32 depth = 0;
|
||||||
|
|
||||||
|
uint32 index = 0;
|
||||||
|
|
||||||
|
uint offset = 0;
|
||||||
|
|
||||||
|
for (uint32 arrayIndex = 0; arrayIndex < textureInfo.ArraySize; arrayIndex++)
|
||||||
|
{
|
||||||
|
for (uint32 cubeFace = 0; cubeFace < (textureInfo.IsCubeMap ? 6 : 1); cubeFace++)
|
||||||
|
{
|
||||||
|
width = header.Width;
|
||||||
|
height = header.Height;
|
||||||
|
depth = header.Depth;
|
||||||
|
|
||||||
|
for (uint32 mipLevel = 0; mipLevel < textureInfo.MipMapCount; ++mipLevel)
|
||||||
|
{
|
||||||
|
/*// This will recalculate te pitch of the main image as well.
|
||||||
|
if (header.Flags.HasFlag(.DDSD_LINEARSIZE))
|
||||||
|
{
|
||||||
|
// compressed textures
|
||||||
|
scanLineSize = Math.Max(1, ((width + 3u) / 4u)) * blockSize;
|
||||||
|
uint32 numScanLines = Math.Max(1, ((height + 3u) / 4u));
|
||||||
|
numBytes = scanLineSize * numScanLines;
|
||||||
|
}
|
||||||
|
else if (header.Flags.HasFlag(.DDSD_PITCH))
|
||||||
|
{
|
||||||
|
// uncompressed data
|
||||||
|
scanLineSize = (width * header.PixelFormat.RGBBitCount + 7u) / 8u;
|
||||||
|
numBytes = scanLineSize * height;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
scanLineSize = header.PitchOrLinearSize;
|
||||||
|
numBytes = scanLineSize * height;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
GetPitch(width, height, textureInfo.PixelFormat, out scanLineSize, let numRows, out numBytes);
|
||||||
|
|
||||||
|
|
||||||
|
LoadedSurface surface = .();
|
||||||
|
// We don't know how large data-array is, so we don't have one yet.
|
||||||
|
// Only save the offset, we will adjust the pointer later.
|
||||||
|
surface.Data = Span<uint8>((uint8*)(void*)offset, (int)numBytes);
|
||||||
|
surface.Pitch = scanLineSize;
|
||||||
|
//surface.SlicePitch = slicePitch;
|
||||||
|
surface.SlicePitch = scanLineSize * numRows;
|
||||||
|
|
||||||
|
surface.ArrayIndex = arrayIndex;
|
||||||
|
surface.CubeFace = cubeFace;
|
||||||
|
surface.MipLevel = mipLevel;
|
||||||
|
|
||||||
|
surfaces.Add(surface);
|
||||||
|
|
||||||
|
++index;
|
||||||
|
|
||||||
|
width >>= 1;
|
||||||
|
height >>= 1;
|
||||||
|
depth >>= 1;
|
||||||
|
|
||||||
|
if (width == 0)
|
||||||
|
{
|
||||||
|
width = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (height == 0)
|
||||||
|
{
|
||||||
|
height = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += numBytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
textureInfo.PixelData = new uint8[offset];
|
||||||
|
|
||||||
|
Result<int> pixelDataResult = data.TryRead(textureInfo.PixelData);
|
||||||
|
|
||||||
|
if (pixelDataResult case .Err)
|
||||||
|
{
|
||||||
|
delete textureInfo.PixelData;
|
||||||
|
return .Err(.StreamReadFailed);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ref LoadedSurface surface in ref surfaces)
|
||||||
|
{
|
||||||
|
// Data pointer so far only has the offset inside the array.
|
||||||
|
// Move the pointer, so that it is inside the array.
|
||||||
|
surface.Data.Ptr += (uint)(void*)textureInfo.PixelData.Ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return .Ok;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,7 +29,7 @@ class MaterialAssetPropertiesEditor : AssetPropertiesEditor
|
|||||||
|
|
||||||
mixin DropAssetTarget<T>() where T : Asset
|
mixin DropAssetTarget<T>() where T : Asset
|
||||||
{
|
{
|
||||||
Asset asset = null;
|
AssetHandle handle = .Invalid;
|
||||||
|
|
||||||
if (ImGui.BeginDragDropTarget())
|
if (ImGui.BeginDragDropTarget())
|
||||||
{
|
{
|
||||||
@@ -39,13 +39,13 @@ class MaterialAssetPropertiesEditor : AssetPropertiesEditor
|
|||||||
{
|
{
|
||||||
StringView fullpath = .((char8*)payload.Data, (int)payload.DataSize);
|
StringView fullpath = .((char8*)payload.Data, (int)payload.DataSize);
|
||||||
|
|
||||||
asset = Content.LoadAsset<Asset>(fullpath);
|
handle = Content.LoadAsset(fullpath);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.EndDragDropTarget();
|
ImGui.EndDragDropTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
asset
|
handle
|
||||||
}
|
}
|
||||||
|
|
||||||
public this(AssetFile asset) : base(asset)
|
public this(AssetFile asset) : base(asset)
|
||||||
@@ -84,11 +84,10 @@ class MaterialAssetPropertiesEditor : AssetPropertiesEditor
|
|||||||
{
|
{
|
||||||
StringView path = .((char8*)payload.Data, (int)payload.DataSize);
|
StringView path = .((char8*)payload.Data, (int)payload.DataSize);
|
||||||
|
|
||||||
using (Texture2D newTexture = Content.LoadAsset<Texture2D>(path))//new Texture2D(path, true))
|
AssetHandle<Texture2D> newTexture = Content.LoadAsset(path);
|
||||||
{
|
|
||||||
newTexture.SamplerState = SamplerStateManager.AnisotropicWrap;
|
//newTexture.Get().SamplerState = SamplerStateManager.AnisotropicWrap;
|
||||||
material.SetTexture(texture.key, newTexture);
|
material.SetTexture(texture.key, newTexture.Cast<Texture>());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.EndDragDropTarget();
|
ImGui.EndDragDropTarget();
|
||||||
@@ -98,10 +97,10 @@ class MaterialAssetPropertiesEditor : AssetPropertiesEditor
|
|||||||
|
|
||||||
private void ShowVariables(Material material, Effect effect)
|
private void ShowVariables(Material material, Effect effect)
|
||||||
{
|
{
|
||||||
|
|
||||||
for (let (name, arguments) in effect.[Friend]_variableDescriptions)
|
for (let (name, arguments) in effect.[Friend]_variableDescriptions)
|
||||||
{
|
{
|
||||||
let variable = effect.Variables[name];
|
if (!effect.Variables.TryGetVariable(name, let variable))
|
||||||
|
continue;
|
||||||
|
|
||||||
bool hasPreviewName = TryGetValue(arguments, "Preview", var previewName);
|
bool hasPreviewName = TryGetValue(arguments, "Preview", var previewName);
|
||||||
|
|
||||||
@@ -109,35 +108,69 @@ class MaterialAssetPropertiesEditor : AssetPropertiesEditor
|
|||||||
|
|
||||||
bool hasPreviewType = TryGetValue(arguments, "Type", var previewType);
|
bool hasPreviewType = TryGetValue(arguments, "Type", var previewType);
|
||||||
|
|
||||||
if (hasPreviewType && previewType.Get<String>() == "Color")
|
if (hasPreviewType && (previewType.Get<String>() == "Color" || previewType.Get<String>() == "ColorHDR"))
|
||||||
{
|
{
|
||||||
Log.EngineLogger.AssertDebug(variable.Type == .Float && variable.Rows == 1);
|
if (previewType.Get<String>().Equals("Color", .InvariantCultureIgnoreCase))
|
||||||
|
|
||||||
if (variable.Columns == 3)
|
|
||||||
{
|
{
|
||||||
material.GetVariable<Vector3>(variable.Name, var value);
|
Log.EngineLogger.AssertDebug(variable.Type == .Float && variable.Rows == 1);
|
||||||
|
|
||||||
value = (Vector3)ColorRGB.LinearToSRGB((ColorRGB)value);
|
if (variable.Columns == 3)
|
||||||
|
|
||||||
if (ImGui.ColorEdit3(displayName.Ptr, *(float[3]*)&value))
|
|
||||||
{
|
{
|
||||||
value = (Vector3)ColorRGB.SRgbToLinear((ColorRGB)value);
|
material.GetVariable<float3>(variable.Name, var value);
|
||||||
material.SetVariable(variable.Name, value);
|
|
||||||
|
value = (float3)ColorRGB.LinearToSRGB((ColorRGB)value);
|
||||||
|
|
||||||
|
if (ImGui.ColorEdit3(displayName.Ptr, *(float[3]*)&value))
|
||||||
|
{
|
||||||
|
value = (float3)ColorRGB.SRgbToLinear((ColorRGB)value);
|
||||||
|
material.SetVariable(variable.Name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (variable.Columns == 4)
|
||||||
|
{
|
||||||
|
material.GetVariable<float4>(variable.Name, var value);
|
||||||
|
|
||||||
|
value = (float4)ColorRGBA.LinearToSRGB((ColorRGBA)value);
|
||||||
|
|
||||||
|
if (ImGui.ColorEdit4(displayName.Ptr, *(float[4]*)&value))
|
||||||
|
{
|
||||||
|
value = (float4)ColorRGBA.SRgbToLinear((ColorRGBA)value);
|
||||||
|
material.SetVariable(variable.Name, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (variable.Columns == 4)
|
else if (previewType.Get<String>().Equals("ColorHDR", .InvariantCultureIgnoreCase))
|
||||||
{
|
{
|
||||||
material.GetVariable<Vector4>(variable.Name, var value);
|
Log.EngineLogger.AssertDebug(variable.Type == .Float && variable.Rows == 1);
|
||||||
|
|
||||||
value = (Vector4)ColorRGBA.LinearToSRGB((ColorRGBA)value);
|
|
||||||
|
|
||||||
if (ImGui.ColorEdit4(displayName.Ptr, *(float[4]*)&value))
|
if (variable.Columns == 3)
|
||||||
{
|
{
|
||||||
value = (Vector4)ColorRGBA.SRgbToLinear((ColorRGBA)value);
|
material.GetVariable<float3>(variable.Name, var value);
|
||||||
material.SetVariable(variable.Name, value);
|
|
||||||
|
value = (float3)ColorRGB.LinearToSRGB((ColorRGB)value);
|
||||||
|
|
||||||
|
if (ImGui.ColorEdit3(displayName.Ptr, *(float[3]*)&value, .HDR | .Float))
|
||||||
|
{
|
||||||
|
value = (float3)ColorRGB.SRgbToLinear((ColorRGB)value);
|
||||||
|
material.SetVariable(variable.Name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (variable.Columns == 4)
|
||||||
|
{
|
||||||
|
material.GetVariable<float4>(variable.Name, var value);
|
||||||
|
|
||||||
|
value = (float4)ColorRGBA.LinearToSRGB((ColorRGBA)value);
|
||||||
|
|
||||||
|
if (ImGui.ColorEdit4(displayName.Ptr, *(float[4]*)&value, .HDR | .Float))
|
||||||
|
{
|
||||||
|
value = (float4)ColorRGBA.SRgbToLinear((ColorRGBA)value);
|
||||||
|
material.SetVariable(variable.Name, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//ImGui.ColorEdit3("", null, .HDR | .Float)
|
||||||
|
|
||||||
else if (variable.Type == .Float && variable.Rows == 1)
|
else if (variable.Type == .Float && variable.Rows == 1)
|
||||||
{
|
{
|
||||||
bool hasMin = TryGetValue(arguments, "Min", var min);
|
bool hasMin = TryGetValue(arguments, "Min", var min);
|
||||||
@@ -156,28 +189,28 @@ class MaterialAssetPropertiesEditor : AssetPropertiesEditor
|
|||||||
if (ImGui.EditVector<1>(displayName, ref *(float[1]*)&value, .(), 0.1f, 100.0f, minV, maxV))
|
if (ImGui.EditVector<1>(displayName, ref *(float[1]*)&value, .(), 0.1f, 100.0f, minV, maxV))
|
||||||
material.SetVariable(variable.Name, value);
|
material.SetVariable(variable.Name, value);
|
||||||
case 2:
|
case 2:
|
||||||
material.GetVariable<Vector2>(variable.Name, var value);
|
material.GetVariable<float2>(variable.Name, var value);
|
||||||
|
|
||||||
Vector2 minV = hasMin ? min.Get<Vector2>() : .(float.MinValue);
|
float2 minV = hasMin ? min.Get<float2>() : (float2)float.MinValue;
|
||||||
Vector2 maxV = hasMax ? max.Get<Vector2>() : .(float.MaxValue);
|
float2 maxV = hasMax ? max.Get<float2>() : (float2)float.MaxValue;
|
||||||
|
|
||||||
if (ImGui.EditVector2(displayName, ref value, .Zero, 0.1f, 100.0f, minV, maxV))
|
if (ImGui.Editfloat2(displayName, ref value, .Zero, 0.1f, 100.0f, minV, maxV))
|
||||||
material.SetVariable(variable.Name, value);
|
material.SetVariable(variable.Name, value);
|
||||||
case 3:
|
case 3:
|
||||||
material.GetVariable<Vector3>(variable.Name, var value);
|
material.GetVariable<float3>(variable.Name, var value);
|
||||||
|
|
||||||
Vector3 minV = hasMin ? min.Get<Vector3>() : .(float.MinValue);
|
float3 minV = hasMin ? min.Get<float3>() : (float3)float.MinValue;
|
||||||
Vector3 maxV = hasMax ? max.Get<Vector3>() : .(float.MaxValue);
|
float3 maxV = hasMax ? max.Get<float3>() : (float3)float.MaxValue;
|
||||||
|
|
||||||
if (ImGui.EditVector3(displayName, ref value, .Zero, 0.1f, 100.0f, minV, maxV))
|
if (ImGui.Editfloat3(displayName, ref value, .Zero, 0.1f, 100.0f, minV, maxV))
|
||||||
material.SetVariable(variable.Name, value);
|
material.SetVariable(variable.Name, value);
|
||||||
case 4:
|
case 4:
|
||||||
material.GetVariable<Vector4>(variable.Name, var value);
|
material.GetVariable<float4>(variable.Name, var value);
|
||||||
|
|
||||||
Vector4 minV = hasMin ? min.Get<Vector4>() : .(float.MinValue);
|
float4 minV = hasMin ? min.Get<float4>() : (float4)float.MinValue;
|
||||||
Vector4 maxV = hasMax ? max.Get<Vector4>() : .(float.MaxValue);
|
float4 maxV = hasMax ? max.Get<float4>() : (float4)float.MaxValue;
|
||||||
|
|
||||||
if (ImGui.EditVector4(displayName, ref value, .Zero, 0.1f, 100.0f, minV, maxV))
|
if (ImGui.Editfloat4(displayName, ref value, .Zero, 0.1f, 100.0f, minV, maxV))
|
||||||
material.SetVariable(variable.Name, value);
|
material.SetVariable(variable.Name, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -200,14 +233,22 @@ class MaterialAssetLoaderConfig : AssetLoaderConfig
|
|||||||
[BonTarget]
|
[BonTarget]
|
||||||
public enum VariableValue
|
public enum VariableValue
|
||||||
{
|
{
|
||||||
|
case bool(bool Value);
|
||||||
|
case bool2(bool2 Value);
|
||||||
|
case bool3(bool3 Value);
|
||||||
|
case bool4(bool4 Value);
|
||||||
|
case int(int Value);
|
||||||
|
case int2(int2 Value);
|
||||||
|
case int3(int3 Value);
|
||||||
|
case int4(int4 Value);
|
||||||
|
case uint(uint Value);
|
||||||
|
case uint2(uint2 Value);
|
||||||
|
case uint3(uint3 Value);
|
||||||
|
case uint4(uint4 Value);
|
||||||
case Float(float Value);
|
case Float(float Value);
|
||||||
case Float2(Vector2 Value);
|
case Float2(float2 Value);
|
||||||
case Float3(Vector3 Value);
|
case Float3(float3 Value);
|
||||||
case Float4(Vector4 Value);
|
case Float4(float4 Value);
|
||||||
case Int(int Value);
|
|
||||||
case Int2(Int2 Value);
|
|
||||||
case Int3(Int3 Value);
|
|
||||||
case Int4(Int4 Value);
|
|
||||||
case ColorRGB(ColorRGB Value);
|
case ColorRGB(ColorRGB Value);
|
||||||
case ColorRGBA(ColorRGBA Value);
|
case ColorRGBA(ColorRGBA Value);
|
||||||
case None;
|
case None;
|
||||||
@@ -341,28 +382,24 @@ class MaterialAssetLoader : IAssetLoader, IAssetSaver //, IReloadingAssetLoader
|
|||||||
Log.EngineLogger.Error("Failed to load material.");
|
Log.EngineLogger.Error("Failed to load material.");
|
||||||
Debug.SafeBreak();
|
Debug.SafeBreak();
|
||||||
return null;
|
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);
|
Material material = new Material(fx);
|
||||||
|
|
||||||
for (let (slotName, textureIdentifier) in materialFile.Textures)
|
for (let (slotName, textureIdentifier) in materialFile.Textures)
|
||||||
{
|
{
|
||||||
using (Texture texture = contentManager.LoadAsset(textureIdentifier) as Texture)
|
|
||||||
|
AssetHandle<Texture> texture = contentManager.LoadAsset(textureIdentifier);
|
||||||
|
|
||||||
|
if (texture.IsInvalid)
|
||||||
{
|
{
|
||||||
if (texture == null)
|
Log.EngineLogger.Error($"Failed to load texture \"{textureIdentifier}\".");
|
||||||
{
|
|
||||||
Log.EngineLogger.Error($"Failed to load texture \"{textureIdentifier}\".");
|
|
||||||
// TODO: LoadAsset should return an error texture.
|
|
||||||
}
|
|
||||||
|
|
||||||
material.SetTexture(slotName, texture);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fx.ReleaseRef();
|
material.SetTexture(slotName, texture);
|
||||||
|
}
|
||||||
|
|
||||||
for (let (slotName, variableValue) in materialFile.Variables)
|
for (let (slotName, variableValue) in materialFile.Variables)
|
||||||
{
|
{
|
||||||
@@ -382,7 +419,7 @@ class MaterialAssetLoader : IAssetLoader, IAssetSaver //, IReloadingAssetLoader
|
|||||||
material.SetVariable(slotName, value);
|
material.SetVariable(slotName, value);
|
||||||
case .None:
|
case .None:
|
||||||
default:
|
default:
|
||||||
Log.EngineLogger.Error("Errorre");
|
Log.EngineLogger.Error($"Unknown variable type of variable {slotName}: {variableValue}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -407,12 +444,11 @@ class MaterialAssetLoader : IAssetLoader, IAssetSaver //, IReloadingAssetLoader
|
|||||||
materialFile.Textures = new .();
|
materialFile.Textures = new .();
|
||||||
materialFile.Variables = new .();
|
materialFile.Variables = new .();
|
||||||
|
|
||||||
//material.SetTexture();
|
for (let (slotName, texture) in material.[Friend]_textures)
|
||||||
|
|
||||||
for (let (slotName, textureViewBinding) in material.[Friend]_textures)
|
|
||||||
{
|
{
|
||||||
//materialFile.Textures.Add(slotName, textureViewBinding.)
|
Texture textureAsset = texture.Handle.Get();
|
||||||
|
|
||||||
|
materialFile.Textures.Add(new String(slotName), new String(textureAsset?.Identifier ?? ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
Effect effect = material.Effect;
|
Effect effect = material.Effect;
|
||||||
@@ -423,7 +459,6 @@ class MaterialAssetLoader : IAssetLoader, IAssetSaver //, IReloadingAssetLoader
|
|||||||
for (let (name, arguments) in effect.[Friend]_variableDescriptions)
|
for (let (name, arguments) in effect.[Friend]_variableDescriptions)
|
||||||
{
|
{
|
||||||
VariableValue variableValue = .None;
|
VariableValue variableValue = .None;
|
||||||
//Object variantValue = null;
|
|
||||||
|
|
||||||
let variable = effect.Variables[name];
|
let variable = effect.Variables[name];
|
||||||
|
|
||||||
@@ -449,7 +484,6 @@ class MaterialAssetLoader : IAssetLoader, IAssetSaver //, IReloadingAssetLoader
|
|||||||
value = ColorRGBA.LinearToSRGB((ColorRGBA)value);
|
value = ColorRGBA.LinearToSRGB((ColorRGBA)value);
|
||||||
|
|
||||||
variableValue = .ColorRGBA(value);
|
variableValue = .ColorRGBA(value);
|
||||||
//variantValue = new box value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (variable.Type == .Float && variable.Rows == 1)
|
else if (variable.Type == .Float && variable.Rows == 1)
|
||||||
@@ -460,60 +494,18 @@ class MaterialAssetLoader : IAssetLoader, IAssetSaver //, IReloadingAssetLoader
|
|||||||
material.GetVariable<float>(variable.Name, let value);
|
material.GetVariable<float>(variable.Name, let value);
|
||||||
variableValue = .Float(value);
|
variableValue = .Float(value);
|
||||||
case 2:
|
case 2:
|
||||||
material.GetVariable<Vector2>(variable.Name, let value);
|
material.GetVariable<float2>(variable.Name, let value);
|
||||||
variableValue = .Float2(value);
|
variableValue = .Float2(value);
|
||||||
case 3:
|
case 3:
|
||||||
material.GetVariable<Vector3>(variable.Name, let value);
|
material.GetVariable<float3>(variable.Name, let value);
|
||||||
variableValue = .Float3(value);
|
variableValue = .Float3(value);
|
||||||
case 4:
|
case 4:
|
||||||
material.GetVariable<Vector4>(variable.Name, let value);
|
material.GetVariable<float4>(variable.Name, let value);
|
||||||
variableValue = .Float4(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 .();
|
String text = scope .();
|
||||||
@@ -527,4 +519,17 @@ class MaterialAssetLoader : IAssetLoader, IAssetSaver //, IReloadingAssetLoader
|
|||||||
|
|
||||||
return .Ok;
|
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)
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,8 @@ using GlitchyEngine.Renderer;
|
|||||||
using GlitchyEngine.Math;
|
using GlitchyEngine.Math;
|
||||||
using DirectXTK;
|
using DirectXTK;
|
||||||
using ImGui;
|
using ImGui;
|
||||||
|
using GlitchyEditor.Assets.Importers;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace GlitchyEditor.Assets;
|
namespace GlitchyEditor.Assets;
|
||||||
|
|
||||||
@@ -164,7 +166,10 @@ class EditorTextureAssetLoaderConfig : AssetLoaderConfig
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class EditorTextureAssetLoader : IAssetLoader, IReloadingAssetLoader
|
using internal GlitchyEngine.Renderer;
|
||||||
|
using internal GlitchyEngine.Platform.DX11;
|
||||||
|
|
||||||
|
class EditorTextureAssetLoader : IAssetLoader//, IReloadingAssetLoader
|
||||||
{
|
{
|
||||||
private static readonly List<StringView> _fileExtensions = new .(){".png", ".dds"} ~ delete _; // ".jpg", ".bmp"
|
private static readonly List<StringView> _fileExtensions = new .(){".png", ".dds"} ~ delete _; // ".jpg", ".bmp"
|
||||||
|
|
||||||
@@ -230,81 +235,170 @@ class EditorTextureAssetLoader : IAssetLoader, IReloadingAssetLoader
|
|||||||
return .Unknown;
|
return .Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** \brief Loads the texture from the specified path.
|
||||||
|
* @param path The path of the texture to load.
|
||||||
|
* @param texture The reference to the pointer that will hold the texture.
|
||||||
|
* @returns true if the texture was loaded successfully; false otherwise.
|
||||||
|
*/
|
||||||
|
protected static bool LoadDdsResourcePlatform(Stream stream)
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
|
||||||
|
uint8[] ddsData = new:ScopedAlloc! uint8[stream.Length];
|
||||||
|
|
||||||
|
var result = stream.TryRead(ddsData);
|
||||||
|
|
||||||
|
if (result case .Err(let err))
|
||||||
|
{
|
||||||
|
Log.EngineLogger.Error($"Failed to read texture data from stream. Error: {err}");
|
||||||
|
}
|
||||||
|
|
||||||
|
DirectX.D3D11.ID3D11Texture2D* texture = null;
|
||||||
|
DirectX.D3D11.ID3D11ShaderResourceView* view = null;
|
||||||
|
|
||||||
|
DirectX.Common.HResult loadResult = DDSTextureLoader.CreateDDSTextureFromMemory(GlitchyEngine.Platform.DX11.NativeDevice,
|
||||||
|
ddsData.Ptr, (uint)ddsData.Count, (.)&texture, &view);
|
||||||
|
|
||||||
|
view.Release();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private static Texture LoadTexture(Stream data, EditorTextureAssetLoaderConfig config)
|
private static Texture LoadTexture(Stream data, EditorTextureAssetLoaderConfig config)
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileResourceFunction!();
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
|
||||||
|
List<LoadedSurface> surfaces = scope .();
|
||||||
|
LoadedTextureInfo textureInfo;
|
||||||
|
|
||||||
Texture texture = null;
|
// Make sure we clean up the pixel data
|
||||||
|
defer { delete textureInfo.PixelData; }
|
||||||
|
|
||||||
|
|
||||||
switch(GetTextureType(data))
|
switch(GetTextureType(data))
|
||||||
{
|
{
|
||||||
case .DDS:
|
case .DDS:
|
||||||
texture = LoadDds(data, config);
|
|
||||||
|
var v = data.Position;
|
||||||
|
|
||||||
|
//LoadDdsResourcePlatform(data);
|
||||||
|
|
||||||
|
data.Position = v;
|
||||||
|
|
||||||
|
Result<void> result = LoadDds(data, config, surfaces, out textureInfo);
|
||||||
|
|
||||||
|
if (result case .Err)
|
||||||
|
return null;
|
||||||
|
|
||||||
case .PNG:
|
case .PNG:
|
||||||
texture = LoadPng(data, config);
|
Result<void> result = LoadPng(data, config, surfaces, out textureInfo);
|
||||||
|
|
||||||
|
if (result case .Err)
|
||||||
|
return null;
|
||||||
|
|
||||||
case .Unknown:
|
case .Unknown:
|
||||||
Runtime.FatalError("Unknown image format.");
|
Log.EngineLogger.Error("Unknown texture format.");
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.EngineLogger.AssertDebug(texture != null);
|
// Make the format SRGB or non-SRGB
|
||||||
|
if (config.IsSRGB)
|
||||||
|
textureInfo.PixelFormat = textureInfo.PixelFormat.GetSRGB();
|
||||||
|
else
|
||||||
|
textureInfo.PixelFormat = textureInfo.PixelFormat.GetNonSRGB();
|
||||||
|
|
||||||
SetSampler(texture, config);
|
Texture texture = CreateTexture(surfaces, textureInfo);
|
||||||
|
|
||||||
|
if (texture != null)
|
||||||
|
{
|
||||||
|
SetSampler(texture, config);
|
||||||
|
texture.[Friend]Complete = true;
|
||||||
|
}
|
||||||
|
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ReloadAsset(AssetFile assetFile, Stream data)
|
private static Texture CreateTexture(List<LoadedSurface> surfaces, LoadedTextureInfo textureInfo)
|
||||||
{
|
{
|
||||||
Texture reloadingTexture = assetFile.LoadedAsset as Texture;
|
TextureSliceData[] slices = scope TextureSliceData[surfaces.Count];
|
||||||
|
|
||||||
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)
|
for (int i < slices.Count)
|
||||||
{
|
{
|
||||||
Log.EngineLogger.Error($"{nameof(Self)}: Config of asset \"{assetFile.FilePath}\" doesn't have the correct type!");
|
slices[i] = .(surfaces[i].Data.Ptr, surfaces[i].Pitch, surfaces[i].SlicePitch);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(GetTextureType(data))
|
//slices[0].SlicePitch = (.)(surfaces[0].Pitch * textureInfo.Height);
|
||||||
|
|
||||||
|
switch (textureInfo.Dimension)
|
||||||
{
|
{
|
||||||
case .DDS:
|
//case .Texture1D:
|
||||||
ReloadDds(reloadingTexture as Texture2D, data, config);
|
case .Texture2D:
|
||||||
case .PNG:
|
if (textureInfo.IsCubeMap)
|
||||||
ReloadPng(reloadingTexture as Texture2D, data, config);
|
{
|
||||||
case .Unknown:
|
Texture2DDesc staging = .();
|
||||||
Runtime.FatalError("Unknown image format.");
|
|
||||||
|
staging.Width = (.)textureInfo.Width;
|
||||||
|
staging.Height = (.)textureInfo.Height;
|
||||||
|
|
||||||
|
staging.MipLevels = (.)textureInfo.MipMapCount;
|
||||||
|
staging.ArraySize = (.)textureInfo.ArraySize;
|
||||||
|
|
||||||
|
staging.Format = textureInfo.PixelFormat;
|
||||||
|
|
||||||
|
// TODO: allow enabling read/write
|
||||||
|
staging.CpuAccess = .None;
|
||||||
|
staging.Usage = .Default;
|
||||||
|
|
||||||
|
TextureCube cubeTexture = new TextureCube(staging);
|
||||||
|
|
||||||
|
//cubeTexture.SetData();
|
||||||
|
|
||||||
|
for (let surface in surfaces)
|
||||||
|
{
|
||||||
|
cubeTexture.SetData(surface.Data.Ptr, surface.Pitch / staging.Width, (TextureCubeFace)surface.CubeFace, (.)surface.ArrayIndex, (.)surface.MipLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cubeTexture;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Texture2DDesc staging = .();
|
||||||
|
|
||||||
|
staging.Width = (.)textureInfo.Width;
|
||||||
|
staging.Height = (.)textureInfo.Height;
|
||||||
|
|
||||||
|
staging.MipLevels = (.)textureInfo.MipMapCount;
|
||||||
|
staging.ArraySize = (.)textureInfo.ArraySize;
|
||||||
|
|
||||||
|
staging.Format = textureInfo.PixelFormat;
|
||||||
|
|
||||||
|
// TODO: allow enabling read/write
|
||||||
|
staging.CpuAccess = .None;
|
||||||
|
staging.Usage = .Immutable;
|
||||||
|
|
||||||
|
Texture2D stagingTexture = new Texture2D(staging);
|
||||||
|
|
||||||
|
stagingTexture.SetData(slices);
|
||||||
|
|
||||||
|
/*for (let surface in surfaces)
|
||||||
|
{
|
||||||
|
stagingTexture.[Friend]PlatformSetData(surface.Data.Ptr, surface.Pitch / staging.Width, 0, 0, staging.Width, staging.Height, (.)surface.ArrayIndex, (.)surface.MipLevel, .Write);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
return stagingTexture;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
Runtime.NotImplemented();
|
||||||
}
|
}
|
||||||
|
|
||||||
SetSampler(reloadingTexture, config);
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SetSampler(Texture texture, EditorTextureAssetLoaderConfig config)
|
private static Result<void> LoadPng(Stream data, EditorTextureAssetLoaderConfig config, List<LoadedSurface> surfaces, out LoadedTextureInfo textureInfo)
|
||||||
{
|
|
||||||
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!();
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
|
||||||
|
textureInfo = .();
|
||||||
|
|
||||||
uint8[] pngData = new:ScopedAlloc! uint8[data.Length];
|
uint8[] pngData = new:ScopedAlloc! uint8[data.Length];
|
||||||
|
|
||||||
@@ -313,40 +407,188 @@ class EditorTextureAssetLoader : IAssetLoader, IReloadingAssetLoader
|
|||||||
if (result case .Err(let err))
|
if (result case .Err(let err))
|
||||||
{
|
{
|
||||||
Log.EngineLogger.Error($"Failed to read data from stream. Texture: Error: {err}");
|
Log.EngineLogger.Error($"Failed to read data from stream. Texture: Error: {err}");
|
||||||
|
return .Err;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8* rawData = null;
|
||||||
|
defer
|
||||||
|
{
|
||||||
|
if (rawData != null)
|
||||||
|
LodePng.LodePng.Free(rawData);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8* rawData = ?;
|
|
||||||
uint32 width = 0, height = 0;
|
uint32 width = 0, height = 0;
|
||||||
|
|
||||||
uint32 errorCode = LodePng.LodePng.Decode32(&rawData, &width, &height, pngData.Ptr, (.)pngData.Count);
|
{
|
||||||
|
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 .Err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Log.EngineLogger.Assert(errorCode == 0, "Failed to load png File");
|
uint8[] pixelData = new uint8[4 * width * height];
|
||||||
|
Internal.MemCpy(pixelData.Ptr, rawData, pixelData.Count);
|
||||||
|
|
||||||
// TODO: load as SRGB because PNGs are usually not stored as linear
|
LoadedSurface surface = .();
|
||||||
//Texture2DDesc desc = .(width, height, srgb? .R8G8B8A8_UNorm_SRGB : .R8G8B8A8_UNorm, 1, 1, .Immutable);
|
surface.Data = Span<uint8>(pixelData);
|
||||||
Texture2DDesc desc = .(width, height, config.IsSRGB ? .R8G8B8A8_UNorm_SRGB : .R8G8B8A8_UNorm, 1, 1, .Immutable);
|
surface.Pitch = 4 * width;
|
||||||
Texture2D texture = new Texture2D(desc);
|
surface.SlicePitch = 0;
|
||||||
texture.SetData<Color>((.)rawData);
|
surface.ArrayIndex = 0;
|
||||||
|
surface.MipLevel = 0;
|
||||||
|
|
||||||
|
surfaces.Add(surface);
|
||||||
|
|
||||||
|
//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
|
// TODO: Generate mip maps
|
||||||
|
|
||||||
LodePng.LodePng.Free(rawData);
|
textureInfo.PixelData = pixelData;
|
||||||
|
textureInfo.Width = width;
|
||||||
|
textureInfo.Height = height;
|
||||||
|
textureInfo.Depth = 1;
|
||||||
|
|
||||||
return texture;
|
textureInfo.ArraySize = 1;
|
||||||
|
textureInfo.MipMapCount = 1;
|
||||||
|
|
||||||
|
textureInfo.Dimension = .Texture2D;
|
||||||
|
|
||||||
|
textureInfo.IsCubeMap = false;
|
||||||
|
|
||||||
|
textureInfo.PixelFormat = config.IsSRGB ? .R8G8B8A8_UNorm_SRGB : .R8G8B8A8_UNorm;
|
||||||
|
|
||||||
|
return .Ok;
|
||||||
|
|
||||||
|
//return texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Result<void> LoadDds(Stream data, EditorTextureAssetLoaderConfig config, List<LoadedSurface> surfaces, out LoadedTextureInfo textureInfo)
|
||||||
|
{
|
||||||
|
var result = DdsImporter.LoadDds(data, config.IsSRGB, surfaces, out textureInfo);
|
||||||
|
|
||||||
|
if (result case .Err)
|
||||||
|
return .Err;
|
||||||
|
|
||||||
|
return .Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ReloadDds(Texture2D reloadingTexture, Stream data, EditorTextureAssetLoaderConfig config)
|
private static void SetSampler(Texture texture, EditorTextureAssetLoaderConfig config)
|
||||||
{
|
{
|
||||||
using (Texture2D newTexture = new [Friend]Texture2D(data))
|
using (SamplerState samplerState = SamplerStateManager.GetSampler(config.SamplerStateDescription))
|
||||||
{
|
{
|
||||||
reloadingTexture.[Friend]SneakySwappyTexture(newTexture);
|
texture.SamplerState = samplerState;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Texture LoadDds(Stream data, EditorTextureAssetLoaderConfig config)
|
private static Texture2D _placeholder2D;
|
||||||
{
|
private static TextureCube _placeholderCube;
|
||||||
Texture2D texture = new [Friend]Texture2D(data);
|
|
||||||
|
|
||||||
return texture;
|
private static Texture2D _error2D;
|
||||||
|
private static TextureCube _errorCube;
|
||||||
|
|
||||||
|
public Asset GetPlaceholderAsset(Type assetType)
|
||||||
|
{
|
||||||
|
switch (assetType)
|
||||||
|
{
|
||||||
|
case typeof(TextureCube):
|
||||||
|
if (_placeholderCube == null)
|
||||||
|
{
|
||||||
|
// TODO: immutable
|
||||||
|
Texture2DDesc desc = .(1, 1, .R8G8B8A8_UNorm, 1, 1, .Default, .None);
|
||||||
|
|
||||||
|
_placeholderCube = new TextureCube(desc);
|
||||||
|
_placeholderCube.SamplerState = SamplerStateManager.PointWrap;
|
||||||
|
Color color = Color.Cyan;
|
||||||
|
_placeholderCube.SetData<Color>(&color, .PositiveX);
|
||||||
|
_placeholderCube.SetData<Color>(&color, .NegativeX);
|
||||||
|
_placeholderCube.SetData<Color>(&color, .PositiveY);
|
||||||
|
_placeholderCube.SetData<Color>(&color, .NegativeY);
|
||||||
|
_placeholderCube.SetData<Color>(&color, .PositiveZ);
|
||||||
|
_placeholderCube.SetData<Color>(&color, .NegativeZ);
|
||||||
|
|
||||||
|
Content.ManageAsset(_placeholderCube);
|
||||||
|
_placeholderCube.ReleaseRef();
|
||||||
|
|
||||||
|
_placeholderCube.[Friend]Complete = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _placeholderCube;
|
||||||
|
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(TextureCube):
|
||||||
|
if (_placeholderCube == null)
|
||||||
|
{
|
||||||
|
// TODO: immutable
|
||||||
|
Texture2DDesc desc = .(2, 2, .R8G8B8A8_UNorm, 1, 1, .Default, .None);
|
||||||
|
|
||||||
|
_errorCube = new TextureCube(desc);
|
||||||
|
_errorCube.SamplerState = SamplerStateManager.PointWrap;
|
||||||
|
|
||||||
|
Color[4] color = .(Color.HotPink, Color.Black, Color.Black, Color.HotPink);
|
||||||
|
|
||||||
|
_errorCube.SetData<Color>(&color, .PositiveX);
|
||||||
|
_errorCube.SetData<Color>(&color, .NegativeX);
|
||||||
|
_errorCube.SetData<Color>(&color, .PositiveY);
|
||||||
|
_errorCube.SetData<Color>(&color, .NegativeY);
|
||||||
|
_errorCube.SetData<Color>(&color, .PositiveZ);
|
||||||
|
_errorCube.SetData<Color>(&color, .NegativeZ);
|
||||||
|
|
||||||
|
Content.ManageAsset(_errorCube);
|
||||||
|
_errorCube.ReleaseRef();
|
||||||
|
|
||||||
|
_errorCube.[Friend]Complete = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _placeholderCube;
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,612 @@
|
|||||||
|
using ImGui;
|
||||||
|
using System;
|
||||||
|
using GlitchyEngine.Content;
|
||||||
|
using GlitchyEngine.Renderer;
|
||||||
|
using GlitchyEngine.Math;
|
||||||
|
using GlitchyEngine;
|
||||||
|
namespace GlitchyEditor.EditWindows;
|
||||||
|
|
||||||
|
class AssetViewer : EditorWindow
|
||||||
|
{
|
||||||
|
public const String s_WindowTitle = "Asset Viewer";
|
||||||
|
|
||||||
|
public EditorContentManager _manager;
|
||||||
|
|
||||||
|
private AssetHandle _selectedAsset;
|
||||||
|
|
||||||
|
append TexturererViewerer _textureViewer = .();
|
||||||
|
|
||||||
|
public this(EditorContentManager contentManager)
|
||||||
|
{
|
||||||
|
_manager = contentManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void InternalShow()
|
||||||
|
{
|
||||||
|
if(!ImGui.Begin(s_WindowTitle, &_open, .None))
|
||||||
|
{
|
||||||
|
ImGui.End();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.PushStyleVar(.CellPadding, .(0, 0));
|
||||||
|
|
||||||
|
bool alt_pressed = ImGui.GetIO().KeyAlt;
|
||||||
|
|
||||||
|
if (ImGui.BeginTable("AssetViewerTable", 2, .BordersInnerV | .Resizable | .Reorderable | .NoPadOuterX))
|
||||||
|
{
|
||||||
|
if (alt_pressed)
|
||||||
|
{
|
||||||
|
// Header anzeigen, damit sie neu angeordnet werden können
|
||||||
|
ImGui.TableSetupColumn("Assets");
|
||||||
|
ImGui.TableSetupColumn("Viewer");
|
||||||
|
ImGui.TableHeadersRow();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.TableNextRow();
|
||||||
|
ImGui.TableSetColumnIndex(0);
|
||||||
|
|
||||||
|
if (ImGui.BeginChild("Assets"))
|
||||||
|
{
|
||||||
|
DrawAssetList();
|
||||||
|
|
||||||
|
ImGui.EndChild();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
|
||||||
|
if (ImGui.BeginChild("Files"))
|
||||||
|
{
|
||||||
|
DrawAssetViewer();
|
||||||
|
|
||||||
|
ImGui.EndChild();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.PopStyleVar(1);
|
||||||
|
|
||||||
|
ImGui.End();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawAssetList()
|
||||||
|
{
|
||||||
|
for (let (handle, asset) in _manager.[Friend]_handleToAsset)
|
||||||
|
{
|
||||||
|
// TODO: gucken, was der Typ ist
|
||||||
|
|
||||||
|
String name = scope String();
|
||||||
|
|
||||||
|
if (asset.Identifier.IsWhiteSpace)
|
||||||
|
name.Append("Unnamed");
|
||||||
|
else
|
||||||
|
name.Append(asset.Identifier);
|
||||||
|
|
||||||
|
name.Append(" (");
|
||||||
|
asset.GetType().GetName(name);
|
||||||
|
name.Append(") [");
|
||||||
|
name.AppendF($"{handle.ID}]");
|
||||||
|
|
||||||
|
name.TrimStart();
|
||||||
|
|
||||||
|
ImGui.TreeNodeFlags flags = .Leaf;
|
||||||
|
|
||||||
|
if(handle == _selectedAsset)
|
||||||
|
flags |= .Selected;
|
||||||
|
|
||||||
|
if (ImGui.TreeNodeEx(name, flags, name))
|
||||||
|
{
|
||||||
|
if (ImGui.IsItemClicked(.Left))
|
||||||
|
_selectedAsset = handle;
|
||||||
|
|
||||||
|
ImGui.TreePop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawAssetViewer()
|
||||||
|
{
|
||||||
|
if (_selectedAsset.IsInvalid)
|
||||||
|
{
|
||||||
|
ImGui.Text("Select an asset to view it.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Asset asset = _selectedAsset.Get<Asset>();
|
||||||
|
|
||||||
|
/*if (!asset.Complete)
|
||||||
|
{
|
||||||
|
ImGui.Text("Loading asset...");
|
||||||
|
return;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/*switch (asset.GetType())
|
||||||
|
{
|
||||||
|
case typeof(RenderTargetGroup):
|
||||||
|
DrawRenderTargetGroupViewer((RenderTargetGroup)asset);
|
||||||
|
case typeof(Texture):
|
||||||
|
_textureViewer.ViewTexture((Texture)asset);
|
||||||
|
|
||||||
|
}*/
|
||||||
|
|
||||||
|
if (var texture = asset as Texture)
|
||||||
|
_textureViewer.ViewTexture(texture);
|
||||||
|
if (var texture = asset as RenderTargetGroup)
|
||||||
|
_textureViewer.ViewTexture(texture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TexturererViewerer
|
||||||
|
{
|
||||||
|
enum BackgroundMode : int32
|
||||||
|
{
|
||||||
|
White,
|
||||||
|
Black,
|
||||||
|
Pink,
|
||||||
|
Checkerboard,
|
||||||
|
CustomColor
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SampleMode : int32
|
||||||
|
{
|
||||||
|
Point,
|
||||||
|
Linear
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ColorChannelSwizzle : int32
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
R,
|
||||||
|
G,
|
||||||
|
B,
|
||||||
|
A
|
||||||
|
}
|
||||||
|
|
||||||
|
AssetHandle<Effect> _effect;
|
||||||
|
AssetHandle<Effect> _renderTargetEffect;
|
||||||
|
|
||||||
|
float _zoom = 1.0f;
|
||||||
|
|
||||||
|
BackgroundMode _backgroundMode = .Checkerboard;
|
||||||
|
ColorRGBA _backgroundColor;
|
||||||
|
|
||||||
|
SampleMode _sampleMode = .Linear;
|
||||||
|
|
||||||
|
RenderTarget2D _target ~ _?.ReleaseRef();
|
||||||
|
// TODO: we don't need depth!
|
||||||
|
DepthStencilTarget _depth ~ _?.ReleaseRef();
|
||||||
|
|
||||||
|
public this()
|
||||||
|
{
|
||||||
|
_effect = Content.LoadAsset("Shaders\\textureViewerShader.hlsl");
|
||||||
|
_renderTargetEffect = Content.LoadAsset("Shaders\\RenderTargetGroupViewer.hlsl");
|
||||||
|
}
|
||||||
|
|
||||||
|
float2 _position;
|
||||||
|
|
||||||
|
bool _moving;
|
||||||
|
|
||||||
|
float _colorOffset = 0;
|
||||||
|
float _colorScale = 1;
|
||||||
|
float _alphaOffset = 0;
|
||||||
|
float _alphaScale = 1;
|
||||||
|
|
||||||
|
int32 _mipLevel = 0;
|
||||||
|
int32 _arraySlice = 0;
|
||||||
|
int32 _groupIndex = 0;
|
||||||
|
|
||||||
|
ColorChannelSwizzle _swizzleR = .R;
|
||||||
|
ColorChannelSwizzle _swizzleG = .G;
|
||||||
|
ColorChannelSwizzle _swizzleB = .B;
|
||||||
|
ColorChannelSwizzle _swizzleA = .A;
|
||||||
|
|
||||||
|
public void ShowSettings(float width, float height, int maxMips, int arraySize, RenderTargetGroup rtGroup)
|
||||||
|
{
|
||||||
|
char8*[] items = scope .("White", "Black", "Pink", "Checkerboard", "Custom Color");
|
||||||
|
|
||||||
|
if (ImGui.CollapsingHeader("View"))
|
||||||
|
{
|
||||||
|
ImGui.SliderFloat("Zoom", &_zoom, 0.01f, 100.0f);
|
||||||
|
|
||||||
|
float maxDimension = max(width, height);
|
||||||
|
|
||||||
|
ImGui.SliderFloat2("Position", *(float[2]*)&_position, 2 * -maxDimension * _zoom, 2 * maxDimension * _zoom);
|
||||||
|
|
||||||
|
ImGui.Separator();
|
||||||
|
|
||||||
|
ImGui.Combo("Background", (.)&_backgroundMode, items.Ptr, (.)items.Count);
|
||||||
|
|
||||||
|
if (_backgroundMode == .CustomColor)
|
||||||
|
{
|
||||||
|
ImGui.ColorPicker4("Color", ref _backgroundColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.CollapsingHeader("Sampling"))
|
||||||
|
{
|
||||||
|
items = scope .("Point", "Linear");
|
||||||
|
|
||||||
|
ImGui.Combo("Sampler", (.)&_sampleMode, items.Ptr, (.)items.Count);
|
||||||
|
|
||||||
|
ImGui.SliderInt("Mip Level", &_mipLevel, 0, (int32)maxMips);
|
||||||
|
ImGui.SliderInt("Array Slice", &_arraySlice, 0, (int32)arraySize);
|
||||||
|
|
||||||
|
ImGui.BeginDisabled(rtGroup == null);
|
||||||
|
|
||||||
|
ImGui.SliderInt("Group Target", &_groupIndex, (rtGroup?.HasDepth == true) ? -1 : 0, (int32)(rtGroup?.ColorTargetCount ?? 1) - 1);
|
||||||
|
|
||||||
|
ImGui.TextUnformatted(scope $"Target name: {(rtGroup?.GetTargetDescription(_groupIndex).DebugName ?? "???")}");
|
||||||
|
|
||||||
|
ImGui.EndDisabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.CollapsingHeader("Color and Transparency"))
|
||||||
|
{
|
||||||
|
ImGui.TextUnformatted("Channel Swizzle:");
|
||||||
|
|
||||||
|
if (ImGui.BeginTable("ColorAndAlpha", 4))
|
||||||
|
{
|
||||||
|
ImGui.TableNextRow();
|
||||||
|
ImGui.TableSetColumnIndex(0);
|
||||||
|
|
||||||
|
ImGui.PushID("Color");
|
||||||
|
|
||||||
|
ImGui.TextUnformatted("Color:");
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.DragFloat("Offset", &_colorOffset, 0.1f);
|
||||||
|
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.DragFloat("Scale", &_colorScale, 0.1f);
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
|
||||||
|
if (ImGui.Button("Reset"))
|
||||||
|
{
|
||||||
|
_colorOffset = 0.0f;
|
||||||
|
_colorScale = 1.0f;
|
||||||
|
}
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.BeginDisabled();
|
||||||
|
if (ImGui.Button("Auto"))
|
||||||
|
{
|
||||||
|
Runtime.NotImplemented();
|
||||||
|
}
|
||||||
|
ImGui.EndDisabled();
|
||||||
|
|
||||||
|
ImGui.PopID();
|
||||||
|
|
||||||
|
ImGui.TableNextRow();
|
||||||
|
ImGui.TableSetColumnIndex(0);
|
||||||
|
|
||||||
|
ImGui.PushID("Alpha");
|
||||||
|
|
||||||
|
ImGui.TextUnformatted("Alpha:");
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.DragFloat("Offset", &_alphaOffset, 0.1f);
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.DragFloat("Scale", &_alphaScale, 0.1f);
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
|
||||||
|
if (ImGui.Button("Reset"))
|
||||||
|
{
|
||||||
|
_alphaOffset = 0.0f;
|
||||||
|
_alphaScale = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.PopID();
|
||||||
|
|
||||||
|
ImGui.EndTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.Separator();
|
||||||
|
|
||||||
|
ImGui.TextUnformatted("Channel Swizzle:");
|
||||||
|
|
||||||
|
if (ImGui.BeginTable("SwizzleTable", 9))
|
||||||
|
{
|
||||||
|
ImGui.TableNextRow();
|
||||||
|
ImGui.TableSetColumnIndex(0);
|
||||||
|
|
||||||
|
SwizzleCombo("R", ref _swizzleR);
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
SwizzleCombo("G", ref _swizzleG);
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
SwizzleCombo("B", ref _swizzleB);
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
SwizzleCombo("A", ref _swizzleA);
|
||||||
|
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
|
||||||
|
if (ImGui.Button("Reset swizzle"))
|
||||||
|
{
|
||||||
|
_swizzleR = .R;
|
||||||
|
_swizzleG = .G;
|
||||||
|
_swizzleB = .B;
|
||||||
|
_swizzleA = .A;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndTable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SwizzleCombo(StringView text, ref ColorChannelSwizzle swizzle)
|
||||||
|
{
|
||||||
|
ImGui.TextUnformatted(text);
|
||||||
|
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
|
||||||
|
if (ImGui.BeginCombo(scope $"##swizzle{text}", scope $"{swizzle}"))
|
||||||
|
{
|
||||||
|
if (ImGui.Selectable("R", swizzle == .R))
|
||||||
|
swizzle = .R;
|
||||||
|
|
||||||
|
if (ImGui.Selectable("G", swizzle == .G))
|
||||||
|
swizzle = .G;
|
||||||
|
|
||||||
|
if (ImGui.Selectable("B", swizzle == .B))
|
||||||
|
swizzle = .B;
|
||||||
|
|
||||||
|
if (ImGui.Selectable("A", swizzle == .A))
|
||||||
|
swizzle = .A;
|
||||||
|
|
||||||
|
if (ImGui.Selectable("None", swizzle == .None))
|
||||||
|
swizzle = .None;
|
||||||
|
|
||||||
|
ImGui.EndCombo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ViewTexture(RenderTargetGroup texture)
|
||||||
|
{
|
||||||
|
ShowSettings(texture.Width, texture.Height, texture.MipLevels - 1, texture.ArraySize - 1, texture);
|
||||||
|
|
||||||
|
if (ImGui.BeginChild("imageChild"))
|
||||||
|
{
|
||||||
|
UpdateInput();
|
||||||
|
|
||||||
|
var viewportSize = ImGui.GetContentRegionAvail();
|
||||||
|
|
||||||
|
viewportSize.x = Math.Max(viewportSize.x, 1);
|
||||||
|
viewportSize.y = Math.Max(viewportSize.y, 1);
|
||||||
|
|
||||||
|
if(_target == null || viewportSize.x != _target.Width || viewportSize.y != _target.Height)
|
||||||
|
{
|
||||||
|
_target?.ReleaseRef();
|
||||||
|
_target = new RenderTarget2D(.(.R8G8B8A8_UNorm_SRGB, (.)viewportSize.x, (.)viewportSize.y));
|
||||||
|
_target.SamplerState = SamplerStateManager.PointClamp;
|
||||||
|
_depth?.ReleaseRef();
|
||||||
|
_depth = new DepthStencilTarget((.)viewportSize.x, (.)viewportSize.y, .D16_UNorm);
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderBackground();
|
||||||
|
|
||||||
|
RenderTexture(texture);
|
||||||
|
|
||||||
|
ImGui.Image(_target, viewportSize);
|
||||||
|
|
||||||
|
ImGui.EndChild();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ViewTexture(Texture texture)
|
||||||
|
{
|
||||||
|
ShowSettings(texture.Width, texture.Height, texture.MipLevels - 1, texture.ArraySize - 1, null);
|
||||||
|
|
||||||
|
if (ImGui.BeginChild("imageChild"))
|
||||||
|
{
|
||||||
|
UpdateInput();
|
||||||
|
|
||||||
|
var viewportSize = ImGui.GetContentRegionAvail();
|
||||||
|
|
||||||
|
viewportSize.x = Math.Max(viewportSize.x, 1);
|
||||||
|
viewportSize.y = Math.Max(viewportSize.y, 1);
|
||||||
|
|
||||||
|
if(_target == null || viewportSize.x != _target.Width || viewportSize.y != _target.Height)
|
||||||
|
{
|
||||||
|
_target?.ReleaseRef();
|
||||||
|
_target = new RenderTarget2D(.(.R8G8B8A8_UNorm_SRGB, (.)viewportSize.x, (.)viewportSize.y));
|
||||||
|
_target.SamplerState = SamplerStateManager.PointClamp;
|
||||||
|
_depth?.ReleaseRef();
|
||||||
|
_depth = new DepthStencilTarget((.)viewportSize.x, (.)viewportSize.y, .D16_UNorm);
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderBackground();
|
||||||
|
|
||||||
|
RenderTexture(texture);
|
||||||
|
|
||||||
|
ImGui.Image(_target, viewportSize);
|
||||||
|
|
||||||
|
ImGui.EndChild();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float lastWheel;
|
||||||
|
|
||||||
|
private void UpdateInput()
|
||||||
|
{
|
||||||
|
var windowPos = ImGui.GetWindowPos();
|
||||||
|
var mousePos = ImGui.GetIO().MousePos;
|
||||||
|
float2 mouseInWindow = .(mousePos.x - windowPos.x, mousePos.y - windowPos.y);
|
||||||
|
|
||||||
|
bool windowHovered = ImGui.IsWindowHovered();
|
||||||
|
|
||||||
|
if(windowHovered && Input.IsMouseButtonPressing(.MiddleButton))
|
||||||
|
{
|
||||||
|
_moving = true;
|
||||||
|
}
|
||||||
|
else if(Input.IsMouseButtonReleased(.MiddleButton))
|
||||||
|
{
|
||||||
|
_moving = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(windowHovered || _moving)
|
||||||
|
{
|
||||||
|
float mouseWheel = ImGui.GetIO().MouseWheel;
|
||||||
|
|
||||||
|
float delta = mouseWheel - lastWheel;
|
||||||
|
|
||||||
|
if(delta != 0)
|
||||||
|
{
|
||||||
|
_position -= mouseInWindow;
|
||||||
|
_position /= _zoom;
|
||||||
|
|
||||||
|
_zoom *= Math.Pow(1.1f, delta);
|
||||||
|
|
||||||
|
_position *= _zoom;
|
||||||
|
_position += mouseInWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_moving)
|
||||||
|
{
|
||||||
|
int2 movement = Input.GetMouseMovement();
|
||||||
|
|
||||||
|
_position.X += movement.X;
|
||||||
|
_position.Y += movement.Y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OrthographicCamera _camera = new OrthographicCamera() ~ delete _;
|
||||||
|
|
||||||
|
private void RenderBackground()
|
||||||
|
{
|
||||||
|
Viewport vp = .(0, 0, _target.Width, _target.Height);
|
||||||
|
RenderCommand.SetViewport(vp);
|
||||||
|
|
||||||
|
// TODO: don't clear pink!
|
||||||
|
RenderCommand.Clear(_target, .Pink);
|
||||||
|
RenderCommand.Clear(_depth, .Depth, 1.0f, 0);
|
||||||
|
|
||||||
|
//_target.Bind();
|
||||||
|
RenderCommand.SetRenderTarget(_target);
|
||||||
|
RenderCommand.SetDepthStencilTarget(_depth);
|
||||||
|
RenderCommand.BindRenderTargets();
|
||||||
|
|
||||||
|
float2 targetSize = float2(_target.Width, _target.Height);
|
||||||
|
|
||||||
|
_camera.Left = 0;
|
||||||
|
_camera.Top = 0;
|
||||||
|
_camera.Right = targetSize.X;
|
||||||
|
_camera.Bottom = -targetSize.Y;
|
||||||
|
_camera.NearPlane = -5;
|
||||||
|
_camera.FarPlane = 5;
|
||||||
|
_camera.Update();
|
||||||
|
|
||||||
|
Renderer2D.BeginScene(_camera);
|
||||||
|
|
||||||
|
switch(_backgroundMode)
|
||||||
|
{
|
||||||
|
case .Black:
|
||||||
|
Renderer2D.DrawQuadPivotCorner(float3(0, 0, 1), targetSize, 0, .Black);
|
||||||
|
case .White:
|
||||||
|
Renderer2D.DrawQuadPivotCorner(float3(0, 0, 1), targetSize, 0, .White);
|
||||||
|
case .Pink:
|
||||||
|
Renderer2D.DrawQuadPivotCorner(float3(0, 0, 1), targetSize, 0, .HotPink);
|
||||||
|
case .CustomColor:
|
||||||
|
Renderer2D.DrawQuadPivotCorner(float3(0, 0, 1), targetSize, 0, _backgroundColor);
|
||||||
|
case .Checkerboard:
|
||||||
|
float quadSize = 50.0f;
|
||||||
|
|
||||||
|
float2 numQuads = (targetSize / 500f) * 10f;
|
||||||
|
|
||||||
|
for(float x = 0; x < numQuads.X; x++)
|
||||||
|
{
|
||||||
|
for(float y = 0; y < numQuads.Y; y++)
|
||||||
|
{
|
||||||
|
Renderer2D.DrawQuadPivotCorner(float3(x * quadSize, -y * quadSize, 1), quadSize.XX, 0, ((x + y) % 2 == 0) ? .White : .Gray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Renderer2D.EndScene();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RenderTexture(TextureViewBinding viewedTexture, float2 textureSize, Format format)
|
||||||
|
{
|
||||||
|
float2 mippedTextureSize = float2((int)textureSize.X >> _mipLevel, (int)textureSize.X >> _mipLevel);
|
||||||
|
|
||||||
|
// Sicherstellen, dass die Auflösung nicht 0 wird
|
||||||
|
mippedTextureSize = max(mippedTextureSize, 1);
|
||||||
|
|
||||||
|
//float2 textureSize = float2(viewedTexture.Width, viewedTexture.Height);
|
||||||
|
float2 zoomedTextureSize = textureSize * _zoom;
|
||||||
|
|
||||||
|
// TODO: Sampler state for rt group
|
||||||
|
//var sampler = viewedTexture.SamplerState;
|
||||||
|
|
||||||
|
/*switch(_sampleMode)
|
||||||
|
{
|
||||||
|
case .Point:
|
||||||
|
viewedTexture.SamplerState = SamplerStateManager.PointClamp;
|
||||||
|
case .Linear:
|
||||||
|
viewedTexture.SamplerState = SamplerStateManager.LinearClamp;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
//Renderer2D.BeginScene(_camera, .SortByTexture, _effect);
|
||||||
|
|
||||||
|
// float3(_position * .(1, -1), 0)
|
||||||
|
RenderCommand.Clear(_depth, .Depth, 1.0f, 0);
|
||||||
|
|
||||||
|
Matrix matrix = .Translation(float3(_position * .(1, -1), 0)) * .Scaling(float3(zoomedTextureSize, 1));
|
||||||
|
|
||||||
|
// TODO: ViewProjection kommt nicht korrekt an?
|
||||||
|
_renderTargetEffect.Variables["WorldViewProjection"].SetData(_camera.ViewProjection * matrix);
|
||||||
|
_renderTargetEffect.Variables["ColorOffset"].SetData(_colorOffset);
|
||||||
|
_renderTargetEffect.Variables["ColorScale"].SetData(_colorScale);
|
||||||
|
_renderTargetEffect.Variables["AlphaOffset"].SetData(_alphaOffset);
|
||||||
|
_renderTargetEffect.Variables["AlphaScale"].SetData(_alphaScale);
|
||||||
|
|
||||||
|
_renderTargetEffect.Variables["Texels"].SetData(mippedTextureSize);
|
||||||
|
|
||||||
|
_renderTargetEffect.Variables["MipLevel"].SetData((float)_mipLevel);
|
||||||
|
|
||||||
|
_renderTargetEffect.Variables["Swizzle"].SetData(int4((int32)_swizzleR, (int32)_swizzleG, (int32)_swizzleB, (int32)_swizzleA));
|
||||||
|
|
||||||
|
if (format.IsInt())
|
||||||
|
{
|
||||||
|
// Int Texture
|
||||||
|
_renderTargetEffect.Variables["Mode"].SetData(1);
|
||||||
|
_renderTargetEffect.SetTexture("IntTexture", viewedTexture);
|
||||||
|
_renderTargetEffect.SetTexture("UIntTexture", null);
|
||||||
|
_renderTargetEffect.SetTexture("Texture", null);
|
||||||
|
}
|
||||||
|
else if (format.IsUInt())
|
||||||
|
{
|
||||||
|
// UInt Texture
|
||||||
|
_renderTargetEffect.Variables["Mode"].SetData(2);
|
||||||
|
_renderTargetEffect.SetTexture("IntTexture", null);
|
||||||
|
_renderTargetEffect.SetTexture("UIntTexture", viewedTexture);
|
||||||
|
_renderTargetEffect.SetTexture("Texture", null);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Float Texture
|
||||||
|
_renderTargetEffect.Variables["Mode"].SetData(0);
|
||||||
|
_renderTargetEffect.SetTexture("IntTexture", null);
|
||||||
|
_renderTargetEffect.SetTexture("UIntTexture", null);
|
||||||
|
_renderTargetEffect.SetTexture("Texture", viewedTexture);
|
||||||
|
}
|
||||||
|
|
||||||
|
_renderTargetEffect.Variables["Swizzle"].SetData(int4((int32)_swizzleR, (int32)_swizzleG, (int32)_swizzleB, (int32)_swizzleA));
|
||||||
|
|
||||||
|
_renderTargetEffect.ApplyChanges();
|
||||||
|
_renderTargetEffect.Bind();
|
||||||
|
|
||||||
|
Quad.Draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RenderTexture(RenderTargetGroup viewedTexture)
|
||||||
|
{
|
||||||
|
var desc = _groupIndex >= 0 ? viewedTexture.[Friend]_colorTargetDescriptions[_groupIndex] : viewedTexture.[Friend]_depthTargetDescription;
|
||||||
|
|
||||||
|
RenderTexture(viewedTexture.GetViewBinding(_groupIndex), float2(viewedTexture.Width, viewedTexture.Height), desc.Format.GetShaderViewFormat());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RenderTexture(Texture viewedTexture)
|
||||||
|
{
|
||||||
|
RenderTexture(viewedTexture.GetViewBinding(), float2(viewedTexture.Width, viewedTexture.Height), viewedTexture.Format);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ using System.Collections;
|
|||||||
using GlitchyEngine.Renderer;
|
using GlitchyEngine.Renderer;
|
||||||
using GlitchyEngine;
|
using GlitchyEngine;
|
||||||
using GlitchyEngine.Content;
|
using GlitchyEngine.Content;
|
||||||
|
using GlitchyEngine.Scripting;
|
||||||
|
|
||||||
namespace GlitchyEditor.EditWindows
|
namespace GlitchyEditor.EditWindows
|
||||||
{
|
{
|
||||||
@@ -60,13 +61,15 @@ namespace GlitchyEditor.EditWindows
|
|||||||
|
|
||||||
ShowComponentEditor<TransformComponent>("Transform", entity, => ShowTransformComponentEditor);
|
ShowComponentEditor<TransformComponent>("Transform", entity, => ShowTransformComponentEditor);
|
||||||
ShowComponentEditor<CameraComponent>("Camera", entity, => ShowCameraComponentEditor, => ShowComponentContextMenu<CameraComponent>);
|
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<MeshRendererComponent>("Mesh Renderer", entity, => ShowMeshRendererComponentEditor, => ShowComponentContextMenu<MeshRendererComponent>);
|
||||||
ShowComponentEditor<LightComponent>("Light", entity, => ShowLightComponentEditor, => ShowComponentContextMenu<LightComponent>);
|
ShowComponentEditor<LightComponent>("Light", entity, => ShowLightComponentEditor, => ShowComponentContextMenu<LightComponent>);
|
||||||
ShowComponentEditor<MeshComponent>("Mesh", entity, => ShowMeshComponentEditor, => ShowComponentContextMenu<MeshComponent>);
|
ShowComponentEditor<MeshComponent>("Mesh", entity, => ShowMeshComponentEditor, => ShowComponentContextMenu<MeshComponent>);
|
||||||
ShowComponentEditor<Rigidbody2DComponent>("Rigidbody 2D", entity, => ShowRigidBody2DComponentEditor, => ShowComponentContextMenu<Rigidbody2DComponent>);
|
ShowComponentEditor<Rigidbody2DComponent>("Rigidbody 2D", entity, => ShowRigidBody2DComponentEditor, => ShowComponentContextMenu<Rigidbody2DComponent>);
|
||||||
ShowComponentEditor<BoxCollider2DComponent>("Box collider 2D", entity, => ShowBoxCollider2DComponentEditor, => ShowComponentContextMenu<BoxCollider2DComponent>);
|
ShowComponentEditor<BoxCollider2DComponent>("Box collider 2D", entity, => ShowBoxCollider2DComponentEditor, => ShowComponentContextMenu<BoxCollider2DComponent>);
|
||||||
ShowComponentEditor<CircleCollider2DComponent>("Circle collider 2D", entity, => ShowCircleCollider2DComponentEditor, => ShowComponentContextMenu<CircleCollider2DComponent>);
|
ShowComponentEditor<CircleCollider2DComponent>("Circle collider 2D", entity, => ShowCircleCollider2DComponentEditor, => ShowComponentContextMenu<CircleCollider2DComponent>);
|
||||||
|
ShowComponentEditor<ScriptComponent>("Script Component", entity, => ShowScriptComponentEditor, => ShowComponentContextMenu<ScriptComponent>);
|
||||||
|
|
||||||
ShowAddComponentButton(entity);
|
ShowAddComponentButton(entity);
|
||||||
}
|
}
|
||||||
@@ -117,18 +120,18 @@ namespace GlitchyEditor.EditWindows
|
|||||||
|
|
||||||
private static void ShowNameComponentEditor(Entity entity)
|
private static void ShowNameComponentEditor(Entity entity)
|
||||||
{
|
{
|
||||||
if (!entity.HasComponent<DebugNameComponent>())
|
if (!entity.HasComponent<NameComponent>())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
char8[256] nameBuffer = default;
|
char8[256] nameBuffer = default;
|
||||||
|
|
||||||
DebugNameComponent* component = entity.GetComponent<DebugNameComponent>();
|
NameComponent* component = entity.GetComponent<NameComponent>();
|
||||||
|
|
||||||
String name = null;
|
StringView name = null;
|
||||||
|
|
||||||
if(component != null)
|
if(component != null)
|
||||||
{
|
{
|
||||||
name = component.DebugName;
|
name = component.Name;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -142,11 +145,10 @@ namespace GlitchyEditor.EditWindows
|
|||||||
{
|
{
|
||||||
if(component == null)
|
if(component == null)
|
||||||
{
|
{
|
||||||
component = entity.AddComponent<DebugNameComponent>();
|
component = entity.AddComponent<NameComponent>();
|
||||||
}
|
}
|
||||||
|
|
||||||
component.DebugName.Clear();
|
component.Name = StringView(&nameBuffer);
|
||||||
component.DebugName.Append(&nameBuffer);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,16 +160,32 @@ namespace GlitchyEditor.EditWindows
|
|||||||
|
|
||||||
textWidth += ImGui.GetStyle().FramePadding.x * 3.0f;
|
textWidth += ImGui.GetStyle().FramePadding.x * 3.0f;
|
||||||
|
|
||||||
Vector3 position = transform.Position;
|
float3 position = transform.Position;
|
||||||
if (ImGui.EditVector3("Position", ref position, .Zero, 0.1f, textWidth))
|
if (ImGui.Editfloat3("Position", ref position, .Zero, 0.1f, textWidth))
|
||||||
|
{
|
||||||
transform.Position = position;
|
transform.Position = position;
|
||||||
|
|
||||||
Vector3 rotationEuler = MathHelper.ToDegrees(transform.EditorRotationEuler);
|
// if necessary reposition Rigidbody2D
|
||||||
if (ImGui.EditVector3("Rotation", ref rotationEuler, .Zero, 0.1f, textWidth))
|
if (entity.TryGetComponent<Rigidbody2DComponent>(let rigidbody2D))
|
||||||
|
{
|
||||||
|
rigidbody2D.SetPosition(position.XY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 rotationEuler = MathHelper.ToDegrees(transform.EditorRotationEuler);
|
||||||
|
if (ImGui.Editfloat3("Rotation", ref rotationEuler, .Zero, 0.1f, textWidth))
|
||||||
|
{
|
||||||
transform.EditorRotationEuler = MathHelper.ToRadians(rotationEuler);
|
transform.EditorRotationEuler = MathHelper.ToRadians(rotationEuler);
|
||||||
|
|
||||||
|
// if necessary reposition Rigidbody2D
|
||||||
|
if (entity.TryGetComponent<Rigidbody2DComponent>(let rigidbody2D))
|
||||||
|
{
|
||||||
|
rigidbody2D.SetAngle(rotationEuler.Z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Vector3 scale = transform.Scale;
|
float3 scale = transform.Scale;
|
||||||
if (ImGui.EditVector3("Scale", ref scale, .One, 0.1f, textWidth))
|
if (ImGui.Editfloat3("Scale", ref scale, .One, 0.1f, textWidth))
|
||||||
transform.Scale = scale;
|
transform.Scale = scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,7 +268,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);
|
ColorRGBA spriteColor = ColorRGBA.LinearToSRGB(spriteRendererComponent.Color);
|
||||||
if (ImGui.ColorEdit4("Color", ref spriteColor))
|
if (ImGui.ColorEdit4("Color", ref spriteColor))
|
||||||
@@ -268,10 +286,7 @@ namespace GlitchyEditor.EditWindows
|
|||||||
|
|
||||||
StringView path = .((char8*)payload.Data, (int)payload.DataSize);
|
StringView path = .((char8*)payload.Data, (int)payload.DataSize);
|
||||||
|
|
||||||
using (Texture2D texture = Content.LoadAsset<Texture2D>(path))
|
spriteRendererComponent.Sprite = Content.LoadAsset(path);
|
||||||
{
|
|
||||||
spriteRendererComponent.Sprite = texture;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.EndDragDropTarget();
|
ImGui.EndDragDropTarget();
|
||||||
@@ -279,8 +294,36 @@ namespace GlitchyEditor.EditWindows
|
|||||||
|
|
||||||
|
|
||||||
ImGui.EditVector<4>("UV Transform", ref *(float[4]*)&spriteRendererComponent.UvTransform);
|
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)
|
private static void ShowMeshRendererComponentEditor(Entity entity, MeshRendererComponent* meshRendererComponent)
|
||||||
@@ -301,10 +344,7 @@ namespace GlitchyEditor.EditWindows
|
|||||||
{
|
{
|
||||||
StringView fullpath = .((char8*)payload.Data, (int)payload.DataSize);
|
StringView fullpath = .((char8*)payload.Data, (int)payload.DataSize);
|
||||||
|
|
||||||
using (Material loadedMaterial = Content.LoadAsset<Material>(fullpath))
|
meshRendererComponent.Material = Content.LoadAsset(fullpath);
|
||||||
{
|
|
||||||
meshRendererComponent.Material = loadedMaterial;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.EndDragDropTarget();
|
ImGui.EndDragDropTarget();
|
||||||
@@ -351,12 +391,12 @@ namespace GlitchyEditor.EditWindows
|
|||||||
textWidth += ImGui.GetStyle().FramePadding.x * 3.0f;
|
textWidth += ImGui.GetStyle().FramePadding.x * 3.0f;
|
||||||
|
|
||||||
|
|
||||||
Vector2 offset = boxCollider.Offset;
|
float2 offset = boxCollider.Offset;
|
||||||
if (ImGui.EditVector2("Offset", ref offset, .Zero, 0.1f, textWidth))
|
if (ImGui.Editfloat2("Offset", ref offset, .Zero, 0.1f, textWidth))
|
||||||
boxCollider.Offset = offset;
|
boxCollider.Offset = offset;
|
||||||
|
|
||||||
Vector2 size = boxCollider.Size;
|
float2 size = boxCollider.Size;
|
||||||
if (ImGui.EditVector2("Size", ref size, .Zero, 0.1f, textWidth))
|
if (ImGui.Editfloat2("Size", ref size, .Zero, 0.1f, textWidth))
|
||||||
boxCollider.Size = size;
|
boxCollider.Size = size;
|
||||||
|
|
||||||
float density = boxCollider.Density;
|
float density = boxCollider.Density;
|
||||||
@@ -382,8 +422,8 @@ namespace GlitchyEditor.EditWindows
|
|||||||
textWidth += ImGui.GetStyle().FramePadding.x * 3.0f;
|
textWidth += ImGui.GetStyle().FramePadding.x * 3.0f;
|
||||||
|
|
||||||
|
|
||||||
Vector2 offset = circleCollider.Offset;
|
float2 offset = circleCollider.Offset;
|
||||||
if (ImGui.EditVector2("Offset", ref offset, .Zero, 0.1f, textWidth))
|
if (ImGui.Editfloat2("Offset", ref offset, .Zero, 0.1f, textWidth))
|
||||||
circleCollider.Offset = offset;
|
circleCollider.Offset = offset;
|
||||||
|
|
||||||
float radius = circleCollider.Radius;
|
float radius = circleCollider.Radius;
|
||||||
@@ -407,6 +447,273 @@ namespace GlitchyEditor.EditWindows
|
|||||||
circleCollider.RestitutionThreshold = restitutionThreshold;
|
circleCollider.RestitutionThreshold = restitutionThreshold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void ShowScriptComponentEditor(Entity entity, ScriptComponent* scriptComponent)
|
||||||
|
{
|
||||||
|
static char8[64] buffer = .();
|
||||||
|
|
||||||
|
StringView search = StringView();
|
||||||
|
|
||||||
|
//char8* scriptLabel = scriptComponent.Instance?.ScriptClass.FullName.ToScopeCStr!() ?? "Select Script...";
|
||||||
|
char8* scriptLabel = scriptComponent.Instance?.ScriptClass.FullName.CStr() ?? "Select Script...";
|
||||||
|
|
||||||
|
if (ImGui.Button(scriptLabel))
|
||||||
|
ImGui.OpenPopup("SelectScript");
|
||||||
|
|
||||||
|
if (ImGui.BeginPopup("SelectScript"))
|
||||||
|
{
|
||||||
|
ImGui.InputText("##ScriptSearch", &buffer, buffer.Count);
|
||||||
|
|
||||||
|
search = StringView(&buffer);
|
||||||
|
|
||||||
|
for (let (className, scriptClass) in ScriptEngine.EntityClasses)
|
||||||
|
{
|
||||||
|
if (!search.IsWhiteSpace && !className.Contains(search, true))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (ImGui.Selectable(className.ToScopeCStr!(),
|
||||||
|
className == scriptComponent.ScriptClassName))
|
||||||
|
{
|
||||||
|
//scriptComponent.Instance = new ScriptInstance(scriptClass);
|
||||||
|
// decrement refCount to 1 (scriptComponent.Instance increments its)
|
||||||
|
//scriptComponent.Instance.ReleaseRef();
|
||||||
|
//ScriptEngine.InitializeInstance(entity, scriptComponent);
|
||||||
|
|
||||||
|
scriptComponent.ScriptClassName = scriptClass.FullName;
|
||||||
|
|
||||||
|
//ScriptEngine.CreateScriptFieldMap(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui.EndPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
ScriptClass scriptClass = ScriptEngine.GetScriptClass(scriptComponent.ScriptClassName);
|
||||||
|
|
||||||
|
/*T GetFieldValue<T>()
|
||||||
|
{
|
||||||
|
return scriptComponent.Instance.GetFieldValue<T>(monoField);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetFieldValue<T>(in T value)
|
||||||
|
{
|
||||||
|
scriptComponent.Instance.SetFieldValue<T>(monoField, value);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
T GetFieldValue<T>(ScriptInstance scriptInstance, in ScriptField scriptField)
|
||||||
|
{
|
||||||
|
return scriptInstance.GetFieldValue<T>(scriptField);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetFieldValue<T>(ScriptInstance scriptInstance, in ScriptField scriptField, out T value)
|
||||||
|
{
|
||||||
|
value = scriptInstance.GetFieldValue<T>(scriptField);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetFieldValue<T>(ScriptInstance scriptInstance, in ScriptField scriptField, in T value)
|
||||||
|
{
|
||||||
|
scriptInstance.SetFieldValue<T>(scriptField, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scriptComponent.Instance?.IsInitialized == true)
|
||||||
|
{
|
||||||
|
SharpClass sharpClass = scriptComponent.Instance.ScriptClass;
|
||||||
|
ScriptInstance scriptInstance = scriptComponent.Instance;
|
||||||
|
|
||||||
|
for (let (fieldName, scriptField) in sharpClass.Fields)
|
||||||
|
{
|
||||||
|
var monoField = scriptField.[Friend]_monoField;
|
||||||
|
|
||||||
|
switch (scriptField.FieldType)
|
||||||
|
{
|
||||||
|
case .Bool:
|
||||||
|
var value = GetFieldValue<bool>(scriptInstance, scriptField);
|
||||||
|
if (ImGui.Checkbox(fieldName.ToScopeCStr!(), &value))
|
||||||
|
SetFieldValue(scriptInstance, scriptField, value);
|
||||||
|
|
||||||
|
case .SByte:
|
||||||
|
var value = GetFieldValue<int8>(scriptInstance, scriptField);
|
||||||
|
if (ImGui.DragScalar(fieldName.ToScopeCStr!(), .S8, &value))
|
||||||
|
SetFieldValue(scriptInstance, scriptField, value);
|
||||||
|
case .Short:
|
||||||
|
var value = GetFieldValue<int16>(scriptInstance, scriptField);
|
||||||
|
if (ImGui.DragScalar(fieldName.ToScopeCStr!(), .S16, &value))
|
||||||
|
SetFieldValue(scriptInstance, scriptField, value);
|
||||||
|
case .Int:
|
||||||
|
var value = GetFieldValue<int32>(scriptInstance, scriptField);
|
||||||
|
if (ImGui.DragScalar(fieldName.ToScopeCStr!(), .S32, &value))
|
||||||
|
SetFieldValue(scriptInstance, scriptField, value);
|
||||||
|
case .Long:
|
||||||
|
var value = GetFieldValue<int64>(scriptInstance, scriptField);
|
||||||
|
if (ImGui.DragScalar(fieldName.ToScopeCStr!(), .S64, &value))
|
||||||
|
SetFieldValue(scriptInstance, scriptField, value);
|
||||||
|
|
||||||
|
case .Byte:
|
||||||
|
var value = GetFieldValue<uint8>(scriptInstance, scriptField);
|
||||||
|
if (ImGui.DragScalar(fieldName.ToScopeCStr!(), .U8, &value))
|
||||||
|
SetFieldValue(scriptInstance, scriptField, value);
|
||||||
|
case .UShort:
|
||||||
|
var value = GetFieldValue<uint16>(scriptInstance, scriptField);
|
||||||
|
if (ImGui.DragScalar(fieldName.ToScopeCStr!(), .U16, &value))
|
||||||
|
SetFieldValue(scriptInstance, scriptField, value);
|
||||||
|
case .UInt:
|
||||||
|
var value = GetFieldValue<uint32>(scriptInstance, scriptField);
|
||||||
|
if (ImGui.DragScalar(fieldName.ToScopeCStr!(), .U32, &value))
|
||||||
|
SetFieldValue(scriptInstance, scriptField, value);
|
||||||
|
case .ULong:
|
||||||
|
var value = GetFieldValue<uint64>(scriptInstance, scriptField);
|
||||||
|
if (ImGui.DragScalar(fieldName.ToScopeCStr!(), .U64, &value))
|
||||||
|
SetFieldValue(scriptInstance, scriptField, value);
|
||||||
|
|
||||||
|
case .Float:
|
||||||
|
var value = GetFieldValue<float>(scriptInstance, scriptField);
|
||||||
|
if (ImGui.DragScalar(fieldName.ToScopeCStr!(), .Float, &value))
|
||||||
|
SetFieldValue(scriptInstance, scriptField, value);
|
||||||
|
|
||||||
|
case .float2:
|
||||||
|
GetFieldValue<float2>(scriptInstance, scriptField, var value);
|
||||||
|
if (ImGui.Editfloat2(fieldName, ref value))
|
||||||
|
SetFieldValue(scriptInstance, scriptField, value);
|
||||||
|
case .float3:
|
||||||
|
GetFieldValue<float3>(scriptInstance, scriptField, var value);
|
||||||
|
if (ImGui.Editfloat3(fieldName, ref value))
|
||||||
|
SetFieldValue(scriptInstance, scriptField, value);
|
||||||
|
case .float4:
|
||||||
|
GetFieldValue<float4>(scriptInstance, scriptField, var value);
|
||||||
|
if (ImGui.Editfloat4(fieldName, ref value))
|
||||||
|
SetFieldValue(scriptInstance, scriptField, value);
|
||||||
|
|
||||||
|
case .Double:
|
||||||
|
var value = GetFieldValue<double>(scriptInstance, scriptField);
|
||||||
|
if (ImGui.DragScalar(fieldName.ToScopeCStr!(), .Double, &value))
|
||||||
|
SetFieldValue(scriptInstance, scriptField, value);
|
||||||
|
|
||||||
|
case .Entity:
|
||||||
|
// TODO!
|
||||||
|
|
||||||
|
case .Enum:
|
||||||
|
// TODO!
|
||||||
|
case .Struct:
|
||||||
|
// TODO!
|
||||||
|
default:
|
||||||
|
Log.EngineLogger.Error($"Unhandled field type {scriptField.FieldType}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (scriptClass != null)
|
||||||
|
{
|
||||||
|
let scriptFields = ScriptEngine.GetScriptFieldMap(entity);
|
||||||
|
|
||||||
|
for (var (name, field) in ref scriptFields)
|
||||||
|
{
|
||||||
|
switch (field.Type)
|
||||||
|
{
|
||||||
|
case .Bool:
|
||||||
|
var value = field.GetData<bool>();
|
||||||
|
if (ImGui.Checkbox(name.CStr(), &value))
|
||||||
|
field.SetData(value);
|
||||||
|
|
||||||
|
case .SByte:
|
||||||
|
var value = field.GetData<int8>();
|
||||||
|
if (ImGui.DragScalar(name.CStr(), .S8, &value))
|
||||||
|
field.SetData(value);
|
||||||
|
case .Short:
|
||||||
|
var value = field.GetData<int16>();
|
||||||
|
if (ImGui.DragScalar(name.CStr(), .S16, &value))
|
||||||
|
field.SetData(value);
|
||||||
|
case .Int:
|
||||||
|
var value = field.GetData<int32>();
|
||||||
|
if (ImGui.DragScalar(name.CStr(), .S32, &value))
|
||||||
|
field.SetData(value);
|
||||||
|
case .Int2:
|
||||||
|
var value = field.GetData<int2>();
|
||||||
|
if (ImGui.DragScalarN(name.CStr(), .S32, &value, 2))
|
||||||
|
field.SetData(value);
|
||||||
|
case .Int3:
|
||||||
|
var value = field.GetData<int3>();
|
||||||
|
if (ImGui.DragScalarN(name.CStr(), .S32, &value, 3))
|
||||||
|
field.SetData(value);
|
||||||
|
case .Int4:
|
||||||
|
var value = field.GetData<int4>();
|
||||||
|
if (ImGui.DragScalarN(name.CStr(), .S32, &value, 4))
|
||||||
|
field.SetData(value);
|
||||||
|
case .Long:
|
||||||
|
var value = field.GetData<int64>();
|
||||||
|
if (ImGui.DragScalar(name.CStr(), .S64, &value))
|
||||||
|
field.SetData(value);
|
||||||
|
|
||||||
|
case .Byte:
|
||||||
|
var value = field.GetData<uint8>();
|
||||||
|
if (ImGui.DragScalar(name.CStr(), .U8, &value))
|
||||||
|
field.SetData(value);
|
||||||
|
case .UShort:
|
||||||
|
var value = field.GetData<uint16>();
|
||||||
|
if (ImGui.DragScalar(name.CStr(), .U16, &value))
|
||||||
|
field.SetData(value);
|
||||||
|
case .UInt:
|
||||||
|
var value = field.GetData<uint32>();
|
||||||
|
if (ImGui.DragScalar(name.CStr(), .U32, &value))
|
||||||
|
field.SetData(value);
|
||||||
|
case .ULong:
|
||||||
|
var value = field.GetData<uint64>();
|
||||||
|
if (ImGui.DragScalar(name.CStr(), .U64, &value))
|
||||||
|
field.SetData(value);
|
||||||
|
|
||||||
|
case .Float:
|
||||||
|
var value = field.GetData<float>();
|
||||||
|
if (ImGui.DragScalar(name.CStr(), .Float, &value))
|
||||||
|
field.SetData(value);
|
||||||
|
case .float2:
|
||||||
|
var value = field.GetData<float2>();
|
||||||
|
if (ImGui.Editfloat2(name, ref value))
|
||||||
|
field.SetData(value);
|
||||||
|
case .float3:
|
||||||
|
var value = field.GetData<float3>();
|
||||||
|
if (ImGui.Editfloat3(name, ref value))
|
||||||
|
field.SetData(value);
|
||||||
|
case .float4:
|
||||||
|
var value = field.GetData<float4>();
|
||||||
|
if (ImGui.Editfloat4(name, ref value))
|
||||||
|
field.SetData(value);
|
||||||
|
|
||||||
|
case .Double:
|
||||||
|
var value = field.GetData<double>();
|
||||||
|
if (ImGui.DragScalar(name.CStr(), .Double, &value))
|
||||||
|
field.SetData(value);
|
||||||
|
case .Double2:
|
||||||
|
var value = field.GetData<double2>();
|
||||||
|
if (ImGui.DragScalarN(name.CStr(), .Double, &value, 2))
|
||||||
|
field.SetData(value);
|
||||||
|
case .Double3:
|
||||||
|
var value = field.GetData<double3>();
|
||||||
|
if (ImGui.DragScalarN(name.CStr(), .Double, &value, 3))
|
||||||
|
field.SetData(value);
|
||||||
|
case .Double4:
|
||||||
|
var value = field.GetData<double4>();
|
||||||
|
if (ImGui.DragScalarN(name.CStr(), .Double, &value, 4))
|
||||||
|
field.SetData(value);
|
||||||
|
|
||||||
|
case .Enum:
|
||||||
|
// TODO!
|
||||||
|
|
||||||
|
//case .String:
|
||||||
|
// TODO!
|
||||||
|
|
||||||
|
case .Entity:
|
||||||
|
// TODO!
|
||||||
|
|
||||||
|
case .Struct:
|
||||||
|
// TODO!
|
||||||
|
|
||||||
|
default:
|
||||||
|
Log.EngineLogger.Error($"Unhandled field type {field.Type}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
private static void LabelColumn(StringView label)
|
private static void LabelColumn(StringView label)
|
||||||
{
|
{
|
||||||
ImGui.TextUnformatted(label);
|
ImGui.TextUnformatted(label);
|
||||||
@@ -488,10 +795,7 @@ namespace GlitchyEditor.EditWindows
|
|||||||
StringView filePath = fullpath.Substring(0, idx);
|
StringView filePath = fullpath.Substring(0, idx);
|
||||||
StringView meshName = fullpath.Substring(idx + 1);*/
|
StringView meshName = fullpath.Substring(idx + 1);*/
|
||||||
|
|
||||||
using (GeometryBinding geometry = Content.LoadAsset<GeometryBinding>(fullpath))
|
meshComponent.Mesh = Content.LoadAsset(fullpath);
|
||||||
{
|
|
||||||
meshComponent.Mesh = geometry;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: support multiple primitives (treat every primitive as a single mesh? or: mesh can have multiple primitives)
|
// 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))
|
/*using (GeometryBinding binding = ModelLoader.LoadMesh(filePath, meshName, 0))
|
||||||
@@ -557,13 +861,15 @@ namespace GlitchyEditor.EditWindows
|
|||||||
ImGui.Separator();
|
ImGui.Separator();
|
||||||
|
|
||||||
ShowComponentButton<CameraComponent>("Camera");
|
ShowComponentButton<CameraComponent>("Camera");
|
||||||
ShowComponentButton<SpriterRendererComponent>("Sprite Renderer");
|
ShowComponentButton<SpriteRendererComponent>("Sprite Renderer");
|
||||||
|
ShowComponentButton<CircleRendererComponent>("Circle Renderer");
|
||||||
ShowComponentButton<LightComponent>("Light");
|
ShowComponentButton<LightComponent>("Light");
|
||||||
ShowComponentButton<Rigidbody2DComponent>("Rigidbody 2D");
|
ShowComponentButton<Rigidbody2DComponent>("Rigidbody 2D");
|
||||||
ShowComponentButton<BoxCollider2DComponent>("Box collider 2D");
|
ShowComponentButton<BoxCollider2DComponent>("Box collider 2D");
|
||||||
ShowComponentButton<CircleCollider2DComponent>("Circle collider 2D");
|
ShowComponentButton<CircleCollider2DComponent>("Circle collider 2D");
|
||||||
ShowComponentButton<MeshComponent>("Mesh");
|
ShowComponentButton<MeshComponent>("Mesh");
|
||||||
ShowComponentButton<MeshRendererComponent>("Mesh Renderer");
|
ShowComponentButton<MeshRendererComponent>("Mesh Renderer");
|
||||||
|
ShowComponentButton<ScriptComponent>("C# Script");
|
||||||
|
|
||||||
ImGui.EndCombo();
|
ImGui.EndCombo();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,7 @@ namespace GlitchyEditor.EditWindows
|
|||||||
|
|
||||||
class ContentBrowserWindow : EditorWindow
|
class ContentBrowserWindow : EditorWindow
|
||||||
{
|
{
|
||||||
// TODO: Get from project
|
public const String s_WindowTitle = "Content Browser";
|
||||||
//const String ContentDirectory = "./content";
|
|
||||||
|
|
||||||
private append String _currentDirectory = .();
|
private append String _currentDirectory = .();
|
||||||
|
|
||||||
@@ -43,32 +42,76 @@ namespace GlitchyEditor.EditWindows
|
|||||||
_currentDirectory.Set(_manager.ContentDirectory);
|
_currentDirectory.Set(_manager.ContentDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!ImGui.Begin("Content Browser", &_open, .None))
|
if(!ImGui.Begin(s_WindowTitle, &_open, .None))
|
||||||
{
|
{
|
||||||
ImGui.End();
|
ImGui.End();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Context menu when clicking on the background.
|
ImGui.PushStyleVar(.CellPadding, .(0, 0));
|
||||||
if (ImGui.BeginPopupContextWindow())
|
|
||||||
|
bool alt_pressed = ImGui.GetIO().KeyAlt;
|
||||||
|
|
||||||
|
if (ImGui.BeginTable("table", 2, .BordersInnerV | .Resizable | .Reorderable | .NoPadOuterX))
|
||||||
{
|
{
|
||||||
ShowCurrentFolderContextMenu();
|
if (alt_pressed)
|
||||||
ImGui.EndPopup();
|
{
|
||||||
|
// Header anzeigen, damit sie neu angeordnet werden können
|
||||||
|
ImGui.TableSetupColumn("Folder Hierarchy");
|
||||||
|
ImGui.TableSetupColumn("Files");
|
||||||
|
ImGui.TableHeadersRow();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.TableNextRow();
|
||||||
|
ImGui.TableSetColumnIndex(0);
|
||||||
|
|
||||||
|
if (ImGui.BeginChild("Sidebar"))
|
||||||
|
{
|
||||||
|
DrawDirectorySideBar();
|
||||||
|
|
||||||
|
ImGui.EndChild();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
|
||||||
|
DrawSearchBar();
|
||||||
|
|
||||||
|
ImGui.Separator();
|
||||||
|
|
||||||
|
if (ImGui.BeginChild("Files"))
|
||||||
|
{
|
||||||
|
DrawCurrentDirectory();
|
||||||
|
|
||||||
|
// Context menu when clicking on the background.
|
||||||
|
if (ImGui.BeginPopupContextWindow())
|
||||||
|
{
|
||||||
|
ShowCurrentFolderContextMenu();
|
||||||
|
ImGui.EndPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndChild();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.Columns(2);
|
ImGui.PopStyleVar(1);
|
||||||
|
|
||||||
DrawDirectorySideBar();
|
|
||||||
|
|
||||||
ImGui.NextColumn();
|
|
||||||
|
|
||||||
DrawCurrentDirectory();
|
|
||||||
|
|
||||||
ImGui.Columns(1);
|
|
||||||
|
|
||||||
ImGui.End();
|
ImGui.End();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char8[256] _filesFilter = .();
|
||||||
|
bool _searchEverywhere;
|
||||||
|
|
||||||
|
private void DrawSearchBar()
|
||||||
|
{
|
||||||
|
ImGui.TextUnformatted("Search:");
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.InputText("##search", &_filesFilter, _filesFilter.Count);
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.Checkbox("Search everywhere", &_searchEverywhere);
|
||||||
|
}
|
||||||
|
|
||||||
/// Renders the context menu that is shown when the user right clicks on the background of the file browser.
|
/// Renders the context menu that is shown when the user right clicks on the background of the file browser.
|
||||||
private void ShowCurrentFolderContextMenu()
|
private void ShowCurrentFolderContextMenu()
|
||||||
{
|
{
|
||||||
@@ -125,32 +168,74 @@ namespace GlitchyEditor.EditWindows
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Vector2 DirectoryItemSize = .(110, 110);
|
private static float2 DirectoryItemSize = .(110, 110);
|
||||||
|
|
||||||
const Vector2 padding = .(24, 24);
|
const float2 padding = .(24, 24);
|
||||||
|
|
||||||
/// Renders the contents of _currentDirectory.
|
/// Renders the contents of _currentDirectory.
|
||||||
private void DrawCurrentDirectory()
|
private void DrawCurrentDirectory()
|
||||||
{
|
{
|
||||||
if (_currentDirectory.IsEmpty)
|
List<TreeNode<AssetNode>> files = null;
|
||||||
return;
|
|
||||||
|
|
||||||
ImGui.Style* style = ImGui.GetStyle();
|
ImGui.Style* style = ImGui.GetStyle();
|
||||||
|
|
||||||
float window_visible_x2 = ImGui.GetWindowPos().x + ImGui.GetWindowContentRegionMax().x;
|
float window_visible_x2 = ImGui.GetWindowPos().x + ImGui.GetWindowContentRegionMax().x;
|
||||||
|
|
||||||
// Get the node of the current directory.
|
StringView searchFilter = StringView(&_filesFilter);
|
||||||
var currentDirectoryNode = _manager.AssetHierarchy.GetNodeFromPath(_currentDirectory);
|
|
||||||
|
|
||||||
if (currentDirectoryNode case .Err)
|
if (_searchEverywhere && searchFilter.Length > 0)
|
||||||
{
|
{
|
||||||
Log.EngineLogger.Error($"No node exists for {_currentDirectory}.");
|
files = scope:: List<TreeNode<AssetNode>>();
|
||||||
ImGui.TextUnformatted("Failed to display contents of directory.");
|
_manager.AssetHierarchy.[Friend]_assetHierarchy.ForEach(scope (node) =>
|
||||||
return;
|
{
|
||||||
|
if (node->Name.Contains(searchFilter, true))
|
||||||
|
{
|
||||||
|
files.Add(node);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_currentDirectory.IsEmpty)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Get the node of the current directory.
|
||||||
|
var currentDirectoryNode = _manager.AssetHierarchy.GetNodeFromPath(_currentDirectory);
|
||||||
|
|
||||||
|
if (currentDirectoryNode case .Err)
|
||||||
|
{
|
||||||
|
Log.EngineLogger.Error($"No node exists for {_currentDirectory}.");
|
||||||
|
ImGui.TextUnformatted("Failed to display contents of directory.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
files = currentDirectoryNode->Children;
|
||||||
|
|
||||||
|
// show back button (".."-File)
|
||||||
|
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)
|
for (var entry in files)
|
||||||
{
|
{
|
||||||
|
if (!entry->Name.Contains(searchFilter, true))
|
||||||
|
continue;
|
||||||
|
|
||||||
ImGui.PushID(entry->Name);
|
ImGui.PushID(entry->Name);
|
||||||
|
|
||||||
DrawDirectoryItem(entry);
|
DrawDirectoryItem(entry);
|
||||||
@@ -161,13 +246,52 @@ namespace GlitchyEditor.EditWindows
|
|||||||
float expectedButtonRight = currentButtonRight + style.ItemSpacing.x + DirectoryItemSize.X;
|
float expectedButtonRight = currentButtonRight + style.ItemSpacing.x + DirectoryItemSize.X;
|
||||||
|
|
||||||
// If we aren't the last entry and the next button won't fit on the same line we start a new line.
|
// If we aren't the last entry and the next button won't fit on the same line we start a new line.
|
||||||
if (entry != currentDirectoryNode->Children.Back && expectedButtonRight < window_visible_x2)
|
if (entry != files.Back && expectedButtonRight < window_visible_x2)
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
|
|
||||||
ImGui.PopID();
|
ImGui.PopID();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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.
|
/// Renders the button for the given directory item.
|
||||||
private void DrawDirectoryItem(TreeNode<AssetNode> entry)
|
private void DrawDirectoryItem(TreeNode<AssetNode> entry)
|
||||||
{
|
{
|
||||||
|
|||||||
+58
-54
@@ -9,7 +9,7 @@ using GlitchyEngine.Events;
|
|||||||
|
|
||||||
namespace GlitchyEditor.EditWindows
|
namespace GlitchyEditor.EditWindows
|
||||||
{
|
{
|
||||||
class SceneViewportWindow : EditorWindow
|
class EditorViewportWindow : EditorWindow
|
||||||
{
|
{
|
||||||
public const String s_WindowTitle = "Scene";
|
public const String s_WindowTitle = "Scene";
|
||||||
|
|
||||||
@@ -27,12 +27,14 @@ namespace GlitchyEditor.EditWindows
|
|||||||
private float _angleSnap = 45.0f;
|
private float _angleSnap = 45.0f;
|
||||||
private bool _doSnap = false;
|
private bool _doSnap = false;
|
||||||
|
|
||||||
|
private bool _visible;
|
||||||
|
|
||||||
public uint32 SelectedEntityId {get; private set; }
|
public uint32 SelectedEntityId {get; private set; }
|
||||||
public bool SelectionChanged { get; private set; }
|
public bool SelectionChanged { get; private set; }
|
||||||
|
|
||||||
public Vector2 ViewportSize => (Vector2)_oldViewportSize;
|
public float2 ViewportSize => (float2)_oldViewportSize;
|
||||||
// Occurs when the viewport is resized.
|
// Occurs when the viewport is resized.
|
||||||
public Event<EventHandler<Vector2>> ViewportSizeChanged ~ _.Dispose();
|
public Event<EventHandler<float2>> ViewportSizeChanged ~ _.Dispose();
|
||||||
// Occurs when an entity was clicked.
|
// Occurs when an entity was clicked.
|
||||||
public Event<EventHandler<uint32>> EntityClicked ~ _.Dispose();
|
public Event<EventHandler<uint32>> EntityClicked ~ _.Dispose();
|
||||||
|
|
||||||
@@ -52,6 +54,8 @@ namespace GlitchyEditor.EditWindows
|
|||||||
/// Gets or sets whether the editor functionality (gizmo, picking etc.) is enabled.
|
/// Gets or sets whether the editor functionality (gizmo, picking etc.) is enabled.
|
||||||
public bool EditorMode { get; set; } = true
|
public bool EditorMode { get; set; } = true
|
||||||
|
|
||||||
|
public bool Visible => _visible;
|
||||||
|
|
||||||
public this(Editor editor)
|
public this(Editor editor)
|
||||||
{
|
{
|
||||||
_editor = editor;
|
_editor = editor;
|
||||||
@@ -65,9 +69,13 @@ namespace GlitchyEditor.EditWindows
|
|||||||
if(!ImGui.Begin(s_WindowTitle, &_open, .NoScrollbar | .MenuBar))
|
if(!ImGui.Begin(s_WindowTitle, &_open, .NoScrollbar | .MenuBar))
|
||||||
{
|
{
|
||||||
ImGui.End();
|
ImGui.End();
|
||||||
|
|
||||||
|
_visible = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_visible = true;
|
||||||
|
|
||||||
let viewportSize = ImGui.GetContentRegionAvail();
|
let viewportSize = ImGui.GetContentRegionAvail();
|
||||||
|
|
||||||
if(ImGui.IsWindowHovered() && Input.IsMouseButtonPressing(.RightButton))
|
if(ImGui.IsWindowHovered() && Input.IsMouseButtonPressing(.RightButton))
|
||||||
@@ -78,30 +86,27 @@ namespace GlitchyEditor.EditWindows
|
|||||||
|
|
||||||
_hasFocus = ImGui.IsWindowFocused();
|
_hasFocus = ImGui.IsWindowFocused();
|
||||||
|
|
||||||
if (EditorMode)
|
ShowMenuBar();
|
||||||
|
|
||||||
|
if (_editor.CurrentCamera.[Friend]BindMouse && _hasFocus)
|
||||||
|
WrapMouseInViewport();
|
||||||
|
|
||||||
|
// If we wrapped this frame we weren't hovering because the cursor has to be be out of bounds to wrap
|
||||||
|
_editor.CurrentCamera.AllowMove = _hasFocus && (ImGui.IsWindowHovered() || _wrappedCursor);
|
||||||
|
|
||||||
|
if (_hasFocus && !_editor.CurrentCamera.InUse)
|
||||||
{
|
{
|
||||||
ShowMenuBar();
|
if (Input.IsKeyPressing(.Q))
|
||||||
|
_gizmoType = .TRANSLATE;
|
||||||
if (_editor.CurrentCamera.[Friend]BindMouse && _hasFocus)
|
if (Input.IsKeyPressing(.W))
|
||||||
WrapMouseInViewport();
|
_gizmoType = .ROTATE;
|
||||||
|
if (Input.IsKeyPressing(.E))
|
||||||
|
_gizmoType = .SCALE;
|
||||||
|
|
||||||
// If we wrapped this frame we weren't hovering because the cursor has to be be out of bounds to wrap
|
if (Input.IsKeyPressing(.G))
|
||||||
_editor.CurrentCamera.AllowMove = _hasFocus && (ImGui.IsWindowHovered() || _wrappedCursor);
|
_gizmoMode = .WORLD;
|
||||||
|
if (Input.IsKeyPressing(.L))
|
||||||
if (_hasFocus && !_editor.CurrentCamera.InUse)
|
_gizmoMode = .LOCAL;
|
||||||
{
|
|
||||||
if (Input.IsKeyPressing(.Q))
|
|
||||||
_gizmoType = .TRANSLATE;
|
|
||||||
if (Input.IsKeyPressing(.W))
|
|
||||||
_gizmoType = .ROTATE;
|
|
||||||
if (Input.IsKeyPressing(.E))
|
|
||||||
_gizmoType = .SCALE;
|
|
||||||
|
|
||||||
if (Input.IsKeyPressing(.G))
|
|
||||||
_gizmoMode = .WORLD;
|
|
||||||
if (Input.IsKeyPressing(.L))
|
|
||||||
_gizmoMode = .LOCAL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_renderTarget != null)
|
if(_renderTarget != null)
|
||||||
@@ -111,20 +116,17 @@ namespace GlitchyEditor.EditWindows
|
|||||||
//ImGui.Image(_editor.CurrentScene.[Friend]_compositeTarget.GetViewBinding(0), viewportSize);
|
//ImGui.Image(_editor.CurrentScene.[Friend]_compositeTarget.GetViewBinding(0), viewportSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (EditorMode)
|
HandleDropTarget();
|
||||||
{
|
|
||||||
HandleDropTarget();
|
bool gizmoUsed = DrawImGuizmo(viewportSize);
|
||||||
|
|
||||||
bool gizmoUsed = DrawImGuizmo(viewportSize);
|
MousePicking(viewportSize, gizmoUsed);
|
||||||
|
|
||||||
MousePicking(viewportSize, gizmoUsed);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.End();
|
ImGui.End();
|
||||||
|
|
||||||
if(_oldViewportSize != viewportSize)
|
if(_oldViewportSize != viewportSize)
|
||||||
{
|
{
|
||||||
ViewportSizeChanged.Invoke(this, (Vector2)viewportSize);
|
ViewportSizeChanged.Invoke(this, (float2)viewportSize);
|
||||||
_viewPortChanged = true;
|
_viewPortChanged = true;
|
||||||
_oldViewportSize = viewportSize;
|
_oldViewportSize = viewportSize;
|
||||||
}
|
}
|
||||||
@@ -152,34 +154,36 @@ namespace GlitchyEditor.EditWindows
|
|||||||
{
|
{
|
||||||
_wrappedCursor = false;
|
_wrappedCursor = false;
|
||||||
|
|
||||||
let mousePos = (Vector2)ImGui.GetMousePos();
|
let mousePos = (float2)ImGui.GetMousePos();
|
||||||
let winPos = (Vector2)ImGui.GetWindowPos();
|
let winPos = (float2)ImGui.GetWindowPos();
|
||||||
let regionMin = winPos + (Vector2)ImGui.GetWindowContentRegionMin();
|
let regionMin = winPos + (float2)ImGui.GetWindowContentRegionMin();
|
||||||
let regionMax = winPos + (Vector2)ImGui.GetWindowContentRegionMax();
|
let regionMax = winPos + (float2)ImGui.GetWindowContentRegionMax();
|
||||||
|
|
||||||
Vector2 newMousePos = mousePos;
|
|
||||||
|
|
||||||
if (mousePos.X < regionMin.X)
|
ImGui.DrawRect((.)regionMin, (.)regionMax, .(0, 255, 0));
|
||||||
|
|
||||||
|
float2 newMousePos = mousePos;
|
||||||
|
|
||||||
|
if (mousePos.X < regionMin.X + 1)
|
||||||
{
|
{
|
||||||
newMousePos.X = regionMax.X - 1;
|
newMousePos.X = regionMax.X - 2;
|
||||||
}
|
}
|
||||||
else if (mousePos.X > regionMax.X - 1)
|
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)
|
else if (mousePos.Y > regionMax.Y - 1)
|
||||||
{
|
{
|
||||||
newMousePos.Y = regionMin.Y + 1;
|
newMousePos.Y = regionMin.Y + 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newMousePos != mousePos)
|
if (any(newMousePos != mousePos))
|
||||||
{
|
{
|
||||||
Input.SetMousePosition((Int2)newMousePos);
|
Input.SetMousePosition((int2)newMousePos);
|
||||||
// After wrapping the cursor the the other side, the camera controller must not compare the positions,
|
// After wrapping the cursor the the other side, the camera controller must not compare the positions,
|
||||||
// because the delta doesn't represent the correct movement of the cursor.
|
// because the delta doesn't represent the correct movement of the cursor.
|
||||||
// TODO: can be solved by using direct mouse movement instead of comparing positions
|
// TODO: can be solved by using direct mouse movement instead of comparing positions
|
||||||
@@ -191,10 +195,10 @@ namespace GlitchyEditor.EditWindows
|
|||||||
/// If the user clicks, the entity beneath the cursor will be selected.
|
/// If the user clicks, the entity beneath the cursor will be selected.
|
||||||
private void MousePicking(ImGui.Vec2 viewportSize, bool gizmoUsed)
|
private void MousePicking(ImGui.Vec2 viewportSize, bool gizmoUsed)
|
||||||
{
|
{
|
||||||
Vector2 relativeMouse = (Vector2)ImGui.GetMousePos() - (Vector2)ImGui.GetItemRectMin();
|
float2 relativeMouse = (float2)ImGui.GetMousePos() - (float2)ImGui.GetItemRectMin();
|
||||||
|
|
||||||
int rtWidth = _editor.CurrentScene.[Friend]_compositeTarget.Width;
|
int rtWidth = _editor.EditorSceneRenderer.CompositeTarget.Width;
|
||||||
int rtHeight = _editor.CurrentScene.[Friend]_compositeTarget.Height;
|
int rtHeight = _editor.EditorSceneRenderer.CompositeTarget.Height;
|
||||||
|
|
||||||
if (Input.IsMouseButtonPressing(.LeftButton) &&
|
if (Input.IsMouseButtonPressing(.LeftButton) &&
|
||||||
ImGui.IsWindowHovered() && !gizmoUsed && !_editor.CurrentCamera.InUse &&
|
ImGui.IsWindowHovered() && !gizmoUsed && !_editor.CurrentCamera.InUse &&
|
||||||
@@ -204,7 +208,7 @@ namespace GlitchyEditor.EditWindows
|
|||||||
{
|
{
|
||||||
uint32 id = uint32.MaxValue;
|
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;
|
SelectionChanged = true;
|
||||||
SelectedEntityId = id;
|
SelectedEntityId = id;
|
||||||
@@ -312,9 +316,9 @@ namespace GlitchyEditor.EditWindows
|
|||||||
parentView = parentTransformCmp.WorldTransform.Invert();
|
parentView = parentTransformCmp.WorldTransform.Invert();
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 snap = .(_snap);
|
float3 snap = (float3)_snap;
|
||||||
if (_gizmoType.HasFlag(.ROTATE))
|
if (_gizmoType.HasFlag(.ROTATE))
|
||||||
snap = .(_angleSnap);
|
snap = (float3)_angleSnap;
|
||||||
|
|
||||||
if (ImGuizmo.Manipulate((.)&view, (.)&projection, _gizmoType, _gizmoMode, (.)&worldTransform, null, _doSnap ? (.)&snap : null))
|
if (ImGuizmo.Manipulate((.)&view, (.)&projection, _gizmoType, _gizmoMode, (.)&worldTransform, null, _doSnap ? (.)&snap : null))
|
||||||
{
|
{
|
||||||
@@ -301,11 +301,11 @@ namespace GlitchyEditor.EditWindows
|
|||||||
{
|
{
|
||||||
String name = null;
|
String name = null;
|
||||||
|
|
||||||
var nameComponent = tree.Value.GetComponent<DebugNameComponent>();
|
var nameComponent = tree.Value.GetComponent<NameComponent>();
|
||||||
|
|
||||||
if(nameComponent != null)
|
if(nameComponent != null)
|
||||||
{
|
{
|
||||||
name = nameComponent.DebugName;
|
name = scope:: .(nameComponent.Name);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -501,13 +501,13 @@ namespace GlitchyEditor.EditWindows
|
|||||||
{
|
{
|
||||||
Entity entity = .(entityId, _scene);
|
Entity entity = .(entityId, _scene);
|
||||||
|
|
||||||
String name = null;
|
StringView name = null;
|
||||||
|
|
||||||
var nameComponent = entity.GetComponent<DebugNameComponent>();
|
var nameComponent = entity.GetComponent<NameComponent>();
|
||||||
|
|
||||||
if(nameComponent != null)
|
if(nameComponent != null)
|
||||||
{
|
{
|
||||||
name = nameComponent.DebugName;
|
name = nameComponent.Name;
|
||||||
}
|
}
|
||||||
else
|
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 float2 ViewportSize => (float2)_oldViewportSize;
|
||||||
|
// Occurs when the viewport is resized.
|
||||||
|
public Event<EventHandler<float2>> 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, (float2)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
|
class PropertiesWindow : EditorWindow
|
||||||
{
|
{
|
||||||
|
public const String s_WindowTitle = "Properties";
|
||||||
|
|
||||||
private AssetPropertiesEditor _currentPropertiesEditor ~ delete _;
|
private AssetPropertiesEditor _currentPropertiesEditor ~ delete _;
|
||||||
|
|
||||||
private bool _lockCurrentAsset;
|
private bool _lockCurrentAsset;
|
||||||
@@ -18,7 +20,7 @@ class PropertiesWindow : EditorWindow
|
|||||||
|
|
||||||
private append String _selectedFileName = .();
|
private append String _selectedFileName = .();
|
||||||
|
|
||||||
private Asset _currentAsset ~ _?.ReleaseRef();
|
private AssetHandle _currentAssetHandle;
|
||||||
|
|
||||||
public this(Editor editor)
|
public this(Editor editor)
|
||||||
{
|
{
|
||||||
@@ -28,7 +30,7 @@ class PropertiesWindow : EditorWindow
|
|||||||
protected override void InternalShow()
|
protected override void InternalShow()
|
||||||
{
|
{
|
||||||
defer { ImGui.End(); }
|
defer { ImGui.End(); }
|
||||||
if(!ImGui.Begin("Properties", &_open, .None))
|
if(!ImGui.Begin(s_WindowTitle, &_open, .None))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// TODO: make a little button in title bar?
|
// TODO: make a little button in title bar?
|
||||||
@@ -73,12 +75,13 @@ class PropertiesWindow : EditorWindow
|
|||||||
|
|
||||||
if (assetFile == null)
|
if (assetFile == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
Asset asset = _editor.ContentManager.GetAsset(null, _currentAssetHandle);
|
||||||
|
|
||||||
// We need the actual asset for preview and sometimes for editing
|
// We need the actual asset for preview and sometimes for editing
|
||||||
if (_currentAsset?.Identifier != assetFile.Identifier)
|
if (asset?.Identifier != assetFile.Identifier)
|
||||||
{
|
{
|
||||||
_currentAsset?.ReleaseRef();
|
_currentAssetHandle = _editor.ContentManager.LoadAsset(assetFile.Identifier);
|
||||||
_currentAsset = _editor.ContentManager.LoadAsset(assetFile.Identifier);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: allow changing AssetLoader
|
// TODO: allow changing AssetLoader
|
||||||
@@ -106,7 +109,8 @@ class PropertiesWindow : EditorWindow
|
|||||||
|
|
||||||
if (ImGui.Button("Save Asset"))
|
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)
|
if (!assetFile.AssetConfig.Config.Changed)
|
||||||
|
|||||||
@@ -17,15 +17,20 @@ namespace GlitchyEditor
|
|||||||
|
|
||||||
private EntityHierarchyWindow _entityHierarchyWindow ~ delete _;
|
private EntityHierarchyWindow _entityHierarchyWindow ~ delete _;
|
||||||
private ComponentEditWindow _componentEditWindow ~ delete _;
|
private ComponentEditWindow _componentEditWindow ~ delete _;
|
||||||
private SceneViewportWindow _sceneViewportWindow~ delete _;
|
private EditorViewportWindow _sceneViewportWindow ~ delete _;
|
||||||
|
private GameViewportWindow _gameViewportWindow ~ delete _;
|
||||||
private ContentBrowserWindow _contentBrowserWindow ~ delete _;
|
private ContentBrowserWindow _contentBrowserWindow ~ delete _;
|
||||||
private PropertiesWindow _propertiesWindow ~ delete _;
|
private PropertiesWindow _propertiesWindow ~ delete _;
|
||||||
|
private AssetViewer _assetViewer ~ delete _;
|
||||||
|
|
||||||
public Scene CurrentScene
|
public Scene CurrentScene
|
||||||
{
|
{
|
||||||
get => _scene;
|
get => _scene;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
|
if (_scene == value)
|
||||||
|
return;
|
||||||
|
|
||||||
_scene = value;
|
_scene = value;
|
||||||
_entityHierarchyWindow.SetContext(_scene);
|
_entityHierarchyWindow.SetContext(_scene);
|
||||||
}
|
}
|
||||||
@@ -35,14 +40,19 @@ namespace GlitchyEditor
|
|||||||
|
|
||||||
public EntityHierarchyWindow EntityHierarchyWindow => _entityHierarchyWindow;
|
public EntityHierarchyWindow EntityHierarchyWindow => _entityHierarchyWindow;
|
||||||
public ComponentEditWindow ComponentEditWindow => _componentEditWindow;
|
public ComponentEditWindow ComponentEditWindow => _componentEditWindow;
|
||||||
public SceneViewportWindow SceneViewportWindow => _sceneViewportWindow;
|
public EditorViewportWindow SceneViewportWindow => _sceneViewportWindow;
|
||||||
|
public GameViewportWindow GameViewportWindow => _gameViewportWindow;
|
||||||
public ContentBrowserWindow ContentBrowserWindow => _contentBrowserWindow;
|
public ContentBrowserWindow ContentBrowserWindow => _contentBrowserWindow;
|
||||||
public PropertiesWindow PropertiesWindow => _propertiesWindow;
|
public PropertiesWindow PropertiesWindow => _propertiesWindow;
|
||||||
|
public AssetViewer AssetViewer => _assetViewer;
|
||||||
|
|
||||||
public EditorCamera* CurrentCamera { get; set; }
|
public EditorCamera* CurrentCamera { get; set; }
|
||||||
|
|
||||||
public Event<EventHandler<StringView>> RequestOpenScene ~ _.Dispose();
|
public Event<EventHandler<StringView>> RequestOpenScene ~ _.Dispose();
|
||||||
|
|
||||||
|
public SceneRenderer GameSceneRenderer {get; set;}
|
||||||
|
public SceneRenderer EditorSceneRenderer {get; set;}
|
||||||
|
|
||||||
/// Creates a new editor for the given world
|
/// Creates a new editor for the given world
|
||||||
public this(Scene scene, EditorContentManager contentManager)
|
public this(Scene scene, EditorContentManager contentManager)
|
||||||
{
|
{
|
||||||
@@ -54,20 +64,24 @@ namespace GlitchyEditor
|
|||||||
|
|
||||||
private void InitWindows()
|
private void InitWindows()
|
||||||
{
|
{
|
||||||
_sceneViewportWindow = new SceneViewportWindow(this);
|
_sceneViewportWindow = new EditorViewportWindow(this);
|
||||||
|
_gameViewportWindow = new GameViewportWindow(this);
|
||||||
_entityHierarchyWindow = new EntityHierarchyWindow(this, _scene);
|
_entityHierarchyWindow = new EntityHierarchyWindow(this, _scene);
|
||||||
_componentEditWindow = new ComponentEditWindow(_entityHierarchyWindow);
|
_componentEditWindow = new ComponentEditWindow(_entityHierarchyWindow);
|
||||||
_contentBrowserWindow = new ContentBrowserWindow((.)Application.Get().ContentManager);
|
_contentBrowserWindow = new ContentBrowserWindow((.)Application.Get().ContentManager);
|
||||||
_propertiesWindow = new PropertiesWindow(this);
|
_propertiesWindow = new PropertiesWindow(this);
|
||||||
|
_assetViewer = new AssetViewer((.)Application.Get().ContentManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update()
|
public void Update()
|
||||||
{
|
{
|
||||||
_sceneViewportWindow.Show();
|
_sceneViewportWindow.Show();
|
||||||
|
_gameViewportWindow.Show();
|
||||||
_entityHierarchyWindow.Show();
|
_entityHierarchyWindow.Show();
|
||||||
_componentEditWindow.Show();
|
_componentEditWindow.Show();
|
||||||
_contentBrowserWindow.Show();
|
_contentBrowserWindow.Show();
|
||||||
_propertiesWindow.Show();
|
_propertiesWindow.Show();
|
||||||
|
_assetViewer.Show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ namespace GlitchyEditor
|
|||||||
{
|
{
|
||||||
EditorContentManager _contentManager;
|
EditorContentManager _contentManager;
|
||||||
|
|
||||||
public this()
|
public this(String[] args)
|
||||||
{
|
{
|
||||||
PushLayer(new EditorLayer(_contentManager));
|
PushLayer(new EditorLayer(args, _contentManager));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override IContentManager InitContentManager()
|
protected override IContentManager InitContentManager()
|
||||||
@@ -39,9 +39,9 @@ namespace GlitchyEditor
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Export, LinkName("CreateApplication")]
|
[Export, LinkName("CreateApplication")]
|
||||||
public static Application CreateApplication()
|
public static Application CreateApplication(String[] args)
|
||||||
{
|
{
|
||||||
return new EditorApp();
|
return new EditorApp(args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,71 +8,11 @@ using GlitchyEngine.Content;
|
|||||||
using GlitchyEditor.Assets;
|
using GlitchyEditor.Assets;
|
||||||
using GlitchyEngine;
|
using GlitchyEngine;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using internal GlitchyEngine.Content.Asset;
|
||||||
|
|
||||||
namespace GlitchyEditor;
|
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
|
class EditorContentManager : IContentManager
|
||||||
{
|
{
|
||||||
private append String _contentDirectory = .();
|
private append String _contentDirectory = .();
|
||||||
@@ -81,15 +21,20 @@ class EditorContentManager : IContentManager
|
|||||||
|
|
||||||
//private append List<String> _identifiers = .() ~ _.ClearAndDeleteItems();
|
//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);
|
private append AssetHierarchy _assetHierarchy = .(this);
|
||||||
|
|
||||||
public AssetHierarchy AssetHierarchy => _assetHierarchy;
|
public AssetHierarchy AssetHierarchy => _assetHierarchy;
|
||||||
|
|
||||||
|
private append List<AssetHandle> _reloadQueue = .();
|
||||||
|
|
||||||
public this()
|
public this()
|
||||||
{
|
{
|
||||||
_assetHierarchy.OnFileContentChanged.Add(new => OnFileContentChanged);
|
_assetHierarchy.OnFileContentChanged.Add(new => OnFileContentChanged);
|
||||||
|
_assetHierarchy.OnFileRenamed.Add(new => OnFileRenamed);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ~this()
|
public ~this()
|
||||||
@@ -99,46 +44,24 @@ class EditorContentManager : IContentManager
|
|||||||
|
|
||||||
private void OnFileContentChanged(AssetNode assetNode)
|
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.
|
// Asset isn't loaded so we don't need to reload it.
|
||||||
if (assetNode.AssetFile.LoadedAsset == null)
|
if (assetNode.AssetFile.LoadedAsset == null)
|
||||||
return;
|
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;
|
return;
|
||||||
|
|
||||||
IAssetLoader assetLoader = null;
|
Asset asset = assetNode.AssetFile.LoadedAsset;
|
||||||
|
|
||||||
String loaderNameBuffer = scope String(64);
|
_identiferToHandle.Remove(oldIdentifier);
|
||||||
|
asset.Identifier = assetNode.AssetFile.Identifier;
|
||||||
for (IAssetLoader loader in _assetLoaders)
|
_identiferToHandle.Add(asset.Identifier, asset.Handle);
|
||||||
{
|
|
||||||
loader.GetType().GetName(loaderNameBuffer..Clear());
|
|
||||||
|
|
||||||
if (loaderNameBuffer == neededAssetLoaderName)
|
|
||||||
{
|
|
||||||
assetLoader = loader;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (assetLoader == null)
|
|
||||||
{
|
|
||||||
Log.EngineLogger.Error($"Could not find asset loader \"{neededAssetLoaderName}\"");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (var assetReloader = assetLoader as IReloadingAssetLoader)
|
|
||||||
{
|
|
||||||
Stream stream = GetStream(assetNode.Path);
|
|
||||||
|
|
||||||
assetReloader.ReloadAsset(assetNode.AssetFile, stream);
|
|
||||||
|
|
||||||
delete stream;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetContentDirectory(StringView contentDirectory)
|
public void SetContentDirectory(StringView contentDirectory)
|
||||||
@@ -152,9 +75,54 @@ class EditorContentManager : IContentManager
|
|||||||
|
|
||||||
public void Update()
|
public void Update()
|
||||||
{
|
{
|
||||||
|
SwapInLoadedAssets();
|
||||||
|
|
||||||
|
if (!_reloadQueue.IsEmpty)
|
||||||
|
{
|
||||||
|
for (AssetHandle handle in _reloadQueue)
|
||||||
|
{
|
||||||
|
ReloadAsset(handle);
|
||||||
|
}
|
||||||
|
_reloadQueue.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
_assetHierarchy.Update();
|
_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)
|
public IAssetLoader GetDefaultAssetLoader(StringView fileExtension)
|
||||||
{
|
{
|
||||||
if (_defaultAssetLoaders.TryGetValue(fileExtension, let value))
|
if (_defaultAssetLoaders.TryGetValue(fileExtension, let value))
|
||||||
@@ -174,9 +142,11 @@ class EditorContentManager : IContentManager
|
|||||||
|
|
||||||
public void RegisterAssetLoader<T>() where T : new, class, IAssetLoader
|
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)
|
for (StringView ext in T.FileExtensions)
|
||||||
_supportedExtensions.Add(new String(ext));
|
_supportedExtensions.Add(new String(ext));
|
||||||
@@ -237,99 +207,230 @@ class EditorContentManager : IContentManager
|
|||||||
|
|
||||||
public bool IsLoaded(StringView identifier)
|
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
|
if (assetType == null)
|
||||||
int poundIndex = identifier.IndexOf('#');
|
{
|
||||||
|
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);
|
return null;
|
||||||
StringView? subassetName = identifier.Substring(poundIndex + 1);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String filePath = scope String(resourceName.Length + _contentDirectory.Length + 2);
|
private void ReloadAsset(AssetHandle handle)
|
||||||
Path.Combine(filePath, _contentDirectory, resourceName);
|
{
|
||||||
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
|
||||||
|
Asset oldAsset = null;
|
||||||
|
|
||||||
Path.Fixup(filePath);
|
if (!_handleToAsset.TryGetValue(handle, out oldAsset))
|
||||||
|
{
|
||||||
|
Log.EngineLogger.Error("Can't reload! No asset exists for handle.");
|
||||||
|
|
||||||
//filePath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
|
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);
|
Result<TreeNode<AssetNode>> resultNode = AssetHierarchy.GetNodeFromPath(filePath);
|
||||||
|
|
||||||
if (resultNode case .Err)
|
if (resultNode case .Err)
|
||||||
{
|
{
|
||||||
Log.EngineLogger.Error($"Could not find asset \"{filePath}\".");
|
Log.EngineLogger.Error($"Could not find asset \"{filePath}\".");
|
||||||
return null;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AssetFile file = resultNode->Value.AssetFile;
|
AssetFile file = resultNode->Value.AssetFile;
|
||||||
|
|
||||||
IAssetLoader assetLoader = null;
|
IAssetLoader assetLoader = GetAssetLoader(file);
|
||||||
|
|
||||||
String loaderTypeName = scope .(128);
|
|
||||||
|
|
||||||
for (IAssetLoader loader in _assetLoaders)
|
|
||||||
{
|
|
||||||
loader.GetType().GetName(loaderTypeName..Clear());
|
|
||||||
|
|
||||||
if (loaderTypeName == file.AssetConfig.AssetLoader)
|
|
||||||
{
|
|
||||||
assetLoader = loader;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.EngineLogger.AssertDebug(assetLoader != null);
|
|
||||||
|
|
||||||
Stream stream = GetStream(filePath);
|
Stream stream = GetStream(filePath);
|
||||||
|
|
||||||
|
// TODO: Add async loading!
|
||||||
Asset loadedAsset = assetLoader.LoadAsset(stream, file.AssetConfig.Config, resourceName, subassetName, this);
|
Asset loadedAsset = assetLoader.LoadAsset(stream, file.AssetConfig.Config, resourceName, subassetName, this);
|
||||||
|
|
||||||
delete stream;
|
delete stream;
|
||||||
|
|
||||||
if (loadedAsset == null)
|
if (loadedAsset == null)
|
||||||
return null;
|
return;
|
||||||
|
|
||||||
//String identifierString = new .(identifier);
|
|
||||||
//_identifiers.Add(identifierString);
|
|
||||||
|
|
||||||
//_loadedAssets[identifierString] = loadedAsset;
|
|
||||||
|
|
||||||
|
|
||||||
loadedAsset.Identifier = identifier;
|
|
||||||
ManageAsset(loadedAsset);
|
|
||||||
|
|
||||||
file.[Friend]_loadedAsset = loadedAsset;
|
file.[Friend]_loadedAsset = loadedAsset;
|
||||||
|
|
||||||
return loadedAsset;
|
SwapAsset(oldAsset, loadedAsset);
|
||||||
|
// SwapAsset increases RefCount, but this scope also holds a reference.
|
||||||
|
loadedAsset.ReleaseRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Saves the asset.
|
/// Returns the resource name and, if it exists, the subasset name.
|
||||||
public Result<void> SaveAsset(Asset asset)
|
private void GetResourceAndSubassetName(StringView identifier, out StringView resourceName, out StringView? subassetName)
|
||||||
{
|
{
|
||||||
// Find subasset name
|
int poundIndex = identifier.IndexOf('#');
|
||||||
int poundIndex = asset.Identifier.IndexOf('#');
|
|
||||||
|
|
||||||
StringView resourceName = poundIndex == -1 ? asset.Identifier : asset.Identifier.Substring(0, poundIndex);
|
resourceName = (poundIndex != -1) ? identifier.Substring(0, poundIndex) : identifier;
|
||||||
StringView? subassetName = asset.Identifier.Substring(poundIndex + 1);
|
subassetName = (poundIndex != -1) ? identifier.Substring(poundIndex + 1) : null;
|
||||||
|
}
|
||||||
|
|
||||||
String filePath = scope String(resourceName.Length + _contentDirectory.Length + 2);
|
private void GetResourceFilePath(StringView resourceName, String filePath)
|
||||||
|
{
|
||||||
Path.Combine(filePath, _contentDirectory, resourceName);
|
Path.Combine(filePath, _contentDirectory, resourceName);
|
||||||
|
|
||||||
Path.Fixup(filePath);
|
Path.Fixup(filePath);
|
||||||
|
}
|
||||||
|
|
||||||
//filePath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
|
private enum PlaceholderType
|
||||||
|
{
|
||||||
|
Loading,
|
||||||
|
Error
|
||||||
|
}
|
||||||
|
|
||||||
TreeNode<AssetNode> assetNode = Try!(AssetHierarchy.GetNodeFromPath(filePath));
|
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!();
|
||||||
|
|
||||||
AssetFile file = assetNode->AssetFile;
|
// 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;
|
||||||
|
|
||||||
|
using (_finishedEntriesLock.Enter())
|
||||||
|
{
|
||||||
|
_finishedEntries.Add((placeholder, loadedAsset));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the asset loader that has to be used for the given file.
|
||||||
|
IAssetLoader GetAssetLoader(AssetFile file)
|
||||||
|
{
|
||||||
IAssetLoader assetLoader = null;
|
IAssetLoader assetLoader = null;
|
||||||
|
|
||||||
String loaderTypeName = scope .(128);
|
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;
|
IAssetSaver assetSaver = assetLoader as IAssetSaver;
|
||||||
|
|
||||||
if (assetSaver == null)
|
if (assetSaver == null)
|
||||||
{
|
{
|
||||||
Log.EngineLogger.Error("The asset loader can't save!");
|
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);
|
assetSaver.EditorSaveAsset(stream, asset, file.AssetConfig.Config, resourceName, subassetName, this);
|
||||||
|
|
||||||
|
// Trim off the end of the file.
|
||||||
|
stream.SetLength(stream.Position);
|
||||||
|
|
||||||
delete stream;
|
delete stream;
|
||||||
|
|
||||||
return .Ok;
|
return .Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Stream OpenStream(StringView assetIdentifier, bool openOnly, bool truncate = false)
|
private Stream OpenStream(StringView assetIdentifier, bool openOnly)
|
||||||
{
|
{
|
||||||
var assetIdentifier;
|
var assetIdentifier;
|
||||||
|
|
||||||
@@ -378,9 +522,6 @@ class EditorContentManager : IContentManager
|
|||||||
|
|
||||||
FileMode fileMode = openOnly ? FileMode.Open : FileMode.OpenOrCreate;
|
FileMode fileMode = openOnly ? FileMode.Open : FileMode.OpenOrCreate;
|
||||||
|
|
||||||
if (truncate)
|
|
||||||
fileMode |= .Truncate;
|
|
||||||
|
|
||||||
var result = fs.Open(assetIdentifier, fileMode, openOnly ? .Read : .ReadWrite, .ReadWrite);
|
var result = fs.Open(assetIdentifier, fileMode, openOnly ? .Read : .ReadWrite, .ReadWrite);
|
||||||
|
|
||||||
if (result case .Err)
|
if (result case .Err)
|
||||||
@@ -413,37 +554,86 @@ class EditorContentManager : IContentManager
|
|||||||
return fs;*/
|
return fs;*/
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ManageAsset(Asset asset)
|
public AssetHandle ManageAsset(Asset asset)
|
||||||
{
|
{
|
||||||
_loadedAssets.Add(asset.Identifier, asset);
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
//_handles.Add(asset.Identifier, handle);
|
||||||
|
_handleToAsset.Add(handle, asset);
|
||||||
|
|
||||||
asset.[Friend]_contentManager = this;
|
asset.[Friend]_contentManager = this;
|
||||||
|
asset.[Friend]_handle = handle;
|
||||||
|
asset.AddRef();
|
||||||
|
|
||||||
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UnmanageAsset(Asset asset)
|
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.[Friend]_contentManager = null;
|
||||||
|
|
||||||
|
asset.ReleaseRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This will unregister all assets from this content manager.
|
/// This will unregister all assets from this content manager.
|
||||||
/// Note: This will not release any assets.
|
/// Note: This will not release any assets.
|
||||||
private void UnmanageAllAssets()
|
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)
|
if (oldIdentifier == newIdentifier)
|
||||||
return;
|
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.
|
// 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);
|
//UnmanageAsset(asset);
|
||||||
ManageAsset(asset);
|
//ManageAsset(asset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,12 +2,13 @@ using System;
|
|||||||
using GlitchyEngine.Renderer;
|
using GlitchyEngine.Renderer;
|
||||||
using GlitchyEngine.Math;
|
using GlitchyEngine.Math;
|
||||||
using GlitchyEngine;
|
using GlitchyEngine;
|
||||||
|
using GlitchyEngine.Content;
|
||||||
|
|
||||||
namespace GlitchyEditor
|
namespace GlitchyEditor
|
||||||
{
|
{
|
||||||
class EditorIcons : RefCounted
|
class EditorIcons : RefCounted
|
||||||
{
|
{
|
||||||
Texture2D _texture ~ _.ReleaseRef();
|
AssetHandle<Texture2D> _texture;
|
||||||
|
|
||||||
public SubTexture2D DirectionalLight ~ _.ReleaseRef();
|
public SubTexture2D DirectionalLight ~ _.ReleaseRef();
|
||||||
public SubTexture2D Camera ~ _.ReleaseRef();
|
public SubTexture2D Camera ~ _.ReleaseRef();
|
||||||
@@ -15,18 +16,21 @@ namespace GlitchyEditor
|
|||||||
public SubTexture2D File ~ _.ReleaseRef();
|
public SubTexture2D File ~ _.ReleaseRef();
|
||||||
public SubTexture2D Play ~ _.ReleaseRef();
|
public SubTexture2D Play ~ _.ReleaseRef();
|
||||||
public SubTexture2D Stop ~ _.ReleaseRef();
|
public SubTexture2D Stop ~ _.ReleaseRef();
|
||||||
|
public SubTexture2D Simulate ~ _.ReleaseRef();
|
||||||
|
public SubTexture2D Pause ~ _.ReleaseRef();
|
||||||
|
public SubTexture2D SingleStep ~ _.ReleaseRef();
|
||||||
|
|
||||||
public SamplerState SamplerState
|
public SamplerState SamplerState
|
||||||
{
|
{
|
||||||
get => _texture.SamplerState;
|
get => _texture.Get().SamplerState;
|
||||||
set => _texture.SamplerState = value;
|
set => _texture.Get().SamplerState = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public this(String texturePath, Vector2 iconSize)
|
public this(String texturePath, float2 iconSize)
|
||||||
{
|
{
|
||||||
_texture = Content.LoadAsset<Texture2D>(texturePath);//new Texture2D(texturePath);
|
_texture = Content.LoadAsset(texturePath, null, true);
|
||||||
|
|
||||||
Vector2 pen = .();
|
float2 pen = .();
|
||||||
|
|
||||||
DirectionalLight = GetNextGridTexture(ref pen, iconSize);
|
DirectionalLight = GetNextGridTexture(ref pen, iconSize);
|
||||||
Camera = GetNextGridTexture(ref pen, iconSize);
|
Camera = GetNextGridTexture(ref pen, iconSize);
|
||||||
@@ -34,9 +38,12 @@ namespace GlitchyEditor
|
|||||||
File = GetNextGridTexture(ref pen, iconSize);
|
File = GetNextGridTexture(ref pen, iconSize);
|
||||||
Play = GetNextGridTexture(ref pen, iconSize);
|
Play = GetNextGridTexture(ref pen, iconSize);
|
||||||
Stop = GetNextGridTexture(ref pen, iconSize);
|
Stop = GetNextGridTexture(ref pen, iconSize);
|
||||||
|
Simulate = GetNextGridTexture(ref pen, iconSize);
|
||||||
|
Pause = GetNextGridTexture(ref pen, iconSize);
|
||||||
|
SingleStep = GetNextGridTexture(ref pen, iconSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SubTexture2D GetNextGridTexture(ref Vector2 pen, Vector2 iconSize)
|
private SubTexture2D GetNextGridTexture(ref float2 pen, float2 iconSize)
|
||||||
{
|
{
|
||||||
SubTexture2D subTexture = .CreateFromGrid(_texture, pen, iconSize);
|
SubTexture2D subTexture = .CreateFromGrid(_texture, pen, iconSize);
|
||||||
|
|
||||||
|
|||||||
+487
-282
@@ -13,106 +13,115 @@ using GlitchyEngine.Renderer.Animation;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using GlitchyEngine.Core;
|
using GlitchyEngine.Core;
|
||||||
using GlitchyEditor.Assets;
|
using GlitchyEditor.Assets;
|
||||||
|
using GlitchyEngine.Scripting;
|
||||||
|
|
||||||
namespace GlitchyEditor
|
namespace GlitchyEditor
|
||||||
{
|
{
|
||||||
class EditorLayer : Layer
|
class EditorLayer : Layer
|
||||||
{
|
{
|
||||||
|
enum SceneState
|
||||||
|
{
|
||||||
|
Edit,
|
||||||
|
Play,
|
||||||
|
Simulate
|
||||||
|
}
|
||||||
|
|
||||||
RasterizerState _rasterizerState ~ _?.ReleaseRef();
|
RasterizerState _rasterizerState ~ _?.ReleaseRef();
|
||||||
RasterizerState _rasterizerStateClockWise ~ _?.ReleaseRef();
|
RasterizerState _rasterizerStateClockWise ~ _?.ReleaseRef();
|
||||||
|
|
||||||
|
// TODO: we shouldn't hold a reference to the context
|
||||||
GraphicsContext _context ~ _.ReleaseRef();
|
GraphicsContext _context ~ _.ReleaseRef();
|
||||||
|
|
||||||
BlendState _alphaBlendState ~ _.ReleaseRef();
|
BlendState _alphaBlendState ~ _.ReleaseRef();
|
||||||
BlendState _opaqueBlendState ~ _.ReleaseRef();
|
BlendState _opaqueBlendState ~ _.ReleaseRef();
|
||||||
DepthStencilState _depthStencilState ~ _.ReleaseRef();
|
DepthStencilState _depthStencilState ~ _.ReleaseRef();
|
||||||
|
|
||||||
Scene _scene ~ delete _;
|
|
||||||
String _sceneFilePath = new String() ~ delete _;
|
|
||||||
|
|
||||||
public String SceneFilePath
|
/// Reference to the scene that is currently being played and worked on.
|
||||||
|
Scene _activeScene ~ _?.ReleaseRef();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
bool _singleStep = false;
|
||||||
|
|
||||||
|
private float _fixedTimestep = 1.0f / 60.0f;
|
||||||
|
|
||||||
|
append List<(String Name, String Path)> _recentProjectPaths = .() ~ {
|
||||||
|
for (var item in _)
|
||||||
|
{
|
||||||
|
delete item.Name;
|
||||||
|
delete item.Path;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private GameTime _simulationGameTime = new .() ~ delete _;
|
||||||
|
|
||||||
|
/// Gets or sets the path of the current scene.
|
||||||
|
public StringView SceneFilePath
|
||||||
{
|
{
|
||||||
get => _sceneFilePath;
|
get => _sceneFilePath;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_sceneFilePath.Clear();
|
_sceneFilePath.Clear();
|
||||||
|
|
||||||
if (value != null)
|
if (!value.IsWhiteSpace)
|
||||||
_sceneFilePath.Append(value);
|
_sceneFilePath.Append(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Editor _editor ~ delete _;
|
[AllowAppend]
|
||||||
|
public this(String[] args, EditorContentManager contentManager) : base("Editor")
|
||||||
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,
|
Application.Get().Window.IsVSync = true;
|
||||||
Play,
|
|
||||||
// Pause,
|
|
||||||
// Simulate
|
|
||||||
}
|
|
||||||
|
|
||||||
SceneState _sceneState = .Edit;
|
|
||||||
|
|
||||||
public this(EditorContentManager contentManager) : base("Example")
|
|
||||||
{
|
|
||||||
Application.Get().Window.IsVSync = false;
|
|
||||||
|
|
||||||
//InitContentManager();
|
|
||||||
_contentManager = contentManager;
|
_contentManager = contentManager;
|
||||||
|
|
||||||
InitGraphics();
|
InitGraphics();
|
||||||
|
|
||||||
_scene = new Scene();
|
_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 = EditorCamera(float3(-3f, 3f, -3f), Quaternion.FromEulerAngles(MathHelper.ToRadians(40), MathHelper.ToRadians(25), 0), MathHelper.ToRadians(75), 0.1f, 1);
|
||||||
_camera.RenderTarget = _cameraTarget;
|
_camera.RenderTarget = _cameraTarget;
|
||||||
|
|
||||||
InitEditor();
|
InitEditor();
|
||||||
|
|
||||||
NewScene();
|
if (args.Count >= 1)
|
||||||
|
LoadSceneFile(args[0]);
|
||||||
|
|
||||||
|
// Create a new scene, if LoadSceneFile failed
|
||||||
|
if (_activeScene == null)
|
||||||
|
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()
|
private void InitGraphics()
|
||||||
{
|
{
|
||||||
_context = Application.Get().Window.Context..AddRef();
|
_context = Application.Get().Window.Context..AddRef();
|
||||||
@@ -141,7 +150,15 @@ namespace GlitchyEditor
|
|||||||
DepthTargetDescription = .(.D24_UNorm_S8_UInt)
|
DepthTargetDescription = .(.D24_UNorm_S8_UInt)
|
||||||
});
|
});
|
||||||
|
|
||||||
_viewportTarget = new RenderTargetGroup(.()
|
_editorViewportTarget = new RenderTargetGroup(.()
|
||||||
|
{
|
||||||
|
Width = 100,
|
||||||
|
Height = 100,
|
||||||
|
ColorTargetDescriptions = TargetDescription[](
|
||||||
|
.(.R8G8B8A8_UNorm))
|
||||||
|
});
|
||||||
|
|
||||||
|
_gameViewportTarget = new RenderTargetGroup(.()
|
||||||
{
|
{
|
||||||
Width = 100,
|
Width = 100,
|
||||||
Height = 100,
|
Height = 100,
|
||||||
@@ -154,18 +171,16 @@ namespace GlitchyEditor
|
|||||||
|
|
||||||
ContentBrowserWindow.s_FolderTexture = _editorIcons.Folder;
|
ContentBrowserWindow.s_FolderTexture = _editorIcons.Folder;
|
||||||
ContentBrowserWindow.s_FileTexture = _editorIcons.File;
|
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()
|
private void InitEditor()
|
||||||
{
|
{
|
||||||
_editor = new Editor(_scene, _contentManager);
|
_editor = new Editor(_editorScene, _contentManager);
|
||||||
_editor.SceneViewportWindow.ViewportSizeChanged.Add(new (s, e) => ViewportSizeChanged(s, e));
|
_editor.SceneViewportWindow.ViewportSizeChanged.Add(new (s, e) => EditorViewportSizeChanged(s, e));
|
||||||
|
_editor.GameViewportWindow.ViewportSizeChanged.Add(new (s, e) => GameViewportSizeChanged(s, e));
|
||||||
_editor.CurrentCamera = &_camera;
|
_editor.CurrentCamera = &_camera;
|
||||||
|
_editor.GameSceneRenderer = _gameSceneRenderer;
|
||||||
|
_editor.EditorSceneRenderer = _editorSceneRenderer;
|
||||||
|
|
||||||
_editor.RequestOpenScene.Add(new (s, fileName) => {
|
_editor.RequestOpenScene.Add(new (s, fileName) => {
|
||||||
LoadSceneFile(fileName);
|
LoadSceneFile(fileName);
|
||||||
@@ -174,20 +189,89 @@ namespace GlitchyEditor
|
|||||||
|
|
||||||
public override void Update(GameTime gameTime)
|
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 && !_singleStep)
|
||||||
|
updateMode = .None;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we are in edit mode we use the "official" gametime.
|
||||||
|
* However in play or simulation mode we use a simulation game time
|
||||||
|
* which is decoupled from the actual time. This allows us to manipulate
|
||||||
|
* the simulation speed without potentially messing with the rest of the editor.
|
||||||
|
*/
|
||||||
|
GameTime gt = null;
|
||||||
|
|
||||||
|
if (updateMode == .Editor)
|
||||||
|
{
|
||||||
|
gt = gameTime;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gt = _simulationGameTime;
|
||||||
|
|
||||||
|
if (_singleStep)
|
||||||
|
{
|
||||||
|
_singleStep = false;
|
||||||
|
_simulationGameTime.ManualStepFrame(_fixedTimestep);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_simulationGameTime.ManualStepFrame(gameTime.DeltaTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_activeScene.Update(gt, updateMode);
|
||||||
|
|
||||||
// Clear the swapchain-buffer
|
// Clear the swapchain-buffer
|
||||||
RenderCommand.Clear(null, .Color | .Depth, .(0.2f, 0.2f, 0.2f), 1.0f, 0);
|
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.SetBlendState(_alphaBlendState);
|
||||||
RenderCommand.SetDepthStencilState(_depthStencilState);
|
RenderCommand.SetDepthStencilState(_depthStencilState);
|
||||||
|
|
||||||
if (_sceneState == .Edit)
|
if (_editor.GameViewportWindow.Visible)
|
||||||
_scene.UpdateEditor(gameTime, _camera, _viewportTarget, scope => DebugDraw3D, scope => DebugDraw2D);
|
{
|
||||||
else if (_sceneState == .Play)
|
_gameSceneRenderer.Scene = _activeScene;
|
||||||
_scene.UpdateRuntime(gameTime, _viewportTarget);
|
|
||||||
|
_activeScene.SetViewportSize((uint32)_editor.GameViewportWindow.ViewportSize.X, (uint32)_editor.GameViewportWindow.ViewportSize.Y);
|
||||||
|
_gameSceneRenderer.SetViewportSize((uint32)_editor.GameViewportWindow.ViewportSize.X, (uint32)_editor.GameViewportWindow.ViewportSize.Y);
|
||||||
|
|
||||||
|
RenderCommand.Clear(_gameViewportTarget, .Color | .Depth, .(0.2f, 0.2f, 0.2f), 1.0f, 0);
|
||||||
|
_gameSceneRenderer.RenderRuntime(gameTime, _gameViewportTarget);
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderCommand.SetBlendState(_alphaBlendState);
|
||||||
|
RenderCommand.SetDepthStencilState(_depthStencilState);
|
||||||
|
|
||||||
|
if (_editor.SceneViewportWindow.Visible)
|
||||||
|
{
|
||||||
|
_camera.Update(gameTime);
|
||||||
|
|
||||||
|
_editorSceneRenderer.Scene = _activeScene;
|
||||||
|
|
||||||
|
// Only use aspect ratio of editor-window, if game is not being rendered
|
||||||
|
if (!_editor.GameViewportWindow.Visible)
|
||||||
|
_activeScene.SetViewportSize((uint32)_editor.SceneViewportWindow.ViewportSize.X, (uint32)_editor.SceneViewportWindow.ViewportSize.Y);
|
||||||
|
|
||||||
|
_editorSceneRenderer.SetViewportSize((uint32)_editor.SceneViewportWindow.ViewportSize.X, (uint32)_editor.SceneViewportWindow.ViewportSize.Y);
|
||||||
|
|
||||||
|
RenderCommand.Clear(_editorViewportTarget, .Color | .Depth, .(0.2f, 0.2f, 0.2f), 1.0f, 0);
|
||||||
|
_editorSceneRenderer.RenderEditor(gameTime, _camera, _editorViewportTarget, scope => DebugDraw3D, scope => DebugDraw2D);
|
||||||
|
}
|
||||||
|
|
||||||
RenderCommand.UnbindRenderTargets();
|
RenderCommand.UnbindRenderTargets();
|
||||||
RenderCommand.SetRenderTarget(null, 0, true);
|
RenderCommand.SetRenderTarget(null, 0, true);
|
||||||
@@ -216,21 +300,21 @@ namespace GlitchyEditor
|
|||||||
|
|
||||||
Matrix Billboard(Matrix transform)
|
Matrix Billboard(Matrix transform)
|
||||||
{
|
{
|
||||||
Vector3 worldPos = transform.Translation;
|
float3 worldPos = transform.Translation;
|
||||||
|
|
||||||
return Matrix.Translation(worldPos) * billboard;
|
return Matrix.Translation(worldPos) * billboard;
|
||||||
}
|
}
|
||||||
|
|
||||||
float CalculateAlpha(Vector3 pos)
|
float CalculateAlpha(float3 pos)
|
||||||
{
|
{
|
||||||
return Math.Clamp(1.5f - Vector3.Distance(_editor.CurrentCamera.Position, pos) / 50, 0, 1);
|
return Math.Clamp(1.5f - 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);
|
Matrix world = Billboard(transform.WorldTransform);
|
||||||
@@ -240,15 +324,15 @@ namespace GlitchyEditor
|
|||||||
//Renderer2D.DrawQuad(world, _iconCamera, .White, .(0, 0, 1, 1), entity.Index);
|
//Renderer2D.DrawQuad(world, _iconCamera, .White, .(0, 0, 1, 1), entity.Index);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var (entity, transform, light) in _scene.[Friend]_ecsWorld.Enumerate<TransformComponent, LightComponent>())
|
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);
|
Renderer.DrawRay(.Zero, .(0, 0, 20), ColorRGBA(light.SceneLight.Color, 1.0f), transform.WorldTransform);
|
||||||
|
|
||||||
for (float angle = 0; angle < MathHelper.TwoPi; angle += MathHelper.TwoPi / 5.0f)
|
for (float angle = 0; angle < MathHelper.TwoPi; angle += MathHelper.TwoPi / 5.0f)
|
||||||
{
|
{
|
||||||
Vector2 pos = MathHelper.CirclePoint(angle, 0.5f);
|
float2 pos = MathHelper.CirclePoint(angle, 0.5f);
|
||||||
|
|
||||||
Renderer.DrawRay(.(pos, 0), .(pos, 20), .White, transform.WorldTransform);
|
Renderer.DrawRay(.(pos, 0), .(pos, 20), .White, transform.WorldTransform);
|
||||||
}
|
}
|
||||||
@@ -258,7 +342,16 @@ namespace GlitchyEditor
|
|||||||
|
|
||||||
float alpha = CalculateAlpha(transform.WorldTransform.Translation);
|
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, _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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -278,7 +371,8 @@ namespace GlitchyEditor
|
|||||||
|
|
||||||
private bool OnImGuiRender(ImGuiRenderEvent event)
|
private bool OnImGuiRender(ImGuiRenderEvent event)
|
||||||
{
|
{
|
||||||
Input.ImGuiDebugDraw();
|
// TODO: make window
|
||||||
|
//Input.ImGuiDebugDraw();
|
||||||
|
|
||||||
//viewer.ViewTexture(Renderer.[Friend]_gBuffer.Target);
|
//viewer.ViewTexture(Renderer.[Friend]_gBuffer.Target);
|
||||||
|
|
||||||
@@ -287,7 +381,8 @@ namespace GlitchyEditor
|
|||||||
|
|
||||||
DrawMainMenuBar();
|
DrawMainMenuBar();
|
||||||
|
|
||||||
_editor.SceneViewportWindow.RenderTarget = _viewportTarget;
|
_editor.SceneViewportWindow.RenderTarget = _editorViewportTarget;
|
||||||
|
_editor.GameViewportWindow.RenderTarget = _gameViewportTarget;
|
||||||
|
|
||||||
_editor.Update();
|
_editor.Update();
|
||||||
|
|
||||||
@@ -317,22 +412,129 @@ namespace GlitchyEditor
|
|||||||
|
|
||||||
ImGui.Begin("##toolbar", null, .NoDecoration | .NoScrollbar | .NoScrollWithMouse);
|
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;
|
||||||
|
|
||||||
ImGui.SameLine((ImGui.GetContentRegionMax().x / 2 - size / 2));
|
|
||||||
|
|
||||||
if (ImGui.ImageButton(icon, .(size, size), .Zero, .Ones, 0))
|
float centerX = ImGui.GetContentRegionMax().x / 2;
|
||||||
|
|
||||||
|
if (_sceneState == .Edit)
|
||||||
|
EditorButtons:
|
||||||
{
|
{
|
||||||
if (_sceneState == .Edit)
|
// 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();
|
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
|
||||||
|
{
|
||||||
|
float totalWidth = size * 2 + padding * 2;
|
||||||
|
|
||||||
|
if (_isPaused)
|
||||||
|
{
|
||||||
|
totalWidth = size * 3 + padding * 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display the buttons for play/simulation state
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.SetCursorPosX(centerX - totalWidth / 2.0f);
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
if (_isPaused)
|
||||||
|
{
|
||||||
|
ImGui.PushID(2);
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
|
||||||
|
SubTexture2D singleStepButtonIcon = _editorIcons.SingleStep;
|
||||||
|
|
||||||
|
if (ImGui.ImageButton(singleStepButtonIcon, .(size, size), .Zero, .Ones, 0))
|
||||||
|
{
|
||||||
|
DoSingleStep();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.BeginPopupContextItem())
|
||||||
|
{
|
||||||
|
ImGui.TextUnformatted("Time step:");
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.DragFloat("##timestep", &_fixedTimestep, 0.001f, 0.001f, 1000.0f, "%.4fs");
|
||||||
|
|
||||||
|
float fps = 1.0f / _fixedTimestep;
|
||||||
|
|
||||||
|
ImGui.TextUnformatted("Frame rate:");
|
||||||
|
ImGui.SameLine();
|
||||||
|
if (ImGui.DragFloat("##fps", &fps, 1.0f, 0.001f, 1000.0f, "%.3f FPS"))
|
||||||
|
{
|
||||||
|
_fixedTimestep = 1.0f / fps;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.AttachTooltip("Step one Frame (Right-click to change time step)");
|
||||||
|
|
||||||
|
ImGui.PopID();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.PushID(1);
|
||||||
|
|
||||||
|
if (ImGui.ImageButton(_editorIcons.Stop, .(size, size), .Zero, .Ones, 0))
|
||||||
|
OnSceneStop();
|
||||||
|
|
||||||
|
ImGui.PopID();
|
||||||
|
|
||||||
|
ImGui.AttachTooltip("Stop");
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.End();
|
ImGui.End();
|
||||||
@@ -343,194 +545,134 @@ namespace GlitchyEditor
|
|||||||
|
|
||||||
private void OnScenePlay()
|
private void OnScenePlay()
|
||||||
{
|
{
|
||||||
_sceneState = .Play;
|
|
||||||
_editor.SceneViewportWindow.EditorMode = false;
|
_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 DoSingleStep()
|
||||||
|
{
|
||||||
|
_singleStep = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnSceneStop()
|
private void OnSceneStop()
|
||||||
{
|
{
|
||||||
_scene.OnRuntimeStop();
|
if (_sceneState == .Play)
|
||||||
|
_activeScene.OnRuntimeStop();
|
||||||
|
else if (_sceneState == .Simulate)
|
||||||
|
_activeScene.OnSimulationStop();
|
||||||
|
|
||||||
|
SetReference!(_activeScene, _editorScene);
|
||||||
|
|
||||||
_editor.SceneViewportWindow.EditorMode = true;
|
_editor.SceneViewportWindow.EditorMode = true;
|
||||||
_sceneState = .Edit;
|
_sceneState = .Edit;
|
||||||
}
|
|
||||||
|
|
||||||
// Just for testing
|
_editor.CurrentScene = _activeScene;
|
||||||
private void TestEntitiesWithModels()
|
|
||||||
{
|
|
||||||
/*{
|
|
||||||
var lightNtt = _scene.CreateEntity("My Sexy Sun 2");
|
|
||||||
let transform = lightNtt.GetComponent<TransformComponent>();
|
|
||||||
transform.Position = .(0, 0, 0);
|
|
||||||
transform.RotationEuler = .(MathHelper.ToRadians(70), MathHelper.ToRadians(-30), 0);
|
|
||||||
|
|
||||||
let light = lightNtt.AddComponent<LightComponent>();
|
|
||||||
light.SceneLight.Illuminance = 10.0f;
|
|
||||||
light.SceneLight.Color = .(1.0f, 0.95f, 0.8f);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
var lightNtt = _scene.CreateEntity("My Sexy Sun 3");
|
|
||||||
let transform = lightNtt.GetComponent<TransformComponent>();
|
|
||||||
transform.Position = .(0, 0, 0);
|
|
||||||
transform.RotationEuler = .(MathHelper.ToRadians(20), MathHelper.ToRadians(-55), 0);
|
|
||||||
|
|
||||||
let light = lightNtt.AddComponent<LightComponent>();
|
|
||||||
light.SceneLight.Illuminance = 10.0f;
|
|
||||||
light.SceneLight.Color = .(1.0f, 0.95f, 0.8f);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
var cameraNtt = _scene.CreateEntity("My Camera");
|
|
||||||
let transform = cameraNtt.GetComponent<TransformComponent>();
|
|
||||||
transform.Position = .(5, 5, -5);
|
|
||||||
transform.RotationEuler = .(MathHelper.ToRadians(45), MathHelper.ToRadians(-45), 0);
|
|
||||||
|
|
||||||
let camera = cameraNtt.AddComponent<CameraComponent>();
|
|
||||||
camera.Primary = true;
|
|
||||||
camera.Camera.SetPerspective(MathHelper.ToRadians(45), 0.1f, 10.0f);
|
|
||||||
camera.RenderTarget = _cameraTarget;
|
|
||||||
}
|
|
||||||
|
|
||||||
var fxLib = Application.Get().EffectLibrary;
|
|
||||||
|
|
||||||
using (Effect myEffect = fxLib.Load("content/Shaders/myEffect.hlsl"))
|
|
||||||
/*using (Texture2D albedo = new Texture2D("Textures/White.png", true))
|
|
||||||
using (Texture2D normal = new Texture2D("Textures/White.png"))
|
|
||||||
using (Texture2D rough = new Texture2D("Textures/White.png"))
|
|
||||||
using (Texture2D metal = new Texture2D("Textures/White.png"))*/
|
|
||||||
using (Texture2D albedo = new Texture2D("Textures/TestMat/rustediron2_albedo.png", true))
|
|
||||||
using (Texture2D normal = new Texture2D("Textures/TestMat/rustediron2_normal.png"))
|
|
||||||
using (Texture2D rough = new Texture2D("Textures/TestMat/rustediron2_roughness.png"))
|
|
||||||
using (Texture2D metal = new Texture2D("Textures/TestMat/rustediron2_metallic.png"))
|
|
||||||
{
|
|
||||||
albedo.SamplerState = SamplerStateManager.AnisotropicWrap;
|
|
||||||
normal.SamplerState = SamplerStateManager.AnisotropicWrap;
|
|
||||||
rough.SamplerState = SamplerStateManager.AnisotropicWrap;
|
|
||||||
metal.SamplerState = SamplerStateManager.AnisotropicWrap;
|
|
||||||
|
|
||||||
List<AnimationClip> clips = scope .();
|
|
||||||
|
|
||||||
using (Material mat = new .(myEffect))
|
|
||||||
{
|
|
||||||
mat.SetTexture("AlbedoTexture", albedo);
|
|
||||||
mat.SetTexture("NormalTexture", normal);
|
|
||||||
mat.SetTexture("MetallicTexture", metal);
|
|
||||||
mat.SetTexture("RoughnessTexture", rough);
|
|
||||||
|
|
||||||
mat.SetVariable("AlbedoColor", ColorRGBA.White);
|
|
||||||
mat.SetVariable("NormalScaling", Vector2.One);
|
|
||||||
mat.SetVariable("MetallicFactor", 1.0f);
|
|
||||||
mat.SetVariable("RoughnessFactor", 1.0f);
|
|
||||||
|
|
||||||
// TODO: completely wrong!
|
|
||||||
EcsEntity e = ModelLoader.LoadModel("content/Models/sphere.glb", mat, _scene.[Friend]_ecsWorld, clips, "Sphere 1");
|
|
||||||
|
|
||||||
Entity entity = .(e, _scene);
|
|
||||||
var transform = entity.GetComponent<TransformComponent>();
|
|
||||||
transform.Position = .(5, 0, 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*using (Material mat = new .(myEffect))
|
|
||||||
{
|
|
||||||
mat.SetTexture("AlbedoTexture", albedo);
|
|
||||||
mat.SetTexture("NormalTexture", normal);
|
|
||||||
mat.SetTexture("MetallicTexture", metal);
|
|
||||||
mat.SetTexture("RoughnessTexture", rough);
|
|
||||||
//mat.SetVariable("BaseColor", Vector4(1, 1, 0, 1));
|
|
||||||
//mat.SetVariable("LightDir", Vector3(0, 1, 0).Normalized());
|
|
||||||
|
|
||||||
|
|
||||||
ModelLoader.LoadModel("content/Models/sphere.glb", myEffect, mat, _scene.[Friend]_ecsWorld, clips);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
ClearAndReleaseItems!(clips);
|
|
||||||
}
|
|
||||||
|
|
||||||
using (Effect myEffect = fxLib.Get("myEffect"))
|
|
||||||
using (Texture2D white = new Texture2D("Textures/White.png"))
|
|
||||||
using (Texture2D normal = new Texture2D("Textures/DefaultNormal.png"))
|
|
||||||
{
|
|
||||||
white.SamplerState = SamplerStateManager.PointClamp;
|
|
||||||
normal.SamplerState = SamplerStateManager.PointClamp;
|
|
||||||
|
|
||||||
List<AnimationClip> clips = scope .();
|
|
||||||
|
|
||||||
for (int x < 10)
|
|
||||||
for (int y < 10)
|
|
||||||
{
|
|
||||||
using (Material mat = new .(myEffect))
|
|
||||||
{
|
|
||||||
mat.SetTexture("AlbedoTexture", white);
|
|
||||||
mat.SetTexture("NormalTexture", normal);
|
|
||||||
mat.SetTexture("MetallicTexture", white);
|
|
||||||
mat.SetTexture("RoughnessTexture", white);
|
|
||||||
|
|
||||||
mat.SetVariable("AlbedoColor", Vector4(1, 0, 0, 1));
|
|
||||||
mat.SetVariable("NormalScaling", Vector2(1.0f));
|
|
||||||
mat.SetVariable("RoughnessFactor", (x + 1) / 10.0f);
|
|
||||||
mat.SetVariable("MetallicFactor", y / 9.0f);
|
|
||||||
|
|
||||||
EcsEntity e = ModelLoader.LoadModel("content/Models/sphere.glb", mat, _scene.[Friend]_ecsWorld, clips, scope $"Sphere {x} {y}");
|
_isPaused = false;
|
||||||
|
|
||||||
Entity entity = .(e, _scene);
|
if (_activeScene != null)
|
||||||
var transform = entity.GetComponent<TransformComponent>();
|
{
|
||||||
transform.Position = .(x * 1.5f, y * 1.5f, 0);
|
/*
|
||||||
}
|
* 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).
|
||||||
ClearAndReleaseItems!(clips);
|
*/
|
||||||
}*/
|
GameViewportSizeChanged(null, _editor.GameViewportWindow.ViewportSize);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new scene.
|
/// Creates a new scene.
|
||||||
private void NewScene()
|
private void NewScene()
|
||||||
{
|
{
|
||||||
|
OnSceneStop();
|
||||||
|
|
||||||
SceneFilePath = null;
|
SceneFilePath = null;
|
||||||
|
|
||||||
delete _scene;
|
|
||||||
_scene = new Scene();
|
|
||||||
_editor.CurrentScene = _scene;
|
|
||||||
var vpSize = _editor.SceneViewportWindow.ViewportSize;
|
|
||||||
_scene.OnViewportResize((.)vpSize.X, (.)vpSize.Y);
|
|
||||||
|
|
||||||
_camera.Position = .(-1.5f, 1.5f, -2.5f);
|
using (Scene newScene = new Scene())
|
||||||
_camera.RotationEuler = .(MathHelper.ToRadians(25), MathHelper.ToRadians(35), 0);
|
|
||||||
|
|
||||||
// Create default camera
|
|
||||||
/*{
|
|
||||||
let camEntity = _scene.CreateEntity("Camera");
|
|
||||||
let transform = camEntity.Transform;
|
|
||||||
transform.Position =
|
|
||||||
}*/
|
|
||||||
|
|
||||||
/*// Create the default light source
|
|
||||||
{
|
{
|
||||||
let lightNtt = _scene.CreateEntity("Light");
|
_camera.Position = .(-1.5f, 1.5f, -2.5f);
|
||||||
let transform = lightNtt.Transform;
|
_camera.RotationEuler = .(MathHelper.ToRadians(25), MathHelper.ToRadians(35), 0);
|
||||||
transform.Position = .(0, 0, 0);
|
|
||||||
transform.RotationEuler = .(MathHelper.ToRadians(45), MathHelper.ToRadians(-100), 0);
|
// Create a default camera
|
||||||
|
{
|
||||||
let light = lightNtt.AddComponent<LightComponent>();
|
let cameraEntity = newScene.CreateEntity("Camera");
|
||||||
light.SceneLight.Illuminance = 10.0f;
|
let transform = cameraEntity.Transform;
|
||||||
light.SceneLight.Color = .(1.0f, 0.95f, 0.8f);
|
transform.Position = float3(0, 2, -5);
|
||||||
|
transform.RotationEuler = float3(0, MathHelper.ToRadians(25), 0);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
SetReference!(_editorScene, newScene);
|
||||||
|
_editor.CurrentScene = _editorScene;
|
||||||
|
SetReference!(_activeScene, _editorScene);
|
||||||
}
|
}
|
||||||
|
|
||||||
TestEntitiesWithModels();*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Saves the scene in the file that is was loaded from or saved to last. If there is no such path (i.e. it is a new scene) the save file dialog will open.
|
/// 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()
|
private void SaveScene()
|
||||||
{
|
{
|
||||||
if (String.IsNullOrWhiteSpace(SceneFilePath))
|
if (SceneFilePath.IsWhiteSpace)
|
||||||
{
|
{
|
||||||
SaveSceneAs();
|
SaveSceneAs();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SceneSerializer serializer = scope .(_scene);
|
SceneSerializer serializer = scope .(_editorScene);
|
||||||
serializer.Serialize(SceneFilePath);
|
serializer.Serialize(SceneFilePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -565,16 +707,44 @@ namespace GlitchyEditor
|
|||||||
/// Loads the given scene file.
|
/// Loads the given scene file.
|
||||||
private void LoadSceneFile(StringView filename)
|
private void LoadSceneFile(StringView filename)
|
||||||
{
|
{
|
||||||
|
OnSceneStop();
|
||||||
|
|
||||||
SceneFilePath = scope String(filename);
|
SceneFilePath = scope String(filename);
|
||||||
|
|
||||||
delete _scene;
|
using (Scene newScene = new Scene())
|
||||||
_scene = new Scene();
|
{
|
||||||
_editor.CurrentScene = _scene;
|
SceneSerializer serializer = scope .(newScene);
|
||||||
var vpSize = _editor.SceneViewportWindow.ViewportSize;
|
let result = serializer.Deserialize(SceneFilePath);
|
||||||
_scene.OnViewportResize((.)vpSize.X, (.)vpSize.Y);
|
|
||||||
|
|
||||||
SceneSerializer serializer = scope .(_scene);
|
// Make sure we actually loaded something!
|
||||||
serializer.Deserialize(SceneFilePath);
|
if (result case .Ok)
|
||||||
|
{
|
||||||
|
SetReference!(_editorScene, newScene);
|
||||||
|
_editor.CurrentScene = _editorScene;
|
||||||
|
SetReference!(_activeScene, _editorScene);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.EngineLogger.Error("Failed to load scene file.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawOpenRecentProjectMenu()
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for (let (name, path) in _recentProjectPaths)
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
if (i >= 10)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (ImGui.MenuItem(scope $"{i}: {name} ({path})"))
|
||||||
|
{
|
||||||
|
LoadSceneFile(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawMainMenuBar()
|
private void DrawMainMenuBar()
|
||||||
@@ -589,11 +759,18 @@ namespace GlitchyEditor
|
|||||||
if (ImGui.MenuItem("Save", "Ctrl+S"))
|
if (ImGui.MenuItem("Save", "Ctrl+S"))
|
||||||
SaveScene();
|
SaveScene();
|
||||||
|
|
||||||
if (ImGui.MenuItem("Save as...", "Ctrl+Shift+N"))
|
if (ImGui.MenuItem("Save as...", "Ctrl+Shift+S"))
|
||||||
SaveSceneAs();
|
SaveSceneAs();
|
||||||
|
|
||||||
if (ImGui.MenuItem("Open...", "Ctrl+O"))
|
if (ImGui.MenuItem("Open...", "Ctrl+O"))
|
||||||
OpenScene();
|
OpenScene();
|
||||||
|
|
||||||
|
if (ImGui.BeginMenu("Open Recent"))
|
||||||
|
{
|
||||||
|
DrawOpenRecentProjectMenu();
|
||||||
|
|
||||||
|
ImGui.EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
ImGui.Separator();
|
ImGui.Separator();
|
||||||
|
|
||||||
@@ -610,20 +787,34 @@ namespace GlitchyEditor
|
|||||||
|
|
||||||
if(ImGui.BeginMenu("View", true))
|
if(ImGui.BeginMenu("View", true))
|
||||||
{
|
{
|
||||||
if(ImGui.MenuItem(EntityHierarchyWindow.s_WindowTitle))
|
|
||||||
{
|
|
||||||
_editor.EntityHierarchyWindow.Open = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ImGui.MenuItem(ComponentEditWindow.s_WindowTitle))
|
if(ImGui.MenuItem(ComponentEditWindow.s_WindowTitle))
|
||||||
{
|
|
||||||
_editor.ComponentEditWindow.Open = true;
|
_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;
|
_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;
|
||||||
|
|
||||||
|
if(ImGui.MenuItem(AssetViewer.s_WindowTitle))
|
||||||
|
_editor.AssetViewer.Open = true;
|
||||||
|
|
||||||
|
ImGui.EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ImGui.BeginMenu("Tools", true))
|
||||||
|
{
|
||||||
|
if(ImGui.MenuItem("Reload Scripts"))
|
||||||
|
ScriptEngine.ReloadAssemblies();
|
||||||
|
|
||||||
ImGui.EndMenu();
|
ImGui.EndMenu();
|
||||||
}
|
}
|
||||||
@@ -637,19 +828,33 @@ namespace GlitchyEditor
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ViewportSizeChanged(Object sender, Vector2 viewportSize)
|
private void EditorViewportSizeChanged(Object sender, float2 viewportSize)
|
||||||
{
|
{
|
||||||
|
if(viewportSize.X <= 0 || viewportSize.Y <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
uint32 sizeX = (uint32)viewportSize.X;
|
uint32 sizeX = (uint32)viewportSize.X;
|
||||||
uint32 sizeY = (uint32)viewportSize.Y;
|
uint32 sizeY = (uint32)viewportSize.Y;
|
||||||
|
|
||||||
if(sizeX == 0 || sizeY == 0)
|
_editorViewportTarget.Resize(sizeX, sizeY);
|
||||||
return;
|
|
||||||
|
|
||||||
_viewportTarget.Resize(sizeX, sizeY);
|
|
||||||
_cameraTarget.Resize(sizeX, sizeY);
|
_cameraTarget.Resize(sizeX, sizeY);
|
||||||
|
|
||||||
_scene.OnViewportResize(sizeX, sizeY);
|
|
||||||
_camera.OnViewportResize(sizeX, sizeY);
|
_camera.OnViewportResize(sizeX, sizeY);
|
||||||
|
|
||||||
|
_activeScene.SetViewportSize(sizeX, sizeY);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GameViewportSizeChanged(Object sender, float2 viewportSize)
|
||||||
|
{
|
||||||
|
if(viewportSize.X <= 0 || viewportSize.Y <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint32 sizeX = (uint32)viewportSize.X;
|
||||||
|
uint32 sizeY = (uint32)viewportSize.Y;
|
||||||
|
|
||||||
|
_gameViewportTarget.Resize(sizeX, sizeY);
|
||||||
|
|
||||||
|
_activeScene.SetViewportSize(sizeX, sizeY);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool OnKeyPressed(KeyPressedEvent e)
|
private bool OnKeyPressed(KeyPressedEvent e)
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ namespace GlitchyEditor
|
|||||||
_samplerPoint = SamplerStateManager.GetSampler(desc);
|
_samplerPoint = SamplerStateManager.GetSampler(desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2 _position;
|
float2 _position;
|
||||||
|
|
||||||
bool _moving;
|
bool _moving;
|
||||||
|
|
||||||
@@ -105,6 +105,7 @@ namespace GlitchyEditor
|
|||||||
{
|
{
|
||||||
_target?.ReleaseRef();
|
_target?.ReleaseRef();
|
||||||
_target = new RenderTarget2D(.(.R8G8B8A8_UNorm, (.)viewportSize.x, (.)viewportSize.y));
|
_target = new RenderTarget2D(.(.R8G8B8A8_UNorm, (.)viewportSize.x, (.)viewportSize.y));
|
||||||
|
_target.SamplerState = SamplerStateManager.PointClamp;
|
||||||
_depth?.ReleaseRef();
|
_depth?.ReleaseRef();
|
||||||
_depth = new DepthStencilTarget((.)viewportSize.x, (.)viewportSize.y, .D16_UNorm);
|
_depth = new DepthStencilTarget((.)viewportSize.x, (.)viewportSize.y, .D16_UNorm);
|
||||||
}
|
}
|
||||||
@@ -124,7 +125,7 @@ namespace GlitchyEditor
|
|||||||
{
|
{
|
||||||
var windowPos = ImGui.GetWindowPos();
|
var windowPos = ImGui.GetWindowPos();
|
||||||
var mousePos = ImGui.GetIO().MousePos;
|
var mousePos = ImGui.GetIO().MousePos;
|
||||||
Vector2 mouseInWindow = .(mousePos.x - windowPos.x, mousePos.y - windowPos.y);
|
float2 mouseInWindow = .(mousePos.x - windowPos.x, mousePos.y - windowPos.y);
|
||||||
|
|
||||||
bool windowHovered = ImGui.IsWindowHovered();
|
bool windowHovered = ImGui.IsWindowHovered();
|
||||||
|
|
||||||
@@ -158,7 +159,7 @@ namespace GlitchyEditor
|
|||||||
|
|
||||||
if(_moving)
|
if(_moving)
|
||||||
{
|
{
|
||||||
Int2 movement = Input.GetMouseMovement();
|
int2 movement = Input.GetMouseMovement();
|
||||||
|
|
||||||
_position.X += movement.X;
|
_position.X += movement.X;
|
||||||
_position.Y += movement.Y;
|
_position.Y += movement.Y;
|
||||||
@@ -181,10 +182,10 @@ namespace GlitchyEditor
|
|||||||
_context.SetDepthStencilTarget(_depth);
|
_context.SetDepthStencilTarget(_depth);
|
||||||
_context.BindRenderTargets();
|
_context.BindRenderTargets();
|
||||||
|
|
||||||
Vector2 textureSize = Vector2(viewedTexture.Width, viewedTexture.Height);
|
float2 textureSize = float2(viewedTexture.Width, viewedTexture.Height);
|
||||||
Vector2 zoomedTextureSize = textureSize * _zoom;
|
float2 zoomedTextureSize = textureSize * _zoom;
|
||||||
|
|
||||||
Vector2 targetSize = Vector2(_target.Width, _target.Height);
|
float2 targetSize = float2(_target.Width, _target.Height);
|
||||||
|
|
||||||
_effect.Variables["ColorOffset"].SetData(_colorOffset);
|
_effect.Variables["ColorOffset"].SetData(_colorOffset);
|
||||||
_effect.Variables["ColorScale"].SetData(_colorScale);
|
_effect.Variables["ColorScale"].SetData(_colorScale);
|
||||||
@@ -204,19 +205,19 @@ namespace GlitchyEditor
|
|||||||
switch(_backgroundMode)
|
switch(_backgroundMode)
|
||||||
{
|
{
|
||||||
case .Black:
|
case .Black:
|
||||||
Renderer2D.DrawQuadPivotCorner(Vector3(0, 0, 1), targetSize, 0, .Black);
|
Renderer2D.DrawQuadPivotCorner(float3(0, 0, 1), targetSize, 0, .Black);
|
||||||
case .White:
|
case .White:
|
||||||
Renderer2D.DrawQuadPivotCorner(Vector3(0, 0, 1), targetSize, 0, .White);
|
Renderer2D.DrawQuadPivotCorner(float3(0, 0, 1), targetSize, 0, .White);
|
||||||
case .Checkerboard:
|
case .Checkerboard:
|
||||||
float quadSize = 50.0f;
|
float quadSize = 50.0f;
|
||||||
|
|
||||||
Vector2 numQuads = (targetSize / 500f) * 10f;
|
float2 numQuads = (targetSize / 500f) * 10f;
|
||||||
|
|
||||||
for(float x = 0; x < numQuads.X; x++)
|
for(float x = 0; x < numQuads.X; x++)
|
||||||
{
|
{
|
||||||
for(float y = 0; y < numQuads.Y; y++)
|
for(float y = 0; y < numQuads.Y; y++)
|
||||||
{
|
{
|
||||||
Renderer2D.DrawQuadPivotCorner(Vector3(x * quadSize, -y * quadSize, 1), quadSize.XX, 0, ((x + y) % 2 == 0) ? .White : .Gray);
|
Renderer2D.DrawQuadPivotCorner(float3(x * quadSize, -y * quadSize, 1), quadSize.XX, 0, ((x + y) % 2 == 0) ? .White : .Gray);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -236,7 +237,7 @@ namespace GlitchyEditor
|
|||||||
|
|
||||||
Renderer2D.BeginScene(_camera, .SortByTexture, _effect);
|
Renderer2D.BeginScene(_camera, .SortByTexture, _effect);
|
||||||
|
|
||||||
Renderer2D.DrawQuad(Vector3(_position * .(1, -1), 0), zoomedTextureSize, 0, viewedTexture);
|
Renderer2D.DrawQuad(float3(_position * .(1, -1), 0), zoomedTextureSize, 0, viewedTexture);
|
||||||
|
|
||||||
Renderer2D.EndScene();
|
Renderer2D.EndScene();
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
FileVersion = 1
|
FileVersion = 1
|
||||||
Dependencies = {GlitchLog = "*", corlib = "*", DirectX = "*", FreeType = "*", cgltf-beef = "*", msdfgen-beef = "*", ImGui = "*", ImGuiImplDX11 = "*", ImGuiImplWin32 = "*", ImGuizmo = "*", Beefy2D = "*", LodePng = "*", GlitchyEngineHelper = "*", bon = "*", box2d-beef = "*", "Beef.Linq" = "*"}
|
Dependencies = {GlitchLog = "*", corlib = "*", DirectX = "*", FreeType = "*", cgltf-beef = "*", msdfgen-beef = "*", ImGui = "*", ImGuiImplDX11 = "*", ImGuiImplWin32 = "*", ImGuizmo = "*", Beefy2D = "*", LodePng = "*", GlitchyEngineHelper = "*", bon = "*", box2d-beef = "*", "Beef.Linq" = "*", NetHostBeef = "*"}
|
||||||
|
|
||||||
[Project]
|
[Project]
|
||||||
Name = "GlitchyEngine"
|
Name = "GlitchyEngine"
|
||||||
@@ -25,3 +25,24 @@ PreprocessorMacros = ["TEST", "GE_WINDOWS"]
|
|||||||
|
|
||||||
[Configs.Debug.Win64]
|
[Configs.Debug.Win64]
|
||||||
PreprocessorMacros = ["DEBUG", "GE_PROFILE", "GE_PROFILE_RENDERER", "GE_PROFILE_RESOURCES", "IMGUI"]
|
PreprocessorMacros = ["DEBUG", "GE_PROFILE", "GE_PROFILE_RENDERER", "GE_PROFILE_RESOURCES", "IMGUI"]
|
||||||
|
|
||||||
|
[[ProjectFolder.Items]]
|
||||||
|
Type = "AutoFolder"
|
||||||
|
Name = "Math"
|
||||||
|
|
||||||
|
[[ProjectFolder.Items.Items]]
|
||||||
|
Type = "IgnoreSource"
|
||||||
|
Name = "Vector2.bf"
|
||||||
|
|
||||||
|
[[ProjectFolder.Items.Items]]
|
||||||
|
Type = "IgnoreSource"
|
||||||
|
Name = "Vector3.bf"
|
||||||
|
|
||||||
|
[[ProjectFolder.Items.Items]]
|
||||||
|
Type = "IgnoreSource"
|
||||||
|
Name = "Vector4.bf"
|
||||||
|
|
||||||
|
[[ProjectFolder.Items.Items]]
|
||||||
|
Type = "IgnoreFolder"
|
||||||
|
Name = "Vectors"
|
||||||
|
AutoInclude = true
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ using GlitchyEngine.ImGui;
|
|||||||
using GlitchyEngine.Renderer;
|
using GlitchyEngine.Renderer;
|
||||||
using GlitchyEngine.Debug;
|
using GlitchyEngine.Debug;
|
||||||
using GlitchyEngine.Content;
|
using GlitchyEngine.Content;
|
||||||
|
using GlitchyEngine.Scripting;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace GlitchyEngine
|
namespace GlitchyEngine
|
||||||
{
|
{
|
||||||
@@ -27,6 +30,9 @@ namespace GlitchyEngine
|
|||||||
|
|
||||||
private IContentManager _contentManager;
|
private IContentManager _contentManager;
|
||||||
|
|
||||||
|
private append List<delegate void()> _jobQueue = .() ~ ClearAndDeleteItems!(_);
|
||||||
|
private append Monitor _jobQueueMutex = .();
|
||||||
|
|
||||||
public bool IsRunning => _running;
|
public bool IsRunning => _running;
|
||||||
public Window Window => _window;
|
public Window Window => _window;
|
||||||
|
|
||||||
@@ -34,9 +40,13 @@ namespace GlitchyEngine
|
|||||||
|
|
||||||
public bool IsMinimized => _isMinimized;
|
public bool IsMinimized => _isMinimized;
|
||||||
|
|
||||||
[Inline]
|
public GameTime GameTime => _gameTime;
|
||||||
|
|
||||||
|
[Inline, Obsolete("Use Application.Instance instead.", false)]
|
||||||
public static Application Get() => s_Instance;
|
public static Application Get() => s_Instance;
|
||||||
|
|
||||||
|
public static Application Instance => s_Instance;
|
||||||
|
|
||||||
public Settings Settings {get; private set;} = new .() ~ delete _;
|
public Settings Settings {get; private set;} = new .() ~ delete _;
|
||||||
|
|
||||||
public this()
|
public this()
|
||||||
@@ -66,6 +76,7 @@ namespace GlitchyEngine
|
|||||||
RenderCommand.RendererAPI = _rendererApi;
|
RenderCommand.RendererAPI = _rendererApi;
|
||||||
|
|
||||||
Renderer.Init();
|
Renderer.Init();
|
||||||
|
ScriptEngine.Init();
|
||||||
|
|
||||||
#if IMGUI
|
#if IMGUI
|
||||||
_imGuiLayer = new ImGuiLayer();
|
_imGuiLayer = new ImGuiLayer();
|
||||||
@@ -88,6 +99,7 @@ namespace GlitchyEngine
|
|||||||
Profiler.ProfileFunction!();
|
Profiler.ProfileFunction!();
|
||||||
|
|
||||||
SamplerStateManager.Uninit();
|
SamplerStateManager.Uninit();
|
||||||
|
|
||||||
Renderer.Deinit();
|
Renderer.Deinit();
|
||||||
|
|
||||||
delete _contentManager;
|
delete _contentManager;
|
||||||
@@ -97,6 +109,8 @@ namespace GlitchyEngine
|
|||||||
|
|
||||||
delete _gameTime;
|
delete _gameTime;
|
||||||
delete _layerStack;
|
delete _layerStack;
|
||||||
|
|
||||||
|
ScriptEngine.Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnEvent(Event e)
|
public void OnEvent(Event e)
|
||||||
@@ -150,6 +164,8 @@ namespace GlitchyEngine
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
RunJobs();
|
||||||
|
|
||||||
if(allowFrame && !_isMinimized)
|
if(allowFrame && !_isMinimized)
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileScope!("Update Layers");
|
Debug.Profiler.ProfileScope!("Update Layers");
|
||||||
@@ -211,5 +227,29 @@ namespace GlitchyEngine
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Executes the given Job on the main thread. Takes ownership of the delegate.
|
||||||
|
public void InvokeOnMainThread(delegate void() ownJob)
|
||||||
|
{
|
||||||
|
using (_jobQueueMutex.Enter())
|
||||||
|
{
|
||||||
|
_jobQueue.Add(ownJob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RunJobs()
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileFunction!();
|
||||||
|
|
||||||
|
using (_jobQueueMutex.Enter())
|
||||||
|
{
|
||||||
|
for (let job in _jobQueue)
|
||||||
|
{
|
||||||
|
job();
|
||||||
|
}
|
||||||
|
|
||||||
|
ClearAndDeleteItems!(_jobQueue);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ namespace GlitchyEngine.Collections
|
|||||||
{
|
{
|
||||||
public T Value;
|
public T Value;
|
||||||
|
|
||||||
|
public Self Parent;
|
||||||
public List<Self> Children = new .() ~ DeleteContainerAndItems!(_);
|
public List<Self> Children = new .() ~ DeleteContainerAndItems!(_);
|
||||||
|
|
||||||
public this() {}
|
public this() {}
|
||||||
@@ -29,6 +30,7 @@ namespace GlitchyEngine.Collections
|
|||||||
}
|
}
|
||||||
|
|
||||||
Self newChild = new .(value);
|
Self newChild = new .(value);
|
||||||
|
newChild.Parent = this;
|
||||||
|
|
||||||
Children.Add(newChild);
|
Children.Add(newChild);
|
||||||
|
|
||||||
@@ -54,6 +56,62 @@ namespace GlitchyEngine.Collections
|
|||||||
{
|
{
|
||||||
return ref node.Value;
|
return ref node.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public delegate void ElementFunc(TreeNode<T> currentNode);
|
||||||
|
|
||||||
|
public enum IterationMode
|
||||||
|
{
|
||||||
|
BreadthFirst,
|
||||||
|
DepthFirst
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ForEach(ElementFunc func, IterationMode iterationMode = .DepthFirst)
|
||||||
|
{
|
||||||
|
if (iterationMode == .BreadthFirst)
|
||||||
|
{
|
||||||
|
ForEach_BreadthFirst(func);
|
||||||
|
}
|
||||||
|
else if (iterationMode == .DepthFirst)
|
||||||
|
{
|
||||||
|
ForEach_DepthFirst(func);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ForEach_BreadthFirst(ElementFunc func)
|
||||||
|
{
|
||||||
|
Queue<TreeNode<T>> nodes = scope .();
|
||||||
|
nodes.Add(this);
|
||||||
|
|
||||||
|
while (!nodes.IsEmpty)
|
||||||
|
{
|
||||||
|
TreeNode<T> node = nodes.PopFront();
|
||||||
|
|
||||||
|
func(node);
|
||||||
|
|
||||||
|
for (var child in node.Children)
|
||||||
|
{
|
||||||
|
nodes.Add(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ForEach_DepthFirst(ElementFunc func)
|
||||||
|
{
|
||||||
|
List<TreeNode<T>> nodes = scope .();
|
||||||
|
nodes.Add(this);
|
||||||
|
|
||||||
|
while (!nodes.IsEmpty)
|
||||||
|
{
|
||||||
|
TreeNode<T> node = nodes.PopBack();
|
||||||
|
|
||||||
|
func(node);
|
||||||
|
|
||||||
|
for (var child in node.Children)
|
||||||
|
{
|
||||||
|
nodes.Add(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
|
|||||||
@@ -8,8 +8,10 @@ using System.IO;
|
|||||||
namespace GlitchyEngine.Content;
|
namespace GlitchyEngine.Content;
|
||||||
|
|
||||||
[BonTarget]
|
[BonTarget]
|
||||||
class Asset : RefCounter
|
abstract class Asset : RefCounter
|
||||||
{
|
{
|
||||||
|
internal AssetHandle _handle = .Invalid;
|
||||||
|
|
||||||
private append String _identifier;
|
private append String _identifier;
|
||||||
|
|
||||||
internal IContentManager _contentManager;
|
internal IContentManager _contentManager;
|
||||||
@@ -20,19 +22,18 @@ class Asset : RefCounter
|
|||||||
public StringView Identifier
|
public StringView Identifier
|
||||||
{
|
{
|
||||||
get => _identifier;
|
get => _identifier;
|
||||||
set
|
internal set => _identifier.Set(value);
|
||||||
{
|
|
||||||
_contentManager?.UpdateAssetIdentifier(this, _identifier, 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...
|
// TODO: do we need unmanaged assets? Probably not...
|
||||||
/// Gets the content manager that manages this asset; or null if this asset isn't managed.
|
/// Gets the content manager that manages this asset; or null if this asset isn't managed.
|
||||||
public IContentManager ContentManager => _contentManager;
|
public IContentManager ContentManager => _contentManager;
|
||||||
|
|
||||||
|
public AssetHandle Handle => _handle;
|
||||||
|
|
||||||
static this
|
static this
|
||||||
{
|
{
|
||||||
gBonEnv.typeHandlers.Add(typeof(Asset),
|
gBonEnv.typeHandlers.Add(typeof(Asset),
|
||||||
@@ -43,7 +44,7 @@ class Asset : RefCounter
|
|||||||
{
|
{
|
||||||
// TODO: crash when _contentManager is deleted first...
|
// TODO: crash when _contentManager is deleted first...
|
||||||
// TODO: unregister from content manager
|
// TODO: unregister from content manager
|
||||||
_contentManager?.UnmanageAsset(this);
|
//_contentManager?.UnmanageAsset(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void AssetSerialize(BonWriter writer, ValueView value, BonEnvironment environment, SerializeValueState state)
|
static void AssetSerialize(BonWriter writer, ValueView value, BonEnvironment environment, SerializeValueState state)
|
||||||
@@ -62,7 +63,15 @@ class Asset : RefCounter
|
|||||||
|
|
||||||
Deserialize.String!(reader, ref identifier, environment);
|
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)
|
if (asset != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,343 @@
|
|||||||
|
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;
|
||||||
|
|
||||||
|
public UUID ID => _uuid;
|
||||||
|
|
||||||
|
/// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ToString(String strBuffer)
|
||||||
|
{
|
||||||
|
_uuid.ToString(strBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
/// @param contentManager The content manager used to load the asset.
|
||||||
/// @returns The loaded asset.
|
/// @returns The loaded asset.
|
||||||
Asset LoadAsset(Stream file, AssetLoaderConfig config, StringView assetIdentifier, StringView? subAsset, IContentManager contentManager);
|
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.
|
/// 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;
|
var contentManager;
|
||||||
|
|
||||||
if (contentManager == null)
|
if (contentManager == null)
|
||||||
contentManager = Application.Get().ContentManager;
|
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;
|
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
|
interface IContentManager
|
||||||
{
|
{
|
||||||
/// Loads the given asset.
|
/// Loads the Asset with the given handle and returns the handle.
|
||||||
Asset LoadAsset(StringView assetIdentifier);
|
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)
|
/// 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.
|
/// The content manager will no longer manage the asset.
|
||||||
void UnmanageAsset(Asset asset);
|
void UnmanageAsset(AssetHandle asset);
|
||||||
|
|
||||||
// TODO: Maybe calling UnmanageAsset -> ManageAsset is enough....
|
|
||||||
/// Provides a method for the asset to tell its content manager that the identifer changed.
|
|
||||||
void UpdateAssetIdentifier(Asset asset, StringView oldIdentifier, StringView newIdentifier);
|
|
||||||
|
|
||||||
/// Returns a data stream for the given asset.
|
/// Returns a data stream for the given asset.
|
||||||
Stream GetStream(StringView assetIdentifier);
|
Stream GetStream(StringView assetIdentifier);
|
||||||
@@ -109,22 +151,22 @@ namespace GlitchyEngine.Content
|
|||||||
Runtime.NotImplemented();
|
Runtime.NotImplemented();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Asset LoadAsset(StringView assetIdentifier)
|
public AssetHandle LoadAsset(StringView assetIdentifier, bool blocking = false)
|
||||||
{
|
{
|
||||||
Runtime.NotImplemented();
|
Runtime.NotImplemented();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ManageAsset(Asset asset)
|
public Asset GetAsset(Type assetType, AssetHandle handle)
|
||||||
{
|
{
|
||||||
Runtime.NotImplemented();
|
Runtime.NotImplemented();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UnmanageAsset(Asset asset)
|
public AssetHandle ManageAsset(Asset asset)
|
||||||
{
|
{
|
||||||
Runtime.NotImplemented();
|
Runtime.NotImplemented();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateAssetIdentifier(Asset asset, StringView oldIdentifier, StringView newIdentifier)
|
public void UnmanageAsset(AssetHandle asset)
|
||||||
{
|
{
|
||||||
Runtime.NotImplemented();
|
Runtime.NotImplemented();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -229,156 +229,6 @@ namespace GlitchyEngine.Content
|
|||||||
return .Success;
|
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)
|
public static GeometryBinding PrimitiveToGeoBinding(CGLTF.Primitive primitive)
|
||||||
{
|
{
|
||||||
GeometryBinding binding = new GeometryBinding();
|
GeometryBinding binding = new GeometryBinding();
|
||||||
@@ -517,15 +367,15 @@ namespace GlitchyEngine.Content
|
|||||||
|
|
||||||
Log.EngineLogger.AssertDebug(positions != null, "The model appears to have no position data?!");
|
Log.EngineLogger.AssertDebug(positions != null, "The model appears to have no position data?!");
|
||||||
|
|
||||||
Vector3[] normals = new Vector3[positions.Count];
|
float3[] normals = new float3[positions.Count];
|
||||||
|
|
||||||
if(primitive.Indices != null)
|
if(primitive.Indices != null)
|
||||||
GenerateNormals(primitive.Indices, positions, normals);
|
GenerateNormals(primitive.Indices, positions, normals);
|
||||||
else
|
else
|
||||||
GenerateNormals(positions, normals);
|
GenerateNormals(positions, normals);
|
||||||
|
|
||||||
VertexBuffer vertexBuffer = new VertexBuffer((uint32)sizeof(Vector3), (uint32)normals.Count, .Immutable);
|
VertexBuffer vertexBuffer = new VertexBuffer((uint32)sizeof(float3), (uint32)normals.Count, .Immutable);
|
||||||
vertexBuffer.SetData<Vector3>(normals);
|
vertexBuffer.SetData<float3>(normals);
|
||||||
|
|
||||||
bindings.Add(vertexBuffer.Binding);
|
bindings.Add(vertexBuffer.Binding);
|
||||||
|
|
||||||
@@ -555,20 +405,20 @@ namespace GlitchyEngine.Content
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Generates the normals for one triangle
|
/// Generates the normals for one triangle
|
||||||
static mixin GenerateTriangleNormals(int index0, int index1, int index2, CGLTF.Accessor* positions, Vector3[] normals)
|
static mixin GenerateTriangleNormals(int index0, int index1, int index2, CGLTF.Accessor* positions, float3[] normals)
|
||||||
{
|
{
|
||||||
Vector3 position0 = GetEntry<Vector3>(positions, (.)index0);
|
float3 position0 = GetEntry<float3>(positions, (.)index0);
|
||||||
Vector3 position1 = GetEntry<Vector3>(positions, (.)index1);
|
float3 position1 = GetEntry<float3>(positions, (.)index1);
|
||||||
Vector3 position2 = GetEntry<Vector3>(positions, (.)index2);
|
float3 position2 = GetEntry<float3>(positions, (.)index2);
|
||||||
|
|
||||||
ref Vector3 normal0 = ref normals[(.)index0];
|
ref float3 normal0 = ref normals[(.)index0];
|
||||||
ref Vector3 normal1 = ref normals[(.)index1];
|
ref float3 normal1 = ref normals[(.)index1];
|
||||||
ref Vector3 normal2 = ref normals[(.)index2];
|
ref float3 normal2 = ref normals[(.)index2];
|
||||||
|
|
||||||
Vector3 e0 = position1 - position0;
|
float3 e0 = position1 - position0;
|
||||||
Vector3 e1 = position2 - position0;
|
float3 e1 = position2 - position0;
|
||||||
|
|
||||||
Vector3 normal = Vector3.Cross(e0, e1);
|
float3 normal = cross(e0, e1);
|
||||||
|
|
||||||
normal0 += normal;
|
normal0 += normal;
|
||||||
normal1 += normal;
|
normal1 += normal;
|
||||||
@@ -576,16 +426,16 @@ namespace GlitchyEngine.Content
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Inline]
|
[Inline]
|
||||||
static void NormalizeNormals(Vector3[] normals)
|
static void NormalizeNormals(float3[] normals)
|
||||||
{
|
{
|
||||||
for(int i < normals.Count)
|
for(int i < normals.Count)
|
||||||
{
|
{
|
||||||
normals[i].Normalize();
|
normalize(normals[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates normals for the given model using indexed geometry
|
/// Generates normals for the given model using indexed geometry
|
||||||
static void GenerateNormals(CGLTF.Accessor* indices, CGLTF.Accessor* positions, Vector3[] normals)
|
static void GenerateNormals(CGLTF.Accessor* indices, CGLTF.Accessor* positions, float3[] normals)
|
||||||
{
|
{
|
||||||
/// Enumerate triangle-wise
|
/// Enumerate triangle-wise
|
||||||
for(uint t = 0; t < indices.Count; t += 3)
|
for(uint t = 0; t < indices.Count; t += 3)
|
||||||
@@ -601,7 +451,7 @@ namespace GlitchyEngine.Content
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Generates normals for the given model using nonindexed geometry
|
/// Generates normals for the given model using nonindexed geometry
|
||||||
static void GenerateNormals(CGLTF.Accessor* positions, Vector3[] normals)
|
static void GenerateNormals(CGLTF.Accessor* positions, float3[] normals)
|
||||||
{
|
{
|
||||||
/// Enumerate triangle-wise
|
/// Enumerate triangle-wise
|
||||||
for(int i = 0; i < (.)positions.Count; i += 3)
|
for(int i = 0; i < (.)positions.Count; i += 3)
|
||||||
@@ -704,7 +554,7 @@ namespace GlitchyEngine.Content
|
|||||||
for(int i < samples)
|
for(int i < samples)
|
||||||
{
|
{
|
||||||
float timeStamp = GetEntry<float>(channel.Sampler.Input, i);
|
float timeStamp = GetEntry<float>(channel.Sampler.Input, i);
|
||||||
Vector3 sample = GetEntry<Vector3>(channel.Sampler.Output, i);
|
float3 sample = GetEntry<float3>(channel.Sampler.Output, i);
|
||||||
|
|
||||||
jointAnimation.TranslationChannel.TimeStamps[i] = timeStamp;
|
jointAnimation.TranslationChannel.TimeStamps[i] = timeStamp;
|
||||||
jointAnimation.TranslationChannel.Values[i] = sample;
|
jointAnimation.TranslationChannel.Values[i] = sample;
|
||||||
@@ -732,7 +582,7 @@ namespace GlitchyEngine.Content
|
|||||||
for(int i < samples)
|
for(int i < samples)
|
||||||
{
|
{
|
||||||
float timeStamp = GetEntry<float>(channel.Sampler.Input, i);
|
float timeStamp = GetEntry<float>(channel.Sampler.Input, i);
|
||||||
Vector3 sample = GetEntry<Vector3>(channel.Sampler.Output, i);
|
float3 sample = GetEntry<float3>(channel.Sampler.Output, i);
|
||||||
|
|
||||||
jointAnimation.ScaleChannel.TimeStamps[i] = timeStamp;
|
jointAnimation.ScaleChannel.TimeStamps[i] = timeStamp;
|
||||||
jointAnimation.ScaleChannel.Values[i] = sample;
|
jointAnimation.ScaleChannel.Values[i] = sample;
|
||||||
@@ -756,11 +606,11 @@ namespace GlitchyEngine.Content
|
|||||||
{
|
{
|
||||||
case typeof(float):
|
case typeof(float):
|
||||||
CGLTF.AccessorReadFloat(accessor, (uint)index, (float*)&result, 1);
|
CGLTF.AccessorReadFloat(accessor, (uint)index, (float*)&result, 1);
|
||||||
case typeof(Vector2):
|
case typeof(float2):
|
||||||
CGLTF.AccessorReadFloat(accessor, (uint)index, (float*)&result, 2);
|
CGLTF.AccessorReadFloat(accessor, (uint)index, (float*)&result, 2);
|
||||||
case typeof(Vector3):
|
case typeof(float3):
|
||||||
CGLTF.AccessorReadFloat(accessor, (uint)index, (float*)&result, 3);
|
CGLTF.AccessorReadFloat(accessor, (uint)index, (float*)&result, 3);
|
||||||
case typeof(Vector4), typeof(Quaternion):
|
case typeof(float4), typeof(Quaternion):
|
||||||
CGLTF.AccessorReadFloat(accessor, (uint)index, (float*)&result, 4);
|
CGLTF.AccessorReadFloat(accessor, (uint)index, (float*)&result, 4);
|
||||||
case typeof(Matrix):
|
case typeof(Matrix):
|
||||||
CGLTF.AccessorReadFloat(accessor, (uint)index, (float*)&result, 16);
|
CGLTF.AccessorReadFloat(accessor, (uint)index, (float*)&result, 16);
|
||||||
|
|||||||
@@ -36,6 +36,11 @@ namespace GlitchyEngine.Core
|
|||||||
return (int)_uuid;
|
return (int)_uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void ToString(String strBuffer)
|
||||||
|
{
|
||||||
|
_uuid.ToString(strBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
static void Serialize(BonWriter writer, ValueView val, BonEnvironment env, SerializeValueState state)
|
static void Serialize(BonWriter writer, ValueView val, BonEnvironment env, SerializeValueState state)
|
||||||
{
|
{
|
||||||
UUID uuid = *(UUID*)val.dataPtr;
|
UUID uuid = *(UUID*)val.dataPtr;
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ namespace GlitchyEngine
|
|||||||
let sw = append Stopwatch(startNow);
|
let sw = append Stopwatch(startNow);
|
||||||
_stopwatch = sw;
|
_stopwatch = sw;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts or continues the internal timer.
|
* Starts or continues the internal timer.
|
||||||
*/
|
*/
|
||||||
@@ -98,5 +98,16 @@ namespace GlitchyEngine
|
|||||||
|
|
||||||
_frameCount++;
|
_frameCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells the timer that a frame has passed and updates the counters according to the given time step.
|
||||||
|
*/
|
||||||
|
public void ManualStepFrame(float deltaTimeSeconds)
|
||||||
|
{
|
||||||
|
_frameTime = TimeSpan.FromSeconds(deltaTimeSeconds);
|
||||||
|
_totalTime += _frameTime;
|
||||||
|
|
||||||
|
_frameCount++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,11 +20,10 @@ namespace GlitchyEngine.Generators
|
|||||||
outFileName.Append(name);
|
outFileName.Append(name);
|
||||||
outText.AppendF(
|
outText.AppendF(
|
||||||
$"""
|
$"""
|
||||||
namespace {Namespace}
|
namespace {Namespace};
|
||||||
|
|
||||||
|
struct {name}
|
||||||
{{
|
{{
|
||||||
struct {name}
|
|
||||||
{{
|
|
||||||
}}
|
|
||||||
}}
|
}}
|
||||||
""");
|
""");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
using DirectX.Common;
|
using DirectX.Common;
|
||||||
using GlitchyEngine.Core;
|
using GlitchyEngine.Core;
|
||||||
|
using System.Collections;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace GlitchyEngine
|
namespace GlitchyEngine
|
||||||
{
|
{
|
||||||
@@ -14,13 +16,22 @@ namespace GlitchyEngine
|
|||||||
oldDest?.ReleaseRef();
|
oldDest?.ReleaseRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Releases the reference to destination, writes newValue into it and adds a reference to newValue.
|
||||||
|
public static mixin SetReferenceVar<T>(T destination, T newValue) where T: var
|
||||||
|
{
|
||||||
|
var oldDest = destination;
|
||||||
|
destination = newValue;
|
||||||
|
destination?.AddRef();
|
||||||
|
oldDest?.Release();
|
||||||
|
}
|
||||||
|
|
||||||
/// Releases the reference to value and nullifies it.
|
/// Releases the reference to value and nullifies it.
|
||||||
public static mixin ReleaseRefAndNullify<T>(T value) where T: RefCounter
|
public static mixin ReleaseRefAndNullify<T>(T value) where T: RefCounter
|
||||||
{
|
{
|
||||||
value?.ReleaseRef();
|
value?.ReleaseRef();
|
||||||
value = null;
|
value = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static mixin DeleteContainerAndReleaseItems(var container)
|
public static mixin DeleteContainerAndReleaseItems(var container)
|
||||||
{
|
{
|
||||||
if (container != null)
|
if (container != null)
|
||||||
@@ -37,5 +48,50 @@ namespace GlitchyEngine
|
|||||||
value?.ReleaseRef();
|
value?.ReleaseRef();
|
||||||
container.Clear();
|
container.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static mixin DeleteDictionaryAndReleaseValues(var container)
|
||||||
|
{
|
||||||
|
if (container != null)
|
||||||
|
{
|
||||||
|
for (var value in container)
|
||||||
|
{
|
||||||
|
value.value?.ReleaseRef();
|
||||||
|
}
|
||||||
|
delete container;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static mixin ClearDictionaryAndDeleteKeys(var dictionary)
|
||||||
|
{
|
||||||
|
if (dictionary != null)
|
||||||
|
{
|
||||||
|
for (var value in dictionary)
|
||||||
|
delete value.key;
|
||||||
|
delete dictionary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static mixin ClearDictionaryAndDeleteValues(var dictionary)
|
||||||
|
{
|
||||||
|
if (dictionary != null)
|
||||||
|
{
|
||||||
|
for (var value in dictionary)
|
||||||
|
delete value.value;
|
||||||
|
delete dictionary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static mixin ClearDictionaryAndDeleteKeysAndValues(var dictionary)
|
||||||
|
{
|
||||||
|
if (dictionary != null)
|
||||||
|
{
|
||||||
|
for (var value in dictionary)
|
||||||
|
{
|
||||||
|
delete value.key;
|
||||||
|
delete value.value;
|
||||||
|
}
|
||||||
|
delete dictionary;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace GlitchyEngine.Math
|
|||||||
{
|
{
|
||||||
extension ColorRGBA
|
extension ColorRGBA
|
||||||
{
|
{
|
||||||
internal uint32 ImGuiU32 => ImGui.ImGui.ColorConvertFloat4ToU32((.)(Vector4)this);
|
internal uint32 ImGuiU32 => ImGui.ImGui.ColorConvertFloat4ToU32((.)(float4)this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,14 +20,14 @@ namespace ImGui
|
|||||||
{
|
{
|
||||||
extension Vec2
|
extension Vec2
|
||||||
{
|
{
|
||||||
public static explicit operator Vector2(Vec2 v) => .(v.x, v.y);
|
public static explicit operator float2(Vec2 v) => .(v.x, v.y);
|
||||||
public static explicit operator Vec2(Vector2 v) => .(v.X, v.Y);
|
public static explicit operator Vec2(float2 v) => .(v.X, v.Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Vec4
|
extension Vec4
|
||||||
{
|
{
|
||||||
public static explicit operator Vector4(Vec4 v) => .(v.x, v.y, v.z, v.w);
|
public static explicit operator float4(Vec4 v) => .(v.x, v.y, v.z, v.w);
|
||||||
public static explicit operator Vec4(Vector4 v) => .(v.X, v.Y, v.Z, v.W);
|
public static explicit operator Vec4(float4 v) => .(v.X, v.Y, v.Z, v.W);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*public static bool IsItemJustDeactivated()
|
/*public static bool IsItemJustDeactivated()
|
||||||
@@ -75,7 +75,7 @@ namespace ImGui
|
|||||||
if (uv0 != .Zero || uv1 != .Ones)
|
if (uv0 != .Zero || uv1 != .Ones)
|
||||||
Runtime.NotImplemented();
|
Runtime.NotImplemented();
|
||||||
|
|
||||||
Vector2 v = (.)subTexture.TexCoords.XY + subTexture.TexCoords.ZW;
|
float2 v = (.)subTexture.TexCoords.XY + subTexture.TexCoords.ZW;
|
||||||
|
|
||||||
Image(subTexture.Texture.GetViewBinding(), size, (.)subTexture.TexCoords.XY, (.)v, tint_col, border_col);
|
Image(subTexture.Texture.GetViewBinding(), size, (.)subTexture.TexCoords.XY, (.)v, tint_col, border_col);
|
||||||
}
|
}
|
||||||
@@ -92,7 +92,7 @@ namespace ImGui
|
|||||||
if (uv0 != .Zero || uv1 != .Ones)
|
if (uv0 != .Zero || uv1 != .Ones)
|
||||||
Runtime.NotImplemented();
|
Runtime.NotImplemented();
|
||||||
|
|
||||||
Vector2 v = (.)subTexture.TexCoords.XY + subTexture.TexCoords.ZW;
|
float2 v = (.)subTexture.TexCoords.XY + subTexture.TexCoords.ZW;
|
||||||
|
|
||||||
return ImageButton(subTexture.Texture.GetViewBinding(), size, (.)subTexture.TexCoords.XY, (.)v, frame_padding, bg_col, tint_col);
|
return ImageButton(subTexture.Texture.GetViewBinding(), size, (.)subTexture.TexCoords.XY, (.)v, frame_padding, bg_col, tint_col);
|
||||||
}
|
}
|
||||||
@@ -107,19 +107,19 @@ namespace ImGui
|
|||||||
protected internal static extern void CleanupFrame();
|
protected internal static extern void CleanupFrame();
|
||||||
|
|
||||||
/// Control to edit a vector 2 with drag functionality and reset buttons
|
/// Control to edit a vector 2 with drag functionality and reset buttons
|
||||||
public static bool EditVector2(StringView label, ref Vector2 value, Vector2 resetValues = .Zero, float dragSpeed = 0.1f, float columnWidth = 100f, Vector2 minValue = .Zero, Vector2 maxValue = .Zero)
|
public static bool Editfloat2(StringView label, ref float2 value, float2 resetValues = .Zero, float dragSpeed = 0.1f, float columnWidth = 100f, float2 minValue = .Zero, float2 maxValue = .Zero)
|
||||||
{
|
{
|
||||||
return EditVector<2>(label, ref *(float[2]*)&value, (float[2])resetValues, dragSpeed, columnWidth, (float[2])minValue, (float[2])maxValue);
|
return EditVector<2>(label, ref *(float[2]*)&value, (float[2])resetValues, dragSpeed, columnWidth, (float[2])minValue, (float[2])maxValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Control to edit a vector 3 with drag functionality and reset buttons
|
/// Control to edit a vector 3 with drag functionality and reset buttons
|
||||||
public static bool EditVector3(StringView label, ref Vector3 value, Vector3 resetValues = .Zero, float dragSpeed = 0.1f, float columnWidth = 100f, Vector3 minValue = .Zero, Vector3 maxValue = .Zero)
|
public static bool Editfloat3(StringView label, ref float3 value, float3 resetValues = .Zero, float dragSpeed = 0.1f, float columnWidth = 100f, float3 minValue = .Zero, float3 maxValue = .Zero)
|
||||||
{
|
{
|
||||||
return EditVector<3>(label, ref *(float[3]*)&value, (float[3])resetValues, dragSpeed, columnWidth, (float[3])minValue, (float[3])maxValue);
|
return EditVector<3>(label, ref *(float[3]*)&value, (float[3])resetValues, dragSpeed, columnWidth, (float[3])minValue, (float[3])maxValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Control to edit a vector 4 with drag functionality and reset buttons
|
/// Control to edit a vector 4 with drag functionality and reset buttons
|
||||||
public static bool EditVector4(StringView label, ref Vector4 value, Vector4 resetValues = .Zero, float dragSpeed = 0.1f, float columnWidth = 100f, Vector4 minValue = .Zero, Vector4 maxValue = .Zero)
|
public static bool Editfloat4(StringView label, ref float4 value, float4 resetValues = .Zero, float dragSpeed = 0.1f, float columnWidth = 100f, float4 minValue = .Zero, float4 maxValue = .Zero)
|
||||||
{
|
{
|
||||||
return EditVector<4>(label, ref *(float[4]*)&value, (float[4])resetValues, dragSpeed, columnWidth, (float[4])minValue, (float[4])maxValue);
|
return EditVector<4>(label, ref *(float[4]*)&value, (float[4])resetValues, dragSpeed, columnWidth, (float[4])minValue, (float[4])maxValue);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,8 +119,6 @@ namespace GlitchyEngine.ImGui
|
|||||||
|
|
||||||
Begin();
|
Begin();
|
||||||
|
|
||||||
ImGui.ShowDemoWindow();
|
|
||||||
|
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileScope!("ImGuiRenderEvent");
|
Debug.Profiler.ProfileScope!("ImGuiRenderEvent");
|
||||||
|
|
||||||
@@ -142,7 +140,11 @@ namespace GlitchyEngine.ImGui
|
|||||||
RenderCommand.BindRenderTargets();
|
RenderCommand.BindRenderTargets();
|
||||||
|
|
||||||
#if GE_GRAPHICS_DX11
|
#if GE_GRAPHICS_DX11
|
||||||
ImGuiImplDX11.RenderDrawData(ImGui.GetDrawData());
|
|
||||||
|
using (ContextMonitor.Enter())
|
||||||
|
{
|
||||||
|
ImGuiImplDX11.RenderDrawData(ImGui.GetDrawData());
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ImGui.CleanupFrame();
|
ImGui.CleanupFrame();
|
||||||
|
|||||||
+10
-10
@@ -28,15 +28,15 @@ namespace GlitchyEngine
|
|||||||
public static extern bool IsKeyReleasing(Key keycode);
|
public static extern bool IsKeyReleasing(Key keycode);
|
||||||
|
|
||||||
// TODO: Should Input be able to set mousepos?
|
// TODO: Should Input be able to set mousepos?
|
||||||
public static extern void SetMousePosition(Int2 pos);
|
public static extern void SetMousePosition(int2 pos);
|
||||||
|
|
||||||
public static extern bool IsMouseButtonPressed(MouseButton button);
|
public static extern bool IsMouseButtonPressed(MouseButton button);
|
||||||
public static extern bool IsMouseButtonReleased(MouseButton button);
|
public static extern bool IsMouseButtonReleased(MouseButton button);
|
||||||
public static extern bool IsMouseButtonPressing(MouseButton button);
|
public static extern bool IsMouseButtonPressing(MouseButton button);
|
||||||
public static extern bool IsMouseButtonReleasing(MouseButton button);
|
public static extern bool IsMouseButtonReleasing(MouseButton button);
|
||||||
public static extern Int2 GetMousePosition();
|
public static extern int2 GetMousePosition();
|
||||||
public static extern Int2 GetMouseMovement();
|
public static extern int2 GetMouseMovement();
|
||||||
public static extern Int2 GetRawMouseMovement();
|
public static extern int2 GetRawMouseMovement();
|
||||||
public static extern int32 GetMouseX();
|
public static extern int32 GetMouseX();
|
||||||
public static extern int32 GetMouseY();
|
public static extern int32 GetMouseY();
|
||||||
|
|
||||||
@@ -44,9 +44,9 @@ namespace GlitchyEngine
|
|||||||
// public static extern bool WasMouseButtonPressing(MouseButton button);
|
// public static extern bool WasMouseButtonPressing(MouseButton button);
|
||||||
public static extern bool WasMouseButtonReleased(MouseButton button);
|
public static extern bool WasMouseButtonReleased(MouseButton button);
|
||||||
//public static extern bool WasMouseButtonReleasing(MouseButton button);
|
//public static extern bool WasMouseButtonReleasing(MouseButton button);
|
||||||
public static extern Int2 GetLastMousePosition();
|
public static extern int2 GetLastMousePosition();
|
||||||
public static extern Int2 GetLastMouseMovement();
|
public static extern int2 GetLastMouseMovement();
|
||||||
public static extern Int2 GetLastRawMouseMovement();
|
public static extern int2 GetLastRawMouseMovement();
|
||||||
public static extern int32 GetLastMouseX();
|
public static extern int32 GetLastMouseX();
|
||||||
public static extern int32 GetLastMouseY();
|
public static extern int32 GetLastMouseY();
|
||||||
|
|
||||||
@@ -121,14 +121,14 @@ namespace GlitchyEngine
|
|||||||
|
|
||||||
public static class Mouse
|
public static class Mouse
|
||||||
{
|
{
|
||||||
private static append List<(Int2 Position, int Hash)> _lockPositions = .();
|
private static append List<(int2 Position, int Hash)> _lockPositions = .();
|
||||||
|
|
||||||
public static void LockCurrentPosition(int hash)
|
public static void LockCurrentPosition(int hash)
|
||||||
{
|
{
|
||||||
LockPosition(Input.GetMousePosition(), hash);
|
LockPosition(Input.GetMousePosition(), hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void LockPosition(Int2 pos, int hash)
|
public static void LockPosition(int2 pos, int hash)
|
||||||
{
|
{
|
||||||
for (var entry in _lockPositions)
|
for (var entry in _lockPositions)
|
||||||
{
|
{
|
||||||
@@ -156,7 +156,7 @@ namespace GlitchyEngine
|
|||||||
//Log.EngineLogger.AssertDebug(false, "No mouse lock position with hash found.");
|
//Log.EngineLogger.AssertDebug(false, "No mouse lock position with hash found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Int2? LockedPosition;
|
public static int2? LockedPosition;
|
||||||
|
|
||||||
public static void NewFrame()
|
public static void NewFrame()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -53,10 +53,10 @@ namespace GlitchyEngine.Math
|
|||||||
|
|
||||||
[Inline]
|
[Inline]
|
||||||
#unwarn
|
#unwarn
|
||||||
public static explicit operator Vector3(ColorRGB color) => *(Vector3*)&color;
|
public static explicit operator float3(ColorRGB color) => *(float3*)&color;
|
||||||
|
|
||||||
[Inline]
|
[Inline]
|
||||||
#unwarn
|
#unwarn
|
||||||
public static explicit operator ColorRGB(Vector3 color) => *(ColorRGB*)&color;
|
public static explicit operator ColorRGB(float3 color) => *(ColorRGB*)&color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -329,10 +329,10 @@ namespace GlitchyEngine.Math
|
|||||||
|
|
||||||
[Inline]
|
[Inline]
|
||||||
#unwarn
|
#unwarn
|
||||||
public static explicit operator Vector4(ColorRGBA color) => *(Vector4*)&color;
|
public static explicit operator float4(ColorRGBA color) => *(float4*)&color;
|
||||||
|
|
||||||
[Inline]
|
[Inline]
|
||||||
#unwarn
|
#unwarn
|
||||||
public static explicit operator ColorRGBA(Vector4 color) => *(ColorRGBA*)&color;
|
public static explicit operator ColorRGBA(float4 color) => *(ColorRGBA*)&color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,12 +13,12 @@ namespace System
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Inline]
|
[Inline]
|
||||||
public Vector2 XX => Vector2((float)this);
|
public float2 XX => (float2)this;
|
||||||
|
|
||||||
[Inline]
|
[Inline]
|
||||||
public Vector3 XXX => Vector3((float)this);
|
public float3 XXX => (float3)this;
|
||||||
|
|
||||||
[Inline]
|
[Inline]
|
||||||
public Vector4 XXXX => Vector4((float)this);
|
public float4 XXXX => (float4)this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,12 +13,32 @@ namespace System
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Inline]
|
[Inline]
|
||||||
public Int2 XX => Int2((int32)this);
|
public int2 XX => (int32)this;
|
||||||
|
|
||||||
[Inline]
|
[Inline]
|
||||||
public Int3 XXX => Int3((int32)this);
|
public int3 XXX => (int32)this;
|
||||||
|
|
||||||
[Inline]
|
[Inline]
|
||||||
public Int4 XXXX => Int4((int32)this);
|
public int4 XXXX => (int32)this;
|
||||||
|
}
|
||||||
|
|
||||||
|
extension UInt32
|
||||||
|
{
|
||||||
|
public uint32 X
|
||||||
|
{
|
||||||
|
[Inline]
|
||||||
|
get => (uint32)this;
|
||||||
|
[Inline]
|
||||||
|
set mut => this = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Inline]
|
||||||
|
public uint2 XX => (uint32)this;
|
||||||
|
|
||||||
|
[Inline]
|
||||||
|
public uint3 XXX => (uint32)this;
|
||||||
|
|
||||||
|
[Inline]
|
||||||
|
public uint4 XXXX => (uint32)this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,831 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Math;
|
||||||
|
|
||||||
|
// TODO: Not all functions are available for scalars yet
|
||||||
|
|
||||||
|
static
|
||||||
|
{
|
||||||
|
/// Returns true if at least one of the components is true.
|
||||||
|
public static bool any(bool value) => value;
|
||||||
|
/// Returns true if at least one of the components is true.
|
||||||
|
public static bool any(bool2 value) => value.X || value.Y;
|
||||||
|
/// Returns true if at least one of the components is true.
|
||||||
|
public static bool any(bool3 value) => value.X || value.Y || value.Z;
|
||||||
|
/// Returns true if at least one of the components is true.
|
||||||
|
public static bool any(bool4 value) => value.X || value.Y || value.Z || value.W;
|
||||||
|
|
||||||
|
/// Returns true if all of the components are true.
|
||||||
|
public static bool all(bool value) => value;
|
||||||
|
/// Returns true if all of the components are true.
|
||||||
|
public static bool all(bool2 value) => value.X && value.Y;
|
||||||
|
/// Returns true if all of the components are true.
|
||||||
|
public static bool all(bool3 value) => value.X && value.Y && value.Z;
|
||||||
|
/// Returns true if all of the components are true.
|
||||||
|
public static bool all(bool4 value) => value.X && value.Y && value.Z && value.W;
|
||||||
|
|
||||||
|
#region abs
|
||||||
|
|
||||||
|
public static float abs(float value)
|
||||||
|
{
|
||||||
|
return Math.Abs(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float2 abs(float2 value)
|
||||||
|
{
|
||||||
|
return float2(Math.Abs(value.X), Math.Abs(value.Y));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float3 abs(float3 value)
|
||||||
|
{
|
||||||
|
return float3(Math.Abs(value.X), Math.Abs(value.Y), Math.Abs(value.Z));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float4 abs(float4 value)
|
||||||
|
{
|
||||||
|
return float4(Math.Abs(value.X), Math.Abs(value.Y), Math.Abs(value.Z), Math.Abs(value.W));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int abs(int value)
|
||||||
|
{
|
||||||
|
return Math.Abs(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int2 abs(int2 value)
|
||||||
|
{
|
||||||
|
return int2(Math.Abs(value.X), Math.Abs(value.Y));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int3 abs(int3 value)
|
||||||
|
{
|
||||||
|
return int3(Math.Abs(value.X), Math.Abs(value.Y), Math.Abs(value.Z));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int4 abs(int4 value)
|
||||||
|
{
|
||||||
|
return int4(Math.Abs(value.X), Math.Abs(value.Y), Math.Abs(value.Z), Math.Abs(value.W));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region modf / frac / trunc
|
||||||
|
|
||||||
|
// Splits the value x into fractional and integer parts, each of which has the same sign as x.
|
||||||
|
public static float modf(float x, out float integerPart)
|
||||||
|
{
|
||||||
|
return Math.[Friend]modff(x.X, out integerPart);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Splits the value x into fractional and integer parts, each of which has the same sign as x.
|
||||||
|
public static float2 modf(float2 x, out float2 integerPart)
|
||||||
|
{
|
||||||
|
float2 fracPart;
|
||||||
|
|
||||||
|
fracPart.X = Math.[Friend]modff(x.X, out integerPart.X);
|
||||||
|
fracPart.Y = Math.[Friend]modff(x.Y, out integerPart.Y);
|
||||||
|
|
||||||
|
return fracPart;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Splits the value x into fractional and integer parts, each of which has the same sign as x.
|
||||||
|
public static float3 modf(float3 x, out float3 integerPart)
|
||||||
|
{
|
||||||
|
float3 fracPart;
|
||||||
|
|
||||||
|
fracPart.X = Math.[Friend]modff(x.X, out integerPart.X);
|
||||||
|
fracPart.Y = Math.[Friend]modff(x.Y, out integerPart.Y);
|
||||||
|
fracPart.Z = Math.[Friend]modff(x.Z, out integerPart.Z);
|
||||||
|
|
||||||
|
return fracPart;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Splits the value x into fractional and integer parts, each of which has the same sign as x.
|
||||||
|
public static float4 modf(float4 x, out float4 integerPart)
|
||||||
|
{
|
||||||
|
float4 fracPart;
|
||||||
|
|
||||||
|
fracPart.X = Math.[Friend]modff(x.X, out integerPart.X);
|
||||||
|
fracPart.Y = Math.[Friend]modff(x.Y, out integerPart.Y);
|
||||||
|
fracPart.Z = Math.[Friend]modff(x.Z, out integerPart.Z);
|
||||||
|
fracPart.W = Math.[Friend]modff(x.W, out integerPart.W);
|
||||||
|
|
||||||
|
return fracPart;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Returns the fractional (or decimal) part of x; which is greater than or equal to 0 and less than 1.
|
||||||
|
public static float2 frac(float2 x) => [Inline]modf(x, let _);
|
||||||
|
|
||||||
|
// Returns the fractional (or decimal) part of x; which is greater than or equal to 0 and less than 1.
|
||||||
|
public static float3 frac(float3 x) => [Inline]modf(x, let _);
|
||||||
|
|
||||||
|
// Returns the fractional (or decimal) part of x; which is greater than or equal to 0 and less than 1.
|
||||||
|
public static float4 frac(float4 x) => [Inline]modf(x, let _);
|
||||||
|
|
||||||
|
|
||||||
|
// Truncates a floating-point value to the integer component.
|
||||||
|
public static float2 trunc(float2 x)
|
||||||
|
{
|
||||||
|
return float2(Math.Truncate(x.X), Math.Truncate(x.Y));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Truncates a floating-point value to the integer component.
|
||||||
|
public static float3 trunc(float3 x)
|
||||||
|
{
|
||||||
|
return float3(Math.Truncate(x.X), Math.Truncate(x.Y), Math.Truncate(x.Z));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Truncates a floating-point value to the integer component.
|
||||||
|
public static float4 trunc(float4 x)
|
||||||
|
{
|
||||||
|
return float4(Math.Truncate(x.X), Math.Truncate(x.Y), Math.Truncate(x.Z), Math.Truncate(x.W));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region infinity and nan check
|
||||||
|
|
||||||
|
/// Determines if the specified floating-point value is finite.
|
||||||
|
public static bool2 isfinite(float2 value)
|
||||||
|
{
|
||||||
|
return bool2(value.X.IsFinite, value.Y.IsFinite);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determines if the specified floating-point value is finite.
|
||||||
|
public static bool3 isfinite(float3 value)
|
||||||
|
{
|
||||||
|
return bool3(value.X.IsFinite, value.Y.IsFinite, value.Z.IsFinite);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determines if the specified floating-point value is finite.
|
||||||
|
public static bool4 isfinite(float4 value)
|
||||||
|
{
|
||||||
|
return bool4(value.X.IsFinite, value.Y.IsFinite, value.Z.IsFinite, value.W.IsFinite);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determines if the specified value is infinite.
|
||||||
|
public static bool2 isinf(float2 value)
|
||||||
|
{
|
||||||
|
return bool2(value.X.IsInfinity, value.Y.IsInfinity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determines if the specified value is infinite.
|
||||||
|
public static bool3 isinf(float3 value)
|
||||||
|
{
|
||||||
|
return bool3(value.X.IsInfinity, value.Y.IsInfinity, value.Z.IsInfinity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determines if the specified value is infinite.
|
||||||
|
public static bool4 isinf(float4 value)
|
||||||
|
{
|
||||||
|
return bool4(value.X.IsInfinity, value.Y.IsInfinity, value.Z.IsInfinity, value.W.IsInfinity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determines if the specified value is infinite.
|
||||||
|
public static bool2 isnan(float2 value)
|
||||||
|
{
|
||||||
|
return bool2(value.X.IsNaN, value.Y.IsNaN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determines if the specified value is infinite.
|
||||||
|
public static bool3 isnan(float3 value)
|
||||||
|
{
|
||||||
|
return bool3(value.X.IsNaN, value.Y.IsNaN, value.Z.IsNaN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determines if the specified value is infinite.
|
||||||
|
public static bool4 isnan(float4 value)
|
||||||
|
{
|
||||||
|
return bool4(value.X.IsNaN, value.Y.IsNaN, value.Z.IsNaN, value.W.IsNaN);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Sign
|
||||||
|
|
||||||
|
/// Returns the sign of x.
|
||||||
|
public static int32 sign(float x)
|
||||||
|
{
|
||||||
|
return (int32)Math.Sign(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the sign of x.
|
||||||
|
public static int2 sign(float2 x)
|
||||||
|
{
|
||||||
|
return int2((int32)Math.Sign(x.X), (int32)Math.Sign(x.Y));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the sign of x.
|
||||||
|
public static int3 sign(float3 x)
|
||||||
|
{
|
||||||
|
return int3((int32)Math.Sign(x.X), (int32)Math.Sign(x.Y), (int32)Math.Sign(x.Z));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the sign of x.
|
||||||
|
public static int4 sign(float4 x)
|
||||||
|
{
|
||||||
|
return int4((int32)Math.Sign(x.X), (int32)Math.Sign(x.Y), (int32)Math.Sign(x.Z), (int32)Math.Sign(x.W));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the sign of x.
|
||||||
|
public static int32 sign(int x)
|
||||||
|
{
|
||||||
|
return (int32)Math.Sign(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the sign of x.
|
||||||
|
public static int2 sign(int2 x)
|
||||||
|
{
|
||||||
|
return int2((int32)Math.Sign(x.X), (int32)Math.Sign(x.Y));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the sign of x.
|
||||||
|
public static int3 sign(int3 x)
|
||||||
|
{
|
||||||
|
return int3((int32)Math.Sign(x.X), (int32)Math.Sign(x.Y), (int32)Math.Sign(x.Z));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the sign of x.
|
||||||
|
public static int4 sign(int4 x)
|
||||||
|
{
|
||||||
|
return int4((int32)Math.Sign(x.X), (int32)Math.Sign(x.Y), (int32)Math.Sign(x.Z), (int32)Math.Sign(x.W));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ceil / floor / round
|
||||||
|
|
||||||
|
public static float ceil(float value)
|
||||||
|
{
|
||||||
|
return Math.Ceiling(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float2 ceil(float2 value)
|
||||||
|
{
|
||||||
|
return float2(Math.Ceiling(value.X), Math.Ceiling(value.Y));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float3 ceil(float3 value)
|
||||||
|
{
|
||||||
|
return float3(Math.Ceiling(value.X), Math.Ceiling(value.Y), Math.Ceiling(value.Z));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float4 ceil(float4 value)
|
||||||
|
{
|
||||||
|
return float4(Math.Ceiling(value.X), Math.Ceiling(value.Y), Math.Ceiling(value.Z), Math.Ceiling(value.W));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float floor(float value)
|
||||||
|
{
|
||||||
|
return Math.Floor(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float2 floor(float2 value)
|
||||||
|
{
|
||||||
|
return float2(Math.Floor(value.X), Math.Floor(value.Y));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float3 floor(float3 value)
|
||||||
|
{
|
||||||
|
return float3(Math.Floor(value.X), Math.Floor(value.Y), Math.Floor(value.Z));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float4 floor(float4 value)
|
||||||
|
{
|
||||||
|
return float4(Math.Floor(value.X), Math.Floor(value.Y), Math.Floor(value.Z), Math.Floor(value.W));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rounds the specified value to the nearest integer.
|
||||||
|
public static float round(float value)
|
||||||
|
{
|
||||||
|
return Math.Round(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rounds the specified value to the nearest integer.
|
||||||
|
public static float2 round(float2 value)
|
||||||
|
{
|
||||||
|
return float2(Math.Round(value.X), Math.Round(value.Y));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rounds the specified value to the nearest integer.
|
||||||
|
public static float3 round(float3 value)
|
||||||
|
{
|
||||||
|
return float3(Math.Round(value.X), Math.Round(value.Y), Math.Round(value.Z));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rounds the specified value to the nearest integer.
|
||||||
|
public static float4 round(float4 value)
|
||||||
|
{
|
||||||
|
return float4(Math.Round(value.X), Math.Round(value.Y), Math.Round(value.Z), Math.Round(value.W));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region min / max
|
||||||
|
|
||||||
|
public static float min(float x, float y)
|
||||||
|
{
|
||||||
|
return Math.Min(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float2 min(float2 x, float2 y)
|
||||||
|
{
|
||||||
|
return float2(Math.Min(x.X, y.X), Math.Min(x.Y, y.Y));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float3 min(float3 x, float3 y)
|
||||||
|
{
|
||||||
|
return float3(Math.Min(x.X, y.X), Math.Min(x.Y, y.Y), Math.Min(x.Z, y.Z));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float4 min(float4 x, float4 y)
|
||||||
|
{
|
||||||
|
return float4(Math.Min(x.X, y.X), Math.Min(x.Y, y.Y), Math.Min(x.Z, y.Z), Math.Min(x.W, y.W));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float max(float x, float y)
|
||||||
|
{
|
||||||
|
return Math.Max(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float2 max(float2 x, float2 y)
|
||||||
|
{
|
||||||
|
return float2(Math.Max(x.X, y.X), Math.Max(x.Y, y.Y));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float3 max(float3 x, float3 y)
|
||||||
|
{
|
||||||
|
return float3(Math.Max(x.X, y.X), Math.Max(x.Y, y.Y), Math.Max(x.Z, y.Z));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float4 max(float4 x, float4 y)
|
||||||
|
{
|
||||||
|
return float4(Math.Max(x.X, y.X), Math.Max(x.Y, y.Y), Math.Max(x.Z, y.Z), Math.Max(x.W, y.W));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region exp, pow, log
|
||||||
|
|
||||||
|
// TODO: log, log10, log2
|
||||||
|
|
||||||
|
/// Returns x raised to the power of y.
|
||||||
|
public static float pow(float x, float y)
|
||||||
|
{
|
||||||
|
return Math.Pow(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns x raised to the power of y.
|
||||||
|
public static float2 pow(float2 x, float2 y)
|
||||||
|
{
|
||||||
|
return float2(Math.Pow(x.X, y.X), Math.Pow(x.Y, y.Y));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns x raised to the power of y.
|
||||||
|
public static float3 pow(float3 x, float3 y)
|
||||||
|
{
|
||||||
|
return float3(Math.Pow(x.X, y.X), Math.Pow(x.Y, y.Y), Math.Pow(x.Z, y.Z));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns x raised to the power of y.
|
||||||
|
public static float4 pow(float4 x, float4 y)
|
||||||
|
{
|
||||||
|
return float4(Math.Pow(x.X, y.X), Math.Pow(x.Y, y.Y), Math.Pow(x.Z, y.Z), Math.Pow(x.W, y.W));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the base-e exponential, or e^x, of the specified value.
|
||||||
|
public static float exp(float x)
|
||||||
|
{
|
||||||
|
return Math.Exp(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the base-e exponential, or e^x, of the specified value.
|
||||||
|
public static float2 exp(float2 x)
|
||||||
|
{
|
||||||
|
return float2(Math.Exp(x.X), Math.Exp(x.Y));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the base-e exponential, or e^x, of the specified value.
|
||||||
|
public static float3 exp(float3 x)
|
||||||
|
{
|
||||||
|
return float3(Math.Exp(x.X), Math.Exp(x.Y), Math.Exp(x.Z));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the base-e exponential, or e^x, of the specified value.
|
||||||
|
public static float4 exp(float4 x)
|
||||||
|
{
|
||||||
|
return float4(Math.Exp(x.X), Math.Exp(x.Y), Math.Exp(x.Z), Math.Exp(x.W));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the base 2 exponential, or 2^x, of the specified value.
|
||||||
|
public static float exp2(float x)
|
||||||
|
{
|
||||||
|
return Math.Pow(2, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the base 2 exponential, or 2^x, of the specified value.
|
||||||
|
public static float2 exp2(float2 x)
|
||||||
|
{
|
||||||
|
return float2(Math.Pow(2, x.X), Math.Pow(2, x.Y));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the base 2 exponential, or 2^x, of the specified value.
|
||||||
|
public static float3 exp2(float3 x)
|
||||||
|
{
|
||||||
|
return float3(Math.Pow(2, x.X), Math.Pow(2, x.Y), Math.Pow(2, x.Z));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the base 2 exponential, or 2^x, of the specified value.
|
||||||
|
public static float4 exp2(float4 x)
|
||||||
|
{
|
||||||
|
return float4(Math.Pow(2, x.X), Math.Pow(2, x.Y), Math.Pow(2, x.Z), Math.Pow(2, x.W));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Degrees / Radians
|
||||||
|
|
||||||
|
public static float toDegrees(float radians) => radians * MathHelper.RadToDeg;
|
||||||
|
public static float2 toDegrees(float2 radians) => radians * MathHelper.RadToDeg;
|
||||||
|
public static float3 toDegrees(float3 radians) => radians * MathHelper.RadToDeg;
|
||||||
|
public static float4 toDegrees(float4 radians) => radians * MathHelper.RadToDeg;
|
||||||
|
|
||||||
|
public static float toRadians(float degrees) => degrees * MathHelper.DegToRad;
|
||||||
|
public static float2 toRadians(float2 degrees) => degrees * MathHelper.DegToRad;
|
||||||
|
public static float3 toRadians(float3 degrees) => degrees * MathHelper.DegToRad;
|
||||||
|
public static float4 toRadians(float4 degrees) => degrees * MathHelper.DegToRad;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Clamp
|
||||||
|
|
||||||
|
public static float clamp(float value, float min, float max)
|
||||||
|
{
|
||||||
|
return Math.Clamp(value.X, min.X, max.X);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float2 clamp(float2 value, float2 min, float2 max)
|
||||||
|
{
|
||||||
|
return float2(Math.Clamp(value.X, min.X, max.X), Math.Clamp(value.Y, min.Y, max.Y));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float3 clamp(float3 value, float3 min, float3 max)
|
||||||
|
{
|
||||||
|
return float3(Math.Clamp(value.X, min.X, max.X), Math.Clamp(value.Y, min.Y, max.Y), Math.Clamp(value.Z, min.Z, max.Z));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float4 clamp(float4 value, float4 min, float4 max)
|
||||||
|
{
|
||||||
|
return float4(Math.Clamp(value.X, min.X, max.X), Math.Clamp(value.Y, min.Y, max.Y), Math.Clamp(value.Z, min.Z, max.Z), Math.Clamp(value.W, min.W, max.W));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int2 clamp(int2 value, int2 min, int2 max)
|
||||||
|
{
|
||||||
|
return int2(Math.Clamp(value.X, min.X, max.X), Math.Clamp(value.Y, min.Y, max.Y));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int3 clamp(int3 value, int3 min, int3 max)
|
||||||
|
{
|
||||||
|
return int3(Math.Clamp(value.X, min.X, max.X), Math.Clamp(value.Y, min.Y, max.Y), Math.Clamp(value.Z, min.Z, max.Z));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int4 clamp(int4 value, int4 min, int4 max)
|
||||||
|
{
|
||||||
|
return int4(Math.Clamp(value.X, min.X, max.X), Math.Clamp(value.Y, min.Y, max.Y), Math.Clamp(value.Z, min.Z, max.Z), Math.Clamp(value.W, min.W, max.W));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Lerp
|
||||||
|
|
||||||
|
/// Performs a linear interpolation.
|
||||||
|
// @param x The first vector value.
|
||||||
|
// @param y The second vector value.
|
||||||
|
// @param y A value that linearly interpolates between x and y.
|
||||||
|
public static float lerp(float x, float y, float s)
|
||||||
|
{
|
||||||
|
return x + s * (y - x);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Performs a linear interpolation.
|
||||||
|
// @param x The first vector value.
|
||||||
|
// @param y The second vector value.
|
||||||
|
// @param y A value that linearly interpolates between x and y.
|
||||||
|
public static float2 lerp(float2 x, float2 y, float s)
|
||||||
|
{
|
||||||
|
return x + s * (y - x);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Performs a linear interpolation.
|
||||||
|
// @param x The first vector value.
|
||||||
|
// @param y The second vector value.
|
||||||
|
// @param y A value that linearly interpolates between x and y.
|
||||||
|
public static float3 lerp(float3 x, float3 y, float s)
|
||||||
|
{
|
||||||
|
return x + s * (y - x);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Performs a linear interpolation.
|
||||||
|
// @param x The first vector value.
|
||||||
|
// @param y The second vector value.
|
||||||
|
// @param y A value that linearly interpolates between x and y.
|
||||||
|
public static float4 lerp(float4 x, float4 y, float s)
|
||||||
|
{
|
||||||
|
return x + s * (y - x);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
// mul? hlsl has like 280 overloads...
|
||||||
|
|
||||||
|
public static float normalize(float value) => 1.0f;
|
||||||
|
public static float2 normalize(float2 value) => value / length(value);
|
||||||
|
public static float3 normalize(float3 value) => value / length(value);
|
||||||
|
public static float4 normalize(float4 value) => value / length(value);
|
||||||
|
|
||||||
|
// pow
|
||||||
|
|
||||||
|
#region Reflect and Refract
|
||||||
|
|
||||||
|
/// Returns a reflection vector using an incident ray and a surface normal.
|
||||||
|
public static float2 reflect(float2 incident, float2 normal) => incident - 2 * normal * dot(incident, normal);
|
||||||
|
/// Returns a reflection vector using an incident ray and a surface normal.
|
||||||
|
public static float3 reflect(float3 incident, float3 normal) => incident - 2 * normal * dot(incident, normal);
|
||||||
|
/// Returns a reflection vector using an incident ray and a surface normal.
|
||||||
|
public static float4 reflect(float4 incident, float4 normal) => incident - 2 * normal * dot(incident, normal);
|
||||||
|
|
||||||
|
// Source: https://thebookofshaders.com/glossary/?search=refract
|
||||||
|
/// Returns a refraction vector using an entering ray, a surface normal, and a refraction index.
|
||||||
|
public static float2 refract(float2 incident, float2 normal, float refractionIndex)
|
||||||
|
{
|
||||||
|
float dot_n_i = dot(normal, incident);
|
||||||
|
|
||||||
|
float k = 1.0f - refractionIndex * refractionIndex * (1.0f - dot_n_i * dot_n_i);
|
||||||
|
|
||||||
|
if (k < 0.0f)
|
||||||
|
return 0.0f;
|
||||||
|
else
|
||||||
|
return refractionIndex * incident - (refractionIndex * dot_n_i + sqrt(k));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a refraction vector using an entering ray, a surface normal, and a refraction index.
|
||||||
|
public static float3 refract(float3 incident, float3 normal, float refractionIndex)
|
||||||
|
{
|
||||||
|
float dot_n_i = dot(normal, incident);
|
||||||
|
|
||||||
|
float k = 1.0f - refractionIndex * refractionIndex * (1.0f - dot_n_i * dot_n_i);
|
||||||
|
|
||||||
|
if (k < 0.0f)
|
||||||
|
return 0.0f;
|
||||||
|
else
|
||||||
|
return refractionIndex * incident - (refractionIndex * dot_n_i + sqrt(k));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a refraction vector using an entering ray, a surface normal, and a refraction index.
|
||||||
|
public static float4 refract(float4 incident, float4 normal, float refractionIndex)
|
||||||
|
{
|
||||||
|
float dot_n_i = dot(normal, incident);
|
||||||
|
|
||||||
|
float k = 1.0f - refractionIndex * refractionIndex * (1.0f - dot_n_i * dot_n_i);
|
||||||
|
|
||||||
|
if (k < 0.0f)
|
||||||
|
return 0.0f;
|
||||||
|
else
|
||||||
|
return refractionIndex * incident - (refractionIndex * dot_n_i + sqrt(k));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// Calculates the per component square root of the given value.
|
||||||
|
public static float sqrt(float value)
|
||||||
|
{
|
||||||
|
return Math.Sqrt(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calculates the per component square root of the given value.
|
||||||
|
public static float2 sqrt(float2 value)
|
||||||
|
{
|
||||||
|
return float2(Math.Sqrt(value.X), Math.Sqrt(value.Y));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calculates the per component square root of the given value.
|
||||||
|
public static float3 sqrt(float3 value)
|
||||||
|
{
|
||||||
|
return float3(Math.Sqrt(value.X), Math.Sqrt(value.Y), Math.Sqrt(value.Z));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calculates the per component square root of the given value.
|
||||||
|
public static float4 sqrt(float4 value)
|
||||||
|
{
|
||||||
|
return float4(Math.Sqrt(value.X), Math.Sqrt(value.Y), Math.Sqrt(value.Z), Math.Sqrt(value.W));
|
||||||
|
}
|
||||||
|
|
||||||
|
// saturate (I don't think there is a faster way than simply using clamp, so simply use clamp...)
|
||||||
|
|
||||||
|
#region Step / Smoothstep
|
||||||
|
|
||||||
|
/// Compares two values, returning 0 or 1 based on which value is greater.
|
||||||
|
/// @returns 1 if the x parameter is greater than or equal to the y parameter; otherwise, 0.
|
||||||
|
public static float step(float y, float x)
|
||||||
|
{
|
||||||
|
return (x >= y) ? 1.0f : 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compares two values, returning 0 or 1 based on which value is greater.
|
||||||
|
/// @returns 1 if the x parameter is greater than or equal to the y parameter; otherwise, 0.
|
||||||
|
public static float2 step(float2 y, float2 x)
|
||||||
|
{
|
||||||
|
bool2 b = (x >= y);
|
||||||
|
|
||||||
|
return float2(b.X ? 1.0f : 0.0f, b.Y ? 1.0f : 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compares two values, returning 0 or 1 based on which value is greater.
|
||||||
|
/// @returns 1 if the x parameter is greater than or equal to the y parameter; otherwise, 0.
|
||||||
|
public static float3 step(float3 y, float3 x)
|
||||||
|
{
|
||||||
|
bool3 b = (x >= y);
|
||||||
|
|
||||||
|
return float3(b.X ? 1.0f : 0.0f, b.Y ? 1.0f : 0.0f, b.Z ? 1.0f : 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compares two values, returning 0 or 1 based on which value is greater.
|
||||||
|
/// @returns 1 if the x parameter is greater than or equal to the y parameter; otherwise, 0.
|
||||||
|
public static float4 step(float4 y, float4 x)
|
||||||
|
{
|
||||||
|
bool4 b = (x >= y);
|
||||||
|
|
||||||
|
return float4(b.X ? 1.0f : 0.0f, b.Y ? 1.0f : 0.0f, b.Z ? 1.0f : 0.0f, b.W ? 1.0f : 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Source: https://thebookofshaders.com/glossary/?search=smoothstep
|
||||||
|
|
||||||
|
/// Returns a smooth Hermite interpolation between 0 and 1, if x is in the range [min, max].
|
||||||
|
/// @returns Returns 0 if x is less than min; 1 if x is greater than max; otherwise, a value between 0 and 1 if x is in the range [min, max].
|
||||||
|
public static float smoothstep(float min, float max, float x)
|
||||||
|
{
|
||||||
|
float t = clamp((x - min) / (max - min), 0.0f, 1.0f);
|
||||||
|
return t * t * (3.0f - 2.0f * t);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a smooth Hermite interpolation between 0 and 1, if x is in the range [min, max].
|
||||||
|
/// @returns Returns 0 if x is less than min; 1 if x is greater than max; otherwise, a value between 0 and 1 if x is in the range [min, max].
|
||||||
|
public static float2 smoothstep(float2 min, float2 max, float2 x)
|
||||||
|
{
|
||||||
|
float2 t = clamp((x - min) / (max - min), 0.0f, 1.0f);
|
||||||
|
return t * t * (3.0f - 2.0f * t);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a smooth Hermite interpolation between 0 and 1, if x is in the range [min, max].
|
||||||
|
/// @returns Returns 0 if x is less than min; 1 if x is greater than max; otherwise, a value between 0 and 1 if x is in the range [min, max].
|
||||||
|
public static float3 smoothstep(float3 min, float3 max, float3 x)
|
||||||
|
{
|
||||||
|
float3 t = clamp((x - min) / (max - min), 0.0f, 1.0f);
|
||||||
|
return t * t * (3.0f - 2.0f * t);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a smooth Hermite interpolation between 0 and 1, if x is in the range [min, max].
|
||||||
|
/// @returns Returns 0 if x is less than min; 1 if x is greater than max; otherwise, a value between 0 and 1 if x is in the range [min, max].
|
||||||
|
public static float4 smoothstep(float4 min, float4 max, float4 x)
|
||||||
|
{
|
||||||
|
float4 t = clamp((x - min) / (max - min), 0.0f, 1.0f);
|
||||||
|
return t * t * (3.0f - 2.0f * t);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Reject / Project
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the projection of a onto b
|
||||||
|
*/
|
||||||
|
public static float2 project(float2 a, float2 b)
|
||||||
|
{
|
||||||
|
return (b * (dot(a, b) / dot(b, b)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the projection of a onto b
|
||||||
|
*/
|
||||||
|
public static float3 project(float3 a, float3 b)
|
||||||
|
{
|
||||||
|
return (b * (dot(a, b) / dot(b, b)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the projection of a onto b
|
||||||
|
*/
|
||||||
|
public static float4 project(float4 a, float4 b)
|
||||||
|
{
|
||||||
|
return (b * (dot(a, b) / dot(b, b)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the rejection of a from b
|
||||||
|
*/
|
||||||
|
public static float2 reject(float2 a, float2 b)
|
||||||
|
{
|
||||||
|
return (a - b * (dot(a, b) / dot(b, b)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the rejection of a from b
|
||||||
|
*/
|
||||||
|
public static float3 reject(float3 a, float3 b)
|
||||||
|
{
|
||||||
|
return (a - b * (dot(a, b) / dot(b, b)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the rejection of a from b
|
||||||
|
*/
|
||||||
|
public static float4 reject(float4 a, float4 b)
|
||||||
|
{
|
||||||
|
return (a - b * (dot(a, b) / dot(b, b)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region dot
|
||||||
|
|
||||||
|
public static float dot(float2 left, float2 right)
|
||||||
|
{
|
||||||
|
return left.X * right.X + left.Y * right.Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float dot(float3 left, float3 right)
|
||||||
|
{
|
||||||
|
return left.X * right.X + left.Y * right.Y + left.Z * right.Z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float dot(float4 left, float4 right)
|
||||||
|
{
|
||||||
|
return left.X * right.X + left.Y * right.Y + left.Z * right.Z + left.W * right.W;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int dot(int2 left, int2 right)
|
||||||
|
{
|
||||||
|
return left.X * right.X + left.Y * right.Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int dot(int3 left, int3 right)
|
||||||
|
{
|
||||||
|
return left.X * right.X + left.Y * right.Y + left.Z * right.Z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int dot(int4 left, int4 right)
|
||||||
|
{
|
||||||
|
return left.X * right.X + left.Y * right.Y + left.Z * right.Z + left.W * right.W;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region lengthSq / length / DistanceSq / Distance
|
||||||
|
|
||||||
|
public static float lengthSq(float2 value) => dot(value, value);
|
||||||
|
|
||||||
|
public static float lengthSq(float3 value) => dot(value, value);
|
||||||
|
|
||||||
|
public static float lengthSq(float4 value) => dot(value, value);
|
||||||
|
|
||||||
|
public static int lengthSq(int2 value) => dot(value, value);
|
||||||
|
|
||||||
|
public static int lengthSq(int3 value) => dot(value, value);
|
||||||
|
|
||||||
|
public static int lengthSq(int4 value) => dot(value, value);
|
||||||
|
|
||||||
|
public static float length(float2 value) => Math.Sqrt(lengthSq(value));
|
||||||
|
|
||||||
|
public static float length(float3 value) => Math.Sqrt(lengthSq(value));
|
||||||
|
|
||||||
|
public static float length(float4 value) => Math.Sqrt(lengthSq(value));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static float distanceSq(float2 left, float2 right) => dot(left, right);
|
||||||
|
|
||||||
|
public static float distanceSq(float3 left, float3 right) => dot(left, right);
|
||||||
|
|
||||||
|
public static float distanceSq(float4 left, float4 right) => dot(left, right);
|
||||||
|
|
||||||
|
public static float distance(float2 left, float2 right) => Math.Sqrt(distanceSq(left, right));
|
||||||
|
|
||||||
|
public static float distance(float3 left, float3 right) => Math.Sqrt(distanceSq(left, right));
|
||||||
|
|
||||||
|
public static float distance(float4 left, float4 right) => Math.Sqrt(distanceSq(left, right));
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public static float3 cross(float3 left, float3 right)
|
||||||
|
{
|
||||||
|
return float3(
|
||||||
|
left.Y * right.Z - left.Z * right.Y,
|
||||||
|
left.Z * right.X - left.X * right.Z,
|
||||||
|
left.X * right.Y - left.Y * right.X);
|
||||||
|
}
|
||||||
|
|
||||||
|
// transpose und determinante für Matrizen
|
||||||
|
|
||||||
|
// sin, cos, tan, asin, acos, atan, atan2, cosh, sinh, tanh
|
||||||
|
}
|
||||||
@@ -4,5 +4,4 @@ namespace GlitchyEngine.Math
|
|||||||
{
|
{
|
||||||
typealias Matrix3x3 = DirectX.Math.Matrix3x3;
|
typealias Matrix3x3 = DirectX.Math.Matrix3x3;
|
||||||
typealias Matrix4x3 = DirectX.Math.Matrix4x3;
|
typealias Matrix4x3 = DirectX.Math.Matrix4x3;
|
||||||
typealias Matrix = DirectX.Math.Matrix;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,19 +30,19 @@ namespace GlitchyEngine.Math
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Converts the given radians to degrees
|
// Converts the given radians to degrees
|
||||||
public static Vector2 ToDegrees(Vector2 radians)
|
public static float2 ToDegrees(float2 radians)
|
||||||
{
|
{
|
||||||
return radians * RadToDeg;
|
return radians * RadToDeg;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converts the given radians to degrees
|
// Converts the given radians to degrees
|
||||||
public static Vector3 ToDegrees(Vector3 radians)
|
public static float3 ToDegrees(float3 radians)
|
||||||
{
|
{
|
||||||
return radians * RadToDeg;
|
return radians * RadToDeg;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converts the given radians to degrees
|
// Converts the given radians to degrees
|
||||||
public static Vector4 ToDegrees(Vector4 radians)
|
public static float4 ToDegrees(float4 radians)
|
||||||
{
|
{
|
||||||
return radians * RadToDeg;
|
return radians * RadToDeg;
|
||||||
}
|
}
|
||||||
@@ -54,19 +54,19 @@ namespace GlitchyEngine.Math
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Converts the given degrees to radians
|
// Converts the given degrees to radians
|
||||||
public static Vector2 ToRadians(Vector2 degrees)
|
public static float2 ToRadians(float2 degrees)
|
||||||
{
|
{
|
||||||
return degrees * DegToRad;
|
return degrees * DegToRad;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converts the given degrees to radians
|
// Converts the given degrees to radians
|
||||||
public static Vector3 ToRadians(Vector3 degrees)
|
public static float3 ToRadians(float3 degrees)
|
||||||
{
|
{
|
||||||
return degrees * DegToRad;
|
return degrees * DegToRad;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converts the given degrees to radians
|
// Converts the given degrees to radians
|
||||||
public static Vector4 ToRadians(Vector4 degrees)
|
public static float4 ToRadians(float4 degrees)
|
||||||
{
|
{
|
||||||
return degrees * DegToRad;
|
return degrees * DegToRad;
|
||||||
}
|
}
|
||||||
@@ -79,24 +79,24 @@ namespace GlitchyEngine.Math
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the point that lies on the unit circle at the specified angle.
|
/// Returns the point that lies on the unit circle at the specified angle.
|
||||||
public static Vector2 CirclePoint(float angle, float radius = 1.0f)
|
public static float2 CirclePoint(float angle, float radius = 1.0f)
|
||||||
{
|
{
|
||||||
return .(Math.Cos(angle), Math.Sin(angle)) * radius;
|
return .(Math.Cos(angle), Math.Sin(angle)) * radius;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Vector2 Pow(Vector2 v, float p)
|
public static float2 Pow(float2 v, float p)
|
||||||
{
|
{
|
||||||
return Vector2(Math.Pow(v.X, p), Math.Pow(v.Y, p));
|
return float2(Math.Pow(v.X, p), Math.Pow(v.Y, p));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Vector3 Pow(Vector3 v, float p)
|
public static float3 Pow(float3 v, float p)
|
||||||
{
|
{
|
||||||
return Vector3(Math.Pow(v.X, p), Math.Pow(v.Y, p), Math.Pow(v.Z, p));
|
return float3(Math.Pow(v.X, p), Math.Pow(v.Y, p), Math.Pow(v.Z, p));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Vector4 Pow(Vector4 v, float p)
|
public static float4 Pow(float4 v, float p)
|
||||||
{
|
{
|
||||||
return Vector4(Math.Pow(v.X, p), Math.Pow(v.Y, p), Math.Pow(v.Z, p), Math.Pow(v.W, p));
|
return float4(Math.Pow(v.X, p), Math.Pow(v.Y, p), Math.Pow(v.Z, p), Math.Pow(v.W, p));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,874 @@
|
|||||||
|
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 float4[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(float4 c0, float4 c1, float4 c2, float4 c3)
|
||||||
|
{
|
||||||
|
Columns[0] = c0;
|
||||||
|
Columns[1] = c1;
|
||||||
|
Columns[2] = c2;
|
||||||
|
Columns[3] = c3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ref float3 Right
|
||||||
|
{
|
||||||
|
[Inline]
|
||||||
|
get
|
||||||
|
{
|
||||||
|
#unwarn
|
||||||
|
return ref *(float3*)&Columns[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ref float3 Up
|
||||||
|
{
|
||||||
|
[Inline]
|
||||||
|
get
|
||||||
|
{
|
||||||
|
#unwarn
|
||||||
|
return ref *(float3*)&Columns[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ref float3 Forward
|
||||||
|
{
|
||||||
|
[Inline]
|
||||||
|
get
|
||||||
|
{
|
||||||
|
#unwarn
|
||||||
|
return ref *(float3*)&Columns[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ref float3 Translation
|
||||||
|
{
|
||||||
|
[Inline]
|
||||||
|
get
|
||||||
|
{
|
||||||
|
#unwarn
|
||||||
|
return ref *(float3*)&Columns[3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float3 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 float4 this[int column]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
#unwarn
|
||||||
|
return ref *(float4*)&Columns[column];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Checked]
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if(column < 0 || column > 3)
|
||||||
|
Internal.ThrowIndexOutOfRange();
|
||||||
|
|
||||||
|
#unwarn
|
||||||
|
return ref *(float4*)&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 float4 operator *(Matrix matrix, float4 columnVector)
|
||||||
|
{
|
||||||
|
#unwarn
|
||||||
|
var m = &matrix.V;
|
||||||
|
|
||||||
|
float4 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 float4 operator *(float4 rowVector, Matrix matrix)
|
||||||
|
{
|
||||||
|
#unwarn
|
||||||
|
var m = &matrix.V;
|
||||||
|
|
||||||
|
float4 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(float3 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(float3 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(float3 position, float3 target, float3 up)
|
||||||
|
{
|
||||||
|
float3 forward = normalize(target - position);
|
||||||
|
|
||||||
|
float3 right = normalize(cross(up, forward));
|
||||||
|
|
||||||
|
float3 newUp = normalize(cross(forward, right));
|
||||||
|
|
||||||
|
Matrix result = .Identity;
|
||||||
|
|
||||||
|
result.Forward = forward;
|
||||||
|
result.Up = up;
|
||||||
|
result.Right = right;
|
||||||
|
result.Translation.X = -dot(position, right);
|
||||||
|
result.Translation.Y = -dot(position, up);
|
||||||
|
result.Translation.Z = -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.
|
||||||
|
|
||||||
|
float3 a = *(float3*)&Columns[0];
|
||||||
|
float3 b = *(float3*)&Columns[1];
|
||||||
|
float3 c = *(float3*)&Columns[2];
|
||||||
|
float3 d = *(float3*)&Columns[3];
|
||||||
|
|
||||||
|
float x = this[3, 0];
|
||||||
|
float y = this[3, 1];
|
||||||
|
float z = this[3, 2];
|
||||||
|
float w = this[3, 3];
|
||||||
|
|
||||||
|
float3 s = cross(a, b);
|
||||||
|
float3 t = cross(c, d);
|
||||||
|
float3 u = y * a - x * b;
|
||||||
|
float3 v = w * c - z * d;
|
||||||
|
|
||||||
|
return dot(s, v) + 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
|
||||||
|
float3 a = *(float3*)&Columns[0];
|
||||||
|
#unwarn
|
||||||
|
float3 b = *(float3*)&Columns[1];
|
||||||
|
#unwarn
|
||||||
|
float3 c = *(float3*)&Columns[2];
|
||||||
|
#unwarn
|
||||||
|
float3 d = *(float3*)&Columns[3];
|
||||||
|
|
||||||
|
float x = this[3, 0];
|
||||||
|
float y = this[3, 1];
|
||||||
|
float z = this[3, 2];
|
||||||
|
float w = this[3, 3];
|
||||||
|
|
||||||
|
float3 s = cross(a, b);
|
||||||
|
float3 t = cross(c, d);
|
||||||
|
float3 u = y * a - x * b;
|
||||||
|
float3 v = w * c - z * d;
|
||||||
|
|
||||||
|
float invDet = 1.0f / (dot(s, v) + dot(t, u));
|
||||||
|
|
||||||
|
s *= invDet;
|
||||||
|
t *= invDet;
|
||||||
|
u *= invDet;
|
||||||
|
v *= invDet;
|
||||||
|
|
||||||
|
float3 r0 = cross(b, v) + t * y;
|
||||||
|
float3 r1 = cross(v, a) - t * x;
|
||||||
|
float3 r2 = cross(d, u) + s * w;
|
||||||
|
float3 r3 = cross(u, c) - s * z;
|
||||||
|
return .(r0.X, r0.Y, r0.Z, -dot(b, t),
|
||||||
|
r1.X, r1.Y, r1.Z, dot(a, t),
|
||||||
|
r2.X, r2.Y, r2.Z, -dot(d, s),
|
||||||
|
r3.X, r3.Y, r3.Z, 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
|
||||||
|
float3 a = *(float3*)&matrix.Columns[0];
|
||||||
|
#unwarn
|
||||||
|
float3 b = *(float3*)&matrix.Columns[1];
|
||||||
|
#unwarn
|
||||||
|
float3 c = *(float3*)&matrix.Columns[2];
|
||||||
|
#unwarn
|
||||||
|
float3 d = *(float3*)&matrix.Columns[3];
|
||||||
|
|
||||||
|
float x = matrix[3, 0];
|
||||||
|
float y = matrix[3, 1];
|
||||||
|
float z = matrix[3, 2];
|
||||||
|
float w = matrix[3, 3];
|
||||||
|
|
||||||
|
float3 s = cross(a, b);
|
||||||
|
float3 t = cross(c, d);
|
||||||
|
float3 u = y * a - x * b;
|
||||||
|
float3 v = w * c - z * d;
|
||||||
|
|
||||||
|
float invDet = 1.0f / (dot(s, v) + dot(t, u));
|
||||||
|
|
||||||
|
s *= invDet;
|
||||||
|
t *= invDet;
|
||||||
|
u *= invDet;
|
||||||
|
v *= invDet;
|
||||||
|
|
||||||
|
float3 r0 = cross(b, v) + t * y;
|
||||||
|
float3 r1 = cross(v, a) - t * x;
|
||||||
|
float3 r2 = cross(d, u) + s * w;
|
||||||
|
float3 r3 = cross(u, c) - s * z;
|
||||||
|
return .(r0.X, r0.Y, r0.Z, -dot(b, t),
|
||||||
|
r1.X, r1.Y, r1.Z, dot(a, t),
|
||||||
|
r2.X, r2.Y, r2.Z, -dot(d, s),
|
||||||
|
r3.X, r3.Y, r3.Z, 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[0]);
|
||||||
|
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 float3 position, out Quaternion rotation, out float3 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 = length(*(float3*)&matrix.Columns[0]);
|
||||||
|
scale.Y = length(*(float3*)&matrix.Columns[1]);
|
||||||
|
scale.Z = length(*(float3*)&matrix.Columns[2]);
|
||||||
|
|
||||||
|
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();
|
|
||||||
|
|
||||||
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -22,7 +22,7 @@ namespace GlitchyEngine.Math
|
|||||||
W = w;
|
W = w;
|
||||||
}
|
}
|
||||||
|
|
||||||
public this(Vector3 xy, float z, float w)
|
public this(float3 xy, float z, float w)
|
||||||
{
|
{
|
||||||
X = xy.X;
|
X = xy.X;
|
||||||
Y = xy.Y;
|
Y = xy.Y;
|
||||||
@@ -30,7 +30,7 @@ namespace GlitchyEngine.Math
|
|||||||
W = w;
|
W = w;
|
||||||
}
|
}
|
||||||
|
|
||||||
public this(Vector3 xyz, float w)
|
public this(float3 xyz, float w)
|
||||||
{
|
{
|
||||||
X = xyz.X;
|
X = xyz.X;
|
||||||
Y = xyz.Y;
|
Y = xyz.Y;
|
||||||
@@ -38,7 +38,7 @@ namespace GlitchyEngine.Math
|
|||||||
W = w;
|
W = w;
|
||||||
}
|
}
|
||||||
|
|
||||||
public this(Vector4 vector)
|
public this(float4 vector)
|
||||||
{
|
{
|
||||||
X = vector.X;
|
X = vector.X;
|
||||||
Y = vector.Y;
|
Y = vector.Y;
|
||||||
@@ -46,7 +46,7 @@ namespace GlitchyEngine.Math
|
|||||||
W = vector.W;
|
W = vector.W;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector3 Vector
|
public float3 Vector
|
||||||
{
|
{
|
||||||
get => .(X, Y, Z);
|
get => .(X, Y, Z);
|
||||||
set mut
|
set mut
|
||||||
@@ -144,7 +144,7 @@ namespace GlitchyEngine.Math
|
|||||||
{
|
{
|
||||||
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/
|
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/
|
||||||
|
|
||||||
var m = matrix.V;
|
var m = matrix;
|
||||||
|
|
||||||
Quaternion result = ?;
|
Quaternion result = ?;
|
||||||
|
|
||||||
@@ -195,11 +195,11 @@ namespace GlitchyEngine.Math
|
|||||||
{
|
{
|
||||||
Quaternion result;
|
Quaternion result;
|
||||||
|
|
||||||
Vector3 v = l.Vector * r.Vector + (l.W * r.Vector) + (r.W * l.Vector);
|
float3 v = l.Vector * r.Vector + (l.W * r.Vector) + (r.W * l.Vector);
|
||||||
result.X = v.X;
|
result.X = v.X;
|
||||||
result.Y = v.Y;
|
result.Y = v.Y;
|
||||||
result.Z = v.Z;
|
result.Z = v.Z;
|
||||||
result.W = (l.W * r.W) - Vector3.Dot(l.Vector, r.Vector);
|
result.W = (l.W * r.W) - dot(l.Vector, r.Vector);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -220,11 +220,11 @@ namespace GlitchyEngine.Math
|
|||||||
|
|
||||||
[Inline]
|
[Inline]
|
||||||
#unwarn
|
#unwarn
|
||||||
public static implicit operator Vector4(in Self value) => *(Vector4*)&value;
|
public static implicit operator float4(in Self value) => *(float4*)&value;
|
||||||
|
|
||||||
[Inline]
|
[Inline]
|
||||||
#unwarn
|
#unwarn
|
||||||
public static implicit operator Quaternion(in Vector4 value) => *(Quaternion*)&value;
|
public static implicit operator Quaternion(in float4 value) => *(Quaternion*)&value;
|
||||||
|
|
||||||
public static bool operator ==(Quaternion l, Quaternion r)
|
public static bool operator ==(Quaternion l, Quaternion r)
|
||||||
{
|
{
|
||||||
@@ -236,7 +236,7 @@ namespace GlitchyEngine.Math
|
|||||||
return l.X != r.X && l.Y != r.Y && l.Z != r.Z && l.W != r.W;
|
return l.X != r.X && l.Y != r.Y && l.Z != r.Z && l.W != r.W;
|
||||||
}
|
}
|
||||||
|
|
||||||
public (Vector3 Axis, float Angle) ToAxisAngle()
|
public (float3 Axis, float Angle) ToAxisAngle()
|
||||||
{
|
{
|
||||||
// scalar part = cos(θ/2)
|
// scalar part = cos(θ/2)
|
||||||
// So, we can extract the angle directly.
|
// So, we can extract the angle directly.
|
||||||
@@ -247,12 +247,12 @@ namespace GlitchyEngine.Math
|
|||||||
// We assume quaternion is unit length, so subtracting w^2 gives us length of just vector part (aka sin(θ/2)).
|
// We assume quaternion is unit length, so subtracting w^2 gives us length of just vector part (aka sin(θ/2)).
|
||||||
float length = Math.Sqrt(1.0f - (W * W));
|
float length = Math.Sqrt(1.0f - (W * W));
|
||||||
|
|
||||||
Vector3 axis;
|
float3 axis;
|
||||||
|
|
||||||
// Normalize vector part to get the axis!
|
// Normalize vector part to get the axis!
|
||||||
if(length == 0)
|
if(length == 0)
|
||||||
{
|
{
|
||||||
axis = Vector3.Zero;
|
axis = float3.Zero;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -265,9 +265,9 @@ namespace GlitchyEngine.Math
|
|||||||
return (axis, angle);
|
return (axis, angle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Quaternion FromAxisAngle(Vector3 axis, float angle)
|
public static Quaternion FromAxisAngle(float3 axis, float angle)
|
||||||
{
|
{
|
||||||
float lengthSq = axis.MagnitudeSquared();
|
float lengthSq = lengthSq(axis);
|
||||||
|
|
||||||
if(lengthSq == 0)
|
if(lengthSq == 0)
|
||||||
{
|
{
|
||||||
@@ -316,11 +316,11 @@ namespace GlitchyEngine.Math
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Vector3 ToEulerAngles(Quaternion q)
|
public static float3 ToEulerAngles(Quaternion q)
|
||||||
{
|
{
|
||||||
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/
|
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/
|
||||||
|
|
||||||
Vector3 result;
|
float3 result;
|
||||||
|
|
||||||
float sqw = q.W*q.W;
|
float sqw = q.W*q.W;
|
||||||
float sqx = q.X*q.X;
|
float sqx = q.X*q.X;
|
||||||
@@ -354,7 +354,7 @@ namespace GlitchyEngine.Math
|
|||||||
float y = 2.0f * (Y * Z + W * X);
|
float y = 2.0f * (Y * Z + W * X);
|
||||||
float x = W * W - X * X - Y * Y + Z * Z;
|
float x = W * W - X * X - Y * Y + Z * Z;
|
||||||
|
|
||||||
if (Vector2(x, y).Equals(.Zero)) //avoid atan2(0,0) - handle singularity - Matiis
|
if (float2(x, y).Equals(.Zero)) //avoid atan2(0,0) - handle singularity - Matiis
|
||||||
return 2.0f * Math.Atan2(X, W);
|
return 2.0f * Math.Atan2(X, W);
|
||||||
|
|
||||||
return Math.Atan2(y, x);
|
return Math.Atan2(y, x);
|
||||||
@@ -370,7 +370,7 @@ namespace GlitchyEngine.Math
|
|||||||
float y = 2.0f * (X * Y + W * Z);
|
float y = 2.0f * (X * Y + W * Z);
|
||||||
float x = W * W + X * X - Y * Y - Z * Z;
|
float x = W * W + X * X - Y * Y - Z * Z;
|
||||||
|
|
||||||
if (Vector2(x, y).Equals(.Zero)) //avoid atan2(0,0) - handle singularity - Matiis
|
if (float2(x, y).Equals(.Zero)) //avoid atan2(0,0) - handle singularity - Matiis
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return Math.Atan2(y, x);
|
return Math.Atan2(y, x);
|
||||||
|
|||||||
@@ -1,299 +0,0 @@
|
|||||||
using Bon;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace GlitchyEngine.Math
|
|
||||||
{
|
|
||||||
[BonTarget]
|
|
||||||
[SwizzleVector(2, "GlitchyEngine.Math.Vector")]
|
|
||||||
public struct Vector2
|
|
||||||
{
|
|
||||||
public const Vector2 Zero = .(0f, 0f);
|
|
||||||
public const Vector2 UnitX = .(1f, 0f);
|
|
||||||
public const Vector2 UnitY = .(0f, 1f);
|
|
||||||
public const Vector2 One = .(1f, 1f);
|
|
||||||
|
|
||||||
public const int ComponentCount = 2;
|
|
||||||
|
|
||||||
public float X, Y;
|
|
||||||
|
|
||||||
public this() => this = default;
|
|
||||||
|
|
||||||
public this(float value)
|
|
||||||
{
|
|
||||||
X = value;
|
|
||||||
Y = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(float x, float y)
|
|
||||||
{
|
|
||||||
X = x;
|
|
||||||
Y = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ref float this[int index]
|
|
||||||
{
|
|
||||||
[Checked]
|
|
||||||
get mut
|
|
||||||
{
|
|
||||||
if(index < 0 || index >= ComponentCount)
|
|
||||||
Internal.ThrowIndexOutOfRange(1);
|
|
||||||
|
|
||||||
return ref (&X)[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
[Inline]
|
|
||||||
get mut => ref (&X)[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
public float this[int index]
|
|
||||||
{
|
|
||||||
[Checked]
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if(index < 0 || index >= ComponentCount)
|
|
||||||
Internal.ThrowIndexOutOfRange(1);
|
|
||||||
|
|
||||||
if(index == 0)
|
|
||||||
return X;
|
|
||||||
else
|
|
||||||
return Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Inline]
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if(index == 0)
|
|
||||||
return X;
|
|
||||||
else
|
|
||||||
return Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Checked]
|
|
||||||
set mut
|
|
||||||
{
|
|
||||||
if(index < 0 || index >= ComponentCount)
|
|
||||||
Internal.ThrowIndexOutOfRange(1);
|
|
||||||
|
|
||||||
if(index == 0)
|
|
||||||
X = value;
|
|
||||||
else
|
|
||||||
Y = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Inline]
|
|
||||||
set mut
|
|
||||||
{
|
|
||||||
if(index == 0)
|
|
||||||
X = value;
|
|
||||||
else
|
|
||||||
Y = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the magnitude (length) of this vector.
|
|
||||||
* @remarks MagnitudeSquared might be used if only the relative length is relevant.
|
|
||||||
*/
|
|
||||||
public float Magnitude()
|
|
||||||
{
|
|
||||||
return Math.Sqrt(X * X + Y * Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the squared magnitude (length) of this vector.
|
|
||||||
*/
|
|
||||||
public float MagnitudeSquared()
|
|
||||||
{
|
|
||||||
return X * X + Y * Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: Normalization interface is bad
|
|
||||||
[Checked]
|
|
||||||
public void Normalize() mut
|
|
||||||
{
|
|
||||||
if(this == .Zero)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this /= Magnitude();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Normalize() mut
|
|
||||||
{
|
|
||||||
this /= Magnitude();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector2 Normalize(Vector2 v)
|
|
||||||
{
|
|
||||||
return v / v.Magnitude();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static float Dot(Vector2 l, Vector2 r)
|
|
||||||
{
|
|
||||||
return l.X * r.X + l.Y * r.Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the projection of a onto b
|
|
||||||
*/
|
|
||||||
public static Vector2 Project(Vector2 a, Vector2 b)
|
|
||||||
{
|
|
||||||
return (b * (Dot(a, b) / Dot(b, b)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the rejection of a from b
|
|
||||||
*/
|
|
||||||
public static Vector2 Reject(Vector2 a, Vector2 b)
|
|
||||||
{
|
|
||||||
return (a - b * (Dot(a, b) / Dot(b, b)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interpolates linearly between two given vectors.
|
|
||||||
* @param a The first vector.
|
|
||||||
* @param b The second vector.
|
|
||||||
* @param interpolationValue The value that linearly interpolates between a and b.
|
|
||||||
* (0 means a will be returned, 1 means b will be returned.)
|
|
||||||
* @returns The resulting linear interpolation.
|
|
||||||
*/
|
|
||||||
public static Vector2 Lerp(Vector2 a, Vector2 b, float interpolationValue)
|
|
||||||
{
|
|
||||||
return a + interpolationValue * (b - a);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector2 Min(Vector2 a, Vector2 b)
|
|
||||||
{
|
|
||||||
return .(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector2 Max(Vector2 a, Vector2 b)
|
|
||||||
{
|
|
||||||
return .(Math.Max(a.X, b.X), Math.Max(a.Y, b.Y));
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Assignment operators
|
|
||||||
//
|
|
||||||
|
|
||||||
// Addition
|
|
||||||
|
|
||||||
public void operator +=(Vector2 value) mut
|
|
||||||
{
|
|
||||||
X += value.X;
|
|
||||||
Y += value.Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator +=(float scalar) mut
|
|
||||||
{
|
|
||||||
X += scalar;
|
|
||||||
Y += scalar;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subtraction
|
|
||||||
|
|
||||||
public void operator -=(Vector2 value) mut
|
|
||||||
{
|
|
||||||
X -= value.X;
|
|
||||||
Y -= value.Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator -=(float scalar) mut
|
|
||||||
{
|
|
||||||
X -= scalar;
|
|
||||||
Y -= scalar;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Multiplication
|
|
||||||
|
|
||||||
public void operator *=(Vector2 value) mut
|
|
||||||
{
|
|
||||||
X *= value.X;
|
|
||||||
Y *= value.Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator *=(float scalar) mut
|
|
||||||
{
|
|
||||||
X *= scalar;
|
|
||||||
Y *= scalar;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Division
|
|
||||||
|
|
||||||
public void operator /=(float scalar) mut
|
|
||||||
{
|
|
||||||
float f = 1.0f / scalar;
|
|
||||||
X *= f;
|
|
||||||
Y *= f;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator /=(Vector2 value) mut
|
|
||||||
{
|
|
||||||
X /= value.X;
|
|
||||||
Y /= value.Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// operators
|
|
||||||
//
|
|
||||||
|
|
||||||
// Addition
|
|
||||||
|
|
||||||
public static Vector2 operator +(Vector2 left, Vector2 right) => Vector2(left.X + right.X, left.Y + right.Y);
|
|
||||||
|
|
||||||
public static Vector2 operator +(Vector2 value, float scalar) => Vector2(value.X + scalar, value.Y + scalar);
|
|
||||||
|
|
||||||
public static Vector2 operator +(float scalar, Vector2 value) => Vector2(scalar + value.X, scalar + value.Y);
|
|
||||||
|
|
||||||
public static Vector2 operator +(Vector2 value) => value;
|
|
||||||
|
|
||||||
// Subtraction
|
|
||||||
|
|
||||||
public static Vector2 operator -(Vector2 left, Vector2 right) => Vector2(left.X - right.X, left.Y - right.Y);
|
|
||||||
|
|
||||||
public static Vector2 operator -(Vector2 value, float scalar) => Vector2(value.X - scalar, value.Y - scalar);
|
|
||||||
|
|
||||||
public static Vector2 operator -(float scalar, Vector2 value) => Vector2(scalar - value.X, scalar - value.Y);
|
|
||||||
|
|
||||||
public static Vector2 operator -(Vector2 value) => Vector2(-value.X, -value.Y);
|
|
||||||
|
|
||||||
// Multiplication
|
|
||||||
|
|
||||||
public static Vector2 operator *(Vector2 left, Vector2 right) => Vector2(left.X * right.X, left.Y * right.Y);
|
|
||||||
|
|
||||||
public static Vector2 operator *(Vector2 value, float scalar) => Vector2(value.X * scalar, value.Y * scalar);
|
|
||||||
|
|
||||||
public static Vector2 operator *(float scalar, Vector2 value) => Vector2(scalar * value.X, scalar * value.Y);
|
|
||||||
|
|
||||||
// Division
|
|
||||||
|
|
||||||
public static Vector2 operator /(Vector2 left, Vector2 right) => Vector2(left.X / right.X, left.Y / right.Y);
|
|
||||||
|
|
||||||
public static Vector2 operator /(Vector2 value, float scalar)
|
|
||||||
{
|
|
||||||
float inv = 1.0f / scalar;
|
|
||||||
return Vector2(value.X * inv, value.Y * inv);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector2 operator /(float scalar, Vector2 value) => Vector2(scalar / value.X, scalar / value.Y);
|
|
||||||
|
|
||||||
// Equality
|
|
||||||
|
|
||||||
public static bool operator ==(Vector2 left, Vector2 right) => left.X == right.X && left.Y == right.Y;
|
|
||||||
|
|
||||||
public static bool operator !=(Vector2 left, Vector2 right) => left.X != right.X || left.Y != right.Y;
|
|
||||||
|
|
||||||
public override void ToString(String strBuffer) => strBuffer.AppendF("X:{0} Y:{1}", X, Y);
|
|
||||||
|
|
||||||
public bool Equals(Vector2 v, float epsilon = Math.[Friend]sMachineEpsilonFloat)
|
|
||||||
{
|
|
||||||
return (Math.Abs(v.X - X) < epsilon) && (Math.Abs(v.Y - Y) < epsilon);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Inline]
|
|
||||||
public static explicit operator Self(float value) => Self(value);
|
|
||||||
|
|
||||||
[Inline]
|
|
||||||
#unwarn
|
|
||||||
public static explicit operator float[2](Vector2 value) => *(float[2]*)&value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,349 +0,0 @@
|
|||||||
using Bon;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace GlitchyEngine.Math
|
|
||||||
{
|
|
||||||
[BonTarget]
|
|
||||||
[SwizzleVector(3, "GlitchyEngine.Math.Vector")]
|
|
||||||
public struct Vector3
|
|
||||||
{
|
|
||||||
public const Vector3 Zero = .(0f, 0f, 0f);
|
|
||||||
public const Vector3 UnitX = .(1f, 0f, 0f);
|
|
||||||
public const Vector3 UnitY = .(0f, 1f, 0f);
|
|
||||||
public const Vector3 UnitZ = .(0f, 0f, 1f);
|
|
||||||
public const Vector3 One = .(1f, 1f, 1f);
|
|
||||||
|
|
||||||
public const Vector3 Forward = .(0f, 0f, 1f);
|
|
||||||
public const Vector3 Backward = .(0f, 0f, -1f);
|
|
||||||
public const Vector3 Left = .(-1f, 0f, 0f);
|
|
||||||
public const Vector3 Right = .(1f, 0f, 0f);
|
|
||||||
public const Vector3 Up = .(0f, 1f, 0f);
|
|
||||||
public const Vector3 Down = .(0f, -1f, 0f);
|
|
||||||
|
|
||||||
public const int ComponentCount = 3;
|
|
||||||
|
|
||||||
public float X, Y, Z;
|
|
||||||
|
|
||||||
public this() => this = default;
|
|
||||||
|
|
||||||
public this(float value)
|
|
||||||
{
|
|
||||||
X = value;
|
|
||||||
Y = value;
|
|
||||||
Z = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(Vector2 value, float z = 0.0f)
|
|
||||||
{
|
|
||||||
X = value.X;
|
|
||||||
Y = value.Y;
|
|
||||||
Z = z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(float x, float y, float z)
|
|
||||||
{
|
|
||||||
X = x;
|
|
||||||
Y = y;
|
|
||||||
Z = z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(Vector3 value)
|
|
||||||
{
|
|
||||||
X = value.X;
|
|
||||||
Y = value.Y;
|
|
||||||
Z = value.Z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(Vector4 value)
|
|
||||||
{
|
|
||||||
X = value.X;
|
|
||||||
Y = value.Y;
|
|
||||||
Z = value.Z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ref float this[int index]
|
|
||||||
{
|
|
||||||
[Checked]
|
|
||||||
get mut
|
|
||||||
{
|
|
||||||
if(index < 0 || index >= ComponentCount)
|
|
||||||
Internal.ThrowIndexOutOfRange(1);
|
|
||||||
|
|
||||||
return ref (&X)[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
[Inline]
|
|
||||||
get mut => ref (&X)[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
public float this[int index]
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
switch(index)
|
|
||||||
{
|
|
||||||
case 0: return X;
|
|
||||||
case 1: return Y;
|
|
||||||
case 2: return Z;
|
|
||||||
default: Internal.ThrowIndexOutOfRange(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
set mut
|
|
||||||
{
|
|
||||||
switch(index)
|
|
||||||
{
|
|
||||||
case 0: X = value;
|
|
||||||
case 1: Y = value;
|
|
||||||
case 2: Z = value;
|
|
||||||
default: Internal.ThrowIndexOutOfRange(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the magnitude (length) of this vector.
|
|
||||||
* @remarks If the exact magnitude isn't needed (e.g. for comparisons) consider using MagnitudeSquared which doesn't use the square root operation.
|
|
||||||
*/
|
|
||||||
public float Magnitude() => Math.Sqrt(X * X + Y * Y + Z * Z);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the squared magnitude (length) of this vector.
|
|
||||||
* @remarks This function avoids the square root operation to calculate the magnitude and is thus more suitable for comparisons where the exact magnitude isn't needed.
|
|
||||||
*/
|
|
||||||
public float MagnitudeSquared() => X * X + Y * Y + Z * Z;
|
|
||||||
|
|
||||||
/// Normalizes this vector.
|
|
||||||
[Checked]
|
|
||||||
public void Normalize() mut
|
|
||||||
{
|
|
||||||
if(this == .Zero)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this /= Magnitude();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Normalizes this vector.
|
|
||||||
public void Normalize() mut
|
|
||||||
{
|
|
||||||
this /= Magnitude();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a copy of this Vector with a magnitude of 1.
|
|
||||||
[Checked]
|
|
||||||
public Vector3 Normalized()
|
|
||||||
{
|
|
||||||
if(this == .Zero)
|
|
||||||
return .Zero;
|
|
||||||
|
|
||||||
return this / Magnitude();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a copy of this Vector with a magnitude of 1.
|
|
||||||
public Vector3 Normalized()
|
|
||||||
{
|
|
||||||
return this / Magnitude();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a copy of the given Vector with a magnitude of 1.
|
|
||||||
public static Vector3 Normalize(Vector3 v)
|
|
||||||
{
|
|
||||||
return v / v.Magnitude();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calculates the dot product of two vectors.
|
|
||||||
public static float Dot(Vector3 l, Vector3 r) => l.X * r.X + l.Y * r.Y + l.Z * r.Z;
|
|
||||||
|
|
||||||
/// Calculates the distance between two vectors.
|
|
||||||
public static float Distance(Vector3 a, Vector3 b) => (a - b).[Inline]Magnitude();
|
|
||||||
|
|
||||||
/// Calculates the squared distance between two vectors.
|
|
||||||
public static float DistanceSquared(Vector3 a, Vector3 b) => (a - b).[Inline]MagnitudeSquared();
|
|
||||||
|
|
||||||
/// Calculates the cross product of two vectors.
|
|
||||||
public static Vector3 Cross(Vector3 l, Vector3 r)
|
|
||||||
{
|
|
||||||
return .(l.Y * r.Z - l.Z * r.Y,
|
|
||||||
l.Z * r.X - l.X * r.Z,
|
|
||||||
l.X * r.Y - l.Y * r.X);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calculates the projection of a onto b.
|
|
||||||
public static Vector3 Project(Vector3 a, Vector3 b)
|
|
||||||
{
|
|
||||||
return (b * (Dot(a, b) / Dot(b, b)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calculates the rejection of a from b.
|
|
||||||
public static Vector3 Reject(Vector3 a, Vector3 b)
|
|
||||||
{
|
|
||||||
return (a - b * (Dot(a, b) / Dot(b, b)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector3 Floor(Vector3 value) => .(Math.Floor(value.X), Math.Floor(value.Y), Math.Floor(value.Z));
|
|
||||||
|
|
||||||
public static Vector3 Ceiling(Vector3 value) => .(Math.Ceiling(value.X), Math.Ceiling(value.Y), Math.Ceiling(value.Z));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interpolates linearly between two given vectors.
|
|
||||||
* @param a The first vector.
|
|
||||||
* @param b The second vector.
|
|
||||||
* @param interpolationValue The value that linearly interpolates between a and b.
|
|
||||||
* (0 means a will be returned, 1 means b will be returned.)
|
|
||||||
* @returns The resulting linear interpolation.
|
|
||||||
*/
|
|
||||||
public static Vector3 Lerp(Vector3 a, Vector3 b, float interpolationValue)
|
|
||||||
{
|
|
||||||
return a + interpolationValue * (b - a);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector3 Min(Vector3 a, Vector3 b) => .(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y), Math.Min(a.Z, b.Z));
|
|
||||||
|
|
||||||
public static Vector3 Max(Vector3 a, Vector3 b) => .(Math.Max(a.X, b.X), Math.Max(a.Y, b.Y), Math.Min(a.Z, b.Z));
|
|
||||||
|
|
||||||
public static Vector3 Abs(Vector3 v) => .(Math.Abs(v.X), Math.Abs(v.Y), Math.Abs(v.Z));
|
|
||||||
|
|
||||||
public static Vector3 Clamp(Vector3 v, Vector3 min, Vector3 max)
|
|
||||||
{
|
|
||||||
return .(Math.Clamp(v.X, min.X, max.X),
|
|
||||||
Math.Clamp(v.Y, min.Y, max.Y),
|
|
||||||
Math.Clamp(v.X, min.Z, max.Z));
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Assignment operators
|
|
||||||
//
|
|
||||||
|
|
||||||
// Addition
|
|
||||||
|
|
||||||
public void operator +=(Vector3 value) mut
|
|
||||||
{
|
|
||||||
X += value.X;
|
|
||||||
Y += value.Y;
|
|
||||||
Z += value.Z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator +=(float scalar) mut
|
|
||||||
{
|
|
||||||
X += scalar;
|
|
||||||
Y += scalar;
|
|
||||||
Z += scalar;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subtraction
|
|
||||||
|
|
||||||
public void operator -=(Vector3 value) mut
|
|
||||||
{
|
|
||||||
X -= value.X;
|
|
||||||
Y -= value.Y;
|
|
||||||
Z -= value.Z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator -=(float scalar) mut
|
|
||||||
{
|
|
||||||
X -= scalar;
|
|
||||||
Y -= scalar;
|
|
||||||
Z -= scalar;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Multiplication
|
|
||||||
|
|
||||||
public void operator *=(Vector3 value) mut
|
|
||||||
{
|
|
||||||
X *= value.X;
|
|
||||||
Y *= value.Y;
|
|
||||||
Z *= value.Z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator *=(float scalar) mut
|
|
||||||
{
|
|
||||||
X *= scalar;
|
|
||||||
Y *= scalar;
|
|
||||||
Z *= scalar;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Division
|
|
||||||
|
|
||||||
public void operator /=(Vector3 value) mut
|
|
||||||
{
|
|
||||||
X /= value.X;
|
|
||||||
Y /= value.Y;
|
|
||||||
Z /= value.Z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator /=(float scalar) mut
|
|
||||||
{
|
|
||||||
float inv = 1.0f / scalar;
|
|
||||||
X *= inv;
|
|
||||||
Y *= inv;
|
|
||||||
Z *= inv;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// operators
|
|
||||||
//
|
|
||||||
|
|
||||||
// Addition
|
|
||||||
|
|
||||||
public static Vector3 operator +(Vector3 left, Vector3 right) => Vector3(left.X + right.X, left.Y + right.Y, left.Z + right.Z);
|
|
||||||
|
|
||||||
public static Vector3 operator +(Vector3 value, float scalar) => Vector3(value.X + scalar, value.Y + scalar, value.Z + scalar);
|
|
||||||
|
|
||||||
public static Vector3 operator +(float scalar, Vector3 value) => Vector3(scalar + value.X, scalar + value.Y, scalar + value.Z);
|
|
||||||
|
|
||||||
public static Vector3 operator +(Vector3 value) => value;
|
|
||||||
|
|
||||||
// Subtraction
|
|
||||||
|
|
||||||
public static Vector3 operator -(Vector3 left, Vector3 right) => Vector3(left.X - right.X, left.Y - right.Y, left.Z - right.Z);
|
|
||||||
|
|
||||||
public static Vector3 operator -(Vector3 value, float scalar) => Vector3(value.X - scalar, value.Y - scalar, value.Z - scalar);
|
|
||||||
|
|
||||||
public static Vector3 operator -(float scalar, Vector3 value) => Vector3(scalar - value.X, scalar - value.Y, scalar - value.Z);
|
|
||||||
|
|
||||||
public static Vector3 operator -(Vector3 value) => Vector3(-value.X, -value.Y, -value.Z);
|
|
||||||
|
|
||||||
// Multiplication
|
|
||||||
|
|
||||||
public static Vector3 operator *(Vector3 left, Vector3 right) => Vector3(left.X * right.X, left.Y * right.Y, left.Z * right.Z);
|
|
||||||
|
|
||||||
public static Vector3 operator *(Vector3 value, float scalar) => Vector3(value.X * scalar, value.Y * scalar, value.Z * scalar);
|
|
||||||
|
|
||||||
public static Vector3 operator *(float scalar, Vector3 value) => Vector3(scalar * value.X, scalar * value.Y, scalar * value.Z);
|
|
||||||
|
|
||||||
// Division
|
|
||||||
|
|
||||||
public static Vector3 operator /(Vector3 left, Vector3 right) => Vector3(left.X / right.X, left.Y / right.Y, left.Z / right.Z);
|
|
||||||
|
|
||||||
public static Vector3 operator /(Vector3 value, float scalar)
|
|
||||||
{
|
|
||||||
float inv = 1.0f / scalar;
|
|
||||||
return Vector3(value.X * inv, value.Y * inv, value.Z * inv);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector3 operator /(float scalar, Vector3 value) => Vector3(scalar / value.X, scalar / value.Y, scalar / value.Z);
|
|
||||||
|
|
||||||
// Modulo
|
|
||||||
|
|
||||||
public static Vector3 operator %(Vector3 left, Vector3 right) => Vector3(left.X % right.X, left.Y % right.Y, left.Z % right.Z);
|
|
||||||
|
|
||||||
public static Vector3 operator %(Vector3 value, float scalar) => Vector3(value.X % scalar, value.Y % scalar, value.Z % scalar);
|
|
||||||
|
|
||||||
public static Vector3 operator %(float scalar, Vector3 value) => Vector3(scalar % value.X, scalar % value.Y, scalar % value.Z);
|
|
||||||
|
|
||||||
// Equality
|
|
||||||
|
|
||||||
public static bool operator ==(Vector3 left, Vector3 right) => left.X == right.X && left.Y == right.Y && left.Z == right.Z;
|
|
||||||
|
|
||||||
public static bool operator !=(Vector3 left, Vector3 right) => left.X != right.X || left.Y != right.Y || left.Z != right.Z;
|
|
||||||
|
|
||||||
public override void ToString(String strBuffer) => strBuffer.AppendF("X:{0} Y:{1} Z:{2}", X, Y, Z);
|
|
||||||
|
|
||||||
[Inline]
|
|
||||||
public static explicit operator Self(float value) => Self(value);
|
|
||||||
|
|
||||||
[Inline]
|
|
||||||
#unwarn
|
|
||||||
public static explicit operator float[3](Vector3 value) => *(float[3]*)&value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,330 +0,0 @@
|
|||||||
using Bon;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace GlitchyEngine.Math
|
|
||||||
{
|
|
||||||
[BonTarget]
|
|
||||||
[SwizzleVector(4, "GlitchyEngine.Math.Vector")]
|
|
||||||
public struct Vector4
|
|
||||||
{
|
|
||||||
public const Vector4 Zero = .(0f, 0f, 0f, 0f);
|
|
||||||
public const Vector4 UnitX = .(1f, 0f, 0f, 0f);
|
|
||||||
public const Vector4 UnitY = .(0f, 1f, 0f, 0f);
|
|
||||||
public const Vector4 UnitZ = .(0f, 0f, 1f, 0f);
|
|
||||||
public const Vector4 UnitW = .(0f, 0f, 0f, 1f);
|
|
||||||
public const Vector4 One = .(1f, 1f, 1f, 1f);
|
|
||||||
|
|
||||||
public const int ComponentCount = 4;
|
|
||||||
|
|
||||||
public float X, Y, Z, W;
|
|
||||||
|
|
||||||
public this() => this = default;
|
|
||||||
|
|
||||||
public this(float value)
|
|
||||||
{
|
|
||||||
X = value;
|
|
||||||
Y = value;
|
|
||||||
Z = value;
|
|
||||||
W = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(Vector2 value, float z, float w)
|
|
||||||
{
|
|
||||||
X = value.X;
|
|
||||||
Y = value.Y;
|
|
||||||
Z = z;
|
|
||||||
W = w;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(Vector2 value1, Vector2 value2)
|
|
||||||
{
|
|
||||||
X = value1.X;
|
|
||||||
Y = value1.Y;
|
|
||||||
Z = value2.X;
|
|
||||||
W = value2.Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(Vector3 value, float w)
|
|
||||||
{
|
|
||||||
X = value.X;
|
|
||||||
Y = value.Y;
|
|
||||||
Z = value.Z;
|
|
||||||
W = w;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(float x, float y, float z, float w)
|
|
||||||
{
|
|
||||||
X = x;
|
|
||||||
Y = y;
|
|
||||||
Z = z;
|
|
||||||
W = w;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ref float this[int index]
|
|
||||||
{
|
|
||||||
[Checked]
|
|
||||||
get mut
|
|
||||||
{
|
|
||||||
if(index < 0 || index >= ComponentCount)
|
|
||||||
Internal.ThrowIndexOutOfRange(1);
|
|
||||||
|
|
||||||
return ref (&X)[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
[Inline]
|
|
||||||
get mut => ref (&X)[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
public float this[int index]
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
switch(index)
|
|
||||||
{
|
|
||||||
case 0: return X;
|
|
||||||
case 1: return Y;
|
|
||||||
case 2: return Z;
|
|
||||||
case 3: return W;
|
|
||||||
default: Internal.ThrowIndexOutOfRange(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
set mut
|
|
||||||
{
|
|
||||||
switch(index)
|
|
||||||
{
|
|
||||||
case 0: X = value;
|
|
||||||
case 1: Y = value;
|
|
||||||
case 2: Z = value;
|
|
||||||
case 3: W = value;
|
|
||||||
default: Internal.ThrowIndexOutOfRange(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the magnitude (length) of this vector.
|
|
||||||
* @remarks MagnitudeSquared might be used if only the relative length is relevant.
|
|
||||||
*/
|
|
||||||
public float Magnitude()
|
|
||||||
{
|
|
||||||
return Math.Sqrt(X * X + Y * Y + Z * Z + W * W);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the squared magnitude (length) of this vector.
|
|
||||||
*/
|
|
||||||
public float MagnitudeSquared()
|
|
||||||
{
|
|
||||||
return X * X + Y * Y + Z * Z + W * W;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Checked]
|
|
||||||
public void Normalize() mut
|
|
||||||
{
|
|
||||||
if(this == .Zero)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this /= Magnitude();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Normalize() mut
|
|
||||||
{
|
|
||||||
this /= Magnitude();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector4 Normalize(Vector4 v)
|
|
||||||
{
|
|
||||||
if(v == .Zero)
|
|
||||||
return .Zero;
|
|
||||||
|
|
||||||
return v / v.Magnitude();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Unchecked]
|
|
||||||
public static Vector4 Normalize(Vector4 v)
|
|
||||||
{
|
|
||||||
return v / v.Magnitude();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static float Dot(Vector4 l, Vector4 r)
|
|
||||||
{
|
|
||||||
return l.X * r.X + l.Y * r.Y + l.Z * r.Z + l.W * r.W;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the projection of a onto b
|
|
||||||
*/
|
|
||||||
public static Vector4 Project(Vector4 a, Vector4 b)
|
|
||||||
{
|
|
||||||
return (b * (Dot(a, b) / Dot(b, b)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the rejection of a from b
|
|
||||||
*/
|
|
||||||
public static Vector4 Reject(Vector4 a, Vector4 b)
|
|
||||||
{
|
|
||||||
return (a - b * (Dot(a, b) / Dot(b, b)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interpolates linearly between two given vectors.
|
|
||||||
* @param a The first vector.
|
|
||||||
* @param b The second vector.
|
|
||||||
* @param interpolationValue The value that linearly interpolates between a and b.
|
|
||||||
* (0 means a will be returned, 1 means b will be returned.)
|
|
||||||
* @returns The resulting linear interpolation.
|
|
||||||
*/
|
|
||||||
public static Vector4 Lerp(Vector4 a, Vector4 b, float interpolationValue)
|
|
||||||
{
|
|
||||||
return a + interpolationValue * (b - a);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector4 Min(Vector4 a, Vector4 b)
|
|
||||||
{
|
|
||||||
return .(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y), Math.Min(a.Z, b.Z), Math.Min(a.W, b.W));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector4 Max(Vector4 a, Vector4 b)
|
|
||||||
{
|
|
||||||
return .(Math.Max(a.X, b.X), Math.Max(a.Y, b.Y), Math.Min(a.Z, b.Z), Math.Min(a.W, b.W));
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Assignment operators
|
|
||||||
//
|
|
||||||
|
|
||||||
// Addition
|
|
||||||
|
|
||||||
public void operator +=(Vector4 value) mut
|
|
||||||
{
|
|
||||||
X += value.X;
|
|
||||||
Y += value.Y;
|
|
||||||
Z += value.Z;
|
|
||||||
W += value.W;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator +=(float scalar) mut
|
|
||||||
{
|
|
||||||
X += scalar;
|
|
||||||
Y += scalar;
|
|
||||||
Z += scalar;
|
|
||||||
W += scalar;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subtraction
|
|
||||||
|
|
||||||
public void operator -=(Vector4 value) mut
|
|
||||||
{
|
|
||||||
X -= value.X;
|
|
||||||
Y -= value.Y;
|
|
||||||
Z -= value.Z;
|
|
||||||
W -= value.W;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator -=(float scalar) mut
|
|
||||||
{
|
|
||||||
X -= scalar;
|
|
||||||
Y -= scalar;
|
|
||||||
Z -= scalar;
|
|
||||||
W -= scalar;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Multiplication
|
|
||||||
|
|
||||||
public void operator *=(Vector4 value) mut
|
|
||||||
{
|
|
||||||
X *= value.X;
|
|
||||||
Y *= value.Y;
|
|
||||||
Z *= value.Z;
|
|
||||||
W *= value.W;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator *=(float scalar) mut
|
|
||||||
{
|
|
||||||
X *= scalar;
|
|
||||||
Y *= scalar;
|
|
||||||
Z *= scalar;
|
|
||||||
W *= scalar;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Division
|
|
||||||
|
|
||||||
public void operator /=(float scalar) mut
|
|
||||||
{
|
|
||||||
float f = 1.0f / scalar;
|
|
||||||
X *= f;
|
|
||||||
Y *= f;
|
|
||||||
Z *= f;
|
|
||||||
W *= f;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator /=(Vector4 value) mut
|
|
||||||
{
|
|
||||||
X /= value.X;
|
|
||||||
Y /= value.Y;
|
|
||||||
Z /= value.Z;
|
|
||||||
W /= value.W;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// operators
|
|
||||||
//
|
|
||||||
|
|
||||||
// Addition
|
|
||||||
|
|
||||||
public static Vector4 operator +(Vector4 left, Vector4 right) => Vector4(left.X + right.X, left.Y + right.Y, left.Z + right.Z, left.W + right.W);
|
|
||||||
|
|
||||||
public static Vector4 operator +(Vector4 value, float scalar) => Vector4(value.X + scalar, value.Y + scalar, value.Z + scalar, value.W + scalar);
|
|
||||||
|
|
||||||
public static Vector4 operator +(float scalar, Vector4 value) => Vector4(scalar + value.X, scalar + value.Y, scalar + value.Z, scalar + value.W);
|
|
||||||
|
|
||||||
public static Vector4 operator +(Vector4 value) => value;
|
|
||||||
|
|
||||||
// Subtraction
|
|
||||||
|
|
||||||
public static Vector4 operator -(Vector4 left, Vector4 right) => Vector4(left.X - right.X, left.Y - right.Y, left.Z - right.Z, left.W - right.W);
|
|
||||||
|
|
||||||
public static Vector4 operator -(Vector4 value, float scalar) => Vector4(value.X - scalar, value.Y - scalar, value.Z - scalar, value.W - scalar);
|
|
||||||
|
|
||||||
public static Vector4 operator -(float scalar, Vector4 value) => Vector4(scalar - value.X, scalar - value.Y, scalar - value.Z, scalar - value.W);
|
|
||||||
|
|
||||||
public static Vector4 operator -(Vector4 value) => Vector4(-value.X, -value.Y, -value.Z, -value.W);
|
|
||||||
|
|
||||||
// Multiplication
|
|
||||||
|
|
||||||
public static Vector4 operator *(Vector4 left, Vector4 right) => Vector4(left.X * right.X, left.Y * right.Y, left.Z * right.Z, left.W * right.W);
|
|
||||||
|
|
||||||
public static Vector4 operator *(Vector4 value, float scalar) => Vector4(value.X * scalar, value.Y * scalar, value.Z * scalar, value.W * scalar);
|
|
||||||
|
|
||||||
public static Vector4 operator *(float scalar, Vector4 value) => Vector4(scalar * value.X, scalar * value.Y, scalar * value.Z, scalar * value.W);
|
|
||||||
|
|
||||||
// Division
|
|
||||||
|
|
||||||
public static Vector4 operator /(Vector4 left, Vector4 right) => Vector4(left.X / right.X, left.Y / right.Y, left.Z / right.Z, left.W / right.W);
|
|
||||||
|
|
||||||
public static Vector4 operator /(Vector4 value, float scalar)
|
|
||||||
{
|
|
||||||
float inv = 1.0f / scalar;
|
|
||||||
return Vector4(value.X * inv, value.Y * inv, value.Z * inv, value.W * inv);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector4 operator /(float scalar, Vector4 value) => Vector4(scalar / value.X, scalar / value.Y, scalar / value.Z, scalar / value.W);
|
|
||||||
|
|
||||||
// Equality
|
|
||||||
|
|
||||||
public static bool operator ==(Vector4 left, Vector4 right) => left.X == right.X && left.Y == right.Y && left.Z == right.Z && left.W == right.W;
|
|
||||||
|
|
||||||
public static bool operator !=(Vector4 left, Vector4 right) => left.X != right.X || left.Y != right.Y || left.Z != right.Z || left.W != right.W;
|
|
||||||
|
|
||||||
public override void ToString(String strBuffer) => strBuffer.AppendF("X:{0} Y:{1} Z:{2} W:{3}", X, Y, Z, W);
|
|
||||||
|
|
||||||
[Inline]
|
|
||||||
public static explicit operator Self(float value) => Self(value);
|
|
||||||
|
|
||||||
[Inline]
|
|
||||||
#unwarn
|
|
||||||
public static explicit operator float[4](Vector4 value) => *(float[4]*)&value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,440 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Math;
|
||||||
|
|
||||||
|
[AttributeUsage(.Struct | .Class)]
|
||||||
|
struct VectorAttribute<T, ComponentCount> : Attribute, IComptimeTypeApply where ComponentCount : const int
|
||||||
|
{
|
||||||
|
public const String[4] ComponentNames = .("X", "Y", "Z", "W");
|
||||||
|
public const String[4] LowerComponentNames = .("x", "y", "z", "w");
|
||||||
|
|
||||||
|
[Comptime]
|
||||||
|
public void ApplyToType(Type type)
|
||||||
|
{
|
||||||
|
GenerateFields(type);
|
||||||
|
|
||||||
|
GenerateCasts(type);
|
||||||
|
|
||||||
|
GenerateConstructors(type);
|
||||||
|
|
||||||
|
GenerateEqualityOperators(type);
|
||||||
|
|
||||||
|
GenerateArrayAccess(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Comptime]
|
||||||
|
private void GenerateFields(Type type)
|
||||||
|
{
|
||||||
|
String fields = scope $"public {typeof(T)} ";
|
||||||
|
|
||||||
|
for (int i < ComponentCount)
|
||||||
|
{
|
||||||
|
if (i != 0)
|
||||||
|
fields.Append(", ");
|
||||||
|
|
||||||
|
fields.Append(ComponentNames[i]);
|
||||||
|
}
|
||||||
|
fields.Append(";\n\n");
|
||||||
|
|
||||||
|
Compiler.EmitTypeBody(type, fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Comptime]
|
||||||
|
private void GenerateCasts(Type type)
|
||||||
|
{
|
||||||
|
String constructorBody = scope String();
|
||||||
|
|
||||||
|
for (int i < ComponentCount)
|
||||||
|
{
|
||||||
|
if (i != 0)
|
||||||
|
constructorBody.Append(", ");
|
||||||
|
|
||||||
|
constructorBody.Append("value");
|
||||||
|
}
|
||||||
|
|
||||||
|
String castSingleToVector = scope $"""
|
||||||
|
public static implicit operator Self({typeof(T)} value)
|
||||||
|
{{
|
||||||
|
return Self({constructorBody});
|
||||||
|
}}
|
||||||
|
|
||||||
|
|
||||||
|
""";
|
||||||
|
|
||||||
|
Compiler.EmitTypeBody(type, castSingleToVector);
|
||||||
|
|
||||||
|
String castVectorToArray = scope $"""
|
||||||
|
[System.Inline]
|
||||||
|
#unwarn
|
||||||
|
public static explicit operator {typeof(T)}[{ComponentCount}](Self value) => *({typeof(T)}[{ComponentCount}]*)&value;
|
||||||
|
|
||||||
|
|
||||||
|
""";
|
||||||
|
|
||||||
|
Compiler.EmitTypeBody(type, castVectorToArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
[Comptime]
|
||||||
|
private void GenerateConstructors(Type type)
|
||||||
|
{
|
||||||
|
// Default constructor
|
||||||
|
//Compiler.EmitTypeBody(type, "public this() => this = default;\n\n");
|
||||||
|
|
||||||
|
// Single constructor
|
||||||
|
GenerateSingleConstructor(type);
|
||||||
|
|
||||||
|
if (ComponentCount == 3)
|
||||||
|
{
|
||||||
|
Generatefloat3Constructors(type);
|
||||||
|
}
|
||||||
|
else if (ComponentCount == 4)
|
||||||
|
{
|
||||||
|
Generatefloat4Constructors(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Comptime]
|
||||||
|
private void GenerateSingleConstructor(Type type)
|
||||||
|
{
|
||||||
|
String parameters = scope .();
|
||||||
|
|
||||||
|
for (int i < ComponentCount)
|
||||||
|
{
|
||||||
|
if (i != 0)
|
||||||
|
parameters.Append(", ");
|
||||||
|
|
||||||
|
parameters.AppendF($"{typeof(T)} {LowerComponentNames[i]}");
|
||||||
|
}
|
||||||
|
|
||||||
|
String body = scope .();
|
||||||
|
|
||||||
|
for (int i < ComponentCount)
|
||||||
|
{
|
||||||
|
body.AppendF($"\t{ComponentNames[i]} = {LowerComponentNames[i]};\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
String constructor = scope $"""
|
||||||
|
public this({parameters})
|
||||||
|
{{
|
||||||
|
{body}
|
||||||
|
}}
|
||||||
|
|
||||||
|
|
||||||
|
""";
|
||||||
|
|
||||||
|
Compiler.EmitTypeBody(type, constructor);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Comptime]
|
||||||
|
private void Generatefloat3Constructors(Type type)
|
||||||
|
{
|
||||||
|
String baseName = type.GetName(.. scope String());
|
||||||
|
|
||||||
|
// Remove number from name
|
||||||
|
baseName.RemoveFromEnd(1);
|
||||||
|
|
||||||
|
String constructor1 = scope $"""
|
||||||
|
public this({baseName}2 xy, {typeof(T)} z)
|
||||||
|
{{
|
||||||
|
X = xy.X;
|
||||||
|
Y = xy.Y;
|
||||||
|
Z = z;
|
||||||
|
}}
|
||||||
|
|
||||||
|
""";
|
||||||
|
|
||||||
|
Compiler.EmitTypeBody(type, constructor1);
|
||||||
|
|
||||||
|
String constructor2 = scope $"""
|
||||||
|
public this({typeof(T)} x, {baseName}2 yz)
|
||||||
|
{{
|
||||||
|
X = x;
|
||||||
|
Y = yz.X;
|
||||||
|
Z = yz.Y;
|
||||||
|
}}
|
||||||
|
|
||||||
|
""";
|
||||||
|
|
||||||
|
Compiler.EmitTypeBody(type, constructor2);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Comptime]
|
||||||
|
private void Generatefloat4Constructors(Type type)
|
||||||
|
{
|
||||||
|
String baseName = type.GetName(.. scope String());
|
||||||
|
|
||||||
|
// Remove number from name
|
||||||
|
baseName.RemoveFromEnd(1);
|
||||||
|
|
||||||
|
String constructor = scope $"""
|
||||||
|
public this({baseName}2 xy, {baseName}2 zw)
|
||||||
|
{{
|
||||||
|
X = xy.X;
|
||||||
|
Y = xy.Y;
|
||||||
|
Z = zw.X;
|
||||||
|
W = zw.Y;
|
||||||
|
}}
|
||||||
|
|
||||||
|
""";
|
||||||
|
|
||||||
|
Compiler.EmitTypeBody(type, constructor);
|
||||||
|
|
||||||
|
|
||||||
|
String constructor1 = scope $"""
|
||||||
|
public this({baseName}2 xy, {typeof(T)} z, {typeof(T)} w)
|
||||||
|
{{
|
||||||
|
X = xy.X;
|
||||||
|
Y = xy.Y;
|
||||||
|
Z = z;
|
||||||
|
W = w;
|
||||||
|
}}
|
||||||
|
|
||||||
|
""";
|
||||||
|
|
||||||
|
Compiler.EmitTypeBody(type, constructor1);
|
||||||
|
|
||||||
|
String constructor2 = scope $"""
|
||||||
|
public this({typeof(T)} x, {baseName}2 yz, {typeof(T)} w)
|
||||||
|
{{
|
||||||
|
X = x;
|
||||||
|
Y = yz.X;
|
||||||
|
Z = yz.Y;
|
||||||
|
W = w;
|
||||||
|
}}
|
||||||
|
|
||||||
|
""";
|
||||||
|
|
||||||
|
Compiler.EmitTypeBody(type, constructor2);
|
||||||
|
|
||||||
|
String constructor3 = scope $"""
|
||||||
|
public this({typeof(T)} x, {typeof(T)} y, {baseName}2 zw)
|
||||||
|
{{
|
||||||
|
X = x;
|
||||||
|
Y = y;
|
||||||
|
Z = zw.X;
|
||||||
|
W = zw.Y;
|
||||||
|
}}
|
||||||
|
|
||||||
|
""";
|
||||||
|
|
||||||
|
Compiler.EmitTypeBody(type, constructor3);
|
||||||
|
|
||||||
|
|
||||||
|
String constructor4 = scope $"""
|
||||||
|
public this({baseName}3 xyz, {typeof(T)} w)
|
||||||
|
{{
|
||||||
|
X = xyz.X;
|
||||||
|
Y = xyz.Y;
|
||||||
|
Z = xyz.Z;
|
||||||
|
W = w;
|
||||||
|
}}
|
||||||
|
|
||||||
|
""";
|
||||||
|
|
||||||
|
Compiler.EmitTypeBody(type, constructor4);
|
||||||
|
|
||||||
|
String constructor5 = scope $"""
|
||||||
|
public this({typeof(T)} x, {baseName}3 yzw)
|
||||||
|
{{
|
||||||
|
X = x;
|
||||||
|
Y = yzw.X;
|
||||||
|
Z = yzw.Y;
|
||||||
|
W = yzw.Z;
|
||||||
|
}}
|
||||||
|
|
||||||
|
""";
|
||||||
|
|
||||||
|
Compiler.EmitTypeBody(type, constructor5);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Constructors
|
||||||
|
|
||||||
|
[Comptime]
|
||||||
|
private void GenerateEqualityOperators(Type type)
|
||||||
|
{
|
||||||
|
GenerateComparison(type, "==");
|
||||||
|
GenerateComparison(type, "!=");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Comptime]
|
||||||
|
public static void GenerateComparison(Type type, String op)
|
||||||
|
{
|
||||||
|
String boolConstructor = scope .();
|
||||||
|
|
||||||
|
for (int i < ComponentCount)
|
||||||
|
{
|
||||||
|
if (i != 0)
|
||||||
|
boolConstructor.Append(", ");
|
||||||
|
|
||||||
|
boolConstructor.AppendF($"left.{ComponentNames[i]} {op} right.{ComponentNames[i]}");
|
||||||
|
}
|
||||||
|
|
||||||
|
String typeName = type.GetName(.. scope String());
|
||||||
|
|
||||||
|
String func = scope $"""
|
||||||
|
public static bool{ComponentCount} operator{op}({typeName} left, {typeName} right)
|
||||||
|
{{
|
||||||
|
return bool{ComponentCount}({boolConstructor});
|
||||||
|
}}
|
||||||
|
|
||||||
|
""";
|
||||||
|
|
||||||
|
Compiler.EmitTypeBody(type, func);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Comptime]
|
||||||
|
private static void GenerateArrayAccess(Type type)
|
||||||
|
{
|
||||||
|
String arrayAccess = scope $"""
|
||||||
|
public {typeof(T)} this[int index]
|
||||||
|
{{
|
||||||
|
get
|
||||||
|
{{
|
||||||
|
if(index < 0 || index >= {ComponentCount})
|
||||||
|
System.Internal.ThrowIndexOutOfRange(1);
|
||||||
|
|
||||||
|
#unwarn
|
||||||
|
return (&X)[index];
|
||||||
|
}}
|
||||||
|
set mut
|
||||||
|
{{
|
||||||
|
if(index < 0 || index >= {ComponentCount})
|
||||||
|
System.Internal.ThrowIndexOutOfRange(1);
|
||||||
|
|
||||||
|
#unwarn
|
||||||
|
(&X)[index] = value;
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
""";
|
||||||
|
|
||||||
|
Compiler.EmitTypeBody(type, arrayAccess);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[AttributeUsage(.Struct | .Class)]
|
||||||
|
struct ComparableVectorAttribute<T, ComponentCount> : Attribute, IComptimeTypeApply where ComponentCount : const int
|
||||||
|
{
|
||||||
|
[Comptime]
|
||||||
|
public void ApplyToType(Type type)
|
||||||
|
{
|
||||||
|
VectorAttribute<T, ComponentCount>.GenerateComparison(type, ">");
|
||||||
|
VectorAttribute<T, ComponentCount>.GenerateComparison(type, ">=");
|
||||||
|
VectorAttribute<T, ComponentCount>.GenerateComparison(type, "<");
|
||||||
|
VectorAttribute<T, ComponentCount>.GenerateComparison(type, "<=");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[AttributeUsage(.Struct | .Class)]
|
||||||
|
struct VectorMathAttribute<T, ComponentCount> : Attribute, IComptimeTypeApply where ComponentCount : const int
|
||||||
|
{
|
||||||
|
public const String[4] ComponentNames = .("X", "Y", "Z", "W");
|
||||||
|
|
||||||
|
[Comptime]
|
||||||
|
public void ApplyToType(Type type)
|
||||||
|
{
|
||||||
|
GenerateUnaryOperatorOverloads(type);
|
||||||
|
|
||||||
|
GenerateOperatorOverloads(type, "+");
|
||||||
|
GenerateOperatorOverloads(type, "-");
|
||||||
|
GenerateOperatorOverloads(type, "*");
|
||||||
|
GenerateOperatorOverloads(type, "/");
|
||||||
|
GenerateOperatorOverloads(type, "%");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Comptime]
|
||||||
|
public static void GenerateUnaryOperatorOverloads(Type type)
|
||||||
|
{
|
||||||
|
String typeName = type.GetName(.. scope String());
|
||||||
|
|
||||||
|
String unaryAdd = scope $"""
|
||||||
|
public static {typeName} operator+({typeName} value) => value;
|
||||||
|
|
||||||
|
""";
|
||||||
|
|
||||||
|
Compiler.EmitTypeBody(type, unaryAdd);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
String resultArguments = scope .();
|
||||||
|
|
||||||
|
for (int i < ComponentCount)
|
||||||
|
{
|
||||||
|
if (i != 0)
|
||||||
|
resultArguments.Append(", ");
|
||||||
|
|
||||||
|
resultArguments.AppendF($"-value.{ComponentNames[i]}");
|
||||||
|
}
|
||||||
|
|
||||||
|
String unaryMinus = scope $"""
|
||||||
|
public static {typeName} operator-({typeName} value)
|
||||||
|
{{
|
||||||
|
return {typeName}({resultArguments});
|
||||||
|
}}
|
||||||
|
|
||||||
|
""";
|
||||||
|
|
||||||
|
Compiler.EmitTypeBody(type, unaryMinus);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Comptime]
|
||||||
|
public static void GenerateOperatorOverloads(Type type, String op)
|
||||||
|
{
|
||||||
|
String typeName = type.GetName(.. scope String());
|
||||||
|
String componentTypeName = typeof(T).GetName(.. scope String());
|
||||||
|
|
||||||
|
[Comptime]
|
||||||
|
void EmitOperatorOverload(String leftType, String rightType, String resultArguments)
|
||||||
|
{
|
||||||
|
String func = scope $"""
|
||||||
|
public static {typeName} operator{op}({leftType} left, {rightType} right)
|
||||||
|
{{
|
||||||
|
return {typeName}({resultArguments});
|
||||||
|
}}
|
||||||
|
|
||||||
|
""";
|
||||||
|
|
||||||
|
Compiler.EmitTypeBody(type, func);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vector + Vector
|
||||||
|
String resultArguments = scope .();
|
||||||
|
|
||||||
|
for (int i < ComponentCount)
|
||||||
|
{
|
||||||
|
if (i != 0)
|
||||||
|
resultArguments.Append(", ");
|
||||||
|
|
||||||
|
resultArguments.AppendF($"left.{ComponentNames[i]} {op} right.{ComponentNames[i]}");
|
||||||
|
}
|
||||||
|
|
||||||
|
EmitOperatorOverload(typeName, typeName, resultArguments);
|
||||||
|
|
||||||
|
// Vector + Scalar
|
||||||
|
resultArguments.Clear();
|
||||||
|
|
||||||
|
for (int i < ComponentCount)
|
||||||
|
{
|
||||||
|
if (i != 0)
|
||||||
|
resultArguments.Append(", ");
|
||||||
|
|
||||||
|
resultArguments.AppendF($"left.{ComponentNames[i]} {op} right");
|
||||||
|
}
|
||||||
|
|
||||||
|
EmitOperatorOverload(typeName, componentTypeName, resultArguments);
|
||||||
|
|
||||||
|
// Scalar + Vector
|
||||||
|
resultArguments.Clear();
|
||||||
|
|
||||||
|
for (int i < ComponentCount)
|
||||||
|
{
|
||||||
|
if (i != 0)
|
||||||
|
resultArguments.Append(", ");
|
||||||
|
|
||||||
|
resultArguments.AppendF($"left {op} right.{ComponentNames[i]}");
|
||||||
|
}
|
||||||
|
|
||||||
|
EmitOperatorOverload(componentTypeName, typeName, resultArguments);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,162 +0,0 @@
|
|||||||
#pragma warning disable 4204
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
|
|
||||||
namespace GlitchyEngine.Math
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* A Vector with two components of type int32.
|
|
||||||
*/
|
|
||||||
[SwizzleVector(2, "Int")]
|
|
||||||
public struct Int2 : IHashable
|
|
||||||
{
|
|
||||||
public const Int2 Zero = .(0, 0);
|
|
||||||
public const Int2 UnitX = .(1, 0);
|
|
||||||
public const Int2 UnitY = .(0, 1);
|
|
||||||
public const Int2 One = .(1, 1);
|
|
||||||
|
|
||||||
public int32 X, Y;
|
|
||||||
|
|
||||||
public this() => this = default;
|
|
||||||
|
|
||||||
public this(int32 value)
|
|
||||||
{
|
|
||||||
X = value;
|
|
||||||
Y = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(int value)
|
|
||||||
{
|
|
||||||
X = (.)value;
|
|
||||||
Y = (.)value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(int32 x, int32 y)
|
|
||||||
{
|
|
||||||
X = x;
|
|
||||||
Y = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(int x, int y)
|
|
||||||
{
|
|
||||||
X = (.)x;
|
|
||||||
Y = (.)y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ref int32 this[int index]
|
|
||||||
{
|
|
||||||
[Inline]
|
|
||||||
get
|
|
||||||
{
|
|
||||||
#if DEBUG
|
|
||||||
if(index < 0 || index >= 2)
|
|
||||||
Internal.ThrowIndexOutOfRange(1);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return ref (&X)[index];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int32 MagnitudeSquared() => X * X + Y * Y;
|
|
||||||
|
|
||||||
public float Magnitude() => Math.Sqrt(X * X + Y * Y);
|
|
||||||
|
|
||||||
public Int2 Abs() => .(Math.Abs(X), Math.Abs(Y));
|
|
||||||
|
|
||||||
//
|
|
||||||
// Assignment operators
|
|
||||||
//
|
|
||||||
|
|
||||||
public void operator +=(Int2 value) mut
|
|
||||||
{
|
|
||||||
X += value.X;
|
|
||||||
Y += value.Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator +=(int32 value) mut
|
|
||||||
{
|
|
||||||
X += value;
|
|
||||||
Y += value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator -=(Int2 value) mut
|
|
||||||
{
|
|
||||||
X -= value.X;
|
|
||||||
Y -= value.Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator -=(int32 value) mut
|
|
||||||
{
|
|
||||||
X -= value;
|
|
||||||
Y -= value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator *=(Int2 value) mut
|
|
||||||
{
|
|
||||||
X *= value.X;
|
|
||||||
Y *= value.Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator *=(int32 value) mut
|
|
||||||
{
|
|
||||||
X *= value;
|
|
||||||
Y *= value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator /=(Int2 value) mut
|
|
||||||
{
|
|
||||||
X /= value.X;
|
|
||||||
Y /= value.Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator /=(int32 value) mut
|
|
||||||
{
|
|
||||||
X /= value;
|
|
||||||
Y /= value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Operators
|
|
||||||
|
|
||||||
public static Int2 operator +(Int2 value) => value;
|
|
||||||
public static Int2 operator +(Int2 left, Int2 right) => .(left.X + right.X, left.Y + right.Y);
|
|
||||||
public static Int2 operator +(Int2 left, int32 right) => .(left.X + right, left.Y + right);
|
|
||||||
public static Int2 operator +(int32 left, Int2 right) => .(left + right.X, left + right.Y);
|
|
||||||
|
|
||||||
public static Int2 operator -(Int2 value) => .(-value.X, -value.Y);
|
|
||||||
public static Int2 operator -(Int2 left, Int2 right) => .(left.X - right.X, left.Y - right.Y);
|
|
||||||
public static Int2 operator -(Int2 left, int32 right) => .(left.X - right, left.Y - right);
|
|
||||||
public static Int2 operator -(int32 left, Int2 right) => .(left - right.X, left - right.Y);
|
|
||||||
|
|
||||||
public static Int2 operator *(Int2 left, Int2 right) => .(left.X * right.X, left.Y * right.Y);
|
|
||||||
public static Int2 operator *(Int2 left, int32 right) => .(left.X * right, left.Y * right);
|
|
||||||
public static Int2 operator *(int32 left, Int2 right) => .(left * right.X, left * right.Y);
|
|
||||||
|
|
||||||
public static Int2 operator /(Int2 left, Int2 right) => .(left.X / right.X, left.Y / right.Y);
|
|
||||||
public static Int2 operator /(Int2 left, int32 right) => .(left.X / right, left.Y / right);
|
|
||||||
public static Int2 operator /(int32 left, Int2 right) => .(left / right.X, left / right.Y);
|
|
||||||
|
|
||||||
public static Int2 operator %(Int2 left, Int2 right) => .(left.X % right.X, left.Y % right.Y);
|
|
||||||
public static Int2 operator %(Int2 left, int32 right) => .(left.X % right, left.Y % right);
|
|
||||||
public static Int2 operator %(int32 left, Int2 right) => .(left % right.X, left % right.Y);
|
|
||||||
|
|
||||||
public static bool operator ==(Int2 left, Int2 right) => left.X == right.X && left.Y == right.Y;
|
|
||||||
public static bool operator ==(Int2 left, int32 right) => left.X == right && left.Y == right;
|
|
||||||
public static bool operator ==(int32 left, Int2 right) => left == right.X && left == right.Y;
|
|
||||||
|
|
||||||
public static bool operator !=(Int2 left, Int2 right) => left.X != right.X || left.Y != right.Y;
|
|
||||||
public static bool operator !=(Int2 left, int32 right) => left.X != right || left.Y != right;
|
|
||||||
public static bool operator !=(int32 left, Int2 right) => left != right.X || left != right.Y;
|
|
||||||
|
|
||||||
public override void ToString(String strBuffer) => strBuffer.AppendF($"X:{X} Y:{Y}");
|
|
||||||
|
|
||||||
public static explicit operator Vector2(Int2 point) => .(point.X, point.Y);
|
|
||||||
|
|
||||||
public static explicit operator Int2(Vector2 point) => .((int32)point.X, (int32)point.Y);
|
|
||||||
|
|
||||||
public int GetHashCode()
|
|
||||||
{
|
|
||||||
return (X * 39) ^ Y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,206 +0,0 @@
|
|||||||
#pragma warning disable 4204
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
|
|
||||||
namespace GlitchyEngine.Math
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* A Vector with three components of type int32.
|
|
||||||
*/
|
|
||||||
[SwizzleVector(3, "Int")]
|
|
||||||
public struct Int3 : IHashable
|
|
||||||
{
|
|
||||||
public const Int3 Zero = .(0, 0, 0);
|
|
||||||
public const Int3 UnitX = .(1, 0, 0);
|
|
||||||
public const Int3 UnitY = .(0, 1, 0);
|
|
||||||
public const Int3 UnitZ = .(0, 0, 1);
|
|
||||||
public const Int3 One = .(1, 1, 1);
|
|
||||||
|
|
||||||
public int32 X, Y, Z;
|
|
||||||
|
|
||||||
public this() => this = default;
|
|
||||||
|
|
||||||
public this(int32 value)
|
|
||||||
{
|
|
||||||
X = value;
|
|
||||||
Y = value;
|
|
||||||
Z = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(int value)
|
|
||||||
{
|
|
||||||
X = (.)value;
|
|
||||||
Y = (.)value;
|
|
||||||
Z = (.)value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(int32 x, int32 y, int32 z)
|
|
||||||
{
|
|
||||||
X = x;
|
|
||||||
Y = y;
|
|
||||||
Z = z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(Int2 xy, int32 z)
|
|
||||||
{
|
|
||||||
X = xy.X;
|
|
||||||
Y = xy.Y;
|
|
||||||
Z = z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(int32 x, Int2 yz)
|
|
||||||
{
|
|
||||||
X = x;
|
|
||||||
Y = yz.X;
|
|
||||||
Z = yz.Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(int x, int y, int z)
|
|
||||||
{
|
|
||||||
X = (.)x;
|
|
||||||
Y = (.)y;
|
|
||||||
Z = (.)z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(Int2 xy, int z)
|
|
||||||
{
|
|
||||||
X = xy.X;
|
|
||||||
Y = xy.Y;
|
|
||||||
Z = (.)z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(int x, Int2 yz)
|
|
||||||
{
|
|
||||||
X = (.)x;
|
|
||||||
Y = yz.X;
|
|
||||||
Z = yz.Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ref int32 this[int index]
|
|
||||||
{
|
|
||||||
[Inline]
|
|
||||||
get
|
|
||||||
{
|
|
||||||
#if DEBUG
|
|
||||||
if(index < 0 || index >= 3)
|
|
||||||
Internal.ThrowIndexOutOfRange(1);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return ref (&X)[index];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int32 MagnitudeSquared() => X * X + Y * Y + Z * Z;
|
|
||||||
|
|
||||||
public float Magnitude() => Math.Sqrt(X * X + Y * Y + Z * Z);
|
|
||||||
|
|
||||||
public Int3 Abs() => .(Math.Abs(X), Math.Abs(Y), Math.Abs(Z));
|
|
||||||
|
|
||||||
//
|
|
||||||
// Assignment operators
|
|
||||||
//
|
|
||||||
|
|
||||||
public void operator +=(Int3 value) mut
|
|
||||||
{
|
|
||||||
X += value.X;
|
|
||||||
Y += value.Y;
|
|
||||||
Z += value.Z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator +=(int32 value) mut
|
|
||||||
{
|
|
||||||
X += value;
|
|
||||||
Y += value;
|
|
||||||
Z += value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator -=(Int3 value) mut
|
|
||||||
{
|
|
||||||
X -= value.X;
|
|
||||||
Y -= value.Y;
|
|
||||||
Z -= value.Z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator -=(int32 value) mut
|
|
||||||
{
|
|
||||||
X -= value;
|
|
||||||
Y -= value;
|
|
||||||
Z -= value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator *=(Int3 value) mut
|
|
||||||
{
|
|
||||||
X *= value.X;
|
|
||||||
Y *= value.Y;
|
|
||||||
Z *= value.Z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator *=(int32 value) mut
|
|
||||||
{
|
|
||||||
X *= value;
|
|
||||||
Y *= value;
|
|
||||||
Z *= value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator /=(Int3 value) mut
|
|
||||||
{
|
|
||||||
X /= value.X;
|
|
||||||
Y /= value.Y;
|
|
||||||
Z /= value.Z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator /=(int32 value) mut
|
|
||||||
{
|
|
||||||
X /= value;
|
|
||||||
Y /= value;
|
|
||||||
Z /= value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Operators
|
|
||||||
|
|
||||||
public static Int3 operator +(Int3 value) => value;
|
|
||||||
public static Int3 operator +(Int3 left, Int3 right) => .(left.X + right.X, left.Y + right.Y, left.Z + right.Z);
|
|
||||||
public static Int3 operator +(Int3 left, int32 right) => .(left.X + right, left.Y + right, left.Z + right);
|
|
||||||
public static Int3 operator +(int32 left, Int3 right) => .(left + right.X, left + right.Y, left + right.Z);
|
|
||||||
|
|
||||||
public static Int3 operator -(Int3 value) => .(-value.X, -value.Y, -value.Z);
|
|
||||||
public static Int3 operator -(Int3 left, Int3 right) => .(left.X - right.X, left.Y - right.Y, left.Z - right.Z);
|
|
||||||
public static Int3 operator -(Int3 left, int32 right) => .(left.X - right, left.Y - right, left.Z- right);
|
|
||||||
public static Int3 operator -(int32 left, Int3 right) => .(left - right.X, left - right.Y, left - right.Z);
|
|
||||||
|
|
||||||
public static Int3 operator *(Int3 left, Int3 right) => .(left.X * right.X, left.Y * right.Y, left.Z * right.Z);
|
|
||||||
public static Int3 operator *(Int3 left, int32 right) => .(left.X * right, left.Y * right, left.Z * right);
|
|
||||||
public static Int3 operator *(int32 left, Int3 right) => .(left * right.X, left * right.Y, left * right.Z);
|
|
||||||
|
|
||||||
public static Int3 operator /(Int3 left, Int3 right) => .(left.X / right.X, left.Y / right.Y, left.Z / right.Z);
|
|
||||||
public static Int3 operator /(Int3 left, int32 right) => .(left.X / right, left.Y / right, left.Z / right);
|
|
||||||
public static Int3 operator /(int32 left, Int3 right) => .(left / right.X, left / right.Y, left / right.Z);
|
|
||||||
|
|
||||||
public static Int3 operator %(Int3 left, Int3 right) => .(left.X % right.X, left.Y % right.Y, left.Z % right.Z);
|
|
||||||
public static Int3 operator %(Int3 left, int32 right) => .(left.X % right, left.Y % right, left.Z % right);
|
|
||||||
public static Int3 operator %(int32 left, Int3 right) => .(left % right.X, left % right.Y, left % right.Z);
|
|
||||||
|
|
||||||
public static bool operator ==(Int3 left, Int3 right) => left.X == right.X && left.Y == right.Y && left.Z == right.Z;
|
|
||||||
public static bool operator ==(Int3 left, int32 right) => left.X == right && left.Y == right && left.Z == right;
|
|
||||||
public static bool operator ==(int32 left, Int3 right) => left == right.X && left == right.Y && left == right.Z;
|
|
||||||
|
|
||||||
public static bool operator !=(Int3 left, Int3 right) => left.X != right.X || left.Y != right.Y || left.Z != right.Z;
|
|
||||||
public static bool operator !=(Int3 left, int32 right) => left.X != right || left.Y != right || left.Z != right;
|
|
||||||
public static bool operator !=(int32 left, Int3 right) => left != right.X || left != right.Y || left != right.Z;
|
|
||||||
|
|
||||||
public override void ToString(String strBuffer) => strBuffer.AppendF($"X:{X} Y:{Y} Z:{Z}");
|
|
||||||
|
|
||||||
public static explicit operator Vector3(Int3 point) => .(point.X, point.Y, point.Z);
|
|
||||||
|
|
||||||
public static explicit operator Int3(Vector3 point) => .((int32)point.X, (int32)point.Y, (int32)point.Z);
|
|
||||||
|
|
||||||
[Inline]
|
|
||||||
public static explicit operator Int2(in Int3 point) => *(Int2*)&point;
|
|
||||||
|
|
||||||
public int GetHashCode()
|
|
||||||
{
|
|
||||||
return (((X * 39) ^ Y) * 39) ^ Z;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,234 +0,0 @@
|
|||||||
#pragma warning disable 4204
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
|
|
||||||
namespace GlitchyEngine.Math
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* A Vector with four components of type int32.
|
|
||||||
*/
|
|
||||||
[SwizzleVector(4, "Int")]
|
|
||||||
public struct Int4 : IHashable
|
|
||||||
{
|
|
||||||
public const Int4 Zero = .(0, 0, 0, 0);
|
|
||||||
public const Int4 UnitX = .(1, 0, 0, 0);
|
|
||||||
public const Int4 UnitY = .(0, 1, 0, 0);
|
|
||||||
public const Int4 UnitZ = .(0, 0, 1, 0);
|
|
||||||
public const Int4 UnitW = .(0, 0, 0, 1);
|
|
||||||
public const Int4 One = .(1, 1, 1, 1);
|
|
||||||
|
|
||||||
public int32 X, Y, Z, W;
|
|
||||||
|
|
||||||
public this() => this = default;
|
|
||||||
|
|
||||||
public this(int32 value)
|
|
||||||
{
|
|
||||||
X = value;
|
|
||||||
Y = value;
|
|
||||||
Z = value;
|
|
||||||
W = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(int value)
|
|
||||||
{
|
|
||||||
X = (.)value;
|
|
||||||
Y = (.)value;
|
|
||||||
Z = (.)value;
|
|
||||||
W = (.)value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(int32 x, int32 y, int32 z, int32 w)
|
|
||||||
{
|
|
||||||
X = x;
|
|
||||||
Y = y;
|
|
||||||
Z = z;
|
|
||||||
W = w;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(Int2 xy, int32 z, int32 w)
|
|
||||||
{
|
|
||||||
X = xy.X;
|
|
||||||
Y = xy.Y;
|
|
||||||
Z = z;
|
|
||||||
W = w;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(int32 x, Int2 yz, int32 w)
|
|
||||||
{
|
|
||||||
X = x;
|
|
||||||
Y = yz.X;
|
|
||||||
Z = yz.Y;
|
|
||||||
W = w;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(int32 x, int32 y, Int2 zw)
|
|
||||||
{
|
|
||||||
X = x;
|
|
||||||
Y = y;
|
|
||||||
Z = zw.X;
|
|
||||||
W = zw.Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(Int2 xy, Int2 zw)
|
|
||||||
{
|
|
||||||
X = xy.X;
|
|
||||||
Y = xy.Y;
|
|
||||||
Z = zw.X;
|
|
||||||
W = zw.Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(Int3 xyz, int32 w)
|
|
||||||
{
|
|
||||||
X = xyz.X;
|
|
||||||
Y = xyz.Y;
|
|
||||||
Z = xyz.Z;
|
|
||||||
W = w;
|
|
||||||
}
|
|
||||||
|
|
||||||
public this(int32 x, Int3 yzw)
|
|
||||||
{
|
|
||||||
X = x;
|
|
||||||
Y = yzw.X;
|
|
||||||
Z = yzw.Y;
|
|
||||||
W = yzw.Z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ref int32 this[int index]
|
|
||||||
{
|
|
||||||
[Inline]
|
|
||||||
get
|
|
||||||
{
|
|
||||||
#if DEBUG
|
|
||||||
if(index < 0 || index >= 3)
|
|
||||||
Internal.ThrowIndexOutOfRange(1);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return ref (&X)[index];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int32 MagnitudeSquared() => X * X + Y * Y + Z * Z + W * W;
|
|
||||||
|
|
||||||
public float Magnitude() => Math.Sqrt(X * X + Y * Y + Z * Z + W * W);
|
|
||||||
|
|
||||||
public Int4 Abs() => .(Math.Abs(X), Math.Abs(Y), Math.Abs(Z), Math.Abs(W));
|
|
||||||
|
|
||||||
//
|
|
||||||
// Assignment operators
|
|
||||||
//
|
|
||||||
|
|
||||||
public void operator +=(Int4 value) mut
|
|
||||||
{
|
|
||||||
X += value.X;
|
|
||||||
Y += value.Y;
|
|
||||||
Z += value.Z;
|
|
||||||
W += value.W;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator +=(int32 value) mut
|
|
||||||
{
|
|
||||||
X += value;
|
|
||||||
Y += value;
|
|
||||||
Z += value;
|
|
||||||
W += value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator -=(Int4 value) mut
|
|
||||||
{
|
|
||||||
X -= value.X;
|
|
||||||
Y -= value.Y;
|
|
||||||
Z -= value.Z;
|
|
||||||
W -= value.W;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator -=(int32 value) mut
|
|
||||||
{
|
|
||||||
X -= value;
|
|
||||||
Y -= value;
|
|
||||||
Z -= value;
|
|
||||||
W -= value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator *=(Int4 value) mut
|
|
||||||
{
|
|
||||||
X *= value.X;
|
|
||||||
Y *= value.Y;
|
|
||||||
Z *= value.Z;
|
|
||||||
W *= value.W;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator *=(int32 value) mut
|
|
||||||
{
|
|
||||||
X *= value;
|
|
||||||
Y *= value;
|
|
||||||
Z *= value;
|
|
||||||
W *= value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator /=(Int4 value) mut
|
|
||||||
{
|
|
||||||
X /= value.X;
|
|
||||||
Y /= value.Y;
|
|
||||||
Z /= value.Z;
|
|
||||||
W /= value.W;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void operator /=(int32 value) mut
|
|
||||||
{
|
|
||||||
X /= value;
|
|
||||||
Y /= value;
|
|
||||||
Z /= value;
|
|
||||||
W /= value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Operators
|
|
||||||
|
|
||||||
public static Int4 operator +(Int4 value) => value;
|
|
||||||
public static Int4 operator +(Int4 left, Int4 right) => .(left.X + right.X, left.Y + right.Y, left.Z + right.Z, left.W + right.W);
|
|
||||||
public static Int4 operator +(Int4 left, int32 right) => .(left.X + right, left.Y + right, left.Z + right, left.W + right);
|
|
||||||
public static Int4 operator +(int32 left, Int4 right) => .(left + right.X, left + right.Y, left + right.Z, left + right.W);
|
|
||||||
|
|
||||||
public static Int4 operator -(Int4 value) => .(-value.X, -value.Y, -value.Z, -value.W);
|
|
||||||
public static Int4 operator -(Int4 left, Int4 right) => .(left.X - right.X, left.Y - right.Y, left.Z - right.Z, left.W - right.W);
|
|
||||||
public static Int4 operator -(Int4 left, int32 right) => .(left.X - right, left.Y - right, left.Z - right, left.W - right);
|
|
||||||
public static Int4 operator -(int32 left, Int4 right) => .(left - right.X, left - right.Y, left - right.Z, left - right.W);
|
|
||||||
|
|
||||||
public static Int4 operator *(Int4 left, Int4 right) => .(left.X * right.X, left.Y * right.Y, left.Z * right.Z, left.W * right.W);
|
|
||||||
public static Int4 operator *(Int4 left, int32 right) => .(left.X * right, left.Y * right, left.Z * right, left.W * right);
|
|
||||||
public static Int4 operator *(int32 left, Int4 right) => .(left * right.X, left * right.Y, left * right.Z, left * right.W);
|
|
||||||
|
|
||||||
public static Int4 operator /(Int4 left, Int4 right) => .(left.X / right.X, left.Y / right.Y, left.Z / right.Z, left.W / right.W);
|
|
||||||
public static Int4 operator /(Int4 left, int32 right) => .(left.X / right, left.Y / right, left.Z / right, left.W / right);
|
|
||||||
public static Int4 operator /(int32 left, Int4 right) => .(left / right.X, left / right.Y, left / right.Z, left / right.W);
|
|
||||||
|
|
||||||
public static Int4 operator %(Int4 left, Int4 right) => .(left.X % right.X, left.Y % right.Y, left.Z % right.Z, left.W % right.W);
|
|
||||||
public static Int4 operator %(Int4 left, int32 right) => .(left.X % right, left.Y % right, left.Z % right, left.W % right);
|
|
||||||
public static Int4 operator %(int32 left, Int4 right) => .(left % right.X, left % right.Y, left % right.Z, left % right.W);
|
|
||||||
|
|
||||||
public static bool operator ==(Int4 left, Int4 right) => left.X == right.X && left.Y == right.Y && left.Z == right.Z && left.W == right.W;
|
|
||||||
public static bool operator ==(Int4 left, int32 right) => left.X == right && left.Y == right && left.Z == right && left.W == right;
|
|
||||||
public static bool operator ==(int32 left, Int4 right) => left == right.X && left == right.Y && left == right.Z && left == right.W;
|
|
||||||
|
|
||||||
public static bool operator !=(Int4 left, Int4 right) => left.X != right.X || left.Y != right.Y || left.Z != right.Z || left.W != right.W;
|
|
||||||
public static bool operator !=(Int4 left, int32 right) => left.X != right || left.Y != right || left.Z != right || left.W != right;
|
|
||||||
public static bool operator !=(int32 left, Int4 right) => left != right.X || left != right.Y || left != right.Z || left != right.W;
|
|
||||||
|
|
||||||
public override void ToString(String strBuffer) => strBuffer.AppendF($"X:{X} Y:{Y} Z:{Z} W:{W}");
|
|
||||||
|
|
||||||
public static explicit operator Vector4(Int4 point) => .(point.X, point.Y, point.Z, point.W);
|
|
||||||
|
|
||||||
public static explicit operator Int4(Vector4 point) => .((int32)point.X, (int32)point.Y, (int32)point.Z, (int32)point.W);
|
|
||||||
|
|
||||||
[Inline]
|
|
||||||
public static explicit operator Int2(in Int4 point) => *(Int2*)&point;
|
|
||||||
|
|
||||||
[Inline]
|
|
||||||
public static explicit operator Int3(in Int4 point) => *(Int3*)&point;
|
|
||||||
|
|
||||||
public int GetHashCode()
|
|
||||||
{
|
|
||||||
return (((((X * 39) ^ Y) * 39) ^ Z) * 39) ^ W;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
using Bon;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Math;
|
||||||
|
|
||||||
|
[BonTarget]
|
||||||
|
[Vector<bool, 2>]
|
||||||
|
[SwizzleVector(2, "GlitchyEngine.Math.bool")]
|
||||||
|
struct bool2
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[BonTarget]
|
||||||
|
[Vector<bool, 3>]
|
||||||
|
[SwizzleVector(3, "GlitchyEngine.Math.bool")]
|
||||||
|
struct bool3
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[BonTarget]
|
||||||
|
[Vector<bool, 4>]
|
||||||
|
[SwizzleVector(4, "GlitchyEngine.Math.bool")]
|
||||||
|
struct bool4
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
using Bon;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Math;
|
||||||
|
|
||||||
|
[BonTarget]
|
||||||
|
[Vector<double, 2>]
|
||||||
|
[ComparableVector<double, 2>]
|
||||||
|
[VectorMath<double, 2>]
|
||||||
|
[SwizzleVector(2, "GlitchyEngine.Math.double")]
|
||||||
|
public struct double2
|
||||||
|
{
|
||||||
|
public const double2 Zero = .(0, 0);
|
||||||
|
public const double2 UnitX = .(1, 0);
|
||||||
|
public const double2 UnitY = .(0, 1);
|
||||||
|
public const double2 One = .(1, 1);
|
||||||
|
|
||||||
|
public static explicit operator int2(double2 value)
|
||||||
|
{
|
||||||
|
return int2((int32)value.X, (int32)value.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static explicit operator uint2(double2 value)
|
||||||
|
{
|
||||||
|
return uint2((uint32)value.X, (uint32)value.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static explicit operator half2(double2 value)
|
||||||
|
{
|
||||||
|
return half2((half)value.X, (half)value.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static explicit operator float2(double2 value)
|
||||||
|
{
|
||||||
|
return float2((float)value.X, (float)value.Y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[BonTarget]
|
||||||
|
[Vector<double, 3>]
|
||||||
|
[ComparableVector<double, 3>]
|
||||||
|
[VectorMath<double, 3>]
|
||||||
|
[SwizzleVector(3, "GlitchyEngine.Math.double")]
|
||||||
|
public struct double3
|
||||||
|
{
|
||||||
|
public const double3 Zero = .(0, 0, 0);
|
||||||
|
public const double3 UnitX = .(1, 0, 0);
|
||||||
|
public const double3 UnitY = .(0, 1, 0);
|
||||||
|
public const double3 UnitZ = .(0, 0, 1);
|
||||||
|
public const double3 One = .(1, 1, 1);
|
||||||
|
|
||||||
|
public const double3 Forward = .(0, 0, 1);
|
||||||
|
public const double3 Backward = .(0, 0, -1);
|
||||||
|
public const double3 Left = .(-1, 0, 0);
|
||||||
|
public const double3 Right = .(1, 0, 0);
|
||||||
|
public const double3 Up = .(0, 1, 0);
|
||||||
|
public const double3 Down = .(0, -1, 0);
|
||||||
|
|
||||||
|
public static explicit operator int3(double3 value)
|
||||||
|
{
|
||||||
|
return int3((int32)value.X, (int32)value.Y, (int32)value.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static explicit operator uint3(double3 value)
|
||||||
|
{
|
||||||
|
return uint3((uint32)value.X, (uint32)value.Y, (uint32)value.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static explicit operator half3(double3 value)
|
||||||
|
{
|
||||||
|
return half3((half)(float)value.X, (half)(float)value.Y, (half)(float)value.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static explicit operator float3(double3 value)
|
||||||
|
{
|
||||||
|
return float3((float)value.X, (float)value.Y, (float)value.Z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[BonTarget]
|
||||||
|
[Vector<double, 4>]
|
||||||
|
[ComparableVector<double, 4>]
|
||||||
|
[VectorMath<double, 4>]
|
||||||
|
[SwizzleVector(4, "GlitchyEngine.Math.double")]
|
||||||
|
public struct double4
|
||||||
|
{
|
||||||
|
public const double4 Zero = .(0, 0, 0, 0);
|
||||||
|
public const double4 UnitX = .(1, 0, 0, 0);
|
||||||
|
public const double4 UnitY = .(0, 1, 0, 0);
|
||||||
|
public const double4 UnitZ = .(0, 0, 1, 0);
|
||||||
|
public const double4 UnitW = .(0, 0, 0, 1);
|
||||||
|
public const double4 One = .(1, 1, 1, 1);
|
||||||
|
|
||||||
|
public static explicit operator int4(double4 value)
|
||||||
|
{
|
||||||
|
return int4((int32)value.X, (int32)value.Y, (int32)value.Z, (int32)value.W);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static explicit operator uint4(double4 value)
|
||||||
|
{
|
||||||
|
return uint4((uint32)value.X, (uint32)value.Y, (uint32)value.Z, (uint32)value.W);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static explicit operator half4(double4 value)
|
||||||
|
{
|
||||||
|
return half4((half)(float)value.X, (half)(float)value.Y, (half)(float)value.Z, (half)(float)value.W);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static explicit operator float4(double4 value)
|
||||||
|
{
|
||||||
|
return float4((float)value.X, (float)value.Y, (float)value.Z, (float)value.W);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
using Bon;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Math;
|
||||||
|
|
||||||
|
[BonTarget]
|
||||||
|
[Vector<float, 2>]
|
||||||
|
[ComparableVector<float, 2>]
|
||||||
|
[VectorMath<float, 2>]
|
||||||
|
[SwizzleVector(2, "GlitchyEngine.Math.float")]
|
||||||
|
public struct float2
|
||||||
|
{
|
||||||
|
public const float2 Zero = .(0f, 0f);
|
||||||
|
public const float2 UnitX = .(1f, 0f);
|
||||||
|
public const float2 UnitY = .(0f, 1f);
|
||||||
|
public const float2 One = .(1f, 1f);
|
||||||
|
|
||||||
|
public static implicit operator int2(float2 value)
|
||||||
|
{
|
||||||
|
return int2((int32)value.X, (int32)value.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static explicit operator half2(float2 value)
|
||||||
|
{
|
||||||
|
return half2((half)value.X, (half)value.Y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[BonTarget]
|
||||||
|
[Vector<float, 3>]
|
||||||
|
[ComparableVector<float, 3>]
|
||||||
|
[VectorMath<float, 3>]
|
||||||
|
[SwizzleVector(3, "GlitchyEngine.Math.float")]
|
||||||
|
public struct float3
|
||||||
|
{
|
||||||
|
public const float3 Zero = .(0f, 0f, 0f);
|
||||||
|
public const float3 UnitX = .(1f, 0f, 0f);
|
||||||
|
public const float3 UnitY = .(0f, 1f, 0f);
|
||||||
|
public const float3 UnitZ = .(0f, 0f, 1f);
|
||||||
|
public const float3 One = .(1f, 1f, 1f);
|
||||||
|
|
||||||
|
public const float3 Forward = .(0f, 0f, 1f);
|
||||||
|
public const float3 Backward = .(0f, 0f, -1f);
|
||||||
|
public const float3 Left = .(-1f, 0f, 0f);
|
||||||
|
public const float3 Right = .(1f, 0f, 0f);
|
||||||
|
public const float3 Up = .(0f, 1f, 0f);
|
||||||
|
public const float3 Down = .(0f, -1f, 0f);
|
||||||
|
|
||||||
|
public static implicit operator int3(float3 value)
|
||||||
|
{
|
||||||
|
return int3((int32)value.X, (int32)value.Y, (int32)value.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static explicit operator half3(float3 value)
|
||||||
|
{
|
||||||
|
return half3((half)value.X, (half)value.Y, (half)value.Z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[BonTarget]
|
||||||
|
[Vector<float, 4>]
|
||||||
|
[ComparableVector<float, 4>]
|
||||||
|
[VectorMath<float, 4>]
|
||||||
|
[SwizzleVector(4, "GlitchyEngine.Math.float")]
|
||||||
|
public struct float4
|
||||||
|
{
|
||||||
|
public const float4 Zero = .(0f, 0f, 0f, 0f);
|
||||||
|
public const float4 UnitX = .(1f, 0f, 0f, 0f);
|
||||||
|
public const float4 UnitY = .(0f, 1f, 0f, 0f);
|
||||||
|
public const float4 UnitZ = .(0f, 0f, 1f, 0f);
|
||||||
|
public const float4 UnitW = .(0f, 0f, 0f, 1f);
|
||||||
|
public const float4 One = .(1f, 1f, 1f, 1f);
|
||||||
|
|
||||||
|
public static implicit operator int4(float4 value)
|
||||||
|
{
|
||||||
|
return int4((int32)value.X, (int32)value.Y, (int32)value.Z, (int32)value.W);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static explicit operator half4(float4 value)
|
||||||
|
{
|
||||||
|
return half4((half)value.X, (half)value.Y, (half)value.Z, (half)value.W);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,312 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Math;
|
||||||
|
|
||||||
|
/// Represents a 16bit floating point number. (IEEE 754 half-precision binary floating-point (binary16))
|
||||||
|
/// Note: Eventhough it is possible, it is not recommended to perform calculations on this type.
|
||||||
|
/// Most operations will simply convert the halfs to floats, perform the calculation and convert the result back to half.
|
||||||
|
struct half : IFloating, ISigned, IFormattable, IHashable, IEquatable<half>, ICanBeNaN
|
||||||
|
{
|
||||||
|
public const half MinValue = half(-65504); // Should be 0xFBFF
|
||||||
|
public const half MaxValue = half(65504); // Should be 0x7BFF
|
||||||
|
|
||||||
|
// The numbers for Inifnity, NaN and Zero need to be hardcoded as binaries,
|
||||||
|
// because the conversion intself relies on them.
|
||||||
|
|
||||||
|
public const half PositiveInfinity = half(0x7C00);
|
||||||
|
public const half NegativeInfinity = half(0xFC00);
|
||||||
|
public const half NaN = half(0x7CFF);
|
||||||
|
|
||||||
|
public const half Zero = half(0x0000);
|
||||||
|
public const half NegativeZero = half(0x8000);
|
||||||
|
|
||||||
|
private uint16 _data;
|
||||||
|
|
||||||
|
public bool IsNegative => (_data & Half_Sign_Mask) > 0;
|
||||||
|
|
||||||
|
public bool IsFinity => (_data & ~Half_Sign_Mask) < Half_Exponent_Mask;
|
||||||
|
public bool IsInfinity => (_data & ~Half_Sign_Mask) == Half_Exponent_Mask;
|
||||||
|
|
||||||
|
public bool IsPositiveInfinity => _data == PositiveInfinity._data;
|
||||||
|
public bool IsNegativeInfinity => _data == NegativeInfinity._data;
|
||||||
|
|
||||||
|
public bool IsNaN => (_data & ~Half_Sign_Mask) > Half_Exponent_Mask;
|
||||||
|
|
||||||
|
public bool IsSubnormal
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var unsignedBits = _data & ~Half_Sign_Mask;
|
||||||
|
|
||||||
|
// Zero isn't normalized and if exponent is 0 we are unnormalized
|
||||||
|
return (unsignedBits != 0) && ((unsignedBits & Half_Exponent_Mask) == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public this(float value)
|
||||||
|
{
|
||||||
|
this = FromFloat32(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private this(uint16 data)
|
||||||
|
{
|
||||||
|
_data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public explicit static operator half(float value) => FromFloat32(value);
|
||||||
|
public explicit static operator float(half value) => ToFloat32(value);
|
||||||
|
|
||||||
|
public static half FromFloat32(float value)
|
||||||
|
{
|
||||||
|
if (value == 0.0f)
|
||||||
|
return half(0x0000);
|
||||||
|
|
||||||
|
if (value == -0.0f)
|
||||||
|
return half(0x8000);
|
||||||
|
|
||||||
|
#unwarn
|
||||||
|
uint32 singleBits = *(uint32*)&value;
|
||||||
|
|
||||||
|
uint32 sign = GetSingleSignBit(singleBits);
|
||||||
|
int32 exponent = (int32)GetSingleExponent(singleBits);
|
||||||
|
uint32 mantissa = GetSingleMantissa(singleBits);
|
||||||
|
|
||||||
|
// Shift 13 so we truncate mantissa from 23 to 10 bits.
|
||||||
|
uint32 halfMantissa = mantissa >> 13;
|
||||||
|
|
||||||
|
if (exponent == 0xFF)
|
||||||
|
{
|
||||||
|
// largest possible single exponent -> either infinity or NaN
|
||||||
|
|
||||||
|
if (mantissa == 0)
|
||||||
|
{
|
||||||
|
// Infinity
|
||||||
|
return (sign == 1) ? NegativeInfinity : PositiveInfinity;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// NaN -> Keeps sign and mantissa intact
|
||||||
|
|
||||||
|
uint16 halfBits = SetHalfSignBit(0, (uint16)sign);
|
||||||
|
// Set all five exponent bits to 1
|
||||||
|
halfBits = SetHalfExponent(halfBits, 0x1F);
|
||||||
|
halfBits = SetHalfMantissa(halfBits, (uint16)halfMantissa);
|
||||||
|
|
||||||
|
return half(halfBits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalized single
|
||||||
|
|
||||||
|
// excess-K decode and encode -127 is k for single, 15 is k for half
|
||||||
|
exponent = exponent - 127 + 15;
|
||||||
|
|
||||||
|
if (exponent < 0)
|
||||||
|
// The given number is too small for a half (even denormalized) -> return 0
|
||||||
|
return (sign == 1) ? NegativeZero : Zero;
|
||||||
|
|
||||||
|
if (exponent > 31)
|
||||||
|
// The given number is too large for a half -> return infinity
|
||||||
|
return (sign == 1) ? NegativeInfinity : PositiveInfinity;
|
||||||
|
|
||||||
|
// The given number fits -> convert (might become denormalized)
|
||||||
|
uint16 halfBits = SetHalfSignBit(0, (uint16)sign);
|
||||||
|
halfBits = SetHalfExponent(halfBits, (uint16)exponent);
|
||||||
|
halfBits = SetHalfMantissa(halfBits, (uint16)halfMantissa);
|
||||||
|
|
||||||
|
return half(halfBits);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float ToFloat32(half value)
|
||||||
|
{
|
||||||
|
#unwarn
|
||||||
|
uint16 halfBits = *(uint16*)&value;
|
||||||
|
|
||||||
|
if (halfBits == Zero._data)
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
if (halfBits == NegativeZero._data)
|
||||||
|
return -0.0f;
|
||||||
|
|
||||||
|
uint16 sign = GetHalfSignBit(halfBits);
|
||||||
|
int16 exponent = (int16)GetHalfExponent(halfBits);
|
||||||
|
uint16 mantissa = GetHalfMantissa(halfBits);
|
||||||
|
|
||||||
|
// Shift 13 so we extend mantissa from 10 to 23 bits.
|
||||||
|
uint32 singleMantissa = (uint32)mantissa << 13;
|
||||||
|
|
||||||
|
if (exponent == 0x1F)
|
||||||
|
{
|
||||||
|
// largest possible half exponent -> either infinity or NaN
|
||||||
|
|
||||||
|
if (mantissa == 0)
|
||||||
|
{
|
||||||
|
// Infinity
|
||||||
|
return (sign == 1) ? float.NegativeInfinity : float.PositiveInfinity;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// NaN -> Keeps sign and mantissa intact
|
||||||
|
|
||||||
|
uint32 singleBits = SetSingleSignBit(0, sign);
|
||||||
|
// Set all five exponent bits to 1
|
||||||
|
singleBits = SetSingleExponent(halfBits, 0xFF);
|
||||||
|
singleBits = SetSingleMantissa(halfBits, singleMantissa);
|
||||||
|
|
||||||
|
return *(float*)&singleBits;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalized half
|
||||||
|
|
||||||
|
// excess-K decode and encode -127 is k for single, 15 is k for half
|
||||||
|
exponent = exponent - 15 + 127;
|
||||||
|
|
||||||
|
uint32 singleBits = SetSingleSignBit(0, sign);
|
||||||
|
singleBits = SetSingleExponent(singleBits, (uint32)exponent);
|
||||||
|
singleBits = SetSingleMantissa(singleBits, singleMantissa);
|
||||||
|
|
||||||
|
return *(float*)&singleBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Single <-> Half Helpers
|
||||||
|
|
||||||
|
const uint32 Single_Sign_Shift = 31;
|
||||||
|
const uint32 Single_Sign_Mask = 0x8000'0000; // 1 bit, offset 31
|
||||||
|
|
||||||
|
const uint32 Single_Exponent_Shift = 23;
|
||||||
|
const uint32 Single_Exponent_Mask = 0x7F80'0000; // 8 bit, offset 23
|
||||||
|
|
||||||
|
const uint32 Single_Mantissa_Mask = 0x007F'FFFF; // 23 bit, offset 0
|
||||||
|
|
||||||
|
const uint16 Half_Sign_Shift = 15;
|
||||||
|
const uint16 Half_Sign_Mask = 0x8000; // 1 bit, offset 15
|
||||||
|
|
||||||
|
const uint16 Half_Exponent_Shift = 10;
|
||||||
|
const uint16 Half_Exponent_Mask = 0x7C00; // 5 bit, offset 10
|
||||||
|
|
||||||
|
const uint16 Half_Mantissa_Mask = 0x03FF; // 10 bit, offset 0
|
||||||
|
|
||||||
|
private static uint32 GetSingleSignBit(uint32 singleData)
|
||||||
|
{
|
||||||
|
return (singleData >> Single_Sign_Shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static uint32 GetSingleExponent(uint32 singleData)
|
||||||
|
{
|
||||||
|
return (singleData & Single_Exponent_Mask) >> Single_Exponent_Shift;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static uint32 GetSingleMantissa(uint32 singleData)
|
||||||
|
{
|
||||||
|
return (singleData & Single_Mantissa_Mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static uint32 SetSingleSignBit(uint32 singleData, uint32 signBit)
|
||||||
|
{
|
||||||
|
return ((signBit << Single_Sign_Shift) & Single_Sign_Mask) | (singleData & ~Single_Sign_Mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static uint32 SetSingleExponent(uint32 singleData, uint32 exponent)
|
||||||
|
{
|
||||||
|
return ((exponent << Single_Exponent_Shift) & Single_Exponent_Mask) | (singleData & ~Single_Exponent_Mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static uint32 SetSingleMantissa(uint32 singleData, uint32 mantissa)
|
||||||
|
{
|
||||||
|
return (mantissa & Single_Mantissa_Mask) | (singleData & ~Single_Mantissa_Mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static uint16 GetHalfSignBit(uint16 HalfData)
|
||||||
|
{
|
||||||
|
return (HalfData >> Half_Sign_Shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static uint16 GetHalfExponent(uint16 HalfData)
|
||||||
|
{
|
||||||
|
return (HalfData & Half_Exponent_Mask) >> Half_Exponent_Shift;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static uint16 GetHalfMantissa(uint16 HalfData)
|
||||||
|
{
|
||||||
|
return (HalfData & Half_Mantissa_Mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static uint16 SetHalfSignBit(uint16 HalfData, uint16 signBit)
|
||||||
|
{
|
||||||
|
return ((signBit << Half_Sign_Shift) & Half_Sign_Mask) | (HalfData & ~Half_Sign_Mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static uint16 SetHalfExponent(uint16 HalfData, uint16 exponent)
|
||||||
|
{
|
||||||
|
return ((exponent << Half_Exponent_Shift) & Half_Exponent_Mask) | (HalfData & ~Half_Exponent_Mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static uint16 SetHalfMantissa(uint16 HalfData, uint16 mantissa)
|
||||||
|
{
|
||||||
|
return (mantissa & Half_Mantissa_Mask) | (HalfData & ~Half_Mantissa_Mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public int GetHashCode()
|
||||||
|
{
|
||||||
|
return _data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ToString(String outString)
|
||||||
|
{
|
||||||
|
ToFloat32(this).ToString(outString);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ToString(String outString, String format, IFormatProvider formatProvider)
|
||||||
|
{
|
||||||
|
ToFloat32(this).ToString(outString, format, formatProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static half operator +(half lhs, half rhs)
|
||||||
|
{
|
||||||
|
return (half)((float)lhs + (float)rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static half operator +(half value) => value;
|
||||||
|
|
||||||
|
public static half operator -(half lhs, half rhs)
|
||||||
|
{
|
||||||
|
return (half)((float)lhs - (float)rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static half operator -(half value)
|
||||||
|
{
|
||||||
|
uint16 signBit = GetHalfSignBit(value._data);
|
||||||
|
|
||||||
|
// Invert the sign bit (~)
|
||||||
|
return half(SetHalfSignBit(value._data, ~signBit));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static half operator *(half lhs, half rhs)
|
||||||
|
{
|
||||||
|
return (half)((float)lhs * (float)rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static half operator /(half lhs, half rhs)
|
||||||
|
{
|
||||||
|
return (half)((float)lhs / (float)rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static half operator %(half lhs, half rhs)
|
||||||
|
{
|
||||||
|
return (half)((float)lhs % (float)rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator==(half value1, half value2) => value1._data == value2._data;
|
||||||
|
|
||||||
|
public static bool operator!=(half value1, half value2) => value1._data != value2._data;
|
||||||
|
|
||||||
|
public static int operator<=>(half value1, half value2) => (float)value1 <=> (float)value2;
|
||||||
|
|
||||||
|
public bool Equals(half other)
|
||||||
|
{
|
||||||
|
return _data == other._data;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
using Bon;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Math;
|
||||||
|
|
||||||
|
[BonTarget]
|
||||||
|
[Vector<half, 2>]
|
||||||
|
[ComparableVector<half, 2>]
|
||||||
|
[VectorMath<half, 2>]
|
||||||
|
[SwizzleVector(2, "GlitchyEngine.Math.half")]
|
||||||
|
public struct half2
|
||||||
|
{
|
||||||
|
public static explicit operator float2(half2 value)
|
||||||
|
{
|
||||||
|
return float2((float)value.X, (float)value.Y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[BonTarget]
|
||||||
|
[Vector<half, 3>]
|
||||||
|
[ComparableVector<half, 3>]
|
||||||
|
[VectorMath<half, 3>]
|
||||||
|
[SwizzleVector(3, "GlitchyEngine.Math.half")]
|
||||||
|
public struct half3
|
||||||
|
{
|
||||||
|
public static explicit operator float3(half3 value)
|
||||||
|
{
|
||||||
|
return float3((float)value.X, (float)value.Y, (float)value.Z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[BonTarget]
|
||||||
|
[Vector<half, 4>]
|
||||||
|
[ComparableVector<half, 4>]
|
||||||
|
[VectorMath<half, 4>]
|
||||||
|
[SwizzleVector(4, "GlitchyEngine.Math.half")]
|
||||||
|
public struct half4
|
||||||
|
{
|
||||||
|
public static explicit operator float4(half4 value)
|
||||||
|
{
|
||||||
|
return float4((float)value.X, (float)value.Y, (float)value.Z, (float)value.W);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
using Bon;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Math;
|
||||||
|
|
||||||
|
[BonTarget]
|
||||||
|
[Vector<int32, 2>]
|
||||||
|
[ComparableVector<int32, 2>]
|
||||||
|
[VectorMath<int32, 2>]
|
||||||
|
[SwizzleVector(2, "GlitchyEngine.Math.int")]
|
||||||
|
public struct int2
|
||||||
|
{
|
||||||
|
public const int2 Zero = .(0, 0);
|
||||||
|
public const int2 UnitX = .(1, 0);
|
||||||
|
public const int2 UnitY = .(0, 1);
|
||||||
|
public const int2 One = .(1, 1);
|
||||||
|
|
||||||
|
public static implicit operator float2(int2 value)
|
||||||
|
{
|
||||||
|
return float2(value.X, value.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static explicit operator uint2(int2 value)
|
||||||
|
{
|
||||||
|
return uint2((uint32)value.X, (uint32)value.Y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[BonTarget]
|
||||||
|
[Vector<int32, 3>]
|
||||||
|
[ComparableVector<int32, 3>]
|
||||||
|
[VectorMath<int32, 3>]
|
||||||
|
[SwizzleVector(3, "GlitchyEngine.Math.int")]
|
||||||
|
public struct int3
|
||||||
|
{
|
||||||
|
public const int3 Zero = .(0, 0, 0);
|
||||||
|
public const int3 UnitX = .(1, 0, 0);
|
||||||
|
public const int3 UnitY = .(0, 1, 0);
|
||||||
|
public const int3 UnitZ = .(0, 0, 1);
|
||||||
|
public const int3 One = .(1, 1, 1);
|
||||||
|
|
||||||
|
public static implicit operator float3(int3 value)
|
||||||
|
{
|
||||||
|
return float3(value.X, value.Y, value.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static explicit operator uint3(int3 value)
|
||||||
|
{
|
||||||
|
return uint3((uint32)value.X, (uint32)value.Y, (uint32)value.Z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[BonTarget]
|
||||||
|
[Vector<int32, 4>]
|
||||||
|
[ComparableVector<int32, 4>]
|
||||||
|
[VectorMath<int32, 4>]
|
||||||
|
[SwizzleVector(4, "GlitchyEngine.Math.int")]
|
||||||
|
public struct int4
|
||||||
|
{
|
||||||
|
public const int4 Zero = .(0, 0, 0, 0);
|
||||||
|
public const int4 UnitX = .(1, 0, 0, 0);
|
||||||
|
public const int4 UnitY = .(0, 1, 0, 0);
|
||||||
|
public const int4 UnitZ = .(0, 0, 1, 0);
|
||||||
|
public const int4 UnitW = .(0, 0, 0, 1);
|
||||||
|
public const int4 One = .(1, 1, 1, 1);
|
||||||
|
|
||||||
|
public static implicit operator float4(int4 value)
|
||||||
|
{
|
||||||
|
return float4(value.X, value.Y, value.Z, value.W);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static explicit operator uint4(int4 value)
|
||||||
|
{
|
||||||
|
return uint4((uint32)value.X, (uint32)value.Y, (uint32)value.Z, (uint32)value.W);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[BonTarget]
|
||||||
|
[Vector<uint32, 2>]
|
||||||
|
[ComparableVector<uint32, 2>]
|
||||||
|
//[VectorMath<uint32, 2>]
|
||||||
|
[SwizzleVector(2, "GlitchyEngine.Math.uint")]
|
||||||
|
public struct uint2
|
||||||
|
{
|
||||||
|
public const uint2 Zero = .(0, 0);
|
||||||
|
public const uint2 UnitX = .(1, 0);
|
||||||
|
public const uint2 UnitY = .(0, 1);
|
||||||
|
public const uint2 One = .(1, 1);
|
||||||
|
|
||||||
|
public static implicit operator float2(uint2 value)
|
||||||
|
{
|
||||||
|
return float2(value.X, value.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static explicit operator int2(uint2 value)
|
||||||
|
{
|
||||||
|
return int2((int32)value.X, (int32)value.Y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[BonTarget]
|
||||||
|
[Vector<uint32, 3>]
|
||||||
|
[ComparableVector<uint32, 3>]
|
||||||
|
//[VectorMath<uint32, 3>]
|
||||||
|
[SwizzleVector(3, "GlitchyEngine.Math.uint")]
|
||||||
|
public struct uint3
|
||||||
|
{
|
||||||
|
public const uint3 Zero = .(0, 0, 0);
|
||||||
|
public const uint3 UnitX = .(1, 0, 0);
|
||||||
|
public const uint3 UnitY = .(0, 1, 0);
|
||||||
|
public const uint3 UnitZ = .(0, 0, 1);
|
||||||
|
public const uint3 One = .(1, 1, 1);
|
||||||
|
|
||||||
|
public static implicit operator float3(uint3 value)
|
||||||
|
{
|
||||||
|
return float3(value.X, value.Y, value.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static explicit operator int3(uint3 value)
|
||||||
|
{
|
||||||
|
return int3((int32)value.X, (int32)value.Y, (int32)value.Z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[BonTarget]
|
||||||
|
[Vector<uint32, 4>]
|
||||||
|
[ComparableVector<uint32, 4>]
|
||||||
|
//[VectorMath<uint32, 4>]
|
||||||
|
[SwizzleVector(4, "GlitchyEngine.Math.uint")]
|
||||||
|
public struct uint4
|
||||||
|
{
|
||||||
|
public const uint4 Zero = .(0, 0, 0, 0);
|
||||||
|
public const uint4 UnitX = .(1, 0, 0, 0);
|
||||||
|
public const uint4 UnitY = .(0, 1, 0, 0);
|
||||||
|
public const uint4 UnitZ = .(0, 0, 1, 0);
|
||||||
|
public const uint4 UnitW = .(0, 0, 0, 1);
|
||||||
|
public const uint4 One = .(1, 1, 1, 1);
|
||||||
|
|
||||||
|
public static implicit operator float4(uint4 value)
|
||||||
|
{
|
||||||
|
return float4(value.X, value.Y, value.Z, value.W);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static explicit operator int4(uint4 value)
|
||||||
|
{
|
||||||
|
return int4((int32)value.X, (int32)value.Y, (int32)value.Z, (int32)value.W);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,7 +14,7 @@ namespace GlitchyEngine
|
|||||||
|
|
||||||
private bool _rotation;
|
private bool _rotation;
|
||||||
|
|
||||||
private Vector3 _cameraPosition;
|
private float3 _cameraPosition;
|
||||||
private float _cameraRotation;
|
private float _cameraRotation;
|
||||||
private float _cameraTranslationSpeed = 1.0f;
|
private float _cameraTranslationSpeed = 1.0f;
|
||||||
private float _cameraRotationSpeed = 1.0f;
|
private float _cameraRotationSpeed = 1.0f;
|
||||||
@@ -41,7 +41,7 @@ namespace GlitchyEngine
|
|||||||
|
|
||||||
if(Application.Get().Window.IsActive)
|
if(Application.Get().Window.IsActive)
|
||||||
{
|
{
|
||||||
Vector3 movement = .();
|
float3 movement = .();
|
||||||
|
|
||||||
if(Input.IsKeyPressed(Key.W))
|
if(Input.IsKeyPressed(Key.W))
|
||||||
{
|
{
|
||||||
@@ -61,8 +61,8 @@ namespace GlitchyEngine
|
|||||||
movement.X += 1;
|
movement.X += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(movement != .Zero)
|
if(any(movement != .Zero))
|
||||||
movement.Normalize();
|
movement = normalize(movement);
|
||||||
|
|
||||||
movement *= (float)(gameTime.FrameTime.TotalSeconds) * _cameraTranslationSpeed * _zoomLevel;
|
movement *= (float)(gameTime.FrameTime.TotalSeconds) * _cameraTranslationSpeed * _zoomLevel;
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user