Hi,

I finished the SDL_TTF support. I attached the changed files in the
Source. Please test it, when everybody's happy I will commit it to CVS.

Regards,
-- 
Gert-Jan de Boer <[EMAIL PROTECTED]>
/*
   Copyright (C) 2004 by Wagner Frederic <[EMAIL PROTECTED]>
   Part of the Starlane Empire Project http://mozenix.org/projects.html

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License.
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY.

   See the COPYING file for more details.
*/

#include"font.h"
#include"se.h"
#include <SDL_ttf.h>

/**constructs the different letters images.
 * \param font : font FILE positioned on current char
 * \param c1 : color in 16bits (game depth)
 * \param c2 : color in 16bits (game depth) 
 * \param y : height of char (at beginning of FILE) */

character::character(TTF_Font* font, SDL_Color clrFg, SDL_Color clrBg, char letter) {
         //j'ai toujours dit que programmer ça forgeait le charactère
         //bon j'ai honte elle est mauvaise celle-là
        char text[2];
	text[0]=(letter+32);
	text[1]='\0';
	TTF_SizeText(font, text, &x, &y);
	img = TTF_RenderText_Solid(font, text, clrFg);
}

/**frees surface, blah blah blah*/
character::~character() {
	SDL_FreeSurface(img);
}

/**constructs all chars*/
font::font(char* filename, SDL_Color foreground, SDL_Color background, int fontsize) {
	//first : correct file name
	char* realname = game->rename(filename);
	
	//open file
	// Init TrueType
	TTF_Init();
// Load the Font
	starFont = TTF_OpenFont(realname,fontsize);

	//free the name
	free(realname);

	//now read all chars
	for (Uint32 i = 0; i < 96 ; i++)
	{
		chars[i] = new character(starFont, foreground, background,(char) i);
	}
}

/**frees all mem*/
font::~font() {
	Uint32 i;
	for(i=0 ; i < 96; i++)
		delete chars[i];
	// Close the Font
	TTF_CloseFont(starFont);
	// Quit Truetype system
	TTF_Quit();
}

/**this method renders the text using the color allocated
 * in the font*/
SDL_Surface *font::render_text(char* text) {
	SDL_Surface* final_img = NULL;
	Uint32 final_x = 0;
	y = chars[1]->y;
	//first go through all letters to calculate size
	for(Uint32 i = 0; i < strlen(text) ; i++) {
		final_x += chars[text[i]-32]->x;
	}
	//now create rendered string and fill it
	final_img = SDL_CreateRGBSurface(SDL_SWSURFACE, final_x, y, game->screen->format->BitsPerPixel, game->screen->format->Rmask, game->screen->format->Gmask, game->screen->format->Bmask, game->screen->format->Amask);
	SDL_Rect src, dest;
	src.x = 0;
	src.y = 0;
	src.h = y;
	dest.x = 0;
	dest.y = 0;
	dest.w = 0;
	dest.h = y;
	
	for(Uint32 i = 0 ; i < strlen(text) ; i++) {
		src.w = chars[text[i]-32]->x;
		dest.w = src.w;

		SDL_BlitSurface(chars[text[i]-32]->img, &src, final_img, &dest);
		dest.x += chars[text[i]-32]->x;
	}

	//now set colorkey as the usual color
	// was 0,254,0
	SDL_SetColorKey(final_img, SDL_SRCCOLORKEY, SDL_MapRGB(final_img->format, 0, 0, 0));

	return final_img;
};


/**this method renders some texts, wrapping words at end of lines
 */
