Jump to content

  • Log In with Google      Sign In   
  • Create Account


for reference: Using SDL_ttf with OpenGL


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
25 replies to this topic

#1 C-Junkie   Members   -  Reputation: 1099

Like
0Likes
Like

Posted 22 November 2004 - 11:46 AM

Here is some example code that I've been meaning to cook up for awhile, that shows a short example of how to use SDL_ttf to render text for use with OpenGL. NeHe's freetype code seems to involve rendering of each letter into a texture, which is slight overkill for what many people would like to do. (it IS more efficient, however, since it doesn't involve the creation and deletion of textures for dynamic data) Anyway, for reference, a simple method to render text in opengl using SDL_ttf.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

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

#include <SDL/SDL.h>
#include <SDL/SDL_ttf.h>

/* adjust these accordingly */
char fontpath[] = "/path/to/a/font/file.ttf";
int screenwidth = 640;
int screenheight = 480;

int round(double x)
{
	return (int)(x + 0.5);
}

int nextpoweroftwo(int x)
{
	double logbase2 = log(x) / log(2);
	return round(pow(2,ceil(logbase2)));
}

char *init_sdl(SDL_Surface** screen)
{
	if(SDL_Init(SDL_INIT_VIDEO))
		return SDL_GetError();
	atexit(SDL_Quit);
	
	*screen = SDL_SetVideoMode(screenwidth, screenheight, 0, SDL_OPENGL);
	
	SDL_WM_SetCaption("C-Junkie's SDLGL text example", 0);
	
	if(TTF_Init())
		return TTF_GetError();
	atexit(TTF_Quit);
	
	return 0;
}

void SDL_GL_RenderText(char *text, 
                      TTF_Font *font,
                      SDL_Color color,
                      SDL_Rect *location)
{
	SDL_Surface *initial;
	SDL_Surface *intermediary;
	SDL_Rect rect;
	int w,h;
	int texture;
	
	/* Use SDL_TTF to render our text */
	initial = TTF_RenderText_Blended(font, text, color);
	
	/* Convert the rendered text to a known format */
	w = nextpoweroftwo(initial->w);
	h = nextpoweroftwo(initial->h);
	
	intermediary = SDL_CreateRGBSurface(0, w, h, 32, 
			0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000);

	SDL_BlitSurface(initial, 0, intermediary, 0);
	
	/* Tell GL about our new texture */
	glGenTextures(1, &texture);
	glBindTexture(GL_TEXTURE_2D, texture);
	glTexImage2D(GL_TEXTURE_2D, 0, 4, w, h, 0, GL_BGRA, 
			GL_UNSIGNED_BYTE, intermediary->pixels );
	
	/* GL_NEAREST looks horrible, if scaled... */
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);	

	/* prepare to render our texture */
	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, texture);
	glColor3f(1.0f, 1.0f, 1.0f);
	
	/* Draw a quad at location */
	glBegin(GL_QUADS);
		/* Recall that the origin is in the lower-left corner
		   That is why the TexCoords specify different corners
		   than the Vertex coors seem to. */
		glTexCoord2f(0.0f, 1.0f); 
			glVertex2f(location->x    , location->y);
		glTexCoord2f(1.0f, 1.0f); 
			glVertex2f(location->x + w, location->y);
		glTexCoord2f(1.0f, 0.0f); 
			glVertex2f(location->x + w, location->y + h);
		glTexCoord2f(0.0f, 0.0f); 
			glVertex2f(location->x    , location->y + h);
	glEnd();
	
	/* Bad things happen if we delete the texture before it finishes */
	glFinish();
	
	/* return the deltas in the unused w,h part of the rect */
	location->w = initial->w;
	location->h = initial->h;
	
	/* Clean up */
	SDL_FreeSurface(initial);
	SDL_FreeSurface(intermediary);
	glDeleteTextures(1, &texture);
}

void glEnable2D()
{
	int vPort[4];
  
	glGetIntegerv(GL_VIEWPORT, vPort);
  
	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();
  
	glOrtho(0, vPort[2], 0, vPort[3], -1, 1);
	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	glLoadIdentity();
}

void glDisable2D()
{
	glMatrixMode(GL_PROJECTION);
	glPopMatrix();   
	glMatrixMode(GL_MODELVIEW);
	glPopMatrix();	
}

void init_gl()
{
	/* Irrelevant stuff for this demo */
	glShadeModel(GL_SMOOTH);
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	glClearDepth(1.0f);
	glDepthFunc(GL_LEQUAL);
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
	
	/* Required if you want alpha-blended textures (for our fonts) */
	glBlendFunc(GL_ONE, GL_ONE);
	glEnable(GL_BLEND);
	
	/* Required setup stuff */
	glViewport(0, 0, 800, 600);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(45.0f, screenwidth / (float)screenheight, 0.1f, 50.0f);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();	
}

int main()
{
	SDL_Surface *screen;
	TTF_Font* font;
	char *err;
	SDL_Color color;
	SDL_Rect position;
	SDL_Event event;
	int done;
	
	/* Do boring initialization */
	if((err = init_sdl(&screen))) {
		printf("Error while initializing: %s", err);
		return 1;
	}
	
	if(!(font = TTF_OpenFont(fontpath, 20))) {
		printf("Error loading font: %s", TTF_GetError());
		return 1;
	}
	
	init_gl();

	done = 0;
	while(!done) {
		/* render a fun litte quad */
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		glLoadIdentity();
		glTranslatef(0.0f, 0.0f, -5.0f);
		glDisable(GL_TEXTURE_2D);
		
		glBegin(GL_QUADS);
			glNormal3f(0.0f, 0.0f, 1.0f);
			glColor3f(0.5f, 0.0f, 0.0f); glVertex3f(-1.5f, -1.0f,  1.0f);
			glColor3f(0.0f, 0.5f, 0.0f); glVertex3f( 1.0f, -2.0f,  1.0f);
			glColor3f(0.0f, 0.0f, 0.5f); glVertex3f( 1.5f,  1.0f,  1.0f);
			glColor3f(0.5f, 0.0f, 0.0f); glVertex3f(-2.0f,  1.0f, -1.0f);
		glEnd();
		
		/* Go in HUD-drawing mode */
		glEnable2D();
		glDisable(GL_DEPTH_TEST);
		
		/* Draw some text */
		color.r = 255;
		color.g = 255;
		color.b = 255;
		/** A quick note about position.
		 * Enable2D puts the origin in the lower-left corner of the
		 * screen, which is different from the normal coordinate
		 * space of most 2D api's. position, therefore,
		 * gives the X,Y coordinates of the lower-left corner of the
		 * rectangle **/
		position.x = screenwidth / 3;
		position.y = screenheight / 2;
		SDL_GL_RenderText("Hello, World!", font, color, &position);
		position.y -= position.h;
		SDL_GL_RenderText("A line right underneath", font, color, &position);
		position.y -= position.h;
		SDL_GL_RenderText("Yay text rendering.", font, color, &position);

		/* Come out of HUD mode */
		glEnable(GL_DEPTH_TEST);
		glDisable2D();
		
		/* Show the screen */
		SDL_GL_SwapBuffers( );
		
		/* Wait until you click the X */
	
		SDL_WaitEvent(&event);
		switch(event.type) {
		case SDL_QUIT:
			done = 1;
			break;
		}
	}
	
	/* Clean up (the atexit's take care of the rest) */
	TTF_CloseFont(font);
	
	return 0;
}



