SDL_ttf and OpenGL resizing, getting artifacts on text edges - opengl

I'm using SDL_ttf for rendering text with OpenGL. However, I'm getting nasty artifacts at edges of text:
Here's the code:
#include <string>
#include "SDL.h"
#include "SDL_opengl.h"
#include <SDL_ttf.h>
using namespace std;
#define WINDOW_WIDTH 1280
#define WINDOW_HEIGHT 1024
struct Color
{
unsigned char R, G, B, A;
Color(unsigned char r, unsigned char g, unsigned char b, unsigned char a) :
R(r), G(g), B(b), A(a)
{}
};
void DrawRectangle(int left, int right, int top, int bottom, Color c, GLuint Texture);
void DrawTextGL(int left, int top, TTF_Font* font, string text);
GLuint SDLSurfaceToTexture(SDL_Surface* surface);
int main(int argc, char** argv)
{
SDL_Init(SDL_INIT_VIDEO);
SDL_Surface* screen = SDL_SetVideoMode(WINDOW_WIDTH, WINDOW_HEIGHT, 32, SDL_OPENGL);
TTF_Init();
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 0);
glEnable(GL_TEXTURE_2D);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0f, WINDOW_WIDTH, WINDOW_HEIGHT, 0.0f, -1.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Enabling transparency
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
SDL_Surface* temp = SDL_LoadBMP("New Bitmap Image.bmp");
GLuint WhiteTexture = SDLSurfaceToTexture(temp);
TTF_Font* Font;
Font = TTF_OpenFont("FreeSerif.ttf", 36);
DrawRectangle(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, Color(0, 0, 0, 255), WhiteTexture);
SDL_GL_SwapBuffers();
DrawTextGL(300, 300, Font, "graveyard");
DrawTextGL(600, 600, Font, "graveyard");
SDL_GL_SwapBuffers();
system("pause");
SDL_Quit();
return 0;
}
void DrawRectangle(int left, int right, int top, int bottom, Color c, GLuint Texture)
{
glBindTexture(GL_TEXTURE_2D, Texture);
glColor4f(c.R/255.0f, c.G/255.0f, c.B/255.0f, c.A/255.0f);
glBegin(GL_QUADS);
//Top-left vertex (corner)
glTexCoord2i(0, 0);
glVertex2f(GLfloat(left), GLfloat(top));
//Top-right vertex (corner)
glTexCoord2i(1, 0);
glVertex2f(GLfloat(right), GLfloat(top));
//Bottom-right vertex (corner)
glTexCoord2i(1, 1);
glVertex2f(GLfloat(right), GLfloat(bottom));
//Bottom-left vertex (corner)
glTexCoord2i(0, 1);
glVertex2f(GLfloat(left), GLfloat(bottom));
glEnd();
}
void DrawTextGL(int left, int top, TTF_Font* font, string text)
{
SDL_Color color = {255, 255, 255, 255};
SDL_Surface* textSurface;
textSurface = TTF_RenderText_Blended(font, text.c_str(), color);
GLuint Texture = SDLSurfaceToTexture(textSurface);
DrawRectangle(left, left + 260, top, top + 80, Color(255, 255, 255, 255), Texture);
SDL_FreeSurface(textSurface);
glDeleteTextures(1, &Texture);
}
GLuint SDLSurfaceToTexture(SDL_Surface* surface)
{
GLuint texture;
GLint nOfColors;
GLenum texture_format;
// get the number of channels in the SDL surface
nOfColors = surface->format->BytesPerPixel;
if (nOfColors == 4) // contains an alpha channel
{
if (surface->format->Rmask == 0x000000ff)
texture_format = GL_RGBA;
else
texture_format = GL_BGRA;
}
else if (nOfColors == 3)
{
if (surface->format->Rmask == 0x000000ff)
texture_format = GL_RGB;
else
texture_format = GL_BGR;
}
else
{
printf("Picture with less than 24-bit color depth detected.\n");
return 0;
}
// Have OpenGL generate a texture object handle for us
glGenTextures(1, &texture);
// Bind the texture object
glBindTexture(GL_TEXTURE_2D, texture);
// Set the texture's stretching properties
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Edit the texture object's image data using the information SDL_Surface gives us
glTexImage2D(GL_TEXTURE_2D, 0, nOfColors, surface->w, surface->h, 0,
texture_format, GL_UNSIGNED_BYTE, surface->pixels);
// Bind the texture to which subsequent calls refer to
glBindTexture(GL_TEXTURE_2D, texture);
return texture;
}
"New Bitmap Image.bmp" is just a bitmap with one white pixel in it. "FreeSerif.ttf" is a font taken from here.

