Ok so after using the font tutorial I found on Cone3d, I decided to try and make it into its own font class that I could plug into my engine (completed Pong, Tetris, Space Invaders, working on a 2d side scroller at the moment).
I havn't really made a lot of chances but at the moment it looks like this.
CFont header:
#ifndef __FONT_H__
#define __FONT_H__
#include "SDL.h"
class CFont
{
public:
int initFont(char *dir, float r, float g, float b, float a);
void drawString(SDL_Surface *dest, int x, int y, char *str, ...);
int stringWidth(char *str, ...);
void freeFont();
private:
SDL_Surface *m_font;
int m_width; // width of sdl_surface image
int m_charWidth; // width of one character (width/16)
int *m_widths; // real widths
unsigned char *m_data; // raw font data
};
#endif
CFont source file
#ifndef __FONT_CPP__
#define __FONT_CPP__
#include "font.h"
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
/*
Returns: 0 if successful, 1 if not
Parameters: Directory, RGB and alpha values
Remarks: None
*/
int CFont::initFont(char *dir, float r, float g, float b, float a)
{
FILE *fp;
char tempString[100];
unsigned char tmp;
int width;
SDL_Surface *tempSurface;
// read font size
sprintf(tempString,"%s/%s",dir,"font.ini");
fp = fopen(tempString, "rb");
if( fp == NULL )
{
return 1;
}
fscanf(fp, "%d", &width);
fclose(fp);
// create our font structure now
m_data = new unsigned char[width*width*4];
m_width = width;
m_charWidth = width/16;
// open the font raw data file and read everything in
sprintf(tempString,"%s/%s",dir,"font.raw");
fp = fopen(tempString, "rb");
if( fp != NULL )
{
for(int i=0;i<width*width;i++)
{
tmp = fgetc(fp);
m_data[i*4] = (unsigned char)255*(unsigned char)r;
m_data[i*4+1] = (unsigned char)255*(unsigned char)g;
m_data[i*4+2] = (unsigned char)255*(unsigned char)b;
m_data[i*4+3] = (unsigned char)(((float)tmp)*a);
}
} else {
return 0;
}
fclose(fp);
// create surface for font
Uint32 rmask,gmask,bmask,amask;
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
rmask = 0xff000000;
gmask = 0x00ff0000;
bmask = 0x0000ff00;
amask = 0x000000ff;
#else
rmask = 0x000000ff;
gmask = 0x0000ff00;
bmask = 0x00ff0000;
amask = 0xff000000;
#endif
tempSurface = SDL_CreateRGBSurfaceFrom(m_data, width, width,
32, width*4, rmask, gmask, bmask, amask);
m_font = SDL_DisplayFormatAlpha(tempSurface);
SDL_FreeSurface(tempSurface);
m_widths = new int[256];
// now read in the information about the width of each character
sprintf(tempString,"%s/%s",dir,"font.dat");
fp = fopen(tempString, "rb");
if( fp != NULL )
{
for(int i=0;i<256;i++)
{
tmp = fgetc(fp);
m_widths=tmp;
}
}
fclose(fp);
return 0;
}
/*
Returns: None
Parameters: Destination surface, coords and the string
Remarks: None
*/
void CFont::drawString(SDL_Surface *dest, int x, int y, char *str, ...)
{
char string[1024];
va_list ap; // Pointer To List Of Arguments
va_start(ap, str); // Parses The String For Variables
vsprintf(string, str, ap); // And Converts Symbols To Actual Numbers
va_end(ap); // Results Are Stored In Text
int length=strlen(string);
int xx=0; // This will hold the place where to draw the next char
for(int i=0; i<length; i++)
{
// Draw single character
SDL_Rect destrect;
destrect.x = xx+x;
destrect.y = y;
SDL_Rect srcrect;
srcrect.w = m_widths[string]+2;
srcrect.h = m_charWidth;
srcrect.x = (string%16*m_charWidth)+((m_charWidth/2)-(m_widths[string])/2);
srcrect.y = (((int)string/16)*m_charWidth);
SDL_BlitSurface(m_font, &srcrect, dest, &destrect);
// Increase xx by the width of the character
xx+=m_widths[string];
}
}
/*
Returns: integer, length of string
Parameters: string to find width of
Remarks: None
*/
int CFont::stringWidth(char *str, ...)
{
char string[1024];
va_list ap; // Pointer To List Of Arguments
va_start(ap, str); // Parses The String For Variables
vsprintf(string, str, ap); // And Converts Symbols To Actual Numbers
va_end(ap); // Results Are Stored In Text
// Now we just count up the width of all the characters
int xx = 0;
int length = strlen(string);
for(int i=0; i<length ;i++)
{
// Add their widths together
xx += m_widths[string];
}
return xx;
}
/*
Returns: None
Parameters: None
Remarks: None
*/
void CFont::freeFont()
{
delete [] m_widths;
delete [] m_data;
SDL_FreeSurface(m_font);
delete m_font;
}
#endif
The way its implemented into the engine is; At the moment its a public member of my CGameEngine class (will be private soon).
CFont* testfont;
and in the constructor for my CGameEngine I run:
testfont = new CFont;
testfont->initFont("data/fonts/font1",1,1,1,1);
as well as freeing it in the destructor
testfont->freeFont();
delete testfont;
This seems pretty straight forward. I just took the procedural code from the tutorial and encapsulated it in a class. The program breaks on run. So I used the debugger. Everything seems fine. It loads the width, opens the file etc. The problem gets when it reaches
tempSurface = SDL_CreateRGBSurfaceFrom(m_data, width, width,
32, width*4, rmask, gmask, bmask, amask);
m_font = SDL_DisplayFormatAlpha(tempSurface);
Specifically, when it reaches the SDL_DisplayFormatAlpha command, though I'm figuring the problem is actually with the above line, and that is probably from the for loop that fills the m_data array.
Is there anyone who could help me and point out where I went wrong? Any help is greatly appreciated
EDIT: ok, the problem doesn't seem to come up if I declare the font as a global, only seems to happen when its a member of my game engine class.