Here's a screenshot of what the output should look like Hosted on imageshack I don't remember who I borrowed the Enable/Disable2D functions from.

Sponsor:

#2 Fruny   Moderators   -  Reputation: 1653

Like
0Likes
Like

Posted 22 November 2004 - 11:47 AM

Bookmarked.

#3 PinguinDude   Members   -  Reputation: 154

Like
0Likes
Like

Posted 22 November 2004 - 11:51 AM

Very very nice :) I rememver having some trouble too last time when I tried to use SDL_ttf... I did get it working but hehe very nice :)

#4 coderx04   Members   -  Reputation: 122

Like
0Likes
Like

Posted 22 November 2004 - 01:14 PM

bookmarked.. Thankss so much .. nice post.

#5 Roots   Members   -  Reputation: 657

Like
0Likes
Like

Posted 22 November 2004 - 02:22 PM

I have a question. Why would you go thru the trouble when there are other font rendering techniques in OpenGL already? What are the advantages of using SDL_ttf over something like FTGL? Thanks :)
Hero of Allacrost --- http://www.allacrost.org
A free, open-source 2D RPG in development.

Latest release Oct. 10th, 2010.

#6 bewatched   Members   -  Reputation: 124

Like
0Likes
Like

Posted 23 November 2004 - 06:27 AM

Is there a way to render multi-lined text (using SDL_tff), or do you have to split it manually and reder it separated?
It seems that SDL_tff (or freetype) doesn't support the newline character. Does anyone knows if i'm worng?

#7 C-Junkie   Members   -  Reputation: 1099

Like
0Likes
Like

Posted 23 November 2004 - 06:36 AM

Quote:
Original post by bewatched
Is there a way to render multi-lined text (using SDL_tff), or do you have to split it manually and reder it separated?
It seems that SDL_tff (or freetype) doesn't support the newline character. Does anyone knows if i'm worng?
Not that I know of. My example just did three calls to the render function to render three lines.

#8 Pipo DeClown   Members   -  Reputation: 804

Like
0Likes
Like

Posted 27 November 2004 - 11:04 AM

I love you. Rate++. Bookmarked. Thank you.
I'm not back. I'm just visiting.

#9 Rob Loach   Moderators   -  Reputation: 1500

Like
0Likes
Like

Posted 29 November 2004 - 01:18 AM

Yet again, C-Junkie, you make me ponder the better things in life.

Rob Loach [Website] [Projects] [Contact]

#10 evolutional   Moderators   -  Reputation: 1064

Like
0Likes
Like

Posted 29 November 2004 - 02:45 AM

Useful.

#11 PnP Bios   Banned   -  Reputation: 490

Like
0Likes
Like

Posted 29 November 2004 - 03:45 AM

Hm. Interesting...
C-Junkie, PM me if you are interested in seeing that added to my library...
HxRender | Cornerstone SDL TutorialsCurrently picking on: Hedos, Programmer One

#12 Tsumuji   Members   -  Reputation: 144

Like
0Likes
Like

Posted 15 February 2005 - 06:30 AM

Very useful. I'm using in my project now. :D Thanks man!!

#13 Koshmaar   Members   -  Reputation: 939

Like
0Likes
Like

Posted 16 February 2005 - 02:45 AM

(necro...?)

Yes, it's nice and simple solution, hovewer, rendering each frame the same text on SDL_Surface by TTF_RenderText (which allocates memory -> which is slow), creating new texture, blitting one to another etc. was (in case of my code) horribly slow.

First I decided to add special function that would render text only once, and that rendered texture could be reused. But (by coincidence) I found on SDL mailing list one mail from Bob Pendleton, who has written SDL_TFF + OpenGL text rendering engine, by caching glyphs that were previously used. I've built similiar system, and it's working amazingly fast - renders multiple lines of text (yup, multiline rendering) without losing one frame, while for previous one the ratio was 5 frames / one function call :-/

I could post it here if anyone was interested... but be warned, it's rather big... very big piece of code :-)

#14 Tsumuji   Members   -  Reputation: 144

Like
0Likes
Like

Posted 16 February 2005 - 06:13 AM

Don't interest. Post-it! Post-it! :D

I see here too that example above is a bit slow, but anyways, it's working...



#15 Koshmaar   Members   -  Reputation: 939

Like
0Likes
Like

Posted 17 February 2005 - 12:11 AM

Ok... you asked for it :-)
Remember though that you probably won't be able to use it after simple copy & paste, there are too many things and references to things that are specific to my engine. If you want to see UML diagram of my font manager, it's here:




Header of file fontMgr.h, contains interface of FontMgr, which is manager responsible for loading, managing, releasing etc. fonts and for passing them to Renderer.



#ifndef FONTMGR_H
#define FONTMGR_H

#include "SDL_ttf.h"
#include <map>
#include <vector>
#include <string>

#include "../../Others/Misc/singleton.h"
#include "tFontObject.h"

// -------------------------------------------------

/*! \file fontMgr.h
\brief File tha contains interface of font system.
*/



//! Use this macro to get access to font system
#define getFontMgr SC::FontMgr::get()

