From 667a1a25efe487ec705e777af7bdf2ab270fb4ec Mon Sep 17 00:00:00 2001 From: Meatcorps Date: Thu, 21 May 2026 09:11:11 +0200 Subject: [PATCH] Fixing the QOL utils --- Raylib-cs/interop/Raylib.cs | 4 +- Raylib-cs/types/Model.cs | 36 +++- Raylib-cs/types/Raylib.Utils.cs | 348 ++++++++++++++++++++++++++++++-- 3 files changed, 370 insertions(+), 18 deletions(-) diff --git a/Raylib-cs/interop/Raylib.cs b/Raylib-cs/interop/Raylib.cs index 1ad4343..6268319 100644 --- a/Raylib-cs/interop/Raylib.cs +++ b/Raylib-cs/interop/Raylib.cs @@ -987,7 +987,7 @@ public static unsafe partial class Raylib /// Decode Base64 string data, memory must be MemFree() [LibraryImport(NativeLibName)] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - public static partial byte* DecodeDataBase64(byte* data, int* outputSize); + public static partial byte* DecodeDataBase64(sbyte* data, int* outputSize); /// Compute CRC32 hash code [LibraryImport(NativeLibName)] @@ -1886,7 +1886,7 @@ public static unsafe partial class Raylib /// Load image sequence from memory buffer [LibraryImport(NativeLibName)] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - public static partial Image LoadImageAnimFromMemory(sbyte* fileName, sbyte* fileData, int dataSize, int* frames); + public static partial Image LoadImageAnimFromMemory(sbyte* fileType, byte* fileData, int dataSize, int* frames); /// Load image from memory buffer, fileType refers to extension: i.e. ".png" [LibraryImport(NativeLibName)] diff --git a/Raylib-cs/types/Model.cs b/Raylib-cs/types/Model.cs index 16bac95..e6548b4 100644 --- a/Raylib-cs/types/Model.cs +++ b/Raylib-cs/types/Model.cs @@ -57,6 +57,12 @@ public unsafe struct ModelSkeleton public Span BonesAsSpan() { + + if (Bones == null || BoneCount <= 0) + { + return Span.Empty; + } + return new Span(Bones, BoneCount); } } @@ -104,7 +110,7 @@ public unsafe struct Model /// /// Skeleton for animation /// - ModelSkeleton Skeleton; + public ModelSkeleton Skeleton; /// /// Current animation pose (Transform[]) @@ -128,11 +134,21 @@ public unsafe struct Model public Span MeshMaterialAsSpan() { + if (MeshMaterial == null || MeshCount <= 0) + { + return Span.Empty; + } + return new Span(MeshMaterial, MeshCount); } public Span MeshesAsSpan() { + if (Meshes == null || MeshCount <= 0) + { + return Span.Empty; + } + return new Span(Meshes, MeshCount); } } @@ -161,11 +177,23 @@ public unsafe struct ModelAnimation /// /// Animation sequence keyframe poses [keyframe][pose] /// - public Transform* KeyframePoses; + public Transform** KeyframePoses; - public Span KeyFramePosesAsSpan() + public Span GetKeyFramePoseAsSpan(int frame) { - return new Span(KeyframePoses, KeyFrameCount); + if (KeyframePoses == null || frame < 0 || frame >= KeyFrameCount) + { + return Span.Empty; + } + + var pose = KeyframePoses[frame]; + + if (pose == null || BoneCount <= 0) + { + return Span.Empty; + } + + return new Span(KeyframePoses[frame], KeyFrameCount); } public string NameToString() diff --git a/Raylib-cs/types/Raylib.Utils.cs b/Raylib-cs/types/Raylib.Utils.cs index 37f7bbe..0dbf173 100644 --- a/Raylib-cs/types/Raylib.Utils.cs +++ b/Raylib-cs/types/Raylib.Utils.cs @@ -20,6 +20,20 @@ public static unsafe partial class Raylib SetWindowTitle(str1.AsPointer()); } + /// Set icon for window (multiple images, RGBA 32bit) + public static void SetWindowIcons(Image[] images) + { + if (images == null || images.Length == 0) + { + return; + } + + fixed (Image* imagesPtr = images) + { + SetWindowIcons(imagesPtr, images.Length); + } + } + /// Get the human-readable, UTF-8 encoded name of the specified monitor public static string GetMonitorName_(int monitor) { @@ -112,6 +126,19 @@ public static unsafe partial class Raylib return LoadImage(str1.AsPointer()); } + /// Load image sequence from memory buffer + public static Image LoadImageAnimFromMemory(string fileType, byte[] fileData, out int frames) + { + using AnsiBuffer type = fileType.ToAnsiBuffer(); + fixed (byte* data = fileData) + { + int frameCount; + var result = LoadImageAnimFromMemory(type.AsPointer(), data, fileData.Length, &frameCount); + frames = frameCount; + return result; + } + } + /// Load image from RAW file data public static Image LoadImageRaw(string fileName, int width, int height, PixelFormat format, int headerSize) { @@ -192,7 +219,7 @@ public static unsafe partial class Raylib /// Set shader uniform value public static void SetShaderValue(Shader shader, int locIndex, T value, ShaderUniformDataType uniformType) - where T : unmanaged + where T : unmanaged { SetShaderValue(shader, locIndex, &value, uniformType); } @@ -244,6 +271,7 @@ public static unsafe partial class Raylib { return false; } + fixed (T* ptr = data) { using AnsiBuffer ansiBuffer = fileName.ToAnsiBuffer(); @@ -251,6 +279,16 @@ public static unsafe partial class Raylib } } + /// Export data to code (.h), returns true on success + public static CBool ExportDataAsCode(byte[] data, string fileName) + { + fixed (byte* ptr = data) + { + using AnsiBuffer name = fileName.ToAnsiBuffer(); + return ExportDataAsCode(ptr, data.Length, name.AsPointer()); + } + } + /// Load file data as byte array (read) public static byte* LoadFileData(string fileName, ref int bytesRead) { @@ -265,6 +303,13 @@ public static unsafe partial class Raylib { int length = 0; byte* data = LoadFileData(fileName, ref length); + + if (data == null) + { + return Array.Empty(); + } + + byte[] arr = new byte[length]; Marshal.Copy((IntPtr)data, arr, 0, length); UnloadFileData(data); @@ -294,6 +339,7 @@ public static unsafe partial class Raylib { files[i] = filePathList[i]; } + UnloadDroppedFiles(filePathList); return files; @@ -409,7 +455,7 @@ public static unsafe partial class Raylib CBool lockView, CBool rotateAroundTarget, CBool rotateUp - ) + ) { fixed (Camera3D* c = &camera) { @@ -866,7 +912,8 @@ public static unsafe partial class Raylib } /// Draw triangle with interpolated colors within an image - public static void ImageDrawTriangleEx(ref Image dst, Vector2 v1, Vector2 v2, Vector2 v3, Color c1, Color c2, Color c3) + public static void ImageDrawTriangleEx(ref Image dst, Vector2 v1, Vector2 v2, Vector2 v3, Color c1, Color c2, + Color c3) { fixed (Image* p = &dst) { @@ -1112,6 +1159,33 @@ public static unsafe partial class Raylib } } + /// Update sound buffer with new data + public static void UpdateSound(Sound sound, ReadOnlySpan data, int sampleCount) where T : unmanaged + { + fixed (T* dataPtr = data) + { + UpdateSound(sound, dataPtr, sampleCount); + } + } + + /// Update sound buffer with new data + public static void UpdateSound(Sound sound, ReadOnlySpan data) where T : unmanaged + { + fixed (T* dataPtr = data) + { + UpdateSound(sound, dataPtr, data.Length); + } + } + + /// Update audio stream buffers with data + public static void UpdateAudioStream(AudioStream sound, ReadOnlySpan data, int frameCount) where T : unmanaged + { + fixed (T* dataPtr = data) + { + UpdateAudioStream(sound, dataPtr, frameCount); + } + } + /// Convert wave data to desired format public static void WaveFormat(ref Wave wave, int sampleRate, int sampleSize, int channels) { @@ -1232,6 +1306,33 @@ public static unsafe partial class Raylib DrawTextPro(font, str1.AsPointer(), position, origin, rotation, fontSize, spacing, tint); } + /// Draw multiple characters (codepoint) + public static void DrawTextCodepoints( + Font font, + int[] codepoints, + Vector2 position, + float fontSize, + float spacing, + Color tint + ) + { + fixed (int* codepointsPtr = codepoints) + { + DrawTextCodepoints(font, codepointsPtr, codepoints.Length, position, fontSize, spacing, tint); + } + } + + /// Measure string size for Font + public static Vector2 MeasureTextCodepoints( + Font font, int[] codepoints, float fontSize, float spacing + ) + { + fixed (int* codepointsPtr = codepoints) + { + return MeasureTextCodepoints(font, codepointsPtr, codepoints.Length, fontSize, spacing); + } + } + /// Measure string width for default font public static int MeasureText(string text, int fontSize) { @@ -1502,12 +1603,12 @@ public static unsafe partial class Raylib public static string GetApplicationDirectoryString() { - return new string(GetApplicationDirectory()); + return Utf8StringUtils.GetUTF8String(GetApplicationDirectory()); } public static string GetWorkingDirectoryString() { - return new string(GetWorkingDirectory()); + return Utf8StringUtils.GetUTF8String(GetWorkingDirectory()); } /// @@ -1529,6 +1630,7 @@ public static unsafe partial class Raylib { output[i] = sequence[i]; } + UnloadRandomSequence(sequence); return output; } @@ -1554,6 +1656,7 @@ public static unsafe partial class Raylib float norm = (float)val / (float)maxi; output[i] = Raymath.Lerp(min, max, norm); } + return output; } @@ -1641,47 +1744,47 @@ public static unsafe partial class Raylib public static string GetFileExtension(string fileName) { using AnsiBuffer fileBuffer = fileName.ToAnsiBuffer(); - return new string(GetFileExtension(fileBuffer.AsPointer())); + return Utf8StringUtils.GetUTF8String(GetFileExtension(fileBuffer.AsPointer())); } /// Get string to filename for a path string public static string GetFileName(string fileName) { using AnsiBuffer fileBuffer = fileName.ToAnsiBuffer(); - return new string(GetFileName(fileBuffer.AsPointer())); + return Utf8StringUtils.GetUTF8String(GetFileName(fileBuffer.AsPointer())); } /// Get filename string without extension public static string GetFileNameWithoutExt(string fileName) { using AnsiBuffer fileBuffer = fileName.ToAnsiBuffer(); - return new string(GetFileNameWithoutExt(fileBuffer.AsPointer())); + return Utf8StringUtils.GetUTF8String(GetFileNameWithoutExt(fileBuffer.AsPointer())); } /// Get full path for a given fileName with path public static string GetDirectoryPath(string filePath) { using AnsiBuffer fileBuffer = filePath.ToAnsiBuffer(); - return new string(GetDirectoryPath(fileBuffer.AsPointer())); + return Utf8StringUtils.GetUTF8String(GetDirectoryPath(fileBuffer.AsPointer())); } /// Get previous directory path for a given path public static string GetPrevDirectoryPath(string dirPath) { using AnsiBuffer dirBuffer = dirPath.ToAnsiBuffer(); - return new string(GetPrevDirectoryPath(dirBuffer.AsPointer())); + return Utf8StringUtils.GetUTF8String(GetPrevDirectoryPath(dirBuffer.AsPointer())); } /// Get current working directory public static string GetWorkingDirectoryAsString() { - return new string(GetWorkingDirectory()); + return Utf8StringUtils.GetUTF8String(GetWorkingDirectory()); } /// Get the directory of the running application public static string GetApplicationDirectoryAsString() { - return new string(GetApplicationDirectory()); + return Utf8StringUtils.GetUTF8String(GetApplicationDirectory()); } /// Change working directory, return true on success @@ -1705,6 +1808,21 @@ public static unsafe partial class Raylib return LoadDirectoryFiles(dirBuffer.AsPointer()); } + /// Get the file count in a directory + public static int GetDirectoryFileCount(string dirPath) + { + using AnsiBuffer dirBuffer = dirPath.ToAnsiBuffer(); + return GetDirectoryFileCount(dirBuffer.AsPointer()); + } + + /// Load directory filepaths with extension filtering and subdir scan; some filters available: "*.*", "FILES*", "DIRS*" + public static int GetDirectoryFileCountEx(string dirPath, string filter, CBool scanSubdirs) + { + using AnsiBuffer dirBuffer = dirPath.ToAnsiBuffer(); + using AnsiBuffer filterBuffer = filter.ToAnsiBuffer(); + return GetDirectoryFileCountEx(dirBuffer.AsPointer(), filterBuffer.AsPointer(), scanSubdirs); + } + /// Load directory filepaths with extension filtering and subdir scan; some filters available: "*.*", "FILES*", "DIRS*" public static FilePathList LoadDirectoryFilesEx(string basePath, string filter, CBool scanSubDirs) { @@ -1713,6 +1831,212 @@ public static unsafe partial class Raylib return LoadDirectoryFilesEx(baseBuffer.AsPointer(), filterBuffer.AsPointer(), scanSubDirs); } + + /// Compress data (DEFLATE algorithm) + public static byte[] CompressData(byte[] data) + { + fixed (byte* dataPtr = data) + { + int compressedSize; + var compressedPtr = CompressData(dataPtr, data.Length, &compressedSize); + + if (compressedPtr == null || compressedSize <= 0) + { + return Array.Empty(); + } + + try + { + var result = new byte[compressedSize]; + + fixed (byte* resultPtr = result) + { + Buffer.MemoryCopy( + compressedPtr, + resultPtr, + compressedSize, + compressedSize + ); + } + + return result; + } + finally + { + MemFree(compressedPtr); + } + } + } + + /// Decompress data (DEFLATE algorithm) + public static byte[] DecompressData(byte[] data) + { + fixed (byte* dataPtr = data) + { + int dataSize; + var compressedPtr = DecompressData(dataPtr, data.Length, &dataSize); + + if (compressedPtr == null || dataSize <= 0) + { + return Array.Empty(); + } + + try + { + var result = new byte[dataSize]; + + fixed (byte* resultPtr = result) + { + Buffer.MemoryCopy( + compressedPtr, + resultPtr, + dataSize, + dataSize + ); + } + + return result; + } + finally + { + MemFree(compressedPtr); + } + } + } + + /// Encode data to Base64 string + public static byte[] EncodeDataBase64(byte[] data) + { + fixed (byte* dataPtr = data) + { + int outputSize; + var compressedPtr = EncodeDataBase64(dataPtr, data.Length, &outputSize); + + if (compressedPtr == null || outputSize <= 0) + { + return Array.Empty(); + } + + try + { + var result = new byte[outputSize]; + + fixed (byte* resultPtr = result) + { + Buffer.MemoryCopy( + compressedPtr, + resultPtr, + outputSize, + outputSize + ); + } + + return result; + } + finally + { + MemFree(compressedPtr); + } + } + } + + /// Decode data to Base64 string + public static byte[] DecodeDataBase64(string data) + { + using Utf8Buffer ptr = data.ToUtf8Buffer(); + + int outputSize; + var compressedPtr = DecodeDataBase64(ptr.AsPointer(), &outputSize); + + if (compressedPtr == null || outputSize <= 0) + { + return Array.Empty(); + } + + try + { + var result = new byte[outputSize]; + + fixed (byte* resultPtr = result) + { + Buffer.MemoryCopy( + compressedPtr, + resultPtr, + outputSize, + outputSize + ); + } + + return result; + } + finally + { + MemFree(compressedPtr); + } + } + + /// Compute CRC32 hash code + public static uint ComputeCRC32(byte[] data) + { + fixed (byte* dataPtr = data) + { + return ComputeCRC32(dataPtr, data.Length); + } + } + + /// Compute MD5 hash code, returns uint[4] array + public static uint[] ComputeMD5(byte[] data) + { + fixed (byte* dataPtr = data) + { + var result = ComputeMD5(dataPtr, data.Length); + return + [ + result[0], + result[1], + result[2], + result[3], + ]; + } + } + + /// Compute SHA1 hash code, returns uint[5] array + public static uint[] ComputeSHA1(byte[] data) + { + fixed (byte* dataPtr = data) + { + var result = ComputeSHA1(dataPtr, data.Length); + return + [ + result[0], + result[1], + result[2], + result[3], + result[4], + ]; + } + } + + /// Compute SHA256 hash code, returns int[8] (32 bytes) + public static uint[] ComputeSHA256(byte[] data) + { + fixed (byte* dataPtr = data) + { + var result = ComputeSHA256(dataPtr, data.Length); + return + [ + result[0], + result[1], + result[2], + result[3], + result[4], + result[5], + result[6], + result[7], + ]; + } + } + /// /// Loads text from a file, reads it, saves it, unloads the file, and returns the loaded text. ///