SDL_Surface *font::render_text(char* text, Uint32 linesize) {
	SDL_Surface* final_img = NULL;
	Uint32 final_x = 0;
	Uint32 current_x = 0;
	Uint32 final_y = y;
	//regexp marker
	bool in_word = false;
	//mark the beginning of the currently parsed word
	Uint32 word_start = 0;
	//counter to check we're not looping (see below)
	Uint32 word_start2 = 0;
	Uint32 i = 0;

	while(text[i] != 0) {
		//check if we're on space
		if (text[i]==32) {
			if (in_word) in_word = false;
		}
		else {
			if (!in_word) {
				in_word = true;
				word_start = i;
			}
		}
		current_x += chars[text[i]-32]->x;
		//check if we should jump to next line
		if (current_x > linesize) {
			current_x = 0;
			final_y += y + 2;
			//wordstart - 1 because we add 1 at the end of the loop
			if (text[i] != 32)
				i = word_start-1;
			in_word = false;
			//check if we're not looping
			if (word_start2 == word_start) {
				cerr<<"font::render_text : word to big to fit in line !!"<<endl;
				return NULL;
			}
			word_start2 = word_start;
			final_x = linesize;
		}
		else final_x = (final_x>current_x)?final_x:current_x;
		i++;
	}


	//ready to go now
	//allocate image

	final_img = SDL_CreateRGBSurface(SDL_SWSURFACE, final_x, final_y, game->screen->format->BitsPerPixel, game->screen->format->Rmask, game->screen->format->Gmask, game->screen->format->Bmask, game->screen->format->Amask);

	//fill image with correct background color
	SDL_FillRect(final_img, NULL, SDL_MapRGB(final_img->format, 0, 254, 0));

	//start the same regexp, blitting chars to surface
	
	i = 0;
	word_start = 0;
	current_x = 0;
	SDL_Rect dest;
	dest.x = 0;
	dest.y = 0;
	dest.h = y;
	
	while (text[i]!=0) {
		//check if we're on space
		if (text[i]==32) {
			if (in_word)  {
				in_word = false;
				for (Uint32 j = word_start; j < i ; j++ ) {
					dest.w = chars[text[j] - 32]->x;
					SDL_BlitSurface(chars[text[j] - 32]->img, NULL, final_img, &dest);
					dest.x += chars[text[j] - 32]->x;
				}
			}
			dest.x += chars[0]->x;
		}
		else {
			if (!in_word) {
				in_word = true;
				word_start = i;
			}
		}
		current_x += chars[text[i]-32]->x;
		//check if we should jump to next line
		if (current_x > linesize) {
			current_x = 0;
			if (text[i] != 32)
				i = word_start - 1;
			in_word=false;
			dest.y += y + 2;
			dest.x = 0;
		}
		i++;
	}

	//eventually print last word
	
	if (in_word)  {
		for (Uint32 j = word_start; j < i ; j++ ) {
			dest.w = chars[text[j] - 32]->x;
			SDL_BlitSurface(chars[text[j] - 32]->img, NULL, final_img, &dest);
			dest.x += chars[text[j] - 32]->x;
		}
	}
	
	//now set colorkey as the usual color
	
	SDL_SetColorKey(final_img, SDL_SRCCOLORKEY, SDL_MapRGB(final_img->format, 0, 254, 0));
	
	return final_img;
}
/*
   Copyright (C) 2004 by Wagner Frederic <[EMAIL PROTECTED]>
   Part of the Starlane Empire Project http://mozenix.org/projects.html

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License.
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY.

   See the COPYING file for more details.
*/

#ifndef GFONT
#define GFONT
#include"common.h"
#include <SDL_ttf.h>

/**this class handles each chars of a font individually,
 * necessary since height differs from char to char*/
class character {
	public:
		//! image builded 
		SDL_Surface *img;
		//! width of char
		int x;
		int y;
		//!constructor from font FILE positioned correctly
		character(TTF_Font* font, SDL_Color clrFg, SDL_Color clrBg, char i);
		//!destructor
		~character();
};

class font {
	private:
		//!height of all chars
		int y;
		//!pointers on all chars
		character* chars[96];
		TTF_Font* starFont;
	public:
		//!constructor (constructs also all characters)
		font(char* filename, SDL_Color foreground, SDL_Color background, int fontsize);
		//!destructor
		~font();
		//!main use of this class
		SDL_Surface *render_text(char* text);
		//!multiline text rendering
		SDL_Surface *render_text(char* text, Uint32 linesize);
};

