Compare commits
	
		
			4 Commits
		
	
	
		
			57b42d8daa
			...
			ecs-test
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 5eaf3547dc | |||
| d80e1177b9 | |||
| cf6cd080c6 | |||
| 87ee6df46f | 
							
								
								
									
										1
									
								
								.idea/.idea.Nerfed/.idea/vcs.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								.idea/.idea.Nerfed/.idea/vcs.xml
									
									
									
										generated
									
									
									
								
							| @@ -4,6 +4,7 @@ | |||||||
|     <mapping directory="" vcs="Git" /> |     <mapping directory="" vcs="Git" /> | ||||||
|     <mapping directory="$PROJECT_DIR$/Nerfed.Runtime/Libraries/FAudio" vcs="Git" /> |     <mapping directory="$PROJECT_DIR$/Nerfed.Runtime/Libraries/FAudio" vcs="Git" /> | ||||||
|     <mapping directory="$PROJECT_DIR$/Nerfed.Runtime/Libraries/ImGui.NET" vcs="Git" /> |     <mapping directory="$PROJECT_DIR$/Nerfed.Runtime/Libraries/ImGui.NET" vcs="Git" /> | ||||||
|  |     <mapping directory="$PROJECT_DIR$/Nerfed.Runtime/Libraries/MoonTools.ECS" vcs="Git" /> | ||||||
|     <mapping directory="$PROJECT_DIR$/Nerfed.Runtime/Libraries/RefreshCS" vcs="Git" /> |     <mapping directory="$PROJECT_DIR$/Nerfed.Runtime/Libraries/RefreshCS" vcs="Git" /> | ||||||
|     <mapping directory="$PROJECT_DIR$/Nerfed.Runtime/Libraries/SDL2CS" vcs="Git" /> |     <mapping directory="$PROJECT_DIR$/Nerfed.Runtime/Libraries/SDL2CS" vcs="Git" /> | ||||||
|     <mapping directory="$PROJECT_DIR$/Nerfed.Runtime/Libraries/WellspringCS" vcs="Git" /> |     <mapping directory="$PROJECT_DIR$/Nerfed.Runtime/Libraries/WellspringCS" vcs="Git" /> | ||||||
|   | |||||||
| @@ -1,6 +1,8 @@ | |||||||
|  | using System.Numerics; | ||||||
| using ImGuiNET; | using ImGuiNET; | ||||||
| using MoonTools.ECS; | using MoonTools.ECS; | ||||||
| using Nerfed.Editor.Components; | using Nerfed.Editor.Components; | ||||||
|  | using Nerfed.Runtime.Serialization; | ||||||
| 
 | 
 | ||||||
| #if DEBUG | #if DEBUG | ||||||
| namespace Nerfed.Editor.Systems | namespace Nerfed.Editor.Systems | ||||||
| @@ -29,27 +31,69 @@ namespace Nerfed.Editor.Systems | |||||||
| 
 | 
 | ||||||
