[Tux4kids-commits] r1306 - branches/commonification/tux4kids-common/trunk/src
Bolesław Kulbabiński
bolekk-guest at alioth.debian.org
Fri Jul 31 14:17:51 UTC 2009
Author: bolekk-guest
Date: 2009-07-31 14:17:50 +0000 (Fri, 31 Jul 2009)
New Revision: 1306
Added:
branches/commonification/tux4kids-common/trunk/src/t4k-audio.c
branches/commonification/tux4kids-common/trunk/src/t4k-loaders.c
branches/commonification/tux4kids-common/trunk/src/t4k-menu.c
Modified:
branches/commonification/tux4kids-common/trunk/src/t4k-globals.h
branches/commonification/tux4kids-common/trunk/src/t4k-main.c
branches/commonification/tux4kids-common/trunk/src/tux4kids-common.h
Log:
work on adding menu, loaders and audio to common
Added: branches/commonification/tux4kids-common/trunk/src/t4k-audio.c
===================================================================
--- branches/commonification/tux4kids-common/trunk/src/t4k-audio.c (rev 0)
+++ branches/commonification/tux4kids-common/trunk/src/t4k-audio.c 2009-07-31 14:17:50 UTC (rev 1306)
@@ -0,0 +1,65 @@
+/***************************************************************************
+ - file: audio.c
+ - description: this file contains audio related functions
+ -------------------
+ begin : Jan 22, 2003
+ copyright : Sam Hart, Jesse Andrews (C) 2003
+ email : tuxtype-dev at tux4kids.net
+
+ Modified for use in tuxmath by David Bruce - 2006.
+ email : <dbruce at tampabay.rr.com>
+ <tuxmath-devel at lists.sourceforge.net>
+***************************************************************************/
+
+/***************************************************************************
+* *
+* This program is free software; you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation; either version 2 of the License, or *
+* (at your option) any later version. *
+* *
+***************************************************************************/
+
+
+#include "tux4kids-common.h"
+#include "t4k-globals.h"
+
+void playsound(Mix_Chunk* sound)
+{
+ Mix_PlayChannel(-1, sound, 0);
+}
+
+Mix_Music *defaultMusic = NULL; // holds music for audioMusicLoad/unload
+
+/* audioMusicLoad attempts to load and play the music file
+ * Note: loops == -1 means forever
+ */
+void audioMusicLoad(Mix_Music* music, int loops)
+{
+ audioMusicUnload(); // make sure defaultMusic is clear
+ defaultMusic = music;
+ Mix_PlayMusic(defaultMusic, loops);
+}
+
+
+/* audioMusicUnload attempts to unload any music data that was
+ * loaded using the audioMusicLoad function
+ */
+void audioMusicUnload( void ) {
+
+ if ( defaultMusic )
+ Mix_FreeMusic( defaultMusic );
+
+ defaultMusic=NULL;
+}
+
+/* audioMusicPlay attempts to play the passed music data.
+ * if a music file was loaded using the audioMusicLoad
+ * it will be stopped and unloaded
+ * Note: loops == -1 means forever
+ */
+void audioMusicPlay( Mix_Music *musicData, int loops ) {
+
+ audioMusicUnload();
+ Mix_PlayMusic( musicData, loops );
+}
Modified: branches/commonification/tux4kids-common/trunk/src/t4k-globals.h
===================================================================
--- branches/commonification/tux4kids-common/trunk/src/t4k-globals.h 2009-07-31 13:57:14 UTC (rev 1305)
+++ branches/commonification/tux4kids-common/trunk/src/t4k-globals.h 2009-07-31 14:17:50 UTC (rev 1306)
@@ -15,13 +15,21 @@
#define min(a,b) (((a) < (b)) ? (a) : (b))
#define max(a,b) (((a) > (b)) ? (a) : (b))
+#define REG_RGBA 16,16,96,96
+#define SEL_RGBA 16,16,128,128
+
+#define MAX_FPS 30
+
extern int dbg_status;
+extern const int dbg_loaders;
extern const int dbg_menu;
extern const int dbg_menu_parser;
extern const int dbg_sdl;
extern const int dbg_all;
+extern char* data_prefix;
+
/* debug macros */
#define DEBUGCODE(mask) if((mask) & dbg_status)
#define DEBUGMSG(mask, ...) if((mask) & dbg_status){ fprintf(stderr, __VA_ARGS__); fflush(stderr); }
Added: branches/commonification/tux4kids-common/trunk/src/t4k-loaders.c
===================================================================
--- branches/commonification/tux4kids-common/trunk/src/t4k-loaders.c (rev 0)
+++ branches/commonification/tux4kids-common/trunk/src/t4k-loaders.c 2009-07-31 14:17:50 UTC (rev 1306)
@@ -0,0 +1,635 @@
+/*
+ loaders.c
+
+ Functions responsible for loading multimedia.
+
+ begin : Thu May 4 2000
+ copyright : (C) 2000 by Sam Hart
+ : (C) 2003 by Jesse Andrews
+ email : tuxtype-dev at tux4kids.net
+
+ Modified for use in tuxmath by David Bruce - 2006.
+ email : <dbruce at tampabay.rr.com>
+ <tuxmath-devel at lists.sourceforge.net>
+
+ Modified to support SVG by Boleslaw Kulbabinski - 2009
+ email : <bkulbabinski at gmail.com>
+
+ Part of "Tux4Kids" Project
+ http://www.tux4kids.com/
+
+ Copyright: See COPYING file that comes with this distribution.
+*/
+
+#include "tux4kids-common.h"
+#include "t4k-globals.h"
+
+#ifdef HAVE_RSVG
+#include<librsvg/rsvg.h>
+#include<librsvg/rsvg-cairo.h>
+#endif
+
+#define PATH_MAX 1024
+
+/* local functions */
+int check_file(const char* file);
+
+#ifdef HAVE_RSVG
+SDL_Surface* load_svg(const char* file_name, int width, int height, const char* layer_name);
+sprite* load_svg_sprite(const char* file_name, int width, int height);
+SDL_Surface* render_svg_from_handle(RsvgHandle* file_handle, int width, int height, const char* layer_name);
+void get_svg_dimensions(const char* file_name, int* width, int* height);
+#endif
+
+SDL_Surface* load_image(const char* file_name, int mode, int w, int h, bool proportional);
+void fit_in_rectangle(int* width, int* height, int max_width, int max_height);
+SDL_Surface* set_format(SDL_Surface* img, int mode);
+sprite* load_sprite(const char* name, int mode, int w, int h, bool proportional);
+
+
+
+/* check to see if file exists, if so return true */
+// int checkFile( const char *file ) {
+// static struct stat fileStats;
+// fileStats.st_mode = 0;
+// stat( file, &fileStats );
+// return (S_IFREG & fileStats.st_mode);
+// }
+
+
+int check_file(const char* file)
+{
+ FILE* fp = NULL;
+
+ if (!file)
+ {
+ DEBUGMSG(dbg_loaders, "check_file(): invalid char* argument!\n");
+ return 0;
+ }
+
+ DEBUGMSG(dbg_loaders, "check_file(): checking: %s\n", file);
+
+ fp = fopen(file, "r");
+ if (fp)
+ {
+ DEBUGMSG(dbg_loaders, "check_file(): Opened successfully as FILE\n");
+ fclose(fp);
+ return 1;
+ }
+
+ DEBUGMSG(dbg_loaders, "check_file(): Unable to open '%s' as either FILE or DIR\n", file);
+ return 0;
+}
+
+
+#ifdef HAVE_RSVG
+
+/* Load a layer of SVG file and resize it to given dimensions.
+ If width or height is negative no resizing is applied.
+ If layer = NULL then the whole image is loaded.
+ layer_name must be preceded with a '#' symbol.
+ Return NULL on failure.
+ (partly based on TuxPaint's SVG loading function) */
+SDL_Surface* load_svg(const char* file_name, int width, int height, const char* layer_name)
+{
+ SDL_Surface* dest;
+ RsvgHandle* file_handle;
+
+ DEBUGMSG(dbg_loaders, "load_svg(): loading %s\n", file_name);
+
+ rsvg_init();
+
+ file_handle = rsvg_handle_new_from_file(file_name, NULL);
+ if(NULL == file_handle)
+ {
+ DEBUGMSG(dbg_loaders, "load_svg(): file %s not found\n", file_name);
+ rsvg_term();
+ return NULL;
+ }
+
+ dest = render_svg_from_handle(file_handle, width, height, layer_name);
+
+ g_object_unref(file_handle);
+ rsvg_term();
+
+ return dest;
+}
+
+sprite* load_svg_sprite(const char* file_name, int width, int height)
+{
+ RsvgHandle* file_handle;
+ sprite* new_sprite;
+ char lay_name[20];
+ int i;
+
+ DEBUGMSG(dbg_loaders, "load_svg_sprite(): loading sprite from %s\n", file_name);
+
+ rsvg_init();
+
+ file_handle = rsvg_handle_new_from_file(file_name, NULL);
+ if(NULL == file_handle)
+ {
+ DEBUGMSG(dbg_loaders, "load_svg_sprite(): file %s not found\n", file_name);
+ rsvg_term();
+ return NULL;
+ }
+
+ new_sprite = malloc(sizeof(sprite));
+ new_sprite->default_img = render_svg_from_handle(file_handle, width, height, "#default");
+
+ /* get number of frames from description */
+ sscanf(rsvg_handle_get_desc(file_handle), "%d", &new_sprite->num_frames);
+ DEBUGMSG(dbg_loaders, "load_svg_sprite(): loading %d frames\n", new_sprite->num_frames);
+
+ for(i = 0; i < new_sprite->num_frames; i++)
+ {
+ sprintf(lay_name, "#frame%d", i);
+ new_sprite->frame[i] = render_svg_from_handle(file_handle, width, height, lay_name);
+ }
+
+ g_object_unref(file_handle);
+ rsvg_term();
+
+ return new_sprite;
+}
+
+/* render a layer of SVG file and resize it to given dimensions.
+ If width or height is negative no resizing is applied. */
+SDL_Surface* render_svg_from_handle(RsvgHandle* file_handle, int width, int height, const char* layer_name)
+{
+ RsvgDimensionData dimensions;
+ cairo_surface_t* temp_surf;
+ cairo_t* context;
+ SDL_Surface* dest;
+ float scale_x, scale_y;
+ Uint32 Rmask, Gmask, Bmask, Amask;
+
+ rsvg_handle_get_dimensions(file_handle, &dimensions);
+
+ /* set scale_x and scale_y */
+ if(width < 0 || height < 0)
+ {
+ width = dimensions.width;
+ height = dimensions.height;
+ scale_x = 1.0;
+ scale_y = 1.0;
+ }
+ else
+ {
+ scale_x = (float)width / dimensions.width;
+ scale_y = (float)height / dimensions.height;
+ }
+
+ /* set color masks */
+ Rmask = screen->format->Rmask;
+ Gmask = screen->format->Gmask;
+ Bmask = screen->format->Bmask;
+ if(screen->format->Amask == 0)
+ /* find a free byte to use for Amask */
+ Amask = ~(Rmask | Gmask | Bmask);
+ else
+ Amask = screen->format->Amask;
+
+ DEBUGMSG(dbg_loaders, "render_svg_from_handle(): color masks: R=%u, G=%u, B=%u, A=%u\n",
+ Rmask, Gmask, Bmask, Amask);
+
+ dest = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_SRCALPHA,
+ width, height, screen->format->BitsPerPixel, Rmask, Gmask, Bmask, Amask);
+
+ SDL_LockSurface(dest);
+ temp_surf = cairo_image_surface_create_for_data(dest->pixels,
+ CAIRO_FORMAT_ARGB32, dest->w, dest->h, dest->pitch);
+
+ context = cairo_create(temp_surf);
+ if(cairo_status(context) != CAIRO_STATUS_SUCCESS)
+ {
+ DEBUGMSG(dbg_loaders, "render_svg_from_handle(): error rendering SVG\n");
+ cairo_surface_destroy(temp_surf);
+ return NULL;
+ }
+
+ cairo_scale(context, scale_x, scale_y);
+
+ /* render appropriate layer */
+ rsvg_handle_render_cairo_sub(file_handle, context, layer_name);
+
+ SDL_UnlockSurface(dest);
+ cairo_surface_destroy(temp_surf);
+ cairo_destroy(context);
+
+ return dest;
+}
+
+void get_svg_dimensions(const char* file_name, int* width, int* height)
+{
+ RsvgHandle* file_handle;
+ RsvgDimensionData dimensions;
+
+ rsvg_init();
+
+ file_handle = rsvg_handle_new_from_file(file_name, NULL);
+ if(file_handle == NULL)
+ {
+ DEBUGMSG(dbg_loaders, "get_svg_dimensions(): file %s not found\n", file_name);
+ rsvg_term();
+ return;
+ }
+
+ rsvg_handle_get_dimensions(file_handle, &dimensions);
+
+ *width = dimensions.width;
+ *height = dimensions.height;
+
+ g_object_unref(file_handle);
+ rsvg_term();
+}
+
+#endif /* HAVE_RSVG */
+
+/* Load an image without resizing it */
+SDL_Surface* LoadImage(const char* file_name, int mode)
+{
+ return LoadScaledImage(file_name, mode, -1, -1);
+}
+
+/* LoadScaledImage : Load an image and resize it to given dimensions.
+ If width or height is negative no resizing is applied.
+ The loader (load_svg() or IMG_Load()) is chosen depending on file extension,
+ If an SVG file is not found try to load its PNG equivalent
+ (unless IMG_NO_PNG_FALLBACK is set) */
+SDL_Surface* LoadScaledImage(const char* file_name, int mode, int width, int height)
+{
+ return load_image(file_name, mode, width, height, false);
+}
+
+/* LoadImageOfBoundingBox : Same as LoadScaledImage but preserve image proportions
+ and fit it into max_width x max_height rectangle.
+ Returned surface is not necessarily max_width x max_height ! */
+SDL_Surface* LoadImageOfBoundingBox(const char* file_name, int mode, int max_width, int max_height)
+{
+ return load_image(file_name, mode, max_width, max_height, true);
+}
+
+
+/* load_image : helper function used by LoadScaledImage and LoadImageOfBoundingBox */
+SDL_Surface* load_image(const char* file_name, int mode, int w, int h, bool proportional)
+{
+ SDL_Surface* loaded_pic = NULL;
+ SDL_Surface* final_pic = NULL;
+ char fn[PATH_MAX];
+ int fn_len;
+ int width = -1, height = -1;
+ bool is_svg = true;
+
+ if(NULL == file_name)
+ {
+ DEBUGMSG(dbg_loaders, "load_image(): file_name is NULL, exiting.\n");
+ return NULL;
+ }
+
+ /* run loader depending on file extension */
+
+ /* add path prefix */
+ snprintf(fn, PATH_MAX, "%s/images/%s", data_prefix, file_name);
+ fn_len = strlen(fn);
+
+ if(strcmp(fn + fn_len - 4, ".svg"))
+ {
+ DEBUGMSG(dbg_loaders, "load_image(): %s is not an SVG, loading using IMG_Load()\n", fn);
+ loaded_pic = IMG_Load(fn);
+ is_svg = false;
+ if (NULL == loaded_pic)
+ {
+ is_svg = true;
+ DEBUGMSG(dbg_loaders, "load_image(): Trying to load SVG equivalent of %s\n", fn);
+ sprintf(strrchr(fn, '.'), ".svg");
+ }
+ }
+ if (is_svg)
+ {
+#ifdef HAVE_RSVG
+ DEBUGMSG(dbg_loaders, "load_image(): trying to load %s as SVG.\n", fn);
+ if(proportional)
+ {
+ get_svg_dimensions(fn, &width, &height);
+ if(width > 0 && height > 0)
+ fit_in_rectangle(&width, &height, w, h);
+ }
+ else
+ {
+ width = w;
+ height = h;
+ }
+ loaded_pic = load_svg(fn, width, height, NULL);
+#endif
+
+ if(loaded_pic == NULL)
+ {
+#ifdef HAVE_RSVG
+ DEBUGMSG(dbg_loaders, "load_image(): failed to load %s as SVG.\n", fn);
+#else
+ DEBUGMSG(dbg_loaders, "load_image(): SVG support not available.\n");
+#endif
+ if(mode & IMG_NO_PNG_FALLBACK)
+ {
+ DEBUGMSG(dbg_loaders, "load_image(): %s : IMG_NO_PNG_FALLBACK is set.\n", fn);
+ }
+ else
+ {
+ DEBUGMSG(dbg_loaders, "load_image(): Trying to load PNG equivalent of %s\n", fn);
+ strcpy(fn + fn_len - 3, "png");
+
+ loaded_pic = IMG_Load(fn);
+ is_svg = false;
+ }
+ }
+ }
+
+ if (NULL == loaded_pic) /* Could not load image: */
+ {
+ if (mode & IMG_NOT_REQUIRED)
+ {
+ DEBUGMSG(dbg_loaders, "load_image(): Warning: could not load optional graphics file %s\n", file_name);
+ return NULL; /* Allow program to continue */
+ }
+ /* If image was required, exit from program: */
+ fprintf(stderr, "load_image(): ERROR could not load required graphics file %s\n", file_name);
+ fprintf(stderr, "%s", SDL_GetError() );
+ return NULL;
+ }
+ else if(!is_svg && w > 0 && h > 0)
+ {
+ if(proportional)
+ {
+ width = loaded_pic->w;
+ height = loaded_pic->h;
+ fit_in_rectangle(&width, &height, w, h);
+ }
+ else
+ {
+ width = w;
+ height = h;
+ }
+ final_pic = zoom(loaded_pic, width, height);
+ SDL_FreeSurface(loaded_pic);
+ loaded_pic = final_pic;
+ final_pic = NULL;
+ }
+
+ final_pic = set_format(loaded_pic, mode);
+ SDL_FreeSurface(loaded_pic);
+ DEBUGMSG(dbg_loaders, "Leaving load_image()\n\n");
+
+ return final_pic;
+}
+
+/* adjust width and height to fit in max_width x max_height rectangle
+ but preserve their proportion */
+void fit_in_rectangle(int* width, int* height, int max_width, int max_height)
+{
+ float scale_w, scale_h;
+
+ if(width != 0 && height != 0)
+ {
+ scale_w = (float) max_width / (*width);
+ scale_h = (float) max_height / (*height);
+ *width *= min(scale_w, scale_h);
+ *height *= min(scale_w, scale_h);
+ }
+}
+
+SDL_Surface* set_format(SDL_Surface* img, int mode)
+{
+ switch (mode & IMG_MODES)
+ {
+ case IMG_REGULAR:
+ {
+ DEBUGMSG(dbg_loaders, "set_format(): handling IMG_REGULAR mode.\n");
+ return SDL_DisplayFormat(img);
+ }
+
+ case IMG_ALPHA:
+ {
+ DEBUGMSG(dbg_loaders, "set_format(): handling IMG_ALPHA mode.\n");
+ return SDL_DisplayFormatAlpha(img);
+ }
+
+ case IMG_COLORKEY:
+ {
+ DEBUGMSG(dbg_loaders, "set_format(): handling IMG_COLORKEY mode.\n");
+ SDL_LockSurface(img);
+ SDL_SetColorKey(img, (SDL_SRCCOLORKEY | SDL_RLEACCEL),
+ SDL_MapRGB(img->format, 255, 255, 0));
+ return SDL_DisplayFormat(img);
+ }
+
+ default:
+ {
+ DEBUGMSG(dbg_loaders, "set_format(): Image mode not recognized\n");
+ }
+ }
+
+ return NULL;
+}
+
+
+/* LoadBkgd() : a wrapper for LoadImage() that optimizes
+ the format of background image */
+SDL_Surface* LoadBkgd(const char* file_name, int width, int height)
+{
+ SDL_Surface* orig = NULL;
+ SDL_Surface* final_pic = NULL;
+
+ orig = LoadScaledImage(file_name, IMG_REGULAR, width, height);
+
+ if (!orig)
+ {
+ DEBUGMSG(dbg_loaders, "In LoadBkgd(), LoadImage() returned NULL on %s\n",
+ file_name);
+ return NULL;
+ }
+
+ /* turn off transparency, since it's the background */
+ SDL_SetAlpha(orig, SDL_RLEACCEL, SDL_ALPHA_OPAQUE);
+ final_pic = SDL_DisplayFormat(orig); /* optimize the format */
+ SDL_FreeSurface(orig);
+
+ return final_pic;
+}
+
+
+sprite* LoadSprite(const char* name, int mode)
+{
+ return LoadScaledSprite(name, mode, -1, -1);
+}
+
+sprite* LoadScaledSprite(const char* name, int mode, int width, int height)
+{
+ return load_sprite(name, mode, width, height, false);
+}
+
+sprite* LoadSpriteOfBoundingBox(const char* name, int mode, int max_width, int max_height)
+{
+ return load_sprite(name, mode, max_width, max_height, true);
+}
+
+sprite* load_sprite(const char* name, int mode, int w, int h, bool proportional)
+{
+ sprite *new_sprite = NULL;
+ char fn[PATH_MAX];
+ int i, width, height;
+
+#ifdef HAVE_RSVG
+ /* check if SVG sprite file is present */
+ sprintf(fn, "%s/images/%s.svg", data_prefix, name);
+ if(1 == check_file(fn))
+ {
+ if(proportional)
+ {
+ get_svg_dimensions(fn, &width, &height);
+ if(width > 0 && height > 0)
+ fit_in_rectangle(&width, &height, w, h);
+ }
+ else
+ {
+ width = w;
+ height = h;
+ }
+
+ new_sprite = load_svg_sprite(fn, width, height);
+
+ if(new_sprite)
+ {
+ set_format(new_sprite->default_img, mode);
+ for(i = 0; i < new_sprite->num_frames; i++)
+ set_format(new_sprite->frame[i], mode);
+ new_sprite->cur = 0;
+ }
+ }
+#endif
+
+ if(!new_sprite)
+ {
+ /* SVG sprite was not loaded, try to load it frame by frame from PNG files */
+ new_sprite = malloc(sizeof(sprite));
+
+ sprintf(fn, "%sd.png", name); // The 'd' means the default image
+ if(proportional)
+ new_sprite->default_img = LoadImageOfBoundingBox(fn, mode | IMG_NOT_REQUIRED, w, h);
+ else
+ new_sprite->default_img = LoadScaledImage(fn, mode | IMG_NOT_REQUIRED, w, h);
+
+ if(!new_sprite->default_img)
+ DEBUGMSG(dbg_loaders, "load_sprite(): failed to load default image for %s\n", name);
+
+ for(i = 0; i < MAX_SPRITE_FRAMES; i++)
+ {
+ sprintf(fn, "%s%d.png", name, i);
+ if(proportional)
+ new_sprite->frame[i] = LoadImageOfBoundingBox(fn, mode | IMG_NOT_REQUIRED, w, h);
+ else
+ new_sprite->frame[i] = LoadScaledImage(fn, mode | IMG_NOT_REQUIRED, w, h);
+
+ if(new_sprite->frame[i] == NULL)
+ {
+ new_sprite->cur = 0;
+ new_sprite->num_frames = i;
+ break;
+ }
+ else
+ DEBUGMSG(dbg_loaders, "load_sprite(): loaded frame %d of %s\n", i, name);
+ }
+ }
+
+ return new_sprite;
+}
+
+sprite* FlipSprite(sprite* in, int X, int Y)
+{
+ sprite *out;
+
+ out = malloc(sizeof(sprite));
+ if (in->default_img != NULL)
+ out->default_img = Flip( in->default_img, X, Y );
+ else
+ out->default_img = NULL;
+ for( out->num_frames=0; out->num_frames<in->num_frames; out->num_frames++ )
+ out->frame[out->num_frames] = Flip( in->frame[out->num_frames], X, Y );
+ out->cur = 0;
+ return out;
+}
+
+void FreeSprite(sprite* gfx)
+{
+ int x;
+ if (!gfx)
+ return;
+
+ DEBUGMSG(dbg_loaders, "Freeing image at %p", gfx);
+ for (x = 0; x < gfx->num_frames; x++)
+ {
+ DEBUGMSG(dbg_loaders, ".");
+ if (gfx->frame[x])
+ {
+ SDL_FreeSurface(gfx->frame[x]);
+ gfx->frame[x] = NULL;
+ }
+ }
+
+ if (gfx->default_img)
+ {
+ SDL_FreeSurface(gfx->default_img);
+ gfx->default_img = NULL;
+ }
+
+ DEBUGMSG(dbg_loaders, "FreeSprite() - done\n");
+ free(gfx);
+}
+
+void NextFrame(sprite* s)
+{
+ if (s && s->num_frames)
+ s->cur = (s->cur + 1) % s->num_frames;
+}
+
+
+
+/* LoadSound : Load a sound/music patch from a file. */
+Mix_Chunk* LoadSound( char *datafile )
+{
+ Mix_Chunk* tempChunk = NULL;
+ char fn[PATH_MAX];
+
+// sprintf(fn , "%s/sounds/%s", realPath[i], datafile);
+ sprintf(fn , "%s/sounds/%s", data_prefix, datafile);
+ tempChunk = Mix_LoadWAV(fn);
+ if (!tempChunk)
+ {
+ fprintf(stderr, "LoadSound(): %s not found\n\n", fn);
+ }
+ return tempChunk;
+}
+
+/* LoadMusic : Load music from a datafile */
+Mix_Music* LoadMusic(char *datafile )
+{
+ char fn[PATH_MAX];
+ Mix_Music* tempMusic = NULL;
+
+ sprintf( fn , "%s/sounds/%s", data_prefix, datafile );
+ if (1 != check_file(fn))
+ {
+ fprintf(stderr, "LoadMusic(): %s not found\n\n", fn);
+ return NULL;
+ }
+
+ tempMusic = Mix_LoadMUS(fn);
+
+ if (!tempMusic)
+ {
+ fprintf(stderr, "LoadMusic(): %s not loaded successfully\n", fn);
+ printf("Error was: %s\n\n", Mix_GetError());
+ }
+ return tempMusic;
+}
+
Modified: branches/commonification/tux4kids-common/trunk/src/t4k-main.c
===================================================================
--- branches/commonification/tux4kids-common/trunk/src/t4k-main.c 2009-07-31 13:57:14 UTC (rev 1305)
+++ branches/commonification/tux4kids-common/trunk/src/t4k-main.c 2009-07-31 14:17:50 UTC (rev 1306)
@@ -16,7 +16,10 @@
int dbg_status;
+char* data_prefix;
+
/* these values have to match those used in games */
+const int dbg_loaders = 1 << 2;
const int dbg_menu = 1 << 4;
const int dbg_menu_parser = 1 << 5;
const int dbg_sdl = 1 << 10;
@@ -27,3 +30,7 @@
dbg_status = dbg_flags;
}
+void SetDataPrefix(char* pref)
+{
+ data_prefix = pref;
+}
Added: branches/commonification/tux4kids-common/trunk/src/t4k-menu.c
===================================================================
--- branches/commonification/tux4kids-common/trunk/src/t4k-menu.c (rev 0)
+++ branches/commonification/tux4kids-common/trunk/src/t4k-menu.c 2009-07-31 14:17:50 UTC (rev 1306)
@@ -0,0 +1,1053 @@
+/*
+ t4k-menu.c
+
+ Functions responsible for loading, parsing and displaying game menu.
+
+ Part of "Tux4Kids" Project
+ http://www.tux4kids.com/
+
+ Author: Boleslaw Kulbabinski <bkulbabinski at gmail.com>, (C) 2009
+
+ Copyright: See COPYING file that comes with this distribution.
+*/
+
+#include "tux4kids-common.h"
+#include "t4k-globals.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct mNode {
+ struct mNode* parent;
+
+ char* title;
+ int font_size;
+
+ char* icon_name;
+ sprite* icon;
+
+ SDL_Rect button_rect;
+ SDL_Rect icon_rect;
+ SDL_Rect text_rect;
+
+ /* submenu_size = 0 if no submenu */
+ int submenu_size;
+ struct mNode** submenu;
+
+ /* these fields are used only if submenu_size = 0 */
+ int activity;
+ int param;
+
+ /* these fields are used only if submenu_size > 0 */
+ bool show_title;
+ int entries_per_screen;
+ int first_entry;
+};
+
+typedef struct mNode MenuNode;
+
+#define QUIT -2
+#define STOP -1
+#define RUN_MAIN_MENU -3
+
+int n_of_activities;
+char** activities;
+
+SDL_Color red, yellow, white, black;
+
+Mix_Chunk* snd_click;
+Mix_Chunk* snd_hover;
+Mix_Music* menu_music;
+
+#define N_OF_MENUS 10
+MenuNode* menus[N_OF_MENUS];
+
+/* actions available while viewing the menu */
+enum { NONE, CLICK, PAGEUP, PAGEDOWN, STOP_ESC, RESIZED };
+
+/* stop button, left and right arrow positions do not
+ depend on currently displayed menu */
+SDL_Rect menu_rect, stop_rect, prev_rect, next_rect;
+SDL_Surface *stop_button, *prev_arrow, *next_arrow, *prev_gray, *next_gray;
+
+/*TODO: move these constants into a config file (maybe together with
+ titleGetScreen() paths and rects ? ) */
+const float menu_pos[4] = {0.38, 0.23, 0.55, 0.72};
+const float stop_pos[4] = {0.94, 0.0, 0.06, 0.06};
+const float prev_pos[4] = {0.87, 0.93, 0.06, 0.06};
+const float next_pos[4] = {0.94, 0.93, 0.06, 0.06};
+const char* stop_path = "status/stop.svg";
+const char* prev_path = "status/left.svg";
+const char* next_path = "status/right.svg";
+const char* prev_gray_path = "status/left_gray.svg";
+const char* next_gray_path = "status/right_gray.svg";
+const float button_gap = 0.2, text_h_gap = 0.4, text_w_gap = 0.5, button_radius = 0.27;
+const int min_font_size = 8, default_font_size = 20, max_font_size = 40;
+
+/* font size used in current resolution */
+int curr_font_size;
+
+/* menu title rect */
+SDL_Rect menu_title_rect;
+
+/* buffer size used when reading attributes or names */
+const int buf_size = 128;
+
+
+
+/* local functions */
+MenuNode* create_empty_node();
+char* get_attribute_name(const char* token);
+char* get_attribute_value(const char* token);
+void read_attributes(FILE* xml_file, MenuNode* node);
+MenuNode* load_menu_from_file(FILE* xml_file, MenuNode* parent);
+void free_menu(MenuNode* menu);
+MenuNode* CreateOneLevelMenu(int items, char** item_names, char* title, char* trailer);
+
+int RunMenu(MenuNode* root, bool return_choice, void (*draw_background)(), int (*handle_event)(SDL_Event*), void (*handle_animations)(), int (*handle_activity)(int, int));
+SDL_Surface** render_buttons(MenuNode* menu, bool selected);
+void prerender_menu(MenuNode* menu);
+char* find_longest_text(MenuNode* menu, int* length);
+void set_font_size();
+void prerender_all();
+
+
+
+/*
+ functions responsible for parsing menu files
+ and creating menu trees
+*/
+
+/* creates new MenuNode struct with all fields set to NULL (or 0) */
+MenuNode* create_empty_node()
+{
+ MenuNode* new_node = malloc(sizeof(MenuNode));
+ new_node->parent = NULL;
+ new_node->title = NULL;
+ new_node->icon_name = NULL;
+ new_node->icon = NULL;
+ new_node->submenu_size = 0;
+ new_node->submenu = NULL;
+ new_node->activity = 0;
+ new_node->param = 0;
+ new_node->first_entry = 0;
+ new_node->show_title = false;
+
+ return new_node;
+}
+
+/* read attributes and fill appropriate node fields */
+void read_attributes(FILE* xml_file, MenuNode* node)
+{
+ char attr_name[buf_size];
+ char attr_val[buf_size];
+ int i;
+
+ /* read tokens until closing '>' is found */
+ do
+ {
+ fscanf(xml_file, " %[^=\n]", attr_name);
+
+ DEBUGMSG(dbg_menu_parser, "read_attributes(): read attribute name: %s\n", attr_name);
+ if(strchr(attr_name, '>'))
+ break;
+
+ fscanf(xml_file, "=\"%[^\"]\"", attr_val);
+ DEBUGMSG(dbg_menu_parser, "read_attributes(): read attribute value: %s\n", attr_val);
+
+ if(strcmp(attr_name, "title") == 0)
+ node->title = strdup(attr_val);
+ else if(strcmp(attr_name, "entries") == 0)
+ node->submenu_size = atoi(attr_val);
+ else if(strcmp(attr_name, "param") == 0)
+ node->param = atoi(attr_val);
+ else if(strcmp(attr_name, "sprite") == 0)
+ node->icon_name = strdup(attr_val);
+ else if(strcmp(attr_name, "run") == 0)
+ {
+ if(strcmp(attr_val, "RUN_MAIN_MENU") == 0)
+ node->activity = RUN_MAIN_MENU;
+ for(i = 0; i < n_of_activities; i++)
+ if(strcmp(attr_val, activities[i]) == 0)
+ node->activity = i;
+ }
+ else
+ DEBUGMSG(dbg_menu_parser, "read_attributes(): unknown attribute %s , omitting\n", attr_name);
+
+ } while(strchr(attr_val, '>') == NULL);
+}
+
+/* recursively read and parse given xml menu file and create menu tree
+ return NULL in case of problems */
+MenuNode* load_menu_from_file(FILE* xml_file, MenuNode* parent)
+{
+ MenuNode* new_node = create_empty_node();
+ char buffer[buf_size];
+ int i;
+
+ new_node->parent = parent;
+
+ DEBUGMSG(dbg_menu_parser, "entering load_menu_from_file()\n");
+ fscanf(xml_file, " < %s", buffer);
+
+ if(strcmp(buffer, "menu") == 0)
+ {
+ read_attributes(xml_file, new_node);
+ if(new_node->title == NULL)
+ {
+ DEBUGMSG(dbg_menu_parser, "load_menu_from_file(): no title attribute, exiting\n");
+ return NULL;
+ }
+
+ if(new_node->submenu_size > 0)
+ {
+ new_node->submenu = malloc(new_node->submenu_size * sizeof(MenuNode));
+ for(i = 0; i < new_node->submenu_size; i++)
+ new_node->submenu[i] = load_menu_from_file(xml_file, new_node);
+ }
+
+ fscanf(xml_file, " </%[^>\n]> ", buffer);
+ if(strcmp(buffer, "menu") != 0)
+ DEBUGMSG(dbg_menu_parser, "load_menu_from_file(): warning - no closing menu tag, found %s instead\n", buffer);
+ }
+ else if(strcmp(buffer, "item") == 0)
+ {
+ read_attributes(xml_file, new_node);
+ if(new_node->title == NULL)
+ {
+ DEBUGMSG(dbg_menu_parser, "load_menu_from_file(): no title attribute, exiting\n");
+ return NULL;
+ }
+ }
+ else
+ {
+ DEBUGMSG(dbg_menu_parser, "load_menu_from_file(): unknown tag: %s\n, exiting\n", buffer);
+ return NULL;
+ }
+
+ DEBUGMSG(dbg_menu_parser, "load_menu_from_file(): node loaded successfully\n");
+ return new_node;
+}
+
+/* recursively free all non-NULL pointers in a menu tree */
+void free_menu(MenuNode* menu)
+{
+ int i;
+
+ DEBUGMSG(dbg_menu, "entering free_menu()\n");
+ if(menu != NULL)
+ {
+ if(menu->title != NULL)
+ free(menu->title);
+ if(menu->icon_name != NULL)
+ free(menu->icon_name);
+ if(menu->icon != NULL)
+ FreeSprite(menu->icon);
+
+ if(menu->submenu != NULL)
+ {
+ for(i = 0; i < menu->submenu_size; i++)
+ if(menu->submenu[i] != NULL)
+ {
+ free_menu(menu->submenu[i]);
+ menu->submenu[i] = NULL;
+ }
+ free(menu->submenu);
+ }
+
+ free(menu);
+ }
+}
+
+/* create a simple one-level menu without sprites.
+ all given strings are copied */
+MenuNode* CreateOneLevelMenu(int items, char** item_names, char* title, char* trailer)
+{
+ MenuNode* menu = create_empty_node();
+ int i;
+
+ if(title)
+ {
+ menu->title = strdup(title);
+ menu->show_title = true;
+ }
+ menu->submenu_size = items + (trailer ? 1 : 0);
+ menu->submenu = (MenuNode**) malloc(menu->submenu_size * sizeof(MenuNode*));
+ for(i = 0; i < items; i++)
+ {
+ menu->submenu[i] = create_empty_node();
+ menu->submenu[i]->title = strdup(item_names[i]);
+ menu->submenu[i]->activity = i;
+ }
+
+ if(trailer)
+ {
+ menu->submenu[items] = create_empty_node();
+ menu->submenu[items]->title = strdup(trailer);
+ menu->submenu[items]->activity = items;
+ }
+
+ return menu;
+}
+
+void SetActivitiesList(int num, char** acts)
+{
+ n_of_activities = num;
+ activities = acts;
+}
+
+void SetMenuSounds(Mix_Music* music, Mix_Chunk* click, Mix_Chunk* hover)
+{
+ snd_click = click;
+ snd_hover = hover;
+ menu_music = music;
+}
+
+void InitMenu()
+{
+ black.r = 0x00; black.g = 0x00; black.b = 0x00;
+ red.r = 0xff; red.g = 0x00; red.b = 0x00;
+ white.r = 0xff; white.g = 0xff; white.b = 0xff;
+ yellow.r = 0xff; yellow.g = 0xff; yellow.b = 0x00;
+}
+
+/* Display the menu and run the event loop.
+ if return_choice = true then return chosen value instead of
+ running handle_activity()
+ this function is a modified copy of choose_menu_item() */
+int RunMenu(MenuNode* root, bool return_choice, void (*draw_background)(), int (*handle_event)(SDL_Event*), void (*handle_animations)(), int (*handle_activity)(int, int))
+{
+ SDL_Surface** menu_item_unselected = NULL;
+ SDL_Surface** menu_item_selected = NULL;
+ SDL_Surface* title_surf;
+ SDL_Event event;
+ MenuNode* menu = root;
+ MenuNode* tmp_node;
+
+ SDL_Rect tmp_rect;
+ sprite* tmp_sprite;
+ int i;
+ int stop = 0;
+ int items;
+
+ int action = NONE;
+
+ Uint32 frame_start = 0; //For keeping frame rate constant
+ Uint32 frame_now = 0;
+ Uint32 frame_counter = 0;
+ int loc = -1; //The currently selected menu item
+ int old_loc = -1;
+ int click_flag = 1;
+
+ for(;;) /* one loop body execution for one menu page */
+ {
+ DEBUGMSG(dbg_menu, "run_menu(): drawing whole new menu page\n");
+
+ draw_background();
+ /* render buttons for current menu page */
+ menu_item_unselected = render_buttons(menu, false);
+ menu_item_selected = render_buttons(menu, true);
+ items = min(menu->entries_per_screen, menu->submenu_size - menu->first_entry);
+
+ DEBUGMSG(dbg_menu, "run_menu(): drawing %d buttons\n", items);
+ for(i = 0; i < items; i++)
+ {
+ if(loc == i)
+ SDL_BlitSurface(menu_item_selected[i], NULL, GetScreen(), &menu->submenu[menu->first_entry + i]->button_rect);
+ else
+ SDL_BlitSurface(menu_item_unselected[i], NULL, GetScreen(), &menu->submenu[menu->first_entry + i]->button_rect);
+ if(menu->submenu[menu->first_entry + i]->icon)
+ SDL_BlitSurface(menu->submenu[menu->first_entry + i]->icon->default_img, NULL, GetScreen(), &menu->submenu[menu->first_entry + i]->icon_rect);
+ }
+
+ SDL_BlitSurface(stop_button, NULL, GetScreen(), &stop_rect);
+
+ if(menu->entries_per_screen < menu->submenu_size)
+ {
+ /* display arrows */
+ if(menu->first_entry > 0)
+ SDL_BlitSurface(prev_arrow, NULL, GetScreen(), &prev_rect);
+ else
+ SDL_BlitSurface(prev_gray, NULL, GetScreen(), &prev_rect);
+ if(menu->first_entry + items < menu->submenu_size)
+ SDL_BlitSurface(next_arrow, NULL, GetScreen(), &next_rect);
+ else
+ SDL_BlitSurface(next_gray, NULL, GetScreen(), &next_rect);
+ }
+
+ if(menu->show_title)
+ {
+ menu_title_rect = menu->submenu[0]->button_rect;
+ menu_title_rect.y = menu_rect.y - menu_title_rect.h;
+ title_surf = BlackOutline(_(menu->title), curr_font_size, &red);
+ SDL_BlitSurface(title_surf, NULL, GetScreen(), &menu_title_rect);
+ SDL_FreeSurface(title_surf);
+ }
+ SDL_UpdateRect(GetScreen(), 0, 0, 0, 0);
+
+ SDL_WM_GrabInput(SDL_GRAB_OFF);
+
+ while (SDL_PollEvent(&event)); // clear pending events
+
+ /******** Main loop: *********/
+ stop = false;
+ DEBUGMSG(dbg_menu, "run_menu(): entering menu loop\n");
+ while (!stop)
+ {
+ frame_start = SDL_GetTicks(); /* For keeping frame rate constant.*/
+
+ action = NONE;
+ while (!stop && SDL_PollEvent(&event))
+ {
+ switch (event.type)
+ {
+ case SDL_QUIT:
+ {
+ FreeSurfaceArray(menu_item_unselected, items);
+ FreeSurfaceArray(menu_item_selected, items);
+ return QUIT;
+ }
+
+ case SDL_MOUSEMOTION:
+ {
+ loc = -1;
+ for (i = 0; i < items; i++)
+ {
+ if (inRect(menu->submenu[menu->first_entry + i]->button_rect, event.motion.x, event.motion.y))
+ {
+ if(snd_hover)
+ playsound(snd_hover);
+ loc = i;
+ break; /* from for loop */
+ }
+ }
+
+ /* "Left" button - make click if button active: */
+ if(inRect(prev_rect, event.motion.x, event.motion.y)
+ && menu->first_entry > 0)
+ {
+ if(click_flag)
+ {
+ if(snd_hover)
+ playsound(snd_hover);
+ click_flag = 0;
+ }
+ }
+
+ /* "Right" button - make click if button active: */
+ else if(inRect(next_rect, event.motion.x, event.motion.y)
+ && menu->first_entry + items < menu->submenu_size)
+ {
+ if(click_flag)
+ {
+ if(snd_hover)
+ playsound(snd_hover);
+ click_flag = 0;
+ }
+ }
+
+ /* "stop" button */
+ else if (inRect(stop_rect, event.motion.x, event.motion.y ))
+ {
+ if(click_flag)
+ {
+ if(snd_hover)
+ playsound(snd_hover);
+ click_flag = 0;
+ }
+ }
+
+ else // Mouse outside of arrow rects - re-enable click sound:
+ click_flag = 1;
+
+ break;
+ }
+
+ case SDL_MOUSEBUTTONDOWN:
+ {
+ loc = -1; // By default, don't be in any entry
+ for (i = 0; i < items; i++)
+ {
+ if (inRect(menu->submenu[menu->first_entry + i]->button_rect, event.motion.x, event.motion.y))
+ {
+ // Play sound if loc is being changed:
+ if(snd_click)
+ playsound(snd_click);
+ loc = i;
+ action = CLICK;
+ break; /* from for loop */
+ }
+ }
+
+ /* "Left" button */
+ if (inRect(prev_rect, event.motion.x, event.motion.y)
+ && menu->first_entry > 0)
+ {
+ if(snd_click)
+ playsound(snd_click);
+ action = PAGEUP;
+ }
+
+ /* "Right" button - go to next page: */
+ else if (inRect(next_rect, event.motion.x, event.motion.y )
+ && menu->first_entry + items < menu->submenu_size)
+ {
+ if(snd_click)
+ playsound(snd_click);
+ action = PAGEDOWN;
+ }
+
+ /* "Stop" button - go to main menu: */
+ else if (inRect(stop_rect, event.button.x, event.button.y ))
+ {
+ if(snd_click)
+ playsound(snd_click);
+ action = STOP_ESC;
+ }
+
+ break;
+ } /* End of case SDL_MOUSEDOWN */
+
+ case SDL_KEYDOWN:
+ {
+ /* Proceed according to particular key pressed: */
+ switch (event.key.keysym.sym)
+ {
+ case SDLK_ESCAPE:
+ {
+ action = STOP_ESC;
+ break;
+ }
+
+ case SDLK_RETURN:
+ case SDLK_SPACE:
+ case SDLK_KP_ENTER:
+ {
+ if(snd_click)
+ playsound(snd_click);
+ action = CLICK;
+ break;
+ }
+
+ /* Go to previous page, if present: */
+ case SDLK_LEFT:
+ case SDLK_PAGEUP:
+ {
+ if(snd_click)
+ playsound(snd_click);
+ if (menu->first_entry > 0)
+ action = PAGEUP;
+ break;
+ }
+
+ /* Go to next page, if present: */
+ case SDLK_RIGHT:
+ case SDLK_PAGEDOWN:
+ {
+ if(snd_click)
+ playsound(snd_click);
+ if (menu->first_entry + items < menu->submenu_size)
+ action = PAGEDOWN;
+ break;
+ }
+
+ /* Go up one entry, if present: */
+ case SDLK_UP:
+ {
+ if(snd_hover)
+ playsound(snd_hover);
+ if (loc > 0)
+ loc--;
+ else if (menu->submenu_size <= menu->entries_per_screen)
+ loc = menu->submenu_size - 1; // wrap around if only 1 GetScreen()
+ else if (menu->first_entry > 0)
+ {
+ loc = menu->entries_per_screen - 1;
+ action = PAGEUP;
+ }
+ break;
+ }
+
+ case SDLK_DOWN:
+ {
+ if(snd_hover)
+ playsound(snd_hover);
+ if (loc + 1 < min(menu->submenu_size, menu->entries_per_screen))
+ loc++;
+ else if (menu->submenu_size <= menu->entries_per_screen)
+ loc = 0; // wrap around if only 1 GetScreen()
+ else if (menu->first_entry + menu->entries_per_screen < menu->submenu_size)
+ {
+ loc = 0;
+ action = PAGEDOWN;
+ }
+ break;
+ }
+
+ /* Toggle GetScreen() mode: */
+ case SDLK_F10:
+ {
+ SwitchScreenMode();
+ action = RESIZED;
+ break;
+ }
+
+ /* Toggle menu music: */
+/* case SDLK_F11:
+ {
+ if (Opts_GetGlobalOpt(MENU_MUSIC))
+ {
+ audioMusicUnload( );
+ Opts_SetGlobalOpt(MENU_MUSIC, 0);
+ }
+ else
+ {
+ Opts_SetGlobalOpt(MENU_MUSIC, 1);
+ audioMusicLoad("tuxi.ogg", -1);
+ }
+ break;
+ }*/
+
+ default:
+ {
+ /* Some other key - do nothing. */
+ }
+
+ break; /* To get out of _outer_ switch/case statement */
+ } /* End of key switch statement */
+ } // End of case SDL_KEYDOWN in outer switch statement
+ } // End event switch statement
+
+ if (old_loc != loc) {
+ DEBUGMSG(dbg_menu, "run_menu(): changed button focus, old=%d, new=%d\n", old_loc, loc);
+ if(old_loc >= 0 && old_loc < items)
+ {
+ tmp_rect = menu->submenu[old_loc + menu->first_entry]->button_rect;
+ SDL_BlitSurface(menu_item_unselected[old_loc], NULL, GetScreen(), &tmp_rect);
+ if(menu->submenu[menu->first_entry + old_loc]->icon)
+ SDL_BlitSurface(menu->submenu[menu->first_entry + old_loc]->icon->default_img, NULL, GetScreen(), &menu->submenu[menu->first_entry + old_loc]->icon_rect);
+ SDL_UpdateRect(GetScreen(), tmp_rect.x, tmp_rect.y, tmp_rect.w, tmp_rect.h);
+ }
+ if(loc >= 0 && loc < items)
+ {
+ tmp_rect = menu->submenu[loc + menu->first_entry]->button_rect;
+ SDL_BlitSurface(menu_item_selected[loc], NULL, GetScreen(), &tmp_rect);
+ if(menu->submenu[menu->first_entry + loc]->icon)
+ {
+ SDL_BlitSurface(menu->submenu[menu->first_entry + loc]->icon->default_img, NULL, GetScreen(), &menu->submenu[menu->first_entry + loc]->icon_rect);
+ menu->submenu[menu->first_entry + loc]->icon->cur = 0;
+ }
+ SDL_UpdateRect(GetScreen(), tmp_rect.x, tmp_rect.y, tmp_rect.w, tmp_rect.h);
+ }
+ old_loc = loc;
+ }
+
+ if(handle_event(&event))
+ stop = true;
+
+ switch(action)
+ {
+ case RESIZED:
+ RenderTitleScreen();
+ menu->first_entry = 0;
+ prerender_all();
+ stop = true;
+ break;
+
+ case CLICK:
+ if(loc < 0 || loc >= items)
+ {
+ DEBUGMSG(dbg_menu, "run_menu(): incorrect location for CLICK action (%d) !\n", loc);
+ }
+ else
+ {
+ tmp_node = menu->submenu[menu->first_entry + loc];
+ if(tmp_node->submenu_size == 0)
+ {
+ if(return_choice)
+ {
+ FreeSurfaceArray(menu_item_unselected, items);
+ FreeSurfaceArray(menu_item_selected, items);
+ return tmp_node->activity;
+ }
+ else
+ {
+ if(tmp_node->activity == RUN_MAIN_MENU)
+ {
+ /* go back to the root of this menu */
+ menu = root;
+ }
+ else
+ {
+ if(handle_activity(tmp_node->activity, tmp_node->param) == QUIT)
+ {
+ DEBUGMSG(dbg_menu, "run_menu(): handle_activity() returned QUIT message, exiting.\n");
+ FreeSurfaceArray(menu_item_unselected, items);
+ FreeSurfaceArray(menu_item_selected, items);
+ return QUIT;
+ }
+ }
+ }
+ }
+ else
+ {
+ menu->first_entry = 0;
+ menu = tmp_node;
+ menu->first_entry = 0;
+ }
+ stop = true;
+ }
+ break;
+
+ case STOP_ESC:
+ if(menu->parent == NULL)
+ {
+ FreeSurfaceArray(menu_item_unselected, items);
+ FreeSurfaceArray(menu_item_selected, items);
+ return STOP;
+ }
+ else
+ menu = menu->parent;
+ stop = true;
+ break;
+
+ case PAGEUP:
+ menu->first_entry -= menu->entries_per_screen;
+ stop = true;
+ break;
+
+ case PAGEDOWN:
+ menu->first_entry += menu->entries_per_screen;
+ stop = true;
+ break;
+ }
+
+ } // End of SDL_PollEvent while loop
+
+ if(stop)
+ break;
+
+ if(!stop && frame_counter % 5 == 0 && loc >= 0 && loc < items)
+ {
+ tmp_sprite = menu->submenu[menu->first_entry + loc]->icon;
+ if(tmp_sprite)
+ {
+ SDL_BlitSurface(menu_item_selected[loc], NULL, GetScreen(), &menu->submenu[menu->first_entry + loc]->icon_rect);
+ SDL_BlitSurface(tmp_sprite->frame[tmp_sprite->cur], NULL, GetScreen(), &menu->submenu[menu->first_entry + loc]->icon_rect);
+ UpdateRect(GetScreen(), &menu->submenu[menu->first_entry + loc]->icon_rect);
+ NextFrame(tmp_sprite);
+ }
+ }
+
+ handle_animations();
+
+ /* Wait so we keep frame rate constant: */
+ frame_now = SDL_GetTicks();
+ if (frame_now < frame_start)
+ frame_start = frame_now; // in case the timer wraps around
+ if((frame_now - frame_start) < 1000 / MAX_FPS)
+ SDL_Delay(1000 / MAX_FPS - (frame_now - frame_start));
+
+ frame_counter++;
+ } // End of while(!stop) loop
+
+ /* free button surfaces */
+ DEBUGMSG(dbg_menu, "run_menu(): freeing %d button surfaces\n", items);
+ FreeSurfaceArray(menu_item_unselected, items);
+ FreeSurfaceArray(menu_item_selected, items);
+ }
+
+ return QUIT;
+}
+
+/* return button surfaces that are currently displayed (without sprites) */
+SDL_Surface** render_buttons(MenuNode* menu, bool selected)
+{
+ SDL_Surface** menu_items = NULL;
+ SDL_Rect curr_rect;
+ SDL_Surface* tmp_surf = NULL;
+ int i;
+ int items = min(menu->entries_per_screen, menu->submenu_size - menu->first_entry);
+
+ menu_items = (SDL_Surface**) malloc(items * sizeof(SDL_Surface*));
+ if(NULL == menu_items)
+ {
+ DEBUGMSG(dbg_menu, "render_buttons(): failed to allocate memory for buttons!\n");
+ return NULL; // error
+ }
+
+ for (i = 0; i < items; i++)
+ {
+ curr_rect = menu->submenu[menu->first_entry + i]->button_rect;
+ menu_items[i] = SDL_CreateRGBSurface(SDL_SWSURFACE|SDL_SRCALPHA,
+ curr_rect.w,
+ curr_rect.h,
+ 32,
+ rmask, gmask, bmask, amask);
+
+ SDL_BlitSurface(GetScreen(), &curr_rect, menu_items[i], NULL);
+ /* button */
+ if(selected)
+ tmp_surf = CreateButton(curr_rect.w, curr_rect.h, button_radius * curr_rect.h, SEL_RGBA);
+ else
+ tmp_surf = CreateButton(curr_rect.w, curr_rect.h, button_radius * curr_rect.h, REG_RGBA);
+
+ SDL_BlitSurface(tmp_surf, NULL, menu_items[i], NULL);
+ SDL_FreeSurface(tmp_surf);
+
+ /* text */
+ tmp_surf = BlackOutline(_(menu->submenu[menu->first_entry + i]->title),
+ curr_font_size, selected ? &yellow : &white);
+ SDL_BlitSurface(tmp_surf, NULL, menu_items[i], &menu->submenu[menu->first_entry + i]->text_rect);
+ SDL_FreeSurface(tmp_surf);
+ }
+
+ return menu_items;
+}
+
+/* recursively load sprites and calculate button rects
+ to fit into current screen */
+void prerender_menu(MenuNode* menu)
+{
+ SDL_Surface* temp_surf;
+ MenuNode* curr_node;
+ int i, imod, max_text_h = 0, max_text_w = 0;
+ int button_h, button_w;
+ bool found_icons = false;
+ char filename[buf_size];
+
+ if(NULL == menu)
+ {
+ DEBUGMSG(dbg_menu, "prerender_menu(): NULL pointer, exiting !\n");
+ return;
+ }
+
+ if(0 == menu->submenu_size)
+ {
+ DEBUGMSG(dbg_menu, "prerender_menu(): no submenu, exiting.\n");
+ return;
+ }
+
+ for(i = 0; i < menu->submenu_size; i++)
+ {
+ if(menu->submenu[i]->icon_name)
+ found_icons = true;
+ temp_surf = NULL;
+ temp_surf = SimpleText(_(menu->submenu[i]->title), curr_font_size, &black);
+ if(temp_surf)
+ {
+ max_text_h = max(max_text_h, temp_surf->h);
+ max_text_w = max(max_text_w, temp_surf->w);
+ SDL_FreeSurface(temp_surf);
+ }
+ }
+
+ button_h = (1.0 + 2.0 * text_h_gap) * max_text_h;
+ button_w = max_text_w + ( (found_icons ? 1.0 : 0.0) + 2.0 * text_w_gap) * button_h;
+
+ menu->entries_per_screen = (int) ( (menu_rect.h - button_gap * button_h) /
+ ( (1.0 + button_gap) * button_h ) );
+
+ for(i = 0; i < menu->submenu_size; i++)
+ {
+ curr_node = menu->submenu[i];
+ curr_node->button_rect.x = menu_rect.x;
+ imod = i % menu->entries_per_screen;
+ curr_node->button_rect.y = menu_rect.y + imod * button_h + (imod + 1) * button_gap * button_h;
+ curr_node->button_rect.w = button_w;
+ curr_node->button_rect.h = button_h;
+
+ curr_node->icon_rect = curr_node->button_rect;
+ curr_node->icon_rect.w = curr_node->icon_rect.h;
+
+ curr_node->text_rect.x = ( (found_icons ? 1.0 : 0.0) + text_w_gap) * curr_node->icon_rect.w;
+ curr_node->text_rect.y = text_h_gap * max_text_h;
+ curr_node->text_rect.h = max_text_h;
+ curr_node->text_rect.w = max_text_w;
+
+ if(curr_node->icon)
+ FreeSprite(curr_node->icon);
+
+ if(curr_node->icon_name)
+ {
+ sprintf(filename, "sprites/%s", curr_node->icon_name);
+ DEBUGMSG(dbg_menu, "prerender_menu(): loading sprite %s for item #%d.\n", filename, i);
+ curr_node->icon = LoadSpriteOfBoundingBox(filename, IMG_ALPHA, button_h, button_h);
+ }
+ else
+ DEBUGMSG(dbg_menu, "prerender_menu(): no sprite for item #%d.\n", i);
+
+ prerender_menu(menu->submenu[i]);
+ }
+}
+
+char* find_longest_text(MenuNode* menu, int* length)
+{
+ SDL_Surface* text = NULL;
+ char *ret = NULL, *temp = NULL;
+ int i;
+
+ if(menu->submenu_size == 0)
+ {
+ text = SimpleText(_(menu->title), curr_font_size, &black);
+ if(text->w > *length)
+ {
+ *length = text->w;
+ ret = menu->title;
+ }
+ SDL_FreeSurface(text);
+ }
+ else
+ {
+ for(i = 0; i < menu->submenu_size; i++)
+ {
+ temp = find_longest_text(menu->submenu[i], length);
+ if(temp)
+ ret = temp;
+ }
+ }
+ return ret;
+}
+
+/* find the longest text in all existing menus and binary search
+ for the best font size */
+void set_font_size()
+{
+ char* longest = NULL;
+ char* temp;
+ SDL_Surface* surf;
+ int length = 0, i, min_f, max_f, mid_f;
+
+ curr_font_size = default_font_size;
+
+ for(i = 0; i < N_OF_MENUS; i++)
+ {
+ if(menus[i])
+ {
+ temp = find_longest_text(menus[i], &length);
+ if(temp)
+ longest = temp;
+ }
+ }
+
+ if(!longest)
+ return;
+
+ min_f = min_font_size;
+ max_f = max_font_size;
+
+ while(min_f < max_f)
+ {
+ mid_f = (min_f + max_f) / 2;
+ surf = SimpleText(_(longest), mid_f, &black);
+ if(surf->w + (1.0 + 2.0 * text_w_gap) * (1.0 + 2.0 * text_h_gap) * surf->h < menu_rect.w)
+ min_f = mid_f + 1;
+ else
+ max_f = mid_f;
+ SDL_FreeSurface(surf);
+ }
+
+ curr_font_size = min_f;
+}
+
+/* prerender arrows, stop button and all non-NULL menus from menus[] array
+ this function should be invoked after every resolution change */
+void PrerenderAll()
+{
+ int i;
+
+ SetRect(&menu_rect, menu_pos);
+
+ SetRect(&stop_rect, stop_pos);
+ if(stop_button)
+ SDL_FreeSurface(stop_button);
+ stop_button = LoadImageOfBoundingBox(stop_path, IMG_ALPHA, stop_rect.w, stop_rect.h);
+ /* move button to the right */
+ stop_rect.x = GetScreen()->w - stop_button->w;
+
+ SetRect(&prev_rect, prev_pos);
+ if(prev_arrow)
+ SDL_FreeSurface(prev_arrow);
+ prev_arrow = LoadImageOfBoundingBox(prev_path, IMG_ALPHA, prev_rect.w, prev_rect.h);
+ if(prev_gray)
+ SDL_FreeSurface(prev_gray);
+ prev_gray = LoadImageOfBoundingBox(prev_gray_path, IMG_ALPHA, prev_rect.w, prev_rect.h);
+ /* move button to the right */
+ prev_rect.x += prev_rect.w - prev_arrow->w;
+
+ SetRect(&next_rect, next_pos);
+ if(next_arrow)
+ SDL_FreeSurface(next_arrow);
+ next_arrow = LoadImageOfBoundingBox(next_path, IMG_ALPHA, next_rect.w, next_rect.h);
+ if(next_gray)
+ SDL_FreeSurface(next_gray);
+ next_gray = LoadImageOfBoundingBox(next_gray_path, IMG_ALPHA, next_rect.w, next_rect.h);
+
+ set_font_size();
+
+ for(i = 0; i < N_OF_MENUS; i++)
+ if(menus[i])
+ prerender_menu(menus[i]);
+}
+
+void LoadMenu(int index, const char* file_name)
+{
+ FILE* menu_file = NULL;
+ int i;
+
+ if(menus[index])
+ {
+ free_menu(menus[index]);
+ menus[index] = NULL;
+ }
+
+ menu_file = fopen(file_name, "r");
+ if(menu_file == NULL)
+ {
+ DEBUGMSG(dbg_menu, "LoadMenu(): Could not load %s !\n", file_name);
+ }
+ else
+ {
+ menus[index] = load_menu_from_file(menu_file, NULL);
+ fclose(menu_file);
+ }
+}
+
+
+
+/* free all loaded menu trees */
+void UnloadMenus(void)
+{
+ int i;
+
+ DEBUGMSG(dbg_menu, "entering UnloadMenus()\n");
+
+ if(stop_button)
+ {
+ SDL_FreeSurface(stop_button);
+ stop_button = NULL;
+ }
+
+ if(prev_arrow)
+ {
+ SDL_FreeSurface(prev_arrow);
+ prev_arrow = NULL;
+ }
+
+ if(next_arrow)
+ {
+ SDL_FreeSurface(next_arrow);
+ next_arrow = NULL;
+ }
+
+ for(i = 0; i < N_OF_MENUS; i++)
+ if(menus[i] != NULL)
+ {
+ DEBUGMSG(dbg_menu, "UnloadMenus(): freeing menu #%d\n", i);
+ free_menu(menus[i]);
+ }
+
+ DEBUGMSG(dbg_menu, "leaving UnloadMenus()\n");
+}
+
Modified: branches/commonification/tux4kids-common/trunk/src/tux4kids-common.h
===================================================================
--- branches/commonification/tux4kids-common/trunk/src/tux4kids-common.h 2009-07-31 13:57:14 UTC (rev 1305)
+++ branches/commonification/tux4kids-common/trunk/src/tux4kids-common.h 2009-07-31 14:17:50 UTC (rev 1306)
@@ -13,6 +13,8 @@
#define TUX4KIDS_COMMON_H
#include "SDL.h"
+#include "SDL_image.h"
+#include "SDL_mixer.h"
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
#define rmask 0xff000000
@@ -26,10 +28,27 @@
#define amask 0xff000000
#endif
+#define MAX_SPRITE_FRAMES 10
+typedef struct {
+ SDL_Surface *frame[MAX_SPRITE_FRAMES];
+ SDL_Surface *default_img;
+ int num_frames;
+ int cur;
+} sprite;
+
/* functions from t4k-main.c */
void SetDebugMode(int dbg_flags);
+/* functions from tk4-menu.c */
+void LoadMenus(void);
+int RunLoginMenu(void);
+void RunMainMenu(void);
+void UnloadMenus(void);
+
+extern SDL_Rect menu_rect, stop_rect, prev_rect, next_rect;
+extern SDL_Surface *stop_button, *prev_arrow, *next_arrow, *prev_gray, *next_gray;
+
/* functions from tk4-sdl.c */
SDL_Surface* GetScreen();
void DrawButton(SDL_Rect* target_rect, int radius, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
@@ -37,4 +56,31 @@
SDL_Surface* CreateButton(int w, int h, int radius, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
void RoundCorners(SDL_Surface* s, Uint16 radius);
+/* functions from tk4-loaders.c */
+#define IMG_REGULAR 0x01
+#define IMG_COLORKEY 0x02
+#define IMG_ALPHA 0x04
+#define IMG_MODES 0x07
+
+#define IMG_NOT_REQUIRED 0x10
+#define IMG_NO_PNG_FALLBACK 0x20
+
+
+SDL_Surface* LoadImage(const char* file_name, int mode);
+SDL_Surface* LoadScaledImage(const char* file_name, int mode, int width, int height);
+SDL_Surface* LoadImageOfBoundingBox(const char* file_name, int mode, int max_width, int max_height);
+
+SDL_Surface* LoadBkgd(const char* file_name, int width, int height);
+
+sprite* LoadSprite(const char* name, int mode);
+sprite* LoadScaledSprite(const char* name, int mode, int width, int height);
+sprite* LoadSpriteOfBoundingBox(const char* name, int mode, int max_width, int max_height);
+sprite* FlipSprite(sprite* in, int X, int Y);
+void FreeSprite(sprite* gfx);
+void NextFrame(sprite* s);
+
+Mix_Chunk* LoadSound(char* datafile);
+Mix_Music* LoadMusic(char *datafile);
+
+
#endif
More information about the Tux4kids-commits
mailing list