SFML community forums

Bindings - other languages => DotNet => Topic started by: Gleade on October 11, 2018, 02:45:28 am

Title: Text render issue
Post by: Gleade on October 11, 2018, 02:45:28 am
Hi,

Version: .NET 2.4

I'm trying to simply draw text and I'm wondering if anyone else is experiencing this issue. The issue is that the text isn't displaying correctly, it's missing characters and has strange gaps in between characters.
What is interesting is I'm getting similar but different results per-run of my application. I have not attempted to replicate the problem, but I will if no one else has or is experiencing this issue.

Trying to draw "Loading: 100%"
Run 1 (Notice the huge gap):
(https://i.imgur.com/G0nNk9R.png)
Run 2 (Notice the missing "1"):
(https://i.imgur.com/upuMMsm.png)

Trying to draw "Hello, World" (Not sure what's going on here):
(https://i.imgur.com/bRcex8X.png)
Title: Re: Text render issue
Post by: Antonio9227 on October 11, 2018, 03:53:16 pm
Can you post a snippet of your code please? I haven't experienced anything like this when working with text objects and it seems interesting.
Title: Re: Text render issue
Post by: Gleade on October 11, 2018, 11:24:05 pm
Hello,

Thank you for your interest. Ive created an engine and it wraps alot of sfml's functionality. I'm at work at the moment, but I'll happily try and recreate what I'm doing in my engine in a complete minimal example afterwards.
Title: Re: Text render issue
Post by: Gleade on October 12, 2018, 12:13:14 pm
I think I found the problem, I'm loading the font from a resource (as byte data). The problem does not occur if I load the font from a local file. Also note: It only appears to occur if the text is changing.

Code below that reproduces my bug:

Code: [Select]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SFML;
using SFML.Graphics;

namespace MInimalExample
{
    class Program
    {
            static void Main(string[] args)
            {
                Console.WriteLine("Press ESC key to close window");
                var window = new SimpleWindow();
                window.Run();

                Console.WriteLine("All done");
            }

    }

    class SimpleWindow
    {
        public void Run()
        {
            Font font = new Font(Properties.Resources.FLAPHEAD);

            Text text = new Text("Hello, World", font);

            var mode = new SFML.Window.VideoMode(800, 600);
            var window = new SFML.Graphics.RenderWindow(mode, "SFML works!");
            window.Closed += Window_Closed;


            // Start the game loop
            while (window.IsOpen)
            {
                window.Clear();
                // Process events
                window.DispatchEvents();

                text.DisplayedString = $"Hi {DateTime.Now}";

                window.Draw(text);

                // Finally, display the rendered frame on screen
                window.Display();
            }
        }

        private void Window_Closed(object sender, EventArgs e)
        {
            var window = (SFML.Window.Window)sender;
                window.Close();
        }

    }
}

Title: Re: Text render issue
Post by: Laurent on October 12, 2018, 12:52:23 pm
This problem may occur if the byte[] data is destroyed while the font is still being used by one or more Text instances.

The Font class itself doesn't ensure that the given byte array remains in memory (ie. it doesn't keep a reference to it), so is it possible that your Properties.Resources.FLAPHEAD array gets destroyed somehow?
Title: Re: Text render issue
Post by: Gleade on October 12, 2018, 02:45:15 pm
Interestingly enough, if I just load from local file into a byte array, I get the same result. You can clearly see the scope in this example.

Code: [Select]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SFML;
using SFML.Graphics;

namespace MInimalExample
{
    class Program
    {
            static void Main(string[] args)
            {
                Console.WriteLine("Press ESC key to close window");
                var window = new SimpleWindow();
                window.Run();

                Console.WriteLine("All done");
            }

    }

    class SimpleWindow
    {
        public void Run()
        {
            byte[] bytes = System.IO.File.ReadAllBytes("FLAPHEAD.TTF");
            Font font = new Font(bytes);

            Text text = new Text("Hello, World", font);

            var mode = new SFML.Window.VideoMode(800, 600);
            var window = new SFML.Graphics.RenderWindow(mode, "SFML works!");
            window.Closed += Window_Closed;


            // Start the game loop
            while (window.IsOpen)
            {
                window.Clear();
                // Process events
                window.DispatchEvents();

                text.DisplayedString = $"Hi {DateTime.Now}";

                window.Draw(text);

                // Finally, display the rendered frame on screen
                window.Display();
            }
        }

        private void Window_Closed(object sender, EventArgs e)
        {
            var window = (SFML.Window.Window)sender;
                window.Close();
        }

    }
}

Title: Re: Text render issue
Post by: FRex on October 12, 2018, 03:43:02 pm
https://github.com/SFML/SFML.Net/blob/master/src/Graphics/Font.cs
public Font(byte[] bytes) : base(IntPtr.Zero)
{
    GCHandle pin = GCHandle.Alloc(bytes, GCHandleType.Pinned);
    try
    {
        CPointer = sfFont_createFromMemory(pin.AddrOfPinnedObject(), Convert.ToUInt64(bytes.Length));
    }
    finally
    {
        pin.Free();
    }
    if (CPointer == IntPtr.Zero)
    {
        throw new LoadingFailedException("font");
    }
}

Doesn't that code pin the byte array (to allow taking it's address), open and then (no matter what since it's in a finally block) unpin it, leaving it free to be moved by the GC when it compacts the heap?
Title: Re: Text render issue
Post by: Laurent on October 12, 2018, 03:51:11 pm
Quote
Doesn't that code pin the byte array (to allow taking it's address), open and then (no matter what since it's in a finally block) unpin it, leaving it free to be moved by the GC when it compacts the heap?
I guess this is a possible explanation. Unfortunately I don't have a deep understanding of what happens here with memory.
Title: Re: Text render issue
Post by: FRex on October 12, 2018, 03:57:20 pm
This is what the description of that option sounds like: https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.gchandletype?view=netframework-4.7.2

It also makes sense for why that constructor makes a 'bad' Font object no matter where the bytes[] comes from and why pinning is a thing.

Can be easily checked too I guess? Pin the bytes[] and print its address from time to time then free it (the GC pin handle) instantly, then bugs should start once new glyps and info is read after a GC move?
Title: Re: Text render issue
Post by: Gleade on October 13, 2018, 01:21:12 am
Thanks for that FRex, that looks to be the case. For a work-around, I can confirm that you can use streams instead (FileStream / MemoryStream).

(https://i.imgur.com/nIwBqFZ.png)
Title: Re: Text render issue
Post by: FRex on October 19, 2018, 11:20:04 pm
Should I open an issue about this, Laurent?
Title: Re: Text render issue
Post by: eXpl0it3r on October 20, 2018, 01:40:03 am
Sure :)
Title: Re: Text render issue
Post by: FRex on October 20, 2018, 01:54:35 am
https://github.com/SFML/SFML.Net/issues/156