Fontmaps

Hi there,

I wanted to share a (glimpse at a) cool thing that I made and ask how I could improve it. I am really giddy about the fact that it worked out nicely, so excuse the gloating that’s inevitably present in the description below :wink:

It’s a fontmap generator. It can take any font, either installed or from a custom file and draw a condensed (bin packed) fontmap of symbols in any size and style using GDI+.
You then request a character and it returns its position, size and the index of the texture it’s currently contained in.
It’s also fully dynamic, so if you request a character that hasn’t been before generated (and you allow the fontmap to be dynamic), the fontmap will automatically generate the character, add it to the texture and return the symbol.
The image below took +/- 13 seconds (it’s 13000+ symbols in all styles possible and a lot of sizes). It’s a 2048x2048

Screenshot

The text below has been written with the symbols that were dynamically generated, added to the fontmap and then extracted to be applied on quads. I love it.

But enough with the gloating, I dearly need some advice. Do the fonts look okay when you see them? Could you look at a text like this for a long time? I have been continually staring at these fonts for so long that I honestly can’t tell. Sometimes the font looks too blurry (GDI+ is set to AntiAliasGridFit), but japanese and arabic symbols look too pixelated. Using AntiAlias (No grid fit) fixes the second problem, but sometimes augments the blurriness on thin lines, makes them gray instead of black.

And second, (I know this is an OpenGL forum, but whom better to ask than you people, many of whom attempted the same thing, I’m sure) where could I find any information that could help me with creating my own GUI? Namely textboxes - none of my pitiful attempts at creating a textbox control succeeded. I need some design, structure or anything that would explain how exactly does a textbox (like the one I’m using right now) effectively manage its text.

Thank you for any help

One idea to improve the quality: render a character at a much larger size, calculate a distance map from it, and store that in your fontmap texture, see Alpha Tested Magnification.pdf for details.

Thanks for the suggestion, but this seems like more work than it would be worth. At least for now, when it’s more important to get a basic UI going.

I used to do quad fonts with OpenGL. But I have been basically working with Direct3D (no more than 9) for a long time since, but intend to get back into desktop OpenGL soon because it will be possible to move away from Direct3D (breaking away from legacy inertia) and because Direct3D is a dead end on Windows XP but OpenGL is not.

If you are using GDI+ then we are talking about Windows. I do not know about post D3D9 but there is D3DXCreateFont which I have tended to favor; especially because I needed to emulate the earlier Win32 Font APIs but in general if Unicode and i18n is a must D3DXCreateFont really does a lot for free. And it seem like it probably works similarly to what you (Inagawa) are doing here. Except obviously it’s not OpenGL!

I don’t know how it stacks up against the kind of font rendering we expect in a web browser. But it you need quite large or single pixel fonts it looks good.

But now what I am wondering is what on earth I will do if I am using OpenGL instead of Direct3D9. I know D3DX has a lot of “OpenGL” mode features. But I am just assuming the two are not compatible due to namesakes if nothing else. I would actually need to be able to emulate the Win32 APIs on Windows at least so this kind of approach will probably be a must.

Anyway at OP. If nothing else you might consider firing up Direct3D instead of GDI. As GDI is deprecated anyway. And drawing to a device context. And then copying that to OpenGL somehow. The main OpenGL context handle on Windows is a device context, so it would probably be compatible. But it would be nice to break away from micromanaging the placement too. I am wondering if GLUT has a way? I see wglUseFontOutlines.

I am using GDI+, not GDI. And if I’m not mistaken, DirectWrite is the only thing superseding GDI+, no? I may be wrong, though. I really needed some robust way of rendering text as soon as possible so I can finally move on and get to programming the rest of the GUI, so GDI+ seemed like the obvious choice after picking apart the source code of other GUIs.

So to be honest, at this point I am far more interested in how to program an editable text box. For the life of me I can’t figure it out. I don’t have the luxury of thinking about the text as a string (and just render the text line by line with GDI+ like others do), but as a collection of quads and that complicates things beyond my capabilities. If anyone could please enlighten me even by a little, I’d be grateful, but as far as the matter with the fontmap goes, I can’t change anything now.

Edit: Where are my manners, thank you for the advice, don’t think I don’t value it; it’s just that by now my priorities are shifted away from the actual fontmap.

I don’t have the luxury of thinking about the text as a string (and just render the text line by line with GDI+ like others do), but as a collection of quads and that complicates things beyond my capabilities.

That… is why you fail.

You’re trying to think about a text box at the level of quad drawing. That’s the wrong way to go; you should be thinking of text boxes at the level of the string, which you then use to generate the list of quads to draw.

