chandragon's picture

How to render text on the screen

Hi
I feel a bit of shame asking such a basic thing, but how do I render text on the screen ?
I searched for classes that could do that and found on internet that many people use a "TextPrinter" instance, but I don't find that class in OpenTK.Graphics.
I read in a post of this forum that it would be in "OpenTK.Compatibility", but I don't have it, has it been removed from the newer versions of OpenTK ? is there any substitute for the TextPrinter ?
Thanks for the answers !


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
the Fiddler's picture

OpenTK.Compatibility.dll is included in the opentk download, you can find it under "Binaries/Release/OpenTK/".

Personally, I prefer to render text on a System.Drawing.Bitmap, upload it to an OpenGL texture and finally use a quad to display it. Since text changes relatively in-frequently, this often results in better performance than other approaches.

I have written a book page explaining the technique with sample code: how to render text using OpenGL. A very simple implementation also exists in the "GameWindow States" sample that's included in OpenTK.sln -> OpenTK.Examples project -> OpenTK subfolder, but this should probably turn into a sample on its own.

chandragon's picture

Thank you for the answer.
I had already looked at the "GameWindow States" sample and your sample code, and made a class with a similar code, but it didn't work.
I tried to modify it so that it looks more like the sample code you posted, but still not working ...
Here's the class:

class Text
    {
        readonly Font TextFont = new Font(FontFamily.GenericSansSerif, 16);
        readonly Bitmap TextBitmap;
        PointF[] positions;
        string[] lignes;
        Brush[] couleurs;
        int texture, nb_lignes;
 
        public Text(int taille,Rectangle ClientSize)
        {
            positions = new PointF[taille];
            lignes = new string[taille];
            couleurs = new Brush[taille];
 
            TextBitmap = new Bitmap(ClientSize.Width, ClientSize.Height); // match window size
 
            texture = GL.GenTexture();
            GL.BindTexture(TextureTarget.Texture2D,texture);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);
            GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, TextBitmap.Width, TextBitmap.Height, 0,
                PixelFormat.Bgra, PixelType.UnsignedByte, IntPtr.Zero);
        }
 
        public void AddText(string s, PointF pos, Brush col)
        {
            lignes[nb_lignes] = s;
            positions[nb_lignes] = pos;
            couleurs[nb_lignes] = col;
            nb_lignes++;
            UpdateText();
        }
 
        public void UpdateText()
        {
            if (nb_lignes != 0)
            {
                using (Graphics gfx = Graphics.FromImage(TextBitmap))
                {
                    gfx.Clear(Color.Transparent);
                    gfx.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
                    for (int i = 0; i < nb_lignes; i++)
                        gfx.DrawString(lignes[i], TextFont, couleurs[i], positions[i]);
                }
 
                System.Drawing.Imaging.BitmapData data = TextBitmap.LockBits(new Rectangle(0, 0, TextBitmap.Width, TextBitmap.Height),
                    System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, TextBitmap.Width, TextBitmap.Height, PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0);
                TextBitmap.UnlockBits(data);
            }
        }
 
        public void Draw()
        {
 
            GL.MatrixMode(MatrixMode.Projection);
            GL.LoadIdentity();
            GL.Ortho(0, TextBitmap.Width, TextBitmap.Height, 0, -1, 1);
 
            GL.Enable(EnableCap.Texture2D);
            GL.Enable(EnableCap.Blend);
            GL.BlendFunc(BlendingFactorSrc.One, BlendingFactorDest.OneMinusSrcAlpha);
 
            GL.Begin(BeginMode.Quads);
            GL.TexCoord2(0f, 1f); GL.Vertex2(0f, 0f);
            GL.TexCoord2(1f, 1f); GL.Vertex2(1f, 0f);
            GL.TexCoord2(1f, 0f); GL.Vertex2(1f, 1f);
            GL.TexCoord2(0f, 0f); GL.Vertex2(0f, 1f);
            GL.End();
        }
    }

After that I included the OpenTK.Compatibility and tried the TextPrinter, but it didn't work either:
I just got a succession of little rectagles where the text should appear when I tried "textprinter.begin(); textprinter.Draw(...); textprinter.end();" and nothing when I tried "textprinter.Print(...);"
What should I do ?

chandragon's picture

I managed to render text with the TextPrinter.
I just had to use the default shader with GL.UseProgram(0) and disable the lighting.
But I still can't get my text class to work ...

the Fiddler's picture

Sorry, I haven't had time to look into this yet, I'll add a new text rendering example to the next release.

Glad to hear you managed to get TextPrinter to work.

chandragon's picture

Thank you !
Can I ask a different question ?
I finished my program and it works fine on windows, but it doesn't work on ubuntu, I get several error messages:

System.TypeInitializationException: An exception was thrown by the type initializer for OpenTK.Graphics.GL ---> System.DllNotFoundException: opengl32.dll (...)

OpenGl is installed on the machine.

the Fiddler's picture

OpenTK uses a feature called DllMap to locate native libraries on Linux and Mac OS X. What you need to do is copy OpenTK.dll.config along with OpenTK.dll. This file can be found in the OpenTK zip.

I'd suggest adding OpenTK.dll.config directly to your solution with the "copy to output directory" option. This way, you can simply zip up your bin folder and distribute it on all platforms.

chandragon's picture

Thank you very much ! it works !
But it's slower than on Windows, if I put too many shapes to draw the frame rate goes down critically.
Is it due to the transit in mono that would slow down the calculations ?
Other thing I noticed: Cursor.Hide(); doesn't work on linux.

kanato's picture

You can get around that by creating a cursor file which is blank, and set the cursor to that instead of using Cursor.Hide.

chandragon's picture

Oh, and how do you do that ?

fictiveLaark's picture

If it should interest anyone I've got a class translated from some Java code that allows you to draw text without bitmaps. Well, it uses bitmaps to make a texture on construction but when you draw a string the class tiles the individual letters from said texture. It does have some issues though.

1. Large fonts can be too big to fit in the bitmap used for texture creation, and you may have missing characters as a result. Seems fixable but for now you can just scale your text when you draw.
2. Spaces were two damn skinny for me, I'm afraid this might have caused some other problem I haven't found yet but basically I hacked it so spaces are the width of an 'a'.

AttachmentSize
TestTest.rar11.09 KB