Compare commits
21 Commits
main
...
developmen
Author | SHA1 | Date | |
---|---|---|---|
0bf38234c6 | |||
ed6969c16a | |||
b0b421151f | |||
41c5def097 | |||
fbbdfb07fa | |||
bf283d804c | |||
063ea08707 | |||
fd11a94ddf | |||
be2295b92d | |||
a93e55619c | |||
48ae24af47 | |||
1366a417f1 | |||
4bfe98852c | |||
98edbe1af5 | |||
3725a3b0fd | |||
f43ab36742 | |||
c7aafd85bc | |||
5de08b8fe4 | |||
16e4077d40 | |||
fc3c1ed1f9 | |||
b100b5c2fe |
2
Engine.Core/.gitignore
vendored
2
Engine.Core/.gitignore
vendored
@ -482,3 +482,5 @@ $RECYCLE.BIN/
|
||||
|
||||
# Vim temporary swap files
|
||||
*.swp
|
||||
|
||||
!Debug
|
||||
|
@ -53,7 +53,7 @@ public abstract class Behaviour : BehaviourBase
|
||||
protected virtual void OnPreUpdate() { }
|
||||
protected virtual void PreUpdate(IBehaviourController _)
|
||||
{
|
||||
Debug.AssertHelpers.AssertInitialized(this);
|
||||
Debug.Assert.AssertInitialized(this);
|
||||
|
||||
OnPreUpdatePreActiveCheck();
|
||||
|
||||
@ -77,7 +77,7 @@ public abstract class Behaviour : BehaviourBase
|
||||
protected virtual void OnUpdate() { }
|
||||
protected virtual void Update(IBehaviourController _)
|
||||
{
|
||||
Debug.AssertHelpers.AssertInitialized(this);
|
||||
Debug.Assert.AssertInitialized(this);
|
||||
|
||||
OnUpdatePreActiveCheck();
|
||||
|
||||
@ -91,7 +91,7 @@ public abstract class Behaviour : BehaviourBase
|
||||
protected virtual void OnPreDraw() { }
|
||||
protected virtual void PreDraw(IBehaviourController _)
|
||||
{
|
||||
Debug.AssertHelpers.AssertInitialized(this);
|
||||
Debug.Assert.AssertInitialized(this);
|
||||
|
||||
OnPreDrawPreActiveCheck();
|
||||
|
||||
|
@ -66,8 +66,8 @@ public abstract class BehaviourBase : BaseEntity, IBehaviour
|
||||
|
||||
protected override void InitializeInternal()
|
||||
{
|
||||
Debug.AssertHelpers.AssertBehaviourControllerAssigned(this);
|
||||
Debug.AssertHelpers.AssertStateEnableAssigned(this);
|
||||
Debug.Assert.AssertBehaviourControllerAssigned(this);
|
||||
Debug.Assert.AssertStateEnableAssigned(this);
|
||||
}
|
||||
|
||||
private void OnStateEnabledChanged(IStateEnable sender, bool previousState) => UpdateActive();
|
||||
|
@ -113,7 +113,7 @@ public class BehaviourController : BaseEntity, IBehaviourController
|
||||
|
||||
protected override void InitializeInternal()
|
||||
{
|
||||
Debug.AssertHelpers.AssertUniverseObjectAssigned(this);
|
||||
Debug.Assert.AssertUniverseObjectAssigned(this);
|
||||
|
||||
foreach (IBehaviour behaviour in behaviours)
|
||||
behaviour.Initialize();
|
||||
@ -127,7 +127,7 @@ public class BehaviourController : BaseEntity, IBehaviourController
|
||||
|
||||
public void Update()
|
||||
{
|
||||
Debug.AssertHelpers.AssertInitialized(this);
|
||||
Debug.Assert.AssertInitialized(this);
|
||||
|
||||
if (!UniverseObject.StateEnable.Enabled || !StateEnable.Enabled)
|
||||
return;
|
||||
@ -138,7 +138,7 @@ public class BehaviourController : BaseEntity, IBehaviourController
|
||||
|
||||
public void UpdatePreDraw()
|
||||
{
|
||||
Debug.AssertHelpers.AssertInitialized(this);
|
||||
Debug.Assert.AssertInitialized(this);
|
||||
|
||||
if (!UniverseObject.StateEnable.Enabled || !StateEnable.Enabled)
|
||||
return;
|
||||
|
@ -2,7 +2,7 @@ using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Syntriax.Engine.Core.Debug;
|
||||
|
||||
public class AssertHelpers
|
||||
public static class Assert
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void AssertInitialized(IInitializable initializable)
|
8
Engine.Core/Debug/ConsoleLogger.cs
Normal file
8
Engine.Core/Debug/ConsoleLogger.cs
Normal file
@ -0,0 +1,8 @@
|
||||
using System;
|
||||
|
||||
namespace Syntriax.Engine.Core.Debug;
|
||||
|
||||
public class ConsoleLogger : LoggerBase
|
||||
{
|
||||
protected override void Write(string message) => Console.WriteLine(message);
|
||||
}
|
20
Engine.Core/Debug/FileLogger.cs
Normal file
20
Engine.Core/Debug/FileLogger.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Syntriax.Engine.Core.Debug;
|
||||
|
||||
public class FileLogger : LoggerBase
|
||||
{
|
||||
public readonly string FilePath;
|
||||
|
||||
public FileLogger(string filePath)
|
||||
{
|
||||
FilePath = filePath;
|
||||
File.Open(filePath, FileMode.Create).Close();
|
||||
}
|
||||
|
||||
protected override void Write(string message)
|
||||
{
|
||||
File.AppendAllTextAsync(FilePath, $"{message}{Environment.NewLine}");
|
||||
}
|
||||
}
|
15
Engine.Core/Debug/ILogger.cs
Normal file
15
Engine.Core/Debug/ILogger.cs
Normal file
@ -0,0 +1,15 @@
|
||||
namespace Syntriax.Engine.Core.Debug;
|
||||
|
||||
public interface ILogger
|
||||
{
|
||||
Level FilterLevel { get; set; }
|
||||
|
||||
void Log(string message, Level level = Level.Info, bool force = false);
|
||||
|
||||
enum Level
|
||||
{
|
||||
Info,
|
||||
Warning,
|
||||
Error,
|
||||
};
|
||||
}
|
20
Engine.Core/Debug/LoggerBase.cs
Normal file
20
Engine.Core/Debug/LoggerBase.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using System;
|
||||
|
||||
namespace Syntriax.Engine.Core.Debug;
|
||||
|
||||
public abstract class LoggerBase : ILogger
|
||||
{
|
||||
public ILogger.Level FilterLevel { get; set; } = ILogger.Level.Info;
|
||||
|
||||
public void Log(string message, ILogger.Level level = ILogger.Level.Info, bool force = false)
|
||||
{
|
||||
if (!force && level < FilterLevel)
|
||||
return;
|
||||
|
||||
string timestamp = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss tt");
|
||||
|
||||
Write($"[{timestamp}] [{level}] \t{message}");
|
||||
}
|
||||
|
||||
protected abstract void Write(string message);
|
||||
}
|
28
Engine.Core/Debug/LoggerExtensions.cs
Normal file
28
Engine.Core/Debug/LoggerExtensions.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Syntriax.Engine.Core.Debug;
|
||||
|
||||
public static class LoggerExtensions
|
||||
{
|
||||
public static void Log<T>(this ILogger logger, T caller, string message, ILogger.Level level = ILogger.Level.Info, bool force = false)
|
||||
{
|
||||
string body = $"{caller?.GetType().Name ?? typeof(T).Name}: {message}";
|
||||
logger.Log(body, level, force);
|
||||
}
|
||||
|
||||
public static void LogWarning<T>(this ILogger logger, T caller, string message, bool force = false) => Log(logger, caller, message, ILogger.Level.Info, force);
|
||||
|
||||
public static void LogError<T>(this ILogger logger, T caller, string message, bool force = false)
|
||||
{
|
||||
Log(logger, caller, message, ILogger.Level.Error, force);
|
||||
Log(logger, caller, $"{nameof(StackTrace)}:{Environment.NewLine}{new StackTrace()}");
|
||||
}
|
||||
|
||||
public static void LogException<T>(this ILogger logger, T caller, Exception exception, bool force = false)
|
||||
{
|
||||
Log(logger, caller, $"Message: {exception.Message}", ILogger.Level.Error, force);
|
||||
Log(logger, caller, $"InnerException: {exception.InnerException}", ILogger.Level.Error, force);
|
||||
Log(logger, caller, $"{nameof(StackTrace)}:{Environment.NewLine}{exception.StackTrace}");
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>false</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>Syntriax.Engine.Core</RootNamespace>
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
@ -6,7 +7,7 @@ namespace Syntriax.Engine.Core.Factory;
|
||||
|
||||
public static class TypeFactory
|
||||
{
|
||||
private static readonly Dictionary<string, Type> registeredTypes = [];
|
||||
private static readonly ConcurrentDictionary<string, Type> registeredTypes = [];
|
||||
|
||||
public static string GetTypeName(Type type) => type.FullName ?? throw new ArgumentException($"{type.Name} must be a resolvable type");
|
||||
|
||||
|
@ -2,7 +2,7 @@ using System;
|
||||
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
public static class DelegateHelpers
|
||||
public static class DelegateExtensions
|
||||
{
|
||||
public static void InvokeSafe(this Delegate @delegate, params object?[] args)
|
||||
{
|
7
Engine.Core/Helpers/Progression/IProgressionTracker.cs
Normal file
7
Engine.Core/Helpers/Progression/IProgressionTracker.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
public interface IProgressionTracker : IReadOnlyProgressionTracker
|
||||
{
|
||||
void Set(float progression, string status);
|
||||
void Reset();
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
public interface IReadOnlyProgressionTracker
|
||||
{
|
||||
event ProgressionUpdatedEventHandler? OnUpdated;
|
||||
event ProgressionEndedEventHandler? OnEnded;
|
||||
|
||||
float Progression { get; }
|
||||
string Status { get; }
|
||||
|
||||
delegate void ProgressionUpdatedEventHandler(IReadOnlyProgressionTracker sender, float previousProgression, string previousStatus);
|
||||
delegate void ProgressionEndedEventHandler(IReadOnlyProgressionTracker sender);
|
||||
}
|
36
Engine.Core/Helpers/Progression/ProgressionTracker.cs
Normal file
36
Engine.Core/Helpers/Progression/ProgressionTracker.cs
Normal file
@ -0,0 +1,36 @@
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
public class ProgressionTracker : IProgressionTracker
|
||||
{
|
||||
public event IReadOnlyProgressionTracker.ProgressionUpdatedEventHandler? OnUpdated = null;
|
||||
public event IReadOnlyProgressionTracker.ProgressionEndedEventHandler? OnEnded = null;
|
||||
|
||||
public float Progression { get; private set; } = 0f;
|
||||
public string Status { get; private set; } = "Default";
|
||||
|
||||
void IProgressionTracker.Set(float progression, string status)
|
||||
{
|
||||
if (Progression >= 1f)
|
||||
return;
|
||||
|
||||
float previousProgression = Progression;
|
||||
string previousStatus = Status;
|
||||
|
||||
Progression = progression.Clamp(Progression, 1f);
|
||||
Status = status;
|
||||
|
||||
OnUpdated?.InvokeSafe(this, previousProgression, previousStatus);
|
||||
|
||||
if (progression >= 1f)
|
||||
OnEnded?.InvokeSafe(this);
|
||||
}
|
||||
|
||||
void IProgressionTracker.Reset()
|
||||
{
|
||||
Progression = 0f;
|
||||
Status = "Default";
|
||||
|
||||
OnUpdated = null;
|
||||
OnEnded = null;
|
||||
}
|
||||
}
|
9
Engine.Core/Helpers/Progression/ProgressiveTask.cs
Normal file
9
Engine.Core/Helpers/Progression/ProgressiveTask.cs
Normal file
@ -0,0 +1,9 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
public record struct ProgressiveTask<T>(IReadOnlyProgressionTracker ProgressionTracker, Task<T> Task)
|
||||
{
|
||||
public static implicit operator (IReadOnlyProgressionTracker progressionTracker, Task<T> task)(ProgressiveTask<T> value) => (value.ProgressionTracker, value.Task);
|
||||
public static implicit operator ProgressiveTask<T>((IReadOnlyProgressionTracker progressionTracker, Task<T> task) value) => new(value.progressionTracker, value.task);
|
||||
}
|
@ -30,6 +30,13 @@ public static class Math
|
||||
/// </summary>
|
||||
public const float DegreeToRadian = PI / 180f;
|
||||
|
||||
/// <summary>
|
||||
/// Gets one minus of given <see cref="T"/>.
|
||||
/// </summary>
|
||||
/// <param name="value">The value <see cref="T"/>.</param>
|
||||
/// <returns>One minus of given <see cref="T"/>.</returns>
|
||||
public static T OneMinus<T>(T value) where T : INumber<T> => T.One - value;
|
||||
|
||||
/// <summary>
|
||||
/// Adds two <see cref="T"/>s.
|
||||
/// </summary>
|
||||
@ -242,13 +249,13 @@ public static class Math
|
||||
public static float Round(float x, int digits, MidpointRounding mode) => MathF.Round(x, digits, mode);
|
||||
|
||||
/// <summary>
|
||||
/// Rounds a number to a specified number of fractional digits.
|
||||
/// Rounds a number to an integer.
|
||||
/// </summary>
|
||||
/// <param name="x">The number to round.</param>
|
||||
/// <param name="digits">The number of fractional digits in the return value.</param>
|
||||
/// <param name="mode">Specification for how to round <paramref name="x"/> if it is midway between two other numbers.</param>
|
||||
/// <returns>The number <paramref name="x"/> rounded to <paramref name="digits"/> fractional digits.</returns>
|
||||
public static int RoundToInt(float x) => (int)MathF.Round(x, 0, MidpointRounding.ToEven);
|
||||
/// <param name="roundMode">Specification for how to round <paramref name="x"/> if it's midway between two numbers</param>
|
||||
/// <returns></returns>
|
||||
public static int RoundToInt(float x, RoundMode roundMode = RoundMode.Ceil) => (int)MathF.Round(x, 0, roundMode == RoundMode.Ceil ? MidpointRounding.ToPositiveInfinity : MidpointRounding.ToNegativeInfinity);
|
||||
public enum RoundMode { Ceil, Floor };
|
||||
|
||||
/// <summary>
|
||||
/// Returns the square of a number.
|
||||
|
@ -5,6 +5,9 @@ namespace Syntriax.Engine.Core;
|
||||
|
||||
public static class MathExtensions
|
||||
{
|
||||
/// <inheritdoc cref="Math.OneMinus{T}(T)" />
|
||||
public static T OneMinus<T>(this T value) where T : INumber<T> => Math.OneMinus(value);
|
||||
|
||||
/// <inheritdoc cref="Math.Add{T}(T, T)" />
|
||||
public static T Add<T>(this T left, T value) where T : INumber<T> => Math.Add(left, value);
|
||||
|
||||
@ -80,8 +83,8 @@ public static class MathExtensions
|
||||
/// <inheritdoc cref="Math.Round(float, int, MidpointRounding)" />
|
||||
public static float Round(this float x, int digits, MidpointRounding mode) => Math.Round(x, digits, mode);
|
||||
|
||||
/// <inheritdoc cref="Math.RoundToInt(float)" />
|
||||
public static int RoundToInt(this float x) => Math.RoundToInt(x);
|
||||
/// <inheritdoc cref="Math.RoundToInt(float, Math.RoundMode)" />
|
||||
public static int RoundToInt(this float x, Math.RoundMode roundMode = Math.RoundMode.Ceil) => Math.RoundToInt(x, roundMode);
|
||||
|
||||
/// <inheritdoc cref="Math.Sqr{T}(T)" />
|
||||
public static T Sqr<T>(this T x) where T : INumber<T> => Math.Sqr(x);
|
||||
|
10
Engine.Core/Preserver.cs
Normal file
10
Engine.Core/Preserver.cs
Normal file
@ -0,0 +1,10 @@
|
||||
namespace Syntriax.Engine.Core
|
||||
{
|
||||
// This is pretty much so the assembly gets loaded automatically because
|
||||
// the builds include the assembly but sometimes doesn't link load it at startup.
|
||||
// I will hopefully one day fix it and remove this.
|
||||
public static class Preserver
|
||||
{
|
||||
public static void Preserve() { }
|
||||
}
|
||||
}
|
185
Engine.Core/Primitives/ColorHSV.cs
Normal file
185
Engine.Core/Primitives/ColorHSV.cs
Normal file
@ -0,0 +1,185 @@
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an HSV color.
|
||||
/// </summary>
|
||||
/// <param name="hue">Hue of the <see cref="ColorHSV"/>.</param>
|
||||
/// <param name="saturation">Saturation of the <see cref="ColorHSV"/>.</param>
|
||||
/// <param name="value">Value of the <see cref="ColorHSV"/>.</param>
|
||||
/// <remarks>
|
||||
/// Initializes a new instance of the <see cref="ColorHSV"/> struct with the specified values.
|
||||
/// </remarks>
|
||||
[System.Diagnostics.DebuggerDisplay("{ToString(),nq}")]
|
||||
public readonly struct ColorHSV(float hue, float saturation, float value)
|
||||
{
|
||||
/// <summary>
|
||||
/// The Hue value of the <see cref="ColorHSV"/>.
|
||||
/// </summary>
|
||||
public readonly float Hue = hue.Clamp(0f, 1f);
|
||||
|
||||
/// <summary>
|
||||
/// The Saturation value of the <see cref="ColorHSV"/>.
|
||||
/// </summary>
|
||||
public readonly float Saturation = saturation.Clamp(0f, 1f);
|
||||
|
||||
/// <summary>
|
||||
/// The Value value of the <see cref="ColorHSV"/>.
|
||||
/// </summary>
|
||||
public readonly float Value = value.Clamp(0f, 1f);
|
||||
|
||||
public static ColorHSV operator -(ColorHSV color) => new(color.Hue.OneMinus().Clamp(0f, 1f), color.Saturation.OneMinus().Clamp(0f, 1f), color.Value.OneMinus().Clamp(0f, 1f));
|
||||
public static ColorHSV operator +(ColorHSV left, ColorHSV right) => new((left.Hue + right.Hue).Clamp(0f, 1f), (left.Saturation + right.Saturation).Clamp(0f, 1f), (left.Value + right.Value).Clamp(0f, 1f));
|
||||
public static ColorHSV operator -(ColorHSV left, ColorHSV right) => new((left.Hue - right.Hue).Clamp(0f, 1f), (left.Saturation - right.Saturation).Clamp(0f, 1f), (left.Value - right.Value).Clamp(0f, 1f));
|
||||
public static ColorHSV operator *(ColorHSV left, ColorHSV right) => new((left.Hue * right.Hue).Clamp(0f, 1f), (left.Saturation * right.Saturation).Clamp(0f, 1f), (left.Value * right.Value).Clamp(0f, 1f));
|
||||
public static ColorHSV operator *(ColorHSV color, float value) => new((color.Hue * value).Clamp(0f, 1f), (color.Saturation * value).Clamp(0f, 1f), (color.Value * value).Clamp(0f, 1f));
|
||||
public static ColorHSV operator *(float value, ColorHSV color) => new((color.Hue * value).Clamp(0f, 1f), (color.Saturation * value).Clamp(0f, 1f), (color.Value * value).Clamp(0f, 1f));
|
||||
public static ColorHSV operator /(ColorHSV color, float value) => new((color.Hue / value).Clamp(0f, 1f), (color.Saturation / value).Clamp(0f, 1f), (color.Value / value).Clamp(0f, 1f));
|
||||
public static bool operator ==(ColorHSV left, ColorHSV right) => left.Hue.ApproximatelyEquals(right.Hue) && left.Saturation.ApproximatelyEquals(right.Saturation) && left.Value.ApproximatelyEquals(right.Value);
|
||||
public static bool operator !=(ColorHSV left, ColorHSV right) => !left.Hue.ApproximatelyEquals(right.Hue) || !left.Saturation.ApproximatelyEquals(right.Saturation) || !left.Value.ApproximatelyEquals(right.Value);
|
||||
|
||||
public static implicit operator ColorHSV(ColorRGBA rgba) => (ColorRGB)rgba;
|
||||
public static implicit operator ColorHSV(ColorRGB rgb)
|
||||
{
|
||||
float hue;
|
||||
float saturation;
|
||||
float value;
|
||||
|
||||
float rd = rgb.R / 255f;
|
||||
float gd = rgb.G / 255f;
|
||||
float bd = rgb.B / 255f;
|
||||
|
||||
float max = Math.Max(rd, Math.Max(gd, bd));
|
||||
float min = Math.Min(rd, Math.Min(gd, bd));
|
||||
float delta = max - min;
|
||||
|
||||
if (delta.ApproximatelyEquals(0))
|
||||
hue = 0f;
|
||||
else if (max.ApproximatelyEquals(rd))
|
||||
hue = 60f * ((gd - bd) / delta % 6f);
|
||||
else if (max.ApproximatelyEquals(gd))
|
||||
hue = 60f * (((bd - rd) / delta) + 2f);
|
||||
else
|
||||
hue = 60f * (((rd - gd) / delta) + 4f);
|
||||
|
||||
if (hue < 0f)
|
||||
hue += 360f;
|
||||
|
||||
hue /= 360f;
|
||||
saturation = max.ApproximatelyEquals(0f) ? 0f : delta / max;
|
||||
value = max;
|
||||
|
||||
return new(hue, saturation, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inverts the given <see cref="ColorHSV"/>.
|
||||
/// </summary>
|
||||
/// <param name="color">The <see cref="ColorHSV"/>.</param>
|
||||
/// <returns>The inverted <see cref="ColorHSV"/>.</returns>
|
||||
public static ColorHSV Invert(ColorHSV color) => -color;
|
||||
|
||||
/// <summary>
|
||||
/// Adds two <see cref="ColorHSV"/>s.
|
||||
/// </summary>
|
||||
/// <param name="left">The first <see cref="ColorHSV"/>.</param>
|
||||
/// <param name="right">The second <see cref="ColorHSV"/>.</param>
|
||||
/// <returns>The sum of the two <see cref="ColorHSV"/>s.</returns>
|
||||
public static ColorHSV Add(ColorHSV left, ColorHSV right) => left + right;
|
||||
|
||||
/// <summary>
|
||||
/// Subtracts one <see cref="ColorHSV"/> from another.
|
||||
/// </summary>
|
||||
/// <param name="left">The <see cref="ColorHSV"/> to subtract from.</param>
|
||||
/// <param name="right">The <see cref="ColorHSV"/> to subtract.</param>
|
||||
/// <returns>The result of subtracting the second <see cref="ColorHSV"/> from the first.</returns>
|
||||
public static ColorHSV Subtract(ColorHSV left, ColorHSV right) => left - right;
|
||||
|
||||
/// <summary>
|
||||
/// Multiplies a <see cref="ColorHSV"/> by a scalar value.
|
||||
/// </summary>
|
||||
/// <param name="color">The <see cref="ColorHSV"/>.</param>
|
||||
/// <param name="value">The scalar value.</param>
|
||||
/// <returns>The result of multiplying the <see cref="ColorHSV"/> by the scalar value.</returns>
|
||||
public static ColorHSV Multiply(ColorHSV color, float value) => color * value;
|
||||
|
||||
/// <summary>
|
||||
/// Divides a <see cref="ColorHSV"/> by a scalar value.
|
||||
/// </summary>
|
||||
/// <param name="color">The <see cref="ColorHSV"/>.</param>
|
||||
/// <param name="value">The scalar value.</param>
|
||||
/// <returns>The result of dividing the <see cref="ColorHSV"/> by the scalar value.</returns>
|
||||
public static ColorHSV Divide(ColorHSV color, float value) => color / value;
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the <see cref="ColorHSV"/> from one point to another.
|
||||
/// </summary>
|
||||
/// <param name="from">The starting point.</param>
|
||||
/// <param name="to">The ending point.</param>
|
||||
/// <returns>The <see cref="ColorHSV"/> from the starting point to the ending point.</returns>
|
||||
public static ColorHSV FromTo(ColorHSV from, ColorHSV to) => to - from;
|
||||
|
||||
/// <summary>
|
||||
/// Performs linear interpolation between two <see cref="ColorHSV"/>s.
|
||||
/// </summary>
|
||||
/// <param name="from">The starting <see cref="ColorHSV"/> (t = 0).</param>
|
||||
/// <param name="to">The ending <see cref="ColorHSV"/> (t = 1).</param>
|
||||
/// <param name="t">The interpolation parameter.</param>
|
||||
/// <returns>The interpolated <see cref="ColorHSV"/>.</returns>
|
||||
public static ColorHSV Lerp(ColorHSV from, ColorHSV to, float t) => from + FromTo(from, to) * t;
|
||||
|
||||
/// <summary>
|
||||
/// Converts the <see cref="ColorHSV"/> to its string representation.
|
||||
/// </summary>
|
||||
/// <returns>A string representation of the <see cref="ColorHSV"/>.</returns>
|
||||
public override string ToString() => $"{nameof(ColorHSV)}({Hue}, {Saturation}, {Value})";
|
||||
|
||||
/// <summary>
|
||||
/// Checks if two <see cref="ColorHSV"/>s are approximately equal within a specified epsilon range.
|
||||
/// </summary>
|
||||
/// <param name="left">The first <see cref="ColorHSV"/>.</param>
|
||||
/// <param name="right">The second <see cref="ColorHSV"/>.</param>
|
||||
/// <param name="epsilon">The epsilon range.</param>
|
||||
/// <returns><see cref="true"/> if the <see cref="ColorHSV"/>s are approximately equal; otherwise, <see cref="false"/>.</returns>
|
||||
public static bool ApproximatelyEquals(ColorHSV left, ColorHSV right, float epsilon = float.Epsilon)
|
||||
=> left.Hue.ApproximatelyEquals(right.Hue, epsilon) && left.Saturation.ApproximatelyEquals(right.Saturation, epsilon) && left.Value.ApproximatelyEquals(right.Value, epsilon);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified object is equal to the current <see cref="ColorHSV"/>.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to compare with the current <see cref="ColorHSV"/>.</param>
|
||||
/// <returns><see cref="true"/> if the specified object is equal to the current <see cref="ColorHSV"/>; otherwise, <see cref="false"/>.</returns>
|
||||
public override bool Equals(object? obj) => obj is ColorHSV objVec && Hue.Equals(objVec.Hue) && Saturation.Equals(objVec.Saturation) && Value.Equals(objVec.Value);
|
||||
|
||||
/// <summary>
|
||||
/// Generates a hash code for the <see cref="ColorHSV"/>.
|
||||
/// </summary>
|
||||
/// <returns>A hash code for the <see cref="ColorHSV"/>.</returns>
|
||||
public override int GetHashCode() => System.HashCode.Combine(Hue, Saturation, Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for <see cref="ColorHSV"/> type.
|
||||
/// </summary>
|
||||
public static class ColorHSVExtensions
|
||||
{
|
||||
/// <inheritdoc cref="ColorHSV.Add(ColorHSV, ColorHSV)" />
|
||||
public static ColorHSV Add(this ColorHSV color, ColorHSV value) => ColorHSV.Add(color, value);
|
||||
|
||||
/// <inheritdoc cref="ColorHSV.Subtract(ColorHSV, ColorHSV)" />
|
||||
public static ColorHSV Subtract(this ColorHSV color, ColorHSV value) => ColorHSV.Subtract(color, value);
|
||||
|
||||
/// <inheritdoc cref="ColorHSV.Multiply(ColorHSV, ColorHSV)" />
|
||||
public static ColorHSV Multiply(this ColorHSV color, float value) => ColorHSV.Multiply(color, value);
|
||||
|
||||
/// <inheritdoc cref="ColorHSV.Divide(ColorHSV, ColorHSV)" />
|
||||
public static ColorHSV Divide(this ColorHSV color, float value) => ColorHSV.Divide(color, value);
|
||||
|
||||
/// <inheritdoc cref="ColorHSV.FromTo(ColorHSV, ColorHSV)" />
|
||||
public static ColorHSV FromTo(this ColorHSV from, ColorHSV to) => ColorHSV.FromTo(from, to);
|
||||
|
||||
/// <inheritdoc cref="ColorHSV.Lerp(ColorHSV, ColorHSV, float)" />
|
||||
public static ColorHSV Lerp(this ColorHSV from, ColorHSV to, float t) => ColorHSV.Lerp(from, to, t);
|
||||
|
||||
/// <inheritdoc cref="ColorHSV.ApproximatelyEquals(ColorHSV, ColorHSV, float) " />
|
||||
public static bool ApproximatelyEquals(this ColorHSV left, ColorHSV right, float epsilon = float.Epsilon) => ColorHSV.ApproximatelyEquals(left, right, epsilon);
|
||||
}
|
164
Engine.Core/Primitives/ColorRGB.cs
Normal file
164
Engine.Core/Primitives/ColorRGB.cs
Normal file
@ -0,0 +1,164 @@
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an RGB color.
|
||||
/// </summary>
|
||||
/// <param name="r">Red value of the <see cref="ColorRGB"/>.</param>
|
||||
/// <param name="g">Green value of the <see cref="ColorRGB"/>.</param>
|
||||
/// <param name="b">Blue value of the <see cref="ColorRGB"/>.</param>
|
||||
/// <remarks>
|
||||
/// Initializes a new instance of the <see cref="ColorRGB"/> struct with the specified values.
|
||||
/// </remarks>
|
||||
[System.Diagnostics.DebuggerDisplay("{ToString(),nq}")]
|
||||
public readonly struct ColorRGB(byte r, byte g, byte b)
|
||||
{
|
||||
/// <summary>
|
||||
/// The Red value of the <see cref="ColorRGB"/>.
|
||||
/// </summary>
|
||||
public readonly byte R = r;
|
||||
|
||||
/// <summary>
|
||||
/// The Green value of the <see cref="ColorRGB"/>.
|
||||
/// </summary>
|
||||
public readonly byte G = g;
|
||||
|
||||
/// <summary>
|
||||
/// The Blue value of the <see cref="ColorRGB"/>.
|
||||
/// </summary>
|
||||
public readonly byte B = b;
|
||||
|
||||
public static ColorRGB operator -(ColorRGB color) => new((byte)(255 - color.R), (byte)(255 - color.G), (byte)(255 - color.B));
|
||||
public static ColorRGB operator +(ColorRGB left, ColorRGB right) => new((byte)(left.R + right.R).Clamp(0, 255), (byte)(left.G + right.G).Clamp(0, 255), (byte)(left.B + right.B).Clamp(0, 255));
|
||||
public static ColorRGB operator -(ColorRGB left, ColorRGB right) => new((byte)(left.R - right.R).Clamp(0, 255), (byte)(left.G - right.G).Clamp(0, 255), (byte)(left.B - right.B).Clamp(0, 255));
|
||||
public static ColorRGB operator *(ColorRGB left, ColorRGB right) => new((byte)(left.R * right.R).Clamp(0, 255), (byte)(left.G * right.G).Clamp(0, 255), (byte)(left.B * right.B).Clamp(0, 255));
|
||||
public static ColorRGB operator *(ColorRGB color, float value) => new((byte)(color.R * value).Clamp(0, 255), (byte)(color.G * value).Clamp(0, 255), (byte)(color.B * value).Clamp(0, 255));
|
||||
public static ColorRGB operator *(float value, ColorRGB color) => new((byte)(color.R * value).Clamp(0, 255), (byte)(color.G * value).Clamp(0, 255), (byte)(color.B * value).Clamp(0, 255));
|
||||
public static ColorRGB operator /(ColorRGB color, float value) => new((byte)(color.R / value).Clamp(0, 255), (byte)(color.G / value).Clamp(0, 255), (byte)(color.B / value).Clamp(0, 255));
|
||||
public static bool operator ==(ColorRGB left, ColorRGB right) => left.R == right.R && left.G == right.G && left.B == right.B;
|
||||
public static bool operator !=(ColorRGB left, ColorRGB right) => left.R != right.R || left.G != right.G || left.B != right.B;
|
||||
|
||||
public static implicit operator ColorRGB(ColorRGBA rgba) => new(rgba.R, rgba.G, rgba.B);
|
||||
public static implicit operator ColorRGB(ColorHSV hsv)
|
||||
{
|
||||
float hue = hsv.Hue * 360f;
|
||||
float chroma = hsv.Value * hsv.Saturation;
|
||||
float x = chroma * (1f - Math.Abs(hue / 60f % 2f - 1f));
|
||||
float m = hsv.Value - chroma;
|
||||
|
||||
float r1 = 0f;
|
||||
float g1 = 0f;
|
||||
float b1 = 0f;
|
||||
|
||||
if (hue < 60) { r1 = chroma; g1 = x; b1 = 0; }
|
||||
else if (hue < 120) { r1 = x; g1 = chroma; b1 = 0; }
|
||||
else if (hue < 180) { r1 = 0; g1 = chroma; b1 = x; }
|
||||
else if (hue < 240) { r1 = 0; g1 = x; b1 = chroma; }
|
||||
else if (hue < 300) { r1 = x; g1 = 0; b1 = chroma; }
|
||||
else if (hue <= 360) { r1 = chroma; g1 = 0; b1 = x; }
|
||||
|
||||
byte r = (byte)Math.RoundToInt((r1 + m) * 255);
|
||||
byte g = (byte)Math.RoundToInt((g1 + m) * 255);
|
||||
byte b = (byte)Math.RoundToInt((b1 + m) * 255);
|
||||
|
||||
return new(r, g, b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inverts the given <see cref="ColorRGB"/>.
|
||||
/// </summary>
|
||||
/// <param name="color">The <see cref="ColorRGB"/>.</param>
|
||||
/// <returns>The inverted <see cref="ColorRGB"/>.</returns>
|
||||
public static ColorRGB Invert(ColorRGB color) => -color;
|
||||
|
||||
/// <summary>
|
||||
/// Adds two <see cref="ColorRGB"/>s.
|
||||
/// </summary>
|
||||
/// <param name="left">The first <see cref="ColorRGB"/>.</param>
|
||||
/// <param name="right">The second <see cref="ColorRGB"/>.</param>
|
||||
/// <returns>The sum of the two <see cref="ColorRGB"/>s.</returns>
|
||||
public static ColorRGB Add(ColorRGB left, ColorRGB right) => left + right;
|
||||
|
||||
/// <summary>
|
||||
/// Subtracts one <see cref="ColorRGB"/> from another.
|
||||
/// </summary>
|
||||
/// <param name="left">The <see cref="ColorRGB"/> to subtract from.</param>
|
||||
/// <param name="right">The <see cref="ColorRGB"/> to subtract.</param>
|
||||
/// <returns>The result of subtracting the second <see cref="ColorRGB"/> from the first.</returns>
|
||||
public static ColorRGB Subtract(ColorRGB left, ColorRGB right) => left - right;
|
||||
|
||||
/// <summary>
|
||||
/// Multiplies a <see cref="ColorRGB"/> by a scalar value.
|
||||
/// </summary>
|
||||
/// <param name="color">The <see cref="ColorRGB"/>.</param>
|
||||
/// <param name="value">The scalar value.</param>
|
||||
/// <returns>The result of multiplying the <see cref="ColorRGB"/> by the scalar value.</returns>
|
||||
public static ColorRGB Multiply(ColorRGB color, float value) => color * value;
|
||||
|
||||
/// <summary>
|
||||
/// Divides a <see cref="ColorRGB"/> by a scalar value.
|
||||
/// </summary>
|
||||
/// <param name="color">The <see cref="ColorRGB"/>.</param>
|
||||
/// <param name="value">The scalar value.</param>
|
||||
/// <returns>The result of dividing the <see cref="ColorRGB"/> by the scalar value.</returns>
|
||||
public static ColorRGB Divide(ColorRGB color, float value) => color / value;
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the <see cref="ColorRGB"/> from one point to another.
|
||||
/// </summary>
|
||||
/// <param name="from">The starting point.</param>
|
||||
/// <param name="to">The ending point.</param>
|
||||
/// <returns>The <see cref="ColorRGB"/> from the starting point to the ending point.</returns>
|
||||
public static ColorRGB FromTo(ColorRGB from, ColorRGB to) => to - from;
|
||||
|
||||
/// <summary>
|
||||
/// Performs linear interpolation between two <see cref="ColorRGB"/>s.
|
||||
/// </summary>
|
||||
/// <param name="from">The starting <see cref="ColorRGB"/> (t = 0).</param>
|
||||
/// <param name="to">The ending <see cref="ColorRGB"/> (t = 1).</param>
|
||||
/// <param name="t">The interpolation parameter.</param>
|
||||
/// <returns>The interpolated <see cref="ColorRGB"/>.</returns>
|
||||
public static ColorRGB Lerp(ColorRGB from, ColorRGB to, float t) => from + FromTo(from, to) * t;
|
||||
|
||||
/// <summary>
|
||||
/// Converts the <see cref="ColorRGB"/> to its string representation.
|
||||
/// </summary>
|
||||
/// <returns>A string representation of the <see cref="ColorRGB"/>.</returns>
|
||||
public override string ToString() => $"{nameof(ColorRGB)}({R}, {G}, {B})";
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified object is equal to the current <see cref="ColorRGB"/>.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to compare with the current <see cref="ColorRGB"/>.</param>
|
||||
/// <returns><see cref="true"/> if the specified object is equal to the current <see cref="ColorRGB"/>; otherwise, <see cref="false"/>.</returns>
|
||||
public override bool Equals(object? obj) => obj is ColorRGB objVec && R.Equals(objVec.R) && G.Equals(objVec.G) && B.Equals(objVec.B);
|
||||
|
||||
/// <summary>
|
||||
/// Generates a hash code for the <see cref="ColorRGB"/>.
|
||||
/// </summary>
|
||||
/// <returns>A hash code for the <see cref="ColorRGB"/>.</returns>
|
||||
public override int GetHashCode() => System.HashCode.Combine(R, G, B);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for <see cref="ColorRGB"/> type.
|
||||
/// </summary>
|
||||
public static class ColorRGBExtensions
|
||||
{
|
||||
/// <inheritdoc cref="ColorRGB.Add(ColorRGB, ColorRGB)" />
|
||||
public static ColorRGB Add(this ColorRGB color, ColorRGB value) => ColorRGB.Add(color, value);
|
||||
|
||||
/// <inheritdoc cref="ColorRGB.Subtract(ColorRGB, ColorRGB)" />
|
||||
public static ColorRGB Subtract(this ColorRGB color, ColorRGB value) => ColorRGB.Subtract(color, value);
|
||||
|
||||
/// <inheritdoc cref="ColorRGB.Multiply(ColorRGB, ColorRGB)" />
|
||||
public static ColorRGB Multiply(this ColorRGB color, float value) => ColorRGB.Multiply(color, value);
|
||||
|
||||
/// <inheritdoc cref="ColorRGB.Divide(ColorRGB, ColorRGB)" />
|
||||
public static ColorRGB Divide(this ColorRGB color, float value) => ColorRGB.Divide(color, value);
|
||||
|
||||
/// <inheritdoc cref="ColorRGB.FromTo(ColorRGB, ColorRGB)" />
|
||||
public static ColorRGB FromTo(this ColorRGB from, ColorRGB to) => ColorRGB.FromTo(from, to);
|
||||
|
||||
/// <inheritdoc cref="ColorRGB.Lerp(ColorRGB, ColorRGB, float)" />
|
||||
public static ColorRGB Lerp(this ColorRGB from, ColorRGB to, float t) => ColorRGB.Lerp(from, to, t);
|
||||
}
|
147
Engine.Core/Primitives/ColorRGBA.cs
Normal file
147
Engine.Core/Primitives/ColorRGBA.cs
Normal file
@ -0,0 +1,147 @@
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an RGBA color.
|
||||
/// </summary>
|
||||
/// <param name="r">Red value of the <see cref="ColorRGBA"/>.</param>
|
||||
/// <param name="g">Green value of the <see cref="ColorRGBA"/>.</param>
|
||||
/// <param name="b">Blue value of the <see cref="ColorRGBA"/>.</param>
|
||||
/// <param name="a">Alpha value of the <see cref="ColorRGBA"/>.</param>
|
||||
/// <remarks>
|
||||
/// Initializes a new instance of the <see cref="ColorRGBA"/> struct with the specified values.
|
||||
/// </remarks>
|
||||
[System.Diagnostics.DebuggerDisplay("{ToString(),nq}")]
|
||||
public readonly struct ColorRGBA(byte r, byte g, byte b, byte a = 255)
|
||||
{
|
||||
/// <summary>
|
||||
/// The Red value of the <see cref="ColorRGBA"/>.
|
||||
/// </summary>
|
||||
public readonly byte R = r;
|
||||
|
||||
/// <summary>
|
||||
/// The Green value of the <see cref="ColorRGBA"/>.
|
||||
/// </summary>
|
||||
public readonly byte G = g;
|
||||
|
||||
/// <summary>
|
||||
/// The Blue value of the <see cref="ColorRGBA"/>.
|
||||
/// </summary>
|
||||
public readonly byte B = b;
|
||||
|
||||
/// <summary>
|
||||
/// The Alpha value of the <see cref="ColorRGBA"/>.
|
||||
/// </summary>
|
||||
public readonly byte A = a;
|
||||
|
||||
public static ColorRGBA operator -(ColorRGBA color) => new((byte)(255 - color.R), (byte)(255 - color.G), (byte)(255 - color.B), color.A);
|
||||
public static ColorRGBA operator +(ColorRGBA left, ColorRGBA right) => new((byte)(left.R + right.R).Clamp(0, 255), (byte)(left.G + right.G).Clamp(0, 255), (byte)(left.B + right.B).Clamp(0, 255), (byte)(left.A + right.A).Clamp(0, 255));
|
||||
public static ColorRGBA operator -(ColorRGBA left, ColorRGBA right) => new((byte)(left.R - right.R).Clamp(0, 255), (byte)(left.G - right.G).Clamp(0, 255), (byte)(left.B - right.B).Clamp(0, 255), (byte)(left.A - right.A).Clamp(0, 255));
|
||||
public static ColorRGBA operator *(ColorRGBA left, ColorRGBA right) => new((byte)(left.R * right.R).Clamp(0, 255), (byte)(left.G * right.G).Clamp(0, 255), (byte)(left.B * right.B).Clamp(0, 255), (byte)(left.A * right.A).Clamp(0, 255));
|
||||
public static ColorRGBA operator *(ColorRGBA color, float value) => new((byte)(color.R * value).Clamp(0, 255), (byte)(color.G * value).Clamp(0, 255), (byte)(color.B * value).Clamp(0, 255), (byte)(color.A * value).Clamp(0, 255));
|
||||
public static ColorRGBA operator *(float value, ColorRGBA color) => new((byte)(color.R * value).Clamp(0, 255), (byte)(color.G * value).Clamp(0, 255), (byte)(color.B * value).Clamp(0, 255), (byte)(color.A * value).Clamp(0, 255));
|
||||
public static ColorRGBA operator /(ColorRGBA color, float value) => new((byte)(color.R / value).Clamp(0, 255), (byte)(color.G / value).Clamp(0, 255), (byte)(color.B / value).Clamp(0, 255), (byte)(color.A / value).Clamp(0, 255));
|
||||
public static bool operator ==(ColorRGBA left, ColorRGBA right) => left.R == right.R && left.G == right.G && left.B == right.B && left.A == right.A;
|
||||
public static bool operator !=(ColorRGBA left, ColorRGBA right) => left.R != right.R || left.G != right.G || left.B != right.B || left.A != right.A;
|
||||
|
||||
public static implicit operator ColorRGBA(ColorRGB rgb) => new(rgb.R, rgb.G, rgb.B, 255);
|
||||
public static implicit operator ColorRGBA(ColorHSV hsv) => (ColorRGB)hsv;
|
||||
|
||||
/// <summary>
|
||||
/// Inverts the given <see cref="ColorRGBA"/>.
|
||||
/// </summary>
|
||||
/// <param name="color">The <see cref="ColorRGBA"/>.</param>
|
||||
/// <returns>The inverted <see cref="ColorRGBA"/>.</returns>
|
||||
public static ColorRGBA Invert(ColorRGBA color) => -color;
|
||||
|
||||
/// <summary>
|
||||
/// Adds two <see cref="ColorRGBA"/>s.
|
||||
/// </summary>
|
||||
/// <param name="left">The first <see cref="ColorRGBA"/>.</param>
|
||||
/// <param name="right">The second <see cref="ColorRGBA"/>.</param>
|
||||
/// <returns>The sum of the two <see cref="ColorRGBA"/>s.</returns>
|
||||
public static ColorRGBA Add(ColorRGBA left, ColorRGBA right) => left + right;
|
||||
|
||||
/// <summary>
|
||||
/// Subtracts one <see cref="ColorRGBA"/> from another.
|
||||
/// </summary>
|
||||
/// <param name="left">The <see cref="ColorRGBA"/> to subtract from.</param>
|
||||
/// <param name="right">The <see cref="ColorRGBA"/> to subtract.</param>
|
||||
/// <returns>The result of subtracting the second <see cref="ColorRGBA"/> from the first.</returns>
|
||||
public static ColorRGBA Subtract(ColorRGBA left, ColorRGBA right) => left - right;
|
||||
|
||||
/// <summary>
|
||||
/// Multiplies a <see cref="ColorRGBA"/> by a scalar value.
|
||||
/// </summary>
|
||||
/// <param name="color">The <see cref="ColorRGBA"/>.</param>
|
||||
/// <param name="value">The scalar value.</param>
|
||||
/// <returns>The result of multiplying the <see cref="ColorRGBA"/> by the scalar value.</returns>
|
||||
public static ColorRGBA Multiply(ColorRGBA color, float value) => color * value;
|
||||
|
||||
/// <summary>
|
||||
/// Divides a <see cref="ColorRGBA"/> by a scalar value.
|
||||
/// </summary>
|
||||
/// <param name="color">The <see cref="ColorRGBA"/>.</param>
|
||||
/// <param name="value">The scalar value.</param>
|
||||
/// <returns>The result of dividing the <see cref="ColorRGBA"/> by the scalar value.</returns>
|
||||
public static ColorRGBA Divide(ColorRGBA color, float value) => color / value;
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the <see cref="ColorRGBA"/> from one point to another.
|
||||
/// </summary>
|
||||
/// <param name="from">The starting point.</param>
|
||||
/// <param name="to">The ending point.</param>
|
||||
/// <returns>The <see cref="ColorRGBA"/> from the starting point to the ending point.</returns>
|
||||
public static ColorRGBA FromTo(ColorRGBA from, ColorRGBA to) => to - from;
|
||||
|
||||
/// <summary>
|
||||
/// Performs linear interpolation between two <see cref="ColorRGBA"/>s.
|
||||
/// </summary>
|
||||
/// <param name="from">The starting <see cref="ColorRGBA"/> (t = 0).</param>
|
||||
/// <param name="to">The ending <see cref="ColorRGBA"/> (t = 1).</param>
|
||||
/// <param name="t">The interpolation parameter.</param>
|
||||
/// <returns>The interpolated <see cref="ColorRGBA"/>.</returns>
|
||||
public static ColorRGBA Lerp(ColorRGBA from, ColorRGBA to, float t) => from + FromTo(from, to) * t;
|
||||
|
||||
/// <summary>
|
||||
/// Converts the <see cref="ColorRGBA"/> to its string representation.
|
||||
/// </summary>
|
||||
/// <returns>A string representation of the <see cref="ColorRGBA"/>.</returns>
|
||||
public override string ToString() => $"{nameof(ColorRGBA)}({R}, {G}, {B}, {A})";
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified object is equal to the current <see cref="ColorRGBA"/>.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to compare with the current <see cref="ColorRGBA"/>.</param>
|
||||
/// <returns><see cref="true"/> if the specified object is equal to the current <see cref="ColorRGBA"/>; otherwise, <see cref="false"/>.</returns>
|
||||
public override bool Equals(object? obj) => obj is ColorRGBA objVec && R.Equals(objVec.R) && G.Equals(objVec.G) && B.Equals(objVec.B) && A.Equals(objVec.A);
|
||||
|
||||
/// <summary>
|
||||
/// Generates a hash code for the <see cref="ColorRGBA"/>.
|
||||
/// </summary>
|
||||
/// <returns>A hash code for the <see cref="ColorRGBA"/>.</returns>
|
||||
public override int GetHashCode() => System.HashCode.Combine(R, G, B, A);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for <see cref="ColorRGBA"/> type.
|
||||
/// </summary>
|
||||
public static class ColorRGBAExtensions
|
||||
{
|
||||
/// <inheritdoc cref="ColorRGBA.Add(ColorRGBA, ColorRGBA)" />
|
||||
public static ColorRGBA Add(this ColorRGBA color, ColorRGBA value) => ColorRGBA.Add(color, value);
|
||||
|
||||
/// <inheritdoc cref="ColorRGBA.Subtract(ColorRGBA, ColorRGBA)" />
|
||||
public static ColorRGBA Subtract(this ColorRGBA color, ColorRGBA value) => ColorRGBA.Subtract(color, value);
|
||||
|
||||
/// <inheritdoc cref="ColorRGBA.Multiply(ColorRGBA, ColorRGBA)" />
|
||||
public static ColorRGBA Multiply(this ColorRGBA color, float value) => ColorRGBA.Multiply(color, value);
|
||||
|
||||
/// <inheritdoc cref="ColorRGBA.Divide(ColorRGBA, ColorRGBA)" />
|
||||
public static ColorRGBA Divide(this ColorRGBA color, float value) => ColorRGBA.Divide(color, value);
|
||||
|
||||
/// <inheritdoc cref="ColorRGBA.FromTo(ColorRGBA, ColorRGBA)" />
|
||||
public static ColorRGBA FromTo(this ColorRGBA from, ColorRGBA to) => ColorRGBA.FromTo(from, to);
|
||||
|
||||
/// <inheritdoc cref="ColorRGBA.Lerp(ColorRGBA, ColorRGBA, float)" />
|
||||
public static ColorRGBA Lerp(this ColorRGBA from, ColorRGBA to, float t) => ColorRGBA.Lerp(from, to, t);
|
||||
}
|
@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Syntriax.Engine.Core;
|
||||
@ -68,12 +67,12 @@ public readonly struct Line2D(Vector2D from, Vector2D to)
|
||||
/// </summary>
|
||||
public static float GetT(Line2D line, Vector2D point)
|
||||
{
|
||||
float fromX = MathF.Abs(line.From.X);
|
||||
float toX = MathF.Abs(line.To.X);
|
||||
float pointX = MathF.Abs(point.X);
|
||||
float fromX = Math.Abs(line.From.X);
|
||||
float toX = Math.Abs(line.To.X);
|
||||
float pointX = Math.Abs(point.X);
|
||||
|
||||
float min = MathF.Min(fromX, toX);
|
||||
float max = MathF.Max(fromX, toX) - min;
|
||||
float min = Math.Min(fromX, toX);
|
||||
float max = Math.Max(fromX, toX) - min;
|
||||
|
||||
pointX -= min;
|
||||
|
||||
@ -114,8 +113,8 @@ public readonly struct Line2D(Vector2D from, Vector2D to)
|
||||
/// </summary>
|
||||
public static bool OnSegment(Line2D line, Vector2D point)
|
||||
{
|
||||
if (point.X <= MathF.Max(line.From.X, line.To.X) && point.X >= MathF.Min(line.From.X, line.To.X) &&
|
||||
point.Y <= MathF.Max(line.From.Y, line.To.Y) && point.Y >= MathF.Min(line.From.Y, line.To.Y))
|
||||
if (point.X <= Math.Max(line.From.X, line.To.X) && point.X >= Math.Min(line.From.X, line.To.X) &&
|
||||
point.Y <= Math.Max(line.From.Y, line.To.Y) && point.Y >= Math.Min(line.From.Y, line.To.Y))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@ -173,7 +172,7 @@ public readonly struct Line2D(Vector2D from, Vector2D to)
|
||||
|
||||
float t = (pointVector.X * edgeVector.X + pointVector.Y * edgeVector.Y) / (edgeVector.X * edgeVector.X + edgeVector.Y * edgeVector.Y);
|
||||
|
||||
t = MathF.Max(0, MathF.Min(1, t));
|
||||
t = Math.Max(0, Math.Min(1, t));
|
||||
|
||||
float closestX = line.From.X + t * edgeVector.X;
|
||||
float closestY = line.From.Y + t * edgeVector.Y;
|
||||
|
@ -1,5 +1,3 @@
|
||||
using System;
|
||||
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
@ -178,11 +176,11 @@ public readonly struct Quaternion(float x, float y, float z, float w)
|
||||
if (dot > 0.9995f)
|
||||
return Lerp(from, to, t);
|
||||
|
||||
float angle = MathF.Acos(dot);
|
||||
float sinAngle = MathF.Sin(angle);
|
||||
float angle = Math.Acos(dot);
|
||||
float sinAngle = Math.Sin(angle);
|
||||
|
||||
float fromWeight = MathF.Sin((1f - t) * angle) / sinAngle;
|
||||
float toWeight = MathF.Sin(t * angle) / sinAngle;
|
||||
float fromWeight = Math.Sin((1f - t) * angle) / sinAngle;
|
||||
float toWeight = Math.Sin(t * angle) / sinAngle;
|
||||
|
||||
return from * fromWeight + to * toWeight;
|
||||
}
|
||||
@ -213,8 +211,8 @@ public readonly struct Quaternion(float x, float y, float z, float w)
|
||||
public static Quaternion FromAxisAngle(Vector3D axis, float angle)
|
||||
{
|
||||
float halfAngle = angle * .5f;
|
||||
float sinHalf = MathF.Sin(halfAngle);
|
||||
return new Quaternion(axis.X * sinHalf, axis.Y * sinHalf, axis.Z * sinHalf, MathF.Cos(halfAngle));
|
||||
float sinHalf = Math.Sin(halfAngle);
|
||||
return new Quaternion(axis.X * sinHalf, axis.Y * sinHalf, axis.Z * sinHalf, Math.Cos(halfAngle));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -301,7 +299,7 @@ public readonly struct Quaternion(float x, float y, float z, float w)
|
||||
/// Generates a hash code for the <see cref="Quaternion"/>.
|
||||
/// </summary>
|
||||
/// <returns>A hash code for the <see cref="Quaternion"/>.</returns>
|
||||
public override int GetHashCode() => HashCode.Combine(X, Y, Z);
|
||||
public override int GetHashCode() => System.HashCode.Combine(X, Y, Z);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -11,19 +11,33 @@ namespace Syntriax.Engine.Core;
|
||||
/// Initializes a new instance of a <see cref="Shape2D"/> struct with the specified vertices.
|
||||
/// </remarks>
|
||||
[System.Diagnostics.DebuggerDisplay("Vertices Count: {Vertices.Count}")]
|
||||
public readonly struct Shape2D(List<Vector2D> vertices) : IEnumerable<Vector2D>
|
||||
public class Shape2D(List<Vector2D> vertices) : IEnumerable<Vector2D>
|
||||
{
|
||||
public static readonly Shape2D Triangle = CreateNgon(3, Vector2D.Up);
|
||||
public static readonly Shape2D Square = CreateNgon(4, Vector2D.One);
|
||||
public static readonly Shape2D Pentagon = CreateNgon(5, Vector2D.Up);
|
||||
public static readonly Shape2D Hexagon = CreateNgon(6, Vector2D.Right);
|
||||
public static Shape2D Triangle => CreateNgon(3, Vector2D.Up);
|
||||
public static Shape2D Square => CreateNgon(4, Vector2D.One);
|
||||
public static Shape2D Pentagon => CreateNgon(5, Vector2D.Up);
|
||||
public static Shape2D Hexagon => CreateNgon(6, Vector2D.Right);
|
||||
|
||||
private readonly List<Vector2D> _verticesList = vertices;
|
||||
public event ShapeUpdatedEventHandler? OnShapeUpdated = null;
|
||||
|
||||
private List<Vector2D> _vertices = vertices;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the vertices of the <see cref="Shape2D"/>.
|
||||
/// </summary>
|
||||
public IReadOnlyList<Vector2D> Vertices => _verticesList;
|
||||
public IReadOnlyList<Vector2D> Vertices
|
||||
{
|
||||
get => _vertices;
|
||||
set
|
||||
{
|
||||
_vertices.Clear();
|
||||
|
||||
foreach (Vector2D vertex in value)
|
||||
_vertices.Add(vertex);
|
||||
|
||||
OnShapeUpdated?.InvokeSafe(this);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The vertex at the specified index.
|
||||
@ -207,13 +221,15 @@ public readonly struct Shape2D(List<Vector2D> vertices) : IEnumerable<Vector2D>
|
||||
/// <param name="from">The <see cref="Shape2D"/> to transform.</param>
|
||||
/// <param name="transform">The <see cref="ITransform2D"/> to apply.</param>
|
||||
/// <param name="to">The transformed <see cref="Shape2D"/>.</param>
|
||||
public static void Transform(Shape2D from, ITransform2D transform, ref Shape2D to)
|
||||
public static void Transform(Shape2D from, ITransform2D transform, Shape2D to)
|
||||
{
|
||||
to._verticesList.Clear();
|
||||
to._vertices.Clear();
|
||||
|
||||
int count = from._verticesList.Count;
|
||||
int count = from._vertices.Count;
|
||||
for (int i = 0; i < count; i++)
|
||||
to._verticesList.Add(transform.Transform(from[i]));
|
||||
to._vertices.Add(transform.Transform(from[i]));
|
||||
|
||||
to.OnShapeUpdated?.InvokeSafe(to);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -240,6 +256,8 @@ public readonly struct Shape2D(List<Vector2D> vertices) : IEnumerable<Vector2D>
|
||||
|
||||
/// <inheritdoc/>
|
||||
IEnumerator IEnumerable.GetEnumerator() => Vertices.GetEnumerator();
|
||||
|
||||
public delegate void ShapeUpdatedEventHandler(Shape2D shape2D);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -275,13 +293,13 @@ public static class Shape2DExtensions
|
||||
public static Shape2D Transform(this ITransform2D transform, Shape2D shape) => Shape2D.Transform(shape, transform);
|
||||
|
||||
/// <inheritdoc cref="Shape2D.Transform(Shape2D, ITransform2D, Shape2D)" />
|
||||
public static void Transform(this ITransform2D transform, Shape2D from, ref Shape2D to) => Shape2D.Transform(from, transform, ref to);
|
||||
public static void Transform(this ITransform2D transform, Shape2D from, Shape2D to) => Shape2D.Transform(from, transform, to);
|
||||
|
||||
/// <inheritdoc cref="Shape2D.Transform(Shape2D, ITransform2D)" />
|
||||
public static Shape2D Transform(this Shape2D shape, ITransform2D transform) => Shape2D.Transform(shape, transform);
|
||||
|
||||
/// <inheritdoc cref="Shape2D.Transform(Shape2D, ITransform2D, ref Shape2D)" />
|
||||
public static void Transform(this Shape2D from, ITransform2D transform, ref Shape2D to) => Shape2D.Transform(from, transform, ref to);
|
||||
/// <inheritdoc cref="Shape2D.Transform(Shape2D, ITransform2D,Shape2D)" />
|
||||
public static void Transform(this Shape2D from, ITransform2D transform, Shape2D to) => Shape2D.Transform(from, transform, to);
|
||||
|
||||
/// <inheritdoc cref="Shape2D.ApproximatelyEquals(Shape2D, Shape2D, float)" />
|
||||
public static bool ApproximatelyEquals(this Shape2D left, Shape2D right, float epsilon = float.Epsilon) => Shape2D.ApproximatelyEquals(left, right, epsilon);
|
||||
|
@ -1,5 +1,3 @@
|
||||
using System;
|
||||
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
[System.Diagnostics.DebuggerDisplay("A: {A.ToString(), nq}, B: {B.ToString(), nq}, B: {C.ToString(), nq}")]
|
||||
@ -10,7 +8,7 @@ public readonly struct Triangle(Vector2D A, Vector2D B, Vector2D C)
|
||||
public readonly Vector2D C { get; init; } = C;
|
||||
|
||||
public readonly float Area
|
||||
=> .5f * MathF.Abs(
|
||||
=> .5f * Math.Abs(
|
||||
A.X * (B.Y - C.Y) +
|
||||
B.X * (C.Y - A.Y) +
|
||||
C.X * (A.Y - B.Y)
|
||||
@ -25,7 +23,7 @@ public readonly struct Triangle(Vector2D A, Vector2D B, Vector2D C)
|
||||
float slopeBC = (triangle.C.Y - triangle.B.Y) / (triangle.C.X - triangle.B.X);
|
||||
|
||||
Vector2D center;
|
||||
if (MathF.Abs(slopeAB - slopeBC) > float.Epsilon)
|
||||
if (Math.Abs(slopeAB - slopeBC) > float.Epsilon)
|
||||
{
|
||||
float x = (slopeAB * slopeBC * (triangle.A.Y - triangle.C.Y) + slopeBC * (triangle.A.X + triangle.B.X) - slopeAB * (triangle.B.X + triangle.C.X)) / (2f * (slopeBC - slopeAB));
|
||||
float y = -(x - (triangle.A.X + triangle.B.X) / 2f) / slopeAB + (triangle.A.Y + triangle.B.Y) / 2f;
|
||||
|
@ -1,5 +1,3 @@
|
||||
using System;
|
||||
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
@ -316,7 +314,7 @@ public readonly struct Vector2D(float x, float y)
|
||||
/// Generates a hash code for the <see cref="Vector2D"/>.
|
||||
/// </summary>
|
||||
/// <returns>A hash code for the <see cref="Vector2D"/>.</returns>
|
||||
public override int GetHashCode() => HashCode.Combine(X, Y);
|
||||
public override int GetHashCode() => System.HashCode.Combine(X, Y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1,5 +1,3 @@
|
||||
using System;
|
||||
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
@ -290,7 +288,7 @@ public readonly struct Vector3D(float x, float y, float z)
|
||||
/// Generates a hash code for the <see cref="Vector3D"/>.
|
||||
/// </summary>
|
||||
/// <returns>A hash code for the <see cref="Vector3D"/>.</returns>
|
||||
public override int GetHashCode() => HashCode.Combine(X, Y, Z);
|
||||
public override int GetHashCode() => System.HashCode.Combine(X, Y, Z);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -9,4 +9,10 @@ public interface ISerializer
|
||||
T Deserialize<T>(string configuration);
|
||||
|
||||
string Serialize(object instance);
|
||||
|
||||
ProgressiveTask<object> DeserializeAsync(string configuration);
|
||||
ProgressiveTask<object> DeserializeAsync(string configuration, Type type);
|
||||
ProgressiveTask<T> DeserializeAsync<T>(string configuration);
|
||||
|
||||
ProgressiveTask<string> SerializeAsync(object instance);
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ public class Universe : BaseEntity, IUniverse
|
||||
|
||||
public void Update(UniverseTime engineTime)
|
||||
{
|
||||
Debug.AssertHelpers.AssertInitialized(this);
|
||||
Debug.Assert.AssertInitialized(this);
|
||||
|
||||
UnscaledTime = engineTime;
|
||||
Time = new(TimeSpan.FromTicks((long)(Time.TimeSinceStart.Ticks + engineTime.DeltaSpan.Ticks * TimeScale)), TimeSpan.FromTicks((long)(engineTime.DeltaSpan.Ticks * TimeScale)));
|
||||
@ -125,7 +125,7 @@ public class Universe : BaseEntity, IUniverse
|
||||
|
||||
public void PreDraw()
|
||||
{
|
||||
Debug.AssertHelpers.AssertInitialized(this);
|
||||
Debug.Assert.AssertInitialized(this);
|
||||
|
||||
for (int i = 0; i < UniverseObjects.Count; i++)
|
||||
UniverseObjects[i].BehaviourController.UpdatePreDraw();
|
||||
|
@ -18,7 +18,7 @@ public class Collider2DShapeBehaviour : Collider2DBehaviourBase, IShapeCollider2
|
||||
private Shape2D _shapeWorld = Shape2D.Square.CreateCopy();
|
||||
private Shape2D _shapeLocal = Shape2D.Square;
|
||||
|
||||
public override void CalculateCollider() => Transform.Transform(ShapeLocal, ref _shapeWorld);
|
||||
public override void CalculateCollider() => ShapeLocal.Transform(Transform, _shapeWorld);
|
||||
|
||||
public Collider2DShapeBehaviour() { }
|
||||
public Collider2DShapeBehaviour(Shape2D shape)
|
||||
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>disable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>Syntriax.Engine.Physics2D</RootNamespace>
|
||||
|
10
Engine.Physics2D/Preserver.cs
Normal file
10
Engine.Physics2D/Preserver.cs
Normal file
@ -0,0 +1,10 @@
|
||||
namespace Syntriax.Engine.Physics2D
|
||||
{
|
||||
// This is pretty much so the assembly gets loaded automatically because
|
||||
// the builds include the assembly but sometimes doesn't link load it at startup.
|
||||
// I will hopefully one day fix it and remove this.
|
||||
public static class Preserver
|
||||
{
|
||||
public static void Preserve() { }
|
||||
}
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
using Syntriax.Engine.Core;
|
||||
using Syntriax.Engine.Core.Serialization;
|
||||
|
||||
using YamlDotNet.Serialization;
|
||||
@ -8,4 +9,5 @@ public interface IEngineTypeYamlConverter : IYamlTypeConverter
|
||||
{
|
||||
YamlSerializer Serializer { get; set; }
|
||||
EntityRegistry EntityRegistry { get; set; }
|
||||
IProgressionTracker ProgressionTracker { get; set; }
|
||||
}
|
||||
|
@ -17,6 +17,9 @@ public class BehaviourControllerConverter : EngineTypeYamlSerializerBase<IBehavi
|
||||
|
||||
public override IBehaviourController? Read(IParser parser, Type type, ObjectDeserializer rootDeserializer)
|
||||
{
|
||||
bool isTrackingController = ProgressionTracker.Progression.ApproximatelyEquals(0f);
|
||||
ProgressionTracker.Set(isTrackingController ? .25f : ProgressionTracker.Progression, $"Reading behaviour controller");
|
||||
|
||||
string id;
|
||||
|
||||
IBehaviourController behaviourController;
|
||||
@ -32,6 +35,7 @@ public class BehaviourControllerConverter : EngineTypeYamlSerializerBase<IBehavi
|
||||
if (parser.Consume<Scalar>().Value.CompareTo(SERIALIZED_SCALAR_NAME) != 0)
|
||||
throw new();
|
||||
SerializedClass instanceSerializedClass = (SerializedClass)rootDeserializer(typeof(SerializedClass))!;
|
||||
ProgressionTracker.Set(isTrackingController ? .5f : ProgressionTracker.Progression, $"Creating {instanceSerializedClass.Type}");
|
||||
behaviourController = (IBehaviourController)instanceSerializedClass.CreateInstance(EntityRegistry);
|
||||
|
||||
string value = parser.Consume<Scalar>().Value;
|
||||
@ -53,6 +57,7 @@ public class BehaviourControllerConverter : EngineTypeYamlSerializerBase<IBehavi
|
||||
foreach (IBehaviour behaviour in behaviours)
|
||||
behaviourController.AddBehaviour(behaviour);
|
||||
|
||||
ProgressionTracker.Set(isTrackingController ? 1f : ProgressionTracker.Progression, $"Created {instanceSerializedClass.Type}");
|
||||
return behaviourController;
|
||||
}
|
||||
|
||||
@ -60,6 +65,9 @@ public class BehaviourControllerConverter : EngineTypeYamlSerializerBase<IBehavi
|
||||
{
|
||||
IBehaviourController behaviourController = (IBehaviourController)value!;
|
||||
|
||||
bool isTrackingController = ProgressionTracker.Progression.ApproximatelyEquals(0f);
|
||||
ProgressionTracker.Set(isTrackingController ? .25f : ProgressionTracker.Progression, $"Serializing behaviour controller");
|
||||
|
||||
emitter.Emit(new MappingStart());
|
||||
|
||||
emitter.Emit(new Scalar(nameof(IBehaviourController.Id)));
|
||||
@ -74,6 +82,7 @@ public class BehaviourControllerConverter : EngineTypeYamlSerializerBase<IBehavi
|
||||
emitter.Emit(new Scalar(BEHAVIOURS_SCALAR_NAME));
|
||||
serializer(behaviourController.GetBehaviours<IBehaviour>().Where(b => !b.GetType().HasAttribute<IgnoreSerializationAttribute>()));
|
||||
|
||||
ProgressionTracker.Set(isTrackingController ? 1f : ProgressionTracker.Progression, $"Serialized behaviour controller");
|
||||
emitter.Emit(new MappingEnd());
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,9 @@ public class BehaviourConverter : EngineTypeYamlSerializerBase<IBehaviour>
|
||||
{
|
||||
public override IBehaviour? Read(IParser parser, Type type, ObjectDeserializer rootDeserializer)
|
||||
{
|
||||
bool isTrackingController = ProgressionTracker.Progression.ApproximatelyEquals(0f);
|
||||
ProgressionTracker.Set(isTrackingController ? .25f : ProgressionTracker.Progression, $"Reading behaviour information");
|
||||
|
||||
string id;
|
||||
int priority;
|
||||
|
||||
@ -32,6 +35,7 @@ public class BehaviourConverter : EngineTypeYamlSerializerBase<IBehaviour>
|
||||
if (parser.Consume<Scalar>().Value.CompareTo(SERIALIZED_SCALAR_NAME) != 0)
|
||||
throw new();
|
||||
SerializedClass instanceSerializedClass = (SerializedClass)rootDeserializer(typeof(SerializedClass))!;
|
||||
ProgressionTracker.Set(isTrackingController ? .5f : ProgressionTracker.Progression, $"Creating {instanceSerializedClass.Type}");
|
||||
behaviour = (IBehaviour)instanceSerializedClass.CreateInstance(EntityRegistry);
|
||||
|
||||
if (parser.Consume<Scalar>().Value.CompareTo(nameof(IBehaviour.StateEnable)) != 0)
|
||||
@ -46,6 +50,7 @@ public class BehaviourConverter : EngineTypeYamlSerializerBase<IBehaviour>
|
||||
stateEnable.Assign(behaviour);
|
||||
behaviour.Assign(stateEnable);
|
||||
|
||||
ProgressionTracker.Set(isTrackingController ? 1f : ProgressionTracker.Progression, $"Created {instanceSerializedClass.Type}");
|
||||
return behaviour;
|
||||
}
|
||||
|
||||
@ -53,6 +58,9 @@ public class BehaviourConverter : EngineTypeYamlSerializerBase<IBehaviour>
|
||||
{
|
||||
IBehaviour behaviour = (IBehaviour)value!;
|
||||
|
||||
bool isTrackingController = ProgressionTracker.Progression.ApproximatelyEquals(0f);
|
||||
ProgressionTracker.Set(isTrackingController ? .25f : ProgressionTracker.Progression, $"Serializing behaviour");
|
||||
|
||||
emitter.Emit(new MappingStart());
|
||||
|
||||
emitter.Emit(new Scalar(nameof(IBehaviour.Id)));
|
||||
@ -67,6 +75,7 @@ public class BehaviourConverter : EngineTypeYamlSerializerBase<IBehaviour>
|
||||
emitter.Emit(new Scalar(nameof(IBehaviour.StateEnable)));
|
||||
serializer(behaviour.StateEnable);
|
||||
|
||||
ProgressionTracker.Set(isTrackingController ? 1f : ProgressionTracker.Progression, $"Serialized behaviour");
|
||||
emitter.Emit(new MappingEnd());
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ public abstract class EngineTypeYamlSerializerBase<T> : IEngineTypeYamlConverter
|
||||
|
||||
public EntityRegistry EntityRegistry { get; set; } = null!;
|
||||
public YamlSerializer Serializer { get; set; } = null!;
|
||||
public IProgressionTracker ProgressionTracker { get; set; } = null!;
|
||||
|
||||
public bool Accepts(Type type) => typeof(T).IsAssignableFrom(type);
|
||||
|
||||
|
@ -0,0 +1,28 @@
|
||||
using System;
|
||||
|
||||
using Syntriax.Engine.Core;
|
||||
|
||||
using YamlDotNet.Core;
|
||||
using YamlDotNet.Core.Events;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace Syntriax.Engine.Serializers.Yaml;
|
||||
|
||||
public class ColorHSVConverter : EngineTypeYamlSerializerBase<ColorHSV>
|
||||
{
|
||||
private static readonly int SUBSTRING_START_LENGTH = nameof(ColorHSV).Length + 1;
|
||||
|
||||
public override ColorHSV Read(IParser parser, Type type, ObjectDeserializer rootDeserializer)
|
||||
{
|
||||
string value = parser.Consume<Scalar>().Value;
|
||||
string insideParenthesis = value[SUBSTRING_START_LENGTH..^1];
|
||||
string[] values = insideParenthesis.Split(", ");
|
||||
return new ColorHSV(float.Parse(values[0]), float.Parse(values[1]), float.Parse(values[2]));
|
||||
}
|
||||
|
||||
public override void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
|
||||
{
|
||||
ColorHSV hsv = (ColorHSV)value!;
|
||||
emitter.Emit(new Scalar($"{nameof(ColorHSV)}({hsv.Hue}, {hsv.Saturation}, {hsv.Value})"));
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
using System;
|
||||
|
||||
using Syntriax.Engine.Core;
|
||||
|
||||
using YamlDotNet.Core;
|
||||
using YamlDotNet.Core.Events;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace Syntriax.Engine.Serializers.Yaml;
|
||||
|
||||
public class ColorRGBAConverter : EngineTypeYamlSerializerBase<ColorRGBA>
|
||||
{
|
||||
private static readonly int SUBSTRING_START_LENGTH = nameof(ColorRGBA).Length + 1;
|
||||
|
||||
public override ColorRGBA Read(IParser parser, Type type, ObjectDeserializer rootDeserializer)
|
||||
{
|
||||
string value = parser.Consume<Scalar>().Value;
|
||||
string insideParenthesis = value[SUBSTRING_START_LENGTH..^1];
|
||||
string[] values = insideParenthesis.Split(", ");
|
||||
return new ColorRGBA(byte.Parse(values[0]), byte.Parse(values[1]), byte.Parse(values[2]), byte.Parse(values[3]));
|
||||
}
|
||||
|
||||
public override void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
|
||||
{
|
||||
ColorRGBA rgb = (ColorRGBA)value!;
|
||||
emitter.Emit(new Scalar($"{nameof(ColorRGBA)}({rgb.R}, {rgb.G}, {rgb.B}, {rgb.A})"));
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
using System;
|
||||
|
||||
using Syntriax.Engine.Core;
|
||||
|
||||
using YamlDotNet.Core;
|
||||
using YamlDotNet.Core.Events;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace Syntriax.Engine.Serializers.Yaml;
|
||||
|
||||
public class ColorRGBConverter : EngineTypeYamlSerializerBase<ColorRGB>
|
||||
{
|
||||
private static readonly int SUBSTRING_START_LENGTH = nameof(ColorRGB).Length + 1;
|
||||
|
||||
public override ColorRGB Read(IParser parser, Type type, ObjectDeserializer rootDeserializer)
|
||||
{
|
||||
string value = parser.Consume<Scalar>().Value;
|
||||
string insideParenthesis = value[SUBSTRING_START_LENGTH..^1];
|
||||
string[] values = insideParenthesis.Split(", ");
|
||||
return new ColorRGB(byte.Parse(values[0]), byte.Parse(values[1]), byte.Parse(values[2]));
|
||||
}
|
||||
|
||||
public override void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
|
||||
{
|
||||
ColorRGB rgb = (ColorRGB)value!;
|
||||
emitter.Emit(new Scalar($"{nameof(ColorRGB)}({rgb.R}, {rgb.G}, {rgb.B})"));
|
||||
}
|
||||
}
|
@ -2,8 +2,9 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using Syntriax.Engine.Core.Serialization;
|
||||
using Syntriax.Engine.Core;
|
||||
using Syntriax.Engine.Core.Factory;
|
||||
using Syntriax.Engine.Core.Serialization;
|
||||
|
||||
using YamlDotNet.Core;
|
||||
using YamlDotNet.Core.Events;
|
||||
@ -15,6 +16,9 @@ public class SerializedClassConverter : EngineTypeYamlSerializerBase<SerializedC
|
||||
{
|
||||
public override SerializedClass? Read(IParser parser, Type type, ObjectDeserializer rootDeserializer)
|
||||
{
|
||||
bool isTrackingController = ProgressionTracker.Progression.ApproximatelyEquals(0f);
|
||||
ProgressionTracker.Set(isTrackingController ? .1f : ProgressionTracker.Progression, $"Reading class");
|
||||
|
||||
SerializedClass serializedClass = new();
|
||||
Dictionary<string, TypeContainer> publicDictionary = [];
|
||||
Dictionary<string, TypeContainer> privateDictionary = [];
|
||||
@ -39,6 +43,7 @@ public class SerializedClassConverter : EngineTypeYamlSerializerBase<SerializedC
|
||||
foreach ((string key, TypeContainer typeContainer) in privateDictionary)
|
||||
serializedClass.Private.Add(key, Serializer.InternalDeserialize(typeContainer.Value!.ToString()!, TypeFactory.GetType(typeContainer.Type)));
|
||||
|
||||
ProgressionTracker.Set(isTrackingController ? 1f : ProgressionTracker.Progression, $"Read {serializedClass.Type}");
|
||||
return serializedClass;
|
||||
}
|
||||
|
||||
@ -46,6 +51,9 @@ public class SerializedClassConverter : EngineTypeYamlSerializerBase<SerializedC
|
||||
{
|
||||
SerializedClass serializedClass = (SerializedClass)value!;
|
||||
|
||||
bool isTrackingController = ProgressionTracker.Progression.ApproximatelyEquals(0f);
|
||||
ProgressionTracker.Set(isTrackingController ? .25f : ProgressionTracker.Progression, $"Serializing {serializedClass.Type}");
|
||||
|
||||
Dictionary<string, TypeContainer> publics = [];
|
||||
Dictionary<string, TypeContainer> privates = [];
|
||||
|
||||
@ -72,6 +80,7 @@ public class SerializedClassConverter : EngineTypeYamlSerializerBase<SerializedC
|
||||
serializer(privates);
|
||||
}
|
||||
|
||||
ProgressionTracker.Set(isTrackingController ? 1f : ProgressionTracker.Progression, $"Serialized {serializedClass.Type}");
|
||||
emitter.Emit(new MappingEnd());
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,9 @@ public class StateEnableConverter : EngineTypeYamlSerializerBase<IStateEnable>
|
||||
{
|
||||
public override IStateEnable? Read(IParser parser, Type type, ObjectDeserializer rootDeserializer)
|
||||
{
|
||||
bool isTrackingController = ProgressionTracker.Progression.ApproximatelyEquals(0f);
|
||||
ProgressionTracker.Set(isTrackingController ? .25f : ProgressionTracker.Progression, $"Reading state enable");
|
||||
|
||||
bool enabled;
|
||||
|
||||
IStateEnable stateEnable;
|
||||
@ -32,6 +35,7 @@ public class StateEnableConverter : EngineTypeYamlSerializerBase<IStateEnable>
|
||||
|
||||
stateEnable.Enabled = enabled;
|
||||
|
||||
ProgressionTracker.Set(isTrackingController ? .25f : ProgressionTracker.Progression, $"Read state enable");
|
||||
return stateEnable;
|
||||
}
|
||||
|
||||
@ -39,6 +43,9 @@ public class StateEnableConverter : EngineTypeYamlSerializerBase<IStateEnable>
|
||||
{
|
||||
IStateEnable stateEnable = (IStateEnable)value!;
|
||||
|
||||
bool isTrackingController = ProgressionTracker.Progression.ApproximatelyEquals(0f);
|
||||
ProgressionTracker.Set(isTrackingController ? .25f : ProgressionTracker.Progression, $"Serializing state enable");
|
||||
|
||||
emitter.Emit(new MappingStart());
|
||||
|
||||
emitter.Emit(new Scalar(nameof(IStateEnable.Enabled)));
|
||||
@ -47,6 +54,7 @@ public class StateEnableConverter : EngineTypeYamlSerializerBase<IStateEnable>
|
||||
emitter.Emit(new Scalar(SERIALIZED_SCALAR_NAME));
|
||||
serializer(new SerializedClass(stateEnable));
|
||||
|
||||
ProgressionTracker.Set(isTrackingController ? 1f : ProgressionTracker.Progression, $"Serialized state enable");
|
||||
emitter.Emit(new MappingEnd());
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,9 @@ public class UniverseConverter : EngineTypeYamlSerializerBase<IUniverse>
|
||||
{
|
||||
public override IUniverse? Read(IParser parser, Type type, ObjectDeserializer rootDeserializer)
|
||||
{
|
||||
bool isTrackingController = ProgressionTracker.Progression.ApproximatelyEquals(0f);
|
||||
ProgressionTracker.Set(isTrackingController ? 0.1f : ProgressionTracker.Progression, "Reading universe");
|
||||
|
||||
string id;
|
||||
|
||||
IUniverse universe;
|
||||
@ -30,12 +33,14 @@ public class UniverseConverter : EngineTypeYamlSerializerBase<IUniverse>
|
||||
if (parser.Consume<Scalar>().Value.CompareTo(SERIALIZED_SCALAR_NAME) != 0)
|
||||
throw new();
|
||||
SerializedClass instanceSerializedClass = (SerializedClass)rootDeserializer(typeof(SerializedClass))!;
|
||||
ProgressionTracker.Set(isTrackingController ? .2f : ProgressionTracker.Progression, $"Creating {instanceSerializedClass.Type}");
|
||||
universe = (IUniverse)instanceSerializedClass.CreateInstance(EntityRegistry);
|
||||
|
||||
if (parser.Consume<Scalar>().Value.CompareTo(nameof(IUniverse.StateEnable)) != 0)
|
||||
throw new();
|
||||
stateEnable = (IStateEnable)rootDeserializer(typeof(IStateEnable))!;
|
||||
|
||||
ProgressionTracker.Set(isTrackingController ? .5f : ProgressionTracker.Progression, $"Reading universe objects");
|
||||
if (parser.Consume<Scalar>().Value.CompareTo(nameof(IUniverse.UniverseObjects)) != 0)
|
||||
throw new();
|
||||
universeObjects = (List<IUniverseObject>)rootDeserializer(typeof(List<IUniverseObject>))!;
|
||||
@ -47,9 +52,16 @@ public class UniverseConverter : EngineTypeYamlSerializerBase<IUniverse>
|
||||
stateEnable.Assign(universe);
|
||||
universe.Assign(stateEnable);
|
||||
|
||||
foreach (IUniverseObject uo in universeObjects)
|
||||
universe.Register(uo);
|
||||
ProgressionTracker.Set(isTrackingController ? .9f : ProgressionTracker.Progression, "Registering universe objects");
|
||||
for (int i = 0; i < universeObjects.Count; i++)
|
||||
{
|
||||
IUniverseObject uo = universeObjects[i];
|
||||
ProgressionTracker.Set(isTrackingController ? .9f + .1f * ((float)i / universeObjects.Count) : ProgressionTracker.Progression, $"Registering {uo.Name}");
|
||||
|
||||
universe.Register(uo);
|
||||
}
|
||||
|
||||
ProgressionTracker.Set(isTrackingController ? 1f : ProgressionTracker.Progression, $"Created {instanceSerializedClass.Type}");
|
||||
return universe;
|
||||
}
|
||||
|
||||
@ -57,16 +69,10 @@ public class UniverseConverter : EngineTypeYamlSerializerBase<IUniverse>
|
||||
{
|
||||
IUniverse universe = (IUniverse)value!;
|
||||
|
||||
IEnumerable<IUniverseObject> rootUniverseObjects = universe.UniverseObjects
|
||||
.Select(uo =>
|
||||
{
|
||||
IUniverseObject root = uo;
|
||||
while (root.Parent is IUniverseObject parent)
|
||||
root = parent;
|
||||
return root;
|
||||
})
|
||||
.Where(uo => !uo.GetType().HasAttribute<IgnoreSerializationAttribute>())
|
||||
.Distinct();
|
||||
bool isTrackingController = ProgressionTracker.Progression.ApproximatelyEquals(0f);
|
||||
ProgressionTracker.Set(isTrackingController ? .25f : ProgressionTracker.Progression, $"Serializing universe");
|
||||
|
||||
IEnumerable<IUniverseObject> rootUniverseObjects = universe.UniverseObjects.Where(uo => uo.Parent is null);
|
||||
|
||||
emitter.Emit(new MappingStart());
|
||||
|
||||
@ -82,6 +88,7 @@ public class UniverseConverter : EngineTypeYamlSerializerBase<IUniverse>
|
||||
emitter.Emit(new Scalar(nameof(IUniverse.UniverseObjects)));
|
||||
serializer(rootUniverseObjects);
|
||||
|
||||
ProgressionTracker.Set(isTrackingController ? 1f : ProgressionTracker.Progression, $"Serialized universe");
|
||||
emitter.Emit(new MappingEnd());
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,8 @@ public class UniverseObjectSerializer : EngineTypeYamlSerializerBase<IUniverseOb
|
||||
{
|
||||
public override IUniverseObject? Read(IParser parser, Type type, ObjectDeserializer rootDeserializer)
|
||||
{
|
||||
bool isTrackingController = ProgressionTracker.Progression.ApproximatelyEquals(0f);
|
||||
|
||||
string name;
|
||||
string id;
|
||||
|
||||
@ -28,6 +30,7 @@ public class UniverseObjectSerializer : EngineTypeYamlSerializerBase<IUniverseOb
|
||||
if (parser.Consume<Scalar>().Value.CompareTo(nameof(IUniverseObject.Name)) != 0)
|
||||
throw new();
|
||||
name = parser.Consume<Scalar>().Value;
|
||||
ProgressionTracker.Set(isTrackingController ? .1f : ProgressionTracker.Progression, $"Reading {name}");
|
||||
|
||||
if (parser.Consume<Scalar>().Value.CompareTo(nameof(IUniverseObject.Id)) != 0)
|
||||
throw new();
|
||||
@ -36,6 +39,7 @@ public class UniverseObjectSerializer : EngineTypeYamlSerializerBase<IUniverseOb
|
||||
if (parser.Consume<Scalar>().Value.CompareTo(SERIALIZED_SCALAR_NAME) != 0)
|
||||
throw new();
|
||||
SerializedClass instanceSerializedClass = (SerializedClass)rootDeserializer(typeof(SerializedClass))!;
|
||||
ProgressionTracker.Set(isTrackingController ? .3f : ProgressionTracker.Progression, $"Creating {instanceSerializedClass.Type}");
|
||||
universeObject = (IUniverseObject)instanceSerializedClass.CreateInstance(EntityRegistry);
|
||||
|
||||
if (parser.Consume<Scalar>().Value.CompareTo(nameof(IUniverseObject.StateEnable)) != 0)
|
||||
@ -64,6 +68,7 @@ public class UniverseObjectSerializer : EngineTypeYamlSerializerBase<IUniverseOb
|
||||
foreach (IUniverseObject child in children)
|
||||
universeObject.AddChild(child);
|
||||
|
||||
ProgressionTracker.Set(isTrackingController ? .3f : ProgressionTracker.Progression, $"Created {name}");
|
||||
return universeObject;
|
||||
}
|
||||
|
||||
@ -71,6 +76,9 @@ public class UniverseObjectSerializer : EngineTypeYamlSerializerBase<IUniverseOb
|
||||
{
|
||||
IUniverseObject universeObject = (IUniverseObject)value!;
|
||||
|
||||
bool isTrackingController = ProgressionTracker.Progression.ApproximatelyEquals(0f);
|
||||
ProgressionTracker.Set(isTrackingController ? .25f : ProgressionTracker.Progression, $"Serializing universe object");
|
||||
|
||||
emitter.Emit(new MappingStart());
|
||||
|
||||
emitter.Emit(new Scalar(nameof(IUniverseObject.Name)));
|
||||
@ -91,6 +99,7 @@ public class UniverseObjectSerializer : EngineTypeYamlSerializerBase<IUniverseOb
|
||||
emitter.Emit(new Scalar(nameof(IUniverseObject.Children)));
|
||||
serializer(universeObject.Children.Where(c => !c.GetType().HasAttribute<IgnoreSerializationAttribute>()));
|
||||
|
||||
ProgressionTracker.Set(isTrackingController ? 1f : ProgressionTracker.Progression, $"Serializing universe object");
|
||||
emitter.Emit(new MappingEnd());
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>false</ImplicitUsings>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>disable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>Syntriax.Engine.Serializers.Yaml</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
@ -0,0 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Syntriax.Engine.Serializers.Yaml;
|
||||
|
||||
[Serializable]
|
||||
public class SerializerInProgressException() : Exception("There's already a running deserialization in progress.");
|
@ -2,7 +2,9 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Syntriax.Engine.Core;
|
||||
using Syntriax.Engine.Core.Serialization;
|
||||
|
||||
using YamlDotNet.Serialization;
|
||||
@ -16,10 +18,14 @@ public class YamlSerializer : Core.Serialization.ISerializer
|
||||
private readonly YamlDotNet.Serialization.IDeserializer deserializer = null!;
|
||||
|
||||
private readonly EntityRegistry entityRegistry = null!;
|
||||
private readonly IProgressionTracker progressionTracker = null!;
|
||||
|
||||
private readonly System.Threading.Lock Lock = new();
|
||||
|
||||
public YamlSerializer()
|
||||
{
|
||||
entityRegistry = new();
|
||||
progressionTracker = new ProgressionTracker();
|
||||
|
||||
SerializerBuilder serializerBuilder = new SerializerBuilder()
|
||||
.WithNamingConvention(PascalCaseNamingConvention.Instance)
|
||||
@ -32,6 +38,7 @@ public class YamlSerializer : Core.Serialization.ISerializer
|
||||
{
|
||||
typeConverter.Serializer = this;
|
||||
typeConverter.EntityRegistry = entityRegistry;
|
||||
typeConverter.ProgressionTracker = progressionTracker;
|
||||
|
||||
deserializerBuilder = deserializerBuilder.WithTypeConverter(typeConverter);
|
||||
serializerBuilder = serializerBuilder.WithTypeConverter(typeConverter);
|
||||
@ -49,35 +56,87 @@ public class YamlSerializer : Core.Serialization.ISerializer
|
||||
|
||||
public string Serialize(object instance)
|
||||
{
|
||||
return serializer.Serialize(instance);
|
||||
lock (Lock)
|
||||
{
|
||||
return serializer.Serialize(instance);
|
||||
}
|
||||
}
|
||||
|
||||
public object Deserialize(string yaml)
|
||||
public object Deserialize(string configuration)
|
||||
{
|
||||
entityRegistry.Reset();
|
||||
object result = deserializer.Deserialize(yaml)!;
|
||||
entityRegistry.AssignAll();
|
||||
return result;
|
||||
lock (Lock)
|
||||
{
|
||||
entityRegistry.Reset();
|
||||
object result = deserializer.Deserialize(configuration)!;
|
||||
entityRegistry.AssignAll();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public object Deserialize(string yaml, Type type)
|
||||
public object Deserialize(string configuration, Type type)
|
||||
{
|
||||
entityRegistry.Reset();
|
||||
object result = deserializer.Deserialize(yaml, type)!;
|
||||
entityRegistry.AssignAll();
|
||||
return result;
|
||||
lock (Lock)
|
||||
{
|
||||
entityRegistry.Reset();
|
||||
object result = deserializer.Deserialize(configuration, type)!;
|
||||
entityRegistry.AssignAll();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public T Deserialize<T>(string yaml)
|
||||
public T Deserialize<T>(string configuration)
|
||||
{
|
||||
entityRegistry.Reset();
|
||||
T result = deserializer.Deserialize<T>(yaml);
|
||||
entityRegistry.AssignAll();
|
||||
return result;
|
||||
lock (Lock)
|
||||
{
|
||||
entityRegistry.Reset();
|
||||
T result = deserializer.Deserialize<T>(configuration);
|
||||
entityRegistry.AssignAll();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
internal object InternalDeserialize(string yaml, Type type)
|
||||
public ProgressiveTask<object> DeserializeAsync(string configuration)
|
||||
{
|
||||
return deserializer.Deserialize(yaml, type)!;
|
||||
lock (Lock)
|
||||
{
|
||||
progressionTracker.Reset();
|
||||
Task<object> task = Task.Run(() => Deserialize(configuration));
|
||||
return new ProgressiveTask<object>(progressionTracker, task);
|
||||
}
|
||||
}
|
||||
|
||||
public ProgressiveTask<object> DeserializeAsync(string configuration, Type type)
|
||||
{
|
||||
lock (Lock)
|
||||
{
|
||||
progressionTracker.Reset();
|
||||
Task<object> task = Task.Run(() => Deserialize(configuration, type));
|
||||
return new ProgressiveTask<object>(progressionTracker, task);
|
||||
}
|
||||
}
|
||||
|
||||
public ProgressiveTask<T> DeserializeAsync<T>(string configuration)
|
||||
{
|
||||
lock (Lock)
|
||||
{
|
||||
progressionTracker.Reset();
|
||||
Task<T> task = Task.Run(() => Deserialize<T>(configuration));
|
||||
return new ProgressiveTask<T>(progressionTracker, task);
|
||||
}
|
||||
}
|
||||
|
||||
public ProgressiveTask<string> SerializeAsync(object instance)
|
||||
{
|
||||
lock (Lock)
|
||||
{
|
||||
progressionTracker.Reset();
|
||||
Task<string> task = Task.Run(() => Serialize(instance));
|
||||
return new ProgressiveTask<string>(progressionTracker, task);
|
||||
}
|
||||
}
|
||||
|
||||
internal object InternalDeserialize(string configuration, Type type)
|
||||
{
|
||||
return deserializer.Deserialize(configuration, type)!;
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>disable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>Syntriax.Engine.Systems</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
10
Engine.Systems/Preserver.cs
Normal file
10
Engine.Systems/Preserver.cs
Normal file
@ -0,0 +1,10 @@
|
||||
namespace Syntriax.Engine.Systems
|
||||
{
|
||||
// This is pretty much so the assembly gets loaded automatically because
|
||||
// the builds include the assembly but sometimes doesn't link load it at startup.
|
||||
// I will hopefully one day fix it and remove this.
|
||||
public static class Preserver
|
||||
{
|
||||
public static void Preserve() { }
|
||||
}
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Syntriax.Engine.Core;
|
||||
|
||||
namespace Syntriax.Engine.Systems.StateMachine;
|
||||
|
@ -1,3 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Syntriax.Engine.Systems.StateMachine;
|
||||
|
||||
public readonly record struct StateTransition(IState State, IReadOnlyList<Func<bool>> Conditions)
|
||||
|
@ -1,5 +1,7 @@
|
||||
// Reference: https://easings.net
|
||||
|
||||
using Syntriax.Engine.Core;
|
||||
|
||||
namespace Syntriax.Engine.Systems.Tween;
|
||||
|
||||
internal static class EaseConstants
|
||||
@ -7,52 +9,54 @@ internal static class EaseConstants
|
||||
internal const float c1 = 1.70158f;
|
||||
internal const float c2 = c1 * 1.525f;
|
||||
internal const float c3 = c1 + 1f;
|
||||
internal const float c4 = 2f * Core.Math.PI / 3f;
|
||||
internal const float c5 = 2f * Core.Math.PI / 4.5f;
|
||||
internal const float c4 = 2f * Math.PI / 3f;
|
||||
internal const float c5 = 2f * Math.PI / 4.5f;
|
||||
}
|
||||
|
||||
public readonly struct EaseLinear : IEasing { public readonly float Evaluate(float x) => x; }
|
||||
public abstract class EasingBase<T> where T : IEasing, new() { public static readonly T Instance = new(); }
|
||||
|
||||
public readonly struct EaseInQuad : IEasing { public readonly float Evaluate(float x) => x * x; }
|
||||
public readonly struct EaseOutQuad : IEasing { public readonly float Evaluate(float x) => 1f - (1f - x) * (1f - x); }
|
||||
public readonly struct EaseInOutQuad : IEasing { public readonly float Evaluate(float x) => x < .5f ? 2f * x * x : 1f - Core.Math.Pow(-2f * x + 2f, 2f) * .5f; }
|
||||
public class EaseLinear : EasingBase<EaseLinear>, IEasing { public float Evaluate(float x) => x; }
|
||||
|
||||
public readonly struct EaseInCubic : IEasing { public readonly float Evaluate(float x) => x * x * x; }
|
||||
public readonly struct EaseOutCubic : IEasing { public readonly float Evaluate(float x) => 1f - Core.Math.Pow(1f - x, 3f); }
|
||||
public readonly struct EaseInOutCubic : IEasing { public readonly float Evaluate(float x) => x < .5f ? 4f * x * x * x : 1f - Core.Math.Pow(-2f * x + 2f, 3f) * .5f; }
|
||||
public class EaseInQuad : EasingBase<EaseInQuad>, IEasing { public float Evaluate(float x) => x * x; }
|
||||
public class EaseOutQuad : EasingBase<EaseOutQuad>, IEasing { public float Evaluate(float x) => 1f - (1f - x) * (1f - x); }
|
||||
public class EaseInOutQuad : EasingBase<EaseInOutQuad>, IEasing { public float Evaluate(float x) => x < .5f ? 2f * x * x : 1f - Math.Pow(-2f * x + 2f, 2f) * .5f; }
|
||||
|
||||
public readonly struct EaseInQuart : IEasing { public readonly float Evaluate(float x) => x * x * x * x; }
|
||||
public readonly struct EaseOutQuart : IEasing { public readonly float Evaluate(float x) => 1f - Core.Math.Pow(1f - x, 4f); }
|
||||
public readonly struct EaseInOutQuart : IEasing { public readonly float Evaluate(float x) => x < .5f ? 8f * x * x * x * x : 1f - Core.Math.Pow(-2f * x + 2f, 4f) * .5f; }
|
||||
public class EaseInCubic : EasingBase<EaseInCubic>, IEasing { public float Evaluate(float x) => x * x * x; }
|
||||
public class EaseOutCubic : EasingBase<EaseOutCubic>, IEasing { public float Evaluate(float x) => 1f - Math.Pow(1f - x, 3f); }
|
||||
public class EaseInOutCubic : EasingBase<EaseInOutCubic>, IEasing { public float Evaluate(float x) => x < .5f ? 4f * x * x * x : 1f - Math.Pow(-2f * x + 2f, 3f) * .5f; }
|
||||
|
||||
public readonly struct EaseInQuint : IEasing { public readonly float Evaluate(float x) => x * x * x * x * x; }
|
||||
public readonly struct EaseOutQuint : IEasing { public readonly float Evaluate(float x) => 1f - Core.Math.Pow(1f - x, 5f); }
|
||||
public readonly struct EaseInOutQuint : IEasing { public readonly float Evaluate(float x) => x < .5f ? 16f * x * x * x * x * x : 1f - Core.Math.Pow(-2f * x + 2f, 5f) * .5f; }
|
||||
public class EaseInQuart : EasingBase<EaseInQuart>, IEasing { public float Evaluate(float x) => x * x * x * x; }
|
||||
public class EaseOutQuart : EasingBase<EaseOutQuart>, IEasing { public float Evaluate(float x) => 1f - Math.Pow(1f - x, 4f); }
|
||||
public class EaseInOutQuart : EasingBase<EaseInOutQuart>, IEasing { public float Evaluate(float x) => x < .5f ? 8f * x * x * x * x : 1f - Math.Pow(-2f * x + 2f, 4f) * .5f; }
|
||||
|
||||
public readonly struct EaseInSine : IEasing { public readonly float Evaluate(float x) => 1f - Core.Math.Cos(x * Core.Math.PI * .5f); }
|
||||
public readonly struct EaseOutSine : IEasing { public readonly float Evaluate(float x) => Core.Math.Sin(x * Core.Math.PI * .5f); }
|
||||
public readonly struct EaseInOutSine : IEasing { public readonly float Evaluate(float x) => -(Core.Math.Cos(Core.Math.PI * x) - 1f) * .5f; }
|
||||
public class EaseInQuint : EasingBase<EaseInQuint>, IEasing { public float Evaluate(float x) => x * x * x * x * x; }
|
||||
public class EaseOutQuint : EasingBase<EaseOutQuint>, IEasing { public float Evaluate(float x) => 1f - Math.Pow(1f - x, 5f); }
|
||||
public class EaseInOutQuint : EasingBase<EaseInOutQuint>, IEasing { public float Evaluate(float x) => x < .5f ? 16f * x * x * x * x * x : 1f - Math.Pow(-2f * x + 2f, 5f) * .5f; }
|
||||
|
||||
public readonly struct EaseInExpo : IEasing { public readonly float Evaluate(float x) => x == 0f ? 0f : Core.Math.Pow(2f, 10f * x - 10f); }
|
||||
public readonly struct EaseOutExpo : IEasing { public readonly float Evaluate(float x) => x == 1f ? 1f : 1f - Core.Math.Pow(2f, -10f * x); }
|
||||
public readonly struct EaseInOutExpo : IEasing { public readonly float Evaluate(float x) => x == 0f ? 0f : x == 1f ? 1f : x < .5f ? Core.Math.Pow(2f, 20f * x - 10f) * .5f : (2f - Core.Math.Pow(2f, -20f * x + 10f)) * .5f; }
|
||||
public class EaseInSine : EasingBase<EaseInSine>, IEasing { public float Evaluate(float x) => 1f - Math.Cos(x * Math.PI * .5f); }
|
||||
public class EaseOutSine : EasingBase<EaseOutSine>, IEasing { public float Evaluate(float x) => Math.Sin(x * Math.PI * .5f); }
|
||||
public class EaseInOutSine : EasingBase<EaseInOutSine>, IEasing { public float Evaluate(float x) => -(Math.Cos(Math.PI * x) - 1f) * .5f; }
|
||||
|
||||
public readonly struct EaseInCirc : IEasing { public readonly float Evaluate(float x) => 1f - Core.Math.Sqrt(1f - Core.Math.Pow(x, 2f)); }
|
||||
public readonly struct EaseOutCirc : IEasing { public readonly float Evaluate(float x) => Core.Math.Sqrt(1f - Core.Math.Pow(x - 1f, 2f)); }
|
||||
public readonly struct EaseInOutCirc : IEasing { public readonly float Evaluate(float x) => x < .5f ? (1f - Core.Math.Sqrt(1f - Core.Math.Pow(2f * x, 2f))) * .5f : (Core.Math.Sqrt(1f - Core.Math.Pow(-2f * x + 2f, 2f)) + 1f) * .5f; }
|
||||
public class EaseInExpo : EasingBase<EaseInExpo>, IEasing { public float Evaluate(float x) => x == 0f ? 0f : Math.Pow(2f, 10f * x - 10f); }
|
||||
public class EaseOutExpo : EasingBase<EaseOutExpo>, IEasing { public float Evaluate(float x) => x == 1f ? 1f : 1f - Math.Pow(2f, -10f * x); }
|
||||
public class EaseInOutExpo : EasingBase<EaseInOutExpo>, IEasing { public float Evaluate(float x) => x == 0f ? 0f : x == 1f ? 1f : x < .5f ? Math.Pow(2f, 20f * x - 10f) * .5f : (2f - Math.Pow(2f, -20f * x + 10f)) * .5f; }
|
||||
|
||||
public readonly struct EaseInBack : IEasing { public readonly float Evaluate(float x) => EaseConstants.c3 * x * x * x - EaseConstants.c1 * x * x; }
|
||||
public readonly struct EaseOutBack : IEasing { public readonly float Evaluate(float x) => 1f + EaseConstants.c3 * Core.Math.Pow(x - 1f, 3f) + EaseConstants.c1 * Core.Math.Pow(x - 1f, 2f); }
|
||||
public readonly struct EaseInOutBack : IEasing { public readonly float Evaluate(float x) => x < .5f ? Core.Math.Pow(2f * x, 2f) * ((EaseConstants.c2 + 1f) * 2f * x - EaseConstants.c2) * .5f : (Core.Math.Pow(2f * x - 2f, 2f) * ((EaseConstants.c2 + 1f) * (x * 2f - 2f) + EaseConstants.c2) + 2f) * .5f; }
|
||||
public class EaseInCirc : EasingBase<EaseInCirc>, IEasing { public float Evaluate(float x) => 1f - Math.Sqrt(1f - Math.Pow(x, 2f)); }
|
||||
public class EaseOutCirc : EasingBase<EaseOutCirc>, IEasing { public float Evaluate(float x) => Math.Sqrt(1f - Math.Pow(x - 1f, 2f)); }
|
||||
public class EaseInOutCirc : EasingBase<EaseInOutCirc>, IEasing { public float Evaluate(float x) => x < .5f ? (1f - Math.Sqrt(1f - Math.Pow(2f * x, 2f))) * .5f : (Math.Sqrt(1f - Math.Pow(-2f * x + 2f, 2f)) + 1f) * .5f; }
|
||||
|
||||
public readonly struct EaseInElastic : IEasing { public readonly float Evaluate(float x) => x == 0 ? 0 : x == 1f ? 1f : -Core.Math.Pow(2f, 10f * x - 10f) * Core.Math.Sin((x * 10f - 10.75f) * EaseConstants.c4); }
|
||||
public readonly struct EaseOutElastic : IEasing { public readonly float Evaluate(float x) => x == 0 ? 0 : x == 1f ? 1f : Core.Math.Pow(2f, -10f * x) * Core.Math.Sin((x * 10f - .75f) * EaseConstants.c4) + 1f; }
|
||||
public readonly struct EaseInOutElastic : IEasing { public readonly float Evaluate(float x) => x == 0 ? 0 : x == 1f ? 1f : x < .5f ? -(Core.Math.Pow(2f, 20f * x - 10f) * Core.Math.Sin((20f * x - 11.125f) * EaseConstants.c5)) * .5f : Core.Math.Pow(2f, -20f * x + 10f) * Core.Math.Sin((20f * x - 11.125f) * EaseConstants.c5) * .5f + 1f; }
|
||||
public class EaseInBack : EasingBase<EaseInBack>, IEasing { public float Evaluate(float x) => EaseConstants.c3 * x * x * x - EaseConstants.c1 * x * x; }
|
||||
public class EaseOutBack : EasingBase<EaseOutBack>, IEasing { public float Evaluate(float x) => 1f + EaseConstants.c3 * Math.Pow(x - 1f, 3f) + EaseConstants.c1 * Math.Pow(x - 1f, 2f); }
|
||||
public class EaseInOutBack : EasingBase<EaseInOutBack>, IEasing { public float Evaluate(float x) => x < .5f ? Math.Pow(2f * x, 2f) * ((EaseConstants.c2 + 1f) * 2f * x - EaseConstants.c2) * .5f : (Math.Pow(2f * x - 2f, 2f) * ((EaseConstants.c2 + 1f) * (x * 2f - 2f) + EaseConstants.c2) + 2f) * .5f; }
|
||||
|
||||
public readonly struct EaseInBounce : IEasing { public readonly float Evaluate(float x) => 1f - new EaseOutBounce().Evaluate(1f - x); }
|
||||
public readonly struct EaseOutBounce : IEasing
|
||||
public class EaseInElastic : EasingBase<EaseInElastic>, IEasing { public float Evaluate(float x) => x == 0 ? 0 : x == 1f ? 1f : -Math.Pow(2f, 10f * x - 10f) * Math.Sin((x * 10f - 10.75f) * EaseConstants.c4); }
|
||||
public class EaseOutElastic : EasingBase<EaseOutElastic>, IEasing { public float Evaluate(float x) => x == 0 ? 0 : x == 1f ? 1f : Math.Pow(2f, -10f * x) * Math.Sin((x * 10f - .75f) * EaseConstants.c4) + 1f; }
|
||||
public class EaseInOutElastic : EasingBase<EaseInOutElastic>, IEasing { public float Evaluate(float x) => x == 0 ? 0 : x == 1f ? 1f : x < .5f ? -(Math.Pow(2f, 20f * x - 10f) * Math.Sin((20f * x - 11.125f) * EaseConstants.c5)) * .5f : Math.Pow(2f, -20f * x + 10f) * Math.Sin((20f * x - 11.125f) * EaseConstants.c5) * .5f + 1f; }
|
||||
|
||||
public class EaseInBounce : EasingBase<EaseInBounce>, IEasing { public float Evaluate(float x) => 1f - EaseOutBounce.Instance.Evaluate(1f - x); }
|
||||
public class EaseOutBounce : EasingBase<EaseOutBounce>, IEasing
|
||||
{
|
||||
public readonly float Evaluate(float x)
|
||||
public float Evaluate(float x)
|
||||
{
|
||||
const float n1 = 7.5625f;
|
||||
const float d1 = 2.75f;
|
||||
@ -69,4 +73,4 @@ public readonly struct EaseOutBounce : IEasing
|
||||
return n1 * (x -= 2.625f / d1) * x + .984375f;
|
||||
}
|
||||
}
|
||||
public readonly struct EaseInOutBounce : IEasing { public readonly float Evaluate(float x) => x < .5f ? (1f - new EaseOutBounce().Evaluate(1f - 2f * x)) * .5f : (1f + new EaseOutBounce().Evaluate(2f * x - 1f)) * .5f; }
|
||||
public class EaseInOutBounce : IEasing { public float Evaluate(float x) => x < .5f ? (1f - EaseOutBounce.Instance.Evaluate(1f - 2f * x)) * .5f : (1f + EaseOutBounce.Instance.Evaluate(2f * x - 1f)) * .5f; }
|
||||
|
10
Engine.Systems/Tween/EngineExtensions/TweenAABBExtensions.cs
Normal file
10
Engine.Systems/Tween/EngineExtensions/TweenAABBExtensions.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using Syntriax.Engine.Core;
|
||||
|
||||
namespace Syntriax.Engine.Systems.Tween;
|
||||
|
||||
public static class TweenAABBExtensions
|
||||
{
|
||||
public static ITween TweenAABB(this AABB initialAABB, ITweenManager tweenManager, float duration, AABB targetAABB, Action<AABB> setMethod)
|
||||
=> tweenManager.StartTween(duration, t => setMethod?.InvokeSafe(new AABB(initialAABB.LowerBoundary.Lerp(targetAABB.LowerBoundary, t), initialAABB.UpperBoundary.Lerp(targetAABB.UpperBoundary, t))));
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
using Syntriax.Engine.Core;
|
||||
|
||||
namespace Syntriax.Engine.Systems.Tween;
|
||||
|
||||
public static class TweenCamera2DExtensions
|
||||
{
|
||||
public static ITween TweenZoom(this ICamera2D camera2D, ITweenManager tweenManager, float duration, float targetZoom)
|
||||
{
|
||||
float initialZoom = camera2D.Zoom;
|
||||
return tweenManager.StartTween(duration, t => camera2D.Zoom = initialZoom.Lerp(targetZoom, t));
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
using Syntriax.Engine.Core;
|
||||
|
||||
namespace Syntriax.Engine.Systems.Tween;
|
||||
|
||||
public static class TweenCircleExtensions
|
||||
{
|
||||
public static ITween TweenCircle(this Circle initialCircle, ITweenManager tweenManager, float duration, Circle targetCircle, System.Action<Circle> setMethod)
|
||||
=> tweenManager.StartTween(duration,
|
||||
t => setMethod?.InvokeSafe(
|
||||
new Circle(
|
||||
initialCircle.Center.Lerp(targetCircle.Center, t),
|
||||
initialCircle.Diameter.Lerp(targetCircle.Diameter, t)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
using Syntriax.Engine.Core;
|
||||
|
||||
namespace Syntriax.Engine.Systems.Tween;
|
||||
|
||||
public static class TweenColorExtensions
|
||||
{
|
||||
public static ITween TweenColor(this ColorRGB initialColorRGB, ITweenManager tweenManager, float duration, ColorRGB targetColorRGB, System.Action<ColorRGB> setMethod)
|
||||
=> tweenManager.StartTween(duration, t => setMethod?.InvokeSafe(initialColorRGB.Lerp(targetColorRGB, t)));
|
||||
|
||||
public static ITween TweenColor(this ColorRGBA initialColorRGBA, ITweenManager tweenManager, float duration, ColorRGBA targetColorRGBA, System.Action<ColorRGBA> setMethod)
|
||||
=> tweenManager.StartTween(duration, t => setMethod?.InvokeSafe(initialColorRGBA.Lerp(targetColorRGBA, t)));
|
||||
|
||||
public static ITween TweenColor(this ColorHSV initialColorHSV, ITweenManager tweenManager, float duration, ColorHSV targetColorHSV, System.Action<ColorHSV> setMethod)
|
||||
=> tweenManager.StartTween(duration, t => setMethod?.InvokeSafe(initialColorHSV.Lerp(targetColorHSV, t)));
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
using Syntriax.Engine.Core;
|
||||
|
||||
namespace Syntriax.Engine.Systems.Tween;
|
||||
|
||||
public static class TweenLine2DEquationExtensions
|
||||
{
|
||||
public static ITween TweenLine2DEquation(this Line2DEquation initialLine2DEquation, ITweenManager tweenManager, float duration, Line2DEquation targetLine2DEquation, System.Action<Line2DEquation> setMethod)
|
||||
=> tweenManager.StartTween(duration,
|
||||
t => setMethod?.InvokeSafe(
|
||||
new Line2DEquation(
|
||||
initialLine2DEquation.Slope.Lerp(targetLine2DEquation.Slope, t),
|
||||
initialLine2DEquation.OffsetY.Lerp(targetLine2DEquation.OffsetY, t)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
using Syntriax.Engine.Core;
|
||||
|
||||
namespace Syntriax.Engine.Systems.Tween;
|
||||
|
||||
public static class TweenLine2DExtensions
|
||||
{
|
||||
public static ITween TweenLine2D(this Line2D initialLine2D, ITweenManager tweenManager, float duration, Line2D targetLine2D, System.Action<Line2D> setMethod)
|
||||
=> tweenManager.StartTween(duration,
|
||||
t => setMethod?.InvokeSafe(
|
||||
new Line2D(
|
||||
initialLine2D.From.Lerp(targetLine2D.From, t),
|
||||
initialLine2D.To.Lerp(targetLine2D.To, t)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using Syntriax.Engine.Core;
|
||||
|
||||
namespace Syntriax.Engine.Systems.Tween;
|
||||
|
||||
public static class TweenProjection1DExtensions
|
||||
{
|
||||
public static ITween TweenProjection1D(this Projection1D initialProjection1D, ITweenManager tweenManager, float duration, Projection1D targetProjection1D, Action<Projection1D> setMethod)
|
||||
=> tweenManager.StartTween(duration,
|
||||
t => setMethod?.InvokeSafe(
|
||||
new Projection1D(
|
||||
initialProjection1D.Min.Lerp(targetProjection1D.Min, t),
|
||||
initialProjection1D.Max.Lerp(targetProjection1D.Max, t)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using Syntriax.Engine.Core;
|
||||
|
||||
namespace Syntriax.Engine.Systems.Tween;
|
||||
|
||||
public static class TweenQuaternionExtensions
|
||||
{
|
||||
public static ITween TweenQuaternion(this Quaternion initialQuaternion, ITweenManager tweenManager, float duration, Quaternion targetQuaternion, Action<Quaternion> setMethod)
|
||||
=> tweenManager.StartTween(duration, t => setMethod?.InvokeSafe(initialQuaternion.SLerp(targetQuaternion, t)));
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
using System.Collections.Generic;
|
||||
using Syntriax.Engine.Core;
|
||||
|
||||
namespace Syntriax.Engine.Systems.Tween;
|
||||
|
||||
public static class TweenShape2DExtensions
|
||||
{
|
||||
public static ITween TweenShape2D(this Shape2D shape, ITweenManager tweenManager, float duration, Shape2D targetShape2D)
|
||||
{
|
||||
List<Vector2D> initialVertices = new(shape.Vertices);
|
||||
List<Vector2D> shapeVertices = new(shape.Vertices);
|
||||
|
||||
return tweenManager.StartTween(duration,
|
||||
t =>
|
||||
{
|
||||
shapeVertices.Clear();
|
||||
int maxCount = initialVertices.Count.Max(targetShape2D.Vertices.Count);
|
||||
for (int i = 0; i < maxCount; i++)
|
||||
{
|
||||
int initialIndex = (i * (initialVertices.Count / (float)maxCount)).RoundToInt(Math.RoundMode.Floor);
|
||||
int targetIndex = (i * (targetShape2D.Vertices.Count / (float)maxCount)).RoundToInt(Math.RoundMode.Floor);
|
||||
shapeVertices.Add(targetShape2D.Vertices[targetIndex].Lerp(initialVertices[initialIndex], 1f - t));
|
||||
}
|
||||
shape.Vertices = shapeVertices;
|
||||
}
|
||||
).OnComplete(() =>
|
||||
{
|
||||
shapeVertices.Clear();
|
||||
for (int i = 0; i < targetShape2D.Vertices.Count; i++)
|
||||
shapeVertices.Add(targetShape2D.Vertices[i]);
|
||||
shape.Vertices = shapeVertices;
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
using Syntriax.Engine.Core;
|
||||
|
||||
namespace Syntriax.Engine.Systems.Tween;
|
||||
|
||||
public static class TweenTransform2DExtensions
|
||||
{
|
||||
public static ITween TweenPosition(this ITransform2D transform2D, ITweenManager tweenManager, float duration, Vector2D targetPosition)
|
||||
{
|
||||
Vector2D initialPosition = transform2D.Position;
|
||||
return tweenManager.StartTween(duration, t => transform2D.Position = initialPosition.Lerp(targetPosition, t));
|
||||
}
|
||||
|
||||
public static ITween TweenScale(this ITransform2D transform2D, ITweenManager tweenManager, float duration, Vector2D targetScale)
|
||||
{
|
||||
Vector2D initialScale = transform2D.Scale;
|
||||
return tweenManager.StartTween(duration, t => transform2D.Scale = initialScale.Lerp(targetScale, t));
|
||||
}
|
||||
|
||||
public static ITween TweenRotation(this ITransform2D transform2D, ITweenManager tweenManager, float duration, float targetRotation)
|
||||
{
|
||||
float initialRotation = transform2D.Rotation;
|
||||
return tweenManager.StartTween(duration, t => transform2D.Rotation = initialRotation.Lerp(targetRotation, t));
|
||||
}
|
||||
|
||||
public static ITween TweenLocalPosition(this ITransform2D transform2D, ITweenManager tweenManager, float duration, Vector2D targetLocalPosition)
|
||||
{
|
||||
Vector2D initialLocalPosition = transform2D.LocalPosition;
|
||||
return tweenManager.StartTween(duration, t => transform2D.LocalPosition = initialLocalPosition.Lerp(targetLocalPosition, t));
|
||||
}
|
||||
|
||||
public static ITween TweenLocalScale(this ITransform2D transform2D, ITweenManager tweenManager, float duration, Vector2D targetLocalScale)
|
||||
{
|
||||
Vector2D initialLocalScale = transform2D.LocalScale;
|
||||
return tweenManager.StartTween(duration, t => transform2D.LocalScale = initialLocalScale.Lerp(targetLocalScale, t));
|
||||
}
|
||||
|
||||
public static ITween TweenLocalRotation(this ITransform2D transform2D, ITweenManager tweenManager, float duration, float targetLocalRotation)
|
||||
{
|
||||
float initialLocalRotation = transform2D.LocalRotation;
|
||||
return tweenManager.StartTween(duration, t => transform2D.LocalRotation = initialLocalRotation.Lerp(targetLocalRotation, t));
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using Syntriax.Engine.Core;
|
||||
|
||||
namespace Syntriax.Engine.Systems.Tween;
|
||||
|
||||
public static class TweenTriangleExtensions
|
||||
{
|
||||
public static ITween TweenTriangle(this Triangle initialTriangle, ITweenManager tweenManager, float duration, Triangle targetTriangle, Action<Triangle> setMethod)
|
||||
=> tweenManager.StartTween(duration,
|
||||
t => setMethod?.InvokeSafe(
|
||||
new Triangle(
|
||||
initialTriangle.A.Lerp(targetTriangle.A, t),
|
||||
initialTriangle.B.Lerp(targetTriangle.B, t),
|
||||
initialTriangle.C.Lerp(targetTriangle.C, t)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
using Syntriax.Engine.Core;
|
||||
|
||||
namespace Syntriax.Engine.Systems.Tween;
|
||||
|
||||
public static class TweenVector2DExtensions
|
||||
{
|
||||
public static ITween TweenVector2D(this Vector2D initialVector2D, ITweenManager tweenManager, float duration, Vector2D targetVector2D, System.Action<Vector2D> setMethod)
|
||||
=> tweenManager.StartTween(duration, t => setMethod?.InvokeSafe(initialVector2D.Lerp(targetVector2D, t)));
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
using Syntriax.Engine.Core;
|
||||
|
||||
namespace Syntriax.Engine.Systems.Tween;
|
||||
|
||||
public static class TweenVector3DExtensions
|
||||
{
|
||||
public static ITween TweenVector3D(this Vector3D initialVector3D, ITweenManager tweenManager, float duration, Vector3D targetVector3D, System.Action<Vector3D> setMethod)
|
||||
=> tweenManager.StartTween(duration, t => setMethod?.InvokeSafe(initialVector3D.Lerp(targetVector3D, t)));
|
||||
}
|
9
Engine.Systems/Tween/ITweenManager.cs
Normal file
9
Engine.Systems/Tween/ITweenManager.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace Syntriax.Engine.Systems.Tween;
|
||||
|
||||
public interface ITweenManager
|
||||
{
|
||||
ITween StartTween(float duration, TweenSetCallback? setCallback = null);
|
||||
void CancelTween(ITween tween);
|
||||
|
||||
delegate void TweenSetCallback(float t);
|
||||
}
|
@ -43,7 +43,7 @@ internal class Tween : ITween
|
||||
public float Progress { get; internal set; } = 0f;
|
||||
private float _counter = 0f;
|
||||
|
||||
public IEasing Easing { get; set; } = new EaseLinear();
|
||||
public IEasing Easing { get; set; } = EaseLinear.Instance;
|
||||
public float Value => Easing.Evaluate(Progress);
|
||||
|
||||
public float Counter
|
||||
|
@ -1,3 +1,5 @@
|
||||
using System;
|
||||
|
||||
using Syntriax.Engine.Core;
|
||||
|
||||
namespace Syntriax.Engine.Systems.Tween;
|
||||
@ -47,42 +49,49 @@ public static class TweenExtensions
|
||||
tweenConcrete.OnStarted += _ => callback.InvokeSafe();
|
||||
return tween;
|
||||
}
|
||||
|
||||
public static ITween OnPause(this ITween tween, Action callback)
|
||||
{
|
||||
Tween tweenConcrete = (Tween)tween;
|
||||
tweenConcrete.OnPaused += _ => callback.InvokeSafe();
|
||||
return tween;
|
||||
}
|
||||
|
||||
public static ITween OnResume(this ITween tween, Action callback)
|
||||
{
|
||||
Tween tweenConcrete = (Tween)tween;
|
||||
tweenConcrete.OnResumed += _ => callback.InvokeSafe();
|
||||
return tween;
|
||||
}
|
||||
|
||||
public static ITween OnCancel(this ITween tween, Action callback)
|
||||
{
|
||||
Tween tweenConcrete = (Tween)tween;
|
||||
tweenConcrete.OnCancelled += _ => callback.InvokeSafe();
|
||||
return tween;
|
||||
}
|
||||
|
||||
public static ITween OnComplete(this ITween tween, Action callback)
|
||||
{
|
||||
Tween tweenConcrete = (Tween)tween;
|
||||
tweenConcrete.OnCompleted += _ => callback.InvokeSafe();
|
||||
return tween;
|
||||
}
|
||||
|
||||
public static ITween OnEnd(this ITween tween, Action callback)
|
||||
{
|
||||
Tween tweenConcrete = (Tween)tween;
|
||||
tweenConcrete.OnEnded += _ => callback.InvokeSafe();
|
||||
return tween;
|
||||
}
|
||||
|
||||
public static ITween OnUpdate(this ITween tween, Action callback)
|
||||
{
|
||||
Tween tweenConcrete = (Tween)tween;
|
||||
tweenConcrete.OnUpdated += _ => callback.InvokeSafe();
|
||||
return tween;
|
||||
}
|
||||
|
||||
public static ITween OnDeltaUpdate(this ITween tween, Action<float> callback)
|
||||
{
|
||||
Tween tweenConcrete = (Tween)tween;
|
||||
|
@ -1,16 +1,17 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Syntriax.Engine.Core;
|
||||
|
||||
namespace Syntriax.Engine.Systems.Tween;
|
||||
|
||||
public class TweenManager : UniverseObject
|
||||
public class TweenManager : UniverseObject, ITweenManager
|
||||
{
|
||||
private CoroutineManager coroutineManager = null!;
|
||||
|
||||
private readonly Dictionary<ITween, IEnumerator> runningCoroutines = [];
|
||||
|
||||
public ITween StartTween(float duration, TweenSetCallback? setCallback = null)
|
||||
public ITween StartTween(float duration, ITweenManager.TweenSetCallback? setCallback = null)
|
||||
{
|
||||
Tween tween = new(duration);
|
||||
tween.OnUpdated += tween => setCallback?.InvokeSafe(tween.Value);
|
||||
@ -60,6 +61,4 @@ public class TweenManager : UniverseObject
|
||||
{
|
||||
coroutineManager = null!;
|
||||
}
|
||||
|
||||
public delegate void TweenSetCallback(float t);
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>disable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>Syntriax.Engine</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
15
Engine/Preserver.cs
Normal file
15
Engine/Preserver.cs
Normal file
@ -0,0 +1,15 @@
|
||||
namespace Syntriax.Engine
|
||||
{
|
||||
// This is pretty much so the assembly gets loaded automatically because
|
||||
// the builds include the assembly but sometimes doesn't link load it at startup.
|
||||
// I will hopefully one day fix it and remove this.
|
||||
public static class Preserver
|
||||
{
|
||||
public static void Preserve()
|
||||
{
|
||||
Core.Preserver.Preserve();
|
||||
Physics2D.Preserver.Preserve();
|
||||
Systems.Preserver.Preserve();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user