Your edit box has two levels of functionality: modify a string based on user-input, and draw that string. If you try to do both of these at the same time, you won’t get anywhere.

I don’t know too much about font stuff. But the default font in visual studio 2010 is so blurry, it’s enough to give you eye cancer.

[QUOTE=Alfonse Reinheart;1242803]That… is why you fail.

You’re trying to think about a text box at the level of quad drawing. That’s the wrong way to go; you should be thinking of text boxes at the level of the string, which you then use to generate the list of quads to draw.

Your edit box has two levels of functionality: modify a string based on user-input, and draw that string. If you try to do both of these at the same time, you won’t get anywhere.[/QUOTE]

I agree, I came to much the same conclusion. But I was concerned about the performance, since I will have to - as you said - generate the quads. Anyway, I will try that and get back to you on this.

I am pretty sure GDI+ is deprecated too. It’s a mess of an API.

I would like to know myself how this is commonly done. I am thinking when it comes to the rendering you would want to be writing the quads to a dynamic vertex buffer, but I am not sure. Honestly I am surprised if there is not a (commonly used) higher level way to do truetype Unicode with OpenGL.

Honestly I am surprised if there is not a (commonly used) higher level way to do truetype Unicode with OpenGL.

Why would you be surprised by that? Do you know how hard full-fledged Unicode text layout is? I know of exactly two open-source libraries that can do Unicode text layout: ICU and Pango. Both of these libraries are designed to care as little as possible about how you actually render the glyphs.

Drawing some glyphs with OpenGL is easy. Drawing the right glyphs in the right place with any graphics API is the tricky part.

[QUOTE=Alfonse Reinheart;1242845]Why would you be surprised by that? Do you know how hard full-fledged Unicode text layout is? I know of exactly two open-source libraries that can do Unicode text layout: ICU and Pango. Both of these libraries are designed to care as little as possible about how you actually render the glyphs.

Drawing some glyphs with OpenGL is easy. Drawing the right glyphs in the right place with any graphics API is the tricky part.[/QUOTE]

Well I will accept that as an answer. It’s not something I’ve looked into, but for the record this is built into Windows. Look into DrawText. The easiest thing to do might be to render the text with Direct3D to either an overlay window or to a neutral device context with a dynamic texture if your text is the usual sort of thing you find in a video game.

That reminds me though that you can also use DrawText (or a related API; as I recall) in a way that does not actually display text, and then query the text that it would have drawn, so that effectively you end up with the Unicode layouts that you would find in the likes of Internet Explorer. You would just need to capture and render the glyphs somehow.

EDITED: I think that might be what you are supposed to do with wglUseFontOutlines and wglUseFontBitmaps (depending on the kind of font you have etc) but these are documented to rely on display lists, and I don’t know how good those are anymore. I think the concept should be added to WebGL (due to the runtime limitations of JavaScript) but otherwise that is probably not the right way. It might be a good step for generating a font texture by whatever terms OpenGL uses for render target textures :slight_smile:

EDITED: It’s too bad those APIs do not expose the texture that the display lists would have used because that might save you the trouble of drawing the display lists to a render target.

Maybe instead of OpenVG Khronos should be pushing OpenUnicode or something first.

That wouldn’t be an open-source library. That would be a specification that someone has to implement. Just like virtually everything else Khronos does. There’s no point in providing a specification for a library like that.

While I was jesting. I dunno. Pango seems top heavy and doesn’t feel like an open standard. ICU (thanks for the heads up) looks like something that should be under the hood so to speak. Fonts are central to graphics, and doing fonts without Unicode is almost pointless to go back to. At the same time Unicode is a lot to deal with. So having something potentially as widespread as OpenGL for Unicode would be pretty important. I think it would probably make more sense for something like GLUT or GLUT itself to implement. Windows has DrawText, so it really has a leg up on everyone else if something as simple to just use cannot be figured out by everyone else.

I mean if there is already wglUseFontOutlines which presumably can do any kind of font for Windows. Why not just modernize it. X has glXUseXFont apparently. These can render any font. They just need a portable layout framework to match them now that we are in the Unicode age.

PS: Literally DrawText is just like pick a font, any font, and give us a string to draw. It’s that simple. You just have to deal with cobbling together your own hybrid fonts to make sure the glyphs you need are in the fonts you are drawing.

Why not just modernize it.

“Modernize it” into what? Into GLUT? Well, GLUT is defunct, so that would have to be FreeGLUT. And while it is active, I’m pretty sure they’re not going to build a full Unicode text layout system into their application.