namespace SC
{

// -------------------------------------------------

typedef std :: vector <usint> FontSizeList;

// -------------------------------------------------

//! Singleton class that internally manages loading and accessing fonts
class FontMgr : public Singleton<FontMgr>
{
public:

friend class Renderer;

void Init();
void Shutdown();

// -------------------------------------------------

//! Mod architecture prefix is added after loading, however you can access font
//! using name you've passed here (that is used only during loading);
void LoadFont(const char * _fontName, const FontSizeList & _sizes );

//! Releases only one font _fon
void ReleaseFont(const char * _fontName, const FontSizeList & _sizes);

//! Releases all actually loaded fonts
void ReleaseAllFonts();

// -------------------------------------------------

//! Returns true if specified font _fontName exists at all (if _size == -1)
//! If _size != -1 then it checks for font _fontName with specified _size
//bool FontExists(const char * _fontName, ssint _size = -1);

// -------------------------------------------------

private:

//! Used only by Renderer.
//! Returned value isn't modified but due to problems making one function const-correct rest had to adjust
//! itself (I forgot about mutable :-) )
TGlyphsContainer * GetGlyphsContainer(const char * _name, usint _size);

// -------------------------------------------------

// map of fonts
typedef std :: map <std :: string, TFontObject> FontsMap;
typedef FontsMap :: iterator FontsMapItor;
typedef std :: pair <std :: string, TFontObject> FontPair;

// -------------------------------------------------

FontsMap fonts;

};

}

#endif




Implementation of FontMgr.



#include <string>

#include "fontMgr.h"
#include "../../Others/Logger/logger.h"
#include "../../Others/Misc/misc.h"
#include "../../Layer1/FileIO/genericFileIO.h"
#include "../../Others/Misc/skinSystem.h"

#include "../../Layer1/MemoryMgr/mmgr.h"

using namespace std;

// ------------------------------------------------- start Init

void SC :: FontMgr :: Init()
{

if ( TTF_Init() == -1)
{
string tmp("Couldn't init SDL_TTF subsystem, reason: ");
tmp += TTF_GetError();
logError2("FontMgr", tmp.c_str());
throw false;
}

log2("FontMgr", "Succesfully created.")
}

// ------------------------------------------------- end Init

// ------------------------------------------------- start Shutdown

void SC :: FontMgr :: Shutdown()
{
if (!fonts.empty())
{
logError2("FontMgr", "There are unreleased fonts in the map:")
ReleaseAllFonts();
}

TTF_Quit();
log2("FontMgr", "Succesfully destroyed.")
}

// ------------------------------------------------- end Shutdown

// ------------------------------------------------- start LoadFont

void SC :: FontMgr :: LoadFont(const char * _fontName, const FontSizeList & _sizes )
{

string fullFontName(getSkinSystem.GetDirectoryPrefix());
fullFontName += _fontName;

if (!fileExists(fullFontName.c_str()))
{
string tmp("Couldn't find font file named: ");
tmp += fullFontName;
logError2("FontMgr", tmp.c_str());
return;
}

string msg("Loading font: ");
msg += _fontName;
log2("FontMgr", msg.c_str())

TFontObject * fontPtr = 0;

TFontObject font(fullFontName.c_str());

FontsMapItor fontsItor = fonts.find(_fontName);

if (fontsItor == fonts.end())
fontPtr = &font;
else
fontPtr = &fontsItor->second;


for (usint i = 0; i < _sizes.size(); ++i)
{
if (!fontPtr->LoadFont(_sizes[i]))
{
string errMsg("Couldn't load font: ");
errMsg += fullFontName;
errMsg += ", using specified font size: ";
const char * _fontSize = usintToString(_sizes[i]);
errMsg += _fontSize;
logError2("FontMgr", errMsg.c_str())
delete [] _fontSize;
continue;
}

}

if (fontsItor == fonts.end())
fonts.insert(FontPair(_fontName, font));

}

// ------------------------------------------------- end LoadFont

// ------------------------------------------------- start ReleaseFont

void SC :: FontMgr :: ReleaseFont(const char * _fontName, const FontSizeList & _sizes)
{
FontsMapItor fontsItor = fonts.find(_fontName);

if (fontsItor == fonts.end())
{
string tmp ("Couldn't find font to release it: ");
tmp += _fontName;
logError2("FontMgr", tmp.c_str())
}
else
{

for (usint i = 0; i < _sizes.size(); ++i)
{
fontsItor->second.ReleaseFont(_sizes[i]);
}

if (fontsItor->second.CanBeReleased())
{
fonts.erase(fontsItor);

string tmp ("Released font: ");
tmp += _fontName;
log2("FontMgr", tmp.c_str())
}
}
}

// ------------------------------------------------- end ReleaseFont

// ------------------------------------------------- start ReleaseAllFonts

void SC :: FontMgr :: ReleaseAllFonts()
{
FontsMapItor fontsItor;

beginG("Releasing fonts")

for (fontsItor = fonts.begin(); fontsItor != fonts.end(); ++fontsItor)
{
log2("Font", fontsItor->first.c_str());
fontsItor->second.ForceReleaseAll();
}

endG;

fonts.clear();
}

// ------------------------------------------------- end ReleaseAllFonts

// ------------------------------------------------- start GetGlyphsContainer


SC :: TGlyphsContainer * SC :: FontMgr :: GetGlyphsContainer(const char * _name, usint _size)
{
FontsMapItor fontsItor = fonts.find(_name);

if (fontsItor == fonts.end())
{
string tmp ("Couldn't find font: ");
tmp += _name;
logError2("FontMgr", tmp.c_str())
return 0;
}
else
{
return (fontsItor->second.GetGlyphsContainer(_size));
}

}

// ------------------------------------------------- end GetGlyphsContainer





Header file tFontObject.h, interface of single "font".



#ifndef TFONTOBJECT_H
#define TFONTOBJECT_H

#include <map>
#include <string>

#include "tGlyphsContainer.h"

// -------------------------------------------------

namespace SC
{

// -------------------------------------------------

class TFontObject
{
public:

TFontObject(const char * _fontName) : fontName(_fontName) { }
bool LoadFont(usint _size);

// -------------------------------------------------

void ReleaseFont(usint _size);
void ForceReleaseAll();
bool CanBeReleased() const { return glyphContainers.empty(); }

// -------------------------------------------------

TGlyphsContainer * GetGlyphsContainer( usint _size);


private:

typedef std :: map<usint, TGlyphsContainer> GlyphContainersMap;
typedef GlyphContainersMap :: iterator GlyphContainersMapItor;

GlyphContainersMap glyphContainers;
std :: string fontName;

};

// -------------------------------------------------

}

