Author SHA1 Message Date
Simon Lübeß 75513bea3d Removed obsolete texture viewer 2023-07-28 21:09:33 +02:00
Simon Lübeß 16c3d7c44d Updated ImGui 2023-07-28 13:38:59 +02:00
Simon Lübeß 7ae069baf6 Fixed loading UI font 2023-07-28 12:26:15 +02:00
Simon Lübeß 00dc3faa19 Failed to show and edit script sctruct
+ SizeInBytes for MonoFields
2023-07-28 11:48:01 +02:00
Simon Lübeß f39acdadb3 Show enum fields in Edit mode 2023-07-28 00:07:10 +02:00
Simon Lübeß 1254d01545 Handle exceptions from C# Scripts + Log window + EditorLogger
+ Renamed Platform/DX11/ImGui.bf to .../Dx11ImGui.bf for clarity
+ ImGuiExtension: ImageButtonEx thata takes a TextureViewBinding
+ EditorLogger that logs to the LogWindow
+ Current logger can now be changed
+ Info, Trace, Warning and Error Icons
2023-07-27 21:58:42 +02:00
Simon Lübeß 0bc517842f Allow changing logger 2023-07-27 00:42:42 +02:00
Simon Lübeß 3e63281508 Fixed mono debugging... 2023-07-26 22:56:43 +02:00
Simon Lübeß ef486b7082 Basic entity highlighting 2023-07-25 19:37:13 +02:00
Simon Lübeß 81a61d5a90 Drag'n'drop for components
+ Added CreateInstance to ScriptClass
+ Added CreateComponentInstance to ScriptInstance
2023-07-25 16:37:41 +02:00
Simon Lübeß 37197cbdf1 Allow dragging and dropping of Entities in editor
+ New Dictionary Helpers
+ Made ImGui Payloads safer
+ Start of Component drag'n'drop
2023-07-24 23:17:00 +02:00
Simon Lübeß b53ed2d8f2 Made script deserialization more robust 2023-07-24 21:28:58 +02:00
Simon Lübeß 457b43352a Debugging, but it doesn't work for some reason 2023-07-21 16:16:24 +02:00
Simon Lübeß cc7fb7311f Added single step for simulation and play mode
+ Added ManualStepTime to GameTime
2023-07-20 23:21:21 +02:00
Simon Lübeß 5f27b8001a Automatic script assembly reloading 2023-07-20 22:11:11 +02:00
Simon Lübeß 0cbb8a4966 Fixed C# -> Beef Type mapping 2023-07-20 17:53:32 +02:00
Simon Lübeß 79adc70f01 Gitignores and missing updates to scripts 2023-07-20 17:51:06 +02:00
Simon Lübeß 78ba016b03 Log Exceptions in thrown by Script OnUpdate-Function 2023-07-20 17:48:50 +02:00
Simon Lübeß 3e55a1614a Shader like vectors for C# Scripting 2023-07-20 17:48:28 +02:00
Simon Lübeß f0de874572 Start of generate vectors for C# 2023-07-19 18:43:26 +02:00
Simon Lübeß 6e02a04a4f Changed ScriptCore to DotNet Standard 2.0 2023-07-19 15:45:36 +02:00
Simon Lübeß cd1562f372 Basic Script reloading
+ ScriptComponent now saves script name instead of direct ScriptClass reference
+ Added ClearDictionaryAndDeleteKeys helper
+ Moved ScriptFieldType to separate file
+ _ScriptFieldMap now uses String as Key
2023-07-18 22:06:34 +02:00
Simon Lübeß e8505f6bdb Scripting: FindEntityWithName and get script instance
+ Some C# UUID stuff
+ Added some Mono functions
+ ScriptEngine:
  + ID -> ScriptInstance map in ScriptEngine
  + GetManagedInstance

+ Fixed Scene not visible after loading a new scene
  + Renamed OnViewportResize to SetViewportSize for Scene and SceneRenderer
