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); }