Jump to content
  • Advertisement
Sign in to follow this  
deadstar

OpenGL SDL_TTF with OpenGL

This topic is 3811 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Here is the finished code for my SDL_TTF wrapper class for use with OpenGL. Upon loading a TTF file, it renders every glyph to a 1024x1024 temporary texture, and renders glyphs using texture coords. You will have to implement the SDL_Surface_To_GL_Tex() yourself, since the code I'm using is from elsewhere. It has been testing on linux, simply remove any Windows specific headers. Screenshot: Header:
#ifndef __SYM_FONT
#define __SYM_FONT

#include <windows.h>

#include <GL/gl.h>
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include <SDL/SDL_ttf.h>

#include <string>
#include <vector>

#include "SYM_3DMaths.h"
#include "SYM_SDL_GL_Utils.h"

using namespace std;

namespace SYM
{
	//Converts an SDL surface into a GLuint
	GLuint SDL_Surface_To_GL_Tex(SDL_Surface *Surface);

	class SYM_GLYPH
	{
		public:
			//Glyph attributes
			int MinX, MaxX, MinY, MaxY, Advance;

			//Texture coordinates
			SYM_UVCOORD TexCoords[2];
	};

	class SYM_FONT
	{
		public:

			//Constructor
			SYM_FONT();

			//Load TTF font and process into a glyph sheet
			bool LoadTTFFont(string TTF_Filename, int Size);

			//Render text
			void RenderText(string Text, float x, float y);

			//Calculates width of text
			float GetTextWidth(string Text);

			//Set text colour
			void SetColour(int r, int g, int b);

		private:
			//Vector of glyphs
			vector<SYM_GLYPH> Glyphs;

			//Temporary glyph
			SYM_GLYPH *TempGlyph;

			//The texture sheet containing the glyphs
			GLuint GlyphSheet;

			//Temporary SDL surface for loading glyphs
			SDL_Surface *TempGlyphSurface;

			//Temporary SDL surface for the glyph sheet
			SDL_Surface *TempGlyphSheet;

			//TTF font
			TTF_Font* Font;

			//Font attributes
			int Height, Ascent, Descent, LineSkip;

			//Colour
			int ColourR, ColourG, ColourB;

			//Current position on the glyph sheet
			SDL_Rect CurrentPos;

			//Size of current glyph
			SDL_Rect GlyphRect;
	};

} //Namespace

#endif



Code:
#include <algorithm>

#include "SYM_Font.h"
#include "SYM_Engine.h"

namespace SYM
{
	SYM_FONT::SYM_FONT()
	{
		//Set default colour
		ColourR = 255;
		ColourG = 255;
		ColourB = 255;

		GlyphRect.x = 0;
		GlyphRect.y = 0;
		GlyphRect.w = 0;
		GlyphRect.h = 0;

		CurrentPos.x = 0;
		CurrentPos.y = 0;
		CurrentPos.w = 0;
		CurrentPos.h = 0;
	}

	bool SYM_FONT::LoadTTFFont(string TTF_Filename, int Size)
	{
		//Convert filename to upper case
		transform(TTF_Filename.begin(), TTF_Filename.end(), TTF_Filename.begin(), toupper);

		//Check if last 4 characters of string are not '.TTF'
		if ((TTF_Filename.substr(TTF_Filename.size() - 4, TTF_Filename.size()) != ".TTF"))
		{
			//Add the extension
			TTF_Filename += ".TTF";
		}

		//Prefix font name with path from engine config
		string FontFile = Engine->FontsPath + TTF_Filename;

		//Load the font
		Font = TTF_OpenFont(FontFile.c_str(), Size);

		//Check font loaded
        if (Font == NULL)
        {
			//Return
			return false;
        }

		//Get font attributes
		Ascent = TTF_FontAscent(Font);
        Descent = TTF_FontDescent(Font);
        Height = TTF_FontHeight(Font);
        LineSkip = TTF_FontLineSkip(Font);

		//TODO: Pre-calculate the size of the glyph sheet
		TempGlyphSheet = SDL_CreateRGBSurface(SDL_SWSURFACE, 1024, 1024, 32, 0, 0, 0, 0);

		//SDL_FillRect(TempGlyphSheet, 0, SDL_MapRGB(TempGlyphSheet->format, 255, 0, 255));

		//Loop through all chars
		for (int i = 0; i <= 254; i++)
        {
			//Clear the surface
			TempGlyphSurface = NULL;

			//Render the glyph onto the SDL surface, in white
			SDL_Color GlyphColour = {255, 255, 255, 0};
			TempGlyphSurface = TTF_RenderGlyph_Blended(Font, i, GlyphColour);

			//New temp glyph
			TempGlyph = new SYM_GLYPH;

			//Get the glyph attributes
			TTF_GlyphMetrics(Font, i, &TempGlyph->MinX, &TempGlyph->MaxX, &TempGlyph->MinY, &TempGlyph->MaxY, &TempGlyph->Advance);

			//Set size of glyph rect
			GlyphRect.w = TempGlyphSurface->w;
			GlyphRect.h = TempGlyphSurface->h;

			//Set size of current position rect
			CurrentPos.w = CurrentPos.x + TempGlyph->MaxX;
			CurrentPos.h = CurrentPos.y +  TempGlyph->MaxY;

			//Blit the glyph onto the glyph sheet
			SDL_BlitSurface(TempGlyphSurface, &GlyphRect, TempGlyphSheet, &CurrentPos);

			//Set texture coordinates for the glyph
			TempGlyph->TexCoords[0].u = (float)CurrentPos.x / 1024;
			TempGlyph->TexCoords[0].v = 1 - ((float)CurrentPos.y / 1024);

			TempGlyph->TexCoords[1].u = (float)(CurrentPos.x + CurrentPos.w) / 1024;
			TempGlyph->TexCoords[1].v = 1 - ((float)(CurrentPos.y + CurrentPos.h) / 1024);

			//Position xpos ready for next glyph
			CurrentPos.x += GlyphRect.w;

			//If the next character will run off the edge of the glyph sheet, advance to next row
			if (CurrentPos.x + CurrentPos.w > 1024)
			{
				CurrentPos.x = 0;
			 	CurrentPos.y += Height;
			}

			//Push back to glyphs vector
			Glyphs.push_back(*TempGlyph);

			//Delete temp glyph
			delete TempGlyph;

			//Free surface
			SDL_FreeSurface(TempGlyphSurface);
 		}

		//Close the font
		TTF_CloseFont(Font);

		//Convert the SDL glyph sheet to an OpenGL compliant texture
		GlyphSheet = SDL_Surface_To_GL_Tex(TempGlyphSheet);

		//Free the temp glyph sheet surface
		SDL_FreeSurface(TempGlyphSheet);

		return true;
	}

	void SYM_FONT::RenderText(string Text, float x, float y)
	{
		int GWidth, GHeight, MinX, MaxX, MinY, MaxY, CharID;

		//Enable texture mapping
		glEnable(GL_TEXTURE_2D);

		//Bind the glyph sheet texture
        glBindTexture(GL_TEXTURE_2D, GlyphSheet);

		//Enable blending
		glEnable(GL_BLEND);

		//Loop through characters
		for (int i = 0; i < Text.size(); i++)
		{
			//Get ID of current char
			CharID = (int)Text;

			//Get dimentions of current char
			MinX = Glyphs[CharID].MinX;
			MaxX = Glyphs[CharID].MaxX;
			MinY = Glyphs[CharID].MinY;
			MaxY = Glyphs[CharID].MaxY;

			//Set text blend colour
			glColor3ub(ColourR, ColourG, ColourB);

			//Draw the glyph
			glBegin(GL_QUADS);
				glTexCoord2f(Glyphs[CharID].TexCoords[0].u, Glyphs[CharID].TexCoords[1].v); glVertex2f(x + MinX, y + MinY);
				glTexCoord2f(Glyphs[CharID].TexCoords[1].u, Glyphs[CharID].TexCoords[1].v); glVertex2f(x + MaxX, y + MinY);
				glTexCoord2f(Glyphs[CharID].TexCoords[1].u, Glyphs[CharID].TexCoords[0].v); glVertex2f(x + MaxX, y + MaxY);
				glTexCoord2f(Glyphs[CharID].TexCoords[0].u, Glyphs[CharID].TexCoords[0].v); glVertex2f(x + MinX, y + MaxY);
            glEnd();

			//Position x ready for next glyph
			x += Glyphs[CharID].Advance;
		}

		//Disable blending
		glDisable(GL_BLEND);

		//Disable texture mapping
		glDisable(GL_TEXTURE_2D);
	}

	float SYM_FONT::GetTextWidth(string Text)
	{
		int Width = 0;
		int CharID;

		for (int i = 0; i < Text.size(); i++)
		{
			CharID = (int)Text;
			Width += Glyphs[CharID].Advance;
		}

		return Width;
	}



} //Namespace



Example usage:
//Don't forget to initialise SDL first

	SYM_FONT Arial24;

	//Load the font
	if (!Arial24.LoadTTFFont("arial.ttf", 24))
	{
		cout << "Error: Could not load font\n";
		return false;
	}

	//Set text colour to red
	Arial24.SetColour(255, 0, 0);

	//Render text
	Arial24.RenderText("Hello World!", 100, 200);



Thank you to all at Gamedev who helped me out with my problems writing it. I hope someone finds the code useful.

Share this post


Link to post
Share on other sites
Advertisement
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!