Chlumsky / msdfgen

Multi-channel signed distance field generator
MIT License
3.97k stars 412 forks source link

[HELP-NEEDED] Using MSDFGEN to create OpenGL textures #95

Closed aeris170 closed 4 years ago

aeris170 commented 4 years ago

Hello, how can I generate MSDF and use the generated data to create an OpenGL texture? You can see how I'm loading the font using freetype and loading the glyphs. The only thing left is to get MSDFGEN to generate an MSDF of the said glyph, and then use the MSDF to generate a texture.

Font* CreateFont(const char* name, const char* path) {
    FT_Face face;
    if (FT_New_Face(internal::text::fl, path, 0, &face)) {
        std::cout << "Fucked up while loading font!\n";
    }
    Font* f{ new Font() };
    for (int i{ 33 }; i < 126; ++i) {
        if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {
            continue;
        }
        //MSDF CODE START
                // how do I generate msdf?
        //MSDF CODE END
        (*f->m_chars)[i] = new Character(
            0, // this is the textureID
            face->glyph->advance.x,
            glm::vec2(face->glyph->bitmap.width, face->glyph->bitmap.rows),
            glm::vec2(face->glyph->bitmap_left, face->glyph->bitmap_top)
        );
    }
    FT_Done_Face(face);
    return f;
}
Type1J commented 4 years ago

Please look at the source to the command line generator. Here's a good starting point: https://github.com/Chlumsky/msdfgen/blob/master/main.cpp#L669

Type1J commented 4 years ago

Actually, there's a better example in the README.md:

#include "msdfgen.h"
#include "msdfgen-ext.h"

using namespace msdfgen;

int main() {
    FreetypeHandle *ft = initializeFreetype();
    if (ft) {
        FontHandle *font = loadFont(ft, "C:\\Windows\\Fonts\\arialbd.ttf");
        if (font) {
            Shape shape;
            if (loadGlyph(shape, font, 'A')) {
                shape.normalize();
                //                      max. angle
                edgeColoringSimple(shape, 3.0);
                //           image width, height
                Bitmap<float, 3> msdf(32, 32);
                //                     range, scale, translation
                generateMSDF(msdf, shape, 4.0, 1.0, Vector2(4.0, 4.0));
                savePng(msdf, "output.png");
            }
            destroyFont(font);
        }
        deinitializeFreetype(ft);
    }
    return 0;
}
Type1J commented 4 years ago

The basic idea is that you need to generate a Shape object from the glyph, then pass that to generateMSDF() as the 2nd argument (1st argument is an output).

aeris170 commented 4 years ago

This is what I've got so far. I've replaced the naked Freetype calls with MSDFGEN calls and succesfully generated an MSDF. I've also used the MSDF to generate a texture. It works nicely. However, I have a small problem. I need the generated MSDF to apply "-autoframe" property. Is there a function call to do that automatically? or do I need to implement it myself?

Font* CreateFont(const char* name, const char* path) {
    msdfgen::FontHandle* font = msdfgen::loadFont(internal::text::ft, path);
    if (!font) {
        std::cout << "Fucked up while loading font!\n";
    }
    Font* f{ new Font() };
    for (int i{ 33 }; i < 126; ++i) {
        //MSDF CODE
        msdfgen::Shape shape;
        texture::Texture* texture{ new texture::Texture };
        if (msdfgen::loadGlyph(shape, font, i)) {
            shape.normalize();
            edgeColoringSimple(shape, 3.0);
            msdfgen::Bitmap<float, 3> msdf(32, 32);
            msdfgen::generateMSDF(msdf, shape, 4.0, 1.0, msdfgen::Vector2(4.0, 4.0));

            glGenTextures(1, texture);
            glBindTexture(GL_TEXTURE_2D, *texture);

            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
            glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, 0.f);

            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 32, 32, 0, GL_RGB, GL_FLOAT, msdf.operator float *()); //hmmmmm
            glGenerateMipmap(GL_TEXTURE_2D);

            glBindTexture(GL_TEXTURE_2D, 0);
        }
        //MSDF CODE
        FT_Face face = msdfgen::getFace(font); //this function does not exist, I implemented it
        (*f->m_chars)[i] = new Character(
            texture,
            face->glyph->advance.x,
            glm::vec2(face->glyph->bitmap.width, face->glyph->bitmap.rows),
            glm::vec2(face->glyph->bitmap_left, face->glyph->bitmap_top)
        );      
        }
    msdfgen::destroyFont(font);
    return f;
}
Type1J commented 4 years ago

Chances are that if you need it, then somebody else will as well.

I'd make a PR adding options (with default values) to the call that you need.

However, in the meantime, I'd also copy that function into my project in a different namespace, and remove it later if/when the PR is accepted.

aeris170 commented 4 years ago

Damn, I have no idea how to get "-autoframe" done. Time to jump into the code then. Wish me luck!