我正在关注wikibooks的教程:http://en.wikibooks.org/wiki/OpenGL_Programming/Modern_OpenGL_Tutorial_Text_Rendering_01
运行OSX 10.9和安装在带有GT 650m的rMBP上的Xcode5,我可以编译示例代码并进行正常渲染,但是当我将代码移植到SDL2设置时,我得到了这个:
我知道着色器是正确的,因为当我将它们移植到示例代码时,我会正确地呈现文本。它看起来像纹理坐标是不正确的,但我无法找到它的原因。我注意到的一件事是,如果我更改为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);
}