You want a lot of things, but they’re not going to happen. Or more to the point, if you want them to happen, you are going to have to make them happen. If you want this in FreeGLUT, then put it into FreeGLUT; it’s open source.

Yeah that is the expectation. Meanwhile apparently non-Windows platforms do not have reasonable text rendering options for people like the OP. Not knowing what Apple has for their Macs.

That mentality just leads to confusion and imperialistic programming patterns which is not good for anyone.

Fortunately the OP seems to be working exclusively with Windows. So he/she has many options laid out before them here now.

If they were looking to be cross platform then they (apparently) have nothing.

PS: Everywhere I see OpenGL I see GLUT. So apparently it’s still popular. I am working from the assumption that GLUT is basically the D3DX of OpenGL, but I am pretty willfully ignorant about these things. If not GLUT then it should be built directly into the OS (environment/window manager) side of things. If the OS doesn’t have said features then it’s already behind the ball. Disclaimer: I am not familiar with the status of Unicode fonts with X/Linux or OSX but X has font facilities so it should be able to do its own layouts without every application having a dependency on something like Pango and there is no reason why OpenGL could not or should not facilitate that.

Modernize it to not using de facto deprecated features the likes of display lists. Though I don’t know if display lists are really such a sin for rendering a moderate amount of text. They are obviously not part of OpenGL ES; which should be able to render fonts out of the box too. For a full screen in a text editor it sounds like an awful idea (but at that point you might be able to justify using something more like Pango)

It’s just not unreasonable for a graphics API to be able to render fonts properly one way or another. Even the more so if we are to really embrace Unicode (open multi-culturalism) sooner or later.

If they were looking to be cross platform then they (apparently) have nothing.

Pango. ICU. Cross-platform.

Are we even having the same discussion here? Just because it’s not in OpenGL itself doesn’t mean it doesn’t exist.

Disclaimer: I am not familiar with the status of Unicode fonts with X/Linux or OSX but X has font facilities so it should be able to do its own layouts without every application having a dependency on something like Pango

You’re used to the Windows world, where if “the system” doesn’t do something, then it may as well not exist. That’s not how things happen outside of the Windows world. In the not-Windows world, you use libraries to get things done.

If you use GTK, you have a dependency on Pango because GTK uses Pango for its text layout. It uses LibXML2 for its XML reading, so you have another dependency there. And so on. That’s how things work in the not-Windows world: you pick your libraries and use them. Some of these are provided by the system. Some of these are provided by you.

Functionally, there’s no difference between having a dependency on Pango and having a dependency on Uniscribe. The only practical difference is that in the Pango case, you have to link to the library explicitly, while in the Uniscribe case, you don’t.

It’s just not unreasonable for a graphics API to be able to render fonts properly one way or another.

It is very unreasonable.

OpenGL is supposed to be a relatively thin wrapper around graphics hardware, in order to achieve a reasonable abstraction and allow for a reasonable platform-neutral interface to that hardware. OpenGL’s job is not to make it easy to do complex things. It’s job is to make it possible to do complex things. If something can be layered on top of OpenGL, then it should be.

You won’t find any font rendering functions in D3D either, for similar reasons.

I am not working exclusively with Windows, actually. The use of GDI+ (a painful experience as it were) is just temporary.

So how would you gentlemen advise me to continue?
The fonts themselves are drawn with GDI+, but I have no glyph metrics whatsoever - the fontmap generates crude metrics as it goes.

First it takes the default position of the symbol ‘Á’, and takes note of its height and Y coordinate in a bitmap so it can position smaller and larger characters on the same ‘line’.
It’s crude, but it actually works. They are positioned in the fontmap’s texture with their whitespace intact and therefore it’s just a matter of picking out the correct rectangle to draw.
Proud though I may be of this thing actually working, and since my work on the textbox is mostly done (thanks, Alfonse), I now seek an alternative to GDI+ - a cross-platform one if possible.

I’ve seen the names ICU and Pango floating around, so in the meantime I’ll go check what the buzz is all about.

Also, this is how the font looks in the textbox - my eyes hurt from looking at it.

I wrote this a while ago


#include <windows.h>
#include <gl\gl.h>
#include <stdio.h>
#include <math.h>

void remapColourRange(UCHAR *data, int numberOfItems) {

    for(int i=0; i<numberOfItems; i++) {
        data[i] = (data[i] * 255) / 64;
    }
}

void copyLine(UCHAR *in, UCHAR *out, int width) {

    for(int i=0; i<width; i++) {
        out[i] = in[i];
    }
}

