xamarin / urho

Code to integrate with the Urho3D engine
Other
463 stars 122 forks source link

Urho.Gui.Text does not render Unicode text properly on desktop project. #161

Open bugcaptor opened 8 years ago

bugcaptor commented 8 years ago

On android it's OK, but on Windows desktop only shows "?" characters. For example CJK characters.

Maybe because of Mono's default encoding (UTF8) and C# default encoding (UTF16) difference? There is no code to convert utf16 to utf8 in marshalling.

migueldeicaza commented 8 years ago

This is a good catch.

In Mono, we assume that the default encoding does UTF-16 to UTF-8, but on the desktop Mono, the default is to use the platform-specific encoding, which is likely ANSI for these APIs.

So we probably need an attribute to configure custom marshaling on Windows to do the UTF-8 conversion (if the Urho API is taking UTF8 strings, which I am not sure it does).

andrekoehler commented 7 years ago

I am also affected by this bug. I tried the following workaround but it does not work:

private static string EncodeStringForUrho(string str)
{
    UTF8Encoding enc = new UTF8Encoding();
    byte[] bytes = enc.GetBytes(str);
    char[] buffer = new char[bytes.Length];
    for (int i = 0; i < bytes.Length; ++i)
    {
        buffer[i] = (char)bytes[i];
    }
    return new string(buffer);
}

I guess the .NET marshaller does not simply use the low bytes of each C# char but applies some advanded logic that renders this workaround useless.

Someone has to fix the value of the DllImportAttribute.CharSet field that is generated by SharpieBinder so that it uses System.Runtime.InteropServices.CharSet.Unicode: https://github.com/xamarin/urho/blob/4c9df3372aae29370725ca3b66878482e58f066b/Bindings/Portable/Generated/Text.cs#L177

And the generated Text_SetText function should use the wchar_t override of the Urho3D::String constructor instead of the char version.

andrekoehler commented 6 years ago

The bug also occurs with Text3D.

Muscipular commented 6 years ago

try hack the api, work for me

    static class TextUnicodeFix
    {
        [DllImport("mono-urho", CallingConvention = CallingConvention.Cdecl)]
        static extern void Text_SetText(IntPtr handle, byte[] text);

        [DllImport("mono-urho", CallingConvention = CallingConvention.Cdecl)]
        internal static extern void Text3D_SetText(IntPtr handle, byte[] text);

        public static unsafe string GetTextFix(this Text text)
        {
            var foo = ((UrhoString*)(text.Handle + 472).ToPointer()); // 472 is offset of text_ in TextClass
            return new string((sbyte*)foo->Buffer, 0, (int)foo->Length, Encoding.UTF8);
        }

        public static unsafe string GetTextFix(this Text3D text)
        {
            var foo = ((UrhoString*)(text.Handle + 748).ToPointer()); // 748 is offset of text_ in Text3DClass
            return new string((sbyte*)foo->Buffer, 0, (int)foo->Length, Encoding.UTF8);
        }

        public static void SetTextFix(this Text text, string str)
        {
            var bytes = Encoding.UTF8.GetBytes(str);
            Text_SetText(text.Handle, bytes);
        }

        public static void SetTextFix(this Text3D text, string str)
        {
            var bytes = Encoding.UTF8.GetBytes(str);
            Text3D_SetText(text.Handle, bytes);
        }
    }
hwd71 commented 5 years ago

Me too.. hack above works for me, thanks!