Paste number 29373: OpenGL + SDL_ttf

Paste number 29373: OpenGL + SDL_ttf
Pasted by: swinchen
When:15 years, 7 months ago
Share:Tweet this! | http://paste.lisp.org/+MNX
Channel:None
Paste contents:
Raw Source | XML | Display As
#include <SDL/SDL.h>
#include <SDL/SDL_ttf.h>
#include <SDL/SDL_opengl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>

#define PI 3.141592653589793238462643

typedef struct
{
	int minx, maxx, miny, maxy, advance;
	GLfloat texcoord[4];
	GLuint texid;
} t_glyph;

typedef struct
{
	int style, pointsize, height, ascent, descent, lineskip;
	SDL_Color color;
	t_glyph glyphs[128];
} t_font;

int build_font(char* filename, t_font* font);
void print_glstr(int x, int y, t_font* font, char* str);
void set_perspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar);
void SDL_GL_Enter2DMode();
void SDL_GL_Leave2DMode();
static int power_of_two(int input);
GLuint SDL_GL_LoadTexture(SDL_Surface *surface, GLfloat *texcoord);

int main(int argc, char* argv[])
{
	t_font font;
	SDL_Surface* screen;
	
	SDL_Color white = {0xFF, 0xFF, 0xFF, 0x00};
	
	if ( SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO) < 0 )
	{
		fprintf(stderr, "ERROR Initializing SDL: %s\n", SDL_GetError());
		return -1;		
	}
	atexit(SDL_Quit);
	
	if ( TTF_Init() < 0 )
	{
		fprintf(stderr, "ERROR Initializing TTF Engine: %s\n", TTF_GetError());
		return -1;
	}
	atexit(TTF_Quit);
	
	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
	screen = SDL_SetVideoMode(800, 600, 32, SDL_OPENGL);
	if ( screen == NULL )
	{
		fprintf(stderr, "ERROR Couldn't set video mode: %s\n", SDL_GetError());
		return -1;
	}
	
	glViewport(0, 0, screen->w, screen->h);
	glMatrixMode( GL_PROJECTION );
	glLoadIdentity();
	
	set_perspective(45.0f, (GLdouble) screen->w / screen->h, 1.0f, 100.0f);
	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LESS);
	glShadeModel(GL_SMOOTH);
	glClearColor(0.0, 0.0, 0.0, 1.0);
	
	
	font.pointsize = 20;
	font.style = TTF_STYLE_NORMAL;
	memcpy(&(font.color), &white, sizeof(SDL_Color));
	if ( build_font("MONACO.TTF",&font) < 0)
	{
		fprintf(stderr, "ERROR building font: %s\n", TTF_GetError());
		return -1;		
	}
	
	while ( SDL_GetTicks() < 5000 )
	{
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		
		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
		glTranslated(0.0, 0.0, -5.0);
		
		glBegin(GL_POINTS);
			glVertex3d(0.0,0.0,0.0);
		glEnd();
		
		SDL_GL_Enter2DMode();
		print_glstr(100, 500, &font, "abcdefghijklmnopqrstuvwxyz");
		SDL_GL_Leave2DMode();		
			
		SDL_GL_SwapBuffers();
	}
	
	SDL_FreeSurface(screen);
	return 0;
}

int build_font(char* filename, t_font* font)
{
	TTF_Font* ttffont;
	SDL_Surface* surf;
	int i;
	GLenum gl_error;
	
	ttffont = TTF_OpenFont(filename, font->pointsize);
	if (ttffont == NULL)
	{
		TTF_SetError("ERROR opening font: %s\n", TTF_GetError());
		return -1;
	}
	
	TTF_SetFontStyle(ttffont, font->style);
	
	font->ascent = TTF_FontAscent(ttffont);
	font->descent = TTF_FontDescent(ttffont);
	font->height = TTF_FontHeight(ttffont);
	font->lineskip = TTF_FontLineSkip(ttffont);
	
	for ( i = ' '; i <= '~'; i++ )
	{
		surf = TTF_RenderGlyph_Blended(ttffont, i, font->color);
		if ( surf == NULL )
		{
			TTF_SetError("ERROR rendering glyph %c: %s\n", (char)i,
				TTF_GetError());
			TTF_CloseFont(ttffont);
			return -1;			
		}
		
		TTF_GlyphMetrics(ttffont, i, &(font->glyphs[i].minx), 
			&(font->glyphs[i].maxx), &(font->glyphs[i].miny),
			&(font->glyphs[i].maxy), &(font->glyphs[i].advance));
		
		font->glyphs[i].texid = SDL_GL_LoadTexture(surf,
			font->glyphs[i].texcoord);
		
		if ( (gl_error = glGetError()) != GL_NO_ERROR ) {
			/* If this failed, the text may exceed texture size limits */
			TTF_SetError("Warning: Couldn't create texture: 0x%x\n", gl_error);
			SDL_FreeSurface(surf);
			TTF_CloseFont(ttffont);
			return -1;
		}		
		SDL_FreeSurface(surf);
	}
	
	TTF_CloseFont(ttffont);
	return 0;
}