void flipImage(UCHAR *data, int width, int height) {

    //===========
    UCHAR *temp;
    DWORD offset;
    DWORD offset2;
    //===========

    offset    = 0;
    offset2    = 0;
    temp    = new UCHAR[width];

    for(int i=0; i<height/2; i++) {

        offset = ((width+3) & ~3) * i;
        copyLine(data+offset,temp,width);            // copy bottom line

        offset2 = ((width+3) & ~3) * (height-i-1);
        copyLine(data+offset2,data+offset,width);    // copy top line to bottom

        copyLine(temp,data+offset2,width);            // temp line to top
    }

    delete []temp;
}

void convertLine(UCHAR *in, UCHAR *out, int width) {

    for(int i=0; i<width*4; i+=4) {
        out[i+0] = 255;
        out[i+1] = 255;
        out[i+2] = 255;
        out[i+3] = in[i/4];
    }
}

void convertToRGB(UCHAR *in, UCHAR *out, int width, int height) {

    //==========
    int offset;
    int offset2;
    //==========

    offset    = (width+3) & ~3;
    offset2    = (((width*4)+3) & ~3);
    
    for(int i=0; i<height; i++) {
        convertLine(in+(offset*i),out+(offset2*i),width);
    }
}

BOOL createFont(HDC hdc, DWORD first, DWORD count, DWORD listBase) {

    //===========================
    GLYPHMETRICS    gm;
    MAT2            mat2;
    DWORD            size;
    UCHAR            *data;
    UCHAR            *RGBData;
    //===========================

    // safety checks

    if(!count)    return FALSE;
    if(!hdc)    return FALSE;

    // initiate variables

    size    = 0;
    data    = NULL;
    RGBData = NULL;
    memset(&gm,0,sizeof(GLYPHMETRICS));

    // identity matrix 

    memset(&mat2, 0, sizeof(mat2));
    mat2.eM11.value = 1;    mat2.eM21.value = 0;
    mat2.eM12.value = 0;    mat2.eM22.value = 1;

    glPushAttrib(GL_PIXEL_MODE_BIT);
    glPixelStorei(GL_UNPACK_ALIGNMENT,4);

    for(DWORD i = 0 ; i< count; i++) {

        glNewList(listBase+i,GL_COMPILE);
        glPushAttrib(GL_ENABLE_BIT|GL_COLOR_BUFFER_BIT);

        // get size of the structure first

        size = GetGlyphOutline(hdc,first+i,GGO_GRAY8_BITMAP, &gm, 0, NULL, &mat2);
        if(size == GDI_ERROR) { glEndList(); continue; }

        if(size) {

            data = new UCHAR[size];

            GetGlyphOutline(hdc,first+i,GGO_GRAY8_BITMAP,&gm,size,data,&mat2);

            remapColourRange(data,size);
            flipImage    (data,gm.gmBlackBoxX,gm.gmBlackBoxY);

            RGBData = new UCHAR[(((gm.gmBlackBoxX*4)+3) & ~3) * gm.gmBlackBoxY ];

            convertToRGB(data,RGBData,gm.gmBlackBoxX,gm.gmBlackBoxY);
        }

        glEnable    (GL_BLEND);
        glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

        glBitmap    (0,0,0,0,(GLfloat)gm.gmptGlyphOrigin.x,(GLfloat)gm.gmptGlyphOrigin.y-(GLfloat)gm.gmBlackBoxY,NULL);    //incriment raster position
        if(size)    glDrawPixels(gm.gmBlackBoxX,gm.gmBlackBoxY, GL_RGBA, GL_UNSIGNED_BYTE, RGBData);
        glBitmap    (0,0,0,0,(GLfloat)-gm.gmptGlyphOrigin.x,-((GLfloat)gm.gmptGlyphOrigin.y-(GLfloat)gm.gmBlackBoxY),NULL);    //incriment raster position
        glBitmap    (0,0,0,0,(GLfloat)gm.gmCellIncX,(GLfloat)gm.gmCellIncY,NULL);    //incriment raster position

        glDisable    (GL_BLEND);

        glPopAttrib    ();
        glEndList    ();

        delete []data;
        delete []RGBData;
    }

    glPopAttrib        ();

    return TRUE;
}

It works as a drop in replacement for wglfontbitmaps. Proper anti-aliased fonts for win32. Opengl 1-2 support.
It’s not especially fast because it uses gldrawpixels, which doesn’t seem to be very fast. But it works fine nonetheless.

If you use it credits to me please :slight_smile: