Created
March 15, 2012 14:08
-
-
Save StonedXander/2044361 to your computer and use it in GitHub Desktop.
GL Textured Font
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "font.h" | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <fcntl.h> | |
#include <unistd.h> | |
#include <string.h> // TODO change to <string> | |
#include <stdlib.h> | |
#include <iostream> | |
#include <SOIL/SOIL.h> | |
#define XML_READING_BUFFER_SIZE 65536 | |
Font::Font() : texture(0) {} | |
void Font::startElementHandler(void *userData, | |
const XML_Char *name, | |
const XML_Char **atts) { | |
Font *font = (Font *) userData; | |
font->startElement(name, atts); | |
} | |
void Font::endElementHandler(void *userData, | |
const XML_Char *name) { | |
Font *font = (Font *) userData; | |
font->endElement(name); | |
} | |
void Font::load(const char *filename) { | |
char buffer[XML_READING_BUFFER_SIZE]; | |
int handle = open(filename, O_RDONLY); | |
ssize_t rdLen; | |
if(handle < 0) { | |
// ERROR | |
return; | |
} | |
XML_Parser parser = XML_ParserCreate(NULL); | |
XML_SetUserData(parser, this); | |
XML_SetElementHandler(parser, startElementHandler, endElementHandler); | |
while((rdLen = read(handle, buffer, XML_READING_BUFFER_SIZE)) > 0) { | |
if(!XML_Parse(parser, buffer, rdLen, rdLen < XML_READING_BUFFER_SIZE)) { | |
// ERROR | |
break; | |
} | |
} | |
XML_ParserFree(parser); | |
close(handle); | |
} | |
void Font::startElement(const XML_Char *name, const XML_Char **atts) { | |
if(strcmp(name, "font") == 0) { | |
// Texture Loading. | |
// First, retrieve the attribute. | |
if((atts[0] != 0) && (strcmp(atts[0], "texture") == 0)) { | |
std::cout << "Load font " << atts[1] << std::endl; | |
texture = SOIL_load_OGL_texture( atts[1], SOIL_LOAD_AUTO, | |
SOIL_CREATE_NEW_ID, | |
SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y | | |
SOIL_FLAG_NTSC_SAFE_RGB); | |
// This is utterly BAD | |
if(texture != 0) { | |
glBindTexture(GL_TEXTURE_2D, texture); | |
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width); | |
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height); | |
} | |
std::cout << "Stored in unit " << texture << std::endl; | |
} | |
} else if(strcmp(name, "glyph") == 0) { | |
// Manage attributes for glyph creation. | |
char c = 0; | |
double ua, ub, va, vb, w, h, ad, bs; | |
for(int j = 0; atts[j] != 0; j += 2) { | |
if(strcmp(atts[j], "char") == 0) { | |
c = atts[j+1][0]; | |
} else { | |
int value = atoi(atts[j+1]); | |
if(strcmp(atts[j], "ua") == 0) { | |
ua = value; | |
} else if(strcmp(atts[j], "ub") == 0) { | |
ub = value; | |
} else if(strcmp(atts[j], "va") == 0) { | |
va = value; | |
} else if(strcmp(atts[j], "vb") == 0) { | |
vb = value; | |
} else if(strcmp(atts[j], "advance") == 0) { | |
ad = value; | |
} else if(strcmp(atts[j], "base") == 0) { | |
bs = value; | |
} | |
} | |
} | |
w = ub - ua; | |
h = vb - va; | |
ua /= (double) width; | |
ub /= (double) width; | |
va /= (double) height; | |
vb /= (double) height; | |
va = 1 - va; | |
vb = 1 - vb; | |
Glyph *gl = glyphs + c; | |
gl->setSize(w, h); | |
gl->setCoordinate(ua, ub, va, vb); | |
gl->setChar(ad, bs); | |
std::cout << "Char '" << c << "' " << w << "x" << h << " @(" << ua; | |
std::cout << ", " << va << " - " << ub << ", " << vb << ") "; | |
std::cout << "A = " << ad << ", B = " << bs << std::endl; | |
} | |
} | |
void Font::endElement(const XML_Char *name) { | |
// Nutting ! | |
} | |
void Font::render(const char *s, | |
double x, double y, | |
double r, double g, double b) { | |
const char *glyph; | |
glColor3d(r, g, b); | |
glBindTexture(GL_TEXTURE_2D, texture); | |
// TODO Line wrapping. | |
for(glyph = s; *glyph != 0; ++glyph) { | |
x += glyphs[*glyph].render(x, y); | |
} | |
} | |
double Glyph::render(double x, double y) { | |
glBegin(GL_QUADS); | |
y += base; | |
glTexCoord2d(ua, va); | |
glVertex2d(x, y); | |
x += w; | |
glTexCoord2d(ub, va); | |
glVertex2d(x, y); | |
y -= h; | |
glTexCoord2d(ub, vb); | |
glVertex2d(x, y); | |
x -= w; | |
glTexCoord2d(ua, vb); | |
glVertex2d(x, y); | |
glEnd(); | |
return advance; | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef _FONT_H_ | |
#define _FONT_H_ | |
#include <GL/glfw.h> | |
#include <expat.h> | |
// We'll try to make an UTF-8 font. | |
// But first, ASCII font. | |
class Glyph { | |
public: | |
Glyph() {} | |
void setSize(double width, double height) { | |
w = width; | |
h = height; | |
} | |
void setCoordinate(double uua, double uub, double vva, double vvb) { | |
ua = uua; | |
ub = uub; | |
va = vva; | |
vb = vvb; | |
} | |
void setChar(double ad, double bs) { | |
advance = ad; | |
base = bs; | |
} | |
// Render the glyph. | |
double render(double, double); | |
private: | |
double w; | |
double h; | |
double ua; | |
double ub; | |
double va; | |
double vb; | |
double advance; | |
double base; | |
}; | |
class Font { | |
public: | |
// Obvious constructor. | |
Font(); | |
// Load the font from an XML description file. | |
void load(const char *); | |
// Render a string. No wrap. | |
void render(const char *, double, double, double, double, double); | |
private: | |
void startElement(const XML_Char *, const XML_Char **); | |
void endElement(const XML_Char *); | |
static void startElementHandler(void *, const XML_Char *, | |
const XML_Char **); | |
static void endElementHandler(void *, const XML_Char *); | |
private: | |
// Texture hosting the font. | |
GLuint texture; | |
int width; | |
int height; | |
Glyph glyphs[256]; | |
}; | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "font.h" | |
#define WINDOW_WIDTH 300 | |
#define WINDOW_HEIGHT 50 | |
int main(int argc, char **argv) { | |
Font font; | |
glfwInit(); | |
if (glfwOpenWindow(WINDOW_WIDTH, WINDOW_HEIGHT, 8, 8, 8, | |
0, 0, 0, GLFW_WINDOW) != GL_TRUE) | |
return -1; | |
glfwSetWindowTitle("The GLFW Window"); | |
glEnable(GL_DEPTH_TEST); | |
glEnable(GL_TEXTURE_2D); | |
glEnable(GL_BLEND); | |
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
glClearColor(0.6, 0.7, 0.9, 0); | |
glMatrixMode(GL_PROJECTION); | |
glLoadIdentity(); | |
glOrtho(0, WINDOW_WIDTH, 0, WINDOW_HEIGHT, -1, 1); | |
glMatrixMode(GL_MODELVIEW); | |
font.load(argv[1]); | |
while(1) { | |
if(glfwGetKey(GLFW_KEY_ESC) == GLFW_PRESS) | |
break; | |
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |
glLoadIdentity(); | |
font.render("abbaceba", 10, 50, 1, 1, 1); | |
glfwSwapBuffers(); | |
} | |
glfwTerminate(); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
font.o: font.h font.c | |
g++ -c font.c -I. | |
main.o: main.c font.h | |
g++ -c main.c -I. | |
all: main.o font.o | |
g++ main.o font.o -o speedcoding -lexpat -lglfw -lSOIL | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<font texture="texture.png"> | |
<glyph char="a" ua="0" ub="32" va="0" vb="32" advance="32" base="0"/> | |
<glyph char="b" ua="32" ub="64" va="0" vb="32" advance="32" base="0"/> | |
<glyph char="c" ua="64" ub="96" va="0" vb="32" advance="32" base="0"/> | |
<glyph char="d" ua="96" ub="128" va="0" vb="32" advance="32" base="0"/> | |
<glyph char="e" ua="0" ub="32" va="32" vb="64" advance="32" base="0"/> | |
</font> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment