mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 13:01:52 +00:00
DotNet script changes transform
This commit is contained in:
@@ -0,0 +1,229 @@
|
||||
using System.Numerics;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace DotNetScriptingHelper.Components;
|
||||
|
||||
[GameComponent, StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct LameTransformComponent
|
||||
{
|
||||
private EcsEntity _parent;
|
||||
|
||||
private Vector3 _position;
|
||||
private Quaternion _rotation;
|
||||
private Vector3 _scale;
|
||||
|
||||
private Vector3 _editorRotationEuler;
|
||||
|
||||
private Matrix4x4 _localTransform;
|
||||
private bool _isDirty;
|
||||
private Matrix4x4 _worldTransform;
|
||||
|
||||
private UIntPtr _frame;
|
||||
|
||||
public EcsEntity Parent
|
||||
{
|
||||
get => _parent;
|
||||
set
|
||||
{
|
||||
if (_parent == value)
|
||||
return;
|
||||
|
||||
_parent = value;
|
||||
_isDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
public Matrix4x4 LocalTransform
|
||||
{
|
||||
get => _localTransform;
|
||||
set
|
||||
{
|
||||
if (_localTransform == value)
|
||||
return;
|
||||
|
||||
_localTransform = value;
|
||||
|
||||
Matrix4x4.Decompose(_localTransform, out _position, out _rotation, out _scale);
|
||||
_isDirty = true;
|
||||
}
|
||||
}
|
||||
// Todo: WorldTransform?
|
||||
|
||||
public Vector3 Position
|
||||
{
|
||||
get => _position;
|
||||
set
|
||||
{
|
||||
if (_position == value)
|
||||
return;
|
||||
|
||||
_position = value;
|
||||
_isDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
public Quaternion Rotation
|
||||
{
|
||||
get => _rotation;
|
||||
set
|
||||
{
|
||||
if (_rotation == value)
|
||||
return;
|
||||
|
||||
_rotation = value;
|
||||
_isDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
public (Vector3 Axis, float Angle) RotationAxisAngle
|
||||
{
|
||||
get => _rotation.ToAxisAngle();
|
||||
set
|
||||
{
|
||||
Quaternion quat = Quaternion.CreateFromAxisAngle(value.Axis, value.Angle);
|
||||
|
||||
if (_rotation == quat)
|
||||
return;
|
||||
|
||||
_rotation = quat;
|
||||
_isDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 RotationEuler
|
||||
{
|
||||
get => _rotation.ToEulerAngles();
|
||||
set => Rotation = Quaternion.CreateFromYawPitchRoll(value.Y, value.X, value.Z);
|
||||
}
|
||||
|
||||
public Vector3 Scale
|
||||
{
|
||||
get => _scale;
|
||||
set
|
||||
{
|
||||
if (_scale == value)
|
||||
return;
|
||||
|
||||
_scale = value;
|
||||
_isDirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe struct TransformComponent
|
||||
{
|
||||
[GameComponent, StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
internal struct TransformComponentData
|
||||
{
|
||||
internal EcsEntity _parent;
|
||||
|
||||
internal Vector3 _position;
|
||||
internal Quaternion _rotation;
|
||||
internal Vector3 _scale;
|
||||
|
||||
internal Vector3 _editorRotationEuler;
|
||||
|
||||
internal Matrix4x4 _localTransform;
|
||||
internal bool _isDirty;
|
||||
internal Matrix4x4 _worldTransform;
|
||||
|
||||
internal UIntPtr _frame;
|
||||
}
|
||||
|
||||
private TransformComponentData* _component;
|
||||
|
||||
internal TransformComponent(IntPtr component)
|
||||
{
|
||||
_component = (TransformComponentData*)component;
|
||||
}
|
||||
|
||||
public EcsEntity Parent
|
||||
{
|
||||
get => _component->_parent;
|
||||
set
|
||||
{
|
||||
if (_component->_parent == value)
|
||||
return;
|
||||
|
||||
_component->_parent = value;
|
||||
_component->_isDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
public Matrix4x4 LocalTransform
|
||||
{
|
||||
get => _component->_localTransform;
|
||||
set
|
||||
{
|
||||
if (_component->_localTransform == value)
|
||||
return;
|
||||
|
||||
_component->_localTransform = value;
|
||||
|
||||
Matrix4x4.Decompose(_component->_localTransform,
|
||||
out _component->_position, out _component->_rotation, out _component->_scale);
|
||||
_component->_isDirty = true;
|
||||
}
|
||||
}
|
||||
// Todo: WorldTransform?
|
||||
|
||||
public Vector3 Position
|
||||
{
|
||||
get => _component->_position;
|
||||
set
|
||||
{
|
||||
if (_component->_position == value)
|
||||
return;
|
||||
|
||||
_component->_position = value;
|
||||
_component->_isDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
public Quaternion Rotation
|
||||
{
|
||||
get => _component->_rotation;
|
||||
set
|
||||
{
|
||||
if (_component->_rotation == value)
|
||||
return;
|
||||
|
||||
_component->_rotation = value;
|
||||
_component->_isDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
public (Vector3 Axis, float Angle) RotationAxisAngle
|
||||
{
|
||||
get => _component->_rotation.ToAxisAngle();
|
||||
set
|
||||
{
|
||||
Quaternion quat = Quaternion.CreateFromAxisAngle(value.Axis, value.Angle);
|
||||
|
||||
if (_component->_rotation == quat)
|
||||
return;
|
||||
|
||||
_component->_rotation = quat;
|
||||
_component->_isDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 RotationEuler
|
||||
{
|
||||
get => _component->_rotation.ToEulerAngles();
|
||||
set => Rotation = Quaternion.CreateFromYawPitchRoll(value.Y, value.X, value.Z);
|
||||
}
|
||||
|
||||
public Vector3 Scale
|
||||
{
|
||||
get => _component->_scale;
|
||||
set
|
||||
{
|
||||
if (_component->_scale == value)
|
||||
return;
|
||||
|
||||
_component->_scale = value;
|
||||
_component->_isDirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,4 +20,14 @@ public readonly struct EcsEntity
|
||||
public bool IsValid => Index != InvalidEntity.Index;
|
||||
|
||||
public static readonly EcsEntity InvalidEntity = new(uint.MaxValue, 0);
|
||||
|
||||
public static bool operator ==(EcsEntity left, EcsEntity right)
|
||||
{
|
||||
return left._id == right._id;
|
||||
}
|
||||
|
||||
public static bool operator !=(EcsEntity left, EcsEntity right)
|
||||
{
|
||||
return left._id != right._id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,14 +2,15 @@
|
||||
|
||||
public struct Entity
|
||||
{
|
||||
public EcsEntity Handle { get; private set; }
|
||||
// TODO: Scene
|
||||
public EcsEntity Handle { get; }
|
||||
public IntPtr Scene { get; }
|
||||
|
||||
public bool IsValid => Handle.IsValid;
|
||||
|
||||
public Entity(EcsEntity handle)
|
||||
public Entity(EcsEntity handle, IntPtr scene)
|
||||
{
|
||||
Handle = handle;
|
||||
Scene = scene;
|
||||
}
|
||||
|
||||
// TODO: Get Parent, Children
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
namespace DotNetScriptingHelper;
|
||||
|
||||
public class GameTime
|
||||
{
|
||||
private ulong _frameCount;
|
||||
|
||||
private TimeSpan _totalTime;
|
||||
private TimeSpan _frameTime;
|
||||
|
||||
public ulong FrameCount => _frameCount;
|
||||
public TimeSpan TotalTime => _totalTime;
|
||||
public TimeSpan FrameTime => _frameTime;
|
||||
|
||||
public float DeltaTime => (float)_frameTime.TotalSeconds;
|
||||
public float TotalSeconds => (float)_totalTime.TotalSeconds;
|
||||
|
||||
internal GameTime(ulong frameCount, TimeSpan totalTime, TimeSpan frameTime)
|
||||
{
|
||||
_frameCount = frameCount;
|
||||
_totalTime = totalTime;
|
||||
_frameTime = frameTime;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace DotNetScriptingHelper;
|
||||
|
||||
public interface IGameComponent
|
||||
{
|
||||
static int I { get; }
|
||||
}
|
||||
|
||||
public class GameComponentAttribute : Attribute
|
||||
{
|
||||
public GameComponentAttribute()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
using System.Numerics;
|
||||
|
||||
namespace DotNetScriptingHelper;
|
||||
|
||||
public static class QuaternionExtensions
|
||||
{
|
||||
public static (Vector3 Axis, float Angle) ToAxisAngle(this Quaternion quat)
|
||||
{
|
||||
// scalar part = cos(θ/2)
|
||||
// So, we can extract the angle directly.
|
||||
float angle = 2.0f * MathF.Acos(quat.W);
|
||||
|
||||
// vector part = axis * sin(θ/2)
|
||||
// In other words, the vector part is the axis, but with length of sin(θ/2).
|
||||
// We assume quaternion is unit length, so subtracting w^2 gives us length of just vector part (aka sin(θ/2)).
|
||||
float length = MathF.Sqrt(1.0f - (quat.W * quat.W));
|
||||
|
||||
Vector3 axis;
|
||||
|
||||
// Normalize vector part to get the axis!
|
||||
if (length == 0)
|
||||
{
|
||||
axis = Vector3.Zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
length = 1.0f / length;
|
||||
axis.X = quat.X * length;
|
||||
axis.Y = quat.Y * length;
|
||||
axis.Z = quat.Z * length;
|
||||
}
|
||||
|
||||
return (axis, angle);
|
||||
}
|
||||
|
||||
public static Vector3 ToEulerAngles(this Quaternion q)
|
||||
{
|
||||
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/
|
||||
|
||||
Vector3 result;
|
||||
|
||||
float sqw = q.W * q.W;
|
||||
float sqx = q.X * q.X;
|
||||
float sqy = q.Y * q.Y;
|
||||
float sqz = q.Z * q.Z;
|
||||
float unit = sqx + sqy + sqz + sqw; // if normalised is one, otherwise is correction factor
|
||||
float test = q.X * q.Y + q.Z * q.W;
|
||||
if (test > 0.4999f * unit)
|
||||
{ // singularity at north pole
|
||||
result.Y = 2.0f * MathF.Atan2(q.X, q.W);
|
||||
result.Z = MathF.PI / 2.0f;
|
||||
result.X = 0.0f;
|
||||
return result;
|
||||
}
|
||||
if (test < -0.4999f * unit)
|
||||
{ // singularity at south pole
|
||||
result.Y = -2.0f * MathF.Atan2(q.X, q.W);
|
||||
result.Z = -MathF.PI / 2.0f;
|
||||
result.X = 0.0f;
|
||||
return result;
|
||||
}
|
||||
result.Y = MathF.Atan2(2 * q.Y * q.W - 2 * q.X * q.Z, sqx - sqy - sqz + sqw);
|
||||
result.Z = MathF.Asin(2 * test / unit);
|
||||
result.X = MathF.Atan2(2 * q.X * q.W - 2 * q.Y * q.Z, -sqx + sqy - sqz + sqw);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using DotNetScriptingHelper.Components;
|
||||
|
||||
namespace DotNetScriptingHelper;
|
||||
|
||||
@@ -9,10 +11,10 @@ public abstract class ScriptableEntity
|
||||
|
||||
public virtual void OnCreate() { }
|
||||
protected virtual void OnDestroy() { }
|
||||
protected virtual void OnUpdate() { }
|
||||
protected virtual void OnUpdate(GameTime gameTime) { }
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static IntPtr CreateInstance(IntPtr typeNamePtr, int typeNameLength, EcsEntity entity)
|
||||
public static IntPtr CreateInstance(IntPtr typeNamePtr, int typeNameLength, EcsEntity entity, IntPtr scene)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -31,7 +33,7 @@ public abstract class ScriptableEntity
|
||||
if (instance is not ScriptableEntity scriptableEntity)
|
||||
return IntPtr.Zero;
|
||||
|
||||
scriptableEntity.Entity = new Entity(entity);
|
||||
scriptableEntity.Entity = new Entity(entity, scene);
|
||||
scriptableEntity.OnCreate();
|
||||
|
||||
GCHandle handle = GCHandle.Alloc(instance);
|
||||
@@ -58,13 +60,39 @@ public abstract class ScriptableEntity
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static void UpdateEntity(IntPtr entityPtr)
|
||||
public static void UpdateEntity(IntPtr entityPtr, ulong frameCount, TimeSpan totalTime, TimeSpan frameTime)
|
||||
{
|
||||
GCHandle entityHandle = GCHandle.FromIntPtr(entityPtr);
|
||||
|
||||
if (entityHandle.Target is ScriptableEntity entity)
|
||||
{
|
||||
entity.OnUpdate();
|
||||
GameTime gameTime = new GameTime(frameCount, totalTime, frameTime);
|
||||
|
||||
entity.OnUpdate(gameTime);
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport("GlitchyEditor.exe", EntryPoint = "GE_DoStuff")]
|
||||
static extern int DoStuff();
|
||||
|
||||
[DllImport("GlitchyEditor.exe", EntryPoint = "GE_DotNetScript_GetComponent")]
|
||||
private static extern IntPtr GetComponent(EcsEntity entity, IntPtr scenePtr);
|
||||
|
||||
protected TransformComponent GetTransform()// where T : struct
|
||||
{
|
||||
IntPtr component = GetComponent(Entity.Handle, Entity.Scene);
|
||||
|
||||
return new TransformComponent(component);
|
||||
|
||||
//unsafe
|
||||
//{
|
||||
// TransformComponent* transform = (TransformComponent*)component;
|
||||
|
||||
// return ref *transform;
|
||||
//}
|
||||
|
||||
//GameComponentAttribute? attribute = typeof(T).GetCustomAttribute<GameComponentAttribute>();
|
||||
|
||||
//Debug.Assert(attribute != null, $"Requested type {typeof(T)} is not a component.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,39 @@
|
||||
using System.Diagnostics;
|
||||
using System.Numerics;
|
||||
using DotNetScriptingHelper.Components;
|
||||
|
||||
namespace DotNetScriptingHelper;
|
||||
|
||||
public class TestEntityScript : ScriptableEntity
|
||||
{
|
||||
public int Inty = 1337;
|
||||
private TransformComponent _transform;
|
||||
|
||||
protected override void OnUpdate()
|
||||
public override void OnCreate()
|
||||
{
|
||||
Debug.WriteLine($"My Number is {Inty++}");
|
||||
_transform = GetTransform();
|
||||
}
|
||||
|
||||
protected override void OnUpdate(GameTime gameTime)
|
||||
{
|
||||
float f = (float)Math.Sin(gameTime.TotalSeconds);
|
||||
|
||||
Vector3 pos = _transform.Position;
|
||||
|
||||
pos.Y = f;
|
||||
|
||||
_transform.Position = pos;
|
||||
|
||||
float fx = MathF.Sin(gameTime.TotalSeconds * 2) / 2 + 1;
|
||||
float fy = MathF.Cos(gameTime.TotalSeconds * 2) / 2 + 1;
|
||||
|
||||
Vector3 scl = _transform.Scale;
|
||||
|
||||
scl.X = fx;
|
||||
scl.Y = fy;
|
||||
|
||||
_transform.Scale = scl;
|
||||
|
||||
float fr = MathF.Cos(gameTime.TotalSeconds / 4) * MathF.PI * 10;
|
||||
|
||||
_transform.Rotation = Quaternion.CreateFromYawPitchRoll(0, 0, fr);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user