#endif
OBJS = se.o main.o introduction.o screen.o rollover.o mouse.o mainmenu.o cfgnew.o font.o video.o intro.o basic_rollover.o state_rollover.o menu_rollover.o starmap.o color_rollover.o assistant.o gfx.o
CFLAGS = -Wall -Werror -O1 -g -Wno-deprecated -Wno-sign-compare
#CFLAGS = -Wall -Werror -O4 -march=k6 -mcpu=k6
CC = g++
starlane-empire:	$(OBJS)
	$(CC) $(OBJS) $(CFLAGS) -o starlane-empire `sdl-config --libs` -lSDL_image -lSDL_mixer -lSDL_ttf
$(OBJS):	%.o:	%.cc
	$(CC) -c $< `sdl-config --cflags` $(CFLAGS)
clean:	
	rm -f *.o core starlane-empire
/*
   Copyright (C) 2004 by Wagner Frederic <[EMAIL PROTECTED]>
   Part of the Starlane Empire Project http://mozenix.org/projects.html

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License.
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY.

   See the COPYING file for more details.
*/

#include"se.h"
#include"mainmenu.h"
#include"introduction.h"
#include"cfgnew.h"
#include"intro.h"

static int eventfilter(const SDL_Event * event)
{
	if (event->type == SDL_KEYDOWN) {
		switch (event->key.keysym.sym) {
		case SDLK_RETURN:
			if (event->key.keysym.mod & KMOD_ALT)
				game->fullscreen();
			return 0;
		default:
			break;
		}
	}
	return 1;
}

static SDL_Surface *LoadIconSurface(char *file, Uint8 ** maskp)
{
	SDL_Surface *icon;
	Uint8 *pixels;
	Uint8 *mask;
	Uint32 mlen, i;

	*maskp = NULL;

	/* Load the icon surface */
	icon = SDL_LoadBMP(file);
	if (icon == NULL) {
		fprintf(stderr, "Couldn't load %s: %s\n", file, SDL_GetError());
		return (NULL);
	}

	/* Check width and height */
	if ((icon->w % 8) != 0) {
		fprintf(stderr, "Icon width must be a multiple of 8!\n");
		SDL_FreeSurface(icon);
		return (NULL);
	}
	if (icon->format->palette == NULL) {
		fprintf(stderr, "Icon must have a palette!\n");
		SDL_FreeSurface(icon);
		return (NULL);
	}

	/* Set the colorkey */
	SDL_SetColorKey(icon, SDL_SRCCOLORKEY, *((Uint8 *) icon->pixels));

	/* Create the mask */
	pixels = (Uint8 *) icon->pixels;
	/*printf("Transparent pixel: (%d,%d,%d)\n",
	   icon->format->palette->colors[*pixels].r,
	   icon->format->palette->colors[*pixels].g,
	   icon->format->palette->colors[*pixels].b); */
	mlen = icon->w * icon->h;
	mask = (Uint8 *) malloc(mlen / 8);
	if (mask == NULL) {
		fprintf(stderr, "Out of memory!\n");
		SDL_FreeSurface(icon);
		return (NULL);
	}
	memset(mask, 0, mlen / 8);
	for (i = 0; i < mlen;) {
		if (pixels[i] != *pixels)
			mask[i / 8] |= 0x01;
		++i;
		if ((i % 8) != 0)
			mask[i / 8] <<= 1;
	}
	*maskp = mask;
	return (icon);
}


/** Initialize sound card, and display */
se::se()
{
	SDL_Color clrFg,clrBg;
	Uint8 *iconmask;
#ifdef DEBUG
	cout << "Initializing SDL" << endl;
#endif
	if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) != 0) {
		cerr << "Unable to initialize SDL: " << SDL_GetError() << endl;
		exit(1);
	}

#ifdef DEBUG
	cout << "Opening video" << endl;