Related

2d text artifact when depth test is enable Opengl

Main.cpp
//Variables
const unsigned int width = 896, height = 504;
//Initiating GLFW Window
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
//Creating a GLFW window
window = glfwCreateWindow(width, height, "Jaguar", NULL, NULL);
//Checking if Window was initiated
if (window == NULL) {
std::cout << "GLFW FAILED TO INITIATE WINDOW!\n";
glfwTerminate();
}
glfwMakeContextCurrent(window);
//Centering Window
int windowWidth, windowHeight;
glfwGetWindowSize(window, &windowWidth, &windowHeight);
const GLFWvidmode* mode = glfwGetVideoMode(glfwGetPrimaryMonitor());
glfwSetWindowPos(window, mode->width / 2 - windowWidth / 2, mode->height / 2 - windowHeight / 2);
//Setting-Up window's icon
GLFWimage icon[1];
icon[0].pixels = stbi_load("resources/images/gui/icon/icon.png", &icon[0].width, &icon[0].height, 0, 4);
glfwSetWindowIcon(window, 1, icon);
stbi_image_free(icon[0].pixels);
//Checking if Glad was initiated
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
std::cout << "GLAD FAILED TO BE INITIATED\n";
}
glEnable(GL_CULL_FACE);
glEnable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
stbi_set_flip_vertically_on_load(true);
//Setting-Up Viewport
glViewport(0, 0, width, height);
//Intitiating MainMenu
states.push(new MainMenuState(*window, &states));
font.cpp
FT_Library ft;
if (FT_Init_FreeType(&ft)) {
std::cout << "FREETYPE::Failed to initialize library\n";
}
FT_Face face;
if (FT_New_Face(ft, filePath, 0, &face)) {
std::cout << "FREETYPE::Failed to load to font: " << filePath << "\n";
}
// set size to load glyphs as
FT_Set_Pixel_Sizes(face, 0, px);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
for (unsigned char c = 0; c < 128; c++) {
if (FT_Load_Char(face, c, FT_LOAD_RENDER)) {
std::cout << "FREETYPE::Failed to load glpyh\n";
}
unsigned int texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, face->glyph->bitmap.width,
face->glyph->bitmap.rows, 0, GL_RED, GL_UNSIGNED_BYTE,
face->glyph->bitmap.buffer);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
Character character = {
texture,
glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows),
glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top)
,face->glyph->advance.x };
Characters.insert(std::pair<char, Character>(c, character));
}
FT_Done_Face(face);
FT_Done_FreeType(ft);
text.cpp
// activate corresponding render state
shader.use();
glUniform3f(glGetUniformLocation(shader.id, "textColor"), color.x, color.y,
color.z);
glActiveTexture(GL_TEXTURE0);
glBindVertexArray(VAO);
// iterate through all characters
std::string::const_iterator c;
for (c = string.begin(); c != string.end(); c++)
{
Character ch = font.Characters[*c];
float xpos = position.x + ch.bearing.x * scale;
float ypos = position.y - (ch.size.y - ch.bearing.y) * scale;
float w = ch.size.x * scale;
float h = ch.size.y * scale;
// update VBO for each character
float vertices[6][4] = {
{ xpos, ypos + h, 0.0f, 0.0f },
{ xpos, ypos, 0.0f, 1.0f },
{ xpos + w, ypos, 1.0f, 1.0f },
{ xpos, ypos + h, 0.0f, 0.0f },
{ xpos + w, ypos, 1.0f, 1.0f },
{ xpos + w, ypos + h, 1.0f, 0.0f }
};
// render glyph texture over quad
glBindTexture(GL_TEXTURE_2D, ch.textureId);
// update content of VBO memory
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// render quad
glDrawArrays(GL_TRIANGLES, 0, 6);
// now advance cursors for next glyph (note that advance is number of
1/64 pixels)
position.x += (ch.advance >> 6) * scale; // bitshift by 6 to get value in
pixels (2^6 = 64)
}
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
Things I have already done:
Render text last
used gl_src_alpha, gl_one_minus_src_alpha
when i have depth testing disable it works just fine do I just enable and disable when needed??
if so how bad/good is it when it come to performance(game smoothness)
I have done some research on it and people are saying enable alpha blending do they mean gl_src_alpha, gl_one_minus_src_alpha
When you use Blending, you must disable the Depth Test. Enable the depth test when you draw the geometry, but disable the depth test before drawing the text. The depth test causes fragments to be discarded depending on the depth function. Blending takes the fragment color outputs from the Fragment Shader and combines them with the colors in the color buffers. Hence Blending is only applied to those fragments that are not discarded.