|         private void DrawEntityComponents(Entity entity) |         private void DrawEntityComponents(Entity entity) | ||||||
|         { |         { | ||||||
|             World.ComponentTypeEnumerator components = World.Debug_GetAllComponentTypes(entity); |             World.ComponentTypeEnumerator componentTypes = World.Debug_GetAllComponentTypes(entity); | ||||||
|              |              | ||||||
|             foreach (Type type in components) |             // Add button of all types that we can add. Also filter out types we already have. | ||||||
|  |             List<Type> componentTypesToAdd = ComponentHelper.AddComponentByType.Keys.ToList(); | ||||||
|  |             foreach (Type componentType in componentTypes) | ||||||
|             { |             { | ||||||
|                 ImGui.Text(type.Name); |                 componentTypesToAdd.Remove(componentType); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  |             const string popupId = "AddComponentPopup"; | ||||||
|  |             if (ImGui.Button("Add Component")) | ||||||
|  |             { | ||||||
|  |                 ImGui.OpenPopup(popupId); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if (ImGui.BeginPopup(popupId)) | ||||||
|  |             { | ||||||
|  |                 foreach (Type componentType in componentTypesToAdd) | ||||||
|  |                 { | ||||||
|  |                     if (ImGui.Selectable(componentType.Name)) | ||||||
|  |                     { | ||||||
|  |                         if (ComponentHelper.AddComponentByType.TryGetValue(componentType, out Action<World, Entity> componentSetter)) | ||||||
|  |                         { | ||||||
|  |                             componentSetter.Invoke(World, entity); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 ImGui.EndPopup(); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             ImGui.Dummy(new Vector2(16, 16)); | ||||||
|  |              | ||||||
|  |             ImGui.Text("ComponentInspectorByType"); | ||||||
|  |             foreach (Type componentType in componentTypes) | ||||||
|  |             { | ||||||
|  |                 if (ComponentHelper.ComponentInspectorByType.TryGetValue(componentType, out Action<World, Entity> componentInspector)) | ||||||
|  |                 { | ||||||
|  |                     componentInspector(World, entity); | ||||||
|  |                 } | ||||||
|  |                 else if (ComponentHelper.GetComponentByType.TryGetValue(componentType, out Func<World, Entity, ValueType> componentGetter)) | ||||||
|  |                 { | ||||||
|  |                     ValueType component = componentGetter.Invoke(World, entity); | ||||||
|  |                     ImGui.Text(component.ToString()); | ||||||
|  |                 } | ||||||
|  |                 else | ||||||
|  |                 { | ||||||
|  |                     ImGui.Text(componentType.Name); | ||||||
|  |                 } | ||||||
|                 ImGui.Separator(); |                 ImGui.Separator(); | ||||||
| 
 |  | ||||||
|             // TODO: explore something without reflection. |  | ||||||
|             // Maybe generate some look up dictionary<type, Action<world, entity>> for 'custom editors'. |  | ||||||
|             // Look into serializing of entities and components. |  | ||||||
|             foreach (Type component in components) |  | ||||||
|             { |  | ||||||
|                 System.Reflection.MethodInfo getMethodInfo = typeof(World).GetMethod("Get"); |  | ||||||
|                 System.Reflection.MethodInfo getComponentMethod = getMethodInfo.MakeGenericMethod(component); |  | ||||||
|                 object result = getComponentMethod.Invoke(World, [entity]); |  | ||||||
| 
 |  | ||||||
|                 // process here |  | ||||||
|                 ImGui.Text(result.ToString()); |  | ||||||
|             } |             } | ||||||
|  |              | ||||||
|  |             ImGui.Dummy(new Vector2(16, 16)); | ||||||
|  | 
 | ||||||
|  |             // ImGui.Text("Reflection"); | ||||||
|  |             // foreach (Type component in componentTypes) | ||||||
|  |             // { | ||||||
|  |             //     System.Reflection.MethodInfo getMethodInfo = typeof(World).GetMethod("Get"); | ||||||
|  |             //     System.Reflection.MethodInfo getComponentMethod = getMethodInfo.MakeGenericMethod(component); | ||||||
|  |             //     object result = getComponentMethod.Invoke(World, [entity]); | ||||||
|  |             // | ||||||
|  |             //     // process here | ||||||
|  |             //     ImGui.Text(result.ToString()); | ||||||
|  |             // } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -4,10 +4,6 @@ namespace Nerfed.Runtime.Components | |||||||
| { | { | ||||||
|     public readonly record struct LocalTransform(Vector3 position, Quaternion rotation, Vector3 scale) |     public readonly record struct LocalTransform(Vector3 position, Quaternion rotation, Vector3 scale) | ||||||
|     { |     { | ||||||
|         public readonly Vector3 position = position; |  | ||||||
|         public readonly Quaternion rotation = rotation; |  | ||||||
|         public readonly Vector3 scale = scale; |  | ||||||
| 
 |  | ||||||
|         public static readonly LocalTransform Identity = new(Vector3.Zero, Quaternion.Identity, Vector3.One); |         public static readonly LocalTransform Identity = new(Vector3.Zero, Quaternion.Identity, Vector3.One); | ||||||
|     } |     } | ||||||
| } | } | ||||||
							
								
								
									
										68
									
								
								Nerfed.Runtime/Serialization/ComponentHelper.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								Nerfed.Runtime/Serialization/ComponentHelper.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,68 @@ | |||||||
|  | using System.Numerics; | ||||||
|  | using ImGuiNET; | ||||||
|  | using MoonTools.ECS; | ||||||
|  | using Nerfed.Runtime.Components; | ||||||
|  | 
 | ||||||
|  | namespace Nerfed.Runtime.Serialization; | ||||||
|  | 
 | ||||||
|  | public static class ComponentHelper | ||||||
|  | { | ||||||
|  |     // Auto generate this. | ||||||
|  |     public static readonly Dictionary<Type, Func<World, Entity, ValueType>> GetComponentByType = new() | ||||||
|  |     { | ||||||
|  |         { typeof(LocalTransform), (world, entity) => world.Get<LocalTransform>(entity) }, | ||||||
|  |         { typeof(Root), (world, entity) => world.Get<Root>(entity) }, | ||||||
|  |     }; | ||||||
|  |      | ||||||
|  |     // Auto generate this. | ||||||
|  |     public static readonly Dictionary<Type, Action<World, Entity, ValueType>> SetComponentByType = new() | ||||||
|  |     { | ||||||
|  |         { typeof(LocalTransform), (world, entity, component) => world.Set(entity, (LocalTransform)component) }, | ||||||
|  |         { typeof(Root), (world, entity, component) => world.Set(entity, (Root)component) }, | ||||||
|  |     }; | ||||||
|  |      | ||||||
|  |     // Auto generate this, but it should only contain user assignable components (so something like 'root' should be excluded). | ||||||
|  |     // Maybe use an attribute for this. | ||||||
|  |     public static readonly Dictionary<Type, Action<World, Entity>> AddComponentByType = new() | ||||||
|  |     { | ||||||
|  |         { typeof(LocalTransform), (world, entity) => world.Set(entity, LocalTransform.Identity) }, | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     // Auto generate this, but also keep the option for 'custom inspectors'. | ||||||
|  |     // Maybe via attribute? | ||||||
|  |     public static readonly Dictionary<Type, Action<World, Entity>> ComponentInspectorByType = new() | ||||||
|  |     { | ||||||
|  |         { | ||||||
|  |             typeof(LocalTransform), (world, entity) => | ||||||
|  |             { | ||||||
|  |                 (Vector3 position, Quaternion rotation, Vector3 scale) = world.Get<LocalTransform>(entity); | ||||||
|  |                 Vector3 eulerAngles = MathEx.ToEulerAngles(rotation); | ||||||
|  |                 eulerAngles = new Vector3(float.RadiansToDegrees(eulerAngles.X), float.RadiansToDegrees(eulerAngles.Y), float.RadiansToDegrees(eulerAngles.Z)); | ||||||
|  |                 bool isDirty = false; | ||||||
|  |                  | ||||||
|  |                 ImGui.BeginGroup(); | ||||||
|  |                 ImGui.Text($"{nameof(LocalTransform)}"); | ||||||
|  |                 isDirty |= ImGui.DragFloat3("Position", ref position, 0.2f, float.MinValue, float.MaxValue /*, "%f0 m" */); // TODO: right format. | ||||||
|  |                 isDirty |= ImGui.DragFloat3("Rotation", ref eulerAngles); | ||||||
|  |                 isDirty |= ImGui.DragFloat3("Scale", ref scale); | ||||||
|  |                 ImGui.EndGroup(); | ||||||
|  | 
 | ||||||
|  |                 if (!isDirty) | ||||||
|  |                 { | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 eulerAngles = new Vector3(float.DegreesToRadians(eulerAngles.X), float.DegreesToRadians(eulerAngles.Y), float.DegreesToRadians(eulerAngles.Z)); | ||||||
|  |                 world.Set(entity, new LocalTransform(position, MathEx.ToQuaternion(eulerAngles), scale)); | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             typeof(Root), (world, entity) => | ||||||
|  |             { | ||||||
|  |                 ImGui.BeginGroup(); | ||||||
|  |                 ImGui.Text($"{nameof(Root)}"); | ||||||
|  |                 ImGui.EndGroup(); | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |     }; | ||||||
|  | } | ||||||
| @@ -1,3 +1,5 @@ | |||||||
|  | using System.Numerics; | ||||||
|  | 
 | ||||||
| namespace Nerfed.Runtime; | namespace Nerfed.Runtime; | ||||||
| 
 | 
 | ||||||
| public static class MathEx | public static class MathEx | ||||||
| @@ -17,4 +19,51 @@ public static class MathEx | |||||||
|     public static float Remap(float value, float oldMin, float oldMax, float newMin, float newMax) { |     public static float Remap(float value, float oldMin, float oldMax, float newMin, float newMax) { | ||||||
|         return (value - oldMin) / (oldMax - oldMin) * (newMax - newMin) + newMin; |         return (value - oldMin) / (oldMax - oldMin) * (newMax - newMin) + newMin; | ||||||
|     } |     } | ||||||
|  |      | ||||||
|  |     // https://stackoverflow.com/questions/70462758/c-sharp-how-to-convert-quaternions-to-euler-angles-xyz | ||||||
|  |     public static Quaternion ToQuaternion(Vector3 v) | ||||||
|  |     { | ||||||
|  |         float cy = (float)Math.Cos(v.Z * 0.5); | ||||||
|  |         float sy = (float)Math.Sin(v.Z * 0.5); | ||||||
|  |         float cp = (float)Math.Cos(v.Y * 0.5); | ||||||
|  |         float sp = (float)Math.Sin(v.Y * 0.5); | ||||||
|  |         float cr = (float)Math.Cos(v.X * 0.5); | ||||||
|  |         float sr = (float)Math.Sin(v.X * 0.5); | ||||||
|  | 
 | ||||||
|  |         return new Quaternion | ||||||
|  |         { | ||||||
|  |             W = (cr * cp * cy + sr * sp * sy), | ||||||
|  |             X = (sr * cp * cy - cr * sp * sy), | ||||||
|  |             Y = (cr * sp * cy + sr * cp * sy), | ||||||
|  |             Z = (cr * cp * sy - sr * sp * cy), | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static Vector3 ToEulerAngles(Quaternion q) | ||||||
|  |     { | ||||||
|  |         Vector3 angles = new(); | ||||||
|  | 
 | ||||||
|  |         // roll / x | ||||||
|  |         double sinrCosp = 2 * (q.W * q.X + q.Y * q.Z); | ||||||
|  |         double cosrCosp = 1 - 2 * (q.X * q.X + q.Y * q.Y); | ||||||
|  |         angles.X = (float)Math.Atan2(sinrCosp, cosrCosp); | ||||||
|  | 
 | ||||||
|  |         // pitch / y | ||||||
|  |         double sinp = 2 * (q.W * q.Y - q.Z * q.X); | ||||||
|  |         if (Math.Abs(sinp) >= 1) | ||||||
|  |         { | ||||||
|  |             angles.Y = (float)Math.CopySign(Math.PI / 2, sinp); | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             angles.Y = (float)Math.Asin(sinp); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // yaw / z | ||||||
|  |         double sinyCosp = 2 * (q.W * q.Z + q.X * q.Y); | ||||||
|  |         double cosyCosp = 1 - 2 * (q.Y * q.Y + q.Z * q.Z); | ||||||
|  |         angles.Z = (float)Math.Atan2(sinyCosp, cosyCosp); | ||||||
|  | 
 | ||||||
|  |         return angles; | ||||||
|  |     } | ||||||
| } | } | ||||||
							
								
								
									
										13
									
								
								Nerfed.Runtime/Util/RandomId.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								Nerfed.Runtime/Util/RandomId.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | using System.Security.Cryptography; | ||||||
|  | 
 | ||||||
|  | namespace Nerfed.Runtime.Util; | ||||||
|  | 
 | ||||||
|  | public static class RandomId | ||||||
|  | { | ||||||
|  |     public static uint GenerateSecureRandomUInt() | ||||||
|  |     { | ||||||
|  |         byte[] buffer = new byte[4]; | ||||||
|  |         RandomNumberGenerator.Fill(buffer); | ||||||
|  |         return BitConverter.ToUInt32(buffer, 0); | ||||||
|  |     } | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user