Jump to content

  • Log In with Google      Sign In   
  • Create Account

FREE SOFTWARE GIVEAWAY

We have 4 x Pro Licences (valued at $59 each) for 2d modular animation software Spriter to give away in this Thursday's GDNet Direct email newsletter.


Read more in this forum topic or make sure you're signed up (from the right-hand sidebar on the homepage) and read Thursday's newsletter to get in the running!


Katz

Member Since 21 Jun 2011
Offline Last Active Jun 22 2011 12:56 PM

Posts I've Made

In Topic: Problem with lesson 43

22 June 2011 - 12:58 PM

OK, I solved my own problem, after much looking around.
I had two main problems: One was that my texture coordinates were entered into integers, although they are supposed to by smaller than 1. (Two days for this problem... *facepalm*)
The other was that I am using a different coordinate system: My ordinate axis runs from top to bottom and not bottom to top.

Anyway, working code, if it may help anybody:
#include <SDL.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include <vector>
#include <string>
#include <iostream>

using namespace std;

struct font_data
{
	int h;
	GLuint *textures;
	GLuint listBase;

	void init(string fontName, unsigned int h); //create font of required height
	void clean();                           	//clean font data
};

void write(const font_data &ft_font, int x, int y, string text);

//get power of two right above given number
inline int nextP2(int nb)
{
	int ret=1;
	while(ret < nb)
    	ret *= 2;
	return ret;
}

//create a display lit corresponding to the given character
void makeDList(FT_Face font, unsigned char ch, GLuint listBase, GLuint *texBase)
{
	if(FT_Load_Char(font, ch, FT_LOAD_RENDER))
    	cout << "FT_Load_Char failed in makeDList." <<  endl;
	FT_GlyphSlot glyph = font->glyph;
	FT_Bitmap &bitmap = glyph->bitmap;

	//get required width and height to get correct texture size
	int width = nextP2(bitmap.width);
	int height = nextP2(bitmap.rows);

	GLubyte *expandedData = new GLubyte [2*width*height];

	for(int j=0;j<height;j++)
	{
    	for(int i=0;i<width;i++)
    	{
        	expandedData[2*(i+j*width)] = 255;
        	expandedData[2*(i+j*width)+1] = (i>=bitmap.width || j>=bitmap.rows) ? 0 : bitmap.buffer[i+bitmap.width*j];
    	}
	}

	glBindTexture(GL_TEXTURE_2D, texBase[ch]);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR);

	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, expandedData);

	delete [] expandedData;

	glNewList(listBase + ch, GL_COMPILE);

    	glBindTexture(GL_TEXTURE_2D, texBase[ch]);

    	glPushMatrix();
    	glTranslatef(glyph->bitmap_left,0,0); //shift character to have right amount of space before
    	glTranslatef(0, (font->bbox.yMax - glyph->metrics.horiBearingY)/64,0); //move down a little if previous line has lower character
    	double x = (double)bitmap.width /(double)width; //take empty space around char into account
    	double y = (double)bitmap.rows / (double)height;

    	glBegin(GL_QUADS);
    	glTexCoord2d(0,y);
        	glVertex2f(0,bitmap.rows);
    	glTexCoord2d(0,0);
        	glVertex2f(0,0);
    	glTexCoord2d(x,0);
        	glVertex2f(bitmap.width,0);
    	glTexCoord2d(x,y);
        	glVertex2f(bitmap.width,bitmap.rows);
    	glEnd();
    	glPopMatrix();
    	glTranslatef(glyph->metrics.horiAdvance/64,0,0);

	glEndList();
}

void font_data::init(string fontName, unsigned int h)
{
	textures = new GLuint[128];
	this->h=h;

	FT_Library library;
	if(FT_Init_FreeType(&library))
    	cout << "Could not initialize Freetype library" << endl;

	FT_Face font;
	if(FT_New_Face(library, fontName.c_str(), 0, &font))
    	cout << "Could not open  font \"" <<fontName<<"\"."<<endl;
	FT_Set_Char_Size(font, h*64,h*64,96,96); //set font size

	//allocate resources for textures and display lists
	listBase=glGenLists(128);
	glGenTextures(128,textures);

	//create each of the fonts display lists
	for(unsigned char i=0;i<128;i++)
    	makeDList(font,i,listBase,textures);

	FT_Done_Face(font);
	FT_Done_FreeType(library);
}

void font_data::clean()
{
	glDeleteLists(listBase,128);
	glDeleteTextures(128,textures);
	delete [] textures;
}

void write(const font_data &ft_font, int x, int y, string text)
{
	GLuint font = ft_font.listBase;
	glListBase(font);

	glPushMatrix();
	glTranslatef(x,y,0); //move to text
	glCallLists(text.length(), GL_UNSIGNED_BYTE,text.c_str());
	glPopMatrix();
}

int main ( int argc, char** argv )
{
	SDL_Init( SDL_INIT_VIDEO );
	SDL_SetVideoMode(800, 600, 32, SDL_OPENGL);
	//set openGL parameters
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(0,800,600,0);
	glDisable(GL_DEPTH_TEST); //depth buffering
	glEnable(GL_TEXTURE_2D); //texture using
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);

	font_data myFont;
	myFont.init("../TD/fonts/jester.ttf", 20);

	SDL_Event event;
	bool quit = false;
	while(!quit)
	{
    	glClear(GL_COLOR_BUFFER_BIT);

    	glColor3ub(255,255,255);
    	glDisable(GL_TEXTURE_2D);
    	glBegin(GL_QUADS);
        	glVertex2d(0,0);
        	glVertex2d(800,0);
        	glVertex2d(800,600);
        	glVertex2d(0,600);
    	glEnd();
    	glEnable(GL_TEXTURE_2D);
    	glColor3ub(180,180,0);
    	write(myFont,200,300, "Hello World!");

    	glFlush();
    	SDL_GL_SwapBuffers();

    	while (SDL_PollEvent(&event))
    	{
        	if(event.type == SDL_QUIT || (event.type == SDL_KEYDOWN && (event.key.keysym.sym == SDLK_ESCAPE || event.key.keysym.sym == SDLK_RETURN)))
            	quit=true;
    	}
	}

	myFont.clean();
	SDL_Quit();
}

PARTNERS