#endif





Implementation of above.



#include "tFontObject.h"

#include "../../Others/logger/logger.h"

#include "../../Layer1/MemoryMgr/mmgr.h"


// ------------------------------------------------- start LoadFont

bool SC :: TFontObject :: LoadFont(usint _size)
{
GlyphContainersMapItor itor;

itor = glyphContainers.find(_size);

if (itor == glyphContainers.end())
{
TGlyphsContainer newGlyph(fontName.c_str(), _size);

if (!newGlyph.Load())
return false;
else
{
glyphContainers.insert(std :: pair<usint, TGlyphsContainer>(_size, newGlyph) );
return true;
}
}

itor->second.Load();
return true;
}

// ------------------------------------------------- end LoadFont

// ------------------------------------------------- start ReleaseFont

void SC :: TFontObject :: ReleaseFont(usint _size)
{
GlyphContainersMapItor itor = glyphContainers.find(_size);

if (itor == glyphContainers.end())
{
debug("Not found font that had to be released.")
return;
}

if (itor->second.Release())
glyphContainers.erase(itor);

}

// ------------------------------------------------- end ReleaseFont

// ------------------------------------------------- start ForceReleaseAll

void SC :: TFontObject :: ForceReleaseAll()
{
for (GlyphContainersMapItor itor = glyphContainers.begin(); itor != glyphContainers.end(); ++itor)
itor->second.ForceRelease();

glyphContainers.clear();
}

// ------------------------------------------------- end ForceReleaseAll

// ------------------------------------------------- start GetGlyphsContainer

SC :: TGlyphsContainer * SC :: TFontObject :: GetGlyphsContainer( usint _size)
{
GlyphContainersMapItor itor = glyphContainers.find(_size);

if (itor == glyphContainers.end())
return 0;
else return (&(itor->second));
}

// ------------------------------------------------- end GetGlyphsContainer





Now where things are starting to be interesting... tGlyphsContainer.h




#ifndef TGLYPHSCONTAINER_H
#define TGLYPHSCONTAINER_H

#include <vector>
#include <string>

#include <gl/gl.h>

#include "../../Layer1/Renderer/renderer.h"
#include "SDL_ttf.h"

// -------------------------------------------------

namespace SC
{

// -------------------------------------------------

struct GlyphTexture
{
GlyphTexture() : textureID(0) { }

GLuint textureID;
usint width, height;
int charWidth, charHeight;
int advance;
};

// -------------------------------------------------

struct TGlyph
{

void ReleaseTextures() const;

uchar character;

GlyphTexture glyphsSolid[8];
GlyphTexture glyphsBlended[8];
};

// -------------------------------------------------

class TGlyphsContainer
{
public:

TGlyphsContainer(const char * _fontName, usint _size) : refCount(0), font(0), fontName(_fontName), size(_size) { }

// -------------------------------------------------

//! returns false if loading TTF font wasn't successfull
bool Load();

//! returns true if this glyph container can be deleted
bool Release();

//! Releases font even if it's reference counter is != 0.
void ForceRelease();

GlyphTexture * GetGlyphTexture(uchar _character, ulint _style, eTextRenderMode _renderMode);

ssint GetFontDescent() const { return descent; }
usint GetFontLineSkip() const { return lineSkip; }
usint GetFontHeight() const { return TTF_FontHeight(font); } // cache it?


private:

//!
void PrerenderGlyph( uchar _character, ulint _style, eTextRenderMode _renderMode, TGlyph & _glyph);

void CacheGlyph( SDL_Surface * tmp, GlyphTexture & _glyph) const;


std :: vector <TGlyph> glyphs;
std :: string fontName;

uchar refCount;
TTF_Font * font;
usint size;
ssint descent;
usint lineSkip; // vertical distance between multi line text output

};

// -------------------------------------------------


}

#endif




Probably most important file, contains implementation of clasess from tGlyphsContainer.h; they're responsible for aformentioned "glyph caching".



#include "tGlyphsContainer.h"
#include "../../Others/logger/logger.h"

#include "../../Layer1/MemoryMgr/mmgr.h"

// ------------------------------------------------- start ReleaseTextures

void SC :: TGlyph :: ReleaseTextures() const
{
GLuint textures[16];

for (usint i = 0; i < 8; ++i)
textures[i] = glyphsBlended[i].textureID;

for (usint i = 8; i < 16; ++i)
textures[i] = glyphsSolid[i].textureID;

glDeleteTextures(16, textures);

}

// ------------------------------------------------- end ReleaseTextures

// -------------------------------------------------
// TGlyphsContainer
// -------------------------------------------------

// ------------------------------------------------- start Load

bool SC :: TGlyphsContainer :: Load()
{
if (font)
{
++refCount;
return true;
}
else
{
font = TTF_OpenFont(fontName.c_str(), size);

if (!font)
{
return false;
}

descent = TTF_FontDescent(font);
lineSkip = TTF_FontLineSkip(font);
refCount = 1;
return true;
}
}

// ------------------------------------------------- end Load

// ------------------------------------------------- start Release

bool SC :: TGlyphsContainer :: Release()
{
--refCount;

if (refCount == 0)
{
SC_ASSERT(font)
TTF_CloseFont(font);
return true;
}
else return false;
}

// ------------------------------------------------- end Release

// -------------------------------------------------

void SC :: TGlyphsContainer :: ForceRelease()
{
TTF_CloseFont(font);

std :: vector <TGlyph> :: iterator itor;

for ( itor = glyphs.begin(); itor != glyphs.end(); ++itor)
(*itor).ReleaseTextures();

}

// -------------------------------------------------

// ------------------------------------------------- start GetGlyphTexture