SDL2 + OpenGL + SDL2_TTF: Displaying text

I'm having trouble getting a TTF font to draw in OpenGL plus SDL2.0.
I remember that before SDL version 2 I had no problems, but there seems to be a lack of documentation on the subject, perhaps due to the new standard.
I have included the code below to show generally what I am doing.
This code is very inefficient as I recreate the Texture every frame, take this into consideration if copy+pasting :)
void main_render() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//Set our color back to white (Full texture color)
glColor3f(1.0f, 1.0f, 1.0f);
mainCamera->perspective();
mainCamera->translate();
//Load the font
TTF_Font *font = TTF_OpenFont("../resource/font.ttf", 10);
if (font == nullptr) {
std::cout << "TTF_OpenFont error: " << std::endl;
return;
}
//Render font to a SDL_Surface
SDL_Color color = {0,0,255,80};
SDL_Surface *surface = TTF_RenderText_Blended(font, "Hi!", color);
if (surface == nullptr) {
TTF_CloseFont(font);
std::cout << "TTF_RenderText error: " << std::endl;
return;
}
//Create a SDL_Texture * from the surface
SDL_Texture * text = SDL_CreateTextureFromSurface(fontRender, surface);
if (text == nullptr){
std::cout << "SDL_CreateTextureFromSurface error: " << std::endl;
return;
}
//Bind the SDL_Texture in OpenGL
SDL_GL_BindTexture(text, NULL, NULL);
//Draw the SDL_Texture * as a Quad
glEnable(GL_TEXTURE_2D);
glBegin(GL_QUADS); {
glTexCoord2d(0, 0); glVertex3f(0, 0, 0);
glTexCoord2d(1, 0); glVertex3f(0 + surface->w, 0, 0);
glTexCoord2d(1, 1); glVertex3f(0 + surface->w, 0 + surface->h, 0);
glTexCoord2d(0, 1); glVertex3f(0, 0 + surface->h, 0);
} glEnd();
glDisable(GL_TEXTURE_2D);
//Cleanup
TTF_CloseFont(font);
SDL_DestroyTexture(text);
SDL_FreeSurface(surface);
//Swap the buffers to refresh the window
mainWindow->swap_buffers();
}
So OpenGL requires that all textures have dimensions of Base2 on my system (2,4,16,32,64...)
I fixed this problem by doing an incremental search for the closest power of two to the original dimension:
unsigned int power_two_floor(unsigned int val) {
unsigned int power = 2, nextVal = power*2;
while((nextVal *= 2) <= val)
power*=2;
return power*2;
}
I then ran into a snag: The texture was the correct color, yet the pixels were scrambled. This was fixed by copying the image to a RGB SDL_Surface, using the adjusted OpenGL dimensions.
//Find the first power of two for OpenGL image
int w = power_two_floor(surface->w)*2;
int h = power_two_floor(surface->h)*2;
//Create a surface to the correct size in RGB format, and copy the old image
SDL_Surface * s = SDL_CreateRGBSurface(0, w, h, 32, 0x00ff0000,0x0000ff00,0x000000ff,0xff000000);
SDL_BlitSurface(surface, NULL, s, NULL);
Adding filter information was required to correct OpenGL from utilizing mipmaps:
//Avoid mipmap filtering
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
Here is my answer:
unsigned int power_two_floor(unsigned int val) {
unsigned int power = 2, nextVal = power*2;
while((nextVal *= 2) <= val)
power*=2;
return power*2;
}
void main_render() {
//Load the font
TTF_Font *font = TTF_OpenFont("../resource/font.ttf", 10);
if (font == nullptr) {
std::cout << "TTF_OpenFont error: " << std::endl;
return;
}
SDL_Color colorFg = {0,0,255};
SDL_Surface *surface;
//Render font to a SDL_Surface
if ((surface = TTF_RenderText_Blended(font, "Hi!", colorFg)) == nullptr) {
TTF_CloseFont(font);
std::cout << "TTF_RenderText error: " << std::endl;
return;
}
GLuint texId;
//Generate OpenGL texture
glEnable(GL_TEXTURE_2D);
glGenTextures(1, &texId);
glBindTexture(GL_TEXTURE_2D, texId);
//Avoid mipmap filtering
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
//Find the first power of two for OpenGL image
int w = power_two_floor(surface->w)*2;
int h = power_two_floor(surface->h)*2;
//Create a surface to the correct size in RGB format, and copy the old image
SDL_Surface * s = SDL_CreateRGBSurface(0, w, h, 32, 0x00ff0000,0x0000ff00,0x000000ff,0xff000000);
SDL_BlitSurface(surface, NULL, s, NULL);
//Copy the created image into OpenGL format
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, s->pixels);
//Draw the OpenGL texture as a Quad
glBegin(GL_QUADS); {
glTexCoord2d(0, 1); glVertex3f(0, 0, 0);
glTexCoord2d(1, 1); glVertex3f(0 + surface->w, 0, 0);
glTexCoord2d(1, 0); glVertex3f(0 + surface->w, 0 + surface->h, 0);
glTexCoord2d(0, 0); glVertex3f(0, 0 + surface->h, 0);
} glEnd();
glDisable(GL_TEXTURE_2D);
//Cleanup
TTF_CloseFont(font);
SDL_FreeSurface(s);
SDL_FreeSurface(surface);
glDeleteTextures(1, &texId);
}

