Author Topic: fonts in opengl  (Read 2670 times)

0 Members and 1 Guest are viewing this topic.

Offline Merick

  • Atari ST
  • ***
  • Posts: 113
  • Karma: 7
    • View Profile
fonts in opengl
« on: November 17, 2007 »
I've been trying to convert an opengl ttf lib to FB, but although it compiles without errors it crashes when I try to run it. Can anyone tell me what I did wrong?

original code:

Code: [Select]
/***************************************************************************/
/*                                                                         */
/*  FontGL.h                                                               */
/*                                                                         */
/*  FontGL: An OpenGL font-rendering library.                              */
/*                                                                         */
/*  Copyright 2006-2007 by Eric Newman.                                    */
/*  Contact: e.newman@mat.ucsb.edu                                         */
/*                                                                         */
/*  FontGL may be freely used and modified for non-commercial purposes by  */
/*  any individual, organization, or entity. However, please be kind and   */
/*  cite the author's work where appropriate.                              */
/*                                                                         */
/***************************************************************************/

#ifndef FONTGL_INCLUDE_H
#define FONTGL_INCLUDE_H

#if defined (__APPLE__) || defined (OSX)

#include <OpenGL/OpenGL.h>
#include <OpenGL/glu.h>

#elif defined (__LINUX__) || defined (UNIX)

#include <GL/gl.h>
#include <GL/glu.h>

#elif defined WIN32

#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>

#endif

#include <ft2build.h>
#include FT_FREETYPE_H

#define ASCII_SIZE 255 // number of characters to use

typedef struct
{
float r, g, b, a;
}
FontGLColor;

class FontGL
{
public:

FontGL(char *fontName, int fontSize, bool antiAliased = true, bool cacheGlyphs = false);
~FontGL();

// renders a text string at the specified 3D position
void render(float x, float y, float z, const char *text);

// returns the width of a text string in pixels
float advance(const char *text);

// returns the "above-line" height of the font in pixels
float ascender() { if (face) return face->size->metrics.ascender/64.f; else return 0.f; }

// returns the "below-line" height of the font in pixels
float descender() { if (face) return face->size->metrics.descender/64.f; else return 0.f; }

// returns the total height of the font in pixels
int size() { return fontsize; }

// sets the color of the font
void setColor(float R, float G, float B, float A)
{ color->r = R; color->g = G; color->b = B; color->a = A; }

// these texture functions are necessary if your app
// creates/destroys multiple windows while running.
// you might also want to set cacheGlyphs to true
// (keeps the font in main memory - a bit faster)
void initTextures();
void uninitTextures();

private:

FT_Library *FontGL_Library;
FT_Face face;
FontGLColor *color;
GLuint *textures;
int *widths, *vOffsets, fontsize, textureSize;
bool antialiased, cacheglyphs;
unsigned char *glyphImages[ASCII_SIZE];

void loadTexture(int textureNum, unsigned char *glyphImage);
void loadGlyph(int glyphNum, unsigned char *glyphImage);
};

#endif

Code: [Select]
/***************************************************************************/
/*                                                                         */
/*  FontGL.cpp                                                             */
/*                                                                         */
/*  FontGL: An OpenGL font-rendering library.                              */
/*                                                                         */
/*  Copyright 2006-2007 by Eric Newman.                                    */
/*  Contact: e.newman@mat.ucsb.edu                                         */
/*                                                                         */
/*  FontGL may be freely used and modified for non-commercial purposes by  */
/*  any individual, organization, or entity. However, please be kind and   */
/*  cite the author's work where appropriate.                              */
/*                                                                         */
/***************************************************************************/

#include "FontGL.h"