SC :: GlyphTexture * SC :: TGlyphsContainer :: GetGlyphTexture(uchar _character, ulint _style, eTextRenderMode _renderMode)
{
std :: vector <TGlyph> :: iterator itor;

for ( itor = glyphs.begin(); itor != glyphs.end(); ++itor)
{

// -------------------------------------------------

if (itor->character == _character)
{
if (_renderMode == trm_Blend)
{

if ((*itor).glyphsBlended[_style].textureID)
return (&(*itor).glyphsBlended[_style]);

else
{
PrerenderGlyph(_character, _style, _renderMode, (*itor));
return (&(*itor).glyphsBlended[_style]);
}

}
else if (_renderMode == trm_Solid)
{

if ((*itor).glyphsSolid[_style].textureID)
return (&(*itor).glyphsSolid[_style]);

else
{
PrerenderGlyph(_character, _style, _renderMode, (*itor));
return (&(*itor).glyphsSolid[_style]);
}

}

SC_ASSERT(!"What, you added new enum value and forgot to update TGlyphsContainer?!")

}

// -------------------------------------------------

}

// we didn't found _character, so it's new glyph, first insert new to vector, then render and finally return

TGlyph newGlyph;
PrerenderGlyph(_character, _style, _renderMode, newGlyph);
newGlyph.character = _character;
glyphs.push_back(newGlyph);

if (_renderMode == trm_Blend)
{
return (&newGlyph.glyphsBlended[_style]);
}
else
if (_renderMode == trm_Solid)
{
return (&newGlyph.glyphsSolid[_style]); // how this can work?! we're returning adress of local variable... lol
}

SC_ASSERT(!"What am I doing here?")
}

// ------------------------------------------------- end GetGlyphTexture

// ------------------------------------------------- start PrerenderGlyph

void SC :: TGlyphsContainer :: PrerenderGlyph( uchar _character, ulint _style, eTextRenderMode _renderMode, TGlyph & _glyph)
{
TTF_SetFontStyle(font, _style);

// it doesn't matter, real color will be later set by Renderer
SDL_Color color = {255, 255, 255, 0};

char letter[2] = { _character, 0};
SDL_Surface * tmp;

if (_renderMode == trm_Solid)
{
tmp = TTF_RenderText_Solid( font, letter, color);
SC_ASSERT(tmp)
CacheGlyph(tmp, _glyph.glyphsSolid[_style]);
TTF_GlyphMetrics(font, (Uint16)_character, 0, 0, 0, 0, &_glyph.glyphsSolid[_style].advance);
}
else
{
tmp = TTF_RenderText_Blended( font, letter, color);
SC_ASSERT(tmp)
CacheGlyph(tmp, _glyph.glyphsBlended[_style]);
TTF_GlyphMetrics(font, (Uint16)_character, 0, 0, 0, 0, &(_glyph.glyphsBlended[_style].advance));
}
}

// ------------------------------------------------- end PrerenderGlyph

// ------------------------------------------------- start RenderGlyphSolid

void SC :: TGlyphsContainer :: CacheGlyph(SDL_Surface * tmp, GlyphTexture & _glyph) const
{
usint w = tmp->w;
usint h = tmp->h;
SDL_Surface * image = tmp;

_glyph.charWidth = w;
_glyph.charHeight = h;

bool IsWidth = IsPowerOfTwo(w);
bool IsHeight = IsPowerOfTwo(h);

if ((!IsWidth) || (!IsHeight))
{
if (!IsWidth) w = PowerOfTwo(w);
if (!IsHeight) h = PowerOfTwo(h);

image = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000);

if ( image == 0 )
{
logError2("FontMgr", "Couldn't allocate memory for expanding glyph texture to power of 2")
SDL_FreeSurface(tmp);
SC_ASSERT(!"Couldn't allocate memory for expanding texture to power of 2")
return;
}

SDL_Rect area;
area.x = 0;
area.y = 0;
area.w = tmp->w;
area.h = tmp->h;

// copy the tmp into the GL texture image
SDL_BlitSurface(tmp, &area, image, &area);
SDL_FreeSurface(tmp);
tmp = 0;
}

glGenTextures(1, &_glyph.textureID);
glBindTexture(GL_TEXTURE_2D, _glyph.textureID);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels);

if (tmp) SDL_FreeSurface(tmp);
else SDL_FreeSurface(image);

_glyph.width = w;
_glyph.height = h;

}


// ------------------------------------------------- end RenderGlyphSolid




And the last (but not least one), some functions from Renderer, they are doing actual rendering to the screen. I'm doing 2d game, so they don't need to change view matrices all the time - I've assumed that when you call them, you have ortographic projection enabled etc.



// ------------------------------------------------- start RenderText

void SC :: Renderer :: RenderText(const char * _text, const char * _fontName, usint _size, const TScrPoint & _position,
const TColor4 & _color, ulint _style, eTextPosition _horizontal,
eTextPosition _vertical, eTextRenderMode _renderMode)
{
SC_ASSERT(_text)
SC_ASSERT(_fontName)
SC_ASSERT(_size > 0)

TGlyphsContainer * glyphs = getFontMgr.GetGlyphsContainer(_fontName, _size);

if (!glyphs)
{
logError2("Renderer", "Couldn't find font to output text.")
return;
}

// -------------------------------------------------

glColor4ub(_color.r, _color.g, _color.b, _color.a);

usint xPos = _position.x;
usint yPos = _position.y;

const char * txtPtr = _text;

// this precaching of glyphs is needed to determine full size of rendered text, it's needed to
// render them properly with given eTextPosition stuff
std :: vector <GlyphTexture*> cachedGlyphs;
TScrPoint renderedText;
TScrPntSet(renderedText, 0, 0);

while (*txtPtr)
{
GlyphTexture * glyph = glyphs->GetGlyphTexture(*txtPtr, _style, _renderMode);
TScrPntAddX(renderedText, renderedText, glyph->advance );
renderedText.y = Max(glyph->charHeight, (int) renderedText.y);

cachedGlyphs.push_back(glyph);
++txtPtr;
}

// ------------------------------------------------- HORIZONTAL JUSTIFICTION

if (_horizontal == tp_Centered) // center text
xPos -= (renderedText.x)/2;
else if (_horizontal == tp_Right) // justify to right
xPos -= renderedText.x;

// ------------------------------------------------- VERTICAL JUSTIFICTION

yPos += glyphs->GetFontDescent();

if (_vertical == tp_Centered) // center text
yPos -= (renderedText.y)/4;
else if (_vertical == tp_Right) // justify to right
yPos -= renderedText.y/2;

// -------------------------------------------------

std :: vector <GlyphTexture*> :: iterator itor = cachedGlyphs.begin();

while (itor != cachedGlyphs.end())
{
GlyphTexture * glyph = (*itor);
SC_ASSERT(glyph)

glBindTexture(GL_TEXTURE_2D, glyph->textureID);

float rightMargin = (float) glyph->charWidth /(float)glyph->width;
float upMargin = (float) glyph->charHeight / (float)glyph->height;

// -------------------------------------------------

glBegin(GL_QUADS);

glTexCoord2f(0.0f, 0.0f);
glVertex3i( xPos, yPos + glyph->charHeight, 1);

glTexCoord2f(0.0f, upMargin);
glVertex3i( xPos, yPos, 1);

glTexCoord2f(rightMargin, upMargin);
glVertex3i( xPos + glyph->charWidth, yPos, 1);

glTexCoord2f(rightMargin, 0.0f);
glVertex3i( xPos + glyph->charWidth, yPos + glyph->charHeight, 1);

glEnd();

// -------------------------------------------------

xPos += glyph->advance;

++itor;
}

glBindTexture(GL_TEXTURE_2D, 0);
boundTexture.id = 0;
glColor4ub(255, 255, 255, 255);
}

