Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Getting font glyphs  (Read 4125 times)

0 Members and 1 Guest are viewing this topic.

Richy19

  • Full Member
  • ***
  • Posts: 190
    • View Profile
Getting font glyphs
« on: July 15, 2012, 09:40:04 pm »
m trying to write my own font rendering system using OGL, and for it I get te texture from a sf::Font like so:

#ifndef BITMAPTEXT_HPP_INCLUDED
#define BITMAPTEXT_HPP_INCLUDED

#include <GL/glew.h>
#include <GL/gl.h>
#include <vector>
#include <SFML/Graphics.hpp>
#include "./Shader.hpp"
#include <glm/glm.hpp>

class BitmapText
{
protected:
    glm::vec3 Pos;
    glm::mat4 Model;

    GLuint vertexbuffer;
    GLuint uvbuffer;

    sf::Font font;
    sf::Texture bitmap;
    Shader shader;
    std::vector<sf::IntRect> Positions;
    std::string text;
    glm::vec4 Color;


    GLuint TextureID;
    GLuint ColorID;
    GLuint MVPID;
    GLuint PositionID;
    GLuint UVID;

    void Rebuild();
public:
    ///
    /// \brief Empty constructor
    ///
    BitmapText();

    ///
    /// \brief Empty deconstructor
    ///
    ~BitmapText();

    ///
    /// \brief Construct class from given arguments
    /// \param Bitmap image
    /// \param Bitmap position array
    bool LoadFile(const std::string& fontFile, int siz );

    ///
    /// \brief Set text
    ///
    void SetText(const std::string& eText);

    void SetPosition(const glm::vec2 &pos);

    virtual void Update();

    virtual void Draw(glm::mat4 &VP);

    void SetColor(float r , float g, float b , float a);
};

#endif // BITMAPTEXT_HPP_INCLUDED








#include <glm/gtx/transform2.hpp>
#include <GL/glew.h>
#include "./BitmapText.hpp"
#include <GL/glfw.h>
#include <iostream>
#include <fstream>
#include "./Utilities.hpp"
#include <limits>


BitmapText::BitmapText()
{

    std::string vertexShader =
    "#version 120\n"
    "uniform mat4 MVP;\n"
    "attribute vec4 Position;\n"
    "attribute vec2 UV;\n"
    "varying vec2 uv;\n"

    "void main(){\n"
        "uv = UV;\n"
        "gl_Position =  MVP * Position;\n"
    "}";

    std::string fragmentShader =
    "#version 120\n"
    "varying vec2 uv;\n"
    "uniform sampler2D Texture;\n"
    "uniform vec4 Color;\n"
    "void main(){\n"
        "vec4 textur = texture2D( Texture, uv ).rgba;\n"
        "textur.rgb = Color.rgb;\n"
        "if(textur.a == 0.0f){\n"
            "textur = vec4(0.0f, 0.0f, 0.0f, 0.0f);\n"
        "}\n"
        "gl_FragColor = textur;\n"
    "}";


    shader.LoadShaderCode(vertexShader ,fragmentShader);




    Color = glm::vec4(1.0f);

    text = "hi";

    glGenBuffers(1, &vertexbuffer);
    glGenBuffers(1, &uvbuffer);



    MVPID = glGetUniformLocation(shader.GetShaderID(), "MVP");
    TextureID = glGetUniformLocation(shader.GetShaderID(), "Texture");
    PositionID = glGetAttribLocation(shader.GetShaderID(), "Position");
    UVID = glGetAttribLocation(shader.GetShaderID(), "UV");
    ColorID = glGetUniformLocation(shader.GetShaderID(), "Color");

//Rebuild();
}

BitmapText::~BitmapText()
{
    glDeleteBuffers(1, &vertexbuffer);
    glDeleteBuffers(1, &uvbuffer);
}

bool BitmapText::LoadFile(const std::string& fontFile, int siz)
{
    font.loadFromFile(fontFile);

    for(unsigned char c = 0; c < std::numeric_limits<unsigned char>::max(); c++)
    {
        sf::Glyph g = font.getGlyph(c, siz, false);
        Positions.push_back(g.textureRect);
    }
    bitmap = font.getTexture( siz );
    bitmap.bind();
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glGenerateMipmap(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, 0);

    Rebuild();
    return true;
}

void BitmapText::SetText(const std::string& eText)
{
    text = eText;
    Rebuild();
}

void BitmapText::SetPosition(const glm::vec2& pos)
{
    Pos = glm::vec3(pos.x, pos.y, 0.1f);
    Rebuild();
}

void BitmapText::Update()
{

}

void BitmapText::Draw(glm::mat4 &VP)
{

    //glPolygonMode( GL_FRONT_AND_BACK, GL_FILL);
    glm::mat4 MVP = VP * Model;

    shader.Bind();
    glUniformMatrix4fv(MVPID, 1, GL_FALSE, &MVP[0][0]);

    glActiveTexture(GL_TEXTURE0);
    bitmap.bind();
    glUniform1i(TextureID, 0);

    glUniform4fv(ColorID,1 , &Color[0]);

    glEnableVertexAttribArray(PositionID);
    glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
    glVertexAttribPointer(
        PositionID,                  // attribute 0. No particular reason for 0, but must match the layout in the shader.
        3,                  // size
        GL_FLOAT,           // type
        GL_FALSE,           // normalized?
        0,                  // stride
        (void*)0            // array buffer offset
    );

    glEnableVertexAttribArray(UVID);
    glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
    glVertexAttribPointer(
        UVID,                  // attribute 0. No particular reason for 0, but must match the layout in the shader.
        2,                  // size
        GL_FLOAT,           // type
        GL_FALSE,           // normalized?
        0,                  // stride
        (void*)0            // array buffer offset
    );

    glDrawArrays(GL_TRIANGLES, 0, text.size() * 6);

    glDisableVertexAttribArray(UVID);
    glDisableVertexAttribArray(PositionID);


    glBindTexture(GL_TEXTURE_2D, 0);
    Shader::Unbind();



    //if(asLines)
    //    glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
    //else
    //    glPolygonMode( GL_FRONT_AND_BACK, GL_FILL);

}

