Skip to content

Instantly share code, notes, and snippets.

@StonedXander
Created March 15, 2012 14:08
Show Gist options
  • Save StonedXander/2044361 to your computer and use it in GitHub Desktop.
Save StonedXander/2044361 to your computer and use it in GitHub Desktop.
GL Textured Font
#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;
}
#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
#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;
}
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
<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