字体渲染中出现奇怪的纹理错误

时间:2014-08-31 03:15:21

标签: macos opengl text glsl

我正在关注wikibooks的教程:http://en.wikibooks.org/wiki/OpenGL_Programming/Modern_OpenGL_Tutorial_Text_Rendering_01

运行OSX 10.9和安装在带有GT 650m的rMBP上的Xcode5,我可以编译示例代码并进行正常渲染,但是当我将代码移植到SDL2设置时,我得到了这个:

Block glyphs with blurry textures

我知道着色器是正确的,因为当我将它们移植到示例代码时,我会正确地呈现文本。它看起来像纹理坐标是不正确的,但我无法找到它的原因。我注意到的一件事是,如果我更改为OpenGL 3.2核心配置文件并修复着色器的已弃用部分,由于使用了tex采样器,我得到了片段着色器编译错误。

完整的代码包含在下面:

// ============================================================================
// [Include Section]
// ============================================================================
#define GLEW_STATIC
#include <iostream>

#include <GL/glew.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_opengl.h>

#include <ft2build.h>
#include FT_FREETYPE_H

#include <unistd.h>
#include <cassert>
using namespace std;

// ============================================================================
// [SdlApplication]
// ============================================================================
#define APPTITLE "SDL Template Program"
// SdlApplication is nothing more than thin wrapper to SDL library. You need
// just to instantiate it and call run() to enter the SDL event loop.

class OGL
{
public:
    OGL(){}
    ~OGL()
    {
        glDeleteProgram(shaderProgram);
        glDeleteShader(fragmentShader);
        glDeleteShader(vertexShader);

        glDeleteBuffers(1, &vbo);

        glDeleteVertexArrays(1, &vao);
    }
public:
    SDL_GLContext context;
    GLuint fragmentShader, shaderProgram, vertexShader;
    GLuint vbo, vao;

    GLuint textProgram;
    GLint uniform_tex;
    GLint uniform_color;
    GLint attribute_coord;
};
struct SdlApplication
{
    SdlApplication();
    ~SdlApplication();

    // Application state (just convenience instead of 0, 1, ...).
    enum APP_STATE
    {
        APP_OK = 0,
        APP_FAILED = 1
    };

    // Initialize application, called by run(), don't call manually.
    int init(int width, int height);

    // Destroy application, called by destructor, don't call manually.
    void destroy();

    // Run application, called by your code.
    int run(int width, int height);

    // Called to process SDL event.
    void onEvent(SDL_Event* ev);

    void render_text(const char *text, float x, float y, float sx, float sy);

    // Called to render content into buffer.
    void Render();

    // Whether the application is in event loop.
    bool _running;
    SDL_Window *win;
    SDL_Renderer *renderer;
    SDL_GLContext context;

    OGL ogl;

    FT_Library ft;
    FT_Face face;
    GLuint vboText;

};

SdlApplication::SdlApplication() :
_running(false)
{
}

SdlApplication::~SdlApplication()
{

    destroy();
}


const GLchar* vTextSource =
"#version 120 \n"
"attribute vec2 coord;"
"varying vec2 texcoord;"
"void main(void) {"
"  gl_Position = vec4(coord.xy, 0, 1);"
"  texcoord = coord.xy;"
"}";

const GLchar* fTextSource =
"#version 120\n"
"varying vec2 texcoord;"
"uniform sampler2D tex;"
"uniform vec4 color;"
//"out vec4 outColor;"
"void main(void) {"
"  gl_FragColor= vec4(1,1,0,texture2D(tex, texcoord).a) * color;"
"}";

int SdlApplication::init(int width, int height)
{
    SDL_version compiled, linked;

    SDL_VERSION(&compiled);
    SDL_GetVersion(&linked);

    cout << "Compiled: " << compiled.major << "." << compiled.minor << endl;
    cout << "Linked: " << linked.major << "." << linked.minor << endl;
    SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, "0");

    // Initialize the SDL library.
    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0)
    {
        fprintf(stderr, "SDL_Init() failed: %s\n", SDL_GetError());
        return APP_FAILED;
    }