void BitmapText::Rebuild()
{
    std::vector<GLfloat> VertexList;
    std::vector<GLfloat> UVList;

    float disp = 0.0f;
    float largestHeight = 0.0f;
    for(int i = 0; i < text.size(); i++)
    {
        sf::IntRect charRect = Positions[text.c_str()[i]];
        if(largestHeight < charRect.height) largestHeight = charRect.height;


        VertexList.push_back(0.0f + disp);
        VertexList.push_back(0.0f);
        VertexList.push_back(0.0f);

        VertexList.push_back(0.0f + disp);
        VertexList.push_back(charRect.height);
        VertexList.push_back(0.0f);

        VertexList.push_back(charRect.width + disp);
        VertexList.push_back(0.0f);
        VertexList.push_back(0.0f);

        VertexList.push_back(charRect.width + disp);
        VertexList.push_back(0.0f);
        VertexList.push_back(0.0f);

        VertexList.push_back(0.0f + disp);
        VertexList.push_back(charRect.height);
        VertexList.push_back(0.0f);


        VertexList.push_back(charRect.width + disp);
        VertexList.push_back(charRect.height);
        VertexList.push_back(0.0f);



        UVList.push_back(charRect.left / bitmap.getSize().x);
        UVList.push_back(charRect.top / bitmap.getSize().y);

        UVList.push_back(charRect.left / bitmap.getSize().x);
        UVList.push_back((charRect.top + charRect.height) / bitmap.getSize().y);

        UVList.push_back((charRect.left + charRect.width ) / bitmap.getSize().x);
        UVList.push_back(charRect.top / bitmap.getSize().y);

        UVList.push_back((charRect.left + charRect.width ) / bitmap.getSize().x);
        UVList.push_back(charRect.top / bitmap.getSize().y);

        UVList.push_back(charRect.left / bitmap.getSize().x);
        UVList.push_back((charRect.top + charRect.height) / bitmap.getSize().y);

        UVList.push_back((charRect.left + charRect.width ) / bitmap.getSize().x);
        UVList.push_back((charRect.top + charRect.height) / bitmap.getSize().y);

        disp += charRect.width;
    }


    glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
    glBufferData(GL_ARRAY_BUFFER, VertexList.size() * sizeof(GLfloat), &VertexList[0], GL_STATIC_DRAW);

    glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
    glBufferData(GL_ARRAY_BUFFER, UVList.size() * sizeof(GLfloat), &UVList[0], GL_STATIC_DRAW);

    Model = glm::translate(glm::mat4(1.0f),Pos.x , Pos.y, 0.0f);
    //MVP =  * Model;

}

void BitmapText::SetColor(float r , float g, float b , float a)
{
    Color.x = r;
    Color.y = g;
    Color.z = b;
    Color.w = a;
}


 

The code to get the glyphs is:

bool BitmapText::LoadFile(const std::string& fontFile, int siz)
{
    font.loadFromFile(fontFile);

    for(unsigned char c = 0; c < std::numeric_limits<unsigned char>::max(); c++)
    {
        sf::Glyph g = font.getGlyph(c, siz, false);
        Positions.push_back(g.textureRect);
    }
    bitmap = font.getTexture( siz );
    bitmap.bind();
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glGenerateMipmap(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, 0);

    Rebuild();
    return true;
}
 

Is this the correct way to do it?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Getting font glyphs
« Reply #1 on: July 15, 2012, 10:54:18 pm »
Your code is too long. Why don't you test it yourself, and ask a precise question if you have a specific problem?
Laurent Gomila - SFML developer

Richy19

  • Full Member
  • ***
  • Posts: 190
    • View Profile
Re: Getting font glyphs
« Reply #2 on: July 16, 2012, 01:57:03 am »
Your code is too long. Why don't you test it yourself, and ask a precise question if you have a specific problem?

I have but it isnt drawing anything, correction its drawing the quad to display but nothing on it

To make it more clear my question is: If I want to get a texture with all the ASCII characters of a font is this the correct way of doing it?
for(unsigned char c = 0; c < std::numeric_limits<unsigned char>::max(); c++)
    {
        sf::Glyph g = font.getGlyph(c, siz, false);
        Positions.push_back(g.textureRect);
    }
    bitmap = font.getTexture( siz );
« Last Edit: July 16, 2012, 02:29:55 am by Richy19 »

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: Getting font glyphs
« Reply #3 on: July 16, 2012, 07:03:52 am »
That is correct as far as I can tell. I would however recommend only loading glyphs up to a specific codepoint for the language you intend to support (see this for unicode character tables) and not to max(). It will result in a very long time to construct the font and even a really huge texture although you won't use most of the loaded glyphs.

You must also be careful when doing glBindTexture(GL_TEXTURE_2D, 0). SFML remembers the last texture you called bind() on and doesn't rebind it even if you unbound it directly through OpenGL yourself. There are ways to hack around this but I won't promote such things for Laurent's sake :). You could just bind another empty texture when you call glBindTexture(GL_TEXTURE_2D, 0) to reset SFML's memory or you could just glDisable(GL_TEXTURE_2D) when you don't need any texturing.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).