FontGL::FontGL(char *fontName, int fontSize, bool antiAliased, bool cacheGlyphs)
{
FontGL_Library = new FT_Library;
FT_Init_FreeType(FontGL_Library);

face = 0;
FT_New_Face(*FontGL_Library, fontName, 0, &face);

fontsize = fontSize;
antialiased = antiAliased;
cacheglyphs = cacheGlyphs;

if (face)
FT_Set_Char_Size(face, 0, fontsize * 64, 0, 0);

color = new FontGLColor;
setColor(1.f, 1.f, 1.f, 1.f);

widths = new int[ASCII_SIZE];
vOffsets = new int[ASCII_SIZE];
textures = new GLuint[ASCII_SIZE];

memset(widths, 0, sizeof(int) * ASCII_SIZE);
memset(vOffsets, 0, sizeof(int) * ASCII_SIZE);
memset(textures, 0, sizeof(int) * ASCII_SIZE);

textureSize = 1;
while (textureSize < fontsize) textureSize *= 2;

if (cacheglyphs)
{
for (int i=0; i<ASCII_SIZE; i++)
{
glyphImages[i] = new unsigned char[textureSize * textureSize * 2];
loadGlyph(i, glyphImages[i]);
}
}

initTextures();
}

FontGL::~FontGL()
{
uninitTextures();

if (cacheglyphs)
{
for (int i=0; i<ASCII_SIZE; i++)
delete glyphImages[i];
}

delete textures;
delete widths;
delete vOffsets;

delete color;

if (face)
FT_Done_Face(face);

FT_Done_FreeType(*FontGL_Library);
delete FontGL_Library;
}

void FontGL::initTextures()
{
glGenTextures(ASCII_SIZE, textures);

if (cacheglyphs)
{
for (int i=0; i<ASCII_SIZE; i++)
loadTexture(i, glyphImages[i]);
}
else
{
unsigned char *glyphImage = new unsigned char[textureSize * textureSize * 2];

for (int i=0; i<ASCII_SIZE; i++)
{
loadGlyph(i, glyphImage);
loadTexture(i, glyphImage);
}

delete glyphImage;
}
}

void FontGL::loadGlyph(int glyphNum, unsigned char *glyphImage)
{
memset(glyphImage, 0, textureSize * textureSize * 2);

if (face)
{
int j, k, l;
int glyph_index;

glyph_index = FT_Get_Char_Index(face, glyphNum);

if (antialiased)
{
FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
}
else
{
FT_Load_Glyph(face, glyph_index, FT_LOAD_MONOCHROME);
FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO);
}

widths[glyphNum] = face->glyph->advance.x/64;
vOffsets[glyphNum] = face->glyph->bitmap_top;

FT_Bitmap *bitmap = &face->glyph->bitmap;

if (antialiased)
{
for (j=0; j<bitmap->rows; j++)
{
for (k=0; k<bitmap->width; k++)
{
glyphImage[(j * textureSize * 2) + (k * 2)] = 255;
glyphImage[(j * textureSize * 2) + (k * 2) + 1] = bitmap->buffer[j * bitmap->width + k];
}
}
}
else
{
unsigned char temp;

for (j=0; j<bitmap->rows; j++)
{
for (k=0; k<bitmap->pitch; k++)
{
for (l=7; l>=0; l--)
{
temp = (bitmap->buffer[j * bitmap->pitch + k] >> l) & 1;

if (temp)
{
glyphImage[(j * textureSize * 2) + ((k * 8 + (7 - l)) * 2)] = 255;
glyphImage[(j * textureSize * 2) + ((k * 8 + (7 - l)) * 2) + 1] = 255;
}
}
}
}
}
}
}

void FontGL::loadTexture(int textureNum, unsigned char *glyphImage)
{
glBindTexture(GL_TEXTURE_2D, textures[textureNum]);
glTexImage2D(GL_TEXTURE_2D, 0, 2, textureSize, textureSize, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, glyphImage);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
}

void FontGL::uninitTextures()
{
glDeleteTextures(ASCII_SIZE, textures);
}

float FontGL::advance(const char *text)
{
float total = 0.f;

for (int i=0; i<(int) strlen(text); i++)
total += widths[text[i]];

return total;
}