/*
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
 */
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);

    win = SDL_CreateWindow(APPTITLE, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL | SDL_WINDOW_ALLOW_HIGHDPI);


    context = SDL_GL_CreateContext(win);

    glewExperimental = GL_TRUE;
    glewInit();
    int w, h;
    SDL_GL_GetDrawableSize(win, &w, &h);
    std::cout << "Drawable:" << w << "x" << h << std::endl;



    //initialize freetype
    if (FT_Init_FreeType(&ft))
        assert(false && "FreeType init failure");

    if (FT_New_Face(ft, "DroidSerif-Regular.ttf", 0, &face))
        assert(false && "Could not open font");

    auto checkShader = [](GLint shader)
    {
        GLint compile_ok = GL_FALSE;
        glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_ok);
        if (compile_ok == GL_FALSE) {
            cout << "failed to compile shader\n";
            glDeleteShader(shader);
            exit(0);
        }
    };

    //create font program
    // Create and compile the vertex shader
    GLint vShader, fShader;
    vShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vShader, 1, &vTextSource, NULL);
    glCompileShader(vShader);
    checkShader(vShader);
    cout << "Vertex shader compiled ok\n";

    // Create and compile the fragment shader
    fShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fShader, 1, &fTextSource, NULL);
    glCompileShader(fShader);
    checkShader(fShader);
    cout << "Fragment shader compiled ok\n";

    // Link the vertex and fragment shader into a shader program
    ogl.textProgram = glCreateProgram();
    glAttachShader(ogl.textProgram, vShader);
    glAttachShader(ogl.textProgram, fShader);
    glLinkProgram(ogl.textProgram);
    assert(ogl.textProgram);

    //get attrib, get uniform
    ogl.attribute_coord = glGetAttribLocation(ogl.textProgram, "coord");
    ogl.uniform_tex = glGetUniformLocation(ogl.textProgram, "tex");
    ogl.uniform_color = glGetUniformLocation(ogl.textProgram, "color");

    if(ogl.attribute_coord == -1 || ogl.uniform_tex == -1 || ogl.uniform_color == -1)
        return 0;

    glGenBuffers(1, &vboText);

    // Success.
    return APP_OK;
}

void SdlApplication::destroy()
{
    if (win)
    {
        SDL_DestroyWindow(win);
        //SDL_DestroyRenderer(renderer);
        SDL_GL_DeleteContext(context);
        SDL_Quit();
    }
}
struct point {
    GLfloat x;
    GLfloat y;
    GLfloat s;
    GLfloat t;
};
/**
 * Render text using the currently loaded font and currently set font size.
 * Rendering starts at coordinates (x, y), z is always 0.
 * The pixel coordinates that the FreeType2 library uses are scaled by (sx, sy).
 */
void SdlApplication::render_text(const char *text, float x, float y, float sx, float sy) {
    const char *p;
    FT_GlyphSlot g = face->glyph;

    /* Create a texture that will be used to hold one "glyph" */
    GLuint tex;

    glActiveTexture(GL_TEXTURE0);
    glGenTextures(1, &tex);
    glBindTexture(GL_TEXTURE_2D, tex);
    glUniform1i(ogl.uniform_tex, 0);

    /* We require 1 byte alignment when uploading texture data */
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

    /* Clamping to edges is important to prevent artifacts when scaling */
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    /* Linear filtering usually looks best for text */
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    /* Set up the VBO for our vertex data */
    glEnableVertexAttribArray(ogl.attribute_coord);
    glBindBuffer(GL_ARRAY_BUFFER, vboText);
    glVertexAttribPointer(ogl.attribute_coord, 4, GL_FLOAT, GL_FALSE, 0, 0);

    /* Loop through all characters */
    for (p = text; *p; p++) {
        /* Try to load and render the character */
        if (FT_Load_Char(face, *p, FT_LOAD_RENDER))
            continue;

        /* Upload the "bitmap", which contains an 8-bit grayscale image, as an alpha texture */
        glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, g->bitmap.width, g->bitmap.rows, 0, GL_ALPHA, GL_UNSIGNED_BYTE, g->bitmap.buffer);

        /* Calculate the vertex and texture coordinates */
        float x2 = x + g->bitmap_left * sx;
        float y2 = -y - g->bitmap_top * sy;
        float w = g->bitmap.width * sx;
        float h = g->bitmap.rows * sy;

        point box[4] = {
            {x2, -y2, 0, 0},
            {x2 + w, -y2, 1, 0},
            {x2, -y2 - h, 0, 1},
            {x2 + w, -y2 - h, 1, 1},
        };

        /* Draw the character on the screen */
        glBufferData(GL_ARRAY_BUFFER, sizeof box, box, GL_DYNAMIC_DRAW);
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

        /* Advance the cursor to the start of the next character */
        x += (g->advance.x >> 6) * sx;
        y += (g->advance.y >> 6) * sy;
    }

    glDisableVertexAttribArray(ogl.attribute_coord);
    glDeleteTextures(1, &tex);
}