I can't display a texture on a quad

I am trying to wrap a texture on a quad.
All I see is a white rectangle:
To load the texture I used freeimage.
I need help in order to fix this very simple demo:
#include <GL/glut.h>
#include <GL/gl.h>
#include <FreeImage.h>
#include <stdio.h>
GLfloat coordinates[] =
{
-0.5, 0.5, 1,
-0.5, -0.5, 0,
0.5, -0.5, 0,
0.5, 0.5, 0
};
GLfloat texCoords[] =
{
0, 1,
0, 0,
1, 0,
1, 1
};
BYTE* data;
FIBITMAP* bitmap;
GLuint texture;
void initGlutCallbacks();
void initGL();
void onReshape(int w, int h);
void display();
FIBITMAP* loadTexture(const char* fileName);
int main(int argc, char** argv){
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
glutInitWindowSize(512, 512);
glutInitWindowPosition(64, 64);
glutCreateWindow("arrays");
initGlutCallbacks();
initGL();
// texture
bitmap = loadTexture("rufol.png");
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
data = FreeImage_GetBits(bitmap);
glTexImage2D(
GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0,
GL_RGBA8, GL_UNSIGNED_BYTE,
data
);
// enable arrays
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// specifying data for the arrays
glVertexPointer
(
3, GL_FLOAT, 0, coordinates
);
glTexCoordPointer
(
2, GL_FLOAT, 0, texCoords
);
glutMainLoop();
}
void initGlutCallbacks(){
glutReshapeFunc(onReshape);
glutDisplayFunc(display);
}
void initGL(){
glClearColor(0.0, 0.0, 0.0, 0.0);
glClearDepth(1.0);
glEnable ( GL_TEXTURE_2D );
}
void onReshape(int w, int h){
}
void display(){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glTexEnvf(GL_TEXTURE_2D, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glDrawArrays(GL_QUADS, 0, 4);
glFlush();
glutSwapBuffers();
}
FIBITMAP* loadTexture(const char* fileName){
FIBITMAP *bitmap = FreeImage_Load(FIF_PNG, "rufol.png");
if(bitmap == 0) printf("error loading the image\n");
FIBITMAP *fbitmap = FreeImage_ConvertTo32Bits(bitmap);
FreeImage_Unload(bitmap);
return fbitmap;
}
As you can see I am not even using perspective. Also lighting is not enabled(I don't know if it is required to display textures). I have tested a very similar code but using colors for each vertex instead of texture coordinates and it worked. So I think it might be something wrong when loading the image.
Have you tried using GL_RGBA instead of GL_RGBA8 as second parameter (format)?

rendering bmp not appearing

i can't seem to load a bitmap and display it :S ... does anyone know what is wrong here? my bmp is 256 x 265 in size. I currently can only see a black screen (nothing is being shown). Any help would be appreciated!
int DrawGLScene(GLvoid) // Here's Where We Do All The Drawing
{
GLuint texture = LoadBMP("C:/Untitled.bmp");
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture);
glBegin(GL_QUADS);
glTexCoord2d(2.8f, 2.8f); glVertex2f(2.8f, 2.8f);
glTexCoord2d(2.8f, 2.8f); glVertex2f(2.8f, 2.8f);
glTexCoord2d(2.8f, 2.8f); glVertex2f(2.8f, 2.8f);
glTexCoord2d(2.8f, 2.8f); glVertex2f(2.8f, 2.8f);
glEnd();
glDisable(GL_TEXTURE_2D);
return TRUE; // Keep Going
}
GLuint LoadBMP(const char *fileName)
{
FILE *file;
unsigned char header[54];
unsigned int dataPos;
unsigned int size;
unsigned int width, height;
unsigned char *data;
file = fopen(fileName, "rb");
if (file == NULL)
{
MessageBox(NULL, L"Error: Invaild file path!", L"Error", MB_OK);
return false;
}
if (fread(header, 1, 54, file) != 54)
{
MessageBox(NULL, L"Error: Invaild file!", L"Error", MB_OK);
return false;
}
if (header[0] != 'B' || header[1] != 'M')
{
MessageBox(NULL, L"Error: Invaild file!", L"Error", MB_OK);
return false;
}
dataPos = (int)&(header[0x0A]);
size = (int)&(header[0x22]);
width = (int)&(header[0x12]);
height = (int)&(header[0x16]);
if (size == NULL)
size = width * height * 3;
if (dataPos == NULL)
dataPos = 54;
data = new unsigned char[size];
fread(data, 1, size, file);
fclose(file);
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
return texture;
}
Of course you do not see anything, you are using the same texture coordinate for every vertex :)
Texture coordinates in OpenGL (unless you are using something like a special rectangle texture) are normalized in the range 0.0 - 1.0. Where (0.0, 0.0) represents the bottom-left corner of the image and (1.0, 1.0) represents the top-right. You should consider stretching the image over your quad exactly one time, so use a combination of all four corners for your coordinates.
Also, use glTexCoord2f (...) since you are clearly using single-precision floating-point coordinates and not double-precision.
Consider this instead:
glBegin( GL_QUADS);
glTexCoord2f (0.0f, 0.0f); glVertex2f (-1.0f, -1.0f);
glTexCoord2f (0.0f, 1.0f); glVertex2f (-1.0f, 1.0f);
glTexCoord2f (1.0f, 1.0f); glVertex2f ( 1.0f, 1.0f);
glTexCoord2f (1.0f, 0.0f); glVertex2f ( 1.0f, -1.0f);
glEnd ();
This code addresses two issues:
It will stretch your bitmap over the quad exactly one time
The vertex coordinates will cover your entire viewport