void FontGL::render(float x, float y, float z, const char *text)
{
glPushAttrib(GL_ENABLE_BIT);

glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glDisable(GL_DEPTH_TEST);

GLint blendDest, blendSource;
glGetIntegerv(GL_BLEND_DST, &blendDest);
glGetIntegerv(GL_BLEND_SRC, &blendSource);

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

glPushMatrix();

glTranslatef(x, y, z);
glColor4f(color->r, color->g, color->b, color->a);

int width, vOffset;

for (unsigned i=0; i<strlen(text); i++)
{
width = widths[text[i]];
vOffset = vOffsets[text[i]];

glBindTexture(GL_TEXTURE_2D, textures[text[i]]);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex3f(0.f, (float) (-vOffset), 0.f);
glTexCoord2f(0.0, 1.0); glVertex3f(0.f, (float) (-vOffset + textureSize), 0.f);
glTexCoord2f(1.0, 1.0); glVertex3f((float) textureSize, (float) (-vOffset + textureSize), 0.f);
glTexCoord2f(1.0, 0.0); glVertex3f((float) textureSize, (float) (-vOffset), 0.f);
glEnd();

glTranslatef((float) width, 0.f, 0.f);
}

glPopMatrix();

glPopAttrib();

glBlendFunc(blendSource, blendDest);
}

my translation:

Code: [Select]
/'***************************************************************************/
/*                                                                         */
/*  FontGL.bi                                                              */
/*                                                                         */
/*  FontGL: An OpenGL font-rendering library.                              */
/*    original code                                                                     */
/*  Copyright 2006-2007 by Eric Newman.                                    */
/*  Contact: e.newman@mat.ucsb.edu                                         */
/*                                                                         */
/*  FontGL may be freely used and modified for non-commercial purposes by  */
/*  any individual, organization, or entity. However, please be kind and   */
/*  cite the author's work where appropriate.                              */
/*                                                                         */
/***************************************************************************'/

' FreeBasic version by Merick

#ifndef FONTGL_INCLUDE_BI
#define FONTGL_INCLUDE_BI

#ifdef __FB_LINUX__
#include "GL/gl.bi"
#include "GL/glu.bi"
#endif
#ifdef __FB_WIN32__
#include once "windows.bi"
#include once "gl/gl.bi"
#include once "gl/glu.bi"
#endif

#ifndef FALSE
#define FALSE 0
#define TRUE (Not FALSE)
#endif

#include once "freetype2/freetype.bi"

#define ASCII_SIZE 255 ' number of characters to use

type FontGLColor
r as single
g as single
b as single
a as single
end type


type FontGL

Public:
declare constructor (byval fontName as zstring ptr, byval fontSize as integer, byval antiAliased as integer = true, byval cacheGlyphs as integer = false)
Declare Destructor ( )

' renders a text string at the specified 3D position
declare sub render(x as single, y as single, z as single, text as zstring ptr)

' returns the width of a text string in pixels
declare function advance(text as zstring ptr) as single

' returns the "above-line" height of the font in pixels
declare function ascender() as single

' returns the "below-line" height of the font in pixels
declare function descender() as single

' returns the total height of the font in pixels
declare function size() as integer

' sets the color of the font
declare sub setColor(R as single, G as single, B as single, A as single)

' these texture functions are necessary if your app
' creates/destroys multiple windows while running.
' you might also want to set cacheGlyphs to true
' (keeps the font in main memory - a bit faster)
declare sub initTextures()
declare sub uninitTextures()

private:

FontGL_Library as FT_Library ptr
face as FT_Face
c as FontGLColor ptr
textures as GLuint ptr
widths as integer ptr
vOffsets as integer ptr
fontsize as integer
textureSize as integer
antialiased as integer
cacheglyphs as integer

glyphImages(ASCII_SIZE) as ubyte ptr

declare sub loadTexture(textureNum as integer, glyphImage as ubyte ptr)
declare sub loadGlyph(glyphNum as integer, glyphImage as ubyte ptr)
end type

function FontGL.ascender() as single
if (face) then
return face->size->metrics.ascender/64
else
return 0
endif
end function

function FontGL.descender() as single
if (face) then
return face->size->metrics.descender/64
else
return 0
endif
end function

function FontGL.size() as integer
return fontsize
end function

sub FontGL.setColor(R as single, G as single, B as single, A as single)
c->r = R
c->g = G
c->b = B
c->a = A
end sub

#endif

Code: [Select]
/'***************************************************************************/
/*                                                                         */
/*  FontGL.bas                                                            */
/*                                                                         */
/*  FontGL: An OpenGL font-rendering library.                              */
/*     original code                                                                    */
/*  Copyright 2006-2007 by Eric Newman.                                    */
/*  Contact: e.newman@mat.ucsb.edu                                         */
/*                                                                         */
/*  FontGL may be freely used and modified for non-commercial purposes by  */
/*  any individual, organization, or entity. However, please be kind and   */
/*  cite the author's work where appropriate.                              */
/*                                                                         */
/***************************************************************************'/

' FreeBasic version by Merick

#include once "FontGL.bi"
#include once "crt/string.bi"

constructor FontGL (byval fName as zstring ptr, byval fSize as integer, byval aAliased as integer = true, byval cGlyphs as integer = false)

FontGL_Library = new FT_Library
FT_Init_FreeType(FontGL_Library)

face = 0
FT_New_Face(*FontGL_Library, fName, 0, @face)

fontsize = fSize
antialiased = aAliased
cacheglyphs = cGlyphs

if (face) then FT_Set_Char_Size(face, 0, fontsize * 64, 0, 0)

c = new FontGLColor
setColor(1.0, 1.0, 1.0, 1.0)

widths = new integer(ASCII_SIZE)
vOffsets = new integer(ASCII_SIZE)
textures = new GLuint(ASCII_SIZE)

memset(widths, 0, sizeof(integer) * ASCII_SIZE)
memset(vOffsets, 0, sizeof(integer) * ASCII_SIZE)
memset(textures, 0, sizeof(integer) * ASCII_SIZE)

textureSize = 1
while (textureSize < fontsize)
textureSize *= 2
wend

if cacheglyphs = true then
dim as integer i
for i= 0 to ASCII_SIZE-1
glyphImages(i) = new ubyte (textureSize * textureSize * 2)
loadGlyph(i, glyphImages(i))
next
endif

initTextures()
end constructor

destructor FontGL()
uninitTextures()

if cacheglyphs = true then
dim as integer i
for i = 0 to ASCII_SIZE -1
delete glyphImages(i)
next
endif

delete textures
delete widths
delete vOffsets

delete c

if (face) then FT_Done_Face(face)

FT_Done_FreeType(*FontGL_Library)
delete FontGL_Library
end destructor

sub FontGL.initTextures()
glGenTextures(ASCII_SIZE, textures)

if cacheglyphs = true then
dim as integer i
for i = 0 to ASCII_SIZE -1
loadTexture(i, glyphImages(i))
next
else
dim as ubyte ptr glyphImage = new ubyte(textureSize * textureSize * 2)

dim as integer i
for i = 0 to ASCII_SIZE -1
loadGlyph(i, glyphImage)
loadTexture(i, glyphImage)
next
delete glyphImage
endif
end sub

sub FontGL.loadGlyph(glyphNum as integer, glyphImage as ubyte ptr)
memset(glyphImage, 0, textureSize * textureSize * 2)

if (face) then
dim as integer j, k, l
dim as integer glyph_index

glyph_index = FT_Get_Char_Index(face, glyphNum)

if antialiased = true then
FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT)
FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL)
else
FT_Load_Glyph(face, glyph_index, FT_LOAD_MONOCHROME)
FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO)
endif

widths[glyphNum] = face->glyph->advance.x/64
vOffsets[glyphNum] = face->glyph->bitmap_top

dim as FT_Bitmap ptr bitmap = @(face->glyph->bitmap)

if antialiased = true then
for j = 0 to bitmap->rows -1
for k = 0 to bitmap->width -1
glyphImage[(j * textureSize * 2) + (k * 2)] = 255
glyphImage[(j * textureSize * 2) + (k * 2) + 1] = bitmap->buffer[j * bitmap->width + k]
next
next
else
dim as ubyte temp

for j = 0 to bitmap->rows -1
for k = 0 to bitmap->pitch -1
for l = 7 to 1 step -1
temp = (bitmap->buffer[j * bitmap->pitch + k] shr l) and 1

if temp then
glyphImage[(j * textureSize * 2) + ((k * 8 + (7 - l)) * 2)] = 255
glyphImage[(j * textureSize * 2) + ((k * 8 + (7 - l)) * 2) + 1] = 255
endif
next
next
next
endif
endif
end sub

sub FontGL.loadTexture(textureNum as integer, glyphImage as ubyte ptr)
glBindTexture(GL_TEXTURE_2D, textures[textureNum])
glTexImage2D(GL_TEXTURE_2D, 0, 2, textureSize, textureSize, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, glyphImage)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
end sub

sub FontGL.uninitTextures()
glDeleteTextures(ASCII_SIZE, textures)
end sub

function FontGL.advance(text as zstring ptr) as single
dim as single total = 0
dim as integer i
for i = 0 to (len(text)-1)
total += widths[text[i]]
next
return total
end function

sub FontGL.render(x as single, y as single, z as single, text as zstring ptr)
glPushAttrib(GL_ENABLE_BIT)

glEnable(GL_TEXTURE_2D)
glEnable(GL_BLEND)
glDisable(GL_DEPTH_TEST)

dim as GLint blendDest, blendSource
glGetIntegerv(GL_BLEND_DST, @blendDest)
glGetIntegerv(GL_BLEND_SRC, @blendSource)

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

glPushMatrix()

glTranslatef(x, y, z)
glColor4f(c->r, c->g, c->b, c->a)

dim as integer w, vOffset

dim as integer i
for i =0 to (len(text)-1)

w = widths[text[i]]
vOffset = vOffsets[text[i]]

glBindTexture(GL_TEXTURE_2D, textures[text[i]])
glBegin(GL_QUADS)
glTexCoord2f(0.0, 0.0): glVertex3f(0.f, (-vOffset), 0.f)
glTexCoord2f(0.0, 1.0): glVertex3f(0.f, (-vOffset + textureSize), 0.f)
glTexCoord2f(1.0, 1.0): glVertex3f(textureSize, (-vOffset + textureSize), 0.f)
glTexCoord2f(1.0, 0.0): glVertex3f(textureSize, (-vOffset), 0.f)
glEnd()

glTranslatef(w, 0.f, 0.f)
next

glPopMatrix()

glPopAttrib()

glBlendFunc(blendSource, blendDest)
end sub

my test program:

Code: [Select]
#include once "fbgfx.bi"
#include once "gl/gl.bi"
#include once "gl/glu.bi"

#include once "FontGL.bas"


open cons for output as #1

screenres 640, 480,,,FB.GFX_OPENGL

glViewport 0, 0, 640, 480                     
glMatrixMode GL_PROJECTION                     
glLoadIdentity                                 
gluPerspective 45.0, 640.0/480.0, 0.1, 100.0   
glMatrixMode GL_MODELVIEW                     
glLoadIdentity                                 

glShadeModel GL_SMOOTH                       
glClearColor 0.0, 0.0, 0.0, 0.5               
glClearDepth 1.0                               
glEnable GL_DEPTH_TEST                       
glDepthFunc GL_LEQUAL                       
glHint GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST   


dim as FontGL sdf  = FontGL(@"sdf.ttf", 10, true, true)


while not multikey(FB.SC_ESCAPE)
glClear(GL_DEPTH_BUFFER_BIT or GL_COLOR_BUFFER_BIT)
sdf.render(0, 0, -5, @"Hello World!")
flip
wend

Offline Rbz

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 2757
  • Karma: 493
    • View Profile
    • https://www.rbraz.com/
Re: fonts in opengl
« Reply #1 on: November 19, 2007 »
Well, I tried to help you here, but I didn't find anything obviously wrong   :-\

Try to debug it, inspecting where it stop working, for example you can check if FB is allocating/setting memory correctly or check error messages of commands like "FT_Init_FreeType" etc.

I don't remember if FB have a way to debug a program in realtime, anyway you can create your own "breakpoints" using for example "MessageBox".
Challenge Trophies Won:

Offline Merick

  • Atari ST
  • ***
  • Posts: 113
  • Karma: 7
    • View Profile
Re: fonts in opengl
« Reply #2 on: November 20, 2007 »
OK, I've done some testing and although I don't know exactly what's wrong,  I've found that the crash occurs inside the type constructor, at this section of code:

Code: [Select]
memset(widths, 0, sizeof(integer) * ASCII_SIZE)
memset(vOffsets, 0, sizeof(integer) * ASCII_SIZE)  <-- crashes here
memset(textures, 0, sizeof(integer) * ASCII_SIZE)

if I comment those out, it will continue, but only until it hits this statment:

loadGlyph(i, glyphImages(i))
« Last Edit: November 20, 2007 by Merick »