#endif
	SDL_WM_SetCaption("Starlane Empire", "Starlane Empire");
	SDL_Surface *icon = LoadIconSurface(rename_img("icon.bmp"), &iconmask);
	SDL_WM_SetIcon(icon, iconmask);

	screen = SDL_SetVideoMode(640, 480, 16, SDL_DOUBLEBUF);
	if (screen == NULL) {
		cout << "Unable to set video mode: " << SDL_GetError() << endl;
		exit(2);
	}
#ifdef DEBUG
	cout << "initializing sound" << endl;
#endif

	if (Mix_OpenAudio(22500, AUDIO_U8, 1, 512) < 0) {
		cerr << "Unable to initialize audio: " << SDL_GetError() << endl;
		sound = SDL_FALSE;
	} else
		sound = SDL_TRUE;

	//initializing font engine and loading fonts
#ifdef DEBUG
	cout << "initializing fonts" << endl;
#endif
	clrFg.r = 255; clrFg.g = 255; clrFg.b = 255; clrFg.unused = 0;
	clrBg.r = 0; clrBg.g = 254; clrBg.b = 0; clrFg.unused = 0;
	bigfont = new font("Vera.ttf", clrFg, clrBg, 12);
	clrFg.r = 0; clrFg.g = 0; clrFg.b = 240; clrFg.unused = 0;
	clrBg.r = 0; clrBg.g = 254; clrBg.b = 0; clrBg.unused = 0;
	smallfont = new font("Vera.ttf", clrFg, clrBg, 8);

	//init event loop filter
	SDL_SetEventFilter(&eventfilter);

	images2display = 0;
	sintroduction = NULL;
	smainmenu = NULL;
	scfgnew = NULL;
	sintro = NULL;

}

/** shuts down audio and video, and freeing images, music*/
se::~se()
{
#ifdef DEBUG
	cout << "Shutting down game" << endl;
#endif
	Mix_CloseAudio();

	//stopping SDL
	SDL_Quit();
	exit(0);
}

/** loads an image 
 * \param filename : relative filename */
SDL_Surface *se::image_load(char* filename)
{
#ifdef DEBUG
	if (filename == NULL) {
		cerr << "Warning : trying to load an unknown image" << endl;
		return NULL;
	}
#endif
	char* realname = rename_img(filename);
	SDL_Surface *image = IMG_Load(realname);
#ifdef DEBUG
	if (image == NULL) {
		cerr << "Warning : unable to load : " << realname << " : " <<
			SDL_GetError() << endl;
		return NULL;
	}
#endif
	free(realname);
	//TODO: should I use a colorkey on non transparent images ?? slowing things ??
	SDL_SetColorKey(image, SDL_SRCCOLORKEY,
					SDL_MapRGB(image->format, 0, 254, 0));
	SDL_Surface *final = SDL_DisplayFormat(image);	//TODO: is that always 16bits ????
	SDL_FreeSurface(image);
	return final;
}

/**loads number of colors images
 * \param filename : base filename
 * for example "0_raceflag.png" will load "a0_raceflag.png" "b0_raceflag.png"
 * ..... */
SDL_Surface** se::color_images_load(char* filename) {
	SDL_Surface** result = (SDL_Surface**) malloc(RACECOLORS*sizeof(SDL_Surface*));
	char* realname = (char*) malloc((strlen(filename)+2)*sizeof(char));
	char letter = 'a';
	realname[0] = 1;
	realname[1] = 0;
	strcat(realname, filename);
	for(unsigned int i = 0 ; i < RACECOLORS ; i++) {
		realname[0] = letter;
		result[i] = image_load(realname);
		letter++;
	}
	free(realname);
	return result;
}

/**converts filename for matching images installation path,
 * remember to free strings manually 
 * \param shortname: the relative image filename*/