Using SDL_ttf with OpenGL

I'm using OpenGL and SDL to create a window in my program.
How do I use SDL_ttf with an OpenGL window?
For example I want to load a font and render some text. I want to draw the text using an SDL OpenGL surface.
Here's how to do it:
Initialize SDL and SDL_ttf, and create a window using SDL_SetVideoMode(). Make sure you pass the SDL_OPENGL flag.
Initialize your OpenGL scene (glViewport(), glMatrixMode() etc.).
Render your text with SDL_ttf using e.g. TTF_RenderUTF8_Blended(). The render functions return an SDL_surface, which you have to convert into an OpenGL texture by passing a pointer to the data (surface->pixels) to OpenGL as well as the format of the data. Like this:
colors = surface->format->BytesPerPixel;
if (colors == 4) { // alpha
if (surface->format->Rmask == 0x000000ff)
texture_format = GL_RGBA;
else
texture_format = GL_BGRA;
} else { // no alpha
if (surface->format->Rmask == 0x000000ff)
texture_format = GL_RGB;
else
texture_format = GL_BGR;
}
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, colors, surface->w, surface->h, 0,
texture_format, GL_UNSIGNED_BYTE, surface->pixels);
Then you can use the texture in OpenGL using glBindTexture() etc. Make sure to call SDL_GL_SwapBuffers() when you're done with drawing.
Based off of: http://content.gpwiki.org/index.php/SDL_ttf:Tutorials:Fonts_in_OpenGL
The code below is an example of how you can render the text on top of finished 3D model you may have built.
#include "SDL.h"
#include "SDL_ttf.h"
/.../
void RenderText(std::string message, SDL_Color color, int x, int y, int size) {
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
gluOrtho2D(0, m_Width, 0, m_Height); // m_Width and m_Height is the resolution of window
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glDisable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
TTF_Font * font = TTF_OpenFont("pathToFont.ttf", size);
SDL_Surface * sFont = TTF_RenderText_Blended(font, message, color);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, sFont->w, sFont->h, 0, GL_BGRA, GL_UNSIGNED_BYTE, sFont->pixels);
glBegin(GL_QUADS);
{
glTexCoord2f(0,0); glVertex2f(x, y);
glTexCoord2f(1,0); glVertex2f(x + sFont->w, y);
glTexCoord2f(1,1); glVertex2f(x + sFont->w, y + sFont->h);
glTexCoord2f(0,1); glVertex2f(x, y + sFont->h);
}
glEnd();
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glDeleteTextures(1, &texture);
TTF_CloseFont(font);
SDL_FreeSurface(sFont);
}
/.../
int main() {
/.../ Render 3D stuff here
// Prints out "Hello World" at location (5,10) at font size 12!
SDL_Color color = {255, 0, 0, 0}; // Red
RenderText("Hello World", color, 5, 10, 12);
/.../
return 0;
}