diff --git a/README.md b/README.md index 6f0a1c7..7a47af3 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,8 @@ C# bindings for raylib, a simple and easy-to-use library to learn videogames pro [![GitHub stars](https://img.shields.io/github/stars/raylib-cs/raylib-cs?style=social)](https://github.com/raylib-cs/raylib-cs/stargazers) [![Build](https://github.com/raylib-cs/raylib-cs/workflows/Build/badge.svg)](https://github.com/raylib-cs/raylib-cs/actions?query=workflow%3ABuild) -Raylib-cs targets net6.0 and uses the [official 5.5 release](https://github.com/raysan5/raylib/releases/tag/5.5) to build the native libraries. +Raylib-cs targets net6.0 net8.0 and uses the [official 5.5 release](https://github.com/raysan5/raylib/releases/tag/5.5) +to build the native libraries. ## Status @@ -37,8 +38,8 @@ dotnet add package Raylib-cs If you need to edit Raylib-cs source then you will need to add the bindings as a project (see below). If you are new to using NuGet (or you've forgotten) and are trying to run the above command in the command prompt, -remember that you need to be *inside the intended project directory* (not just inside the solution directory) otherwise -the command won't work. +remember that you need to be *inside the intended project directory* (not just inside the solution directory) +otherwise the command won't work. ## Installation - Manual @@ -60,10 +61,10 @@ using Raylib_cs; namespace HelloWorld; -class Program +internal static class Program { // STAThread is required if you deploy using NativeAOT on Windows - See https://github.com/raylib-cs/raylib-cs/issues/301 - [STAThread] + [System.STAThread] public static void Main() { Raylib.InitWindow(800, 480, "Hello World"); diff --git a/Raylib-cs/Raylib-cs.csproj b/Raylib-cs/Raylib-cs.csproj index 6f014f2..ea1167f 100644 --- a/Raylib-cs/Raylib-cs.csproj +++ b/Raylib-cs/Raylib-cs.csproj @@ -1,4 +1,4 @@ - + net6.0;net8.0 false @@ -49,9 +49,6 @@ - - - - + diff --git a/Raylib-cs/interop/Raylib.cs b/Raylib-cs/interop/Raylib.cs index fdb4871..db56c5b 100644 --- a/Raylib-cs/interop/Raylib.cs +++ b/Raylib-cs/interop/Raylib.cs @@ -1,7 +1,7 @@ -using System; -using System.Numerics; using System.Runtime.InteropServices; +using System.Numerics; using System.Security; +using System; namespace Raylib_cs; diff --git a/Raylib-cs/interop/Raymath.cs b/Raylib-cs/interop/Raymath.cs index 04d549b..1435898 100644 --- a/Raylib-cs/interop/Raymath.cs +++ b/Raylib-cs/interop/Raymath.cs @@ -1,5 +1,5 @@ -using System.Numerics; using System.Runtime.InteropServices; +using System.Numerics; using System.Security; namespace Raylib_cs; @@ -21,7 +21,7 @@ public static unsafe partial class Raymath /// /// Used by DllImport to load the native library /// - public const string NativeLibName = "raylib"; + public const string NativeLibName = Raylib.NativeLibName; /// Clamp float value [DllImport(NativeLibName, CallingConvention = CallingConvention.Cdecl)] @@ -37,12 +37,9 @@ public static unsafe partial class Raymath /// Remap input value within input range to output range [DllImport(NativeLibName, CallingConvention = CallingConvention.Cdecl)] - public static extern float Remap( - float value, - float inputStart, - float inputEnd, - float outputStart, - float outputEnd + public static extern float Remap(float value, + float inputStart, float inputEnd, + float outputStart, float outputEnd ); /// Wrap input value from min to max diff --git a/Raylib-cs/types/AudioCallback.cs b/Raylib-cs/types/AudioCallback.cs deleted file mode 100644 index 2f7b372..0000000 --- a/Raylib-cs/types/AudioCallback.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; - -namespace Raylib_cs; - -/// -/// Audio stream processor. -/// Used with Raylib.AttachAudioMixedProcessor() -/// and Raylib.DetachAudioMixedProcessor() -/// -public delegate void AudioCallback(Span buffer); diff --git a/Raylib-cs/types/AudioMixed.cs b/Raylib-cs/types/AudioMixed.cs index bf98491..1e60348 100644 --- a/Raylib-cs/types/AudioMixed.cs +++ b/Raylib-cs/types/AudioMixed.cs @@ -1,17 +1,22 @@ -using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System; namespace Raylib_cs; +/// +/// Audio stream processor. +/// Used with +/// and +/// +public delegate void AudioCallback(Span buffer); + internal static unsafe class AudioMixed { public static AudioCallback Callback = null; - [UnmanagedCallersOnly(CallConvs = new[] - { - typeof(CallConvCdecl), - })] + [UnmanagedCallersOnly(CallConvs = new Type[] + { typeof(CallConvCdecl) })] public static void Processor(void* buffer, uint frames) { // The buffer is stereo audio, so we need to double our frame count. diff --git a/Raylib-cs/types/AudioStream.cs b/Raylib-cs/types/AudioStream.cs index 454a155..2f7c024 100644 --- a/Raylib-cs/types/AudioStream.cs +++ b/Raylib-cs/types/AudioStream.cs @@ -8,9 +8,9 @@ namespace Raylib_cs; /// NOTE: Useful to create custom audio streams not bound to a specific file /// [StructLayout(LayoutKind.Sequential)] -public partial struct AudioStream +public struct AudioStream { - //TODO: convert + // TODO: convert /// /// Pointer to internal data(rAudioBuffer *) used by the audio system /// diff --git a/Raylib-cs/types/Automation.cs b/Raylib-cs/types/Automation.cs index 21b7cd6..00ddff7 100644 --- a/Raylib-cs/types/Automation.cs +++ b/Raylib-cs/types/Automation.cs @@ -31,5 +31,5 @@ public unsafe struct AutomationEventList public AutomationEvent* Events; /// - public ReadOnlySpan EventsAsSpan => new(Events, (int)Count); + public readonly ReadOnlySpan EventsAsSpan => new ReadOnlySpan(Events, (int)Count); } diff --git a/Raylib-cs/types/Camera2D.cs b/Raylib-cs/types/Camera2D.cs index f26f6e4..7902111 100644 --- a/Raylib-cs/types/Camera2D.cs +++ b/Raylib-cs/types/Camera2D.cs @@ -7,7 +7,7 @@ namespace Raylib_cs; /// Camera2D, defines position/orientation in 2d space /// [StructLayout(LayoutKind.Sequential)] -public partial struct Camera2D +public struct Camera2D { /// /// Camera offset (displacement from target) diff --git a/Raylib-cs/types/Camera3D.cs b/Raylib-cs/types/Camera3D.cs index 935f6fa..b9065d9 100644 --- a/Raylib-cs/types/Camera3D.cs +++ b/Raylib-cs/types/Camera3D.cs @@ -28,7 +28,7 @@ public enum CameraProjection /// Camera3D, defines position/orientation in 3d space /// [StructLayout(LayoutKind.Sequential)] -public partial struct Camera3D +public struct Camera3D { /// /// Camera position diff --git a/Raylib-cs/types/Color.cs b/Raylib-cs/types/Color.cs index 4ba3476..d696152 100644 --- a/Raylib-cs/types/Color.cs +++ b/Raylib-cs/types/Color.cs @@ -1,5 +1,5 @@ -using System; using System.Runtime.InteropServices; +using System; namespace Raylib_cs; @@ -7,7 +7,7 @@ namespace Raylib_cs; /// Color type, RGBA (32bit) /// [StructLayout(LayoutKind.Sequential)] -public partial struct Color +public struct Color { public byte R; public byte G; @@ -96,28 +96,133 @@ public partial struct Color /// public Color(float r, float g, float b, float a) { - // X = (byte)Math.Clamp(MathF.Round(x * 255), 0f, 255f); - this.R = (byte)((r < 0) ? 0 : ((r > 1) ? 255 : ((r * 255) + .5f))); - this.G = (byte)((g < 0) ? 0 : ((g > 1) ? 255 : ((g * 255) + .5f))); - this.B = (byte)((b < 0) ? 0 : ((b > 1) ? 255 : ((b * 255) + .5f))); - this.A = (byte)((a < 0) ? 0 : ((a > 1) ? 255 : ((a * 255) + .5f))); + this.R = (byte)(Math.Clamp(r, 0.0f, 1.0f) * 255); + this.G = (byte)(Math.Clamp(g, 0.0f, 1.0f) * 255); + this.B = (byte)(Math.Clamp(b, 0.0f, 1.0f) * 255); + this.A = (byte)(Math.Clamp(a, 0.0f, 1.0f) * 255); } /// /// . - /// Accepts 's, upscales and clamps them to the range 0..255. + /// Accepts 's, upscales and clamps them to the range 0...255. /// Then they are converted to 's by rounding. /// public Color(float r, float g, float b) { - // X = (byte)Math.Clamp(MathF.Round(x * 255), 0f, 255f); - this.R = (byte)((r < 0) ? 0 : ((r > 1) ? 255 : ((r * 255) + .5f))); - this.G = (byte)((g < 0) ? 0 : ((g > 1) ? 255 : ((g * 255) + .5f))); - this.B = (byte)((b < 0) ? 0 : ((b > 1) ? 255 : ((b * 255) + .5f))); + this.R = (byte)(Math.Clamp(r, 0.0f, 1.0f) * 255); + this.G = (byte)(Math.Clamp(g, 0.0f, 1.0f) * 255); + this.B = (byte)(Math.Clamp(b, 0.0f, 1.0f) * 255); this.A = 255; } - public override string ToString() + public readonly void GetHSV(out float h, out float s, out float v) + { + float rf = this.R / 255f; + float gf = this.G / 255f; + float bf = this.B / 255f; + + float max = MathF.Max(rf, MathF.Max(gf, bf)); + float min = MathF.Min(rf, MathF.Min(gf, bf)); + float delta = max - min; + + // Value + v = max; + + // Saturation + s = (max == 0f) ? 0f : delta / max; + + // Hue + if (delta == 0f) + { + h = 0f; + } + else if (max == rf) + { + h = 60f * (((gf - bf) / delta) % 6f); + } + else if (max == gf) + { + h = 60f * (((bf - rf) / delta) + 2f); + } + else // max == bf + { + h = 60f * (((rf - gf) / delta) + 4f); + } + + // Keep h inside 0 and 360 + if (h < 0f) + { + h += 360f; + } + } + + public static Color FromHSV(float h, float s, float v) + { + float c = v * s; + float x = c * (1f - MathF.Abs((h / 60f) % 2f - 1f)); + float m = v - c; + + float rf, gf, bf; + + if (h < 60f) + { + rf = c; + gf = x; + bf = 0; + } + else if (h < 120f) + { + rf = x; + gf = c; + bf = 0; + } + else if (h < 180f) + { + rf = 0; + gf = c; + bf = x; + } + else if (h < 240f) + { + rf = 0; + gf = x; + bf = c; + } + else if (h < 300f) + { + rf = x; + gf = 0; + bf = c; + } + else + { + rf = c; + gf = 0; + bf = x; + } + + byte r = (byte)((rf + m) * 255f + 0.5f); + byte g = (byte)((gf + m) * 255f + 0.5f); + byte b = (byte)((bf + m) * 255f + 0.5f); + return new Color(r, g, b, byte.MaxValue); + } + + public static Color Lerp(Color origin, Color target, float t) + { + byte r = LerpB(origin.R, target.R, t); + byte g = LerpB(origin.R, target.G, t); + byte b = LerpB(origin.R, target.B, t); + byte a = LerpB(origin.R, target.A, t); + return new Color(r, g, b, a); + } + + // Lerp byte + private static byte LerpB(byte a, byte b, float t) + { + return (byte)(a + (b - a) * t); + } + + public readonly override string ToString() { return $"{{R:{R} G:{G} B:{B} A:{A}}}"; } diff --git a/Raylib-cs/types/Font.cs b/Raylib-cs/types/Font.cs index 1b4ed41..0cb478f 100644 --- a/Raylib-cs/types/Font.cs +++ b/Raylib-cs/types/Font.cs @@ -59,7 +59,7 @@ public partial struct GlyphInfo /// Font, font texture and GlyphInfo array data /// [StructLayout(LayoutKind.Sequential)] -public unsafe partial struct Font +public unsafe struct Font { /// /// Base size (default chars height) diff --git a/Raylib-cs/types/Image.cs b/Raylib-cs/types/Image.cs index ab15020..b86accf 100644 --- a/Raylib-cs/types/Image.cs +++ b/Raylib-cs/types/Image.cs @@ -1,4 +1,5 @@ using System.Runtime.InteropServices; +using System.Numerics; namespace Raylib_cs; @@ -133,7 +134,7 @@ public enum PixelFormat /// Image, pixel data stored in CPU memory (RAM) /// [StructLayout(LayoutKind.Sequential)] -public unsafe partial struct Image +public unsafe struct Image { /// /// Image raw data @@ -159,4 +160,9 @@ public unsafe partial struct Image /// Data format (PixelFormat type) /// public PixelFormat Format; + + /// + /// Get width and height packed in a Vector2 + /// + public readonly Vector2 Dimensions => new Vector2(Width, Height); } diff --git a/Raylib-cs/types/Logging.cs b/Raylib-cs/types/Logging.cs index 2e1789f..3c51234 100644 --- a/Raylib-cs/types/Logging.cs +++ b/Raylib-cs/types/Logging.cs @@ -29,7 +29,7 @@ internal readonly struct Native } [StructLayout(LayoutKind.Sequential, Pack = 4)] -struct VaListLinuxX64 +internal struct VaListLinuxX64 { uint _gpOffset; uint _fpOffset; @@ -42,10 +42,10 @@ struct VaListLinuxX64 /// public static unsafe class Logging { - [UnmanagedCallersOnly(CallConvs = new[] { typeof(System.Runtime.CompilerServices.CallConvCdecl) })] + [UnmanagedCallersOnly(CallConvs = new Type[] { typeof(System.Runtime.CompilerServices.CallConvCdecl) })] public static unsafe void LogConsole(int msgType, sbyte* text, sbyte* args) { - var message = GetLogMessage(new IntPtr(text), new IntPtr(args)); + string message = GetLogMessage(new IntPtr(text), new IntPtr(args)); Console.WriteLine(message); } @@ -62,13 +62,13 @@ public static unsafe class Logging return LinuxX64LogCallback(format, args); } - var byteLength = VsnPrintf(IntPtr.Zero, UIntPtr.Zero, format, args) + 1; + int byteLength = VsnPrintf(IntPtr.Zero, UIntPtr.Zero, format, args) + 1; if (byteLength <= 1) { return string.Empty; } - var buffer = Marshal.AllocHGlobal(byteLength); + IntPtr buffer = Marshal.AllocHGlobal(byteLength); VsPrintf(buffer, format, args); string result = Marshal.PtrToStringUTF8(buffer); @@ -77,12 +77,12 @@ public static unsafe class Logging return result; } - static string AppleLogCallback(IntPtr format, IntPtr args) + private static string AppleLogCallback(IntPtr format, IntPtr args) { IntPtr buffer = IntPtr.Zero; try { - var count = Native.VasPrintfApple(ref buffer, format, args); + int count = Native.VasPrintfApple(ref buffer, format, args); if (count == -1) { return string.Empty; @@ -95,10 +95,10 @@ public static unsafe class Logging } } - static string LinuxX64LogCallback(IntPtr format, IntPtr args) + private static string LinuxX64LogCallback(IntPtr format, IntPtr args) { // The args pointer cannot be reused between two calls. We need to make a copy of the underlying structure. - var listStructure = Marshal.PtrToStructure(args); + VaListLinuxX64 listStructure = Marshal.PtrToStructure(args); IntPtr listPointer = IntPtr.Zero; int byteLength = 0; string result = ""; @@ -125,9 +125,9 @@ public static unsafe class Logging } // https://github.com/dotnet/runtime/issues/51052 - static int VsnPrintf(IntPtr buffer, UIntPtr size, IntPtr format, IntPtr args) + private static int VsnPrintf(IntPtr buffer, UIntPtr size, IntPtr format, IntPtr args) { - var os = Environment.OSVersion; + OperatingSystem os = Environment.OSVersion; if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { return Native.VsnPrintfWindows(buffer, size, format, args); @@ -144,7 +144,7 @@ public static unsafe class Logging } // https://github.com/dotnet/runtime/issues/51052 - static int VsPrintf(IntPtr buffer, IntPtr format, IntPtr args) + private static int VsPrintf(IntPtr buffer, IntPtr format, IntPtr args) { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { diff --git a/Raylib-cs/types/Material.cs b/Raylib-cs/types/Material.cs index 45de7c5..6d30e64 100644 --- a/Raylib-cs/types/Material.cs +++ b/Raylib-cs/types/Material.cs @@ -48,7 +48,7 @@ public enum MaterialMapIndex /// Material texture map /// [StructLayout(LayoutKind.Sequential)] -public partial struct MaterialMap +public struct MaterialMap { /// /// Material map texture @@ -70,14 +70,14 @@ public partial struct MaterialMap /// Material type (generic) /// [StructLayout(LayoutKind.Sequential)] -public unsafe partial struct Material +public unsafe struct Material { /// /// Material shader /// public Shader Shader; - //TODO: convert + // TODO: convert /// /// Material maps /// diff --git a/Raylib-cs/types/Mesh.cs b/Raylib-cs/types/Mesh.cs index 16733c4..926647d 100644 --- a/Raylib-cs/types/Mesh.cs +++ b/Raylib-cs/types/Mesh.cs @@ -9,7 +9,7 @@ namespace Raylib_cs; /// NOTE: Data stored in CPU memory (and GPU) /// [StructLayout(LayoutKind.Sequential)] -public unsafe partial struct Mesh +public unsafe struct Mesh { /// /// Creates a mesh ready for default vertex data allocation @@ -136,7 +136,7 @@ public unsafe partial struct Mesh /// public readonly Span TexCoordsAs() where T : unmanaged { - return new(TexCoords, 2 * VertexCount * sizeof(float) / sizeof(T)); + return new Span(TexCoords, 2 * VertexCount * sizeof(float) / sizeof(T)); } /// @@ -144,7 +144,7 @@ public unsafe partial struct Mesh /// public readonly Span TexCoords2As() where T : unmanaged { - return new(TexCoords2, 2 * VertexCount * sizeof(float) / sizeof(T)); + return new Span(TexCoords2, 2 * VertexCount * sizeof(float) / sizeof(T)); } /// @@ -152,7 +152,7 @@ public unsafe partial struct Mesh /// public readonly Span NormalsAs() where T : unmanaged { - return new(Normals, 3 * VertexCount * sizeof(float) / sizeof(T)); + return new Span(Normals, 3 * VertexCount * sizeof(float) / sizeof(T)); } /// @@ -160,7 +160,7 @@ public unsafe partial struct Mesh /// public readonly Span TangentsAs() where T : unmanaged { - return new(Tangents, 4 * VertexCount * sizeof(float) / sizeof(T)); + return new Span(Tangents, 4 * VertexCount * sizeof(float) / sizeof(T)); } /// @@ -168,7 +168,7 @@ public unsafe partial struct Mesh /// public readonly Span ColorsAs() where T : unmanaged { - return new(Colors, 4 * VertexCount * sizeof(byte) / sizeof(T)); + return new Span(Colors, 4 * VertexCount * sizeof(byte) / sizeof(T)); } /// @@ -176,7 +176,7 @@ public unsafe partial struct Mesh /// public readonly Span IndicesAs() where T : unmanaged { - return new(Indices, 3 * TriangleCount * sizeof(ushort) / sizeof(T)); + return new Span(Indices, 3 * TriangleCount * sizeof(ushort) / sizeof(T)); } #endregion diff --git a/Raylib-cs/types/Model.cs b/Raylib-cs/types/Model.cs index 6b64dd7..75fd00f 100644 --- a/Raylib-cs/types/Model.cs +++ b/Raylib-cs/types/Model.cs @@ -8,7 +8,7 @@ namespace Raylib_cs; /// Bone information /// [StructLayout(LayoutKind.Sequential)] -public unsafe partial struct BoneInfo +public unsafe struct BoneInfo { /// /// Bone name (char[32]) @@ -25,7 +25,7 @@ public unsafe partial struct BoneInfo /// Model type /// [StructLayout(LayoutKind.Sequential)] -public unsafe partial struct Model +public unsafe struct Model { /// /// Local transform matrix @@ -79,7 +79,7 @@ public unsafe partial struct Model /// Model animation /// [StructLayout(LayoutKind.Sequential)] -public unsafe partial struct ModelAnimation +public unsafe struct ModelAnimation { /// /// Number of bones @@ -97,7 +97,7 @@ public unsafe partial struct ModelAnimation public readonly BoneInfo* Bones; /// - public ReadOnlySpan BoneInfo => new(Bones, BoneCount); + public readonly ReadOnlySpan BoneInfo => new ReadOnlySpan(Bones, BoneCount); /// /// Poses array by frame (Transform **) @@ -110,9 +110,9 @@ public unsafe partial struct ModelAnimation public fixed sbyte Name[32]; /// - public FramePosesCollection FramePosesColl => new(FramePoses, FrameCount, BoneCount); + public readonly FramePosesCollection FramePosesColl => new FramePosesCollection(FramePoses, FrameCount, BoneCount); - public struct FramePosesCollection + public readonly struct FramePosesCollection { readonly Transform** _framePoses; @@ -120,9 +120,9 @@ public unsafe partial struct ModelAnimation readonly int _boneCount; - public FramePoses this[int index] => new(_framePoses[index], _boneCount); + public readonly FramePoses this[int index] => new FramePoses(_framePoses[index], _boneCount); - public Transform this[int index1, int index2] => new FramePoses(_framePoses[index1], _boneCount)[index2]; + public readonly Transform this[int index1, int index2] => new FramePoses(_framePoses[index1], _boneCount)[index2]; internal FramePosesCollection(Transform** framePoses, int frameCount, int boneCount) { @@ -133,13 +133,13 @@ public unsafe partial struct ModelAnimation } } -public unsafe struct FramePoses +public readonly unsafe struct FramePoses { readonly Transform* _poses; readonly int _count; - public ref Transform this[int index] => ref _poses[index]; + public readonly ref Transform this[int index] => ref _poses[index]; internal FramePoses(Transform* poses, int count) { diff --git a/Raylib-cs/types/Music.cs b/Raylib-cs/types/Music.cs index 91e52d3..8cc17a8 100644 --- a/Raylib-cs/types/Music.cs +++ b/Raylib-cs/types/Music.cs @@ -7,7 +7,7 @@ namespace Raylib_cs; /// NOTE: Anything longer than ~10 seconds should be streamed /// [StructLayout(LayoutKind.Sequential)] -public unsafe partial struct Music +public unsafe struct Music { /// /// Audio stream @@ -29,7 +29,7 @@ public unsafe partial struct Music /// public int CtxType; - //TODO span + // TODO span /// /// Audio context data, depends on type /// diff --git a/Raylib-cs/types/NPatchInfo.cs b/Raylib-cs/types/NPatchInfo.cs index cee694b..54efba9 100644 --- a/Raylib-cs/types/NPatchInfo.cs +++ b/Raylib-cs/types/NPatchInfo.cs @@ -27,7 +27,7 @@ public enum NPatchLayout /// N-Patch layout info /// [StructLayout(LayoutKind.Sequential)] -public partial struct NPatchInfo +public struct NPatchInfo { /// /// Texture source rectangle diff --git a/Raylib-cs/types/Ray.cs b/Raylib-cs/types/Ray.cs index 768dd6a..23b47ee 100644 --- a/Raylib-cs/types/Ray.cs +++ b/Raylib-cs/types/Ray.cs @@ -7,7 +7,7 @@ namespace Raylib_cs; /// Ray, ray for raycasting /// [StructLayout(LayoutKind.Sequential)] -public partial struct Ray +public struct Ray { /// /// Ray position (origin) @@ -30,7 +30,7 @@ public partial struct Ray /// Raycast hit information /// [StructLayout(LayoutKind.Sequential)] -public partial struct RayCollision +public struct RayCollision { /// /// Did the ray hit something? diff --git a/Raylib-cs/types/Raylib.Utils.cs b/Raylib-cs/types/Raylib.Utils.cs index 43e74bc..eb12e24 100644 --- a/Raylib-cs/types/Raylib.Utils.cs +++ b/Raylib-cs/types/Raylib.Utils.cs @@ -1,6 +1,6 @@ -using System; -using System.Numerics; using System.Runtime.InteropServices; +using System.Numerics; +using System; namespace Raylib_cs; @@ -9,14 +9,14 @@ public static unsafe partial class Raylib /// Initialize window and OpenGL context public static void InitWindow(int width, int height, string title) { - using var str1 = title.ToUtf8Buffer(); + using Utf8Buffer str1 = title.ToUtf8Buffer(); InitWindow(width, height, str1.AsPointer()); } /// Set title for window (only PLATFORM_DESKTOP) public static void SetWindowTitle(string title) { - using var str1 = title.ToUtf8Buffer(); + using Utf8Buffer str1 = title.ToUtf8Buffer(); SetWindowTitle(str1.AsPointer()); } @@ -35,94 +35,94 @@ public static unsafe partial class Raylib /// Set clipboard text content public static void SetClipboardText(string text) { - using var str1 = text.ToUtf8Buffer(); + using Utf8Buffer str1 = text.ToUtf8Buffer(); SetClipboardText(str1.AsPointer()); } /// Open URL with default system browser (if available) public static void OpenURL(string url) { - using var str1 = url.ToUtf8Buffer(); + using Utf8Buffer str1 = url.ToUtf8Buffer(); OpenURL(str1.AsPointer()); } /// Set internal gamepad mappings (SDL_GameControllerDB) public static int SetGamepadMappings(string mappings) { - using var str1 = mappings.ToUtf8Buffer(); + using Utf8Buffer str1 = mappings.ToUtf8Buffer(); return SetGamepadMappings(str1.AsPointer()); } /// Load shader from files and bind default locations public static Shader LoadShader(string vsFileName, string fsFileName) { - using var str1 = vsFileName.ToAnsiBuffer(); - using var str2 = fsFileName.ToAnsiBuffer(); + using AnsiBuffer str1 = vsFileName.ToAnsiBuffer(); + using AnsiBuffer str2 = fsFileName.ToAnsiBuffer(); return LoadShader(str1.AsPointer(), str2.AsPointer()); } /// Load shader from code string and bind default locations public static Shader LoadShaderFromMemory(string vsCode, string fsCode) { - using var str1 = vsCode.ToUtf8Buffer(); - using var str2 = fsCode.ToUtf8Buffer(); + using Utf8Buffer str1 = vsCode.ToUtf8Buffer(); + using Utf8Buffer str2 = fsCode.ToUtf8Buffer(); return LoadShaderFromMemory(str1.AsPointer(), str2.AsPointer()); } /// Get shader uniform location public static int GetShaderLocation(Shader shader, string uniformName) { - using var str1 = uniformName.ToUtf8Buffer(); + using Utf8Buffer str1 = uniformName.ToUtf8Buffer(); return GetShaderLocation(shader, str1.AsPointer()); } /// Get shader attribute location public static int GetShaderLocationAttrib(Shader shader, string attribName) { - using var str1 = attribName.ToUtf8Buffer(); + using Utf8Buffer str1 = attribName.ToUtf8Buffer(); return GetShaderLocationAttrib(shader, str1.AsPointer()); } /// Takes a screenshot of current screen (saved a .png) public static void TakeScreenshot(string fileName) { - using var str1 = fileName.ToAnsiBuffer(); + using AnsiBuffer str1 = fileName.ToAnsiBuffer(); TakeScreenshot(str1.AsPointer()); } /// Check file extension public static CBool IsFileExtension(string fileName, string ext) { - using var str1 = fileName.ToAnsiBuffer(); - using var str2 = ext.ToAnsiBuffer(); + using AnsiBuffer str1 = fileName.ToAnsiBuffer(); + using AnsiBuffer str2 = ext.ToAnsiBuffer(); return IsFileExtension(str1.AsPointer(), str2.AsPointer()); } /// Get file modification time (last write time) public static long GetFileModTime(string fileName) { - using var str1 = fileName.ToAnsiBuffer(); + using AnsiBuffer str1 = fileName.ToAnsiBuffer(); return GetFileModTime(str1.AsPointer()); } /// Load image from file into CPU memory (RAM) public static Image LoadImage(string fileName) { - using var str1 = fileName.ToAnsiBuffer(); + using AnsiBuffer str1 = fileName.ToAnsiBuffer(); return LoadImage(str1.AsPointer()); } /// Load image from RAW file data public static Image LoadImageRaw(string fileName, int width, int height, PixelFormat format, int headerSize) { - using var str1 = fileName.ToAnsiBuffer(); + using AnsiBuffer str1 = fileName.ToAnsiBuffer(); return LoadImageRaw(str1.AsPointer(), width, height, format, headerSize); } /// Load image sequence from file (frames appended to image.data) public static Image LoadImageAnim(string fileName, out int frames) { - using var str1 = fileName.ToAnsiBuffer(); + using AnsiBuffer str1 = fileName.ToAnsiBuffer(); fixed (int* p = &frames) { return LoadImageAnim(str1.AsPointer(), p); @@ -134,7 +134,7 @@ public static unsafe partial class Raylib /// public static Image LoadImageFromMemory(string fileType, byte[] fileData) { - using var fileTypeNative = fileType.ToAnsiBuffer(); + using AnsiBuffer fileTypeNative = fileType.ToAnsiBuffer(); fixed (byte* fileDataNative = fileData) { Image image = LoadImageFromMemory(fileTypeNative.AsPointer(), fileDataNative, fileData.Length); @@ -145,21 +145,21 @@ public static unsafe partial class Raylib /// Export image data to file public static CBool ExportImage(Image image, string fileName) { - using var str1 = fileName.ToAnsiBuffer(); + using AnsiBuffer str1 = fileName.ToAnsiBuffer(); return ExportImage(image, str1.AsPointer()); } /// Export image as code file defining an array of bytes public static CBool ExportImageAsCode(Image image, string fileName) { - using var str1 = fileName.ToAnsiBuffer(); + using AnsiBuffer str1 = fileName.ToAnsiBuffer(); return ExportImageAsCode(image, str1.AsPointer()); } /// Show trace log messages (LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR) public static void TraceLog(TraceLogLevel logLevel, string text) { - using var str1 = text.ToUtf8Buffer(); + using Utf8Buffer str1 = text.ToUtf8Buffer(); TraceLog(logLevel, str1.AsPointer()); } @@ -228,25 +228,71 @@ public static unsafe partial class Raylib return (T*)MemAlloc(count * (uint)sizeof(T)); } + /// Save data to file from an unmanaged type + /// True if the operation was successfully + public static CBool SaveFileData(T data, string fileName) where T : unmanaged + { + using AnsiBuffer ansiBuffer = fileName.ToAnsiBuffer(); + return SaveFileData(ansiBuffer.AsPointer(), &data, sizeof(T)); + } + + /// Save data to file from an unmanaged type + /// True if the operation was successfully + public static CBool SaveFileData(T[] data, string fileName) where T : unmanaged + { + if (data == null || data.Length == 0) + { + return false; + } + fixed (T* ptr = data) + { + using AnsiBuffer ansiBuffer = fileName.ToAnsiBuffer(); + return SaveFileData(ansiBuffer.AsPointer(), ptr, sizeof(T) * data.Length); + } + } + /// Load file data as byte array (read) public static byte* LoadFileData(string fileName, ref int bytesRead) { - using var str1 = fileName.ToAnsiBuffer(); + using AnsiBuffer str1 = fileName.ToAnsiBuffer(); fixed (int* p = &bytesRead) { return LoadFileData(str1.AsPointer(), p); } } + public static byte[] LoadFileData(string fileName) + { + int length = 0; + byte* data = LoadFileData(fileName, ref length); + byte[] arr = new byte[length]; + Marshal.Copy((IntPtr)data, arr, 0, length); + UnloadFileData(data); + return arr; + } + + /// + /// Load file data as an array of unmanaged types + /// + public static T[] LoadFileData(string fileName) where T : unmanaged + { + int length = 0; + byte* data = LoadFileData(fileName, ref length); + Span values = new Span(data, length / sizeof(T)); + T[] arr = values.ToArray(); + UnloadFileData(data); + return arr; + } + /// Get dropped files names (memory should be freed) public static string[] GetDroppedFiles() { - var filePathList = LoadDroppedFiles(); - var files = new string[filePathList.Count]; + FilePathList filePathList = LoadDroppedFiles(); + string[] files = new string[filePathList.Count]; - for (var i = 0; i < filePathList.Count; i++) + for (uint i = 0; i < filePathList.Count; i++) { - files[i] = Marshal.PtrToStringUTF8((IntPtr)filePathList.Paths[i]); + files[i] = filePathList[i]; } UnloadDroppedFiles(filePathList); @@ -426,21 +472,21 @@ public static unsafe partial class Raylib /// Generate image: grayscale image from text data public static Image GenImageText(int width, int height, string text) { - using var str1 = text.ToUtf8Buffer(); + using Utf8Buffer str1 = text.ToUtf8Buffer(); return GenImageText(width, height, str1.AsPointer()); } /// Create an image from text (default font) public static Image ImageText(string text, int fontSize, Color color) { - using var str1 = text.ToUtf8Buffer(); + using Utf8Buffer str1 = text.ToUtf8Buffer(); return ImageText(str1.AsPointer(), fontSize, color); } /// Create an image from text (custom sprite font) public static Image ImageTextEx(Font font, string text, float fontSize, float spacing, Color tint) { - using var str1 = text.ToUtf8Buffer(); + using Utf8Buffer str1 = text.ToUtf8Buffer(); return ImageTextEx(font, str1.AsPointer(), fontSize, spacing, tint); } @@ -749,6 +795,22 @@ public static unsafe partial class Raylib } } + public static void ImageDrawCircleLines(ref Image dst, int centerX, int centerY, int radius, Color color) + { + fixed (Image* p = &dst) + { + ImageDrawCircleLines(p, centerX, centerY, radius, color); + } + } + + public static void ImageDrawCircleLinesV(ref Image dst, Vector2 center, int radius, Color color) + { + fixed (Image* p = &dst) + { + ImageDrawCircleLinesV(p, center, radius, color); + } + } + /// Draw circle within an image (Vector version) public static void ImageDrawCircleV(ref Image dst, Vector2 center, int radius, Color color) { @@ -857,7 +919,7 @@ public static unsafe partial class Raylib /// Draw text (using default font) within an image (destination) public static void ImageDrawText(ref Image dst, string text, int x, int y, int fontSize, Color color) { - using var str1 = text.ToUtf8Buffer(); + using Utf8Buffer str1 = text.ToUtf8Buffer(); fixed (Image* p = &dst) { ImageDrawText(p, str1.AsPointer(), x, y, fontSize, color); @@ -875,7 +937,7 @@ public static unsafe partial class Raylib Color color ) { - using var str1 = text.ToUtf8Buffer(); + using Utf8Buffer str1 = text.ToUtf8Buffer(); fixed (Image* p = &dst) { ImageDrawTextEx(p, font, str1.AsPointer(), position, fontSize, spacing, color); @@ -885,7 +947,7 @@ public static unsafe partial class Raylib /// Load texture from file into GPU memory (VRAM) public static Texture2D LoadTexture(string fileName) { - using var str1 = fileName.ToAnsiBuffer(); + using AnsiBuffer str1 = fileName.ToAnsiBuffer(); return LoadTexture(str1.AsPointer()); } @@ -931,7 +993,7 @@ public static unsafe partial class Raylib /// Load font from file into GPU memory (VRAM) public static Font LoadFont(string fileName) { - using var str1 = fileName.ToAnsiBuffer(); + using AnsiBuffer str1 = fileName.ToAnsiBuffer(); return LoadFont(str1.AsPointer()); } @@ -941,7 +1003,7 @@ public static unsafe partial class Raylib /// public static Font LoadFontEx(string fileName, int fontSize, int[] codepoints, int codepointCount) { - using var str1 = fileName.ToAnsiBuffer(); + using AnsiBuffer str1 = fileName.ToAnsiBuffer(); fixed (int* p = codepoints) { return LoadFontEx(str1.AsPointer(), fontSize, p, codepointCount); @@ -959,7 +1021,7 @@ public static unsafe partial class Raylib int codepointCount ) { - using var fileTypeNative = fileType.ToAnsiBuffer(); + using AnsiBuffer fileTypeNative = fileType.ToAnsiBuffer(); fixed (byte* fileDataNative = fileData) { fixed (int* fontCharsNative = codepoints) @@ -972,7 +1034,6 @@ public static unsafe partial class Raylib fontCharsNative, codepointCount ); - return font; } } @@ -1017,7 +1078,7 @@ public static unsafe partial class Raylib /// Load model animations from file public static ModelAnimation* LoadModelAnimations(string fileName, ref int animCount) { - using var str1 = fileName.ToAnsiBuffer(); + using AnsiBuffer str1 = fileName.ToAnsiBuffer(); fixed (int* p = &animCount) { return LoadModelAnimations(str1.AsPointer(), p); @@ -1126,21 +1187,14 @@ public static unsafe partial class Raylib /// Draw text (using default font) public static void DrawText(string text, int posX, int posY, int fontSize, Color color) { - using var str1 = text.ToUtf8Buffer(); + using Utf8Buffer str1 = text.ToUtf8Buffer(); DrawText(str1.AsPointer(), posX, posY, fontSize, color); } /// Draw text using font and additional parameters - public static void DrawTextEx( - Font font, - string text, - Vector2 position, - float fontSize, - float spacing, - Color tint - ) + public static void DrawTextEx(Font font, string text, Vector2 position, float fontSize, float spacing, Color tint) { - using var str1 = text.ToUtf8Buffer(); + using Utf8Buffer str1 = text.ToUtf8Buffer(); DrawTextEx(font, str1.AsPointer(), position, fontSize, spacing, tint); } @@ -1156,32 +1210,32 @@ public static unsafe partial class Raylib Color tint ) { - using var str1 = text.ToUtf8Buffer(); + using Utf8Buffer str1 = text.ToUtf8Buffer(); DrawTextPro(font, str1.AsPointer(), position, origin, rotation, fontSize, spacing, tint); } /// Measure string width for default font public static int MeasureText(string text, int fontSize) { - using var str1 = text.ToUtf8Buffer(); + using Utf8Buffer str1 = text.ToUtf8Buffer(); return MeasureText(str1.AsPointer(), fontSize); } /// Measure string size for Font public static Vector2 MeasureTextEx(Font font, string text, float fontSize, float spacing) { - using var str1 = text.ToUtf8Buffer(); + using Utf8Buffer str1 = text.ToUtf8Buffer(); return MeasureTextEx(font, str1.AsPointer(), fontSize, spacing); } /// Get all codepoints in a string, codepoints count returned by parameters public static int[] LoadCodepoints(string text, ref int count) { - using var str1 = text.ToUtf8Buffer(); + using Utf8Buffer str1 = text.ToUtf8Buffer(); fixed (int* c = &count) { - var pointsPtr = LoadCodepoints(str1.AsPointer(), c); - var codepoints = new ReadOnlySpan(pointsPtr, count).ToArray(); + int* pointsPtr = LoadCodepoints(str1.AsPointer(), c); + int[] codepoints = new ReadOnlySpan(pointsPtr, count).ToArray(); UnloadCodepoints(pointsPtr); return codepoints; } @@ -1190,14 +1244,14 @@ public static unsafe partial class Raylib /// Get total number of codepoints in a UTF8 encoded string public static int GetCodepointCount(string text) { - using var str1 = text.ToUtf8Buffer(); + using Utf8Buffer str1 = text.ToUtf8Buffer(); return GetCodepointCount(str1.AsPointer()); } /// Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure public static int GetCodepoint(string text, ref int codepointSize) { - using var str1 = text.ToUtf8Buffer(); + using Utf8Buffer str1 = text.ToUtf8Buffer(); fixed (int* p = &codepointSize) { return GetCodepoint(str1.AsPointer(), p); @@ -1209,7 +1263,7 @@ public static unsafe partial class Raylib { fixed (int* l1 = &utf8Size) { - var ptr = CodepointToUTF8(codepoint, l1); + sbyte* ptr = CodepointToUTF8(codepoint, l1); return Utf8StringUtils.GetUTF8String(ptr); } } @@ -1219,8 +1273,8 @@ public static unsafe partial class Raylib { fixed (int* c1 = codepoints) { - var ptr = LoadUTF8(c1, length); - var text = Utf8StringUtils.GetUTF8String(ptr); + sbyte* ptr = LoadUTF8(c1, length); + string text = Utf8StringUtils.GetUTF8String(ptr); MemFree(ptr); return text; } @@ -1229,21 +1283,21 @@ public static unsafe partial class Raylib /// Draw a model (with texture if set) public static Model LoadModel(string fileName) { - using var str1 = fileName.ToAnsiBuffer(); + using AnsiBuffer str1 = fileName.ToAnsiBuffer(); return LoadModel(str1.AsPointer()); } /// Export mesh data to file, returns true on success public static CBool ExportMesh(Mesh mesh, string fileName) { - using var str1 = fileName.ToAnsiBuffer(); + using AnsiBuffer str1 = fileName.ToAnsiBuffer(); return ExportMesh(mesh, str1.AsPointer()); } /// Export mesh as code file (.h) defining multiple arrays of vertex attributes public static CBool ExportMeshAsCode(Mesh mesh, string fileName) { - using var str1 = fileName.ToAnsiBuffer(); + using AnsiBuffer str1 = fileName.ToAnsiBuffer(); return ExportMeshAsCode(mesh, str1.AsPointer()); } @@ -1268,19 +1322,16 @@ public static unsafe partial class Raylib /// Load wave data from file public static Wave LoadWave(string fileName) { - using var str1 = fileName.ToAnsiBuffer(); + using AnsiBuffer str1 = fileName.ToAnsiBuffer(); return LoadWave(str1.AsPointer()); } /// /// Load wave from managed memory, fileType refers to extension: i.e. ".wav" /// - public static Wave LoadWaveFromMemory( - string fileType, - byte[] fileData - ) + public static Wave LoadWaveFromMemory(string fileType, byte[] fileData) { - using var fileTypeNative = fileType.ToAnsiBuffer(); + using AnsiBuffer fileTypeNative = fileType.ToAnsiBuffer(); fixed (byte* fileDataNative = fileData) { @@ -1297,40 +1348,37 @@ public static unsafe partial class Raylib /// Load sound from file public static Sound LoadSound(string fileName) { - using var str1 = fileName.ToAnsiBuffer(); + using AnsiBuffer str1 = fileName.ToAnsiBuffer(); return LoadSound(str1.AsPointer()); } /// Export wave data to file public static CBool ExportWave(Wave wave, string fileName) { - using var str1 = fileName.ToAnsiBuffer(); + using AnsiBuffer str1 = fileName.ToAnsiBuffer(); return ExportWave(wave, str1.AsPointer()); } /// Export wave sample data to code (.h) public static CBool ExportWaveAsCode(Wave wave, string fileName) { - using var str1 = fileName.ToAnsiBuffer(); + using AnsiBuffer str1 = fileName.ToAnsiBuffer(); return ExportWaveAsCode(wave, str1.AsPointer()); } /// Load music stream from file public static Music LoadMusicStream(string fileName) { - using var str1 = fileName.ToAnsiBuffer(); + using AnsiBuffer str1 = fileName.ToAnsiBuffer(); return LoadMusicStream(str1.AsPointer()); } /// /// Load music stream from managed memory, fileType refers to extension: i.e. ".wav" /// - public static Music LoadMusicStreamFromMemory( - string fileType, - byte[] fileData - ) + public static Music LoadMusicStreamFromMemory(string fileType, byte[] fileData) { - using var fileTypeNative = fileType.ToAnsiBuffer(); + using AnsiBuffer fileTypeNative = fileType.ToAnsiBuffer(); fixed (byte* fileDataNative = fileData) { @@ -1408,14 +1456,14 @@ public static unsafe partial class Raylib /// Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS public static AutomationEventList LoadAutomationEventList(string fileName) { - using var str1 = fileName.ToUtf8Buffer(); + using Utf8Buffer str1 = fileName.ToUtf8Buffer(); return LoadAutomationEventList(str1.AsPointer()); } /// Export automation events list as text file public static CBool ExportAutomationEventList(AutomationEventList list, string fileName) { - using var str1 = fileName.ToUtf8Buffer(); + using Utf8Buffer str1 = fileName.ToUtf8Buffer(); return ExportAutomationEventList(list, str1.AsPointer()); } @@ -1427,4 +1475,98 @@ public static unsafe partial class Raylib SetAutomationEventList(p); } } + + public static int MakeDirectory(string path) + { + using AnsiBuffer pathBuffer = path.ToAnsiBuffer(); + return MakeDirectory(pathBuffer.AsPointer()); + } + + public static string GetApplicationDirectoryString() + { + return new string(GetApplicationDirectory()); + } + + public static string GetWorkingDirectoryString() + { + return new string(GetWorkingDirectory()); + } + + /// + /// Load a sequence of random numbers, store them and return them but not before unloading them. + /// + /// Amount of random numbers to load + /// Minimum random value + /// Maximum random value + /// An array filled with the random numbers + public static int[] GetRandomSequence(uint count, int min, int max) + { + int temp = min; + min = Math.Min(min, max); + max = Math.Max(temp, max); + int* sequence = LoadRandomSequence(count, min, max); + int[] output = new int[count]; + //Marshal.Copy((IntPtr)sequence, output, 0, count); + for (uint i = 0; i < count; i++) + { + output[i] = sequence[i]; + } + UnloadRandomSequence(sequence); + return output; + } + + /// + /// Load a sequence of random numbers, store them and return them but not before unloading them. + /// + /// Amount of random numbers to load + /// Minimum random value + /// Maximum random value + /// An array filled with the random numbers + public static float[] GetRandomSequence(uint count, float min, float max) + { + float temp = min; + min = Math.Min(min, max); + max = Math.Max(temp, max); + const int maxi = 100000; + int* sequence = LoadRandomSequence(count, 0, maxi); + float[] output = new float[count]; + for (uint i = 0; i < count; i++) + { + int val = sequence[i]; + float norm = (float)val / (float)maxi; + output[i] = Raymath.Lerp(min, max, norm); + } + return output; + } + + /// + /// Create a file in the specified path to save the specified text + /// + public static void SaveFileText(string fileName, string text) + { + using AnsiBuffer fileBuffer = fileName.ToAnsiBuffer(); + using AnsiBuffer textBuffer = text.ToAnsiBuffer(); + SaveFileText(fileBuffer.AsPointer(), textBuffer.AsPointer()); + } + + /// + /// Loads text from a file, reads it, saves it, unloads the file, and returns the loaded text. + /// + /// The text content of the file on the given path + public static string LoadFileText(string fileName) + { + using AnsiBuffer nameBuffer = fileName.ToAnsiBuffer(); + sbyte* data = LoadFileText(nameBuffer.AsPointer()); + string text = new string(data); + UnloadFileText(data); + return text; + } + + public static Vector2 GetScreenCenter() + { + Vector2 center = new Vector2(); + center.X = GetScreenWidth() / 2.0f; + center.Y = GetScreenHeight() / 2.0f; + return center; + } } diff --git a/Raylib-cs/types/Raymath.Utils.cs b/Raylib-cs/types/Raymath.Utils.cs new file mode 100644 index 0000000..35b734d --- /dev/null +++ b/Raylib-cs/types/Raymath.Utils.cs @@ -0,0 +1,98 @@ +using System; + +namespace Raylib_cs; + +public static partial class Raymath +{ + public static float Clamp01(float value) => Clamp(value, 0.0f, 1.0f); + + /// + /// Loops the value, so that it is never larger than length and never smaller than 0 + /// + public static float Repeat(float value, float length) + { + return Clamp(value - MathF.Floor(value / length) * length, 0f, length); + } + + /// + /// Same as Lerp but makes sure the values interpolate correctly when they wrap around + /// 360 degrees. + /// + /// The start angle. A float expressed in degrees. + /// The end angle. A float expressed in degrees. + /// The interpolation value between the start and end angles. + /// This value is clamped to the range [0, 1]. + /// Returns the interpolated float result between angle a and angle b, + /// based on the interpolation value t. + public static float LerpAngle(float a, float b, float t) + { + float num = Repeat(b - a, 360f); + if (num > 180f) + { + num -= 360f; + } + + return a + num * Clamp01(t); + } + + public static int Sign(float value) => MathF.Sign(value); + + /// + /// Returns a value that increments and decrements between zero and the + /// length. It follows the triangle wave formula where the bottom is set to zero + /// and the peak is set to length. + /// + public static float PingPong(float t, float length) + { + t = Repeat(t, length * 2f); + return length - MathF.Abs(t - length); + } + + /// + /// Moves a value current towards target. + /// + /// The current value. + /// The value to move towards. + /// The maximum change applied to the current value. + public static float MoveTowards(float current, float target, float maxDelta) + { + if (MathF.Abs(target - current) <= maxDelta) + { + return target; + } + + return current + Sign(target - current) * maxDelta; + } + + /// + /// Calculates the shortest difference between two angles. + /// + /// The current angle in degrees. + /// The target angle in degrees. + /// A value between -179 and 180, in degrees. + public static float DeltaAngle(float current, float target) + { + float num = Repeat(target - current, 360f); + if (num > 180f) + { + num -= 360f; + } + + return num; + } + + /// + /// Same as MoveTowards but makes sure the values interpolate correctly when they wrap around 360 degrees. + /// + public static float MoveTowardsAngle(float current, float target, float maxDelta) + { + float num = DeltaAngle(current, target); + if (0f - maxDelta < num && num < maxDelta) + { + return target; + } + + target = current + num; + return MoveTowards(current, target, maxDelta); + } +} diff --git a/Raylib-cs/types/Rectangle.cs b/Raylib-cs/types/Rectangle.cs index c870bcf..d78275b 100644 --- a/Raylib-cs/types/Rectangle.cs +++ b/Raylib-cs/types/Rectangle.cs @@ -7,7 +7,7 @@ namespace Raylib_cs; /// Rectangle type /// [StructLayout(LayoutKind.Sequential)] -public partial struct Rectangle +public struct Rectangle { public float X; public float Y; @@ -72,7 +72,42 @@ public partial struct Rectangle } } - public override string ToString() + public readonly Vector2 Center + { + get + { + Vector2 center = new Vector2(); + center.X = X + (Width / 2.0f); + center.Y = Y + (Height / 2.0f); + return center; + } + } + + public readonly void GetIntegerValues(out int x, out int y, out int width, out int height) + { + x = (int)this.X; + y = (int)this.Y; + width = (int)this.Width; + height = (int)this.Height; + } + + public void Grow(float growth) + { + X -= growth; + Y -= growth; + Width += growth * 2.0f; + Height += growth * 2.0f; + } + + public void Shrink(float shrink) + { + X += shrink; + Y += shrink; + Width -= shrink * 2.0f; + Height -= shrink * 2.0f; + } + + public readonly override string ToString() { return $"{{X:{X} Y:{Y} Width:{Width} Height:{Height}}}"; } diff --git a/Raylib-cs/types/RenderBatch.cs b/Raylib-cs/types/RenderBatch.cs index cfc1615..18cd57a 100644 --- a/Raylib-cs/types/RenderBatch.cs +++ b/Raylib-cs/types/RenderBatch.cs @@ -7,7 +7,7 @@ namespace Raylib_cs; /// RenderBatch type /// [StructLayout(LayoutKind.Sequential)] -public unsafe partial struct RenderBatch +public unsafe struct RenderBatch { /// /// Number of vertex buffers (multi-buffering support) @@ -44,7 +44,7 @@ public unsafe partial struct RenderBatch /// Dynamic vertex buffers (position + texcoords + colors + indices arrays) /// [StructLayout(LayoutKind.Sequential)] -public unsafe partial struct VertexBuffer +public unsafe struct VertexBuffer { /// /// Number of elements in the buffer (QUADS) diff --git a/Raylib-cs/types/RenderTexture2D.cs b/Raylib-cs/types/RenderTexture2D.cs index 65d7849..ccbb23d 100644 --- a/Raylib-cs/types/RenderTexture2D.cs +++ b/Raylib-cs/types/RenderTexture2D.cs @@ -6,7 +6,7 @@ namespace Raylib_cs; /// RenderTexture2D type, for texture rendering /// [StructLayout(LayoutKind.Sequential)] -public partial struct RenderTexture2D +public struct RenderTexture2D { /// /// OpenGL Framebuffer Object (FBO) id diff --git a/Raylib-cs/types/Shader.cs b/Raylib-cs/types/Shader.cs index eb32614..892e18a 100644 --- a/Raylib-cs/types/Shader.cs +++ b/Raylib-cs/types/Shader.cs @@ -76,7 +76,7 @@ public enum ShaderUniformDataType /// Shader type (generic) /// [StructLayout(LayoutKind.Sequential)] -public unsafe partial struct Shader +public unsafe struct Shader { /// /// Shader program id diff --git a/Raylib-cs/types/Sound.cs b/Raylib-cs/types/Sound.cs index b537fc1..6bf3b9a 100644 --- a/Raylib-cs/types/Sound.cs +++ b/Raylib-cs/types/Sound.cs @@ -6,7 +6,7 @@ namespace Raylib_cs; /// Sound source type /// [StructLayout(LayoutKind.Sequential)] -public partial struct Sound +public struct Sound { /// /// Audio stream diff --git a/Raylib-cs/types/Texture2D.cs b/Raylib-cs/types/Texture2D.cs index e1b5316..65e3d2f 100644 --- a/Raylib-cs/types/Texture2D.cs +++ b/Raylib-cs/types/Texture2D.cs @@ -1,4 +1,5 @@ using System.Runtime.InteropServices; +using System.Numerics; namespace Raylib_cs; @@ -102,7 +103,7 @@ public enum CubemapLayout /// NOTE: Data stored in GPU memory /// [StructLayout(LayoutKind.Sequential)] -public partial struct Texture2D +public struct Texture2D { /// /// OpenGL texture id @@ -128,4 +129,9 @@ public partial struct Texture2D /// Data format (PixelFormat type) /// public PixelFormat Format; + + /// + /// Get width and height packed in a Vector2 + /// + public readonly Vector2 Dimensions => new Vector2(Width, Height); } diff --git a/Raylib-cs/types/Transform.cs b/Raylib-cs/types/Transform.cs index 2ccaace..10b15ab 100644 --- a/Raylib-cs/types/Transform.cs +++ b/Raylib-cs/types/Transform.cs @@ -7,7 +7,7 @@ namespace Raylib_cs; /// Transform, vertex transformation data /// [StructLayout(LayoutKind.Sequential)] -public partial struct Transform +public struct Transform { /// /// Translation @@ -23,4 +23,14 @@ public partial struct Transform /// Scale /// public Vector3 Scale; + + public void TranslateLocal(Vector3 translation) + { + Translation += Vector3.Transform(translation, Rotation); + } + + public void TranslateGlobal(Vector3 translation) + { + Translation += translation; + } } diff --git a/Raylib-cs/types/Wave.cs b/Raylib-cs/types/Wave.cs index adcd390..ddcd75c 100644 --- a/Raylib-cs/types/Wave.cs +++ b/Raylib-cs/types/Wave.cs @@ -6,7 +6,7 @@ namespace Raylib_cs; /// Wave type, defines audio wave data /// [StructLayout(LayoutKind.Sequential)] -public unsafe partial struct Wave +public unsafe struct Wave { /// /// Number of samples @@ -28,7 +28,7 @@ public unsafe partial struct Wave /// public uint Channels; - //TODO: SPAN ? + // TODO: SPAN? /// /// Buffer data pointer /// diff --git a/Raylib-cs/types/native/AnsiBuffer.cs b/Raylib-cs/types/native/AnsiBuffer.cs index e730bc2..00bbc63 100644 --- a/Raylib-cs/types/native/AnsiBuffer.cs +++ b/Raylib-cs/types/native/AnsiBuffer.cs @@ -1,5 +1,5 @@ -using System; using System.Runtime.InteropServices; +using System; namespace Raylib_cs; diff --git a/Raylib-cs/types/native/CBool.cs b/Raylib-cs/types/native/CBool.cs index 93e9408..cd7ec2b 100644 --- a/Raylib-cs/types/native/CBool.cs +++ b/Raylib-cs/types/native/CBool.cs @@ -1,4 +1,3 @@ -using System; using System.Runtime.InteropServices; namespace Raylib_cs; @@ -13,8 +12,8 @@ public readonly struct CBool * which can be later implicitely cast onto any type during usage. * * It is wise to note that C booleans are any numeric value, but allocating an - * Int64 for every CBool instance is.. well, wildly memory-inefficient. Yes, the - * process is basically treated as a 0-cost instantiation, but it's better to rely + * Int64 (long) for every CBool instance is.. well, wildly memory-inefficient. Yes, + * the process is basically treated as a 0-cost instantiation, but it's better to rely * on explicit motivation than to blindly trust the runtime judgement on its memory * management. * @@ -30,7 +29,7 @@ public readonly struct CBool { this.Value = (sbyte)(value ? 1 : 0); } - public CBool(Int64 value) + public CBool(long value) { this.Value = (sbyte)(value != 0 ? 1 : 0); } @@ -45,20 +44,20 @@ public readonly struct CBool // Allows for CBools to be implicitely assigned to a native boolean variable. public static implicit operator bool(CBool x) { - return x.Value != 0 ? true : false; + return x.Value != 0; } // Native -> CBool // Allows native booleans to be implicitely constructed into CBools while passing parameters. public static implicit operator CBool(bool x) { - return new CBool { Value = (sbyte)(x ? 1 : 0) }; + return new CBool(x); } // Same goes for integer numeric values (any value, so an Int64 is used). - public static implicit operator CBool(Int64 x) + public static implicit operator CBool(long x) { - return new CBool { Value = (sbyte)(x != 0 ? 1 : 0) }; + return new CBool(x); } /* Arithmetic overloads diff --git a/Raylib-cs/types/native/FilePathList.cs b/Raylib-cs/types/native/FilePathList.cs index b75dc1c..9c50a3b 100644 --- a/Raylib-cs/types/native/FilePathList.cs +++ b/Raylib-cs/types/native/FilePathList.cs @@ -22,4 +22,19 @@ public unsafe struct FilePathList /// Filepaths entries /// public byte** Paths; + + public string this[uint i] + { + get + { + if (i >= 0 && i < Count) + { + return Marshal.PtrToStringUTF8((System.IntPtr)Paths[i]); + } + else + { + throw new System.IndexOutOfRangeException(); + } + } + } } diff --git a/Raylib-cs/types/native/Utf8Buffer.cs b/Raylib-cs/types/native/Utf8Buffer.cs index f77bff7..3acb824 100644 --- a/Raylib-cs/types/native/Utf8Buffer.cs +++ b/Raylib-cs/types/native/Utf8Buffer.cs @@ -41,10 +41,10 @@ public static class Utf8StringUtils return null; } - var length = Encoding.UTF8.GetByteCount(text); + int length = Encoding.UTF8.GetByteCount(text); - var byteArray = new byte[length + 1]; - var wrote = Encoding.UTF8.GetBytes(text, 0, text.Length, byteArray, 0); + byte[] byteArray = new byte[length + 1]; + int wrote = Encoding.UTF8.GetBytes(text, 0, text.Length, byteArray, 0); byteArray[wrote] = 0; return byteArray;