char* se::rename_img(char* shortname) {
	Uint32 size;
	int dash_position = -1;
	//see if we can match a '_' for names like 02_image.png
	for(unsigned int i = 0 ; i < strlen(shortname) ; i++)
		if (shortname[i]=='_') {
			dash_position = i;
			break;
		}
	char* realname;
	if (dash_position == -1) {
		//standard image name
		size = 1 + strlen("data/graphx/") + strlen(shortname);
		realname = (char *) malloc(size * sizeof(char));
		realname[0] = 0;
		strcat(realname, "data/graphx/");
		strcat(realname, shortname);
	} else {
		//image extracted using ascendancy's parser
		size = 1 + strlen("data/graphx/") + strlen(shortname) - (dash_position+1) - 4 + strlen(shortname); //4 is for ".png"
		realname = (char *) malloc((1+size) * sizeof(char)); //+1 for \0
		realname[0] = 0;
		strcat(realname, "data/graphx/");
		strcat(realname, shortname+dash_position+1);
		realname[size - strlen(shortname)-1] = '/';
		realname[size - strlen(shortname)] = 0;
		strcat(realname, shortname);
	}
	return realname;
}

/**converts filename for matching installation path,
 * remember to free strings manually 
 * \param shortname: the relative filename*/
char* se::rename(char* shortname) {
	Uint32 size;
	size = 1 + strlen("data/") + strlen(shortname);
	char* realname = (char *) malloc(size * sizeof(char));
	realname[0] = 0;
	strcat(realname, "data/");
	strcat(realname, shortname);
	return realname;
}

/** this function displays an image and adds the position
 * to the list of positions to be updated */
void se::display(SDL_Surface * img)
{
#ifdef DEBUG
	if ((img->w > screen->w) || (img->h > screen->h)) {
		cerr <<
			"se::display(SDL_Surface*) : image format too big for this screen's resolution!"
			<< endl;
		return;
	}
#endif
	SDL_BlitSurface(img, NULL, screen, NULL);

	images2display++;
	//TODO: add to list to be updated ??
}


/** displays an image on screen and add position to the list of rects
 * to be updated */
void se::display(SDL_Surface * img, SDL_Rect * src, SDL_Rect * dst)
{
	//QADH to prevent BlitSurface from overwriting rects
	//usefull for not erasing mouse position
	int w=0,h=0;
	if (dst != NULL) {
		w = dst-> w;
		h = dst-> h;
	}
	SDL_BlitSurface(img, src, screen, dst);
	if (dst != NULL) {
		dst->w = w;
		dst->h = h;
	}
	images2display++;
	//TODO: add to list to be updated
}

/** updates the screen flip or updaterect */
void se::update()
{
	//TODO: change that
	if (images2display > 0)
		SDL_Flip(screen);
	images2display = 0;
}

/** fade compute the fade out of source into dest by dividing each pixel component
 * by 255/value. dest has to be allocated before calling the fade 
 * value = 255 => normal image
 * value = 0 => black
 * \param source : image to fade 
 * \param dest : pointer to resulting faded image
 * \param value : fade intensity*/
void se::fade(SDL_Surface * source, SDL_Surface * dest,
					  Uint32 value)
{
#ifdef DEBUG
	if ((dest == NULL) || (source == NULL)) {
		cerr << "invalid operand in fade" << endl;
		return;
	}
#endif
	if (SDL_MUSTLOCK(dest))
		SDL_LockSurface(dest);
	if (SDL_MUSTLOCK(source))
		SDL_LockSurface(source);

	Uint16 *spix = (Uint16 *) source->pixels;
	Uint16 *dpix = (Uint16 *) dest->pixels;

	Uint16 rshift = source->format->Rshift;
	Uint16 gshift = source->format->Gshift;
	Uint16 bshift = source->format->Bshift;

	Uint16 rmask = source->format->Rmask;
	Uint16 gmask = source->format->Gmask;
	Uint16 bmask = source->format->Bmask;

	Uint16 r, g, b;
	Uint16 pixel;


	for (Sint32 i = 0; i < source->h; i++)
		for (Sint32 j = 0; j < source->w; j++) {
			r = (spix[source->pitch * i / 2 + j] & rmask) >> rshift;
			g = (spix[source->pitch * i / 2 + j] & gmask) >> gshift;
			b = (spix[source->pitch * i / 2 + j] & bmask) >> bshift;

			r = r * value / 255;
			g = g * value / 255;
			b = b * value / 255;

			pixel = (r << rshift) + (g << gshift) + (b << bshift);

			dpix[dest->pitch * i / 2 + j] = pixel;
		}

	if (SDL_MUSTLOCK(dest))
		SDL_UnlockSurface(dest);
	if (SDL_MUSTLOCK(source))
		SDL_UnlockSurface(source);
}