int SdlApplication::run(int width, int height)
{
    // Initialize application.
    int state = init(width, height);
    if (state != APP_OK) return state;

    // Enter to the SDL event loop.
    SDL_Event ev;
    _running = true;

    while (SDL_WaitEvent(&ev))
    {
        onEvent(&ev);
        //Render();
        //SDL_GL_SwapWindow(win);
        if (_running == false)
        {
            break;
        }

        //glUseProgram(ogl.shaderProgram);
        //  glDrawArrays(GL_TRIANGLES, 0, 3);


        //render text
        float sx = 2.0 / width;
        float sy = 2.0 / height;

    glUseProgram(ogl.textProgram);
        /* White background */
        glClearColor(1, 1, 1, 1);
        glClear(GL_COLOR_BUFFER_BIT);

    /* Enable blending, necessary for our alpha texture */
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    GLfloat black[4] = { 0, 0, 0, 1 };
    GLfloat red[4] = { 1, 0, 0, 1 };
    GLfloat transparent_green[4] = { 0, 1, 0, 0.5 };

    FT_Set_Pixel_Sizes(face, 0, 48);
    glUniform4fv(ogl.uniform_color, 1, black);

        render_text("The Quick Brown Fox Jumps Over The Lazy Dog", -1 + 8 * sx, 1 - 50 * sy, sx, sy);
        render_text("The Misaligned Fox Jumps Over The Lazy Dog", -1 + 8.5 * sx, 1 - 100.5 * sy, sx, sy);

        /* Scaling the texture versus changing the font size */
        render_text("The Small Texture Scaled Fox Jumps Over The Lazy Dog", -1 + 8 * sx, 1 - 175 * sy, sx * 0.5, sy * 0.5);
        FT_Set_Pixel_Sizes(face, 0, 24);
        render_text("The Small Font Sized Fox Jumps Over The Lazy Dog", -1 + 8 * sx, 1 - 200 * sy, sx, sy);
        FT_Set_Pixel_Sizes(face, 0, 48);
        render_text("The Tiny Texture Scaled Fox Jumps Over The Lazy Dog", -1 + 8 * sx, 1 - 235 * sy, sx * 0.25, sy * 0.25);
        FT_Set_Pixel_Sizes(face, 0, 12);
        render_text("The Tiny Font Sized Fox Jumps Over The Lazy Dog", -1 + 8 * sx, 1 - 250 * sy, sx, sy);
        FT_Set_Pixel_Sizes(face, 0, 48);

        /* Colors and transparency */
        render_text("The Solid Black Fox Jumps Over The Lazy Dog", -1 + 8 * sx, 1 - 430 * sy, sx, sy);

        glUniform4fv(ogl.uniform_color, 1, red);
        render_text("The Solid Red Fox Jumps Over The Lazy Dog", -1 + 8 * sx, 1 - 330 * sy, sx, sy);
        render_text("The Solid Red Fox Jumps Over The Lazy Dog", -1 + 28 * sx, 1 - 450 * sy, sx, sy);

        glUniform4fv(ogl.uniform_color, 1, transparent_green);
        render_text("The Transparent Green Fox Jumps Over The Lazy Dog", -1 + 8 * sx, 1 - 380 * sy, sx, sy);
        render_text("The Transparent Green Fox Jumps Over The Lazy Dog", -1 + 18 * sx, 1 - 440 * sy, sx, sy);
        SDL_GL_SwapWindow(win);
    }

    return APP_OK;
}

void SdlApplication::onEvent(SDL_Event* ev)
{
    switch (ev->type)
    {
        case SDL_QUIT:
            _running = false;
            break;

        case SDL_KEYDOWN:
        {
            if (ev->key.keysym.sym == SDLK_ESCAPE)
            {
                _running = false;
            }
        }
    }
}

void SdlApplication::Render()
{}


// ============================================================================
// [Entry-Point]
// ============================================================================

int main(int argc, char* argv[])
{
    SdlApplication app;
    return app.run(640, 480);
}

0 个答案:

没有答案