Anonymous's picture

What about FONTS??

I've search a lot for a little example including fonts and it does not exist in the whole Internet. Is that simply not possible? I really need put text in my window and now I dont know if OpentTK could offer any support for that. Can anybody give some help about this problem?


Comments

Comment viewing options

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

The frustration with using fonts in OpenGL! I'm trying to find a way to add font rendering in OpenTK, but this is not a simple issue, and I don't believe I'll find a solution in time for the 1.0 release. Ideally OpenTK would support both truetype fonts and bitmap based fonts, but this is still a long way off.

The best advice I can give you is to cook up a texture-based font renderer: load a bitmap (png) with all needed glyphs aligned in a grid, then play with the texture coordinates to render glyphs on quads. I've used this successfully in the past, and it works well enough for simple games/applications.

bobbypowers's picture

I've come up with something that currently works for me, mostly, but is definitely sub-optimal. It works on Windows (only), and uses WGL to build a display lists of polygons of fonts. I've attached the code for my font class below. There are several things tho: 1. generating this list is slow (~.6-1.0 seconds on a core2duo). to get around this, I preload the fonts I need at startup, and store them in a list. Then I have a method I call when I want to draw a particular font, it checks against the pre-rendered ones and uses one if it matches, otherwise it creates it, adds it to the list and then uses it. 2. they look great real big, or if you can enable a multisampling extension (or presumably any type of scene antialiasing, I have yet to look into this), but otherwise look kind of crappy at regular/small font sizes. I plan soon on checking whether multisamplings turned on, and if it isn't creating antialiased bitmaps instead. Hopefully at least. Hope this helps a little.

yours,
Bobby

public class NewFont3D
    {
        //Public members
        private int list_base;
        Font ourFont;
 
        Gdi.GLYPHMETRICSFLOAT[] gmf = new Gdi.GLYPHMETRICSFLOAT[256];
 
        public NewFont3D(Font newFont)
        {
            ourFont = newFont;
 
            IntPtr hDC = Wgl.wglGetCurrentDC();
 
            IntPtr hFont = newFont.ToHfont();
 
            Gdi.SelectObject(hDC, hFont);
 
 
            list_base = Gl.glGenLists(256);
 
            Wgl.wglUseFontOutlines(hDC,							// Select The Current DC
                                0,								// Starting Character
                                255,							// Number Of Display Lists To Build
                                list_base,						// Starting Display Lists
                                0.0f,							// Deviation From The True Outlines
                                0.2f,							// Font Thickness In The Z Direction
                                Wgl.WGL_FONT_POLYGONS,			// Use Polygons, Not Lines
                                gmf);							// Address Of Buffer To Recieve Data
 
        }
 
        public bool SameFont(Font anotherFont)
        {
            if (ourFont.SizeInPoints == anotherFont.SizeInPoints &&
                ourFont.Name == anotherFont.Name &&
                ourFont.Style == anotherFont.Style)
                return true;
 
            return false;
        }
 
        public void Dispose()
        {
            Gl.glDeleteLists(list_base, 255);
        }
 
 
        public float extent(string what)
        {
            float length = 0;
 
            for (int loop = 0; loop < what.Length; loop++)	// Loop To Find Text Length
            {
                length += gmf[(byte)what[loop]].gmfCellIncX;			// Increase Length By Each Characters Width
            }
            return length * 2 * ourFont.SizeInPoints;
        }
 
        public void print(Coord location, string what)
        {
            Gl.glPushMatrix();
 
            byte[] textbytes = new byte[what.Length];
            for (int i = 0; i < what.Length; i++)
                textbytes[i] = (byte)what[i];
 
            Gl.glTranslated(location.X, location.Y, 0);
            Gl.glTranslatef(0, 0, 100);
            Gl.glPushAttrib(Gl.GL_LIST_BIT);							        // Pushes The Display List Bits
            Gl.glListBase(list_base);									        // Sets The Base Character to 0
 
 
            Gl.glScaled(2 * ourFont.SizeInPoints, 2 * ourFont.SizeInPoints, 0);
 
            Gl.glCallLists(what.Length, Gl.GL_UNSIGNED_BYTE, textbytes);	    // Draws The Display List Text
            Gl.glPopAttrib();
 
            // needed becuase in the display lists generated by WGL they flip the faces and don't return them
            Gl.glFrontFace(Gl.GL_CCW);
 
            Gl.glPopMatrix();
        }
    }
the Fiddler.'s picture

Thanks for the code, it definitely helps! Strange thing, I was thinking about something like this just a few hours ago. I'll port this to GLX and add it to OpenTK - it's not Freetype, but it's better than nothing.

Inertia's picture

To my knowledge glCallLists() itself will call glCallList() a couple of times, which is rather expensive if you are drawing alot of text. If your application is something like a chatroom (where you have a large amount of static text and only the input line changing), consider the possibility of compiling display lists at runtime for every _line_ once (glDrawArrays) instead of every character. This also has the benefit that addding coloring to characters/words/etc. is very cheap (e.g. you can check for certain unicode chars and interpret them as colors when building the vertex array). Not sure how much more expensive GL_COMPILE_AND_EXECUTE is compared to directly drawing it though, but after compilation the display list should execute much faster than passing every single character, or drawing the vertex array without VBOs. I don't have benchmarks to prove anything and results might vary depending on the driver. Just my 2 cents.