2023-07-17 20:27:18 +02:00
Simon Lübeß 66d66d3308 Serialize script fields in "array" + more forgiving deserialization 2023-07-17 04:04:01 +02:00
Simon Lübeß 88b393157a Make sure we always initialize with a scene 2023-07-17 04:00:30 +02:00
Simon Lübeß 28155ec92c Allow opening a scene on launch
+ don't resize on load/new scene
2023-07-17 02:19:49 +02:00
Simon Lübeß 1641bafd06 Don't instantiate scripts for Editor + ScriptComponent Serialzation + Don't crash when scene loading failed 2023-07-17 01:27:58 +02:00
Simon Lübeß 76bff3a6c1 Texture importer now supports mip maps 2023-07-06 17:06:59 +02:00
Simon Lübeß a507eeb1cd Kind of fixed a memory leak 2023-07-01 12:49:17 +02:00
Simon Lübeß 77c45db122 Replaced IntX by intX, Basic AssetViewer (can view Textures, kind of) 2023-07-01 00:15:01 +02:00
Simon Lübeß e12fcaacff Added Math min/max for float 2023-06-28 22:03:43 +02:00
Simon Lübeß b31d43820a Support emissive materials 2023-06-28 19:33:39 +02:00
Simon Lübeß 334c2c0366 Search in Content Browser (and added ForEach in TreeNode) 2023-06-28 19:27:52 +02:00
Simon Lübeß bb520b43ec Added support for Cube Textures, Improved dds import (and textures in general), Texture refactoring and DX11 DeviceContext synchronization 2023-06-25 17:58:16 +02:00
Simon Lübeß 46693666aa Fixed current directories context menu not opening
i.e. when right clicking the background of the current directory
2023-06-25 03:20:35 +02:00
Simon Lübeß 9e1f648aa0 Transitioned from VectorX to floatX
And some trying to update Rigidbody when transform changes
2023-06-25 02:47:33 +02:00
Simon Lübeß 5f5da2ed35 Moved vector type files 2023-06-25 01:11:06 +02:00
Simon Lübeß fa2277cd99 Start of shader like vectors + added 16 bit float 2023-06-24 23:45:56 +02:00
Simon Lübeß 54936d5744 Fixed crash when viewport size is negative 2023-06-24 13:07:07 +02:00
Simon Lübeß 04d69717a3 Automatically pull and build mono once + .gitignore 2023-06-18 21:03:59 +02:00
Simon Lübeß 3becc1e25b fixed Settings-File not being created and start of Recent-Projects-Menu 2023-06-18 16:05:03 +02:00
Simon Lübeß e8e6207bc1 Merge branch 'scripting' of github.com:aharabada/glitchy-engine-beef into scripting
# Conflicts:
#	GlitchyEngine/src/Scripting/ScriptClass.bf
#	GlitchyEngine/src/Scripting/ScriptEngine.bf
#	GlitchyEngine/src/Scripting/ScriptInstance.bf
#	GlitchyEngine/src/World/Scene.bf
#	GlitchyEngineHelper/src/Mono/Mono.bf
2023-06-18 14:33:28 +02:00
Simon Lübeß f4c5bf9c2d Added binding for mono_field_get_value_object 2023-06-18 14:24:26 +02:00
Simon Lübeß f4607a6210 Script default values after init, Fix memory leak, Copy Script values on Play 2023-05-31 14:38:07 +02:00
Simon Lübeß 6a59deb9e2 Weiß ich nicht, ist Monate her... 2023-05-30 16:54:57 +02:00
Simon Lübeß ac1817fe33 Weiß ich nicht, ist Monate her... 2023-05-30 16:52:27 +02:00
Simon Lübeß 5855b13873 Wer weiß, was ich alles so gemacht hatte...
- Fixed crash caused by early ScriptEngine shutdown
2023-05-30 16:50:22 +02:00
Simon Lübeß ef5e4ba64f Fixed ScriptClass leaking 2023-03-30 15:13:21 +02:00
Simon Lübeß 4fd9a924a0 Added basic component access in Scripts 2023-03-29 16:32:46 +02:00
Simon Lübeß e60d74fccd Basic entity scripting 2023-03-29 13:33:34 +02:00
Simon Lübeß 5e5134a607 Added Mono for C# scripting 2023-03-26 13:11:44 +02:00
Simon Lübeß fd6826785a Updated submodules again? 2023-03-25 13:24:50 +01:00
Simon Lübeß 43bcf01299 Merge branch 'asset_handle' into main 2023-03-25 13:20:40 +01:00
Simon Lübeß 0ee2f5fa9e Merge branch 'asset_handle' into main 2023-03-25 13:15:56 +01:00
213 changed files with 21389 additions and 3033 deletions
+3
View File
@@ -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
+2 -2
View File
@@ -1,7 +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"}}
Unlocked = ["corlib"] Unlocked = ["corlib"]
WorkspaceFolders = {GlitchyEngine = ["GlitchyEngine", "GlitchLog", "GlitchyEngineHelper"], "GlitchyEngine/Dependencies" = ["cgltf-beef", "DirectX", "FreeType", "ImGui", "ImGuiImplDX11", "ImGuiImplWin32", "ImGuizmo", "LodePng", "msdfgen-beef", "bon", "box2d-beef", "Beef.Linq"]} WorkspaceFolders = {GlitchyEngine = ["GlitchyEngine", "GlitchLog", "GlitchyEngineHelper", "ScriptCore"], "GlitchyEngine/Dependencies" = ["cgltf-beef", "DirectX", "FreeType", "ImGui", "ImGuiImplDX11", "ImGuiImplWin32", "ImGuizmo", "LodePng", "msdfgen-beef", "bon", "box2d-beef", "Beef.Linq"]}
[Workspace] [Workspace]
StartupProject = "GlitchyEditor" StartupProject = "GlitchyEditor"
+3
View File
@@ -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,46 @@
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 OnUpdate(float 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,155 @@
using System;
using System.Runtime.Remoting.Metadata.W3cXsd2001;
using GlitchyEngine;
using GlitchyEngine.Editor;
using GlitchyEngine.Math;
using static GlitchyEngine.Math.Math;
namespace Sandbox
{
public enum MyEnum
{
Yes = 1,
No,
Maybe = 1337
}
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 MyEnum AEnum = MyEnum.Maybe;
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>();
if (_rigidBody == null)
{
Log.Error("_rigidBody was not set in editor.");
}
if (Camera == null)
{
Log.Warning("Camera wasn't set in editor. Searching...");
Camera = FindEntityWithName("Camera").As<Camera>();
if (Camera == null)
{
Log.Error("Camera not found.");
}
}
Log.Warning("Achtung.");
try
{
SubVoid();
}
catch (Exception e)
{
Console.WriteLine(e);
throw e;
}
}
void SubVoid()
{
throw new Exception("Ouha!", new IndexOutOfRangeException("Bist du jecke2?!", new AccessViolationException("Haleluja")));
}
/// <summary>
/// Called every frame.
/// </summary>
/// <param name="deltaTime"></param>
void OnUpdate(float 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;
}
if (Input.IsKeyPressing(Key.N))
SubVoid();
_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,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// Allgemeine Informationen über eine Assembly werden über die folgenden
// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
// die einer Assembly zugeordnet sind.
[assembly: AssemblyTitle("Sanbox")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Sanbox")]
[assembly: AssemblyCopyright("Copyright © 2023")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly
// für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von
// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen.
[assembly: ComVisible(false)]
// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
[assembly: Guid("7a70819c-5317-402a-8553-95c5a001e370")]
// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
//
// Hauptversion
// Nebenversion
// Buildnummer
// Revision
//
// Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden,
// indem Sie "*" wie unten gezeigt eingeben:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
@@ -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>portable</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,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
+215 -13
View File
@@ -23,7 +23,7 @@
}, },
TransformComponent = { TransformComponent = {
Position = { Position = {
X = 0, X = -0.72789681,
Y = 2, Y = 2,
Z = 0 Z = 0
}, },
@@ -71,8 +71,8 @@
SpriteRendererComponent = { SpriteRendererComponent = {
Color = { Color = {
R = 1, R = 1,
G = 0.941886365, G = 0.941887021,
B = 0.401484847, B = 0.401484489,
A = 1 A = 1
}, },
Sprite = "", Sprite = "",
@@ -162,14 +162,20 @@
OrthographicHeight = 10, OrthographicHeight = 10,
OrthographicNearPlane = 0, OrthographicNearPlane = 0,
OrthographicFarPlane = 10, OrthographicFarPlane = 10,
AspectRatio = 3.22169805, AspectRatio = 2.05582929,
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"
}, },
CircleRendererComponent = { CircleRendererComponent = {
Color = { Color = {
@@ -189,8 +195,8 @@
}, },
TransformComponent = { TransformComponent = {
Position = { Position = {
X = -0.12120308, X = -0.121203206,
Y = 0.660160363, Y = 0.660161078,
Z = 0 Z = 0
}, },
Rotation = { Rotation = {
@@ -224,7 +230,17 @@
Friction = 0.5, Friction = 0.5,
Restitution = 0, Restitution = 0,
RestitutionThreshold = 0.5 RestitutionThreshold = 0.5
} },
ScriptComponent = {
ScriptClass = "Sandbox.MyTestEntity",
Fields = [
_rigidBody = (Component)15710354273720487680,
TheEntity = (Entity)0,
JumpForce = (Float)200,
MoveForce = (Float)148,
MyNumber = (Int)22,
Camera = (Entity)1491484622542812645
] }
}, },
{ {
Id = 935640822766280888, Id = 935640822766280888,
@@ -249,9 +265,9 @@
Z = 1 Z = 1
}, },
EditorEulerRotation = { EditorEulerRotation = {
X = 1.0908947, X = 1.09089541,
Y = -0.340793997, Y = -0.340793997,
Z = 0.160857916 Z = 0.160857871
} }
}, },
LightComponent = { LightComponent = {
@@ -260,7 +276,7 @@
Color = { Color = {
R = 0.985467017, R = 0.985467017,
G = 1, G = 1,
B = 0.569978654 B = 0.569977939
} }
} }
}, },
@@ -273,7 +289,7 @@
Position = { Position = {
X = 0, X = 0,
Y = 0, Y = 0,
Z = -1.47202551 Z = 2.56930423
}, },
Rotation = { Rotation = {
X = 0, X = 0,
@@ -298,6 +314,192 @@
MeshRendererComponent = { MeshRendererComponent = {
Material = "Textures/TestMaterial.mat" Material = "Textures/TestMaterial.mat"
} }
},
{
Id = 2241063100006479259,
NameComponent = {
Name = "Floor 2"
},
SpriteRendererComponent = {
Color = {
R = 0.425658971,
G = 0.855207443,
B = 0.0558161177,
A = 1
},
Sprite = "",
UvTransform = {
X = 0,
Y = 0,
Z = 1,
W = 1
}
},
TransformComponent = {
Position = {
X = 6.74610233,
Y = -2.03225946,
Z = 0
},
Rotation = {
X = 0,
Y = 0,
Z = -0.331792623,
W = 0.94335258
},
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.666117013,
G = 0.0600316115,
B = 1,
A = 1
},
Sprite = "",
UvTransform = {
X = 0,
Y = 0,
Z = 1,
W = 1
}
},
TransformComponent = {
Position = {
X = 15.2321281,
Y = -1.98709273,
Z = 0
},
Rotation = {
X = 0,
Y = 0,
Z = 0.134986058,
W = 0.990847468
},
Scale = {
X = 13.9764528,
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.176544309,
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.62550163,
Z = 0
},
Rotation = {
X = 0,
Y = 0,
Z = 0.187087879,
W = 0.982343197
},
Scale = {
X = 0.999999464,
Y = 6.49634314,
Z = 1
},
EditorEulerRotation = {
X = 0,
Y = 0,
Z = 0.376393616
}
},
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.899999857,
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 */
}
+36 -43
View File
@@ -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.
@@ -9,8 +9,8 @@
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.
@@ -1,20 +1,16 @@
{ {
AssetLoader = "EditorTextureAssetLoader", AssetLoader = "EditorTextureAssetLoader",
Config = (GlitchyEditor.Assets.EditorTextureAssetLoaderConfig){ Config = (GlitchyEditor.Assets.EditorTextureAssetLoaderConfig){
_generateMipMaps = false,
_isSrgb = false,
_samplerStateDescription = { _samplerStateDescription = {
MinFilter = .Linear, MinFilter = .Anisotropic,
MagFilter = .Linear, MagFilter = .Anisotropic,
MipFilter = .Linear, MipFilter = .Anisotropic,
FilterMode = .Default,
ComparisonFunction = .Never, ComparisonFunction = .Never,
AddressModeU = .Wrap, AddressModeU = .Wrap,
AddressModeV = .Wrap, AddressModeV = .Wrap,
AddressModeW = .Clamp, AddressModeW = .Clamp,
MipLODBias = 0, MipMinLOD = -Infinity,
MipMinLOD = -3.40282347e+38, MipMaxLOD = Infinity,
MipMaxLOD = 3.40282347e+38,
MaxAnisotropy = 1, MaxAnisotropy = 1,
BorderColor = { BorderColor = {
R = 1, R = 1,
@@ -1,10 +1,11 @@
{ {
Effect = "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", "NormalTexture": "Textures/TestMat/rustediron2_normal.png",
"MetallicTexture": "Textures\\TestMat\\rustediron2_metallic.png", "MetallicTexture": "Textures/TestMat/rustediron2_metallic.png",
"RoughnessTexture": "Textures\\TestMat\\rustediron2_roughness.png" "RoughnessTexture": "Textures/TestMat/rustediron2_roughness.png",
"EmissiveTexture": "Textures/rocket.png"
], ],
Variables = [ Variables = [
"AlbedoColor": .ColorRGBA{ "AlbedoColor": .ColorRGBA{
@@ -26,6 +27,13 @@
}, },
"RoughnessFactor": .Float{ "RoughnessFactor": .Float{
Value = 1 Value = 1
},
"EmissiveColor": .ColorRGB{
Value = {
R = 1,
G = 0,
B = 0
}
} }
] ]
} }
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
}
}
}
}
+1
View File
@@ -0,0 +1 @@
4.5/
+1
View File
@@ -0,0 +1 @@
Install mono and copy the folder `lib/mono/4.5` here!
@@ -0,0 +1,63 @@
{
"runtimeTarget": {
"name": ".NETStandard,Version=v2.0/",
"signature": ""
},
"compilationOptions": {},
"targets": {
".NETStandard,Version=v2.0": {},
".NETStandard,Version=v2.0/": {
"ScriptCore/1.0.0": {
"dependencies": {
"Half": "1.0.0",
"NETStandard.Library": "2.0.3"
},
"runtime": {
"ScriptCore.dll": {}
}
},
"Half/1.0.0": {
"runtime": {
"lib/netstandard2.0/System.Half.dll": {
"assemblyVersion": "1.0.0.0",
"fileVersion": "1.0.0.0"
}
}
},
"Microsoft.NETCore.Platforms/1.1.0": {},
"NETStandard.Library/2.0.3": {
"dependencies": {
"Microsoft.NETCore.Platforms": "1.1.0"
}
}
}
},
"libraries": {
"ScriptCore/1.0.0": {
"type": "project",
"serviceable": false,
"sha512": ""
},
"Half/1.0.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-EPLLPQA1UjF9QM3ymNhWLhgcnBNc8e1po4qWRWTD3Hd9xiohYlkCob0QjDIbJs6Nvfd4eAbsjxIwRyh7httyXA==",
"path": "half/1.0.0",
"hashPath": "half.1.0.0.nupkg.sha512"
},
"Microsoft.NETCore.Platforms/1.1.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==",
"path": "microsoft.netcore.platforms/1.1.0",
"hashPath": "microsoft.netcore.platforms.1.1.0.nupkg.sha512"
},
"NETStandard.Library/2.0.3": {
"type": "package",
"serviceable": true,
"sha512": "sha512-st47PosZSHrjECdjeIzZQbzivYBJFv6P2nv4cj2ypdI204DO+vZ7l5raGMiX4eXMJ53RfOIg+/s4DHVZ54Nu2A==",
"path": "netstandard.library/2.0.3",
"hashPath": "netstandard.library.2.0.3.nupkg.sha512"
}
}
}
@@ -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;
}
}
+87 -43
View File
@@ -33,7 +33,7 @@ class MaterialAssetPropertiesEditor : AssetPropertiesEditor
if (ImGui.BeginDragDropTarget()) if (ImGui.BeginDragDropTarget())
{ {
ImGui.Payload* payload = ImGui.AcceptDragDropPayload("CONTENT_BROWSER_ITEM"); ImGui.Payload* payload = ImGui.AcceptDragDropPayload(.ContentBrowserItem);
if (payload != null) if (payload != null)
{ {
@@ -78,7 +78,7 @@ class MaterialAssetPropertiesEditor : AssetPropertiesEditor
if (ImGui.BeginDragDropTarget()) if (ImGui.BeginDragDropTarget())
{ {
ImGui.Payload* payload = ImGui.AcceptDragDropPayload("CONTENT_BROWSER_ITEM"); ImGui.Payload* payload = ImGui.AcceptDragDropPayload(.ContentBrowserItem);
if (payload != null) if (payload != null)
{ {
@@ -99,7 +99,8 @@ class MaterialAssetPropertiesEditor : AssetPropertiesEditor
{ {
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);
@@ -107,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, ref *(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, ref *(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 (variable.Columns == 3)
if (ImGui.ColorEdit4(displayName.Ptr, *(float[4]*)&value))
{ {
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, ref *(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, ref *(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);
@@ -154,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);
} }
} }
@@ -198,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;
@@ -347,6 +390,7 @@ class MaterialAssetLoader : IAssetLoader, IAssetSaver //, IReloadingAssetLoader
for (let (slotName, textureIdentifier) in materialFile.Textures) for (let (slotName, textureIdentifier) in materialFile.Textures)
{ {
AssetHandle<Texture> texture = contentManager.LoadAsset(textureIdentifier); AssetHandle<Texture> texture = contentManager.LoadAsset(textureIdentifier);
if (texture.IsInvalid) if (texture.IsInvalid)
@@ -402,7 +446,7 @@ class MaterialAssetLoader : IAssetLoader, IAssetSaver //, IReloadingAssetLoader
for (let (slotName, texture) in material.[Friend]_textures) for (let (slotName, texture) in material.[Friend]_textures)
{ {
Texture textureAsset = texture.Get(); Texture textureAsset = texture.Handle.Get();
materialFile.Textures.Add(new String(slotName), new String(textureAsset?.Identifier ?? "")); materialFile.Textures.Add(new String(slotName), new String(textureAsset?.Identifier ?? ""));
} }
@@ -450,13 +494,13 @@ 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);
} }
} }
+238 -15
View File
@@ -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,6 +166,9 @@ class EditorTextureAssetLoaderConfig : AssetLoaderConfig
} }
} }
using internal GlitchyEngine.Renderer;
using internal GlitchyEngine.Platform.DX11;
class EditorTextureAssetLoader : IAssetLoader//, IReloadingAssetLoader 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,23 +235,80 @@ 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!();
Texture texture = null; List<LoadedSurface> surfaces = scope .();
LoadedTextureInfo textureInfo;
// 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:
Log.EngineLogger.Error("Unknown texture format."); Log.EngineLogger.Error("Unknown texture format.");
texture = null; return null;
} }
// Make the format SRGB or non-SRGB
if (config.IsSRGB)
textureInfo.PixelFormat = textureInfo.PixelFormat.GetSRGB();
else
textureInfo.PixelFormat = textureInfo.PixelFormat.GetNonSRGB();
Texture texture = CreateTexture(surfaces, textureInfo);
if (texture != null) if (texture != null)
{ {
SetSampler(texture, config); SetSampler(texture, config);
@@ -256,10 +318,88 @@ class EditorTextureAssetLoader : IAssetLoader//, IReloadingAssetLoader
return texture; return texture;
} }
private static Texture2D LoadPng(Stream data, EditorTextureAssetLoaderConfig config) private static Texture CreateTexture(List<LoadedSurface> surfaces, LoadedTextureInfo textureInfo)
{
TextureSliceData[] slices = scope TextureSliceData[surfaces.Count];
for (int i < slices.Count)
{
slices[i] = .(surfaces[i].Data.Ptr, surfaces[i].Pitch, surfaces[i].SlicePitch);
}
//slices[0].SlicePitch = (.)(surfaces[0].Pitch * textureInfo.Height);
switch (textureInfo.Dimension)
{
//case .Texture1D:
case .Texture2D:
if (textureInfo.IsCubeMap)
{
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 = .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();
}
return null;
}
private static Result<void> LoadPng(Stream data, EditorTextureAssetLoaderConfig config, List<LoadedSurface> surfaces, out LoadedTextureInfo textureInfo)
{ {
Debug.Profiler.ProfileResourceFunction!(); Debug.Profiler.ProfileResourceFunction!();
textureInfo = .();
uint8[] pngData = new:ScopedAlloc! uint8[data.Length]; uint8[] pngData = new:ScopedAlloc! uint8[data.Length];
var result = data.TryRead(pngData); var result = data.TryRead(pngData);
@@ -267,7 +407,7 @@ 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 null; return .Err;
} }
uint8* rawData = null; uint8* rawData = null;
@@ -285,25 +425,55 @@ class EditorTextureAssetLoader : IAssetLoader//, IReloadingAssetLoader
if (errorCode != 0) if (errorCode != 0)
{ {
Log.EngineLogger.Error($"Failed to decode PNG file {errorCode}."); Log.EngineLogger.Error($"Failed to decode PNG file {errorCode}.");
return null; return .Err;
} }
} }
Texture2DDesc desc = .(width, height, config.IsSRGB ? .R8G8B8A8_UNorm_SRGB : .R8G8B8A8_UNorm, 1, 1, .Immutable); uint8[] pixelData = new uint8[4 * width * height];
Texture2D texture = new Texture2D(desc); Internal.MemCpy(pixelData.Ptr, rawData, pixelData.Count);
texture.SetData<Color>((.)rawData);
LoadedSurface surface = .();
surface.Data = Span<uint8>(pixelData);
surface.Pitch = 4 * width;
surface.SlicePitch = 0;
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
return texture; textureInfo.PixelData = pixelData;
textureInfo.Width = width;
textureInfo.Height = height;
textureInfo.Depth = 1;
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 Texture LoadDds(Stream data, EditorTextureAssetLoaderConfig config) private static Result<void> LoadDds(Stream data, EditorTextureAssetLoaderConfig config, List<LoadedSurface> surfaces, out LoadedTextureInfo textureInfo)
{ {
// TODO: Move the loading of Dds files here. var result = DdsImporter.LoadDds(data, config.IsSRGB, surfaces, out textureInfo);
Texture2D texture = new [Friend]Texture2D(data);
return texture; if (result case .Err)
return .Err;
return .Ok;
} }
private static void SetSampler(Texture texture, EditorTextureAssetLoaderConfig config) private static void SetSampler(Texture texture, EditorTextureAssetLoaderConfig config)
@@ -315,12 +485,38 @@ class EditorTextureAssetLoader : IAssetLoader//, IReloadingAssetLoader
} }
private static Texture2D _placeholder2D; private static Texture2D _placeholder2D;
private static TextureCube _placeholderCube;
private static Texture2D _error2D; private static Texture2D _error2D;
private static TextureCube _errorCube;
public Asset GetPlaceholderAsset(Type assetType) public Asset GetPlaceholderAsset(Type assetType)
{ {
switch (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): case typeof(Texture2D):
fallthrough; fallthrough;
default: default:
@@ -347,6 +543,31 @@ class EditorTextureAssetLoader : IAssetLoader//, IReloadingAssetLoader
{ {
switch (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): case typeof(Texture2D):
fallthrough; fallthrough;
default: default:
@@ -356,7 +577,9 @@ class EditorTextureAssetLoader : IAssetLoader//, IReloadingAssetLoader
_error2D = new Texture2D(desc); _error2D = new Texture2D(desc);
_error2D.SamplerState = SamplerStateManager.PointWrap; _error2D.SamplerState = SamplerStateManager.PointWrap;
Color[4] color = .(Color.HotPink, Color.Black, Color.Black, Color.HotPink); Color[4] color = .(Color.HotPink, Color.Black, Color.Black, Color.HotPink);
_error2D.SetData<Color>(&color); _error2D.SetData<Color>(&color);
Content.ManageAsset(_error2D); Content.ManageAsset(_error2D);
@@ -0,0 +1,662 @@
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));
ImGui.Columns(2);
if (ImGui.BeginChild("Assets"))
{
DrawAssetList();
ImGui.EndChild();
}
ImGui.NextColumn();
if (ImGui.BeginChild("Files"))
{
DrawAssetViewer();
ImGui.EndChild();
}
ImGui.Columns(1);
/*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();
}*/
/*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", ref *(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,9 @@ using System.Collections;
using GlitchyEngine.Renderer; using GlitchyEngine.Renderer;
using GlitchyEngine; using GlitchyEngine;
using GlitchyEngine.Content; using GlitchyEngine.Content;
using GlitchyEngine.Scripting;
using GlitchyEngine.Core;
using Mono;
namespace GlitchyEditor.EditWindows namespace GlitchyEditor.EditWindows
{ {
@@ -68,6 +71,7 @@ namespace GlitchyEditor.EditWindows
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);
} }
@@ -158,16 +162,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);
Vector3 scale = transform.Scale; // if necessary reposition Rigidbody2D
if (ImGui.EditVector3("Scale", ref scale, .One, 0.1f, textWidth)) if (entity.TryGetComponent<Rigidbody2DComponent>(let rigidbody2D))
{
rigidbody2D.SetAngle(rotationEuler.Z);
}
}
float3 scale = transform.Scale;
if (ImGui.Editfloat3("Scale", ref scale, .One, 0.1f, textWidth))
transform.Scale = scale; transform.Scale = scale;
} }
@@ -260,7 +280,7 @@ namespace GlitchyEditor.EditWindows
if (ImGui.BeginDragDropTarget()) if (ImGui.BeginDragDropTarget())
{ {
ImGui.Payload* payload = ImGui.AcceptDragDropPayload("CONTENT_BROWSER_ITEM"); ImGui.Payload* payload = ImGui.AcceptDragDropPayload(.ContentBrowserItem);
if (payload != null) if (payload != null)
{ {
@@ -288,7 +308,7 @@ namespace GlitchyEditor.EditWindows
if (ImGui.BeginDragDropTarget()) if (ImGui.BeginDragDropTarget())
{ {
ImGui.Payload* payload = ImGui.AcceptDragDropPayload("CONTENT_BROWSER_ITEM"); ImGui.Payload* payload = ImGui.AcceptDragDropPayload(.ContentBrowserItem);
if (payload != null) if (payload != null)
{ {
@@ -320,7 +340,7 @@ namespace GlitchyEditor.EditWindows
if (ImGui.BeginDragDropTarget()) if (ImGui.BeginDragDropTarget())
{ {
ImGui.Payload* payload = ImGui.AcceptDragDropPayload("CONTENT_BROWSER_ITEM"); ImGui.Payload* payload = ImGui.AcceptDragDropPayload(.ContentBrowserItem);
if (payload != null) if (payload != null)
{ {
@@ -373,12 +393,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;
@@ -404,8 +424,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;
@@ -429,6 +449,561 @@ 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...";
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);
}
T GetData<T>(void* instance, ScriptField scriptField)
{
T data = default;
Mono.mono_field_get_value((.)instance, scriptField.[Friend]_monoField, &data);
return data;
}
void GetData<T>(void* instance, ScriptField scriptField, T* data)
{
Mono.mono_field_get_value((.)instance, scriptField.[Friend]_monoField, data);
}
void SetData<T>(void* instance, ScriptField scriptField, in T value)
{
Mono.mono_field_set_value((.)instance, scriptField.[Friend]_monoField, &value);
}
void SetData<T>(void* instance, ScriptField scriptField, T* data)
{
Mono.mono_field_set_value((.)instance, scriptField.[Friend]_monoField, data);
}
if (scriptComponent.Instance?.IsInitialized == true)
{
SharpClass sharpClass = scriptComponent.Instance.ScriptClass;
ScriptInstance scriptInstance = scriptComponent.Instance;
/*void DoFunnyStuff(void* instance, SharpType sharpType)
{
for (let (fieldName, scriptField) in sharpType.Fields)
{
var monoField = scriptField.[Friend]_monoField;
switch (scriptField.FieldType)
{
case .Float:
var value = GetData<float>(instance, scriptField);
if (ImGui.DragScalar(fieldName.ToScopeCStr!(), .Float, &value))
SetData(instance, scriptField, value);
case .Struct:
{
var v = Mono.mono_field_get_value_object(ScriptEngine.[Friend]s_AppDomain, scriptField.[Friend]_monoField, (.)instance);
void* dataPtr = Mono.mono_object_unbox(v);
Span<uint8> data = .((.)dataPtr, scriptField.SizeInBytes);
if (ImGui.CollapsingHeader(fieldName.Ptr))
{
DoFunnyStuff(dataPtr, scriptField.SharpType);
}
SetData<MonoObject>(instance, scriptField, v);
//Mono.mono_field_set_value_object(ScriptEngine.[Friend]s_AppDomain, scriptField.[Friend]_monoField, (.)instance);
//uint8* data = ;
/*uint8[] data = scope .[scriptField.SizeInBytes];
GetData(instance, scriptField, data.Ptr);
if (ImGui.CollapsingHeader(fieldName.Ptr))
{
DoFunnyStuff(data.Ptr, scriptField.SharpType);
}
MonoObject* boxed = Mono.mono_value_box(ScriptEngine.[Friend]s_AppDomain, ((SharpClass)scriptField.SharpType).[Friend]_monoClass, data.Ptr);
SetData<MonoObject>(instance, scriptField, boxed);*/
//Mono.mono_field_get_value(instance, scriptField.[Friend]_monoField, data.Ptr);
}
default:
//Log.EngineLogger.Error($"Unhandled field type {scriptField.FieldType}");
}
}
}
DoFunnyStuff(scriptInstance.[Friend]_instance, sharpClass);*/
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!
/*{
uint8[] data = scope .[scriptField.SizeInBytes];
Mono.mono_field_get_value(scriptInstance.[Friend]_instance, scriptField.[Friend]_monoField, data.Ptr);
//scriptField.
//scriptInstance.GetFieldValue();
//scriptInstance.ScriptClass.Fields[]
/*
var value = GetFieldValue<double>(scriptInstance, scriptField);
if (ImGui.DragScalar(fieldName.ToScopeCStr!(), .Double, &value))
SetFieldValue(scriptInstance, scriptField, value);
*/
}*/
default:
Log.EngineLogger.Error($"Unhandled field type {scriptField.FieldType}");
}
}
}
else if (scriptClass != null)
{
let scriptFields = ScriptEngine.GetScriptFieldMap(entity);
for (var (fieldName, field) in ref scriptFields)
{
switch (field.Type)
{
case .Bool:
var value = field.GetData<bool>();
if (ImGui.Checkbox(fieldName.CStr(), &value))
field.SetData(value);
case .SByte:
var value = field.GetData<int8>();
if (ImGui.DragScalar(fieldName.CStr(), .S8, &value))
field.SetData(value);
case .Short:
var value = field.GetData<int16>();
if (ImGui.DragScalar(fieldName.CStr(), .S16, &value))
field.SetData(value);
case .Int:
var value = field.GetData<int32>();
if (ImGui.DragScalar(fieldName.CStr(), .S32, &value))
field.SetData(value);
case .Int2:
var value = field.GetData<int2>();
if (ImGui.DragScalarN(fieldName.CStr(), .S32, &value, 2))
field.SetData(value);
case .Int3:
var value = field.GetData<int3>();
if (ImGui.DragScalarN(fieldName.CStr(), .S32, &value, 3))
field.SetData(value);
case .Int4:
var value = field.GetData<int4>();
if (ImGui.DragScalarN(fieldName.CStr(), .S32, &value, 4))
field.SetData(value);
case .Long:
var value = field.GetData<int64>();
if (ImGui.DragScalar(fieldName.CStr(), .S64, &value))
field.SetData(value);
case .Byte:
var value = field.GetData<uint8>();
if (ImGui.DragScalar(fieldName.CStr(), .U8, &value))
field.SetData(value);
case .UShort:
var value = field.GetData<uint16>();
if (ImGui.DragScalar(fieldName.CStr(), .U16, &value))
field.SetData(value);
case .UInt:
var value = field.GetData<uint32>();
if (ImGui.DragScalar(fieldName.CStr(), .U32, &value))
field.SetData(value);
case .ULong:
var value = field.GetData<uint64>();
if (ImGui.DragScalar(fieldName.CStr(), .U64, &value))
field.SetData(value);
case .Float:
var value = field.GetData<float>();
if (ImGui.DragScalar(fieldName.CStr(), .Float, &value))
field.SetData(value);
case .float2:
var value = field.GetData<float2>();
if (ImGui.Editfloat2(fieldName, ref value))
field.SetData(value);
case .float3:
var value = field.GetData<float3>();
if (ImGui.Editfloat3(fieldName, ref value))
field.SetData(value);
case .float4:
var value = field.GetData<float4>();
if (ImGui.Editfloat4(fieldName, ref value))
field.SetData(value);
case .Double:
var value = field.GetData<double>();
if (ImGui.DragScalar(fieldName.CStr(), .Double, &value))
field.SetData(value);
case .Double2:
var value = field.GetData<double2>();
if (ImGui.DragScalarN(fieldName.CStr(), .Double, &value, 2))
field.SetData(value);
case .Double3:
var value = field.GetData<double3>();
if (ImGui.DragScalarN(fieldName.CStr(), .Double, &value, 3))
field.SetData(value);
case .Double4:
var value = field.GetData<double4>();
if (ImGui.DragScalarN(fieldName.CStr(), .Double, &value, 4))
field.SetData(value);
case .Enum:
ShowEnumSelector(field, fieldName, scriptClass);
//case .String:
// TODO!
case .Entity:
ShowEntityReceiver(field, fieldName, scriptClass);
case .Component:
ShowComponentReceiver(field, fieldName, scriptClass);
case .Struct:
// TODO!
case .Class:
// We don't support editing classes
default:
Log.EngineLogger.Error($"Unhandled field type {field.Type}");
}
}
}
}
private static void ShowEnumSelector(ScriptFieldInstance* field, StringView fieldName, ScriptClass scriptClass)
{
ScriptField scriptField = scriptClass.Fields[fieldName];
SharpEnum enumType = scriptField.SharpType as SharpEnum;
Log.EngineLogger.Assert(enumType != null, "Enum must have a SharpEnum!");
// Simply get Enum as a uint64
var fieldValue = field.GetData<uint64>();
StringView valueName = "<Invalid Value>";
if (enumType.Values.TryGetValue(fieldValue, let enumValue))
valueName = enumValue.Name;
if (ImGui.BeginCombo(fieldName.Ptr, valueName.Ptr))
{
for (let (entryValue, enumEntry) in enumType.Values)
{
if (ImGui.Selectable(enumEntry.Name.Ptr, fieldValue == entryValue))
field.SetData(entryValue);
}
ImGui.EndCombo();
}
}
private static Entity? ShowEntitySelector()
{
static char8[128] entitySearch = .();
Entity? result = null;
if (ImGui.BeginPopup("ENTITY_SELECTOR"))
{
ImGui.TextUnformatted("Search:");
ImGui.SameLine();
if (ImGui.InputText("##entitySearcher", &entitySearch, (uint64)entitySearch.Count))
{
}
ImGui.EndPopup();
}
return result;
}
private static void ShowEntityReceiver(ScriptFieldInstance* field, StringView fieldName, ScriptClass scriptClass)
{
var entityId = field.GetData<UUID>();
Result<Entity> fieldEntity = Editor.Instance.CurrentScene.GetEntityByID(entityId);
String entityName = scope .(32);
if (entityId == UUID(0))
entityName.Set("None");
else if (fieldEntity case .Ok(Entity e))
entityName.Set(e.Name);
else
entityName..Clear().AppendF($"Missing entity ({entityId})");
ImGui.Text($"{fieldName}: ");
ImGui.SameLine();
if (ImGui.Button(entityName))
{
if (fieldEntity case .Ok)
Editor.Instance.EntityHierarchyWindow.HighlightEntity(fieldEntity);
}
if (ImGui.BeginDragDropTarget())
{
ImGui.Payload* peekPayload = ImGui.AcceptDragDropPayload(.Entity, .AcceptPeekOnly);
bool allowDrop = false;
if (peekPayload != null)
{
Entity draggedEntity = *(Entity*)peekPayload.Data;
ScriptClass draggedScriptClass = ScriptEngine.[Friend]s_EntityRoot;
if (draggedEntity.TryGetComponent<ScriptComponent>(let draggedScript))
{
var draggedClassName = draggedScript.ScriptClassName;
draggedScriptClass = ScriptEngine.GetScriptClass(draggedClassName);
}
// TODO: I don't like the fact, that we are using mono directly
ScriptField scriptField = scriptClass.Fields[fieldName];
var fieldMonoClass = Mono.mono_type_get_class(scriptField.GetMonoType());
allowDrop = draggedScriptClass.[Friend]IsSubclass(fieldMonoClass);
}
if (allowDrop)
{
ImGui.Payload* payload = ImGui.AcceptDragDropPayload(.Entity);
if (payload != null)
{
Log.EngineLogger.AssertDebug(payload.DataSize == sizeof(Entity));
Entity droppedEntity = *(Entity*)payload.Data;
if (droppedEntity.IsValid)
field.SetData<UUID>(droppedEntity.UUID);
}
}
ImGui.EndDragDropTarget();
}
}
//private static Entity?
private static void ShowComponentReceiver(ScriptFieldInstance* field, StringView fieldName, ScriptClass scriptClass)
{
var entityId = field.GetData<UUID>();
Result<Entity> fieldEntity = Editor.Instance.CurrentScene.GetEntityByID(entityId);
String entityName = scope .(32);
if (entityId == UUID(0))
entityName.Set("None");
else if (fieldEntity case .Ok(Entity e))
entityName.Set(e.Name);
else
entityName..Clear().AppendF($"Missing reference ({entityId})");
ImGui.Text($"{fieldName}: ");
ImGui.SameLine();
if (ImGui.Button(entityName))
{
if (fieldEntity case .Ok)
Editor.Instance.EntityHierarchyWindow.HighlightEntity(fieldEntity);
}
if (ImGui.BeginDragDropTarget())
{
ImGui.Payload* peekPayload = ImGui.AcceptDragDropPayload(.Entity, .AcceptPeekOnly);
bool allowDrop = false;
if (peekPayload != null)
{
Entity draggedEntity = *(Entity*)peekPayload.Data;
// TODO: I don't like the fact, that we are using mono directly
ScriptField scriptField = scriptClass.Fields[fieldName];
// For some reason we have to retrieve the MonoType like this. Using scriptField.GetMonoType() directly returns the wrong type...
MonoReflectionType* reflectionType = Mono.mono_type_get_object(ScriptEngine.[Friend]s_AppDomain, scriptField.GetMonoType());
MonoType* actualMonoType = Mono.mono_reflection_type_get_type(reflectionType);
// TODO: We shouldn't abuse the script glue like that.
// ScriptGlue should only be called by C#, not by Beef.
if (ScriptGlue.[Friend]s_HasComponentMethods.TryGetValue(actualMonoType, let has_component))
{
allowDrop = has_component(draggedEntity);
}
else
{
Log.EngineLogger.Warning($"No HasComponent-Function found for field {scriptField.Name}");
allowDrop = false;
}
}
if (allowDrop)
{
ImGui.Payload* payload = ImGui.AcceptDragDropPayload(.Entity);
if (payload != null)
{
Log.EngineLogger.AssertDebug(payload.DataSize == sizeof(Entity));
Entity droppedEntity = *(Entity*)payload.Data;
if (droppedEntity.IsValid)
field.SetData<UUID>(droppedEntity.UUID);
}
}
ImGui.EndDragDropTarget();
}
}
private static void LabelColumn(StringView label) private static void LabelColumn(StringView label)
{ {
ImGui.TextUnformatted(label); ImGui.TextUnformatted(label);
@@ -493,7 +1068,7 @@ namespace GlitchyEditor.EditWindows
if (ImGui.BeginDragDropTarget()) if (ImGui.BeginDragDropTarget())
{ {
ImGui.Payload* payload = ImGui.AcceptDragDropPayload("CONTENT_BROWSER_ITEM"); ImGui.Payload* payload = ImGui.AcceptDragDropPayload(.ContentBrowserItem);
if (payload != null) if (payload != null)
{ {
@@ -584,6 +1159,7 @@ namespace GlitchyEditor.EditWindows
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();
} }
@@ -48,34 +48,70 @@ namespace GlitchyEditor.EditWindows
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);
ImGui.BeginChild("Sidebar");
DrawDirectorySideBar();
ImGui.EndChild();
ImGui.NextColumn();
ImGui.BeginChild("Files");
DrawCurrentDirectory();
ImGui.EndChild();
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()
{ {
@@ -132,50 +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();
}
} }
if (currentDirectoryNode->Parent != null) for (var entry in files)
{ {
ImGui.PushID("Back"); if (!entry->Name.Contains(searchFilter, true))
continue;
DrawBackButton(currentDirectoryNode->Parent);
// X-Coordinate of the right side of the current entry.
float currentButtonRight = ImGui.GetItemRectMax().x;
// Expected right-Coordinate if next entry was on the same line.
float expectedButtonRight = currentButtonRight + style.ItemSpacing.x + DirectoryItemSize.X;
// If the next button won't fit on the same line we start a new line.
if (expectedButtonRight < window_visible_x2)
ImGui.SameLine();
ImGui.PopID();
}
for (var entry in currentDirectoryNode->Children)
{
ImGui.PushID(entry->Name); ImGui.PushID(entry->Name);
DrawDirectoryItem(entry); DrawDirectoryItem(entry);
@@ -186,7 +246,7 @@ 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();
@@ -210,7 +270,7 @@ namespace GlitchyEditor.EditWindows
SubTexture2D image = s_FolderTexture; SubTexture2D image = s_FolderTexture;
ImGui.ImageButton(image, (.)(DirectoryItemSize - padding)); ImGui.ImageButton("", image, (.)(DirectoryItemSize - padding));
ImGui.PopStyleColor(); ImGui.PopStyleColor();
@@ -250,7 +310,7 @@ namespace GlitchyEditor.EditWindows
// TODO: preview images // TODO: preview images
SubTexture2D image = entry->IsDirectory ? s_FolderTexture : s_FileTexture; SubTexture2D image = entry->IsDirectory ? s_FolderTexture : s_FileTexture;
ImGui.ImageButton(image, (.)(DirectoryItemSize - padding)); ImGui.ImageButton("FileImage", image, (.)(DirectoryItemSize - padding));
ImGui.PopStyleColor(); ImGui.PopStyleColor();
@@ -264,7 +324,7 @@ namespace GlitchyEditor.EditWindows
Path.Fixup(fullpath); Path.Fixup(fullpath);
ImGui.SetDragDropPayload("CONTENT_BROWSER_ITEM", fullpath.CStr(), (.)fullpath.Length, .Once); ImGui.SetDragDropPayload(.ContentBrowserItem, fullpath.CStr(), (.)fullpath.Length, .Once);
ImGui.EndDragDropSource(); ImGui.EndDragDropSource();
} }
@@ -310,7 +370,7 @@ namespace GlitchyEditor.EditWindows
String fullpath = scope String(entry->Path); String fullpath = scope String(entry->Path);
fullpath.AppendF($"#{subAsset.Name}"); fullpath.AppendF($"#{subAsset.Name}");
ImGui.SetDragDropPayload("CONTENT_BROWSER_ITEM", fullpath.CStr(), (.)fullpath.Length, .Once); ImGui.SetDragDropPayload(.ContentBrowserItem, fullpath.CStr(), (.)fullpath.Length, .Once);
ImGui.EndDragDropSource(); ImGui.EndDragDropSource();
} }
@@ -32,9 +32,9 @@ namespace GlitchyEditor.EditWindows
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();
@@ -126,7 +126,7 @@ namespace GlitchyEditor.EditWindows
if(_oldViewportSize != viewportSize) if(_oldViewportSize != viewportSize)
{ {
ViewportSizeChanged.Invoke(this, (Vector2)viewportSize); ViewportSizeChanged.Invoke(this, (float2)viewportSize);
_viewPortChanged = true; _viewPortChanged = true;
_oldViewportSize = viewportSize; _oldViewportSize = viewportSize;
} }
@@ -137,7 +137,7 @@ namespace GlitchyEditor.EditWindows
{ {
if (ImGui.BeginDragDropTarget()) if (ImGui.BeginDragDropTarget())
{ {
ImGui.Payload* payload = ImGui.AcceptDragDropPayload("CONTENT_BROWSER_ITEM"); ImGui.Payload* payload = ImGui.AcceptDragDropPayload(.ContentBrowserItem);
if (payload != null) if (payload != null)
{ {
@@ -154,14 +154,14 @@ 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();
ImGui.DrawRect((.)regionMin, (.)regionMax, .(0, 255, 0)); ImGui.DrawRect((.)regionMin, (.)regionMax, .(0, 255, 0));
Vector2 newMousePos = mousePos; float2 newMousePos = mousePos;
if (mousePos.X < regionMin.X + 1) if (mousePos.X < regionMin.X + 1)
{ {
@@ -181,9 +181,9 @@ namespace GlitchyEditor.EditWindows
newMousePos.Y = regionMin.Y + 10; 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
@@ -195,7 +195,7 @@ 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.EditorSceneRenderer.CompositeTarget.Width; int rtWidth = _editor.EditorSceneRenderer.CompositeTarget.Width;
int rtHeight = _editor.EditorSceneRenderer.CompositeTarget.Height; int rtHeight = _editor.EditorSceneRenderer.CompositeTarget.Height;
@@ -316,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))
{ {
@@ -21,8 +21,26 @@ namespace GlitchyEditor.EditWindows
private List<Entity> _selectedEntities = new .() ~ delete _; private List<Entity> _selectedEntities = new .() ~ delete _;
private Entity _entityToHighlight;
public List<Entity> SelectedEntities => _selectedEntities; public List<Entity> SelectedEntities => _selectedEntities;
private List<Entity> _entitiesToUnfold = new .() ~ delete _;
public void HighlightEntity(Entity e)
{
_entityToHighlight = e;
Entity walker = _entityToHighlight;
while (walker.Parent != null)
{
walker = walker.Parent.Value;
_entitiesToUnfold.Add(walker);
}
}
public this(Editor editor, Scene scene) public this(Editor editor, Scene scene)
{ {
_editor = editor; _editor = editor;
@@ -322,8 +340,21 @@ namespace GlitchyEditor.EditWindows
if(inSelectedList) if(inSelectedList)
flags |= .Selected; flags |= .Selected;
if (_entitiesToUnfold.Contains(tree.Value))
{
_entitiesToUnfold.Remove(tree.Value);
ImGui.SetNextItemOpen(true, .None);
}
bool isOpen = ImGui.TreeNodeEx((void*)(uint)tree.Value.Handle.[Friend]Index, flags, $"{name}"); bool isOpen = ImGui.TreeNodeEx((void*)(uint)tree.Value.Handle.[Friend]Index, flags, $"{name}");
if (_entityToHighlight == tree.Value)
{
ImGui.SetScrollHereY(0);
_entityToHighlight = .();
}
ImGui.PushID((void*)(uint)tree.Value.Handle.[Friend]Index); ImGui.PushID((void*)(uint)tree.Value.Handle.[Friend]Index);
bool deleted = false; bool deleted = false;
@@ -341,9 +372,13 @@ namespace GlitchyEditor.EditWindows
if (deleted) if (deleted)
return; return;
bool isDragged = false;
if(ImGui.BeginDragDropSource()) if(ImGui.BeginDragDropSource())
{ {
ImGui.SetDragDropPayload("DND_Entity", &tree.Value, sizeof(Entity)); isDragged = true;
ImGui.SetDragDropPayload(.Entity, &tree.Value, sizeof(Entity));
ImGui.Text(name); ImGui.Text(name);
@@ -352,7 +387,7 @@ namespace GlitchyEditor.EditWindows
if(ImGui.BeginDragDropTarget()) if(ImGui.BeginDragDropTarget())
{ {
ImGui.Payload* payload = ImGui.AcceptDragDropPayload("DND_Entity"); ImGui.Payload* payload = ImGui.AcceptDragDropPayload(.Entity);
if(payload != null) if(payload != null)
{ {
@@ -407,6 +442,12 @@ namespace GlitchyEditor.EditWindows
} }
if (clicked || clickedRight) if (clicked || clickedRight)
{
lastClickedEntity = tree.Value;
}
//if (!isDragged && (clicked || clickedRight))
if (!isDragged && (!ImGui.IsMouseDown(.Left) && !ImGui.IsMouseDown(.Right) && ImGui.IsItemHovered()) && tree.Value == lastClickedEntity)
{ {
if (inSelectedList && !clickedRight) if (inSelectedList && !clickedRight)
{ {
@@ -418,9 +459,13 @@ namespace GlitchyEditor.EditWindows
SelectEntity(tree.Value, !ImGui.GetIO().KeyCtrl && !clickedRight); SelectEntity(tree.Value, !ImGui.GetIO().KeyCtrl && !clickedRight);
inSelectedList = true; inSelectedList = true;
} }
lastClickedEntity = .();
} }
} }
private static Entity lastClickedEntity;
private void ShowEntityHierarchy() private void ShowEntityHierarchy()
{ {
StringView searchString = StringView(&_entitySearchChars); StringView searchString = StringView(&_entitySearchChars);
@@ -464,7 +509,7 @@ namespace GlitchyEditor.EditWindows
{ {
if(ImGui.BeginDragDropTarget()) if(ImGui.BeginDragDropTarget())
{ {
ImGui.Payload* payload = ImGui.AcceptDragDropPayload("DND_Entity"); ImGui.Payload* payload = ImGui.AcceptDragDropPayload(.Entity);
if(payload != null) if(payload != null)
{ {
@@ -527,6 +572,10 @@ namespace GlitchyEditor.EditWindows
ImGuiPrintEntityTree(scope .(entity)); ImGuiPrintEntityTree(scope .(entity));
} }
} }
// If the mouse was released and no entity took the chance to become selected we probably hovered the background while releasing -> select no entity
if (!ImGui.IsMouseDown(.Left) && !ImGui.IsMouseDown(.Right))
lastClickedEntity = .();
} }
} }
} }
@@ -20,9 +20,9 @@ namespace GlitchyEditor.EditWindows
private RenderTargetGroup _renderTarget ~ _?.ReleaseRef(); private RenderTargetGroup _renderTarget ~ _?.ReleaseRef();
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();
@@ -80,7 +80,7 @@ namespace GlitchyEditor.EditWindows
if(_oldViewportSize != viewportSize) if(_oldViewportSize != viewportSize)
{ {
ViewportSizeChanged.Invoke(this, (Vector2)viewportSize); ViewportSizeChanged.Invoke(this, (float2)viewportSize);
_viewPortChanged = true; _viewPortChanged = true;
_oldViewportSize = viewportSize; _oldViewportSize = viewportSize;
} }
@@ -91,7 +91,7 @@ namespace GlitchyEditor.EditWindows
{ {
if (ImGui.BeginDragDropTarget()) if (ImGui.BeginDragDropTarget())
{ {
ImGui.Payload* payload = ImGui.AcceptDragDropPayload("CONTENT_BROWSER_ITEM"); ImGui.Payload* payload = ImGui.AcceptDragDropPayload(.ContentBrowserItem);
if (payload != null) if (payload != null)
{ {
+375
View File
@@ -0,0 +1,375 @@
using System;
using ImGui;
using System.Collections;
using GlitchyEngine.Core;
using GlitchyEngine.World;
using GlitchLog;
using GlitchyEngine.Scripting;
using GlitchyEngine.Renderer;
namespace GlitchyEditor.EditWindows;
enum MessageType
{
case None = 0;
case Trace = 1;
case Info = 2;
case Warning = 4;
case Error = 8;
public this(LogLevel level)
{
switch (level)
{
case .Error:
this = Error;
case .Warning:
this = Warning;
case .Info:
this = Info;
case .Trace:
this = Trace;
default:
this = None;
}
}
}
class MessageSource
{
public UUID? Entity = null;
public StringView? ScriptName = null;
public int? Line = null;
/// If true, the message is only meant for engine developers... so only me :(
public bool IsEngineMessage = false;
public MonoExceptionHelper Exception = null ~ _?.ReleaseRef();
public String AdditionalData = null ~ delete _;
}
class LogMessage
{
private String _message ~ delete _;
public MessageType MessageType { get; private set; }
public DateTime Timestamp { get; private set; }
public MessageSource Source { get; private set; } ~ delete _;
public StringView Message => _message;
public this(DateTime timestamp, StringView message, MessageType logLevel, MessageSource ownSource)
{
Timestamp = timestamp;
_message = new String(message);
MessageType = logLevel;
Source = ownSource;
}
}
class LogWindow : EditorWindow
{
public const String s_WindowTitle = "Log";
private append List<LogMessage> _messages = .() ~ ClearAndDeleteItems!(_);
public static SubTexture2D s_ErrorIcon;
public static SubTexture2D s_WarningIcon;
public static SubTexture2D s_InfoIcon;
public static SubTexture2D s_TraceIcon;
private bool _showGameMessages = true;
private bool _showEngineMessages = false;
private bool _autoScroll = true;
private bool _collapseMessages = true;
private MessageType _visibleMessageTypes = .Error | .Warning | .Info | .Trace;
protected override void InternalShow()
{
defer { ImGui.End(); }
if(!ImGui.Begin(s_WindowTitle, &_open, .MenuBar))
return;
ShowMenuBar();
ShowMessages();
}
private void ShowMenuBar()
{
if(ImGui.BeginMenuBar())
{
if (ImGui.MenuItem("Clear"))
{
ClearLog();
}
if (ImGui.BeginMenu("Filter"))
{
ImGui.Checkbox("Show game messages", &_showGameMessages);
ImGui.AttachTooltip("If checked, the log will show messages generated by the game (e.g. scripts).");
ImGui.Checkbox("Show engine messages", &_showEngineMessages);
ImGui.AttachTooltip("""
If checked, the log will show messages generated by the engine.
These messages are usually only necessary for engine debugging/development and don't provide practical information for game developers.
""");
ImGui.EndMenu();
}
ImGui.Checkbox("Collapse", &_collapseMessages);
ImGui.AttachTooltip("If checked, identical messages will be collapsed into one.");
var maxSpace = ImGui.GetFontSize();
ImGui.Vec2 buttonSize = .(maxSpace, maxSpace);
var col = ImGui.GetStyleColorVec4(.Button);
ImGui.PushStyleVar(.FramePadding, ImGui.Vec2(2, 2));
if (_visibleMessageTypes.HasFlag(.Trace))
ImGui.PushStyleColor(.Button, *col);
else
ImGui.PushStyleColor(.Button, .(0, 0, 0, 0));
if (ImGui.ImageButtonEx(1, s_TraceIcon, buttonSize, .Zero, .Ones))
_visibleMessageTypes ^= .Trace;
ImGui.PopStyleColor();
if (_visibleMessageTypes.HasFlag(.Info))
ImGui.PushStyleColor(.Button, *col);
else
ImGui.PushStyleColor(.Button, .(0, 0, 0, 0));
if (ImGui.ImageButtonEx(2, s_InfoIcon, buttonSize, .Zero, .Ones))
_visibleMessageTypes ^= .Info;
ImGui.PopStyleColor();
if (_visibleMessageTypes.HasFlag(.Warning))
ImGui.PushStyleColor(.Button, *col);
else
ImGui.PushStyleColor(.Button, .(0, 0, 0, 0));
if (ImGui.ImageButtonEx(3, s_WarningIcon, buttonSize, .Zero, .Ones))
_visibleMessageTypes ^= .Warning;
ImGui.PopStyleColor();
if (_visibleMessageTypes.HasFlag(.Error))
ImGui.PushStyleColor(.Button, *col);
else
ImGui.PushStyleColor(.Button, .(0, 0, 0, 0));
if (ImGui.ImageButtonEx(4, s_ErrorIcon, buttonSize, .Zero, .Ones))
_visibleMessageTypes ^= .Error;
ImGui.PopStyleColor();
ImGui.PopStyleVar();
ImGui.EndMenuBar();
}
}
private void ShowMessages()
{
if (ImGui.BeginTable("Messages", 3, .BordersInnerH | .SizingFixedFit))
{
ImGui.TableSetupColumn("", .WidthFixed);
ImGui.TableSetupColumn("", .WidthStretch);
ImGui.TableSetupColumn("", .WidthFixed);
//LogMessage lastMessage = null;
int count = 1;
// Message ID for ImGui
int imGuiMessageId = 0;
for (let message in _messages)
{
if (!_visibleMessageTypes.HasFlag(message.MessageType))
continue;
if ((message.Source.IsEngineMessage && !_showEngineMessages) || (!message.Source.IsEngineMessage && !_showGameMessages))
continue;
/*defer
{
lastMessage = message;
}*/
do
{
LogMessage lastMessage = (message != _messages.Back) ? _messages[@message.Index + 1] : null;
if (_collapseMessages && lastMessage != null)
{
if (message.MessageType != lastMessage.MessageType)
break;
if (message.Message != lastMessage.Message)
break;
if (message.Source.Entity != lastMessage.Source.Entity)
break;
// For exceptions the stack trace is basically the only relevant thing
if (message.Source.Exception?.StackTrace != lastMessage.Source.Exception?.StackTrace)
break;
// We collapse this message with the previous one:
// Increment counter and go to next message.
count++;
continue;
}
}
// Push current index as ID
ImGui.PushID((void*)++imGuiMessageId);
ImGui.TableNextRow();
ImGui.TableSetColumnIndex(0);
switch (message.MessageType)
{
case .Error:
ImGui.Image(s_ErrorIcon, ImGui.Vec2(32, 32));
ImGui.AttachTooltip("Error");
case .Warning:
ImGui.Image(s_WarningIcon, ImGui.Vec2(32, 32));
ImGui.AttachTooltip("Warning");
case .Info:
ImGui.Image(s_InfoIcon, ImGui.Vec2(32, 32));
ImGui.AttachTooltip("Info");
case .Trace:
ImGui.Image(s_TraceIcon, ImGui.Vec2(32, 32));
ImGui.AttachTooltip("Trace");
default:
ImGui.TextUnformatted("Unknown");
}
ImGui.TableNextColumn();
// Timestamp
ImGui.TextWrapped($"[{message.Timestamp:HH:mm:ss.fff}]");
if (message.Source.IsEngineMessage)
{
ImGui.SameLine();
ImGui.TextUnformatted("Engine");
}
// Show entity
if (message.Source?.Entity != null)
{
ImGui.SameLine();
Result<Entity> entity = Editor.Instance.CurrentScene.GetEntityByID(message.Source.Entity.Value);
if (entity case .Ok(let e))
{
ImGui.Text($"Entity: \"{e.Name}\" (ID: {message.Source.Entity})");
if (ImGui.IsItemClicked())
Editor.Instance.EntityHierarchyWindow.HighlightEntity(entity);
}
else
{
ImGui.Text($"Entity: (ID: {message.Source.Entity})");
}
}
if (message.Source.Exception != null)
{
if (ImGui.CollapsingHeader(message.Message.Ptr))
{
// Show the native to managed entry point only if we show engine messages
if (_showEngineMessages)
ImGui.TextUnformatted(message.Source.Exception.StackTrace);
else
ImGui.TextUnformatted(message.Source.Exception.CleanStackTrace);
ImGui.NewLine();
}
}
else
{
ImGui.TextUnformatted(message.Message);
}
// Dont show the counter if we only have one message.
if (count > 1)
{
// the message is not collapsible with the previous one.
// Print message count for last message and reset counter.
// This message will be printed normally.
ImGui.TableNextColumn();
ImGui.Text($"{count}");
}
count = 1;
ImGui.PopID();
}
if (_autoScroll)
{
if (ImGui.GetIO().MouseWheel > 0)
{
_autoScroll = false;
}
else
{
ImGui.SetScrollY(ImGui.GetScrollMaxY());
}
}
else
{
if (ImGui.GetScrollMaxY() == ImGui.GetScrollY())
{
_autoScroll = true;
}
}
ImGui.EndTable();
}
}
public void ClearLog()
{
ClearAndDeleteItems!(_messages);
}
public void Log(DateTime timestamp, LogLevel severity, StringView message, MessageSource source)
{
LogMessage logMessage = new LogMessage(timestamp, message, MessageType(severity), source);
_messages.Add(logMessage);
}
public void LogException(DateTime timestamp, MonoExceptionHelper exception)
{
StringView firstLine = exception.StackTrace;
int firstInIndex = exception.StackTrace.IndexOf("\n");
if (firstInIndex != -1)
firstLine = firstLine.Substring(0, firstInIndex);
String message = scope .(128);
message.AppendF($"Exception: \"{exception.FullName}\" | Message: \"{exception.Message}\" {firstLine}\0");
// TODO: are mono exceptions never engine only?
LogMessage logMessage = new LogMessage(timestamp, message, .Error, new MessageSource(){Entity = exception.Instance, Exception = exception..AddRef(), IsEngineMessage = false});
_messages.Add(logMessage);
}
}
+20
View File
@@ -21,6 +21,8 @@ namespace GlitchyEditor
private GameViewportWindow _gameViewportWindow ~ 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 _;
private LogWindow _logWindow ~ delete _;
public Scene CurrentScene public Scene CurrentScene
{ {
@@ -43,6 +45,8 @@ namespace GlitchyEditor
public GameViewportWindow GameViewportWindow => _gameViewportWindow; 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 LogWindow LogWindow => _logWindow;
public EditorCamera* CurrentCamera { get; set; } public EditorCamera* CurrentCamera { get; set; }
@@ -51,15 +55,27 @@ namespace GlitchyEditor
public SceneRenderer GameSceneRenderer {get; set;} public SceneRenderer GameSceneRenderer {get; set;}
public SceneRenderer EditorSceneRenderer {get; set;} public SceneRenderer EditorSceneRenderer {get; set;}
private static Editor s_Instance;
public static Editor Instance => s_Instance;
/// 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)
{ {
Log.EngineLogger.AssertDebug(s_Instance == null, "Cannot create a second instance of a singleton.");
s_Instance = this;
_scene = scene; _scene = scene;
_contentManager = contentManager; _contentManager = contentManager;
InitWindows(); InitWindows();
} }
public ~this()
{
s_Instance = null;
}
private void InitWindows() private void InitWindows()
{ {
_sceneViewportWindow = new EditorViewportWindow(this); _sceneViewportWindow = new EditorViewportWindow(this);
@@ -68,6 +84,8 @@ namespace GlitchyEditor
_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);
_logWindow = new LogWindow();
} }
public void Update() public void Update()
@@ -78,6 +96,8 @@ namespace GlitchyEditor
_componentEditWindow.Show(); _componentEditWindow.Show();
_contentBrowserWindow.Show(); _contentBrowserWindow.Show();
_propertiesWindow.Show(); _propertiesWindow.Show();
_assetViewer.Show();
_logWindow.Show();
} }
} }
} }
+7 -4
View File
@@ -9,9 +9,12 @@ namespace GlitchyEditor
{ {
EditorContentManager _contentManager; EditorContentManager _contentManager;
public this() public this(String[] args)
{ {
PushLayer(new EditorLayer(_contentManager)); PushLayer(new EditorLayer(args, _contentManager));
Log.ClientLogger = new EditorLogger();
Log.EngineLogger = new EditorLogger() { IsEngineLogger = true };
} }
protected override IContentManager InitContentManager() protected override IContentManager InitContentManager()
@@ -39,9 +42,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);
} }
} }
} }
+13 -3
View File
@@ -18,6 +18,11 @@ namespace GlitchyEditor
public SubTexture2D Stop ~ _.ReleaseRef(); public SubTexture2D Stop ~ _.ReleaseRef();
public SubTexture2D Simulate ~ _.ReleaseRef(); public SubTexture2D Simulate ~ _.ReleaseRef();
public SubTexture2D Pause ~ _.ReleaseRef(); public SubTexture2D Pause ~ _.ReleaseRef();
public SubTexture2D SingleStep ~ _.ReleaseRef();
public SubTexture2D Error ~ _.ReleaseRef();
public SubTexture2D Warning ~ _.ReleaseRef();
public SubTexture2D Info ~ _.ReleaseRef();
public SubTexture2D Trace ~ _.ReleaseRef();
public SamplerState SamplerState public SamplerState SamplerState
{ {
@@ -25,11 +30,11 @@ namespace GlitchyEditor
set => _texture.Get().SamplerState = value; set => _texture.Get().SamplerState = value;
} }
public this(String texturePath, Vector2 iconSize) public this(String texturePath, float2 iconSize)
{ {
_texture = Content.LoadAsset(texturePath, null, true); _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);
@@ -39,9 +44,14 @@ namespace GlitchyEditor
Stop = GetNextGridTexture(ref pen, iconSize); Stop = GetNextGridTexture(ref pen, iconSize);
Simulate = GetNextGridTexture(ref pen, iconSize); Simulate = GetNextGridTexture(ref pen, iconSize);
Pause = GetNextGridTexture(ref pen, iconSize); Pause = GetNextGridTexture(ref pen, iconSize);
SingleStep = GetNextGridTexture(ref pen, iconSize);
Error = GetNextGridTexture(ref pen, iconSize);
Warning = GetNextGridTexture(ref pen, iconSize);
Info = GetNextGridTexture(ref pen, iconSize);
Trace = 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);
+246 -102
View File
@@ -13,6 +13,7 @@ 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
{ {
@@ -69,6 +70,19 @@ namespace GlitchyEditor
SceneState _sceneState = .Edit; SceneState _sceneState = .Edit;
bool _isPaused = false; 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. /// Gets or sets the path of the current scene.
public StringView SceneFilePath public StringView SceneFilePath
@@ -83,26 +97,29 @@ namespace GlitchyEditor
} }
} }
public this(EditorContentManager contentManager) : base("Editor") [AllowAppend]
public this(String[] args, EditorContentManager contentManager) : base("Editor")
{ {
Application.Get().Window.IsVSync = false; Application.Get().Window.IsVSync = true;
_contentManager = contentManager; _contentManager = contentManager;
InitGraphics(); InitGraphics();
_editorScene = new Scene();
SetReference!(_activeScene, _editorScene);
_gameSceneRenderer = new SceneRenderer(); _gameSceneRenderer = new SceneRenderer();
_editorSceneRenderer = 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 InitGraphics() private void InitGraphics()
@@ -154,6 +171,11 @@ namespace GlitchyEditor
ContentBrowserWindow.s_FolderTexture = _editorIcons.Folder; ContentBrowserWindow.s_FolderTexture = _editorIcons.Folder;
ContentBrowserWindow.s_FileTexture = _editorIcons.File; ContentBrowserWindow.s_FileTexture = _editorIcons.File;
LogWindow.s_ErrorIcon = _editorIcons.Error;
LogWindow.s_WarningIcon = _editorIcons.Warning;
LogWindow.s_InfoIcon = _editorIcons.Info;
LogWindow.s_TraceIcon = _editorIcons.Trace;
} }
private void InitEditor() private void InitEditor()
@@ -188,11 +210,37 @@ namespace GlitchyEditor
updateMode = .Physics; updateMode = .Physics;
} }
if (_sceneState != .Edit && _isPaused) if (_sceneState != .Edit && _isPaused && !_singleStep)
updateMode = .None; 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;
_activeScene.Update(gameTime, updateMode); 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);
@@ -200,27 +248,36 @@ namespace GlitchyEditor
RenderCommand.SetBlendState(_alphaBlendState); RenderCommand.SetBlendState(_alphaBlendState);
RenderCommand.SetDepthStencilState(_depthStencilState); RenderCommand.SetDepthStencilState(_depthStencilState);
if (_editor.GameViewportWindow.Visible)
{
_gameSceneRenderer.Scene = _activeScene;
_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) if (_editor.SceneViewportWindow.Visible)
{ {
_camera.Update(gameTime); _camera.Update(gameTime);
_editorSceneRenderer.Scene = _activeScene; _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); RenderCommand.Clear(_editorViewportTarget, .Color | .Depth, .(0.2f, 0.2f, 0.2f), 1.0f, 0);
_editorSceneRenderer.RenderEditor(gameTime, _camera, _editorViewportTarget, scope => DebugDraw3D, scope => DebugDraw2D); _editorSceneRenderer.RenderEditor(gameTime, _camera, _editorViewportTarget, scope => DebugDraw3D, scope => DebugDraw2D);
} }
RenderCommand.SetBlendState(_alphaBlendState);
RenderCommand.SetDepthStencilState(_depthStencilState);
if (_editor.GameViewportWindow.Visible)
{
_gameSceneRenderer.Scene = _activeScene;
RenderCommand.Clear(_gameViewportTarget, .Color | .Depth, .(0.2f, 0.2f, 0.2f), 1.0f, 0);
_gameSceneRenderer.RenderRuntime(gameTime, _gameViewportTarget);
}
RenderCommand.UnbindRenderTargets(); RenderCommand.UnbindRenderTargets();
RenderCommand.SetRenderTarget(null, 0, true); RenderCommand.SetRenderTarget(null, 0, true);
RenderCommand.BindRenderTargets(); RenderCommand.BindRenderTargets();
@@ -248,14 +305,14 @@ 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 _activeScene.GetEntities<TransformComponent, CameraComponent>()) for (var (entity, transform, camera) in _activeScene.GetEntities<TransformComponent, CameraComponent>())
@@ -280,7 +337,7 @@ namespace GlitchyEditor
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);
} }
@@ -313,16 +370,8 @@ namespace GlitchyEditor
dispatcher.Dispatch<MouseScrolledEvent>(scope (e) => OnMouseScrolled(e)); dispatcher.Dispatch<MouseScrolledEvent>(scope (e) => OnMouseScrolled(e));
} }
ImGui.ID _mainDockspaceId;
TextureViewer viewer = new TextureViewer() ~ delete _;
private bool OnImGuiRender(ImGuiRenderEvent event) private bool OnImGuiRender(ImGuiRenderEvent event)
{ {
Input.ImGuiDebugDraw();
//viewer.ViewTexture(Renderer.[Friend]_gBuffer.Target);
ImGui.Viewport* viewport = ImGui.GetMainViewport(); ImGui.Viewport* viewport = ImGui.GetMainViewport();
ImGui.DockSpaceOverViewport(viewport); ImGui.DockSpaceOverViewport(viewport);
@@ -365,7 +414,6 @@ namespace GlitchyEditor
float centerX = ImGui.GetContentRegionMax().x / 2; float centerX = ImGui.GetContentRegionMax().x / 2;
if (_sceneState == .Edit) if (_sceneState == .Edit)
EditorButtons: EditorButtons:
{ {
@@ -376,16 +424,20 @@ namespace GlitchyEditor
ImGui.SameLine(); ImGui.SameLine();
ImGui.SetCursorPosX(centerX - totalWidth / 2); ImGui.SetCursorPosX(centerX - totalWidth / 2);
if (ImGui.ImageButton(_editorIcons.Play, .(size, size), .Zero, .Ones, 0)) ImGui.PushID(0);
if (ImGui.ImageButton("", _editorIcons.Play, .(size, size), .Zero, .Ones))
OnScenePlay(); OnScenePlay();
ImGui.PopID();
ImGui.AttachTooltip("Play the game."); ImGui.AttachTooltip("Play the game.");
ImGui.SameLine(); ImGui.SameLine();
ImGui.PushID(1); ImGui.PushID(1);
if (ImGui.ImageButton(_editorIcons.Simulate, .(size, size), .Zero, .Ones, 0)) if (ImGui.ImageButton("", _editorIcons.Simulate, .(size, size), .Zero, .Ones))
OnSceneSimulate(); OnSceneSimulate();
ImGui.PopID(); ImGui.PopID();
@@ -404,7 +456,7 @@ namespace GlitchyEditor
//ImGui.SameLine(penX += size + 2 * padding); //ImGui.SameLine(penX += size + 2 * padding);
ImGui.SameLine(); ImGui.SameLine();
if (ImGui.ImageButton(_editorIcons.Pause, .(size, size), .Zero, .Ones, 0)) if (ImGui.ImageButton("", _editorIcons.Pause, .(size, size), .Zero, .Ones))
_isPaused = !_isPaused; _isPaused = !_isPaused;
ImGui.PopID(); ImGui.PopID();
@@ -414,14 +466,21 @@ namespace GlitchyEditor
} }
else else
{ {
float totalWidth = size * 2 + padding * 2;
if (_isPaused)
{
totalWidth = size * 3 + padding * 4;
}
// Display the buttons for play/simulation state // Display the buttons for play/simulation state
ImGui.SameLine(); ImGui.SameLine();
ImGui.SetCursorPosX(centerX - size - padding); ImGui.SetCursorPosX(centerX - totalWidth / 2.0f);
SubTexture2D pauseButtonIcon = _isPaused ? _editorIcons.Play : _editorIcons.Pause; SubTexture2D pauseButtonIcon = _isPaused ? _editorIcons.Play : _editorIcons.Pause;
if (ImGui.ImageButton(pauseButtonIcon, .(size, size), .Zero, .Ones, 0)) if (ImGui.ImageButton("PlayPause", pauseButtonIcon, .(size, size), .Zero, .Ones))
{ {
if (_isPaused) if (_isPaused)
OnSceneResume(); OnSceneResume();
@@ -431,10 +490,46 @@ namespace GlitchyEditor
ImGui.AttachTooltip(_isPaused ? "Resume" : "Pause"); ImGui.AttachTooltip(_isPaused ? "Resume" : "Pause");
if (_isPaused)
{
ImGui.PushID(2);
ImGui.SameLine();
SubTexture2D singleStepButtonIcon = _editorIcons.SingleStep;
if (ImGui.ImageButton("Step", singleStepButtonIcon, .(size, size), .Zero, .Ones))
{
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.SameLine();
ImGui.PushID(1); ImGui.PushID(1);
if (ImGui.ImageButton(_editorIcons.Stop, .(size, size), .Zero, .Ones, 0)) if (ImGui.ImageButton("Stop", _editorIcons.Stop, .(size, size), .Zero, .Ones))
OnSceneStop(); OnSceneStop();
ImGui.PopID(); ImGui.PopID();
@@ -492,11 +587,16 @@ namespace GlitchyEditor
_isPaused = false; _isPaused = false;
} }
private void DoSingleStep()
{
_singleStep = true;
}
private void OnSceneStop() private void OnSceneStop()
{ {
if (_sceneState == .Play) if (_sceneState == .Play)
_activeScene.OnRuntimeStop(); _activeScene.OnRuntimeStop();
else else if (_sceneState == .Simulate)
_activeScene.OnSimulationStop(); _activeScene.OnSimulationStop();
SetReference!(_activeScene, _editorScene); SetReference!(_activeScene, _editorScene);
@@ -508,12 +608,15 @@ namespace GlitchyEditor
_isPaused = false; _isPaused = false;
/* if (_activeScene != null)
* 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). * Update the viewport size because if the game windows size changed in
*/ * "Game"-mode the updated aspect-rations will reset once we go back
GameViewportSizeChanged(null, _editor.GameViewportWindow.ViewportSize); * into "Editor"-mode (because Game-Mode works on a copy of the scene).
*/
GameViewportSizeChanged(null, _editor.GameViewportWindow.ViewportSize);
}
} }
/// Creates a new scene. /// Creates a new scene.
@@ -523,44 +626,41 @@ namespace GlitchyEditor
SceneFilePath = null; SceneFilePath = null;
Scene newScene = new Scene(); using (Scene newScene = new Scene())
_camera.Position = .(-1.5f, 1.5f, -2.5f);
_camera.RotationEuler = .(MathHelper.ToRadians(25), MathHelper.ToRadians(35), 0);
// Create a default camera
{ {
let cameraEntity = newScene.CreateEntity("Camera"); _camera.Position = .(-1.5f, 1.5f, -2.5f);
let transform = cameraEntity.Transform; _camera.RotationEuler = .(MathHelper.ToRadians(25), MathHelper.ToRadians(35), 0);
transform.Position = Vector3(0, 2, -5);
transform.RotationEuler = Vector3(0, MathHelper.ToRadians(25), 0);
let camera = cameraEntity.AddComponent<CameraComponent>(); // Create a default camera
camera.Primary = true; {
camera.Camera.ProjectionType = .InfinitePerspective; let cameraEntity = newScene.CreateEntity("Camera");
camera.Camera.PerspectiveFovY = MathHelper.ToRadians(75); let transform = cameraEntity.Transform;
camera.Camera.PerspectiveNearPlane = 0.1f; 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);
} }
// 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);
}
_editorScene.ReleaseRef();
_editorScene = newScene;
_editor.CurrentScene = _editorScene;
var vpSize = _editor.SceneViewportWindow.ViewportSize;
_editorScene.OnViewportResize((.)vpSize.X, (.)vpSize.Y);
SetReference!(_activeScene, _editorScene);
} }
/// Saves the scene in the file that is was loaded from or saved to last. If there is no such path (i.e. it is a new scene) the save file dialog will open. /// 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.
@@ -611,16 +711,40 @@ namespace GlitchyEditor
SceneFilePath = scope String(filename); SceneFilePath = scope String(filename);
_editorScene.ReleaseRef(); using (Scene newScene = new Scene())
_editorScene = new Scene(); {
_editor.CurrentScene = _editorScene; SceneSerializer serializer = scope .(newScene);
var vpSize = _editor.SceneViewportWindow.ViewportSize; let result = serializer.Deserialize(SceneFilePath);
_editorScene.OnViewportResize((.)vpSize.X, (.)vpSize.Y);
SceneSerializer serializer = scope .(_editorScene); // 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.");
}
}
}
SetReference!(_activeScene, _editorScene); 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()
@@ -635,12 +759,19 @@ 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();
if (ImGui.MenuItem("Settings")) if (ImGui.MenuItem("Settings"))
@@ -674,9 +805,24 @@ namespace GlitchyEditor
if(ImGui.MenuItem(PropertiesWindow.s_WindowTitle)) if(ImGui.MenuItem(PropertiesWindow.s_WindowTitle))
_editor.PropertiesWindow.Open = true; _editor.PropertiesWindow.Open = true;
if(ImGui.MenuItem(AssetViewer.s_WindowTitle))
_editor.AssetViewer.Open = true;
if(ImGui.MenuItem(LogWindow.s_WindowTitle))
_editor.LogWindow.Open = true;
ImGui.EndMenu(); ImGui.EndMenu();
} }
if(ImGui.BeginMenu("Tools", true))
{
if(ImGui.MenuItem("Reload Scripts"))
ScriptEngine.ReloadAssemblies();
ImGui.EndMenu();
}
ImGui.EndMainMenuBar(); ImGui.EndMainMenuBar();
} }
@@ -685,35 +831,33 @@ namespace GlitchyEditor
return false; return false;
} }
private void EditorViewportSizeChanged(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)
return;
_editorViewportTarget.Resize(sizeX, sizeY); _editorViewportTarget.Resize(sizeX, sizeY);
_cameraTarget.Resize(sizeX, sizeY); _cameraTarget.Resize(sizeX, sizeY);
_camera.OnViewportResize(sizeX, sizeY); _camera.OnViewportResize(sizeX, sizeY);
_editorSceneRenderer.OnViewportResize(sizeX, sizeY); _activeScene.SetViewportSize(sizeX, sizeY);
} }
private void GameViewportSizeChanged(Object sender, Vector2 viewportSize) private void GameViewportSizeChanged(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)
return;
_gameViewportTarget.Resize(sizeX, sizeY); _gameViewportTarget.Resize(sizeX, sizeY);
_activeScene.OnViewportResize(sizeX, sizeY); _activeScene.SetViewportSize(sizeX, sizeY);
_gameSceneRenderer.OnViewportResize(sizeX, sizeY);
} }
private bool OnKeyPressed(KeyPressedEvent e) private bool OnKeyPressed(KeyPressedEvent e)
+128
View File
@@ -0,0 +1,128 @@
using GlitchLog;
using System;
using System.Diagnostics;
using GlitchyEngine.Scripting;
namespace GlitchyEditor;
public class EditorLogger : Logger
{
// {l} = log level (first parameter)
// {t} = current date time (second parameter)
// {n} = logger name (third parameter)
// {m} = message
private String _name;
public override String Name
{
get => _name;
set => _name = value;
}
public bool IsEngineLogger {get; set;}
public this()
{
//Debug.Assert(Debug.IsDebuggerPresent, "The DebugLogger requires a debugger to be present.");
}
#if GL_NOLOG || GL_LOG_NOTRACE
[SkipCall]
#endif
[Inline]
public override void Trace(StringView format, params Object[] args)
{
InternalLog(.Trace, format, params args);
}
#if GL_NOLOG || GL_LOG_NOINFO
[SkipCall]
#endif
[Inline]
public override void Info(StringView format, params Object[] args)
{
InternalLog(.Info, format, params args);
}
#if GL_NOLOG || GL_LOG_NOWARNING
[SkipCall]
#endif
[Inline]
public override void Warning(StringView format, params Object[] args)
{
InternalLog(.Warning, format, params args);
}
#if GL_NOLOG || GL_LOG_NOERROR
[SkipCall]
#endif
[Inline]
public override void Error(StringView format, params Object[] args)
{
InternalLog(.Error, format, params args);
}
#if GL_NOLOG || GL_LOG_NOCRITICAL
[SkipCall]
#endif
[Inline]
public override void Critical(StringView format, params Object[] args)
{
InternalLog(.Critical, format, params args);
}
#if GL_NOLOG
[SkipCall]
#endif
[Inline]
public override void Log(LogLevel level, StringView format, params Object[] args)
{
InternalLog(level, format, params args);
}
public override void Assert(bool condition, String error = Compiler.CallerExpression[0], String filePath = Compiler.CallerFilePath, int line = Compiler.CallerLineNum)
{
if (!condition)
{
String failStr = scope .()..AppendF("Assert failed: {} at line {} in {}", error, line, filePath);
InternalLog(.Critical, failStr);
Internal.FatalError(failStr, 1);
}
}
public override void AssertDebug(bool condition, String error = Compiler.CallerExpression[0], String filePath = Compiler.CallerFilePath, int line = Compiler.CallerLineNum)
{
if (!condition)
{
String failStr = scope .()..AppendF("Assert failed: {} at line {} in {}", error, line, filePath);
InternalLog(.Critical, failStr);
Internal.FatalError(failStr, 1);
}
}
private void InternalLog(LogLevel level, StringView format, params Object[] args)
{
if(_logLevel > level)
return;
DateTime timestamp = DateTime.Now;
String message = scope String(4096);
message.AppendF(format, params args);
Debug.Write($"[{timestamp:HH:mm:ss.fff}] ({_name})|{level.UpperString}: {message}");
if (Editor.Instance == null)
return;
if (args.Count > 0 && (var ex = args[^1] as MonoExceptionHelper))
{
Editor.Instance.LogWindow.LogException(timestamp, ex);
}
else
{
Editor.Instance.LogWindow.Log(timestamp, level, message, new .() {IsEngineMessage = IsEngineLogger});
}
}
}
+33
View File
@@ -0,0 +1,33 @@
using System;
namespace ImGui;
enum DragDropPayloadType
{
case ContentBrowserItem;
case Entity;
public String GetName()
{
switch (this)
{
case .ContentBrowserItem:
return "CONTENT_BROWSER_ITEM";
case .Entity:
return "ENTITY";
}
}
}
extension ImGui
{
public static Payload* AcceptDragDropPayload(DragDropPayloadType type, DragDropFlags flags = .None)
{
return AcceptDragDropPayload(type.GetName(), flags);
}
public static bool SetDragDropPayload(DragDropPayloadType type, void* data, size sz, Cond cond = .None)
{
return SetDragDropPayload(type.GetName(), data, sz, cond);
}
}
-246
View File
@@ -1,246 +0,0 @@
using GlitchyEngine.Renderer;
using GlitchyEngine;
using ImGui;
using GlitchyEngine.Math;
using System;
namespace GlitchyEditor
{
class TextureViewer
{
enum BackgroundMode : int32
{
White,
Black,
Checkerboard
}
enum SampleMode : int32
{
Point,
Linear
}
GraphicsContext _context ~ _.ReleaseRef();
Effect _effect ~ _.ReleaseRef();
float _zoom = 1.0f;
BackgroundMode _backgroundMode = .Checkerboard;
SampleMode _sampleMode = .Linear;
RenderTarget2D _target ~ _?.ReleaseRef();
// TODO: we don't need depth!
DepthStencilTarget _depth ~ _?.ReleaseRef();
SamplerState _samplerPoint ~ _.ReleaseRef();
SamplerState _samplerLinear ~ _.ReleaseRef();
public this()
{
_context = Application.Get().Window.Context..AddRef();
InitEffect();
InitState();
// TODO: rasterizerstate and depthstencilstate
}
private void InitEffect()
{
_effect = new Effect("content\\Shaders\\textureViewerShader.hlsl");
}
private void InitState()
{
SamplerStateDescription desc = .();
desc.MagFilter = .Linear;
desc.MinFilter = .Linear;
_samplerLinear = SamplerStateManager.GetSampler(desc);
desc.MagFilter = .Point;
desc.MinFilter = .Point;
_samplerPoint = SamplerStateManager.GetSampler(desc);
}
Vector2 _position;
bool _moving;
float _colorOffset = 0;
float _colorScale = 1;
float _alphaOffset = 0;
float _alphaScale = 1;
public void ViewTexture(Texture viewedTexture)
{
ImGui.Begin("Texture Viewer");
ImGui.SliderFloat("Zoom", &_zoom, 0.01f, 100.0f);
char8*[] items = scope .("White", "Black", "Checkerboard");
ImGui.Combo("Background", (.)&_backgroundMode, items.Ptr, (.)items.Count);
items = scope .("Point", "Linear");
ImGui.Combo("Sampler", (.)&_sampleMode, items.Ptr, (.)items.Count);
ImGui.SliderFloat2("Color offset and scale", *(float[2]*)&_colorOffset, -1.0f, 1.0f);
ImGui.SliderFloat2("Alpha offset and scale", *(float[2]*)&_alphaOffset, -1.0f, 1.0f);
ImGui.SliderFloat2("Position", *(float[2]*)&_position, 2 * -Math.Max(viewedTexture.Width, viewedTexture.Height) * _zoom, 2 * Math.Max(viewedTexture.Width, viewedTexture.Height) * _zoom);
ImGui.BeginChild("imageChild");
UpdateInput();
var viewportSize = ImGui.GetContentRegionAvail();
viewportSize.x = Math.Max(viewportSize.x, 1);
viewportSize.y = Math.Max(viewportSize.y, 1);
if(_target == null || viewportSize.x != _target.Width || viewportSize.y != _target.Height)
{
_target?.ReleaseRef();
_target = new RenderTarget2D(.(.R8G8B8A8_UNorm, (.)viewportSize.x, (.)viewportSize.y));
_depth?.ReleaseRef();
_depth = new DepthStencilTarget((.)viewportSize.x, (.)viewportSize.y, .D16_UNorm);
}
RenderTexture(viewedTexture);
ImGui.Image(_target, viewportSize);
ImGui.EndChild();
ImGui.End();
}
float lastWheel;
private void UpdateInput()
{
var windowPos = ImGui.GetWindowPos();
var mousePos = ImGui.GetIO().MousePos;
Vector2 mouseInWindow = .(mousePos.x - windowPos.x, mousePos.y - windowPos.y);
bool windowHovered = ImGui.IsWindowHovered();
if(windowHovered && Input.IsMouseButtonPressing(.MiddleButton))
{
_moving = true;
}
else if(Input.IsMouseButtonReleased(.MiddleButton))
{
_moving = false;
}
if(windowHovered || _moving)
{
float mouseWheel = ImGui.GetIO().MouseWheel;
float delta = mouseWheel - lastWheel;
if(delta != 0)
{
_position -= mouseInWindow;
_position /= _zoom;
_zoom *= Math.Pow(1.1f, delta);
_position *= _zoom;
_position += mouseInWindow;
}
}
if(_moving)
{
Int2 movement = Input.GetMouseMovement();
_position.X += movement.X;
_position.Y += movement.Y;
}
}
OrthographicCamera _camera = new OrthographicCamera() ~ delete _;
private void RenderTexture(Texture viewedTexture)
{
Viewport vp = .(0, 0, _target.Width, _target.Height);
RenderCommand.SetViewport(vp);
// TODO: don't clear pink!
RenderCommand.Clear(_target, .Pink);
RenderCommand.Clear(_depth, .Depth, 1.0f, 0);
//_target.Bind();
_context.SetRenderTarget(_target);
_context.SetDepthStencilTarget(_depth);
_context.BindRenderTargets();
Vector2 textureSize = Vector2(viewedTexture.Width, viewedTexture.Height);
Vector2 zoomedTextureSize = textureSize * _zoom;
Vector2 targetSize = Vector2(_target.Width, _target.Height);
_effect.Variables["ColorOffset"].SetData(_colorOffset);
_effect.Variables["ColorScale"].SetData(_colorScale);
_effect.Variables["AlphaOffset"].SetData(_alphaOffset);
_effect.Variables["AlphaScale"].SetData(_alphaScale);
_camera.Left = 0;
_camera.Top = 0;
_camera.Right = targetSize.X;
_camera.Bottom = -targetSize.Y;
_camera.NearPlane = -5;
_camera.FarPlane = 5;
_camera.Update();
Renderer2D.BeginScene(_camera);
switch(_backgroundMode)
{
case .Black:
Renderer2D.DrawQuadPivotCorner(Vector3(0, 0, 1), targetSize, 0, .Black);
case .White:
Renderer2D.DrawQuadPivotCorner(Vector3(0, 0, 1), targetSize, 0, .White);
case .Checkerboard:
float quadSize = 50.0f;
Vector2 numQuads = (targetSize / 500f) * 10f;
for(float x = 0; x < numQuads.X; x++)
{
for(float y = 0; y < numQuads.Y; y++)
{
Renderer2D.DrawQuadPivotCorner(Vector3(x * quadSize, -y * quadSize, 1), quadSize.XX, 0, ((x + y) % 2 == 0) ? .White : .Gray);
}
}
break;
}
Renderer2D.EndScene();
var sampler = viewedTexture.SamplerState;
switch(_sampleMode)
{
case .Point:
viewedTexture.SamplerState = _samplerPoint;
case .Linear:
viewedTexture.SamplerState = _samplerLinear;
}
Renderer2D.BeginScene(_camera, .SortByTexture, _effect);
Renderer2D.DrawQuad(Vector3(_position * .(1, -1), 0), zoomedTextureSize, 0, viewedTexture);
Renderer2D.EndScene();
viewedTexture.SamplerState = sampler;
}
}
}
+21
View File
@@ -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
+39 -1
View File
@@ -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;
@@ -36,9 +42,11 @@ namespace GlitchyEngine
public GameTime GameTime => _gameTime; public GameTime GameTime => _gameTime;
[Inline] [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()
@@ -68,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();
@@ -90,6 +99,7 @@ namespace GlitchyEngine
Profiler.ProfileFunction!(); Profiler.ProfileFunction!();
SamplerStateManager.Uninit(); SamplerStateManager.Uninit();
Renderer.Deinit(); Renderer.Deinit();
delete _contentManager; delete _contentManager;
@@ -99,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)
@@ -152,6 +164,8 @@ namespace GlitchyEngine
} }
#endif #endif
RunJobs();
if(allowFrame && !_isMinimized) if(allowFrame && !_isMinimized)
{ {
Debug.Profiler.ProfileScope!("Update Layers"); Debug.Profiler.ProfileScope!("Update Layers");
@@ -213,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);
}
}
} }
} }
+56
View File
@@ -56,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
+7
View File
@@ -19,6 +19,8 @@ struct AssetHandle : IHashable
public bool IsValid => this != .Invalid; public bool IsValid => this != .Invalid;
public bool IsInvalid => this == .Invalid; public bool IsInvalid => this == .Invalid;
public UUID ID => _uuid;
/// Create a new random AssetHandle /// Create a new random AssetHandle
public this() public this()
{ {
@@ -73,6 +75,11 @@ struct AssetHandle : IHashable
return .Ok; return .Ok;
} }
public override void ToString(String strBuffer)
{
_uuid.ToString(strBuffer);
}
} }
struct AssetHandle<T> where T : Asset struct AssetHandle<T> where T : Asset
+22 -22
View File
@@ -367,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);
@@ -405,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;
@@ -426,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)
@@ -451,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)
@@ -554,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;
@@ -582,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;
@@ -606,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);
+5
View File
@@ -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;
+11
View File
@@ -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++;
}
} }
} }
+53
View File
@@ -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,6 +16,15 @@ 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
{ {
@@ -37,5 +48,47 @@ 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 ClearDictionaryAndReleaseKeys(var dictionary)
{
if (dictionary != null)
{
for (var value in dictionary)
value.key?.ReleaseRef();
dictionary.Clear();
}
}
public static mixin ClearDictionaryAndReleaseValues(var dictionary)
{
if (dictionary != null)
{
for (var value in dictionary)
value.value?.ReleaseRef();
dictionary.Clear();
}
}
} }
} }
+25 -13
View File
@@ -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);
} }
@@ -87,17 +87,29 @@ namespace ImGui
public static extern void Image(TextureViewBinding textureViewBinding, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, Vec4 tint_col = Vec4.Ones, Vec4 border_col = Vec4.Zero); public static extern void Image(TextureViewBinding textureViewBinding, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, Vec4 tint_col = Vec4.Ones, Vec4 border_col = Vec4.Zero);
public static bool ImageButton(SubTexture2D subTexture, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, int32 frame_padding = -1, Vec4 bg_col = Vec4.Zero, Vec4 tint_col = Vec4.Ones) public static bool ImageButton(char8* id, SubTexture2D subTexture, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, Vec4 bg_col = Vec4.Zero, Vec4 tint_col = Vec4.Ones)
{ {
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(id, subTexture.Texture.GetViewBinding(), size, (.)subTexture.TexCoords.XY, (.)v, bg_col, tint_col);
} }
public static extern bool ImageButton(TextureViewBinding textureViewBinding, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, int32 frame_padding = -1, Vec4 bg_col = Vec4.Zero, Vec4 tint_col = Vec4.Ones); public static extern bool ImageButton(char8* id, TextureViewBinding textureViewBinding, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, Vec4 bg_col = Vec4.Zero, Vec4 tint_col = Vec4.Ones);
public static bool ImageButtonEx(uint32 id, SubTexture2D subTexture, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, Vec4 bg_col = Vec4.Zero, Vec4 tint_col = Vec4.Ones)
{
if (uv0 != .Zero || uv1 != .Ones)
Runtime.NotImplemented();
float2 v = (.)subTexture.TexCoords.XY + subTexture.TexCoords.ZW;
return ImageButtonEx(id, subTexture.Texture.GetViewBinding(), size, (.)subTexture.TexCoords.XY, (.)v, bg_col, tint_col);
}
public static extern bool ImageButtonEx(uint32 id, TextureViewBinding textureViewBinding, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, Vec4 bg_col = Vec4.Zero, Vec4 tint_col = Vec4.Ones);
public static void TextUnformatted(StringView text) => TextUnformattedImpl(text.Ptr, text.Ptr + text.Length); public static void TextUnformatted(StringView text) => TextUnformattedImpl(text.Ptr, text.Ptr + text.Length);
@@ -107,19 +119,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);
} }
+35 -20
View File
@@ -86,29 +86,42 @@ namespace GlitchyEngine.ImGui
ImGuizmo.BeginFrame(); ImGuizmo.BeginFrame();
} }
private void LoadFont()
{
var settings = Application.Instance.Settings.ImGuiSettings;
ImGui.GetIO().Fonts.Clear();
Stream fontFile = Application.Instance.ContentManager.GetStream(settings.FontName);
if (fontFile != null)
{
// We need to use ImGuis memory allocator because ImGui takes ownership
uint8* fontData = (uint8*)ImGui.MemAlloc((uint64)fontFile.Length);
var result = fontFile.TryRead(Span<uint8>(fontData, fontFile.Length));
if (result case .Err)
Log.EngineLogger.Error($"Failed to load font \"{settings.FontName}\" from stream.");
ImGui.GetIO().Fonts.AddFontFromMemoryTTF(fontData, (int32)fontFile.Length, settings.FontSize);
}
else
{
ImGui.GetIO().Fonts.AddFontDefault();
}
ImGui.GetIO().Fonts.AddFontDefault();
delete fontFile;
}
public void ImGuiRender() public void ImGuiRender()
{ {
Debug.Profiler.ProfileFunction!(); Debug.Profiler.ProfileFunction!();
if (SettingsInvalid) if (SettingsInvalid)
{ {
var settings = Application.Get().Settings.ImGuiSettings; LoadFont();
ImGui.GetIO().Fonts.Clear();
// TODO: Fix fonts
//String fullpath = scope String();
//Application.Get().ContentManager.GetFilePath(fullpath, settings.FontName);
/*Application.Get().ContentManager.GetStream(settings.FontName);
if (File.Exists(fullpath))
{
ImGui.GetIO().Fonts.AddFontFromMemoryTTF();
ImGui.GetIO().Fonts.AddFontFromFileTTF(fullpath, settings.FontSize);
}
else
{*/
ImGui.GetIO().Fonts.AddFontDefault();
//}
#if GE_GRAPHICS_DX11 #if GE_GRAPHICS_DX11
ImGuiImplDX11.CreateDeviceObjects(); ImGuiImplDX11.CreateDeviceObjects();
@@ -119,8 +132,6 @@ namespace GlitchyEngine.ImGui
Begin(); Begin();
ImGui.ShowDemoWindow();
{ {
Debug.Profiler.ProfileScope!("ImGuiRenderEvent"); Debug.Profiler.ProfileScope!("ImGuiRenderEvent");
@@ -142,7 +153,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
View File
@@ -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()
{ {
+27 -4
View File
@@ -8,10 +8,33 @@ namespace GlitchyEngine
static Logger _engineLogger ~ delete _; static Logger _engineLogger ~ delete _;
static Logger _clientLogger ~ delete _; static Logger _clientLogger ~ delete _;
[Inline] public static Logger EngineLogger
public static Logger EngineLogger => _engineLogger; {
[Inline] [Inline]
public static Logger ClientLogger => _clientLogger; get => _engineLogger;
set
{
if (_engineLogger == value)
return;
delete _engineLogger;
_engineLogger = value;
}
}
public static Logger ClientLogger
{
[Inline]
get => _clientLogger;
set
{
if (_clientLogger == value)
return;
delete _clientLogger;
_clientLogger = value;
}
}
static this() static this()
{ {
+2 -2
View File
@@ -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;
} }
} }
+2 -2
View File
@@ -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;
} }
} }
+3 -3
View File
@@ -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;
} }
} }
+23 -3
View File
@@ -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;
} }
} }
+831
View File
@@ -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
}
+13 -13
View File
@@ -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));
} }
} }
} }
+81 -84
View File
@@ -21,7 +21,7 @@ public struct Matrix
public using Values V; public using Values V;
public float[4][4] Values; public float[4][4] Values;
public Vector4[4] Columns; public float4[4] Columns;
/// Creates a new zero-matrix. /// Creates a new zero-matrix.
public this() => this = default; public this() => this = default;
@@ -53,7 +53,7 @@ public struct Matrix
} }
/// Creates a new matrix and initializes it with the given column-vectors. /// Creates a new matrix and initializes it with the given column-vectors.
public this(Vector4 c0, Vector4 c1, Vector4 c2, Vector4 c3) public this(float4 c0, float4 c1, float4 c2, float4 c3)
{ {
Columns[0] = c0; Columns[0] = c0;
Columns[1] = c1; Columns[1] = c1;
@@ -61,47 +61,47 @@ public struct Matrix
Columns[3] = c3; Columns[3] = c3;
} }
public ref Vector3 Right public ref float3 Right
{ {
[Inline] [Inline]
get get
{ {
#unwarn #unwarn
return ref *(Vector3*)&Columns[0]; return ref *(float3*)&Columns[0];
} }
} }
public ref Vector3 Up public ref float3 Up
{ {
[Inline] [Inline]
get get
{ {
#unwarn #unwarn
return ref *(Vector3*)&Columns[1]; return ref *(float3*)&Columns[1];
} }
} }
public ref Vector3 Forward public ref float3 Forward
{ {
[Inline] [Inline]
get get
{ {
#unwarn #unwarn
return ref *(Vector3*)&Columns[2]; return ref *(float3*)&Columns[2];
} }
} }
public ref Vector3 Translation public ref float3 Translation
{ {
[Inline] [Inline]
get get
{ {
#unwarn #unwarn
return ref *(Vector3*)&Columns[3]; return ref *(float3*)&Columns[3];
} }
} }
public Vector3 Scale public float3 Scale
{ {
[Inline] [Inline]
get => .(_11, _22, _33); get => .(_11, _22, _33);
@@ -134,12 +134,12 @@ public struct Matrix
} }
} }
public ref Vector4 this[int column] public ref float4 this[int column]
{ {
get get
{ {
#unwarn #unwarn
return ref *(Vector4*)&Columns[column]; return ref *(float4*)&Columns[column];
} }
@@ -150,7 +150,7 @@ public struct Matrix
Internal.ThrowIndexOutOfRange(); Internal.ThrowIndexOutOfRange();
#unwarn #unwarn
return ref *(Vector4*)&Columns[column]; return ref *(float4*)&Columns[column];
} }
} }
@@ -351,12 +351,12 @@ public struct Matrix
/** /**
* Multiplies a matrix and a column-vector resulting in a column vector. * Multiplies a matrix and a column-vector resulting in a column vector.
*/ */
public static Vector4 operator *(Matrix matrix, Vector4 columnVector) public static float4 operator *(Matrix matrix, float4 columnVector)
{ {
#unwarn #unwarn
var m = &matrix.V; var m = &matrix.V;
Vector4 result = ?; float4 result = ?;
result.X = (m._11 * columnVector.X) + (m._12 * columnVector.Y) + (m._13 * columnVector.Z) + (m._14 * columnVector.W); 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.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.Z = (m._31 * columnVector.X) + (m._32 * columnVector.Y) + (m._33 * columnVector.Z) + (m._34 * columnVector.W);
@@ -367,12 +367,12 @@ public struct Matrix
/** /**
* Multiplies a row-vector and a matrix resulting in a row vector. * Multiplies a row-vector and a matrix resulting in a row vector.
*/ */
public static Vector4 operator *(Vector4 rowVector, Matrix matrix) public static float4 operator *(float4 rowVector, Matrix matrix)
{ {
#unwarn #unwarn
var m = &matrix.V; var m = &matrix.V;
Vector4 result = ?; float4 result = ?;
result.X = (rowVector.X * m._11) + (rowVector.Y * m._21) + (rowVector.Z * m._31) + (rowVector.W * m._41); 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.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.Z = (rowVector.X * m._13) + (rowVector.Y * m._23) + (rowVector.Z * m._33) + (rowVector.W * m._43);
@@ -406,7 +406,7 @@ public struct Matrix
0, 0, 0, 1); 0, 0, 0, 1);
} }
public static Matrix Scaling(Vector3 scale) public static Matrix Scaling(float3 scale)
{ {
return .(scale.X, 0, 0, 0, return .(scale.X, 0, 0, 0,
0, scale.Y, 0, 0, 0, scale.Y, 0, 0,
@@ -422,7 +422,7 @@ public struct Matrix
0, 0, 0, 1); 0, 0, 0, 1);
} }
public static Matrix Translation(Vector3 translation) public static Matrix Translation(float3 translation)
{ {
return .(1, 0, 0, translation.X, return .(1, 0, 0, translation.X,
0, 1, 0, translation.Y, 0, 1, 0, translation.Y,
@@ -470,25 +470,22 @@ public struct Matrix
* @param up A vector defining the up direction of the camera. * @param up A vector defining the up direction of the camera.
* @returns a view matrix. * @returns a view matrix.
*/ */
public static Matrix LookAt(Vector3 position, Vector3 target, Vector3 up) public static Matrix LookAt(float3 position, float3 target, float3 up)
{ {
Vector3 forward = target - position; float3 forward = normalize(target - position);
forward.Normalize();
Vector3 right = Vector3.Cross(up, forward); float3 right = normalize(cross(up, forward));
right.Normalize();
Vector3 newUp = Vector3.Cross(forward, right); float3 newUp = normalize(cross(forward, right));
newUp.Normalize();
Matrix result = .Identity; Matrix result = .Identity;
result.Forward = forward; result.Forward = forward;
result.Up = up; result.Up = up;
result.Right = right; result.Right = right;
result.Translation.X = -Vector3.Dot(position, right); result.Translation.X = -dot(position, right);
result.Translation.Y = -Vector3.Dot(position, up); result.Translation.Y = -dot(position, up);
result.Translation.Z = -Vector3.Dot(position, forward); result.Translation.Z = -dot(position, forward);
return result; return result;
} }
@@ -511,22 +508,22 @@ public struct Matrix
{ {
// From: Lengyel, Eric. Foundations of Game Engine Development, Volume 1: Mathematics (S.61). Kindle-Version. // From: Lengyel, Eric. Foundations of Game Engine Development, Volume 1: Mathematics (S.61). Kindle-Version.
Vector3 a = *(Vector3*)&Columns[0]; float3 a = *(float3*)&Columns[0];
Vector3 b = *(Vector3*)&Columns[1]; float3 b = *(float3*)&Columns[1];
Vector3 c = *(Vector3*)&Columns[2]; float3 c = *(float3*)&Columns[2];
Vector3 d = *(Vector3*)&Columns[3]; float3 d = *(float3*)&Columns[3];
float x = this[3, 0]; float x = this[3, 0];
float y = this[3, 1]; float y = this[3, 1];
float z = this[3, 2]; float z = this[3, 2];
float w = this[3, 3]; float w = this[3, 3];
Vector3 s = Vector3.Cross(a, b); float3 s = cross(a, b);
Vector3 t = Vector3.Cross(c, d); float3 t = cross(c, d);
Vector3 u = y * a - x * b; float3 u = y * a - x * b;
Vector3 v = w * c - z * d; float3 v = w * c - z * d;
return Vector3.Dot(s, v) + Vector3.Dot(t, u); return dot(s, v) + dot(t, u);
} }
/** /**
@@ -537,39 +534,39 @@ public struct Matrix
// From: Lengyel, Eric. Foundations of Game Engine Development, Volume 1: Mathematics (S.61). Kindle-Version. // From: Lengyel, Eric. Foundations of Game Engine Development, Volume 1: Mathematics (S.61). Kindle-Version.
#unwarn #unwarn
Vector3 a = *(Vector3*)&Columns[0]; float3 a = *(float3*)&Columns[0];
#unwarn #unwarn
Vector3 b = *(Vector3*)&Columns[1]; float3 b = *(float3*)&Columns[1];
#unwarn #unwarn
Vector3 c = *(Vector3*)&Columns[2]; float3 c = *(float3*)&Columns[2];
#unwarn #unwarn
Vector3 d = *(Vector3*)&Columns[3]; float3 d = *(float3*)&Columns[3];
float x = this[3, 0]; float x = this[3, 0];
float y = this[3, 1]; float y = this[3, 1];
float z = this[3, 2]; float z = this[3, 2];
float w = this[3, 3]; float w = this[3, 3];
Vector3 s = Vector3.Cross(a, b); float3 s = cross(a, b);
Vector3 t = Vector3.Cross(c, d); float3 t = cross(c, d);
Vector3 u = y * a - x * b; float3 u = y * a - x * b;
Vector3 v = w * c - z * d; float3 v = w * c - z * d;
float invDet = 1.0f / (Vector3.Dot(s, v) + Vector3.Dot(t, u)); float invDet = 1.0f / (dot(s, v) + dot(t, u));
s *= invDet; s *= invDet;
t *= invDet; t *= invDet;
u *= invDet; u *= invDet;
v *= invDet; v *= invDet;
Vector3 r0 = Vector3.Cross(b, v) + t * y; float3 r0 = cross(b, v) + t * y;
Vector3 r1 = Vector3.Cross(v, a) - t * x; float3 r1 = cross(v, a) - t * x;
Vector3 r2 = Vector3.Cross(d, u) + s * w; float3 r2 = cross(d, u) + s * w;
Vector3 r3 = Vector3.Cross(u, c) - s * z; float3 r3 = cross(u, c) - s * z;
return .(r0.X, r0.Y, r0.Z, -Vector3.Dot(b, t), return .(r0.X, r0.Y, r0.Z, -dot(b, t),
r1.X, r1.Y, r1.Z, Vector3.Dot(a, t), r1.X, r1.Y, r1.Z, dot(a, t),
r2.X, r2.Y, r2.Z, -Vector3.Dot(d, s), r2.X, r2.Y, r2.Z, -dot(d, s),
r3.X, r3.Y, r3.Z, Vector3.Dot(c, s)); r3.X, r3.Y, r3.Z, dot(c, s));
} }
/// Calculates the inverse of the matrix. /// Calculates the inverse of the matrix.
@@ -578,39 +575,39 @@ public struct Matrix
// From: Lengyel, Eric. Foundations of Game Engine Development, Volume 1: Mathematics (S.61). Kindle-Version. // From: Lengyel, Eric. Foundations of Game Engine Development, Volume 1: Mathematics (S.61). Kindle-Version.
#unwarn #unwarn
Vector3 a = *(Vector3*)&matrix.Columns[0]; float3 a = *(float3*)&matrix.Columns[0];
#unwarn #unwarn
Vector3 b = *(Vector3*)&matrix.Columns[1]; float3 b = *(float3*)&matrix.Columns[1];
#unwarn #unwarn
Vector3 c = *(Vector3*)&matrix.Columns[2]; float3 c = *(float3*)&matrix.Columns[2];
#unwarn #unwarn
Vector3 d = *(Vector3*)&matrix.Columns[3]; float3 d = *(float3*)&matrix.Columns[3];
float x = matrix[3, 0]; float x = matrix[3, 0];
float y = matrix[3, 1]; float y = matrix[3, 1];
float z = matrix[3, 2]; float z = matrix[3, 2];
float w = matrix[3, 3]; float w = matrix[3, 3];
Vector3 s = Vector3.Cross(a, b); float3 s = cross(a, b);
Vector3 t = Vector3.Cross(c, d); float3 t = cross(c, d);
Vector3 u = y * a - x * b; float3 u = y * a - x * b;
Vector3 v = w * c - z * d; float3 v = w * c - z * d;
float invDet = 1.0f / (Vector3.Dot(s, v) + Vector3.Dot(t, u)); float invDet = 1.0f / (dot(s, v) + dot(t, u));
s *= invDet; s *= invDet;
t *= invDet; t *= invDet;
u *= invDet; u *= invDet;
v *= invDet; v *= invDet;
Vector3 r0 = Vector3.Cross(b, v) + t * y; float3 r0 = cross(b, v) + t * y;
Vector3 r1 = Vector3.Cross(v, a) - t * x; float3 r1 = cross(v, a) - t * x;
Vector3 r2 = Vector3.Cross(d, u) + s * w; float3 r2 = cross(d, u) + s * w;
Vector3 r3 = Vector3.Cross(u, c) - s * z; float3 r3 = cross(u, c) - s * z;
return .(r0.X, r0.Y, r0.Z, -Vector3.Dot(b, t), return .(r0.X, r0.Y, r0.Z, -dot(b, t),
r1.X, r1.Y, r1.Z, Vector3.Dot(a, t), r1.X, r1.Y, r1.Z, dot(a, t),
r2.X, r2.Y, r2.Z, -Vector3.Dot(d, s), r2.X, r2.Y, r2.Z, -dot(d, s),
r3.X, r3.Y, r3.Z, Vector3.Dot(c, s)); r3.X, r3.Y, r3.Z, dot(c, s));
} }
/** /**
@@ -792,9 +789,9 @@ public struct Matrix
*/ */
public void Orthogonalize() mut public void Orthogonalize() mut
{ {
Columns[1] -= .Project(Columns[1], Columns[0]); Columns[1] -= project(Columns[1], Columns[0]);
Columns[2] -= .Project(Columns[2], Columns[0]) + .Project(Columns[2], Columns[1]); 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]); Columns[3] -= project(Columns[3], Columns[0]) + project(Columns[3], Columns[1]) + project(Columns[3], Columns[2]);
} }
/** /**
@@ -802,10 +799,10 @@ public struct Matrix
*/ */
public void Orthonormalize() mut public void Orthonormalize() mut
{ {
Columns[0].Normalize(); Columns[0] = normalize(Columns[0]);
Columns[1] = .Normalize(.Reject(Columns[1], Columns[0])); Columns[1] = normalize(reject(Columns[1], Columns[0]));
Columns[2] = .Normalize(.Reject(.Reject(Columns[2], Columns[0]), Columns[1])); 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])); Columns[3] = normalize(reject(reject(reject(Columns[2], Columns[0]), Columns[1]), Columns[2]));
} }
public static Self RotationQuaternion(Quaternion rotation) public static Self RotationQuaternion(Quaternion rotation)
{ {
@@ -845,7 +842,7 @@ public struct Matrix
return result; return result;
} }
public static void Decompose(Self matrix, out Vector3 position, out Quaternion rotation, out Vector3 scale) public static void Decompose(Self matrix, out float3 position, out Quaternion rotation, out float3 scale)
{ {
var matrix; var matrix;
@@ -857,9 +854,9 @@ public struct Matrix
// TODO: this doesn't detect mirroring // TODO: this doesn't detect mirroring
// Extract scaling from matrix // Extract scaling from matrix
scale.X = (*(Vector3*)&matrix.Columns[0]).Magnitude(); scale.X = length(*(float3*)&matrix.Columns[0]);
scale.Y = (*(Vector3*)&matrix.Columns[1]).Magnitude(); scale.Y = length(*(float3*)&matrix.Columns[1]);
scale.Z = (*(Vector3*)&matrix.Columns[2]).Magnitude(); scale.Z = length(*(float3*)&matrix.Columns[2]);
if(MathHelper.IsZero(scale.X) || MathHelper.IsZero(scale.Y) || MathHelper.IsZero(scale.Z)) if(MathHelper.IsZero(scale.X) || MathHelper.IsZero(scale.Y) || MathHelper.IsZero(scale.Z))
{ {
+17 -17
View File
@@ -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
@@ -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);
-299
View File
@@ -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;
}
}
-349
View File
@@ -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;
}
}
-330
View File
@@ -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;
}
}
+440
View File
@@ -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);
}
}
-162
View File
@@ -1,162 +0,0 @@
#pragma warning disable 4204
using System;
using System.Diagnostics;
namespace GlitchyEngine.Math
{
/**
* A Vector with two components of type int32.
*/
[SwizzleVector(2, "Int")]
public struct Int2 : IHashable
{
public const Int2 Zero = .(0, 0);
public const Int2 UnitX = .(1, 0);
public const Int2 UnitY = .(0, 1);
public const Int2 One = .(1, 1);
public int32 X, Y;
public this() => this = default;
public this(int32 value)
{
X = value;
Y = value;
}
public this(int value)
{
X = (.)value;
Y = (.)value;
}
public this(int32 x, int32 y)
{
X = x;
Y = y;
}
public this(int x, int y)
{
X = (.)x;
Y = (.)y;
}
public ref int32 this[int index]
{
[Inline]
get
{
#if DEBUG
if(index < 0 || index >= 2)
Internal.ThrowIndexOutOfRange(1);
#endif
return ref (&X)[index];
}
}
public int32 MagnitudeSquared() => X * X + Y * Y;
public float Magnitude() => Math.Sqrt(X * X + Y * Y);
public Int2 Abs() => .(Math.Abs(X), Math.Abs(Y));
//
// Assignment operators
//
public void operator +=(Int2 value) mut
{
X += value.X;
Y += value.Y;
}
public void operator +=(int32 value) mut
{
X += value;
Y += value;
}
public void operator -=(Int2 value) mut
{
X -= value.X;
Y -= value.Y;
}
public void operator -=(int32 value) mut
{
X -= value;
Y -= value;
}
public void operator *=(Int2 value) mut
{
X *= value.X;
Y *= value.Y;
}
public void operator *=(int32 value) mut
{
X *= value;
Y *= value;
}
public void operator /=(Int2 value) mut
{
X /= value.X;
Y /= value.Y;
}
public void operator /=(int32 value) mut
{
X /= value;
Y /= value;
}
// Operators
public static Int2 operator +(Int2 value) => value;
public static Int2 operator +(Int2 left, Int2 right) => .(left.X + right.X, left.Y + right.Y);
public static Int2 operator +(Int2 left, int32 right) => .(left.X + right, left.Y + right);
public static Int2 operator +(int32 left, Int2 right) => .(left + right.X, left + right.Y);
public static Int2 operator -(Int2 value) => .(-value.X, -value.Y);
public static Int2 operator -(Int2 left, Int2 right) => .(left.X - right.X, left.Y - right.Y);
public static Int2 operator -(Int2 left, int32 right) => .(left.X - right, left.Y - right);
public static Int2 operator -(int32 left, Int2 right) => .(left - right.X, left - right.Y);
public static Int2 operator *(Int2 left, Int2 right) => .(left.X * right.X, left.Y * right.Y);
public static Int2 operator *(Int2 left, int32 right) => .(left.X * right, left.Y * right);
public static Int2 operator *(int32 left, Int2 right) => .(left * right.X, left * right.Y);
public static Int2 operator /(Int2 left, Int2 right) => .(left.X / right.X, left.Y / right.Y);
public static Int2 operator /(Int2 left, int32 right) => .(left.X / right, left.Y / right);
public static Int2 operator /(int32 left, Int2 right) => .(left / right.X, left / right.Y);
public static Int2 operator %(Int2 left, Int2 right) => .(left.X % right.X, left.Y % right.Y);
public static Int2 operator %(Int2 left, int32 right) => .(left.X % right, left.Y % right);
public static Int2 operator %(int32 left, Int2 right) => .(left % right.X, left % right.Y);
public static bool operator ==(Int2 left, Int2 right) => left.X == right.X && left.Y == right.Y;
public static bool operator ==(Int2 left, int32 right) => left.X == right && left.Y == right;
public static bool operator ==(int32 left, Int2 right) => left == right.X && left == right.Y;
public static bool operator !=(Int2 left, Int2 right) => left.X != right.X || left.Y != right.Y;
public static bool operator !=(Int2 left, int32 right) => left.X != right || left.Y != right;
public static bool operator !=(int32 left, Int2 right) => left != right.X || left != right.Y;
public override void ToString(String strBuffer) => strBuffer.AppendF($"X:{X} Y:{Y}");
public static explicit operator Vector2(Int2 point) => .(point.X, point.Y);
public static explicit operator Int2(Vector2 point) => .((int32)point.X, (int32)point.Y);
public int GetHashCode()
{
return (X * 39) ^ Y;
}
}
}
-206
View File
@@ -1,206 +0,0 @@
#pragma warning disable 4204
using System;
using System.Diagnostics;
namespace GlitchyEngine.Math
{
/**
* A Vector with three components of type int32.
*/
[SwizzleVector(3, "Int")]
public struct Int3 : IHashable
{
public const Int3 Zero = .(0, 0, 0);
public const Int3 UnitX = .(1, 0, 0);
public const Int3 UnitY = .(0, 1, 0);
public const Int3 UnitZ = .(0, 0, 1);
public const Int3 One = .(1, 1, 1);
public int32 X, Y, Z;
public this() => this = default;
public this(int32 value)
{
X = value;
Y = value;
Z = value;
}
public this(int value)
{
X = (.)value;
Y = (.)value;
Z = (.)value;
}
public this(int32 x, int32 y, int32 z)
{
X = x;
Y = y;
Z = z;
}
public this(Int2 xy, int32 z)
{
X = xy.X;
Y = xy.Y;
Z = z;
}
public this(int32 x, Int2 yz)
{
X = x;
Y = yz.X;
Z = yz.Y;
}
public this(int x, int y, int z)
{
X = (.)x;
Y = (.)y;
Z = (.)z;
}
public this(Int2 xy, int z)
{
X = xy.X;
Y = xy.Y;
Z = (.)z;
}
public this(int x, Int2 yz)
{
X = (.)x;
Y = yz.X;
Z = yz.Y;
}
public ref int32 this[int index]
{
[Inline]
get
{
#if DEBUG
if(index < 0 || index >= 3)
Internal.ThrowIndexOutOfRange(1);
#endif
return ref (&X)[index];
}
}
public int32 MagnitudeSquared() => X * X + Y * Y + Z * Z;
public float Magnitude() => Math.Sqrt(X * X + Y * Y + Z * Z);
public Int3 Abs() => .(Math.Abs(X), Math.Abs(Y), Math.Abs(Z));
//
// Assignment operators
//
public void operator +=(Int3 value) mut
{
X += value.X;
Y += value.Y;
Z += value.Z;
}
public void operator +=(int32 value) mut
{
X += value;
Y += value;
Z += value;
}
public void operator -=(Int3 value) mut
{
X -= value.X;
Y -= value.Y;
Z -= value.Z;
}
public void operator -=(int32 value) mut
{
X -= value;
Y -= value;
Z -= value;
}
public void operator *=(Int3 value) mut
{
X *= value.X;
Y *= value.Y;
Z *= value.Z;
}
public void operator *=(int32 value) mut
{
X *= value;
Y *= value;
Z *= value;
}
public void operator /=(Int3 value) mut
{
X /= value.X;
Y /= value.Y;
Z /= value.Z;
}
public void operator /=(int32 value) mut
{
X /= value;
Y /= value;
Z /= value;
}
// Operators
public static Int3 operator +(Int3 value) => value;
public static Int3 operator +(Int3 left, Int3 right) => .(left.X + right.X, left.Y + right.Y, left.Z + right.Z);
public static Int3 operator +(Int3 left, int32 right) => .(left.X + right, left.Y + right, left.Z + right);
public static Int3 operator +(int32 left, Int3 right) => .(left + right.X, left + right.Y, left + right.Z);
public static Int3 operator -(Int3 value) => .(-value.X, -value.Y, -value.Z);
public static Int3 operator -(Int3 left, Int3 right) => .(left.X - right.X, left.Y - right.Y, left.Z - right.Z);
public static Int3 operator -(Int3 left, int32 right) => .(left.X - right, left.Y - right, left.Z- right);
public static Int3 operator -(int32 left, Int3 right) => .(left - right.X, left - right.Y, left - right.Z);
public static Int3 operator *(Int3 left, Int3 right) => .(left.X * right.X, left.Y * right.Y, left.Z * right.Z);
public static Int3 operator *(Int3 left, int32 right) => .(left.X * right, left.Y * right, left.Z * right);
public static Int3 operator *(int32 left, Int3 right) => .(left * right.X, left * right.Y, left * right.Z);
public static Int3 operator /(Int3 left, Int3 right) => .(left.X / right.X, left.Y / right.Y, left.Z / right.Z);
public static Int3 operator /(Int3 left, int32 right) => .(left.X / right, left.Y / right, left.Z / right);
public static Int3 operator /(int32 left, Int3 right) => .(left / right.X, left / right.Y, left / right.Z);
public static Int3 operator %(Int3 left, Int3 right) => .(left.X % right.X, left.Y % right.Y, left.Z % right.Z);
public static Int3 operator %(Int3 left, int32 right) => .(left.X % right, left.Y % right, left.Z % right);
public static Int3 operator %(int32 left, Int3 right) => .(left % right.X, left % right.Y, left % right.Z);
public static bool operator ==(Int3 left, Int3 right) => left.X == right.X && left.Y == right.Y && left.Z == right.Z;
public static bool operator ==(Int3 left, int32 right) => left.X == right && left.Y == right && left.Z == right;
public static bool operator ==(int32 left, Int3 right) => left == right.X && left == right.Y && left == right.Z;
public static bool operator !=(Int3 left, Int3 right) => left.X != right.X || left.Y != right.Y || left.Z != right.Z;
public static bool operator !=(Int3 left, int32 right) => left.X != right || left.Y != right || left.Z != right;
public static bool operator !=(int32 left, Int3 right) => left != right.X || left != right.Y || left != right.Z;
public override void ToString(String strBuffer) => strBuffer.AppendF($"X:{X} Y:{Y} Z:{Z}");
public static explicit operator Vector3(Int3 point) => .(point.X, point.Y, point.Z);
public static explicit operator Int3(Vector3 point) => .((int32)point.X, (int32)point.Y, (int32)point.Z);
[Inline]
public static explicit operator Int2(in Int3 point) => *(Int2*)&point;
public int GetHashCode()
{
return (((X * 39) ^ Y) * 39) ^ Z;
}
}
}
-234
View File
@@ -1,234 +0,0 @@
#pragma warning disable 4204
using System;
using System.Diagnostics;
namespace GlitchyEngine.Math
{
/**
* A Vector with four components of type int32.
*/
[SwizzleVector(4, "Int")]
public struct Int4 : IHashable
{
public const Int4 Zero = .(0, 0, 0, 0);
public const Int4 UnitX = .(1, 0, 0, 0);
public const Int4 UnitY = .(0, 1, 0, 0);
public const Int4 UnitZ = .(0, 0, 1, 0);
public const Int4 UnitW = .(0, 0, 0, 1);
public const Int4 One = .(1, 1, 1, 1);
public int32 X, Y, Z, W;
public this() => this = default;
public this(int32 value)
{
X = value;
Y = value;
Z = value;
W = value;
}
public this(int value)
{
X = (.)value;
Y = (.)value;
Z = (.)value;
W = (.)value;
}
public this(int32 x, int32 y, int32 z, int32 w)
{
X = x;
Y = y;
Z = z;
W = w;
}
public this(Int2 xy, int32 z, int32 w)
{
X = xy.X;
Y = xy.Y;
Z = z;
W = w;
}
public this(int32 x, Int2 yz, int32 w)
{
X = x;
Y = yz.X;
Z = yz.Y;
W = w;
}
public this(int32 x, int32 y, Int2 zw)
{
X = x;
Y = y;
Z = zw.X;
W = zw.Y;
}
public this(Int2 xy, Int2 zw)
{
X = xy.X;
Y = xy.Y;
Z = zw.X;
W = zw.Y;
}
public this(Int3 xyz, int32 w)
{
X = xyz.X;
Y = xyz.Y;
Z = xyz.Z;
W = w;
}
public this(int32 x, Int3 yzw)
{
X = x;
Y = yzw.X;
Z = yzw.Y;
W = yzw.Z;
}
public ref int32 this[int index]
{
[Inline]
get
{
#if DEBUG
if(index < 0 || index >= 3)
Internal.ThrowIndexOutOfRange(1);
#endif
return ref (&X)[index];
}
}
public int32 MagnitudeSquared() => X * X + Y * Y + Z * Z + W * W;
public float Magnitude() => Math.Sqrt(X * X + Y * Y + Z * Z + W * W);
public Int4 Abs() => .(Math.Abs(X), Math.Abs(Y), Math.Abs(Z), Math.Abs(W));
//
// Assignment operators
//
public void operator +=(Int4 value) mut
{
X += value.X;
Y += value.Y;
Z += value.Z;
W += value.W;
}
public void operator +=(int32 value) mut
{
X += value;
Y += value;
Z += value;
W += value;
}
public void operator -=(Int4 value) mut
{
X -= value.X;
Y -= value.Y;
Z -= value.Z;
W -= value.W;
}
public void operator -=(int32 value) mut
{
X -= value;
Y -= value;
Z -= value;
W -= value;
}
public void operator *=(Int4 value) mut
{
X *= value.X;
Y *= value.Y;
Z *= value.Z;
W *= value.W;
}
public void operator *=(int32 value) mut
{
X *= value;
Y *= value;
Z *= value;
W *= value;
}
public void operator /=(Int4 value) mut
{
X /= value.X;
Y /= value.Y;
Z /= value.Z;
W /= value.W;
}
public void operator /=(int32 value) mut
{
X /= value;
Y /= value;
Z /= value;
W /= value;
}
// Operators
public static Int4 operator +(Int4 value) => value;
public static Int4 operator +(Int4 left, Int4 right) => .(left.X + right.X, left.Y + right.Y, left.Z + right.Z, left.W + right.W);
public static Int4 operator +(Int4 left, int32 right) => .(left.X + right, left.Y + right, left.Z + right, left.W + right);
public static Int4 operator +(int32 left, Int4 right) => .(left + right.X, left + right.Y, left + right.Z, left + right.W);
public static Int4 operator -(Int4 value) => .(-value.X, -value.Y, -value.Z, -value.W);
public static Int4 operator -(Int4 left, Int4 right) => .(left.X - right.X, left.Y - right.Y, left.Z - right.Z, left.W - right.W);
public static Int4 operator -(Int4 left, int32 right) => .(left.X - right, left.Y - right, left.Z - right, left.W - right);
public static Int4 operator -(int32 left, Int4 right) => .(left - right.X, left - right.Y, left - right.Z, left - right.W);
public static Int4 operator *(Int4 left, Int4 right) => .(left.X * right.X, left.Y * right.Y, left.Z * right.Z, left.W * right.W);
public static Int4 operator *(Int4 left, int32 right) => .(left.X * right, left.Y * right, left.Z * right, left.W * right);
public static Int4 operator *(int32 left, Int4 right) => .(left * right.X, left * right.Y, left * right.Z, left * right.W);
public static Int4 operator /(Int4 left, Int4 right) => .(left.X / right.X, left.Y / right.Y, left.Z / right.Z, left.W / right.W);
public static Int4 operator /(Int4 left, int32 right) => .(left.X / right, left.Y / right, left.Z / right, left.W / right);
public static Int4 operator /(int32 left, Int4 right) => .(left / right.X, left / right.Y, left / right.Z, left / right.W);
public static Int4 operator %(Int4 left, Int4 right) => .(left.X % right.X, left.Y % right.Y, left.Z % right.Z, left.W % right.W);
public static Int4 operator %(Int4 left, int32 right) => .(left.X % right, left.Y % right, left.Z % right, left.W % right);
public static Int4 operator %(int32 left, Int4 right) => .(left % right.X, left % right.Y, left % right.Z, left % right.W);
public static bool operator ==(Int4 left, Int4 right) => left.X == right.X && left.Y == right.Y && left.Z == right.Z && left.W == right.W;
public static bool operator ==(Int4 left, int32 right) => left.X == right && left.Y == right && left.Z == right && left.W == right;
public static bool operator ==(int32 left, Int4 right) => left == right.X && left == right.Y && left == right.Z && left == right.W;
public static bool operator !=(Int4 left, Int4 right) => left.X != right.X || left.Y != right.Y || left.Z != right.Z || left.W != right.W;
public static bool operator !=(Int4 left, int32 right) => left.X != right || left.Y != right || left.Z != right || left.W != right;
public static bool operator !=(int32 left, Int4 right) => left != right.X || left != right.Y || left != right.Z || left != right.W;
public override void ToString(String strBuffer) => strBuffer.AppendF($"X:{X} Y:{Y} Z:{Z} W:{W}");
public static explicit operator Vector4(Int4 point) => .(point.X, point.Y, point.Z, point.W);
public static explicit operator Int4(Vector4 point) => .((int32)point.X, (int32)point.Y, (int32)point.Z, (int32)point.W);
[Inline]
public static explicit operator Int2(in Int4 point) => *(Int2*)&point;
[Inline]
public static explicit operator Int3(in Int4 point) => *(Int3*)&point;
public int GetHashCode()
{
return (((((X * 39) ^ Y) * 39) ^ Z) * 39) ^ W;
}
}
}
+27
View File
@@ -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
{
}
+113
View File
@@ -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);
}
}
+83
View File
@@ -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);
}
}
+312
View File
@@ -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;
}
}
+43
View File
@@ -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);
}
}
+148
View File
@@ -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;
@@ -12,8 +12,8 @@ namespace GlitchyEngine
private float _aspectRatio; private float _aspectRatio;
private float _fovY = Math.PI_f / 4; private float _fovY = Math.PI_f / 4;
private Vector3 _cameraPosition; private float3 _cameraPosition;
private Vector3 _cameraRotation; private float3 _cameraRotation;
private float _cameraTranslationSpeed = 1.0f; private float _cameraTranslationSpeed = 1.0f;
private float _cameraRotationSpeedX = 0.001f; private float _cameraRotationSpeedX = 0.001f;
@@ -27,7 +27,7 @@ namespace GlitchyEngine
set => _cameraTranslationSpeed = value; set => _cameraTranslationSpeed = value;
} }
public Vector2 RotationSpeed public float2 RotationSpeed
{ {
get => .(_cameraRotationSpeedX, _cameraRotationSpeedY); get => .(_cameraRotationSpeedX, _cameraRotationSpeedY);
set set
@@ -37,7 +37,7 @@ namespace GlitchyEngine
} }
} }
public Vector3 CameraPosition public float3 CameraPosition
{ {
get => _cameraPosition; get => _cameraPosition;
set set
@@ -48,7 +48,7 @@ namespace GlitchyEngine
} }
} }
public Vector3 CameraRotation public float3 CameraRotation
{ {
get => _cameraRotation; get => _cameraRotation;
set set
@@ -100,7 +100,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))
{ {
@@ -129,14 +129,14 @@ namespace GlitchyEngine
movement.Y -= 1; movement.Y -= 1;
} }
if(movement != .Zero) if(any(movement != .Zero))
movement.Normalize(); normalize(movement);
movement *= (float)(gameTime.FrameTime.TotalSeconds) * _cameraTranslationSpeed; movement *= (float)(gameTime.FrameTime.TotalSeconds) * _cameraTranslationSpeed;
Vector4 delta = Vector4(movement, 1.0f) * _camera.View; float4 delta = float4(movement, 1.0f) * _camera.View;
_cameraPosition += Vector3(delta.X, delta.Y, delta.Z); _cameraPosition += float3(delta.X, delta.Y, delta.Z);
//_cameraPosition += movement; //_cameraPosition += movement;
// Camera rotation // Camera rotation
@@ -8,6 +8,7 @@ using DirectX.Common;
using DirectX.D3D11; using DirectX.D3D11;
using DirectX.D3D11.SDKLayers; using DirectX.D3D11.SDKLayers;
using System.Diagnostics; using System.Diagnostics;
using System.Threading;
namespace GlitchyEngine.Platform.DX11 namespace GlitchyEngine.Platform.DX11
{ {
@@ -18,6 +19,8 @@ namespace GlitchyEngine.Platform.DX11
protected internal static ID3D11Device* NativeDevice; protected internal static ID3D11Device* NativeDevice;
protected internal static ID3D11DeviceContext* NativeContext; protected internal static ID3D11DeviceContext* NativeContext;
protected internal static Monitor ContextMonitor = new Monitor() ~ delete _;
#if DEBUG #if DEBUG
protected internal static ID3D11Debug* DebugDevice; protected internal static ID3D11Debug* DebugDevice;
#endif #endif
@@ -42,7 +45,10 @@ namespace GlitchyEngine.Platform.DX11
HResult deviceResult; HResult deviceResult;
{ {
Debug.Profiler.ProfileScope!("D3D11.CreateDevice"); Debug.Profiler.ProfileScope!("D3D11.CreateDevice");
deviceResult = D3D11.CreateDevice(null, .Hardware, 0, deviceFlags, levels, &NativeDevice, &deviceLevel, &NativeContext); using (ContextMonitor.Enter())
{
deviceResult = D3D11.CreateDevice(null, .Hardware, 0, deviceFlags, levels, &NativeDevice, &deviceLevel, &NativeContext);
}
} }
Log.EngineLogger.Assert(deviceResult.Succeeded, scope $"Failed to create D3D11 Device. Message({(int32)deviceResult}): {deviceResult}"); Log.EngineLogger.Assert(deviceResult.Succeeded, scope $"Failed to create D3D11 Device. Message({(int32)deviceResult}): {deviceResult}");
@@ -22,12 +22,24 @@ namespace ImGui
textureViewBinding.Release(); textureViewBinding.Release();
} }
public static override bool ImageButton(TextureViewBinding textureViewBinding, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, int32 frame_padding = -1, Vec4 bg_col = Vec4.Zero, Vec4 tint_col = Vec4.Ones) public static override bool ImageButton(char8* id, TextureViewBinding textureViewBinding, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, Vec4 bg_col = Vec4.Zero, Vec4 tint_col = Vec4.Ones)
{ {
var view = textureViewBinding._nativeShaderResourceView..AddRef(); var view = textureViewBinding._nativeShaderResourceView..AddRef();
_resourceViews.Add(view); _resourceViews.Add(view);
bool pressed = ImGui.ImageButton(view, size, uv0, uv1, frame_padding, bg_col, tint_col); bool pressed = ImGui.ImageButton(id, view, size, uv0, uv1, bg_col, tint_col);
textureViewBinding.Release();
return pressed;
}
public static override bool ImageButtonEx(uint32 id, TextureViewBinding textureViewBinding, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, Vec4 bg_col = Vec4.Zero, Vec4 tint_col = Vec4.Ones)
{
var view = textureViewBinding._nativeShaderResourceView..AddRef();
_resourceViews.Add(view);
bool pressed = ImGui.ImageButtonEx(id, view, size, uv0, uv1, bg_col, tint_col);
textureViewBinding.Release(); textureViewBinding.Release();
@@ -8,7 +8,7 @@ using Bon;
namespace GlitchyEngine.Math namespace GlitchyEngine.Math
{ {
extension Vector2 extension float2
{ {
[Inline] [Inline]
public static implicit operator DirectX.Math.Vector2(in Self value) => *(DirectX.Math.Vector2*)&value; public static implicit operator DirectX.Math.Vector2(in Self value) => *(DirectX.Math.Vector2*)&value;
@@ -17,7 +17,7 @@ namespace GlitchyEngine.Math
public static implicit operator Self(in DirectX.Math.Vector2 value) => *(Self*)&value; public static implicit operator Self(in DirectX.Math.Vector2 value) => *(Self*)&value;
} }
extension Vector3 extension float3
{ {
[Inline] [Inline]
public static implicit operator DirectX.Math.Vector3(in Self value) => *(DirectX.Math.Vector3*)&value; public static implicit operator DirectX.Math.Vector3(in Self value) => *(DirectX.Math.Vector3*)&value;
@@ -26,7 +26,7 @@ namespace GlitchyEngine.Math
public static implicit operator Self(in DirectX.Math.Vector3 value) => *(Self*)&value; public static implicit operator Self(in DirectX.Math.Vector3 value) => *(Self*)&value;
} }
extension Vector4 extension float4
{ {
[Inline] [Inline]
public static implicit operator DirectX.Math.Vector4(in Self value) => *(DirectX.Math.Vector4*)&value; public static implicit operator DirectX.Math.Vector4(in Self value) => *(DirectX.Math.Vector4*)&value;
@@ -100,14 +100,24 @@ namespace GlitchyEngine.Renderer
{ {
case .Default: case .Default:
Box dataBox = .(dstByteOffset, 0, 0, dstByteOffset + byteLength, 1, 1); Box dataBox = .(dstByteOffset, 0, 0, dstByteOffset + byteLength, 1, 1);
NativeContext.UpdateSubresource(nativeBuffer, 0, &dataBox, data, byteLength, byteLength); using (ContextMonitor.Enter())
{
NativeContext.UpdateSubresource(nativeBuffer, 0, &dataBox, data, byteLength, byteLength);
}
case .Dynamic: case .Dynamic:
Log.EngineLogger.Assert(mapType == .WriteDiscard || mapType == .WriteNoOverwrite, scope $"When writing to dynamic resources the map type must be {nameof(Renderer.MapType.WriteDiscard)} or {nameof(Renderer.MapType.WriteNoOverwrite)}."); Log.EngineLogger.Assert(mapType == .WriteDiscard || mapType == .WriteNoOverwrite, scope $"When writing to dynamic resources the map type must be {nameof(Renderer.MapType.WriteDiscard)} or {nameof(Renderer.MapType.WriteNoOverwrite)}.");
// Todo: DoNotWaitFlag // Todo: DoNotWaitFlag
MappedSubresource map = ?; MappedSubresource map = ?;
NativeContext.Map(nativeBuffer, 0, (.)mapType, .None, &map); using (ContextMonitor.Enter())
{
NativeContext.Map(nativeBuffer, 0, (.)mapType, .None, &map);
}
Internal.MemCpy(((uint8*)map.Data) + dstByteOffset, data, byteLength); Internal.MemCpy(((uint8*)map.Data) + dstByteOffset, data, byteLength);
NativeContext.Unmap(nativeBuffer, 0);
using (ContextMonitor.Enter())
{
NativeContext.Unmap(nativeBuffer, 0);
}
case .Immutable: case .Immutable:
Log.EngineLogger.Error("Can't set the data of an immutable resource."); Log.EngineLogger.Error("Can't set the data of an immutable resource.");
return .Err; return .Err;
@@ -81,12 +81,15 @@ namespace GlitchyEngine.Renderer
{ {
Debug.Profiler.ProfileRendererFunction!(); Debug.Profiler.ProfileRendererFunction!();
NativeContext.InputAssembler.SetVertexBuffers(0, nativeBuffers.Count, &nativeBuffers, &bufferStrides, &bufferOffsets); using (ContextMonitor.Enter())
GraphicsContext.Get().SetVertexLayout(_vertexLayout); {
NativeContext.InputAssembler.SetPrimitiveTopology((.)_primitiveTopology); NativeContext.InputAssembler.SetVertexBuffers(0, nativeBuffers.Count, &nativeBuffers, &bufferStrides, &bufferOffsets);
GraphicsContext.Get().SetVertexLayout(_vertexLayout);
NativeContext.InputAssembler.SetPrimitiveTopology((.)_primitiveTopology);
if(_indexBuffer != null) if(_indexBuffer != null)
NativeContext.InputAssembler.SetIndexBuffer(_indexBuffer.nativeBuffer, _indexBuffer.Format == .Index32Bit ? .R32_UInt : .R16_UInt, _indexByteOffset); NativeContext.InputAssembler.SetIndexBuffer(_indexBuffer.nativeBuffer, _indexBuffer.Format == .Index32Bit ? .R32_UInt : .R16_UInt, _indexByteOffset);
}
} }
public override void Unbind() public override void Unbind()
@@ -97,11 +100,14 @@ namespace GlitchyEngine.Renderer
uint32[nativeBuffers.Count] zeroStrides = .(); uint32[nativeBuffers.Count] zeroStrides = .();
uint32[nativeBuffers.Count] zeroOffsets = .(); uint32[nativeBuffers.Count] zeroOffsets = .();
NativeContext.InputAssembler.SetVertexBuffers(0, nativeBuffers.Count, &nullBuffers, &zeroStrides, &zeroOffsets); using (ContextMonitor.Enter())
NativeContext.InputAssembler.SetInputLayout(null); {
NativeContext.InputAssembler.SetPrimitiveTopology(.Undefined); NativeContext.InputAssembler.SetVertexBuffers(0, nativeBuffers.Count, &nullBuffers, &zeroStrides, &zeroOffsets);
NativeContext.InputAssembler.SetInputLayout(null);
NativeContext.InputAssembler.SetPrimitiveTopology(.Undefined);
NativeContext.InputAssembler.SetIndexBuffer(null, .R16_UNorm, 0); NativeContext.InputAssembler.SetIndexBuffer(null, .R16_UNorm, 0);
}
} }
} }
} }
@@ -158,19 +158,28 @@ namespace GlitchyEngine.Renderer
public override void BindRenderTargets() public override void BindRenderTargets()
{ {
NativeContext.OutputMerger.SetRenderTargets(MaxRTVCount, &_renderTargets, _depthStencilTarget); using (ContextMonitor.Enter())
{
NativeContext.OutputMerger.SetRenderTargets(MaxRTVCount, &_renderTargets, _depthStencilTarget);
}
} }
public override void ClearRenderTarget(RenderTarget2D renderTarget, ColorRGBA color) public override void ClearRenderTarget(RenderTarget2D renderTarget, ColorRGBA color)
{ {
NativeContext.ClearRenderTargetView((renderTarget ?? _swapChain.BackBuffer)._nativeRenderTargetView, color); using (ContextMonitor.Enter())
{
NativeContext.ClearRenderTargetView((renderTarget ?? _swapChain.BackBuffer)._nativeRenderTargetView, color);
}
} }
public override void SetVertexBuffer(uint32 slot, Buffer buffer, uint32 stride, uint32 offset = 0) public override void SetVertexBuffer(uint32 slot, Buffer buffer, uint32 stride, uint32 offset = 0)
{ {
// make stride and offset mutable so that we can take their pointers. // make stride and offset mutable so that we can take their pointers.
var stride, offset; var stride, offset;
NativeContext.InputAssembler.SetVertexBuffers(slot, 1, &buffer.nativeBuffer, &stride, &offset); using (ContextMonitor.Enter())
{
NativeContext.InputAssembler.SetVertexBuffers(slot, 1, &buffer.nativeBuffer, &stride, &offset);
}
} }
[Inline] [Inline]
@@ -181,7 +190,10 @@ namespace GlitchyEngine.Renderer
_currentInputLayout = _currentVertexLayout.GetNativeVertexLayout(_currentVertexShader.nativeCode); _currentInputLayout = _currentVertexLayout.GetNativeVertexLayout(_currentVertexShader.nativeCode);
_currentInputLayout.AddRef(); _currentInputLayout.AddRef();
NativeContext.InputAssembler.SetInputLayout(_currentInputLayout); using (ContextMonitor.Enter())
{
NativeContext.InputAssembler.SetInputLayout(_currentInputLayout);
}
} }
} }
@@ -200,33 +212,48 @@ namespace GlitchyEngine.Renderer
public override void Draw(uint32 vertexCount, uint32 startVertexIndex = 0) public override void Draw(uint32 vertexCount, uint32 startVertexIndex = 0)
{ {
BindState(); using (ContextMonitor.Enter())
{
BindState();
NativeContext.Draw(vertexCount, startVertexIndex); NativeContext.Draw(vertexCount, startVertexIndex);
}
} }
public override void DrawIndexed(uint32 indexCount, uint32 startIndexLocation = 0, int32 vertexOffset = 0) public override void DrawIndexed(uint32 indexCount, uint32 startIndexLocation = 0, int32 vertexOffset = 0)
{ {
BindState(); using (ContextMonitor.Enter())
{
BindState();
NativeContext.DrawIndexed(indexCount, startIndexLocation, vertexOffset); NativeContext.DrawIndexed(indexCount, startIndexLocation, vertexOffset);
}
} }
public override void DrawIndexedInstanced(uint32 indexCountPerInstance, uint32 instanceCount, uint32 startIndexLocation, int32 baseVertexLocation, uint32 startInstanceLocation) public override void DrawIndexedInstanced(uint32 indexCountPerInstance, uint32 instanceCount, uint32 startIndexLocation, int32 baseVertexLocation, uint32 startInstanceLocation)
{ {
BindState(); using (ContextMonitor.Enter())
{
BindState();
NativeContext.DrawIndexedInstanced(indexCountPerInstance, instanceCount, startIndexLocation, baseVertexLocation, startInstanceLocation); NativeContext.DrawIndexedInstanced(indexCountPerInstance, instanceCount, startIndexLocation, baseVertexLocation, startInstanceLocation);
}
} }
public override void SetIndexBuffer(Buffer buffer, IndexFormat indexFormat = .Index16Bit, uint32 byteOffset = 0) public override void SetIndexBuffer(Buffer buffer, IndexFormat indexFormat = .Index16Bit, uint32 byteOffset = 0)
{ {
NativeContext.InputAssembler.SetIndexBuffer(buffer.nativeBuffer, indexFormat == .Index32Bit ? .R32_UInt : .R16_UInt, byteOffset); using (ContextMonitor.Enter())
{
NativeContext.InputAssembler.SetIndexBuffer(buffer.nativeBuffer, indexFormat == .Index32Bit ? .R32_UInt : .R16_UInt, byteOffset);
}
} }
public override void SetViewports(uint32 viewportsCount, GlitchyEngine.Renderer.Viewport* viewports) public override void SetViewports(uint32 viewportsCount, GlitchyEngine.Renderer.Viewport* viewports)
{ {
NativeContext.Rasterizer.SetViewports(viewportsCount, (.)viewports); using (ContextMonitor.Enter())
{
NativeContext.Rasterizer.SetViewports(viewportsCount, (.)viewports);
}
} }
public override void SetVertexLayout(VertexLayout vertexLayout) public override void SetVertexLayout(VertexLayout vertexLayout)
@@ -241,7 +268,10 @@ namespace GlitchyEngine.Renderer
public override void SetPrimitiveTopology(GlitchyEngine.Renderer.PrimitiveTopology primitiveTopology) public override void SetPrimitiveTopology(GlitchyEngine.Renderer.PrimitiveTopology primitiveTopology)
{ {
NativeContext.InputAssembler.SetPrimitiveTopology((DirectX.Common.PrimitiveTopology)primitiveTopology); using (ContextMonitor.Enter())
{
NativeContext.InputAssembler.SetPrimitiveTopology((DirectX.Common.PrimitiveTopology)primitiveTopology);
}
} }
private uint32 _ps_FirstTexture; private uint32 _ps_FirstTexture;
@@ -344,18 +374,27 @@ namespace GlitchyEngine.Renderer
{ {
void** voidArray = scope void*[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT]*; void** voidArray = scope void*[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT]*;
NativeContext.PixelShader.SetShaderResources(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, (.)voidArray); using (ContextMonitor.Enter())
NativeContext.VertexShader.SetShaderResources(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, (.)voidArray); {
NativeContext.PixelShader.SetShaderResources(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, (.)voidArray);
NativeContext.VertexShader.SetShaderResources(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, (.)voidArray);
}
} }
public override void BindVertexShader(VertexShader vertexShader) public override void BindVertexShader(VertexShader vertexShader)
{ {
BindShaderToStage(vertexShader); using (ContextMonitor.Enter())
{
BindShaderToStage(vertexShader);
}
} }
public override void BindPixelShader(PixelShader pixelShader) public override void BindPixelShader(PixelShader pixelShader)
{ {
BindShaderToStage(pixelShader); using (ContextMonitor.Enter())
{
BindShaderToStage(pixelShader);
}
} }
public override void BindConstantBuffer(Buffer buffer, int slot, ShaderStage stage) public override void BindConstantBuffer(Buffer buffer, int slot, ShaderStage stage)
@@ -444,11 +444,24 @@ namespace GlitchyEngine.Renderer
Box srcBox = .(x, y, arraySlice, x + width, y + height, arraySlice + 1); Box srcBox = .(x, y, arraySlice, x + width, y + height, arraySlice + 1);
NativeContext.CopySubresourceRegion(stagingTexture, 0, 0, 0, 0, texture, srcSubResource, &srcBox); using (ContextMonitor.Enter())
{
NativeContext.CopySubresourceRegion(stagingTexture, 0, 0, 0, 0, texture, srcSubResource, &srcBox);
}
MappedSubresource subresource = ?; MappedSubresource subresource = ?;
result = NativeContext.Map(stagingTexture, 0, .Read, .None, &subresource); using (ContextMonitor.Enter())
defer NativeContext.Unmap(stagingTexture, 0); {
result = NativeContext.Map(stagingTexture, 0, .Read, .None, &subresource);
}
defer
{
using (ContextMonitor.Enter())
{
NativeContext.Unmap(stagingTexture, 0);
}
}
if (result != 0) if (result != 0)
return .Err; return .Err;
@@ -466,7 +479,7 @@ namespace GlitchyEngine.Renderer
return .Ok; return .Ok;
} }
public override void CopyTo(RenderTargetGroup destination, int dstTarget, Int2 dstTopLeft, Int2 size, Int2 srcTopLeft, int srcTarget) public override void CopyTo(RenderTargetGroup destination, int dstTarget, int2 dstTopLeft, int2 size, int2 srcTopLeft, int srcTarget)
{ {
ID3D11Texture2D* dstTexture = destination.GetNativeTexture(dstTarget); ID3D11Texture2D* dstTexture = destination.GetNativeTexture(dstTarget);
ID3D11Texture2D* srcTexture = GetNativeTexture(srcTarget); ID3D11Texture2D* srcTexture = GetNativeTexture(srcTarget);
@@ -475,7 +488,10 @@ namespace GlitchyEngine.Renderer
Box srcBox = .((.)srcTopLeft.X, (.)srcTopLeft.Y, 0, (.)(srcTopLeft.X + size.X), (.)(srcTopLeft.Y + size.Y), 1); Box srcBox = .((.)srcTopLeft.X, (.)srcTopLeft.Y, 0, (.)(srcTopLeft.X + size.X), (.)(srcTopLeft.Y + size.Y), 1);
NativeContext.CopySubresourceRegion(dstTexture, 0, (.)dstTopLeft.X, (.)dstTopLeft.Y, 0, srcTexture, 0, &srcBox); using (ContextMonitor.Enter())
{
NativeContext.CopySubresourceRegion(dstTexture, 0, (.)dstTopLeft.X, (.)dstTopLeft.Y, 0, srcTexture, 0, &srcBox);
}
} }
} }
} }
@@ -45,7 +45,10 @@ namespace GlitchyEngine.Renderer
{ {
Debug.Profiler.ProfileRendererFunction!(); Debug.Profiler.ProfileRendererFunction!();
NativeContext.ClearRenderTargetView(RtOrBackbuffer!(renderTarget)._nativeRenderTargetView, color); using (ContextMonitor.Enter())
{
NativeContext.ClearRenderTargetView(RtOrBackbuffer!(renderTarget)._nativeRenderTargetView, color);
}
} }
public override void Clear(DepthStencilTarget target, ClearOptions clearOptions, float depth, uint8 stencil) public override void Clear(DepthStencilTarget target, ClearOptions clearOptions, float depth, uint8 stencil)
@@ -67,36 +70,42 @@ namespace GlitchyEngine.Renderer
flags |= .Stencil; flags |= .Stencil;
} }
NativeContext.ClearDepthStencilView(target.nativeView, flags, depth, stencil); using (ContextMonitor.Enter())
{
NativeContext.ClearDepthStencilView(target.nativeView, flags, depth, stencil);
}
} }
private void ClearRtv(DirectX.D3D11.ID3D11RenderTargetView* rtv, ClearColor clearColor) private void ClearRtv(DirectX.D3D11.ID3D11RenderTargetView* rtv, ClearColor clearColor)
{ {
switch(clearColor) using (ContextMonitor.Enter())
{ {
case .Color(let color): switch(clearColor)
NativeContext.ClearRenderTargetView(rtv, color);
case .UInt(let value):
#unwarn
NativeContext.OutputMerger.SetRenderTargets(1, &rtv, null);
using (BlendState lastBlendState = _currentBlendState..AddRef())
{ {
SetBlendState(_nonblendingState); case .Color(let color):
NativeContext.ClearRenderTargetView(rtv, color);
case .UInt(let value):
#unwarn
NativeContext.OutputMerger.SetRenderTargets(1, &rtv, null);
_clearUintFx.Variables["ClearValue"].SetData(value); using (BlendState lastBlendState = _currentBlendState..AddRef())
_clearUintFx.ApplyChanges(); {
_clearUintFx.Bind(); SetBlendState(_nonblendingState);
FullscreenQuad.Draw(); _clearUintFx.Variables["ClearValue"].SetData(value);
_clearUintFx.ApplyChanges();
_clearUintFx.Bind();
SetBlendState(lastBlendState); FullscreenQuad.Draw();
SetBlendState(lastBlendState);
}
// Rebind the old render targets
BindRenderTargets();
default:
Runtime.NotImplemented();
} }
// Rebind the old render targets
BindRenderTargets();
default:
Runtime.NotImplemented();
} }
} }
@@ -143,7 +152,10 @@ namespace GlitchyEngine.Renderer
clearDepth = depth ?? clearDepth; clearDepth = depth ?? clearDepth;
clearStencil = stencil ?? clearStencil; clearStencil = stencil ?? clearStencil;
NativeContext.ClearDepthStencilView(renderTarget._nativeDepthTargetView, flags, clearDepth, clearStencil); using (ContextMonitor.Enter())
{
NativeContext.ClearDepthStencilView(renderTarget._nativeDepthTargetView, flags, clearDepth, clearStencil);
}
} }
} }
} }
@@ -199,7 +211,10 @@ namespace GlitchyEngine.Renderer
Debug.Profiler.ProfileRendererFunction!(); Debug.Profiler.ProfileRendererFunction!();
SetReference!(_currentRasterizerState, rasterizerState); SetReference!(_currentRasterizerState, rasterizerState);
NativeContext.Rasterizer.SetState(_currentRasterizerState.nativeRasterizerState); using (ContextMonitor.Enter())
{
NativeContext.Rasterizer.SetState(_currentRasterizerState.nativeRasterizerState);
}
} }
private BlendState _currentBlendState ~ _?.ReleaseRef(); private BlendState _currentBlendState ~ _?.ReleaseRef();
@@ -209,7 +224,11 @@ namespace GlitchyEngine.Renderer
Debug.Profiler.ProfileRendererFunction!(); Debug.Profiler.ProfileRendererFunction!();
SetReference!(_currentBlendState, blendState); SetReference!(_currentBlendState, blendState);
NativeContext.OutputMerger.SetBlendState(_currentBlendState.nativeBlendState, blendFactor);
using (ContextMonitor.Enter())
{
NativeContext.OutputMerger.SetBlendState(_currentBlendState.nativeBlendState, blendFactor);
}
} }
private DepthStencilState _currentDepthStencilState ~ _?.ReleaseRef(); private DepthStencilState _currentDepthStencilState ~ _?.ReleaseRef();
@@ -219,7 +238,11 @@ namespace GlitchyEngine.Renderer
Debug.Profiler.ProfileRendererFunction!(); Debug.Profiler.ProfileRendererFunction!();
SetReference!(_currentDepthStencilState, depthStencilState); SetReference!(_currentDepthStencilState, depthStencilState);
NativeContext.OutputMerger.SetDepthStencilState(_currentDepthStencilState.nativeDepthStencilState, stencilReference);
using (ContextMonitor.Enter())
{
NativeContext.OutputMerger.SetDepthStencilState(_currentDepthStencilState.nativeDepthStencilState, stencilReference);
}
} }
public override void DrawIndexed(GeometryBinding geometry) public override void DrawIndexed(GeometryBinding geometry)
@@ -122,8 +122,11 @@ namespace GlitchyEngine.Renderer
public override void Bind(uint32 slot) public override void Bind(uint32 slot)
{ {
NativeContext.VertexShader.SetSamplers(slot, 1, &nativeSamplerState); using (ContextMonitor.Enter())
NativeContext.PixelShader.SetSamplers(slot, 1, &nativeSamplerState); {
NativeContext.VertexShader.SetSamplers(slot, 1, &nativeSamplerState);
NativeContext.PixelShader.SetSamplers(slot, 1, &nativeSamplerState);
}
} }
} }
} }
@@ -205,7 +205,30 @@ namespace GlitchyEngine.Renderer
buffer.ReleaseRef(); buffer.ReleaseRef();
} }
case .Texture: case .Texture:
_textures.Add(scope String(bindDesc.Name), bindDesc.BindPoint, TextureViewBinding(null, null));
TextureDimension texDim;
switch (bindDesc.Dimension)
{
case .Texture1D:
texDim = .Texture1D;
case .Texture1DArray:
texDim = .Texture1DArray;
case .Texture2D:
texDim = .Texture2D;
case .Texture2DArray:
texDim = .Texture2DArray;
case .Texture3D:
texDim = .Texture3D;
case .TextureCube:
texDim = .TextureCube;
case .TextureCubeArray:
texDim = .TextureCubeArray;
default:
texDim = .Unknown;
}
_textures.Add(scope String(bindDesc.Name), bindDesc.BindPoint, TextureViewBinding(null, null), texDim);
case .Sampler: case .Sampler:
// TODO: do we have to do something for samplers? // TODO: do we have to do something for samplers?
default: default:
@@ -19,43 +19,6 @@ namespace GlitchyEngine.Renderer
extension Texture extension Texture
{ {
protected internal ID3D11ShaderResourceView* _nativeResourceView ~ _?.Release(); protected internal ID3D11ShaderResourceView* _nativeResourceView ~ _?.Release();
/** \brief Loads the texture from the specified path.
* @param path The path of the texture to load.
* @param texture The reference to the pointer that will hold the texture.
* @returns true if the texture was loaded successfully; false otherwise.
*/
protected bool LoadDdsResourcePlatform<T>(Stream stream, ref T* texture) where T : ID3D11Resource
{
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}");
}
((ID3D11Resource*)texture)?.Release();
_nativeResourceView?.Release();
HResult loadResult = DDSTextureLoader.CreateDDSTextureFromMemory(NativeDevice,
ddsData.Ptr, (uint)ddsData.Count, (.)&texture, &_nativeResourceView);
if(loadResult.Failed)
{
Log.EngineLogger.Error($"Failed to load texture. Error({(int)loadResult}): {loadResult}");
ReleaseAndNullify!(texture);
ReleaseAndNullify!(_nativeResourceView);
return false;
}
return true;
}
} }
extension Texture2DDesc extension Texture2DDesc
@@ -93,43 +56,65 @@ namespace GlitchyEngine.Renderer
public override uint32 Height => nativeDesc.Height; public override uint32 Height => nativeDesc.Height;
public override uint32 ArraySize => nativeDesc.ArraySize; public override uint32 ArraySize => nativeDesc.ArraySize;
public override uint32 MipLevels => nativeDesc.MipLevels; public override uint32 MipLevels => nativeDesc.MipLevels;
public override Format Format => nativeDesc.Format;
protected override void LoadDdsPlatform(Stream stream)
{
Debug.Profiler.ProfileResourceFunction!();
LoadDdsResourcePlatform(stream, ref nativeTexture); /*protected override void CreateTexturePlatform(Texture2DDesc desc, bool isRenderTarget, void* data, uint32 linePitch)
let resType = nativeTexture.GetResourceType();
Log.EngineLogger.Assert(resType == .Texture2D, scope $"The texture is not a 2D texture (it is {resType}).");
nativeTexture.GetDescription(out nativeDesc);
}
protected override void CreateTexturePlatform(Texture2DDesc desc, bool isRenderTarget, void* data, uint32 linePitch)
{ {
Debug.Profiler.ProfileResourceFunction!(); Debug.Profiler.ProfileResourceFunction!();
PrepareTexturePlatform(desc, isRenderTarget); PrepareTexturePlatform(desc, isRenderTarget);
InternalCreateTexture(data, linePitch, 0); InternalCreateTexture(data, linePitch, 0);
} }*/
private void InternalCreateTexture(void* data, uint32 linePitch, uint32 slicePitch) /// Creates the native texture. Initializes it, if slices is not null and has enough Entries to fill all slices.
/// @returns true if the texture has been initialized; false otherwise.
private bool InternalCreateTexture(Span<TextureSliceData> slices)
{ {
Debug.Profiler.ProfileResourceFunction!(); Debug.Profiler.ProfileResourceFunction!();
SubresourceData resData = .(data, linePitch, slicePitch); SubresourceData[] data = null;
// If data is null, set subresourceData null if (slices.Length == MipLevels * ArraySize)
SubresourceData* resDataPtr = data == null ? null : &resData; {
data = scope:: SubresourceData[slices.Length];
var result = NativeDevice.CreateTexture2D(ref nativeDesc, resDataPtr, &nativeTexture); for (int i < slices.Length)
{
TextureSliceData slice = slices[i];
data[i] = .(slice.Data, slice.LinePitch, slice.SlicePitch);
}
}
var result = NativeDevice.CreateTexture2D(ref nativeDesc, data?.Ptr, &nativeTexture);
Log.EngineLogger.Assert(result.Succeeded, scope $"Failed to create texture 2D. Error ({result.Underlying}): {result}"); Log.EngineLogger.Assert(result.Succeeded, scope $"Failed to create texture 2D. Error ({result.Underlying}): {result}");
result = NativeDevice.CreateShaderResourceView(nativeTexture, null, &_nativeResourceView); result = NativeDevice.CreateShaderResourceView(nativeTexture, null, &_nativeResourceView);
Log.EngineLogger.Assert(result.Succeeded, scope $"Failed to create texture view. Error ({result.Underlying}): {result}"); Log.EngineLogger.Assert(result.Succeeded, scope $"Failed to create texture view. Error ({result.Underlying}): {result}");
// If Data is non-null the texture got initialized with data.
return (data != null);
} }
/*private void InternalCreateTexture(void* data, uint32 linePitch, uint32 slicePitch)
{
Debug.Profiler.ProfileResourceFunction!();
/*SubresourceData resData = .(data, linePitch, slicePitch);
// If data is null, set subresourceData null
SubresourceData* resDataPtr = data == null ? null : &resData;*/
SubresourceData[2] resData = .(.(data, linePitch, slicePitch), .(null, 0, 0));
var result = NativeDevice.CreateTexture2D(ref nativeDesc, &resData, &nativeTexture);
Log.EngineLogger.Assert(result.Succeeded, scope $"Failed to create texture 2D. Error ({result.Underlying}): {result}");
result = NativeDevice.CreateShaderResourceView(nativeTexture, null, &_nativeResourceView);
Log.EngineLogger.Assert(result.Succeeded, scope $"Failed to create texture view. Error ({result.Underlying}): {result}");
}*/
protected override void PrepareTexturePlatform(Texture2DDesc desc, bool isRenderTarget) protected override void PrepareTexturePlatform(Texture2DDesc desc, bool isRenderTarget)
{ {
Debug.Profiler.ProfileResourceFunction!(); Debug.Profiler.ProfileResourceFunction!();
@@ -145,6 +130,26 @@ namespace GlitchyEngine.Renderer
nativeDesc.BindFlags |= .RenderTarget; nativeDesc.BindFlags |= .RenderTarget;
} }
protected override Result<void> PlatformSetData(Span<TextureSliceData> slices)
{
Debug.Profiler.ProfileResourceFunction!();
if(nativeTexture == null)
{
if (InternalCreateTexture(slices))
return .Ok;
}
Runtime.NotImplemented();
/*int index = firstArraySlice;
for (TextureSliceData slice in slices)
{
}*/
}
// TODO: Update Texture Arrays! // TODO: Update Texture Arrays!
protected override Result<void> PlatformSetData(void* data, uint32 elementSize, uint32 destX, protected override Result<void> PlatformSetData(void* data, uint32 elementSize, uint32 destX,
uint32 destY, uint32 destWidth, uint32 destHeight, uint32 arraySlice, uint32 mipLevel, GlitchyEngine.Renderer.MapType mapType) uint32 destY, uint32 destWidth, uint32 destHeight, uint32 arraySlice, uint32 mipLevel, GlitchyEngine.Renderer.MapType mapType)
@@ -153,6 +158,21 @@ namespace GlitchyEngine.Renderer
if(nativeTexture == null) if(nativeTexture == null)
{ {
if(destX == 0 && destY == 0 && destWidth == nativeDesc.Width && destHeight == nativeDesc.Height &&
arraySlice == 0 && mipLevel == 0 && ArraySize == 1 && MipLevels == 1)
{
TextureSliceData[1] dataSlice = .(.(data, elementSize * destWidth, elementSize * destWidth * destHeight));
// Turns out we need to initialize all slices at once or none... so... tough shit, we cant early out here.
if (InternalCreateTexture(dataSlice))
return .Ok;
}
else
{
InternalCreateTexture(null);
}
/* Old shit follows...
if(destX == 0 && destY == 0 && destWidth == nativeDesc.Width && destHeight == nativeDesc.Height) if(destX == 0 && destY == 0 && destWidth == nativeDesc.Width && destHeight == nativeDesc.Height)
{ {
// We can pass the data while creating the buffer, so we can return here. // We can pass the data while creating the buffer, so we can return here.
@@ -165,6 +185,7 @@ namespace GlitchyEngine.Renderer
Log.EngineLogger.Assert(nativeDesc.Usage != .Immutable, "The entire immutable texture has to be initialized."); Log.EngineLogger.Assert(nativeDesc.Usage != .Immutable, "The entire immutable texture has to be initialized.");
InternalCreateTexture(null, 0, 0); InternalCreateTexture(null, 0, 0);
} }
*/
} }
//Log.EngineLogger.AssertDebug(); //Log.EngineLogger.AssertDebug();
@@ -177,7 +198,12 @@ namespace GlitchyEngine.Renderer
case .Default: case .Default:
Box dataBox = .(destX, destY, 0, destX + destWidth, destY + destHeight, 1); Box dataBox = .(destX, destY, 0, destX + destWidth, destY + destHeight, 1);
var rowPitch = elementSize * destWidth; var rowPitch = elementSize * destWidth;
NativeContext.UpdateSubresource(nativeTexture, subresourceIndex, &dataBox, data, rowPitch, rowPitch * destHeight);
using (ContextMonitor.Enter())
{
NativeContext.UpdateSubresource(nativeTexture, subresourceIndex, &dataBox, data, rowPitch, rowPitch * destHeight);
}
case .Dynamic: case .Dynamic:
Runtime.NotImplemented(); Runtime.NotImplemented();
/* /*
@@ -220,6 +246,187 @@ namespace GlitchyEngine.Renderer
sourceBox.Back = 1; sourceBox.Back = 1;
} }
// Make sure the destination was initialized
if(destination.nativeTexture == null)
destination.InternalCreateTexture(null);
using (ContextMonitor.Enter())
{
NativeContext.CopySubresourceRegion(destination.nativeTexture,
D3D11.CalcSubresource(destMipSlice, destArraySlice, destination.MipLevels), destX, destY, 0,
source.nativeTexture, D3D11.CalcSubresource(srcMipSlice, srcArraySlice, source.MipLevels), (.)&sourceBox);
}
}
public override void CopyTo(Texture2D destination)
{
Debug.Profiler.ProfileResourceFunction!();
if(nativeTexture == null)
return;
Log.EngineLogger.AssertDebug(nativeDesc.Format == destination.nativeDesc.Format,
"Source and destination resources must have the same texel-format.");
// Make sure the destination was initialized
if(destination.nativeTexture == null)
destination.InternalCreateTexture(null);
uint32 arraySlices = Math.Min(ArraySize, destination.ArraySize);
uint32 mipSlices = Math.Min(MipLevels, destination.MipLevels);
for(uint32 arraySlice < arraySlices)
for(uint32 mipSlice < mipSlices)
{
Box sourceBox = .(0, 0, 0, Width, Height, 1);
using (ContextMonitor.Enter())
{
NativeContext.CopySubresourceRegion(destination.nativeTexture,
D3D11.CalcSubresource(mipSlice, arraySlice, destination.MipLevels), 0, 0, 0,
nativeTexture, D3D11.CalcSubresource(mipSlice, arraySlice, MipLevels), (.)&sourceBox);
}
}
}
protected override TextureViewBinding PlatformGetViewBinding()
{
return .(_nativeResourceView, _samplerState?.nativeSamplerState);
}
}
extension TextureCube
{
protected internal ID3D11Texture2D* nativeTexture ~ _?.Release();
protected internal NativeTex2DDesc nativeDesc;
public override uint32 Width => nativeDesc.Width;
public override uint32 Height => nativeDesc.Height;
public override uint32 ArraySize => nativeDesc.ArraySize / 6;
public override uint32 MipLevels => nativeDesc.MipLevels;
public override Format Format => nativeDesc.Format;
protected override void CreateTexturePlatform(Texture2DDesc desc, bool isRenderTarget, void* data, uint32 linePitch)
{
Debug.Profiler.ProfileResourceFunction!();
PrepareTexturePlatform(desc, isRenderTarget);
InternalCreateTexture(data, linePitch, 0);
}
protected override void PrepareTexturePlatform(Texture2DDesc desc, bool isRenderTarget)
{
Debug.Profiler.ProfileResourceFunction!();
nativeTexture?.Release();
nativeTexture = null;
_nativeResourceView?.Release();
_nativeResourceView = null;
nativeDesc = (NativeTex2DDesc)desc;
// Make it a texture cube
nativeDesc.MiscFlags |= .TextureCube;
nativeDesc.ArraySize *= 6;
if(isRenderTarget)
nativeDesc.BindFlags |= .RenderTarget;
}
private void InternalCreateTexture(void* data, uint32 linePitch, uint32 slicePitch)
{
Debug.Profiler.ProfileResourceFunction!();
SubresourceData resData = .(data, linePitch, slicePitch);
// If data is null, set subresourceData null
SubresourceData* resDataPtr = null;//data == null ? null : &resData;
var result = NativeDevice.CreateTexture2D(ref nativeDesc, resDataPtr, &nativeTexture);
Log.EngineLogger.Assert(result.Succeeded, scope $"Failed to create texture 2D. Error ({result.Underlying}): {result}");
result = NativeDevice.CreateShaderResourceView(nativeTexture, null, &_nativeResourceView);
Log.EngineLogger.Assert(result.Succeeded, scope $"Failed to create texture view. Error ({result.Underlying}): {result}");
}
// TODO: Update Texture Arrays!
protected override Result<void> PlatformSetData(void* data, uint32 elementSize, uint32 destX,
uint32 destY, uint32 destWidth, uint32 destHeight, uint32 arraySlice, uint32 mipLevel, GlitchyEngine.Renderer.MapType mapType)
{
Debug.Profiler.ProfileResourceFunction!();
if(nativeTexture == null)
{
if(destX == 0 && destY == 0 && destWidth == nativeDesc.Width && destHeight == nativeDesc.Height)
{
// We can pass the data while creating the buffer, so we can return here.
var rowPitch = elementSize * destWidth;
InternalCreateTexture(data, rowPitch, rowPitch * destHeight);
}
else
{
// If we don't set the entire texture we need to create the texture with unknown content and set it manually
Log.EngineLogger.Assert(nativeDesc.Usage != .Immutable, "The entire immutable texture has to be initialized.");
InternalCreateTexture(null, 0, 0);
}
}
//Log.EngineLogger.AssertDebug();
// TODO: Debug.Assert(dstByteOffset + byteLength <= _description.Size, "The destination offset and byte length are too long for the target buffer.");
uint32 subresourceIndex = D3D11.CalcSubresource(mipLevel, arraySlice, nativeDesc.MipLevels);
switch(nativeDesc.Usage)
{
case .Default:
Box dataBox = .(destX, destY, 0, destX + destWidth, destY + destHeight, 1);
var rowPitch = elementSize * destWidth;
using (ContextMonitor.Enter())
{
NativeContext.UpdateSubresource(nativeTexture, subresourceIndex, &dataBox, data, rowPitch, rowPitch * destHeight);
}
case .Dynamic:
Runtime.NotImplemented();
/*
Log.EngineLogger.Assert(mapType.CanWrite, "The map type has to have write access.");
// Todo: DoNotWaitFlag
MappedSubresource map = ?;
_context.nativeContext.Map(nativeBuffer, 0, (.)mapType, .None, &map);
Internal.MemCpy(((uint8*)map.Data) + dstByteOffset, data, byteLength);
_context.nativeContext.Unmap(nativeBuffer, 0);
*/
case .Immutable:
Log.EngineLogger.Error("Can't set the data of an immutable resource.");
return .Err;
default:
Log.EngineLogger.Error($"Unknown resource usage: {nativeDesc.Usage}");
return .Err;
}
return .Ok;
}
/*public static override void CopySubresourceRegion(Texture2D source, Texture2D destination,
ResourceBox sourceBox = default, uint32 destX = 0, uint32 destY = 0,
uint32 srcArraySlice = 0, uint32 srcMipSlice = 0, uint32 destArraySlice = 0, uint32 destMipSlice = 0)
{
Debug.Profiler.ProfileResourceFunction!();
Log.EngineLogger.AssertDebug(source != destination || srcArraySlice != destArraySlice
|| srcMipSlice != destMipSlice, "Cannot copy from and to the same sub resource.");
Log.EngineLogger.AssertDebug(source.nativeDesc.Format == destination.nativeDesc.Format,
"Source and destination resources must have the same texel-format.");
var sourceBox;
if(sourceBox.Right == 0)
{
sourceBox.Right = source.Width;
sourceBox.Bottom = source.Height;
sourceBox.Back = 1;
}
// Make sure the destination was initialized // Make sure the destination was initialized
if(destination.nativeTexture == null) if(destination.nativeTexture == null)
destination.InternalCreateTexture(null, 0, 0); destination.InternalCreateTexture(null, 0, 0);
@@ -255,44 +462,13 @@ namespace GlitchyEngine.Renderer
D3D11.CalcSubresource(mipSlice, arraySlice, destination.MipLevels), 0, 0, 0, D3D11.CalcSubresource(mipSlice, arraySlice, destination.MipLevels), 0, 0, 0,
nativeTexture, D3D11.CalcSubresource(mipSlice, arraySlice, MipLevels), (.)&sourceBox); nativeTexture, D3D11.CalcSubresource(mipSlice, arraySlice, MipLevels), (.)&sourceBox);
} }
} }*/
protected override TextureViewBinding PlatformGetViewBinding() protected override TextureViewBinding PlatformGetViewBinding()
{ {
return .(_nativeResourceView, _samplerState?.nativeSamplerState); return .(_nativeResourceView, _samplerState?.nativeSamplerState);
} }
} }
extension TextureCube
{
protected internal ID3D11Texture2D* nativeTexture ~ _?.Release();
protected internal NativeTex2DDesc nativeDesc;
public override uint32 Width => nativeDesc.Width;
public override uint32 Height => nativeDesc.Height;
public override uint32 ArraySize => nativeDesc.ArraySize / 6;
public override uint32 MipLevels => nativeDesc.MipLevels;
protected override void LoadTexturePlatform(Stream stream)
{
Debug.Profiler.ProfileResourceFunction!();
LoadDdsResourcePlatform(stream, ref nativeTexture);
let resType = nativeTexture.GetResourceType();
Log.EngineLogger.Assert(resType == .Texture2D, scope $"The texture \"{_path}\" is not a texture cube (it is {resType}).");
nativeTexture.GetDescription(out nativeDesc);
Log.EngineLogger.Assert(nativeDesc.MiscFlags.HasFlag(.TextureCube), scope $"The texture \"{_path}\" is not a texture cube.");
// TODO: load fallback texture
}
protected override TextureViewBinding PlatformGetViewBinding()
{
return .(_nativeResourceView, _samplerState.nativeSamplerState);
}
}
} }
#endif #endif
@@ -19,13 +19,13 @@ namespace GlitchyEngine
//[CLink, CallingConvention(.Stdcall)] //[CLink, CallingConvention(.Stdcall)]
//static extern int16 GetKeyState(int32 keycode); //static extern int16 GetKeyState(int32 keycode);
[CLink, CallingConvention(.Stdcall)] [CLink, CallingConvention(.Stdcall)]
static extern IntBool GetCursorPos(out Int2 p); static extern IntBool GetCursorPos(out int2 p);
[CLink, CallingConvention(.Stdcall)] [CLink, CallingConvention(.Stdcall)]
static extern IntBool SetCursorPos(c_int x, c_int y); static extern IntBool SetCursorPos(c_int x, c_int y);
[CLink, CallingConvention(.Stdcall)] [CLink, CallingConvention(.Stdcall)]
static extern IntBool ScreenToClient(HWnd hWnd, ref Int2 p); static extern IntBool ScreenToClient(HWnd hWnd, ref int2 p);
[CLink, CallingConvention(.Stdcall)] [CLink, CallingConvention(.Stdcall)]
static extern IntBool ClientToScreen(HWnd hWnd, ref Int2 p); static extern IntBool ClientToScreen(HWnd hWnd, ref int2 p);
[Import("user32.lib"), CLink] [Import("user32.lib"), CLink]
public static extern IntBool RegisterRawInputDevices(RAWINPUTDEVICE* pRawInputDevices, uint32 uiNumDevices, uint32 cbSize); public static extern IntBool RegisterRawInputDevices(RAWINPUTDEVICE* pRawInputDevices, uint32 uiNumDevices, uint32 cbSize);
@@ -50,9 +50,9 @@ namespace GlitchyEngine
struct WindowsInputState struct WindowsInputState
{ {
public int8[256] KeyStates; public int8[256] KeyStates;
public Int2 CursorPosition; public int2 CursorPosition;
public Int2 CursorPositionDifference; public int2 CursorPositionDifference;
public Int2 RawCursorMovement; public int2 RawCursorMovement;
} }
static WindowsInputState[2] IputStates; static WindowsInputState[2] IputStates;
@@ -157,11 +157,11 @@ namespace GlitchyEngine
public override static bool IsMouseButtonReleasing(MouseButton button) => IsMouseButtonReleased(button) && WasMouseButtonPressed(button); public override static bool IsMouseButtonReleasing(MouseButton button) => IsMouseButtonReleased(button) && WasMouseButtonPressed(button);
public override static Int2 GetMousePosition() => CurrentState.CursorPosition; public override static int2 GetMousePosition() => CurrentState.CursorPosition;
public override static Int2 GetMouseMovement() => CurrentState.CursorPositionDifference; public override static int2 GetMouseMovement() => CurrentState.CursorPositionDifference;
public override static Int2 GetRawMouseMovement() => CurrentState.RawCursorMovement; public override static int2 GetRawMouseMovement() => CurrentState.RawCursorMovement;
public override static int32 GetMouseX() => CurrentState.CursorPosition.X; public override static int32 GetMouseX() => CurrentState.CursorPosition.X;
@@ -182,17 +182,17 @@ namespace GlitchyEngine
return state >= 0; return state >= 0;
} }
public override static Int2 GetLastMousePosition() => LastState.CursorPosition; public override static int2 GetLastMousePosition() => LastState.CursorPosition;
public override static Int2 GetLastMouseMovement() => LastState.CursorPositionDifference; public override static int2 GetLastMouseMovement() => LastState.CursorPositionDifference;
public override static Int2 GetLastRawMouseMovement() => LastState.RawCursorMovement; public override static int2 GetLastRawMouseMovement() => LastState.RawCursorMovement;
public override static int32 GetLastMouseX() => LastState.CursorPosition.X; public override static int32 GetLastMouseX() => LastState.CursorPosition.X;
public override static int32 GetLastMouseY() => LastState.CursorPosition.Y; public override static int32 GetLastMouseY() => LastState.CursorPosition.Y;
public override static void SetMousePosition(Int2 pos) public override static void SetMousePosition(int2 pos)
{ {
HWnd windowHandle = (HWnd)(int)Application.Get().Window.NativeWindow; HWnd windowHandle = (HWnd)(int)Application.Get().Window.NativeWindow;
@@ -67,13 +67,13 @@ namespace GlitchyEngine
// //
// Size // Size
// //
public override Int2 Size public override int2 Size
{ {
get => *(Int2*)&_clientRect.Width; get => *(int2*)&_clientRect.Width;
set set
{ {
*(Int2*)&_clientRect.Width = value; *(int2*)&_clientRect.Width = value;
ApplyRectangle(); ApplyRectangle();
} }
} }
@@ -103,13 +103,13 @@ namespace GlitchyEngine
// //
// Position // Position
// //
public override Int2 Position public override int2 Position
{ {
get => *(Int2*)&_clientRect; get => *(int2*)&_clientRect;
set set
{ {
*(Int2*)&_clientRect = value; *(int2*)&_clientRect = value;
ApplyRectangle(); ApplyRectangle();
} }
} }
@@ -263,7 +263,7 @@ namespace GlitchyEngine
return .Ok; return .Ok;
} }
internal Int2 _rawMouseMovementAccumulator; internal int2 _rawMouseMovementAccumulator;
private static LRESULT MessageHandler(HWND hwnd, uint32 uMsg, WPARAM wParam, LPARAM lParam) private static LRESULT MessageHandler(HWND hwnd, uint32 uMsg, WPARAM wParam, LPARAM lParam)
{ {
@@ -478,7 +478,7 @@ namespace GlitchyEngine
window._eventCallback(event); window._eventCallback(event);
// We accumulate the raw movements an collect them once each frame in WindowsInput.Impl_NewFrame() // We accumulate the raw movements an collect them once each frame in WindowsInput.Impl_NewFrame()
window._rawMouseMovementAccumulator += Int2(raw.Data.Mouse.lLastX, raw.Data.Mouse.lLastY); window._rawMouseMovementAccumulator += int2(raw.Data.Mouse.lLastX, raw.Data.Mouse.lLastY);
} }
} }
} }
+2 -2
View File
@@ -8,7 +8,7 @@ namespace GlitchyEngine
class Program class Program
{ {
[LinkName("CreateApplication")] [LinkName("CreateApplication")]
static extern Application CreateApplication(); static extern Application CreateApplication(String[] args);
public static int Main(String[] args) public static int Main(String[] args)
{ {
@@ -23,7 +23,7 @@ namespace GlitchyEngine
Stopwatch initWatch = scope Stopwatch(); Stopwatch initWatch = scope Stopwatch();
app = CreateApplication(); app = CreateApplication(args);
initWatch.Stop(); initWatch.Stop();
@@ -188,9 +188,9 @@ namespace GlitchyEngine.Renderer.Animation
class JointAnimation// : IDisposable class JointAnimation// : IDisposable
{ {
public JointAnimationChannel<Vector3> TranslationChannel ~ delete _; public JointAnimationChannel<float3> TranslationChannel ~ delete _;
public JointAnimationChannel<Quaternion> RotationChannel ~ delete _; public JointAnimationChannel<Quaternion> RotationChannel ~ delete _;
public JointAnimationChannel<Vector3> ScaleChannel ~ delete _; public JointAnimationChannel<float3> ScaleChannel ~ delete _;
public float Duration public float Duration
{ {
@@ -221,7 +221,7 @@ namespace GlitchyEngine.Renderer.Animation
case .Step: case .Step:
result.Translation = previous; result.Translation = previous;
case .Linear: case .Linear:
result.Translation = Vector3.Lerp(previous, next, interpolationValue); result.Translation = lerp(previous, next, interpolationValue);
default: default:
result.Rotation = ?; result.Rotation = ?;
Runtime.NotImplemented(); Runtime.NotImplemented();
@@ -262,7 +262,7 @@ namespace GlitchyEngine.Renderer.Animation
case .Step: case .Step:
result.Scale = previous; result.Scale = previous;
case .Linear: case .Linear:
result.Scale = Vector3.Lerp(previous, next, interpolationValue); result.Scale = lerp(previous, next, interpolationValue);
default: default:
result.Rotation = ?; result.Rotation = ?;
Runtime.NotImplemented(); Runtime.NotImplemented();
@@ -14,7 +14,7 @@ namespace GlitchyEngine.Renderer.Animation
public struct JointPose public struct JointPose
{ {
public Quaternion Rotation; public Quaternion Rotation;
public Vector3 Translation; public float3 Translation;
public Vector3 Scale; public float3 Scale;
} }
} }
+134
View File
@@ -1,6 +1,139 @@
using System; using System;
using GlitchyEngine.Core; using GlitchyEngine.Core;
namespace DirectX.DXGI
{
public extension Format
{
public bool IsInt()
{
switch(this)
{
case R32G32B32A32_SInt, R32G32B32_SInt, R16G16B16A16_SInt, R32G32_SInt, R8G8B8A8_SInt, R16G16_SInt,
R32_SInt, R8G8_SInt, R16_SInt, R8_SInt:
return true;
default:
return false;
}
}
public bool IsUInt()
{
switch(this)
{
case R32G32B32A32_UInt, R32G32B32_UInt, R16G16B16A16_UInt, R32G32_UInt, R10G10B10A2_UInt, R8G8B8A8_UInt, R16G16_UInt,
R32_UInt, R8G8_UInt, R16_UInt, R8_UInt:
return true;
default:
return false;
}
}
public uint32 BitsPerPixel()
{
switch (this)
{
case .R32G32B32A32_Typeless,.R32G32B32A32_Float,.R32G32B32A32_UInt,.R32G32B32A32_SInt:
return 128;
case .R32G32B32_Typeless,.R32G32B32_Float,.R32G32B32_UInt,.R32G32B32_SInt:
return 96;
case .R16G16B16A16_Typeless,.R16G16B16A16_Float,.R16G16B16A16_UNorm,.R16G16B16A16_UInt,.R16G16B16A16_SNorm,.R16G16B16A16_SInt,.R32G32_Typeless,.R32G32_Float,.R32G32_UInt,.R32G32_SInt,.R32G8X24_Typeless,.D32_Float_S8X24_UInt,.R32_Float_X8X24_Typeless,.X32_Typeless_G8X24_UInt,.Y416,.Y210,.Y216:
return 64;
case .R10G10B10A2_Typeless,.R10G10B10A2_UNorm,.R10G10B10A2_UInt,.R11G11B10_Float,.R8G8B8A8_Typeless,.R8G8B8A8_UNorm,.R8G8B8A8_UNorm_SRGB,.R8G8B8A8_UInt,.R8G8B8A8_SNorm,.R8G8B8A8_SInt,.R16G16_Typeless,.R16G16_Float,.R16G16_UNorm,.R16G16_UInt,.R16G16_SNorm,.R16G16_SInt,.R32_Typeless,.D32_Float,.R32_Float,.R32_UInt,.R32_SInt,.R24G8_Typeless,.D24_UNorm_S8_UInt,.R24_UNorm_X8_Typeless,.X24_Typeless_G8_UInt,.R9G9B9E5_SHAREDEXP,.R8G8_B8G8_UNorm,.G8R8_G8B8_UNorm,.B8G8R8A8_UNorm,.B8G8R8X8_UNorm,.R10G10B10_XR_BIAS_A2_UNorm,.B8G8R8A8_Typeless,.B8G8R8A8_UNorm_SRGB,.B8G8R8X8_Typeless,.B8G8R8X8_UNorm_SRGB,.AYUV,.Y410,.YUY2:
//#if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)
//case .R10G10B10_7E3_A2_Float,.R10G10B10_6E4_A2_Float,.R10G10B10_SNorm_A2_UNorm:
//#endif
return 32;
case .P010,.P016, .V408:
/*#if (_WIN32_WINNT >= _WIN32_WINNT_WIN10)
case .V408:
#endif
#if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)
case .D16_UNorm_S8_UInt,.R16_UNorm_X8_Typeless,.X16_Typeless_G8_UInt:
#endif*/
return 24;
case .R8G8_Typeless,.R8G8_UNorm,.R8G8_UInt,.R8G8_SNorm,.R8G8_SInt,.R16_Typeless,.R16_Float,.D16_UNorm,.R16_UNorm,.R16_UInt,.R16_SNorm,.R16_SInt,.B5G6R5_UNorm,.B5G5R5A1_UNorm,.A8P8,.B4G4R4A4_UNORM, .P208,.V208:
/*#if (_WIN32_WINNT >= _WIN32_WINNT_WIN10)
case .P208,.V208:
#endif*/
return 16;
case .NV12,.OPAQUE_420,.NV11:
return 12;
case .R8_Typeless,.R8_UNorm,.R8_UInt,.R8_SNorm,.R8_SInt,.A8_UNorm,.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,.AI44,.IA44,.P8:
/*#if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)
case .R4G4_UNorm:
#endif*/
return 8;
case .R1_UNorm:
return 1;
case .BC1_Typeless,.BC1_UNorm,.BC1_UNorm_SRGB,.BC4_Typeless,.BC4_UNorm,.BC4_SNorm:
return 4;
//case .Unknown,.FORCE_UInt:
default:
return 0;
}
}
/// Returns the SRGB-Format for the given Format, or the Format itself, if no SRGB-variant exists.
public Format GetSRGB()
{
switch (this)
{
case .BC1_UNorm:
return .BC1_UNorm_SRGB;
case .BC2_UNorm:
return .BC2_UNorm_SRGB;
case .BC3_UNorm:
return .BC3_UNorm_SRGB;
case .BC7_UNorm:
return .BC7_UNorm_SRGB;
case .R8G8B8A8_UNorm:
return .R8G8B8A8_UNorm_SRGB;
case .B8G8R8A8_UNorm:
return .B8G8R8A8_UNorm_SRGB;
case .B8G8R8X8_UNorm:
return .B8G8R8X8_UNorm_SRGB;
default:
return this;
}
}
/// Returns the non-SRGB-Format for the given Format.
public Format GetNonSRGB()
{
switch (this)
{
case .BC1_UNorm_SRGB:
return .BC1_UNorm;
case .BC2_UNorm_SRGB:
return .BC2_UNorm;
case .BC3_UNorm_SRGB:
return .BC3_UNorm;
case .BC7_UNorm_SRGB:
return .BC7_UNorm;
case .R8G8B8A8_UNorm_SRGB:
return .R8G8B8A8_UNorm;
case .B8G8R8A8_UNorm_SRGB:
return .B8G8R8A8_UNorm;
case .B8G8R8X8_UNorm_SRGB:
return .B8G8R8X8_UNorm;
default:
return this;
}
}
}
}
namespace GlitchyEngine.Renderer namespace GlitchyEngine.Renderer
{ {
/** /**
@@ -29,6 +162,7 @@ namespace GlitchyEngine.Renderer
typealias Format = DirectX.DXGI.Format; typealias Format = DirectX.DXGI.Format;
public struct BufferDescription public struct BufferDescription
{ {
/** /**
+41 -23
View File
@@ -77,28 +77,40 @@ namespace GlitchyEngine.Renderer
{ {
case typeof(bool): case typeof(bool):
EnsureTypeMatch(1, 1, .Bool); EnsureTypeMatch(1, 1, .Bool);
case typeof(bool2):
EnsureTypeMatch(1, 2, .Bool);
case typeof(bool3):
EnsureTypeMatch(1, 3, .Bool);
case typeof(bool4):
EnsureTypeMatch(1, 4, .Bool);
case typeof(int32):
EnsureTypeMatch(1, 1, .Int);
case typeof(int2):
EnsureTypeMatch(1, 2, .Int);
case typeof(int3):
EnsureTypeMatch(1, 3, .Int);
case typeof(int4):
EnsureTypeMatch(1, 4, .Int);
case typeof(uint32):
EnsureTypeMatch(1, 1, .UInt);
case typeof(uint2):
EnsureTypeMatch(1, 2, .UInt);
case typeof(uint3):
EnsureTypeMatch(1, 3, .UInt);
case typeof(uint4):
EnsureTypeMatch(1, 4, .UInt);
case typeof(float): case typeof(float):
EnsureTypeMatch(1, 1, .Float); EnsureTypeMatch(1, 1, .Float);
case typeof(Vector2): case typeof(float2):
EnsureTypeMatch(1, 2, .Float); EnsureTypeMatch(1, 2, .Float);
case typeof(Vector3): case typeof(float3):
EnsureTypeMatch(1, 3, .Float); EnsureTypeMatch(1, 3, .Float);
case typeof(Vector4): case typeof(float4):
EnsureTypeMatch(1, 4, .Float); EnsureTypeMatch(1, 4, .Float);
case typeof(int32):
EnsureTypeMatch(1, 1, .Int);
case typeof(Int2):
EnsureTypeMatch(1, 2, .Int);
case typeof(Int3):
EnsureTypeMatch(1, 3, .Int);
case typeof(Int4):
EnsureTypeMatch(1, 4, .Int);
case typeof(uint32):
EnsureTypeMatch(1, 1, .UInt);
case typeof(Matrix4x3): case typeof(Matrix4x3):
EnsureTypeMatch(4, 3, .Float); EnsureTypeMatch(4, 3, .Float);
case typeof(Matrix3x3): case typeof(Matrix3x3):
@@ -130,18 +142,24 @@ namespace GlitchyEngine.Renderer
} }
public void SetData(bool value) => SetData<bool>(value); public void SetData(bool value) => SetData<bool>(value);
public void SetData(bool2 value) => SetData<bool2>(value);
public void SetData(float value) => SetData<float>(value); public void SetData(bool3 value) => SetData<bool3>(value);
public void SetData(Vector2 value) => SetData<Vector2>(value); public void SetData(bool4 value) => SetData<bool4>(value);
public void SetData(Vector3 value) => SetData<Vector3>(value);
public void SetData(Vector4 value) => SetData<Vector4>(value);
public void SetData(int32 value) => SetData<int32>(value); public void SetData(int32 value) => SetData<int32>(value);
public void SetData(Int2 value) => SetData<Int2>(value); public void SetData(int2 value) => SetData<int2>(value);
public void SetData(Int3 value) => SetData<Int3>(value); public void SetData(int3 value) => SetData<int3>(value);
public void SetData(Int4 value) => SetData<Int4>(value); public void SetData(int4 value) => SetData<int4>(value);
public void SetData(uint32 value) => SetData<uint32>(value); public void SetData(uint32 value) => SetData<uint32>(value);
public void SetData(uint2 value) => SetData<uint2>(value);
public void SetData(uint3 value) => SetData<uint3>(value);
public void SetData(uint4 value) => SetData<uint4>(value);
public void SetData(float value) => SetData<float>(value);
public void SetData(float2 value) => SetData<float2>(value);
public void SetData(float3 value) => SetData<float3>(value);
public void SetData(float4 value) => SetData<float4>(value);
public void SetData(ColorRGB value) => SetData<ColorRGB>(value); public void SetData(ColorRGB value) => SetData<ColorRGB>(value);
public void SetData(ColorRGBA value) => SetData<ColorRGBA>(value); public void SetData(ColorRGBA value) => SetData<ColorRGBA>(value);
+6 -6
View File
@@ -31,8 +31,8 @@ namespace GlitchyEngine.Renderer
protected float _nearPlane; protected float _nearPlane;
protected float _farPlane; protected float _farPlane;
protected Vector3 _position; protected float3 _position;
protected Vector3 _rotation; protected float3 _rotation;
/// If true the transform matrix is outdated and needs to be recalculated. /// If true the transform matrix is outdated and needs to be recalculated.
protected bool _transformOutdated = true; protected bool _transformOutdated = true;
@@ -76,12 +76,12 @@ namespace GlitchyEngine.Renderer
} }
} }
public Vector3 Position public float3 Position
{ {
get => _position; get => _position;
set set
{ {
if(_position == value) if(all(_position == value))
return; return;
_position = value; _position = value;
@@ -89,12 +89,12 @@ namespace GlitchyEngine.Renderer
} }
} }
public Vector3 Rotation public float3 Rotation
{ {
get => _rotation; get => _rotation;
set set
{ {
if(_rotation == value) if(all(_rotation == value))
return; return;
_rotation = value; _rotation = value;
@@ -45,6 +45,11 @@ namespace GlitchyEngine.Renderer
} }
} }
public bool TryGetVariable(String name, out BufferVariable variable)
{
return _nameToVariable.TryGetValue(name, out variable);
}
public BufferVariable this[String name] => _nameToVariable[name]; public BufferVariable this[String name] => _nameToVariable[name];
public List<BufferVariable>.Enumerator GetEnumerator() public List<BufferVariable>.Enumerator GetEnumerator()
+7 -7
View File
@@ -39,9 +39,9 @@ namespace GlitchyEngine.Renderer
if(length != 0.0f) if(length != 0.0f)
{ {
transform.Columns[0]..Normalize() *= length; transform.Columns[0] = normalize(transform.Columns[0]) * length;
transform.Columns[1]..Normalize() *= length; transform.Columns[1] = normalize(transform.Columns[1]) * length;
transform.Columns[2]..Normalize() *= length; transform.Columns[2] = normalize(transform.Columns[2]) * length;
} }
Renderer.DrawLine(.Zero, .Right, .Red, transform); Renderer.DrawLine(.Zero, .Right, .Red, transform);
@@ -66,7 +66,7 @@ namespace GlitchyEngine.Renderer
_frustumGeometry = new GeometryBinding(); _frustumGeometry = new GeometryBinding();
_frustumGeometry.SetPrimitiveTopology(.LineList); _frustumGeometry.SetPrimitiveTopology(.LineList);
_frustumVertices = new VertexBuffer(typeof(Vector4), 8, .Dynamic, .Write); _frustumVertices = new VertexBuffer(typeof(float4), 8, .Dynamic, .Write);
_frustumGeometry.SetVertexBufferSlot(_frustumVertices, 0); _frustumGeometry.SetVertexBufferSlot(_frustumVertices, 0);
using (IndexBuffer indexBuffer = new IndexBuffer(24, .Immutable)) using (IndexBuffer indexBuffer = new IndexBuffer(24, .Immutable))
@@ -109,7 +109,7 @@ namespace GlitchyEngine.Renderer
2, 6, 2, 6,
3, 7); 3, 7);
Vector4[8] corners; float4[8] corners;
// Perspective // Perspective
if(projection._43 != 0.0f) if(projection._43 != 0.0f)
{ {
@@ -121,7 +121,7 @@ namespace GlitchyEngine.Renderer
float gOverS = projection._11; float gOverS = projection._11;
float g = projection._22; float g = projection._22;
//var corners = //(Vector4*)&_vbFrustum.Data; //var corners = //(float4*)&_vbFrustum.Data;
if(Math.Abs(d1) >= 10000) if(Math.Abs(d1) >= 10000)
{ {
@@ -167,7 +167,7 @@ namespace GlitchyEngine.Renderer
float n = -projection._34 / projection._33; float n = -projection._34 / projection._33;
float f = (1 - projection._34) / projection._33; float f = (1 - projection._34) / projection._33;
//var corners = (Vector4*)&_vbFrustum.Data; //var corners = (float4*)&_vbFrustum.Data;
corners[0] = .(r, t, n, 1.0f); corners[0] = .(r, t, n, 1.0f);
corners[1] = .(r, b, n, 1.0f); corners[1] = .(r, b, n, 1.0f);
corners[2] = .(l, b, n, 1.0f); corners[2] = .(l, b, n, 1.0f);
+26 -24
View File
@@ -104,6 +104,18 @@ public class EffectLibrary
public bool Exists(String effectName) => _effects.ContainsKey(effectName); public bool Exists(String effectName) => _effects.ContainsKey(effectName);
}*/ }*/
public enum TextureDimension
{
Unknown,
Texture1D,
Texture1DArray,
Texture2D,
Texture2DArray,
Texture3D,
TextureCube,
TextureCubeArray
}
public class Effect : Asset public class Effect : Asset
{ {
internal VertexShader _vs ~ _?.ReleaseRef(); internal VertexShader _vs ~ _?.ReleaseRef();
@@ -137,14 +149,16 @@ public class Effect : Asset
public struct TextureEntry public struct TextureEntry
{ {
public TextureViewBinding BoundTexture; public TextureViewBinding BoundTexture;
public TextureDimension TextureDimension;
public ShaderTextureCollection.ResourceEntry* VsSlot; public ShaderTextureCollection.ResourceEntry* VsSlot;
public ShaderTextureCollection.ResourceEntry* PsSlot; public ShaderTextureCollection.ResourceEntry* PsSlot;
public this(TextureViewBinding boundTexture, ShaderTextureCollection.ResourceEntry* vsSlot, ShaderTextureCollection.ResourceEntry* psSlot) public this(TextureViewBinding boundTexture, TextureDimension textureDimension, ShaderTextureCollection.ResourceEntry* vsSlot, ShaderTextureCollection.ResourceEntry* psSlot)
{ {
BoundTexture = boundTexture; BoundTexture = boundTexture;
VsSlot = vsSlot; VsSlot = vsSlot;
PsSlot = psSlot; PsSlot = psSlot;
TextureDimension = textureDimension;
} }
} }
@@ -233,7 +247,7 @@ public class Effect : Asset
{ {
Debug.Profiler.ProfileRendererFunction!(); Debug.Profiler.ProfileRendererFunction!();
[Inline]InternalSetTexture(name, textureViewBinding..AddRef()); [Inline]InternalSetTexture(name, textureViewBinding);
} }
private void InternalSetTexture(String name, TextureViewBinding textureViewBinding) private void InternalSetTexture(String name, TextureViewBinding textureViewBinding)
@@ -242,29 +256,17 @@ public class Effect : Asset
ref TextureEntry entry = ref _textures[name]; ref TextureEntry entry = ref _textures[name];
// TODO: Thats weird, we increment this reference somewhere... but WHERE?!
entry.BoundTexture.Release(); entry.BoundTexture.Release();
entry.BoundTexture = textureViewBinding; entry.BoundTexture = textureViewBinding;
entry.VsSlot?.BoundTexture..Release() = entry.BoundTexture..AddRef(); if (entry.VsSlot != null)
entry.PsSlot?.BoundTexture..Release() = entry.BoundTexture..AddRef(); SetReferenceVar!(entry.VsSlot.BoundTexture, entry.BoundTexture);
if (entry.PsSlot != null)
SetReferenceVar!(entry.PsSlot.BoundTexture, entry.BoundTexture);
} }
/*private void ApplyTextures()
{
Debug.Profiler.ProfileRendererFunction!();
for(let (name, entry) in _textures)
{
entry.VsSlot?.BoundTexture.Release();
entry.VsSlot?.BoundTexture = entry.BoundTexture;
entry.VsSlot?.BoundTexture.AddRef();
entry.PsSlot?.BoundTexture.Release();
entry.PsSlot?.BoundTexture = entry.BoundTexture;
entry.PsSlot?.BoundTexture.AddRef();
}
}*/
public void ApplyChanges() public void ApplyChanges()
{ {
Debug.Profiler.ProfileRendererFunction!(); Debug.Profiler.ProfileRendererFunction!();
@@ -602,11 +604,11 @@ public class Effect : Asset
} }
if (numComponents == 2) if (numComponents == 2)
return Variant.Create(*(Vector2*)floats.Ptr); return Variant.Create(*(float2*)floats.Ptr);
else if (numComponents == 3) else if (numComponents == 3)
return Variant.Create(*(Vector3*)floats.Ptr); return Variant.Create(*(float3*)floats.Ptr);
else if (numComponents == 4) else if (numComponents == 4)
return Variant.Create(*(Vector4*)floats.Ptr); return Variant.Create(*(float4*)floats.Ptr);
} }
else else
{ {
@@ -741,7 +743,7 @@ public class Effect : Asset
// Get existing entry or create new // Get existing entry or create new
if(!_textures.TryGetValue(shaderEntry.Name, out entry)) if(!_textures.TryGetValue(shaderEntry.Name, out entry))
{ {
entry = .(shaderEntry.BoundTexture, null, null); entry = .(shaderEntry.BoundTexture, shaderEntry.Dimension, null, null);
entry.BoundTexture.AddRef(); entry.BoundTexture.AddRef();
} }

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