void print_glstr(int x, int y, t_font* font, char* str)
{
	int texMinX, texMaxX, texMinY, texMaxY, i, w, h;
	
	while (*str != 0)
	{
		i = (int)*str;
		texMinX = font->glyphs[i].texcoord[0];
		texMinY = font->glyphs[i].texcoord[1];
		texMaxX = font->glyphs[i].texcoord[2];
		texMaxY = font->glyphs[i].texcoord[3];
		w = font->glyphs[i].maxx;
		h = font->glyphs[i].maxy;
		
		glBindTexture(GL_TEXTURE_2D, font->glyphs[i].texid);
		glBegin(GL_TRIANGLE_STRIP);
			glTexCoord2f(texMinX, texMinY); glVertex2i(x,   y  );
			glTexCoord2f(texMaxX, texMinY); glVertex2i(x+w, y  );
			glTexCoord2f(texMinX, texMaxY); glVertex2i(x,   y+h);
			glTexCoord2f(texMaxX, texMaxY); glVertex2i(x+w, y+h);
		glEnd();
		
		x += font->glyphs[i].advance;
		str++;
	}
}

void set_perspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar)
{
   GLdouble ymax;
   ymax = zNear * tan(fovy * PI / 360.0f);
   glFrustum(-ymax*aspect, ymax*aspect, -ymax, ymax, zNear, zFar);
}

void SDL_GL_Enter2DMode()
{
	SDL_Surface *screen = SDL_GetVideoSurface();

	/* Note, there may be other things you need to change,
	   depending on how you have your OpenGL state set up.
	*/
	glPushAttrib(GL_ENABLE_BIT);
	glDisable(GL_DEPTH_TEST);
	glDisable(GL_CULL_FACE);
	glEnable(GL_TEXTURE_2D);

	/* This allows alpha blending of 2D textures with the scene */
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	glViewport(0, 0, screen->w, screen->h);

	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();

	glOrtho(0.0, (GLdouble)screen->w, (GLdouble)screen->h, 0.0, 0.0, 1.0);

	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	glLoadIdentity();

	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
}

void SDL_GL_Leave2DMode()
{
	glMatrixMode(GL_MODELVIEW);
	glPopMatrix();

	glMatrixMode(GL_PROJECTION);
	glPopMatrix();

	glPopAttrib();
}

/* Quick utility function for texture creation */
static int power_of_two(int input)
{
	int value = 1;

	while ( value < input ) {
		value <<= 1;
	}
	return value;
}

GLuint SDL_GL_LoadTexture(SDL_Surface *surface, GLfloat *texcoord)
{
	GLuint texture;
	int w, h;
	SDL_Surface *image;
	SDL_Rect area;
	Uint32 saved_flags;
	Uint8  saved_alpha;

	/* Use the surface width and height expanded to powers of 2 */
	w = power_of_two(surface->w);
	h = power_of_two(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;
	}

	/* Save the alpha blending attributes */
	saved_flags = surface->flags&(SDL_SRCALPHA|SDL_RLEACCELOK);
	saved_alpha = surface->format->alpha;
	if ( (saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
		SDL_SetAlpha(surface, 0, 0);
	}

	/* 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);

	/* Restore the alpha blending attributes */
	if ( (saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
		SDL_SetAlpha(surface, saved_flags, saved_alpha);
	}

	/* Create an OpenGL texture for the image */
	glGenTextures(1, &texture);
	glBindTexture(GL_TEXTURE_2D, texture);
	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;
}

This paste has no annotations.

Colorize as:
Show Line Numbers

Lisppaste pastes can be made by anyone at any time. Imagine a fearsomely comprehensive disclaimer of liability. Now fear, comprehensively.