// ------------------------------------------------- end RenderText

// ------------------------------------------------- start RenderTextMulti

void SC :: Renderer :: RenderTextMulti(const char * _text, const char * _fontName, usint _size,
const TScrPoint & _position, const TColor4 & _color, ulint _style,
eTextPosition _horizontal, eTextRenderMode _renderMode)
{
SC_ASSERT(_text)
SC_ASSERT(_fontName)
SC_ASSERT(_size > 0)

TGlyphsContainer * glyphs = getFontMgr.GetGlyphsContainer(_fontName, _size);

if (!glyphs)
{
logError2("Renderer", "Couldn't find font to output text.")
return;
}

usint lineSkip = glyphs->GetFontLineSkip();

// -------------------------------------------------

std :: vector < std :: string> vLines; // these are the individual lines of text
std :: string text(_text);

int n = 0;

// Break the string into its lines, remember that it's different from std C++ language: end of line
// is determined by "/n" not "\n" existance!
while( n != -1 )
{
// Get until either '/n' or '\0'
std :: string strSub;
n = text.find( "/n", 0 ); // Find the next "/n"
strSub = text.substr( 0, n);
if( n != -1 )
text = text.substr( n+2, std::string::npos );

vLines.push_back(strSub);
}

// -------------------------------------------------

glColor4ub(_color.r, _color.g, _color.b, _color.a);

usint xPos = _position.x;
usint yPos = _position.y;

yPos += glyphs->GetFontDescent();

for( usint i = 0; i < vLines.size(); i++ )
{
const char * txtPtr = vLines[i].c_str();
xPos = _position.x;

// this precaching of glyphs is needed to determine full size of rendered text, it's needed to
// render them properly with given eTextPosition stuff
std :: vector <GlyphTexture*> cachedGlyphs;
TScrPoint renderedText;
TScrPntSet(renderedText, 0, 0);

while (*txtPtr)
{
GlyphTexture * glyph = glyphs->GetGlyphTexture(*txtPtr, _style, _renderMode);
TScrPntAddX(renderedText, renderedText, glyph->advance );

//renderedText.y = Max(glyph->height, (usint) renderedText.y);
renderedText.y = Max(glyph->charHeight, (int) renderedText.y);

cachedGlyphs.push_back(glyph);
++txtPtr;
}

// ------------------------------------------------- HORIZONTAL JUSTIFICTION

if (_horizontal == tp_Centered) // center text
xPos -= (renderedText.x)/2;
else if (_horizontal == tp_Right) // justify to right
xPos -= renderedText.x;

// -------------------------------------------------

std :: vector <GlyphTexture*> :: iterator itor = cachedGlyphs.begin();

while (itor != cachedGlyphs.end())
{
GlyphTexture * glyph = (*itor);
SC_ASSERT(glyph)

glBindTexture(GL_TEXTURE_2D, glyph->textureID);

float rightMargin = (float) glyph->charWidth /(float)glyph->width;
float upMargin = (float) glyph->charHeight / (float)glyph->height;

// -------------------------------------------------

glBegin(GL_QUADS);

glTexCoord2f(0.0f, 0.0f);
glVertex3i( xPos, yPos + glyph->charHeight, 1);

glTexCoord2f(0.0f, upMargin);
glVertex3i( xPos, yPos, 1);

glTexCoord2f(rightMargin, upMargin);
glVertex3i( xPos + glyph->charWidth, yPos, 1);

glTexCoord2f(rightMargin, 0.0f);
glVertex3i( xPos + glyph->charWidth, yPos + glyph->charHeight, 1);

glEnd();

// -------------------------------------------------

xPos += glyph->advance;

++itor;
}

yPos -= lineSkip;

}

glBindTexture(GL_TEXTURE_2D, 0);
boundTexture.id = 0;
glColor4ub(255, 255, 255, 255);

}

// ------------------------------------------------- end RenderTextMulti

// ------------------------------------------------- start TextWidth

SC :: ulint SC :: Renderer :: TextWidth(const char * _text, const char * _fontName, usint _size, ulint _style,
eTextRenderMode _renderMode)
{
SC_ASSERT(_text)
SC_ASSERT(_fontName)
SC_ASSERT(_size > 0)

TGlyphsContainer * glyphs = getFontMgr.GetGlyphsContainer(_fontName, _size);

if (!glyphs)
{
logError2("Renderer", "Couldn't find font to count text width.")
return 0;
}

// -------------------------------------------------

std :: vector < std :: string> vLines; // these are the individual lines of text
std :: string text(_text);

int n = 0;

// Break the string into its lines, remember that it's different from std C++ language: end of line
// is determined by "/n" not "\n" existance!
while( n != -1 )
{
// Get until either '/n' or '\0'
std :: string strSub;
n = text.find( "/n", 0 ); // Find the next "/n"
strSub = text.substr( 0, n);
if( n != -1 )
text = text.substr( n+2, std::string::npos );

vLines.push_back(strSub);
}

ulint maxRenderedTextWidth = 0;

for (std :: vector<std :: string> :: iterator itor = vLines.begin(); itor != vLines.end(); ++itor)
{
const char * txtPtr = (*itor).c_str();
ulint renderedTextWidth = 0;

// sum width of all letters from _text
while (*txtPtr)
{
GlyphTexture * glyph = glyphs->GetGlyphTexture(*txtPtr, _style, _renderMode);
renderedTextWidth += glyph->advance;
++txtPtr;
}

maxRenderedTextWidth = Max(maxRenderedTextWidth, renderedTextWidth);
}

return maxRenderedTextWidth;
}

// ------------------------------------------------- end TextWidth