/**loads a wav music file for SDL_Mixer
 * \param : the absolute filename*/
Mix_Chunk* se::music_load(char *filename)
{
#ifdef DEBUG
	cout << "loading music " << filename << endl;
#endif
	Mix_Chunk *zik = Mix_LoadWAV(filename);

	if (zik == NULL) {
		cerr << "Unable to load music: " << filename << " " <<
			SDL_GetError() << endl;
		return NULL;
	}

	return zik;
}

void se::music_play(Mix_Chunk* zik)
{
	if (sound == false)
		return;
#ifdef DEBUG
	if (zik == NULL) {
		cerr << "trying to play non existing music" << endl;
		return;
	}
#endif
	Mix_FadeInChannel(0, zik, 0, 4000);
}

void se::quit()
{
	cout << "Quitting game" << endl;
	delete game;
}

void se::fullscreen()
{
	if (SDL_WM_ToggleFullScreen(screen)) {
		cout << "Toggled fullscreen mode - now "
			<< ((screen->flags & SDL_FULLSCREEN) ? "fullscreen" :
				"windowed")
			<< endl;
	} else {
		cout << "Unable to toggle fullscreen mode" << endl;
	}
}

void se::black()
{
	SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
	images2display++;
	//TODO: add to list of updates ?
}

void se::handle()
{
	gamescreen->handle();
}

void se::introduction()
{
	sintroduction = new gintroduction();
	gamescreen = sintroduction;
}

void se::mainmenu()
{
#ifdef DEBUG
	cout << "Starting mainmenu" << endl;
#endif
	
	if (theme00 == NULL) {
		//load and start playing music
		theme00 = game->music_load("data/music/theme00.wav");
	}

	//first time ??
	if (smainmenu == NULL) {
		//free introduction structures
		if (sintroduction != NULL)
			delete sintroduction;
		//start new menu
		smainmenu = new gmainmenu();
	}
	if(sintro != NULL)
		delete sintro;
	game->framerate = 35;
	smainmenu->display();
	game->music_play(theme00);
	gamescreen = smainmenu;
	//flush event queue
	SDL_Event ev;
	while (SDL_PollEvent(&ev)) {
	};
}

void se::cfgnew()
{
#ifdef DEBUG
	cout << "Starting new game" << endl;
#endif
	if (scfgnew == NULL) {
		scfgnew = new gcfgnew();
		gamescreen = scfgnew;
		//flush event queue
		SDL_Event ev;
		while (SDL_PollEvent(&ev)) {
		};
	}
}

void se::intro()
{
#ifdef DEBUG
	cout << "Starting a new introduction video" << endl;
#endif
	sintro = new gintro();
	gamescreen = sintro;
}

/**loads a palette from a .pal file
 * \param shortname : relative filename */
void se::palette_load(char* shortname) {
	//first use of palette ?
	if (palette.colors == NULL)
		palette.colors = (SDL_Color*) malloc(256*sizeof(SDL_Color));

	char* realname = rename_img(shortname);
	FILE *palfile = fopen(realname, "r");
	if (palfile == NULL) {
		cerr<<"Unable to open palette file:"<<SDL_GetError()<<endl;
		free(realname);
		return;
	}
	for(int i =0; i<256; i++) {
		fread(&(palette.colors[i].r), sizeof(char), 1, palfile);
		fread(&(palette.colors[i].g), sizeof(char), 1, palfile);
		fread(&(palette.colors[i].b), sizeof(char), 1, palfile);
	}
	free(realname);
	fclose(palfile);
}

Reply via email to