mirror of
https://github.com/raylib-cs/raylib-cs
synced 2025-09-09 03:01:41 -04:00
Update string handling
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using Xunit;
|
||||
using Raylib_cs;
|
||||
|
||||
namespace Raylib_cs.Tests
|
||||
{
|
||||
@@ -39,5 +40,26 @@ namespace Raylib_cs.Tests
|
||||
Assert.True(BlittableHelper.IsBlittable<VrStereoConfig>());
|
||||
Assert.True(BlittableHelper.IsBlittable<RenderBatch>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Debug()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
Raylib.InitWindow(screenWidth, screenHeight, "Aaåäö");
|
||||
|
||||
while (!Raylib.WindowShouldClose())
|
||||
{
|
||||
Raylib.BeginDrawing();
|
||||
Raylib.ClearBackground(Color.RAYWHITE);
|
||||
Raylib.EndDrawing();
|
||||
}
|
||||
|
||||
Raylib.CloseWindow();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Numerics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.Xml;
|
||||
|
||||
namespace Raylib_cs
|
||||
{
|
||||
@@ -75,7 +76,15 @@ namespace Raylib_cs
|
||||
|
||||
/// <summary>Initialize window and OpenGL context</summary>
|
||||
[DllImport(nativeLibName, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void InitWindow(int width, int height, [MarshalAs(UnmanagedType.LPUTF8Str)] string title);
|
||||
public static extern void InitWindow(int width, int height, byte* title);
|
||||
|
||||
public static void InitWindow(int width, int height, Utf8String title)
|
||||
{
|
||||
fixed (byte* p = title)
|
||||
{
|
||||
InitWindow(width, height, p);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Check if KEY_ESCAPE pressed or Close icon pressed</summary>
|
||||
[DllImport(nativeLibName, CallingConvention = CallingConvention.Cdecl)]
|
||||
@@ -147,7 +156,15 @@ namespace Raylib_cs
|
||||
|
||||
/// <summary>Set title for window (only PLATFORM_DESKTOP)</summary>
|
||||
[DllImport(nativeLibName, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void SetWindowTitle([MarshalAs(UnmanagedType.LPUTF8Str)] string title);
|
||||
public static extern void SetWindowTitle(byte* title);
|
||||
|
||||
public static void SetWindowTitle(Utf8String title)
|
||||
{
|
||||
fixed (byte* p = title)
|
||||
{
|
||||
SetWindowTitle(p);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Set window position on screen (only PLATFORM_DESKTOP)</summary>
|
||||
[DllImport(nativeLibName, CallingConvention = CallingConvention.Cdecl)]
|
||||
@@ -239,7 +256,15 @@ namespace Raylib_cs
|
||||
|
||||
/// <summary>Set clipboard text content</summary>
|
||||
[DllImport(nativeLibName, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void SetClipboardText([MarshalAs(UnmanagedType.LPUTF8Str)] string text);
|
||||
public static extern void SetClipboardText(byte* text);
|
||||
|
||||
public static void SetClipboardText(Utf8String text)
|
||||
{
|
||||
fixed (byte* p = text)
|
||||
{
|
||||
SetClipboardText(p);
|
||||
}
|
||||
}
|
||||
|
||||
// Custom frame control functions
|
||||
// NOTE: Those functions are intended for advance users that want full control over the frame processing
|
||||
@@ -1101,11 +1126,26 @@ namespace Raylib_cs
|
||||
|
||||
/// <summary>Create an image from text (default font)</summary>
|
||||
[DllImport(nativeLibName, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern Image ImageText([MarshalAs(UnmanagedType.LPUTF8Str)] string text, int fontSize, Color color);
|
||||
public static extern Image ImageText(byte* text, int fontSize, Color color);
|
||||
|
||||
public static Image ImageText(Utf8String text, int fontSize, Color color)
|
||||
{
|
||||
fixed (byte* p = text)
|
||||
{
|
||||
return ImageText(p, fontSize, color);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Create an image from text (custom sprite font)</summary>
|
||||
[DllImport(nativeLibName, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern Image ImageTextEx(Font font, [MarshalAs(UnmanagedType.LPUTF8Str)] string text, float fontSize, float spacing, Color tint);
|
||||
public static extern Image ImageTextEx(Font font, byte* text, float fontSize, float spacing, Color tint);
|
||||
public static Image ImageTextEx(Font font, Utf8String text, float fontSize, float spacing, Color tint)
|
||||
{
|
||||
fixed (byte* p = text)
|
||||
{
|
||||
return ImageTextEx(font, p, fontSize, spacing, tint);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Convert image to POT (power-of-two)</summary>
|
||||
[DllImport(nativeLibName, CallingConvention = CallingConvention.Cdecl)]
|
||||
@@ -1273,13 +1313,28 @@ namespace Raylib_cs
|
||||
|
||||
/// <summary>Draw text (using default font) within an image (destination)</summary>
|
||||
[DllImport(nativeLibName, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void ImageDrawText(ref Image dst, [MarshalAs(UnmanagedType.LPUTF8Str)] string text, int x, int y, int fontSize, Color color);
|
||||
public static extern void ImageDrawText(ref Image dst, byte* text, int x, int y, int fontSize, Color color);
|
||||
|
||||
public static void ImageDrawText(ref Image dst, Utf8String text, int x, int y, int fontSize, Color color)
|
||||
{
|
||||
fixed (byte* p = text)
|
||||
{
|
||||
ImageDrawText(ref dst, p, x,y,fontSize,color);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Draw text (custom sprite font) within an image (destination)</summary>
|
||||
[DllImport(nativeLibName, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void ImageDrawTextEx(ref Image dst, Font font, [MarshalAs(UnmanagedType.LPUTF8Str)] string text, Vector2 position, float fontSize, float spacing, Color tint);
|
||||
|
||||
public static extern void ImageDrawTextEx(ref Image dst, Font font, byte* text, Vector2 position, float fontSize, float spacing, Color tint);
|
||||
|
||||
public static void ImageDrawTextEx(ref Image dst, Font font, Utf8String text, Vector2 position, float fontSize, float spacing, Color tint)
|
||||
{
|
||||
fixed (byte* p = text)
|
||||
{
|
||||
ImageDrawTextEx(ref dst, font, p, position, fontSize, spacing, tint);
|
||||
}
|
||||
}
|
||||
|
||||
// Texture loading functions
|
||||
// NOTE: These functions require GPU access
|
||||
|
||||
@@ -1469,15 +1524,42 @@ namespace Raylib_cs
|
||||
|
||||
/// <summary>Draw text (using default font)</summary>
|
||||
[DllImport(nativeLibName, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void DrawText([MarshalAs(UnmanagedType.LPUTF8Str)] string text, int posX, int posY, int fontSize, Color color);
|
||||
public static extern void DrawText(byte* text, int posX, int posY, int fontSize, Color color);
|
||||
|
||||
public static void DrawText(Utf8String text, int posX, int posY, int fontSize, Color color)
|
||||
{
|
||||
fixed (byte* p = text)
|
||||
{
|
||||
DrawText(p, posX, posY, fontSize, color);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Draw text using font and additional parameters</summary>
|
||||
[DllImport(nativeLibName, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void DrawTextEx(Font font, [MarshalAs(UnmanagedType.LPUTF8Str)] string text, Vector2 position, float fontSize, float spacing, Color tint);
|
||||
public static extern void DrawTextEx(Font font, byte* text, Vector2 position, float fontSize, float spacing, Color tint);
|
||||
|
||||
public static void DrawTextEx(Font font, Utf8String text, Vector2 position, float fontSize,
|
||||
float spacing, Color tint)
|
||||
{
|
||||
fixed (byte* p = text)
|
||||
{
|
||||
DrawTextEx(font, p, position, fontSize, spacing, tint);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Draw text using Font and pro parameters (rotation)</summary>
|
||||
[DllImport(nativeLibName, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void DrawTextPro(Font font, [MarshalAs(UnmanagedType.LPUTF8Str)] string text, Vector2 position, float fontSize, float spacing, Color tint);
|
||||
public static extern void DrawTextPro(Font font, byte* text, Vector2 position, float fontSize, float spacing, Color tint);
|
||||
|
||||
public static void DrawTextPro(Font font, Utf8String text, Vector2 position, float fontSize,
|
||||
float spacing, Color tint)
|
||||
{
|
||||
fixed (byte* p = text)
|
||||
{
|
||||
DrawTextEx(font, p, position, fontSize, spacing, tint);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>Draw one character (codepoint)</summary>
|
||||
[DllImport(nativeLibName, CallingConvention = CallingConvention.Cdecl)]
|
||||
@@ -1488,11 +1570,27 @@ namespace Raylib_cs
|
||||
|
||||
/// <summary>Measure string width for default font</summary>
|
||||
[DllImport(nativeLibName, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int MeasureText([MarshalAs(UnmanagedType.LPUTF8Str)] string text, int fontSize);
|
||||
public static extern int MeasureText(byte* text, int fontSize);
|
||||
|
||||
public static int MeasureText(Utf8String text, int fontSize)
|
||||
{
|
||||
fixed (byte* p = text)
|
||||
{
|
||||
return MeasureText(p, fontSize);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Measure string size for Font</summary>
|
||||
[DllImport(nativeLibName, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern Vector2 MeasureTextEx(Font font, [MarshalAs(UnmanagedType.LPUTF8Str)] string text, float fontSize, float spacing);
|
||||
public static extern Vector2 MeasureTextEx(Font font, byte* text, float fontSize, float spacing);
|
||||
|
||||
public static Vector2 MeasureTextEx(Font font, Utf8String text, float fontSize, float spacing)
|
||||
{
|
||||
fixed (byte* p = text)
|
||||
{
|
||||
return MeasureTextEx(font, p, fontSize, spacing);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Get glyph index position in font for a codepoint (unicode character), fallback to '?' if not found</summary>
|
||||
[DllImport(nativeLibName, CallingConvention = CallingConvention.Cdecl)]
|
||||
|
220
Raylib-cs/Utf8String.cs
Normal file
220
Raylib-cs/Utf8String.cs
Normal file
@@ -0,0 +1,220 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace Raylib_cs;
|
||||
|
||||
#region LICENSE
|
||||
|
||||
// ** -- TAKEN FROM SQLitePCL.raw -- ** \\
|
||||
/* https://github.com/ericsink/SQLitePCL.raw */
|
||||
/*
|
||||
Copyright 2014-2021 SourceGear, LLC
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// CHANGES:
|
||||
// - Update Method Names
|
||||
// - Implicit Conversion From string
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// A raw string representation suitable for passing into many core SQLite apis. These will normally be pointers to
|
||||
/// utf8 encoded bytes, with a trailing <c>\0</c> terminator. <see langword="null"/> strings can be represented as
|
||||
/// well as empty strings.
|
||||
/// </summary>
|
||||
public readonly ref struct Utf8String
|
||||
{
|
||||
// this span will contain a zero terminator byte
|
||||
// if sp.Length is 0, it represents a null string
|
||||
// if sp.Length is 1, the only byte must be zero, and it is an empty string
|
||||
readonly ReadOnlySpan<byte> sp;
|
||||
|
||||
public ref readonly byte GetPinnableReference()
|
||||
{
|
||||
return ref sp.GetPinnableReference();
|
||||
}
|
||||
|
||||
private Utf8String(ReadOnlySpan<byte> a)
|
||||
{
|
||||
// no check here. anything that calls this
|
||||
// constructor must make assurances about the
|
||||
// zero terminator.
|
||||
sp = a;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="Utf8String"/> which directly points at the memory pointed to by <paramref
|
||||
/// name="span"/>. The span must contain a valid <see cref="Encoding.UTF8"/> encoded block of memory that
|
||||
/// terminates with a <c>\0</c> byte. The span passed in must include the <c>\0</c> terminator.
|
||||
/// <para/>
|
||||
/// Both <see langword="null"/> and empty strings can be created here. To create a <see langword="null"/> string,
|
||||
/// pass in an empty <see cref="ReadOnlySpan{T}"/>. To create an empty string, pass in a span with length 1, that
|
||||
/// only contains a <c>\0</c>
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// Thrown if <c>span.Length > 0</c> and <c>span[^1]</c> is not <c>\0</c>.
|
||||
/// </exception>
|
||||
public static Utf8String FromSpan(ReadOnlySpan<byte> span)
|
||||
{
|
||||
if (
|
||||
(span.Length > 0)
|
||||
&& (span[^1] != 0)
|
||||
)
|
||||
{
|
||||
throw new ArgumentException("zero terminator required");
|
||||
}
|
||||
|
||||
return new Utf8String(span);
|
||||
}
|
||||
|
||||
public static Utf8String FromString(string s)
|
||||
{
|
||||
if (s == null)
|
||||
{
|
||||
return new Utf8String(ReadOnlySpan<byte>.Empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Utf8String(s.ToUtf8String());
|
||||
}
|
||||
}
|
||||
|
||||
static unsafe long GetLength(byte* p)
|
||||
{
|
||||
var q = p;
|
||||
while (*q != 0)
|
||||
{
|
||||
q++;
|
||||
}
|
||||
|
||||
return q - p;
|
||||
}
|
||||
|
||||
static unsafe ReadOnlySpan<byte> FindZeroTerminator(byte* p)
|
||||
{
|
||||
var len = (int)GetLength(p);
|
||||
return new ReadOnlySpan<byte>(p, len + 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="Utf8String"/> which directly points at the memory pointed to by <paramref
|
||||
/// name="p"/>. The pointer must either be <see langword="null"/> or point to a valid <see
|
||||
/// cref="Encoding.UTF8"/> encoded block of memory that terminates with a <c>\0</c> byte.
|
||||
/// </summary>
|
||||
public static unsafe Utf8String FromPtr(byte* p)
|
||||
{
|
||||
if (p == null)
|
||||
{
|
||||
return new Utf8String(ReadOnlySpan<byte>.Empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Utf8String(FindZeroTerminator(p));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO maybe remove this and just use FromSpan?
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="Utf8String"/> which directly points at the memory pointed to by <paramref
|
||||
/// name="p"/> with length <paramref name="len"/>. The pointer must be to a valid <see cref="Encoding.UTF8"/>
|
||||
/// encoded block of memory that terminates with a <c>\0</c> byte. The <paramref name="len"/> value refers to
|
||||
/// the number of bytes in the utf8 encoded value <em>not</em> including the <c>\0</c> byte terminator.
|
||||
/// <para/>
|
||||
/// <paramref name="p"/> can be <see langword="null"/>, in which case <paramref name="len"/> is ignored
|
||||
/// and a new <see cref="Utf8String"/> instance is created that represents <see langword="null"/>. Note that this
|
||||
/// different from a pointer to a single <c>\0</c> byte and a length of one. That would represent an empty <see
|
||||
/// cref="Utf8String"/> string.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// Thrown if <paramref name="p"/> is not <see langword="null"/> and <c>p[len]</c> is not <c>\0</c>.
|
||||
/// </exception>
|
||||
public static unsafe Utf8String FromPtrLen(byte* p, int len)
|
||||
{
|
||||
if (p == null)
|
||||
{
|
||||
return new Utf8String(ReadOnlySpan<byte>.Empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
// the given len does NOT include the zero terminator
|
||||
var sp = new ReadOnlySpan<byte>(p, len + 1);
|
||||
return FromSpan(sp);
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe Utf8String FromIntPtr(IntPtr p)
|
||||
{
|
||||
if (p == IntPtr.Zero)
|
||||
{
|
||||
return new Utf8String(ReadOnlySpan<byte>.Empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Utf8String(FindZeroTerminator((byte*)(p.ToPointer())));
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (sp.Length == 0)
|
||||
{
|
||||
return "NUL";
|
||||
}
|
||||
|
||||
unsafe
|
||||
{
|
||||
fixed (byte* q = sp)
|
||||
{
|
||||
return Encoding.UTF8.GetString(q, sp.Length - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="Encoding.UTF8"/> encoded bytes for the provided <paramref name="value"/>. The array
|
||||
/// will include a trailing <c>\0</c> character. The length of the array will <see cref="Encoding.UTF8"/>'s
|
||||
/// <see cref="Encoding.GetByteCount(string)"/><c>+1</c> (for the trailing <c>\0</c> byte). These bytes are
|
||||
/// suitable to use with <see cref="FromSpan"/> using the extension <see
|
||||
/// cref="MemoryExtensions.AsSpan{T}(T[])"/> or <see cref="FromPtr(byte*)"/> or <see cref="FromPtrLen(byte*,
|
||||
/// int)"/>. Note that for <see cref="FromPtrLen(byte*, int)"/> the length provided should not include the
|
||||
/// trailing <c>\0</c> terminator.
|
||||
/// </summary>
|
||||
public static byte[] GetZeroTerminatedUTF8Bytes(string value)
|
||||
{
|
||||
return value.ToUtf8String();
|
||||
}
|
||||
|
||||
public static implicit operator Utf8String(string s)
|
||||
{
|
||||
return FromString(s);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Utf8StringUtils
|
||||
{
|
||||
public static byte[] ToUtf8String(this string sourceText)
|
||||
{
|
||||
if (sourceText == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var length = Encoding.UTF8.GetByteCount(sourceText);
|
||||
|
||||
var byteArray = new byte[length + 1];
|
||||
var wrote = Encoding.UTF8.GetBytes(sourceText, 0, sourceText.Length, byteArray, 0);
|
||||
byteArray[wrote] = 0;
|
||||
|
||||
return byteArray;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user