// ------------------------------------------------- start TextHeight

SC :: ulint SC :: Renderer :: TextHeight(const char * _text, const char * _fontName, usint _size, ulint _style,
eTextRenderMode _renderMode)
{
SC_ASSERT(_text)
SC_ASSERT(_fontName)
SC_ASSERT(_size > 0)

TGlyphsContainer * glyphs = getFontMgr.GetGlyphsContainer(_fontName, _size);

if (!glyphs)
{
logError2("Renderer", "Couldn't find font to count text width.")
return 0;
}

// -------------------------------------------------

std :: string text(_text);

usint lineHeight = glyphs->GetFontHeight();

int n = 0;
usint found = 1; // 1 not 0 because every string constists at least of one line of text

while( n != -1 )
{
std :: string strSub;
n = text.find( "/n", 0 );

if( n != -1 )
{
text = text.substr( n+1, std::string::npos );
++found;
}
}

return (found * lineHeight);

}

// ------------------------------------------------- end TextHeight





And the really last one :-) test which shows how to use this system:



#include "SC.h"

using namespace SC;

class MyTask : public ITask
{

public:

MyTask() {}
~MyTask() {}

bool Start();
void Update();
void Stop() { }

};


TScrPoint v1, v2;

const usint fontSize = 20;

bool MyTask :: Start()
{

TScrPntSet(v1, 1, 300);

return true;
}

usint i = 400;
eTextPosition pos = tp_Normal;

TColor4 color = { 0, 255, 0, 255 };

#define fontName "font.ttf"
#define fontStyle trm_Blend

// -------------------------------------------------

void MyTask :: Update()
{
getRenderer.ClearBuffer(bt_Color);

TScrPntSet(v1, 400, 300);
getRenderer.RenderTextMulti("Man got his women/nto get his seed/nhe got the power/nshe got the need", fontName, fontSize, v1, color, ts_Underline, tp_Right, fontStyle);


ulint time = getTimer.GetFPSCount();

const char * temp = ulintToString(time);

SetWindowCaption(temp);

delete [] temp;

}

//--------------------------------------------------

MyTask * task;

int main(int argc, char ** argv)
{

InitLib();

getRenderer.SetColorDepth(32);
getRenderer.SetFullscreen(0);
getRenderer.SetScreenSize(800, 600);
getRenderer.EnterGraphicsMode();

InitSubsystems();

FontSizeList sizes;

sizes.push_back(fontSize);
getFontMgr.LoadFont(fontName, sizes);

task = new MyTask;
SC_ASSERT(task)
task -> SetPriority(501);

getKernel.AddTask(task);

getKernel.Execute();

delete task;

getFontMgr.ReleaseFont(fontName, sizes);


getRenderer.CloseGraphicsMode();

ShutdownLib();

return 0;
}





As you can see, 80% of above code isn't responsible for the actual text rendering :-/ rather for loading, releasing, managing fonts, reference counting etc. Anyway, I hope someone will find it usefull.


#16 neXius   Members   -  Reputation: 124

Like
0Likes
Like

Posted 20 February 2005 - 02:14 PM

Koshmaar, that looks like exactly what I've been looking for

Thanks!

#17 Koshmaar   Members   -  Reputation: 939

Like
0Likes
Like

Posted 26 February 2005 - 04:09 AM

Don't thank me, thank Bob Pendleton :-) without his idea I wouldn't write it.

I've thought that for the sake of completness, I would post here also original font manager written by Bob (it's covered under LGPL)



class Font
{
private:
static const int minGlyph = ' ';
static const int maxGlyph = 126;

static int initCounter;

typedef struct
{
int minx, maxx;
int miny, maxy;
int advance;
SDL_Surface *pic;
GLuint tex;
GLfloat texMinX, texMinY;
GLfloat texMaxX, texMaxY;
} glyph;

int height;
int ascent;
int descent;
int lineSkip;
glyph glyphs[maxGlyph + 1];

unsigned char *address;
int length;
int pointSize;
int style;
float fgRed, fgGreen, fgBlue;
float bgRed, bgGreen, bgBlue;

TTF_Font *ttfFont;

SDL_Color foreground;
SDL_Color background;

void loadChar(char c)
{
GLfloat texcoord[4];
char letter[2] = {0, 0};

if ((minGlyph <= c) &&
(c <= maxGlyph) &&
(NULL == glyphs[((int)c)].pic))
{
SDL_Surface *g0 = NULL;
SDL_Surface *g1 = NULL;

letter[0] = c;

TTF_GlyphMetrics(ttfFont,
(Uint16)c,
&glyphs[((int)c)].minx,
&glyphs[((int)c)].maxx,
&glyphs[((int)c)].miny,
&glyphs[((int)c)].maxy,
&glyphs[((int)c)].advance);

g0 = TTF_RenderText_Shaded(ttfFont,
letter,
foreground,
background);

if (NULL != g0)
{
g1 = SDL_DisplayFormat(g0);
SDL_FreeSurface(g0);
}

if (NULL != g1)
{
glyphs[((int)c)].pic = g1;
glyphs[((int)c)].tex = loadTextureColorKey(g1, texcoord, 0, 0,
0);
glyphs[((int)c)].texMinX = texcoord[0];
glyphs[((int)c)].texMinY = texcoord[1];
glyphs[((int)c)].texMaxX = texcoord[2];
glyphs[((int)c)].texMaxY = texcoord[3];
}
}
}

public:

Font(unsigned char *address,
int length,
int pointSize,
int style,
float fgRed, float fgGreen, float fgBlue,
float bgRed, float bgGreen, float bgBlue):
address(address), length(length),
pointSize(pointSize),
style(style),
fgRed(fgRed), fgGreen(fgGreen), fgBlue(fgBlue),
bgRed(bgRed), bgGreen(bgGreen), bgBlue(bgBlue),
ttfFont(NULL)
{
if (0 == initCounter)
{
if (TTF_Init() < 0)
{
errorExit("Can't init SDL_ttf");
}
}
initCounter++;
initFont();
}

~Font()
{
initCounter--;
if (0 == initCounter)
{
TTF_Quit();
}
}

void initFont()
{
SDL_RWops *src = NULL;
int i;

src = SDL_RWFromMem(address, length);

ttfFont = TTF_OpenFontRW(src, 1, pointSize);
if (NULL == ttfFont)
{
errorExit("Can't open font file");
}

TTF_SetFontStyle(ttfFont, style);

foreground.r = (Uint8)(255 * fgRed);
foreground.g = (Uint8)(255 * fgGreen);
foreground.b = (Uint8)(255 * fgBlue);

background.r = (Uint8)(255 * bgRed);
background.g = (Uint8)(255 * bgGreen);
background.b = (Uint8)(255 * bgBlue);

height = TTF_FontHeight(ttfFont);
ascent = TTF_FontAscent(ttfFont);
descent = TTF_FontDescent(ttfFont);
lineSkip = TTF_FontLineSkip(ttfFont);

for (i = minGlyph; i <= maxGlyph; i++)
{
glyphs[i].pic = NULL;
glyphs[i].tex = 0;
}
}

int getLineSkip()
{
return lineSkip;
}

int getHeight()
{
return height;
}

void textSize(char *text,
SDL_Rect *r)
{
int maxx = 0;
int advance = 0;

r->x = 0;
r->y = 0;
r->w = 0;
r->h = height;

while (0 != *text)
{
if ((minGlyph <= *text) && (*text <= maxGlyph))
{
loadChar(*text);

maxx = glyphs[((int)*text)].maxx;
advance = glyphs[((int)*text)].advance;
r->w += advance;
}

text++;
}

r->w = r->w - advance + maxx;
}

void drawText(char *text, int x, int y)
{
GLfloat left, right;
GLfloat top, bottom;
GLfloat texMinX, texMinY;
GLfloat texMaxX, texMaxY;

glPushAttrib(GL_ALL_ATTRIB_BITS);

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

glEnable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

while (0 != *text)
{
if ((minGlyph <= *text) && (*text <= maxGlyph))
{
loadChar(*text);

texMinX = glyphs[((int)*text)].texMinX;
texMinY = glyphs[((int)*text)].texMinY;
texMaxX = glyphs[((int)*text)].texMaxX;
texMaxY = glyphs[((int)*text)].texMaxY;

left = x;
right = x + glyphs[((int)*text)].pic->w;
top = y;
bottom = y + glyphs[((int)*text)].pic->h;

glBindTexture(GL_TEXTURE_2D, glyphs[((int)*text)].tex);

glBegin(GL_TRIANGLE_STRIP);

glTexCoord2f(texMinX, texMinY); glVertex2f( left, top);
glTexCoord2f(texMaxX, texMinY); glVertex2f(right, top);
glTexCoord2f(texMinX, texMaxY); glVertex2f( left, bottom);
glTexCoord2f(texMaxX, texMaxY); glVertex2f(right, bottom);

glEnd();

x += glyphs[((int)*text)].advance;
}

text++;
}

glPopAttrib();
}
};

//-------------------------------------------------

int Font::initCounter = 0;

//-------------------------------------------------

// Create a texture from a surface. Set the alpha according
// to the color key. Pixels that match the color key get an
// alpha of zero while all other pixels get an alpha of
// one.

GLuint loadTextureColorKey(SDL_Surface *surface,
GLfloat *texcoord,
int ckr,
int ckg,
int ckb)
{
GLuint texture;
int w, h;
SDL_Surface *image;
SDL_Rect area;
Uint32 colorkey;

// Use the surface width and height expanded to powers of 2

w = powerOfTwo(surface->w);
h = powerOfTwo(surface->h);
texcoord[0] = 0.0f; // Min X
texcoord[1] = 0.0f; // Min Y
texcoord[2] = (GLfloat)surface->w / w; // Max X
texcoord[3] = (GLfloat)surface->h / h; // Max Y

image = SDL_CreateRGBSurface(
SDL_SWSURFACE,
w, h,
32,
#if SDL_BYTEORDER == SDL_LIL_ENDIAN // OpenGL RGBA masks
0x000000FF,
0x0000FF00,
0x00FF0000,
0xFF000000
#else
0xFF000000,
0x00FF0000,
0x0000FF00,
0x000000FF
#endif
);
if (image == NULL)
{
return 0;
}

// Set up so that colorkey pixels become transparent

colorkey = SDL_MapRGBA(image->format, ckr, ckg, ckb, 0);
SDL_FillRect(image, NULL, colorkey);

colorkey = SDL_MapRGBA(surface->format, ckr, ckg, ckb, 0);
SDL_SetColorKey(surface, SDL_SRCCOLORKEY, colorkey);

// Copy the surface into the GL texture image
area.x = 0;
area.y = 0;
area.w = surface->w;
area.h = surface->h;
SDL_BlitSurface(surface, &area, image, &area);

// Create an OpenGL texture for the image

glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D,
0,
GL_RGBA,
w, h,
0,
GL_RGBA,
GL_UNSIGNED_BYTE,
image->pixels);

SDL_FreeSurface(image); // No longer needed

return texture;
}
------------------------------------------------




It's much shorter, so it should be easier to follow the code :-)

#18 crim   Members   -  Reputation: 122

Like
0Likes
Like

Posted 23 June 2005 - 08:48 AM

::Sorry for bring topic back up
If GL_BGRA is unidentified put this line in
#include <GL/glext.h>

#19 cyberpuk   Members   -  Reputation: 122

Like
0Likes
Like

Posted 17 December 2005 - 07:18 AM

Hello,


How can I render OPENGL textures with SDL_TTF fonts and transparent background?
I compiled the first example and the textures have black background.
Also, I would like how to obtain a HDC (Handle Device Context) of a Main Window that is created with SDL library.


Thank's.

#20 Drew_Benton   Crossbones+   -  Reputation: 1713

Like
0Likes
Like

Posted 17 December 2005 - 09:38 AM

Quote:
Original post by cyberpuk
How can I render OPENGL textures with SDL_TTF fonts and transparent background?


That's an OpenGL specific issue, I'm not sure if it's possible, I've tried it in the past using this and couln't get it to come out how I wanted it to, so maybe someone with more OpenGL knowledge can answer that one.

Quote:
Also, I would like how to obtain a HDC (Handle Device Context) of a Main Window that is created with SDL library.


#include <SDL_syswm.h>
#include <windows.h>
...
// global or a static local variable
SDL_SysWMinfo pInfo;
...
// In init function just need to call once
SDL_VERSION(&pInfo.version);
SDL_GetWMInfo(&pInfo);
...
// Get's the DC based on the window's HWND
HWND myHwnd = pInfo.window;
HDC myDC = GetDC(myHwnd);






Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS