Caution: It's not yet SuperTux independed, more work on this will follow, that's just the first step.
The file structure isn't fixed, better ideas will surely find there way in it!
SVN-Revision: 1592
--- /dev/null
+INCLUDES =
+METASOURCES = AUTO
+lib_LTLIBRARIES = libsupertux.la
+libsupertux_la_SOURCES =app/defines.h \
+ app/gettext.h \
+ app/globals.h app/globals.cpp \
+ app/setup.h app/setup.cpp \
+ audio/musicref.h audio/musicref.cpp \
+ audio/sound.h audio/sound.cpp \
+ audio/sound_manager.h audio/sound_manager.cpp \
+ gui/button.h gui/button.cpp \
+ gui/menu.h gui/menu.cpp \
+ gui/mousecursor.cpp gui/mousecursor.h \
+ math/physic.h math/physic.cpp \
+ math/vector.h math/vector.cpp \
+ special/base.h \
+ special/game_object.h special/game_object.cpp \
+ special/moving_object.h special/moving_object.cpp \
+ special/sprite.h special/sprite.cpp \
+ special/sprite_manager.h special/sprite_manager.cpp \
+ special/stringlist.h special/stringlist.cpp \
+ special/timer.h special/timer.cpp \
+ utils/configfile.h utils/configfile.cpp \
+ utils/exceptions.h \
+ utils/lispreader.h utils/lispreader.cpp \
+ utils/lispwriter.h utils/lispwriter.cpp \
+ video/drawing_context.h video/drawing_context.cpp \
+ video/font.h video/font.cpp \
+ video/screen.h video/screen.cpp \
+ video/surface.h video/surface.cpp
+libsupertux_la_LDFLAGS = -module
+
--- /dev/null
+// $Id$
+//
+// SuperTux
+// Copyright (C) 2000 Bill Kendrick <bill@newbreedsoftware.com>
+// Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#ifndef SUPERTUX_DEFINES_H
+#define SUPERTUX_DEFINES_H 1
+
+#include <config.h>
+
+/* Version: */
+
+#ifndef VERSION
+ #define VERSION "0.1.1"
+#endif
+
+enum Direction { LEFT = 0, RIGHT = 1 };
+
+/* Direction (keyboard/joystick) states: */
+
+#define UP 0
+#define DOWN 1
+
+/* Dying types: */
+
+/* ---- NO 0 */
+enum DyingType {
+ DYING_NOT = 0,
+ DYING_SQUISHED = 1,
+ DYING_FALLING = 2
+};
+
+/* Screen-related stuff */
+// +1 is needed because when tiles are wrapping around the screen there
+// are two partial tiles on the screen
+#define VISIBLE_TILES_X (25 +1)
+#define VISIBLE_TILES_Y (19 +1)
+
+/* Speed constraints: */
+
+#define MAX_WALK_XM 2.3
+#define MAX_RUN_XM 3.2
+#define MAX_YM 20.0
+#define MAX_JUMP_TIME 375
+#define MAX_LIVES 99
+
+#define WALK_SPEED 1.0
+#define RUN_SPEED 1.5
+#define JUMP_SPEED 1.2
+
+/* gameplay related defines */
+
+#define START_LIVES 4
+
+#define MAX_FIRE_BULLETS 2
+#define MAX_ICE_BULLETS 1
+#define FROZEN_TIME 3000
+
+#define YM_FOR_JUMP 6.0
+#define WALK_ACCELERATION_X 0.03
+#define RUN_ACCELERATION_X 0.04
+#define KILL_BOUNCE_YM 8.0
+
+#define SKID_XM 2.0
+#define SKID_TIME 200
+
+/* Size constraints: */
+
+#define X_OFFSCREEN_DISTANCE (screen->w/2)
+#define Y_OFFSCREEN_DISTANCE (screen->h/2)
+
+/* Debugging */
+
+#ifdef DEBUG
+ #define DEBUG_MSG( msg ) { \
+ printf( msg ); printf("\n"); \
+ }
+ #else
+ #define DEBUG_MSG( msg ) {}
+#endif
+
+#define UNUSED_ARG(a) do {/* null */} while (&a == 0)
+
+#endif /*SUPERTUX_DEFINES_H*/
+
--- /dev/null
+/* Convenience header for conditional use of GNU <libintl.h>.
+ Copyright (C) 1995-1998, 2000-2002 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Library General Public License as published
+ by the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ USA. */
+
+#ifndef _LIBGETTEXT_H
+#define _LIBGETTEXT_H 1
+
+#ifdef HAVE_GETTEXT
+# define _(String) gettext(String)
+# define N_(String) gettext_noop(String)
+#else
+# define _(String) String
+# define N_(String) String
+#endif
+
+/* NLS can be disabled through the configure --disable-nls option. */
+#if ENABLE_NLS
+
+/* Get declarations of GNU message catalog functions. */
+#include <libintl.h>
+
+#else
+
+/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which
+ chokes if dcgettext is defined as a macro. So include it now, to make
+ later inclusions of <locale.h> a NOP. We don't include <libintl.h>
+ as well because people using "gettext.h" will not include <libintl.h>,
+ and also including <libintl.h> would fail on SunOS 4, whereas <locale.h>
+ is OK. */
+#if defined(__sun)
+# include <locale.h>
+#endif
+
+#ifndef gettext
+
+/* Disabled NLS.
+ The casts to 'const char *' serve the purpose of producing warnings
+ for invalid uses of the value returned from these functions.
+ On pre-ANSI systems without 'const', the config.h file is supposed to
+ contain "#define const". */
+# define gettext(Msgid) ((const char *) (Msgid))
+# define dgettext(Domainname, Msgid) ((const char *) (Msgid))
+# define dcgettext(Domainname, Msgid, Category) ((const char *) (Msgid))
+# define ngettext(Msgid1, Msgid2, N) \
+ ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
+# define dngettext(Domainname, Msgid1, Msgid2, N) \
+ ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
+# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \
+ ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
+# define textdomain(Domainname) ((const char *) (Domainname))
+# define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname))
+# define bind_textdomain_codeset(Domainname, Codeset) ((const char *) (Codeset))
+
+#endif
+
+#endif
+
+/* A pseudo function call that serves as a marker for the automated
+ extraction of messages, but does not call gettext(). The run-time
+ translation is done at a different place in the code.
+ The argument, String, should be a literal string. Concatenated strings
+ and other string expressions won't work.
+ The macro's expansion is not parenthesized, so that it is suitable as
+ initializer for static 'char[]' or 'const char[]' variables. */
+#define gettext_noop(String) String
+
+#endif /* _LIBGETTEXT_H */
--- /dev/null
+// $Id$
+//
+// SuperTux
+// Copyright (C) 2004 SuperTux Development Team, see AUTHORS for details
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#include "app/globals.h"
+
+/** The datadir prefix prepended when loading game data file */
+std::string datadir;
+
+JoystickKeymap::JoystickKeymap()
+{
+ a_button = 0;
+ b_button = 1;
+ start_button = 2;
+
+ x_axis = 0;
+ y_axis = 1;
+
+ dead_zone = 4096;
+}
+
+JoystickKeymap joystick_keymap;
+
+SDL_Surface * screen;
+Font* gold_text;
+Font* blue_text;
+Font* gray_text;
+Font* yellow_nums;
+Font* white_text;
+Font* white_small_text;
+Font* white_big_text;
+
+MouseCursor * mouse_cursor;
+
+bool use_gl;
+bool use_joystick;
+bool use_fullscreen;
+bool debug_mode;
+bool show_fps;
+float game_speed = 1.0f;
+
+int joystick_num = 0;
+char* level_startup_file = 0;
+bool launch_leveleditor_mode = false;
+bool launch_worldmap_mode = false;
+
+/* SuperTux directory ($HOME/.supertux) and save directory($HOME/.supertux/save) */
+char *st_dir, *st_save_dir;
+
+SDL_Joystick * js;
+
+/* Returns 1 for every button event, 2 for a quit event and 0 for no event. */
+int wait_for_event(SDL_Event& event,unsigned int min_delay, unsigned int max_delay, bool empty_events)
+{
+ int i;
+ Timer maxdelay;
+ Timer mindelay;
+
+ maxdelay.init(false);
+ mindelay.init(false);
+
+ if(max_delay < min_delay)
+ max_delay = min_delay;
+
+ maxdelay.start(max_delay);
+ mindelay.start(min_delay);
+
+ if(empty_events)
+ while (SDL_PollEvent(&event))
+ {}
+
+ /* Handle events: */
+
+ for(i = 0; maxdelay.check() || !i; ++i)
+ {
+ while (SDL_PollEvent(&event))
+ {
+ if(!mindelay.check())
+ {
+ if (event.type == SDL_QUIT)
+ {
+ /* Quit event - quit: */
+ return 2;
+ }
+ else if (event.type == SDL_KEYDOWN)
+ {
+ /* Keypress - skip intro: */
+
+ return 1;
+ }
+ else if (event.type == SDL_JOYBUTTONDOWN)
+ {
+ /* Fire button - skip intro: */
+
+ return 1;
+ }
+ else if (event.type == SDL_MOUSEBUTTONDOWN)
+ {
+ /* Mouse button - skip intro: */
+ return 1;
+ }
+ }
+ }
+ SDL_Delay(10);
+ }
+
+ return 0;
+}
--- /dev/null
+// $Id$
+//
+// SuperTux
+// Copyright (C) 2004 Bill Kendrick <bill@newbreedsoftware.com>
+// Tobias Glaesser <tobi.web@gmx.de>
+// Ingo Ruhnke <grumbel@gmx.de>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#ifndef SUPERTUX_GLOBALS_H
+#define SUPERTUX_GLOBALS_H
+
+#include <string>
+
+#include "SDL.h"
+
+#include "video/font.h"
+#include "gui/menu.h"
+#include "gui/mousecursor.h"
+
+extern std::string datadir;
+
+struct JoystickKeymap
+{
+ int a_button;
+ int b_button;
+ int start_button;
+
+ int x_axis;
+ int y_axis;
+
+ int dead_zone;
+
+ JoystickKeymap();
+};
+
+extern JoystickKeymap joystick_keymap;
+
+extern SDL_Surface* screen;
+extern Font* gold_text;
+extern Font* white_text;
+extern Font* blue_text;
+extern Font* gray_text;
+extern Font* white_small_text;
+extern Font* white_big_text;
+extern Font* yellow_nums;
+
+extern MouseCursor * mouse_cursor;
+
+extern bool use_gl;
+extern bool use_joystick;
+extern bool use_fullscreen;
+extern bool debug_mode;
+extern bool show_fps;
+
+/** The number of the joystick that will be use in the game */
+extern int joystick_num;
+extern char* level_startup_file;
+extern bool launch_leveleditor_mode;
+extern bool launch_worldmap_mode;
+
+/* SuperTux directory ($HOME/.supertux) and save directory($HOME/.supertux/save) */
+extern char* st_dir;
+extern char* st_save_dir;
+
+extern float game_speed;
+extern SDL_Joystick * js;
+
+int wait_for_event(SDL_Event& event,unsigned int min_delay = 0, unsigned int max_delay = 0, bool empty_events = false);
+
+#endif /* SUPERTUX_GLOBALS_H */
--- /dev/null
+// $Id$
+//
+// SuperTux - A Jump'n Run
+// Copyright (C) 2000 Bill Kendrick <bill@newbreedsoftware.com>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#include <cassert>
+#include <cstdio>
+#include <iostream>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <cerrno>
+#include <unistd.h>
+
+#include "SDL.h"
+#include "SDL_image.h"
+#ifndef NOOPENGL
+#include "SDL_opengl.h"
+#endif
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#ifndef WIN32
+#include <libgen.h>
+#endif
+
+#include <cctype>
+
+#include "app/globals.h"
+#include "app/defines.h"
+#include "app/setup.h"
+#include "video/screen.h"
+#include "video/surface.h"
+#include "gui/menu.h"
+#include "utils/configfile.h"
+#include "audio/sound_manager.h"
+#include "app/gettext.h"
+
+
+#ifdef WIN32
+#define mkdir(dir, mode) mkdir(dir)
+// on win32 we typically don't want LFS paths
+#undef DATA_PREFIX
+#define DATA_PREFIX "./data/"
+#endif
+
+/* Screen proprities: */
+/* Don't use this to test for the actual screen sizes. Use screen->w/h instead! */
+#define SCREEN_W 800
+#define SCREEN_H 600
+
+/* Local function prototypes: */
+
+void seticon(void);
+void usage(char * prog, int ret);
+
+/* Does the given file exist and is it accessible? */
+int faccessible(const char *filename)
+{
+ struct stat filestat;
+ if (stat(filename, &filestat) == -1)
+ {
+ return false;
+ }
+ else
+ {
+ if(S_ISREG(filestat.st_mode))
+ return true;
+ else
+ return false;
+ }
+}
+
+/* Can we write to this location? */
+int fwriteable(const char *filename)
+{
+ FILE* fi;
+ fi = fopen(filename, "wa");
+ if (fi == NULL)
+ {
+ return false;
+ }
+ return true;
+}
+
+/* Makes sure a directory is created in either the SuperTux home directory or the SuperTux base directory.*/
+int fcreatedir(const char* relative_dir)
+{
+ char path[1024];
+ snprintf(path, 1024, "%s/%s/", st_dir, relative_dir);
+ if(mkdir(path,0755) != 0)
+ {
+ snprintf(path, 1024, "%s/%s/", datadir.c_str(), relative_dir);
+ if(mkdir(path,0755) != 0)
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+ else
+ {
+ return true;
+ }
+}
+
+FILE * opendata(const char * rel_filename, const char * mode)
+{
+ char * filename = NULL;
+ FILE * fi;
+
+ filename = (char *) malloc(sizeof(char) * (strlen(st_dir) +
+ strlen(rel_filename) + 1));
+
+ strcpy(filename, st_dir);
+ /* Open the high score file: */
+
+ strcat(filename, rel_filename);
+
+ /* Try opening the file: */
+ fi = fopen(filename, mode);
+
+ if (fi == NULL)
+ {
+ fprintf(stderr, "Warning: Unable to open the file \"%s\" ", filename);
+
+ if (strcmp(mode, "r") == 0)
+ fprintf(stderr, "for read!!!\n");
+ else if (strcmp(mode, "w") == 0)
+ fprintf(stderr, "for write!!!\n");
+ }
+ free( filename );
+
+ return(fi);
+}
+
+/* Get all names of sub-directories in a certain directory. */
+/* Returns the number of sub-directories found. */
+/* Note: The user has to free the allocated space. */
+string_list_type dsubdirs(const char *rel_path,const char* expected_file)
+{
+ DIR *dirStructP;
+ struct dirent *direntp;
+ string_list_type sdirs;
+ char filename[1024];
+ char path[1024];
+
+ string_list_init(&sdirs);
+ sprintf(path,"%s/%s",st_dir,rel_path);
+ if((dirStructP = opendir(path)) != NULL)
+ {
+ while((direntp = readdir(dirStructP)) != NULL)
+ {
+ char absolute_filename[1024];
+ struct stat buf;
+
+ sprintf(absolute_filename, "%s/%s", path, direntp->d_name);
+
+ if (stat(absolute_filename, &buf) == 0 && S_ISDIR(buf.st_mode))
+ {
+ if(expected_file != NULL)
+ {
+ sprintf(filename,"%s/%s/%s",path,direntp->d_name,expected_file);
+ if(!faccessible(filename))
+ continue;
+ }
+
+ string_list_add_item(&sdirs,direntp->d_name);
+ }
+ }
+ closedir(dirStructP);
+ }
+
+ sprintf(path,"%s/%s",datadir.c_str(),rel_path);
+ if((dirStructP = opendir(path)) != NULL)
+ {
+ while((direntp = readdir(dirStructP)) != NULL)
+ {
+ char absolute_filename[1024];
+ struct stat buf;
+
+ sprintf(absolute_filename, "%s/%s", path, direntp->d_name);
+
+ if (stat(absolute_filename, &buf) == 0 && S_ISDIR(buf.st_mode))
+ {
+ if(expected_file != NULL)
+ {
+ sprintf(filename,"%s/%s/%s",path,direntp->d_name,expected_file);
+ if(!faccessible(filename))
+ {
+ continue;
+ }
+ else
+ {
+ sprintf(filename,"%s/%s/%s/%s",st_dir,rel_path,direntp->d_name,expected_file);
+ if(faccessible(filename))
+ continue;
+ }
+ }
+
+ string_list_add_item(&sdirs,direntp->d_name);
+ }
+ }
+ closedir(dirStructP);
+ }
+
+ return sdirs;
+}
+
+string_list_type dfiles(const char *rel_path, const char* glob, const char* exception_str)
+{
+ DIR *dirStructP;
+ struct dirent *direntp;
+ string_list_type sdirs;
+ char path[1024];
+
+ string_list_init(&sdirs);
+ sprintf(path,"%s/%s",st_dir,rel_path);
+ if((dirStructP = opendir(path)) != NULL)
+ {
+ while((direntp = readdir(dirStructP)) != NULL)
+ {
+ char absolute_filename[1024];
+ struct stat buf;
+
+ sprintf(absolute_filename, "%s/%s", path, direntp->d_name);
+
+ if (stat(absolute_filename, &buf) == 0 && S_ISREG(buf.st_mode))
+ {
+ if(exception_str != NULL)
+ {
+ if(strstr(direntp->d_name,exception_str) != NULL)
+ continue;
+ }
+ if(glob != NULL)
+ if(strstr(direntp->d_name,glob) == NULL)
+ continue;
+
+ string_list_add_item(&sdirs,direntp->d_name);
+ }
+ }
+ closedir(dirStructP);
+ }
+
+ sprintf(path,"%s/%s",datadir.c_str(),rel_path);
+ if((dirStructP = opendir(path)) != NULL)
+ {
+ while((direntp = readdir(dirStructP)) != NULL)
+ {
+ char absolute_filename[1024];
+ struct stat buf;
+
+ sprintf(absolute_filename, "%s/%s", path, direntp->d_name);
+
+ if (stat(absolute_filename, &buf) == 0 && S_ISREG(buf.st_mode))
+ {
+ if(exception_str != NULL)
+ {
+ if(strstr(direntp->d_name,exception_str) != NULL)
+ continue;
+ }
+ if(glob != NULL)
+ if(strstr(direntp->d_name,glob) == NULL)
+ continue;
+
+ string_list_add_item(&sdirs,direntp->d_name);
+ }
+ }
+ closedir(dirStructP);
+ }
+
+ return sdirs;
+}
+
+void free_strings(char **strings, int num)
+{
+ int i;
+ for(i=0; i < num; ++i)
+ free(strings[i]);
+}
+
+/* --- SETUP --- */
+/* Set SuperTux configuration and save directories */
+void st_directory_setup(void)
+{
+ char *home;
+ char str[1024];
+ /* Get home directory (from $HOME variable)... if we can't determine it,
+ use the current directory ("."): */
+ if (getenv("HOME") != NULL)
+ home = getenv("HOME");
+ else
+ home = ".";
+
+ st_dir = (char *) malloc(sizeof(char) * (strlen(home) +
+ strlen("/.supertux") + 1));
+ strcpy(st_dir, home);
+ strcat(st_dir, "/.supertux");
+
+ /* Remove .supertux config-file from old SuperTux versions */
+ if(faccessible(st_dir))
+ {
+ remove
+ (st_dir);
+ }
+
+ st_save_dir = (char *) malloc(sizeof(char) * (strlen(st_dir) + strlen("/save") + 1));
+
+ strcpy(st_save_dir,st_dir);
+ strcat(st_save_dir,"/save");
+
+ /* Create them. In the case they exist they won't destroy anything. */
+ mkdir(st_dir, 0755);
+ mkdir(st_save_dir, 0755);
+
+ sprintf(str, "%s/levels", st_dir);
+ mkdir(str, 0755);
+
+ // User has not that a datadir, so we try some magic
+ if (datadir.empty())
+ {
+#ifndef WIN32
+ // Detect datadir
+ char exe_file[PATH_MAX];
+ if (readlink("/proc/self/exe", exe_file, PATH_MAX) < 0)
+ {
+ puts("Couldn't read /proc/self/exe, using default path: " DATA_PREFIX);
+ datadir = DATA_PREFIX;
+ }
+ else
+ {
+ std::string exedir = std::string(dirname(exe_file)) + "/";
+
+ datadir = exedir + "../data"; // SuperTux run from source dir
+ if (access(datadir.c_str(), F_OK) != 0)
+ {
+ datadir = exedir + "../share/supertux"; // SuperTux run from PATH
+ if (access(datadir.c_str(), F_OK) != 0)
+ { // If all fails, fall back to compiled path
+ datadir = DATA_PREFIX;
+ }
+ }
+ }
+#else
+ datadir = DATA_PREFIX;
+#endif
+ }
+ printf("Datadir: %s\n", datadir.c_str());
+}
+
+void st_general_setup(void)
+{
+ /* Seed random number generator: */
+
+ srand(SDL_GetTicks());
+
+ /* Set icon image: */
+
+ seticon();
+
+ /* Unicode needed for input handling: */
+
+ SDL_EnableUNICODE(1);
+
+ /* Load global images: */
+ gold_text = new Font(datadir + "/images/fonts/gold.png", Font::TEXT, 16,18);
+ blue_text = new Font(datadir + "/images/fonts/blue.png", Font::TEXT, 16,18,3);
+ white_text = new Font(datadir + "/images/fonts/white.png",
+ Font::TEXT, 16,18);
+ gray_text = new Font(datadir + "/images/fonts/gray.png",
+ Font::TEXT, 16,18);
+ white_small_text = new Font(datadir + "/images/fonts/white-small.png",
+ Font::TEXT, 8,9, 1);
+ white_big_text = new Font(datadir + "/images/fonts/white-big.png",
+ Font::TEXT, 20,22, 3);
+ yellow_nums = new Font(datadir + "/images/fonts/numbers.png",
+ Font::NUM, 32,32);
+
+ /* Load GUI/menu images: */
+ checkbox = new Surface(datadir + "/images/status/checkbox.png", true);
+ checkbox_checked = new Surface(datadir + "/images/status/checkbox-checked.png", true);
+ back = new Surface(datadir + "/images/status/back.png", true);
+ arrow_left = new Surface(datadir + "/images/icons/left.png", true);
+ arrow_right = new Surface(datadir + "/images/icons/right.png", true);
+
+ /* Load the mouse-cursor */
+ mouse_cursor = new MouseCursor( datadir + "/images/status/mousecursor.png",1);
+ MouseCursor::set_current(mouse_cursor);
+
+}
+
+void st_general_free(void)
+{
+
+ /* Free global images: */
+ delete gold_text;
+ delete white_text;
+ delete blue_text;
+ delete gray_text;
+ delete white_small_text;
+ delete white_big_text;
+ delete yellow_nums;
+
+ /* Free GUI/menu images: */
+ delete checkbox;
+ delete checkbox_checked;
+ delete back;
+ delete arrow_left;
+ delete arrow_right;
+
+ /* Free mouse-cursor */
+ delete mouse_cursor;
+
+ /* Free menus */
+ delete main_menu;
+ delete game_menu;
+ delete options_menu;
+ delete options_keys_menu;
+ delete options_joystick_menu;
+ delete highscore_menu;
+ delete contrib_menu;
+ delete contrib_subset_menu;
+ delete save_game_menu;
+ delete load_game_menu;
+}
+
+void st_video_setup(void)
+{
+ /* Init SDL Video: */
+ if (SDL_Init(SDL_INIT_VIDEO) < 0)
+ {
+ fprintf(stderr,
+ "\nError: I could not initialize video!\n"
+ "The Simple DirectMedia error that occured was:\n"
+ "%s\n\n", SDL_GetError());
+ exit(1);
+ }
+
+ /* Open display: */
+ if(use_gl)
+ st_video_setup_gl();
+ else
+ st_video_setup_sdl();
+
+ Surface::reload_all();
+
+ /* Set window manager stuff: */
+ SDL_WM_SetCaption("SuperTux " VERSION, "SuperTux");
+}
+
+void st_video_setup_sdl(void)
+{
+ if (use_fullscreen)
+ {
+ screen = SDL_SetVideoMode(SCREEN_W, SCREEN_H, 0, SDL_FULLSCREEN ) ; /* | SDL_HWSURFACE); */
+ if (screen == NULL)
+ {
+ fprintf(stderr,
+ "\nWarning: I could not set up fullscreen video for "
+ "800x600 mode.\n"
+ "The Simple DirectMedia error that occured was:\n"
+ "%s\n\n", SDL_GetError());
+ use_fullscreen = false;
+ }
+ }
+ else
+ {
+ screen = SDL_SetVideoMode(SCREEN_W, SCREEN_H, 0, SDL_HWSURFACE | SDL_DOUBLEBUF );
+
+ if (screen == NULL)
+ {
+ fprintf(stderr,
+ "\nError: I could not set up video for 800x600 mode.\n"
+ "The Simple DirectMedia error that occured was:\n"
+ "%s\n\n", SDL_GetError());
+ exit(1);
+ }
+ }
+}
+
+void st_video_setup_gl(void)
+{
+#ifndef NOOPENGL
+
+ SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
+ SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
+ SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
+ SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
+ SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+
+ if (use_fullscreen)
+ {
+ screen = SDL_SetVideoMode(SCREEN_W, SCREEN_H, 0, SDL_FULLSCREEN | SDL_OPENGL) ; /* | SDL_HWSURFACE); */
+ if (screen == NULL)
+ {
+ fprintf(stderr,
+ "\nWarning: I could not set up fullscreen video for "
+ "640x480 mode.\n"
+ "The Simple DirectMedia error that occured was:\n"
+ "%s\n\n", SDL_GetError());
+ use_fullscreen = false;
+ }
+ }
+ else
+ {
+ screen = SDL_SetVideoMode(SCREEN_W, SCREEN_H, 0, SDL_OPENGL);
+
+ if (screen == NULL)
+ {
+ fprintf(stderr,
+ "\nError: I could not set up video for 640x480 mode.\n"
+ "The Simple DirectMedia error that occured was:\n"
+ "%s\n\n", SDL_GetError());
+ exit(1);
+ }
+ }
+
+ /*
+ * Set up OpenGL for 2D rendering.
+ */
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_CULL_FACE);
+
+ glViewport(0, 0, screen->w, screen->h);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0, screen->w, screen->h, 0, -1.0, 1.0);
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(0.0f, 0.0f, 0.0f);
+
+#endif
+
+}
+
+void st_joystick_setup(void)
+{
+
+ /* Init Joystick: */
+
+ use_joystick = true;
+
+ if (SDL_Init(SDL_INIT_JOYSTICK) < 0)
+ {
+ fprintf(stderr, "Warning: I could not initialize joystick!\n"
+ "The Simple DirectMedia error that occured was:\n"
+ "%s\n\n", SDL_GetError());
+
+ use_joystick = false;
+ }
+ else
+ {
+ /* Open joystick: */
+ if (SDL_NumJoysticks() <= 0)
+ {
+ fprintf(stderr, "Info: No joysticks were found.\n");
+
+ use_joystick = false;
+ }
+ else
+ {
+ js = SDL_JoystickOpen(joystick_num);
+
+ if (js == NULL)
+ {
+ fprintf(stderr, "Warning: Could not open joystick %d.\n"
+ "The Simple DirectMedia error that occured was:\n"
+ "%s\n\n", joystick_num, SDL_GetError());
+
+ use_joystick = false;
+ }
+ else
+ {
+ if (SDL_JoystickNumAxes(js) < 2)
+ {
+ fprintf(stderr,
+ "Warning: Joystick does not have enough axes!\n");
+
+ use_joystick = false;
+ }
+ else
+ {
+ if (SDL_JoystickNumButtons(js) < 2)
+ {
+ fprintf(stderr,
+ "Warning: "
+ "Joystick does not have enough buttons!\n");
+
+ use_joystick = false;
+ }
+ }
+ }
+ }
+ }
+}
+
+void st_audio_setup(void)
+{
+
+ /* Init SDL Audio silently even if --disable-sound : */
+
+ if (audio_device)
+ {
+ if (SDL_Init(SDL_INIT_AUDIO) < 0)
+ {
+ /* only print out message if sound or music
+ was not disabled at command-line
+ */
+ if (use_sound || use_music)
+ {
+ fprintf(stderr,
+ "\nWarning: I could not initialize audio!\n"
+ "The Simple DirectMedia error that occured was:\n"
+ "%s\n\n", SDL_GetError());
+ }
+ /* keep the programming logic the same :-)
+ because in this case, use_sound & use_music' values are ignored
+ when there's no available audio device
+ */
+ use_sound = false;
+ use_music = false;
+ audio_device = false;
+ }
+ }
+
+
+ /* Open sound silently regarless the value of "use_sound": */
+
+ if (audio_device)
+ {
+ if (open_audio(44100, AUDIO_S16, 2, 2048) < 0)
+ {
+ /* only print out message if sound or music
+ was not disabled at command-line
+ */
+ if (use_sound || use_music)
+ {
+ fprintf(stderr,
+ "\nWarning: I could not set up audio for 44100 Hz "
+ "16-bit stereo.\n"
+ "The Simple DirectMedia error that occured was:\n"
+ "%s\n\n", SDL_GetError());
+ }
+ use_sound = false;
+ use_music = false;
+ audio_device = false;
+ }
+ }
+
+}
+
+
+/* --- SHUTDOWN --- */
+
+void st_shutdown(void)
+{
+ close_audio();
+ SDL_Quit();
+ config->save();
+}
+
+/* --- ABORT! --- */
+
+void st_abort(const std::string& reason, const std::string& details)
+{
+ fprintf(stderr, "\nError: %s\n%s\n\n", reason.c_str(), details.c_str());
+ st_shutdown();
+ abort();
+}
+
+/* Set Icon (private) */
+
+void seticon(void)
+{
+// int masklen;
+// Uint8 * mask;
+ SDL_Surface * icon;
+
+
+ /* Load icon into a surface: */
+
+ icon = IMG_Load((datadir + "/images/supertux.xpm").c_str());
+ if (icon == NULL)
+ {
+ fprintf(stderr,
+ "\nError: I could not load the icon image: %s%s\n"
+ "The Simple DirectMedia error that occured was:\n"
+ "%s\n\n", datadir.c_str(), "/images/supertux.xpm", SDL_GetError());
+ exit(1);
+ }
+
+
+ /* Create mask: */
+/*
+ masklen = (((icon -> w) + 7) / 8) * (icon -> h);
+ mask = (Uint8*) malloc(masklen * sizeof(Uint8));
+ memset(mask, 0xFF, masklen);
+*/
+
+ /* Set icon: */
+
+ SDL_WM_SetIcon(icon, NULL);//mask);
+
+
+ /* Free icon surface & mask: */
+
+// free(mask);
+ SDL_FreeSurface(icon);
+}
+
+
+/* Parse command-line arguments: */
+
+void parseargs(int argc, char * argv[])
+{
+ int i;
+
+ config->load();
+
+ /* Parse arguments: */
+
+ for (i = 1; i < argc; i++)
+ {
+ if (strcmp(argv[i], "--fullscreen") == 0 ||
+ strcmp(argv[i], "-f") == 0)
+ {
+ use_fullscreen = true;
+ }
+ else if (strcmp(argv[i], "--window") == 0 ||
+ strcmp(argv[i], "-w") == 0)
+ {
+ use_fullscreen = false;
+ }
+ else if (strcmp(argv[i], "--joystick") == 0 || strcmp(argv[i], "-j") == 0)
+ {
+ assert(i+1 < argc);
+ joystick_num = atoi(argv[++i]);
+ }
+ else if (strcmp(argv[i], "--joymap") == 0)
+ {
+ assert(i+1 < argc);
+ if (sscanf(argv[++i],
+ "%d:%d:%d:%d:%d",
+ &joystick_keymap.x_axis,
+ &joystick_keymap.y_axis,
+ &joystick_keymap.a_button,
+ &joystick_keymap.b_button,
+ &joystick_keymap.start_button) != 5)
+ {
+ puts("Warning: Invalid or incomplete joymap, should be: 'XAXIS:YAXIS:A:B:START'");
+ }
+ else
+ {
+ std::cout << "Using new joymap:\n"
+ << " X-Axis: " << joystick_keymap.x_axis << "\n"
+ << " Y-Axis: " << joystick_keymap.y_axis << "\n"
+ << " A-Button: " << joystick_keymap.a_button << "\n"
+ << " B-Button: " << joystick_keymap.b_button << "\n"
+ << " Start-Button: " << joystick_keymap.start_button << std::endl;
+ }
+ }
+ else if (strcmp(argv[i], "--leveleditor") == 0)
+ {
+ launch_leveleditor_mode = true;
+ }
+ else if (strcmp(argv[i], "--worldmap") == 0)
+ {
+ launch_worldmap_mode = true;
+ }
+ else if (strcmp(argv[i], "--datadir") == 0
+ || strcmp(argv[i], "-d") == 0 )
+ {
+ assert(i+1 < argc);
+ datadir = argv[++i];
+ }
+ else if (strcmp(argv[i], "--show-fps") == 0)
+ {
+ /* Use full screen: */
+
+ show_fps = true;
+ }
+ else if (strcmp(argv[i], "--opengl") == 0 ||
+ strcmp(argv[i], "-gl") == 0)
+ {
+#ifndef NOOPENGL
+ /* Use OpengGL: */
+
+ use_gl = true;
+#endif
+ }
+ else if (strcmp(argv[i], "--sdl") == 0)
+ {
+ use_gl = false;
+ }
+ else if (strcmp(argv[i], "--usage") == 0)
+ {
+ /* Show usage: */
+
+ usage(argv[0], 0);
+ }
+ else if (strcmp(argv[i], "--version") == 0)
+ {
+ /* Show version: */
+ printf("SuperTux " VERSION "\n");
+ exit(0);
+ }
+ else if (strcmp(argv[i], "--disable-sound") == 0)
+ {
+ /* Disable the compiled in sound feature */
+ printf("Sounds disabled \n");
+ use_sound = false;
+ audio_device = false;
+ }
+ else if (strcmp(argv[i], "--disable-music") == 0)
+ {
+ /* Disable the compiled in sound feature */
+ printf("Music disabled \n");
+ use_music = false;
+ }
+ else if (strcmp(argv[i], "--debug") == 0)
+ {
+ /* Enable the debug-mode */
+ debug_mode = true;
+
+ }
+ else if (strcmp(argv[i], "--help") == 0)
+ { /* Show help: */
+ puts(_(" SuperTux " VERSION "\n"
+ " Please see the file \"README.txt\" for more details.\n"));
+ printf(_("Usage: %s [OPTIONS] FILENAME\n\n"), argv[0]);
+ puts(_("Display Options:\n"
+ " -f, --fullscreen Run in fullscreen mode.\n"
+ " -w, --window Run in window mode.\n"
+ " --opengl If OpenGL support was compiled in, this will tell\n"
+ " SuperTux to make use of it.\n"
+ " --sdl Use the SDL software graphical renderer\n"
+ "\n"
+ "Sound Options:\n"
+ " --disable-sound If sound support was compiled in, this will\n"
+ " disable sound for this session of the game.\n"
+ " --disable-music Like above, but this will disable music.\n"
+ "\n"
+ "Misc Options:\n"
+ " -j, --joystick NUM Use joystick NUM (default: 0)\n"
+ " --joymap XAXIS:YAXIS:A:B:START\n"
+ " Define how joystick buttons and axis should be mapped\n"
+ " --leveleditor Opens the leveleditor in a file.\n"
+ " --worldmap Opens the specified worldmap file.\n"
+ " -d, --datadir DIR Load Game data from DIR (default: automatic)\n"
+ " --debug Enables the debug mode, which is useful for developers.\n"
+ " --help Display a help message summarizing command-line\n"
+ " options, license and game controls.\n"
+ " --usage Display a brief message summarizing command-line options.\n"
+ " --version Display the version of SuperTux you're running.\n\n"
+ ));
+ exit(0);
+ }
+ else if (argv[i][0] != '-')
+ {
+ level_startup_file = argv[i];
+ }
+ else
+ {
+ /* Unknown - complain! */
+
+ usage(argv[0], 1);
+ }
+ }
+}
+
+
+/* Display usage: */
+
+void usage(char * prog, int ret)
+{
+ FILE * fi;
+
+
+ /* Determine which stream to write to: */
+
+ if (ret == 0)
+ fi = stdout;
+ else
+ fi = stderr;
+
+
+ /* Display the usage message: */
+
+ fprintf(fi, _("Usage: %s [--fullscreen] [--opengl] [--disable-sound] [--disable-music] [--debug] | [--usage | --help | --version] [--leveleditor] [--worldmap] FILENAME\n"),
+ prog);
+
+
+ /* Quit! */
+
+ exit(ret);
+}
+
+std::vector<std::string> read_directory(const std::string& pathname)
+{
+ std::vector<std::string> dirnames;
+
+ DIR* dir = opendir(pathname.c_str());
+ if (dir)
+ {
+ struct dirent *direntp;
+
+ while((direntp = readdir(dir)))
+ {
+ dirnames.push_back(direntp->d_name);
+ }
+
+ closedir(dir);
+ }
+
+ return dirnames;
+}
+
+/* EOF */
--- /dev/null
+// $Id$
+//
+// SuperTux - A Jump'n Run
+// Copyright (C) 2000 Bill Kendrick <bill@newbreedsoftware.com>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#ifndef SUPERTUX_SETUP_H
+#define SUPERTUX_SETUP_H
+
+#include <vector>
+#include <string>
+#include "gui/menu.h"
+#include "audio/sound.h"
+#include "special/base.h"
+
+int faccessible(const char *filename);
+int fcreatedir(const char* relative_dir);
+int fwriteable(const char *filename);
+std::vector<std::string> read_directory(const std::string& pathname);
+
+FILE * opendata(const char * filename, const char * mode);
+string_list_type dsubdirs(const char *rel_path, const char* expected_file);
+string_list_type dfiles(const char *rel_path, const char* glob, const char* exception_str);
+void free_strings(char **strings, int num);
+void st_directory_setup(void);
+void st_general_setup(void);
+void st_general_free();
+void st_video_setup_sdl(void);
+void st_video_setup_gl(void);
+void st_video_setup(void);
+void st_audio_setup(void);
+void st_joystick_setup(void);
+void st_shutdown(void);
+void st_abort(const std::string& reason, const std::string& details);
+
+void parseargs(int argc, char * argv[]);
+
+#endif /*SUPERTUX_SETUP_H*/
+
--- /dev/null
+// $Id$
+//
+// SuperTux - A Jump'n Run
+// Copyright (C) 2000 Bill Kendrick <bill@newbreedsoftware.com>
+// Copyright (C) 2004 Matthias Braun <matze@braunis.de>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#include "audio/musicref.h"
+
+MusicRef::MusicRef()
+ : music(0)
+{
+}
+
+MusicRef::MusicRef(SoundManager::MusicResource* newmusic)
+ : music(newmusic)
+{
+ if(music)
+ music->refcount++;
+}
+
+MusicRef::~MusicRef()
+{
+ if(music) {
+ music->refcount--;
+ if(music->refcount == 0)
+ music->manager->free_music(music);
+ }
+}
+
+MusicRef::MusicRef(const MusicRef& other)
+ : music(other.music)
+{
+ if(music)
+ music->refcount++;
+}
+
+MusicRef&
+MusicRef::operator =(const MusicRef& other)
+{
+ SoundManager::MusicResource* oldres = music;
+ music = other.music;
+ if(music)
+ music->refcount++;
+ if(oldres) {
+ oldres->refcount--;
+ if(oldres->refcount == 0)
+ music->manager->free_music(music);
+ }
+
+ return *this;
+}
+
--- /dev/null
+// $Id$
+//
+// SuperTux - A Jump'n Run
+// Copyright (C) 2004 Matthias Braun <matze@braunis.de>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#ifndef SUPERTUX_MUSICREF_H
+#define SUPERTUX_MUSICREF_H
+
+#include "audio/sound_manager.h"
+
+/** This class holds a reference to a music file and maintains a correct
+ * refcount for that file.
+ */
+class MusicRef
+{
+public:
+ MusicRef();
+ MusicRef(const MusicRef& other);
+ ~MusicRef();
+
+ MusicRef& operator= (const MusicRef& other);
+
+private:
+ friend class SoundManager;
+ MusicRef(SoundManager::MusicResource* music);
+
+ SoundManager::MusicResource* music;
+};
+
+#endif /*SUPERTUX_MUSICREF_H*/
+
--- /dev/null
+// $Id$
+//
+// SuperTux - A Jump'n Run
+// Copyright (C) 2000 Bill Kendrick <bill@newbreedsoftware.com>
+// Copyright (C) 2004 Duong-Khang NGUYEN <neoneurone@users.sf.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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#include <string>
+#include "audio/sound.h"
+
+/*global variable*/
+bool use_sound = true; /* handle sound on/off menu and command-line option */
+bool use_music = true; /* handle music on/off menu and command-line option */
+bool audio_device = true; /* != 0: available and initialized */
+
+#include <SDL_mixer.h>
+
+std::vector<Mix_Chunk*> sounds;
+
+/* --- OPEN THE AUDIO DEVICE --- */
+
+int open_audio (int frequency, Uint16 format, int channels, int chunksize)
+{
+ if (Mix_OpenAudio( frequency, format, channels, chunksize ) < 0)
+ return -1;
+
+ // allocate 16 channels for mixing
+ if (Mix_AllocateChannels(8) != 8)
+ return -2;
+
+ return 0;
+}
+
+
+/* --- CLOSE THE AUDIO DEVICE --- */
+
+void close_audio( void )
+{
+ if (audio_device) {
+ Mix_CloseAudio();
+ }
+}
+
+
+/* --- LOAD A SOUND --- */
+
+Mix_Chunk* load_sound(const std::string& file)
+{
+ if(!audio_device)
+ return 0;
+
+ Mix_Chunk* snd = Mix_LoadWAV(file.c_str());
+
+ /*if (snd == 0)
+ st_abort("Can't load", file);*/
+
+ return(snd);
+}
+
+void free_chunk(Mix_Chunk *chunk)
+{
+ Mix_FreeChunk( chunk );
+}
+
--- /dev/null
+// $Id$
+//
+// SuperTux - A Jump'n Run
+// Copyright (C) 2000 Bill Kendrick <bill@newbreedsoftware.com>
+// Copyright (C) 2004 Duong-Khang NGUYEN <neoneurone@users.sf.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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#ifndef SUPERTUX_SOUND_H
+#define SUPERTUX_SOUND_H
+
+//#include "defines.h" /* get YES/NO defines */
+#include <vector>
+
+/*global variable*/
+extern bool use_sound; /* handle sound on/off menu and command-line option */
+extern bool use_music; /* handle music on/off menu and command-line */
+extern bool audio_device; /* != 0: available and initialized */
+
+/* enum of different internal music types */
+enum Music_Type {
+ NO_MUSIC,
+ LEVEL_MUSIC,
+ HURRYUP_MUSIC,
+ HERRING_MUSIC
+};
+
+#include <string>
+#include <SDL_mixer.h>
+
+/* variables for stocking the sound and music */
+extern std::vector<Mix_Chunk*> sounds;
+
+/* functions handling the sound and music */
+int open_audio(int frequency, Uint16 format, int channels, int chunksize);
+void close_audio( void );
+
+Mix_Chunk * load_sound(const std::string& file);
+void free_chunk(Mix_Chunk*chunk);
+
+#endif /*SUPERTUX_SOUND_H*/
--- /dev/null
+// $Id$
+//
+// SuperTux - A Jump'n Run
+// Copyright (C) 2004 Matthias Braun <matze@braunis.de
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#include <cmath>
+#include <cassert>
+
+#include "audio/sound_manager.h"
+#include "audio/musicref.h"
+#include "audio/sound.h"
+#include "app/globals.h"
+#include "app/setup.h"
+#include "special/moving_object.h"
+
+SoundManager::SoundManager()
+ : current_music(0), music_enabled(true)
+{
+}
+
+SoundManager::~SoundManager()
+{
+ if(audio_device)
+ Mix_HaltMusic();
+}
+
+void
+SoundManager::play_sound(Mix_Chunk* sound)
+{
+ if(!audio_device || !use_sound)
+ return;
+
+ Mix_PlayChannel(-1, sound, 0);
+}
+
+void
+SoundManager::play_sound(Mix_Chunk* sound, const MovingObject* object, const Vector& pos)
+{
+ // TODO keep track of the object later and move the sound along with the
+ // object.
+ play_sound(sound, object->get_pos(), pos);
+}
+
+void
+SoundManager::play_sound(Mix_Chunk* sound, const Vector& pos, const Vector& pos2)
+{
+ if(!audio_device || !use_sound)
+ return;
+
+ // TODO make sure this formula is good
+ float distance
+ = pos2.x- pos.x;
+ int loud = int(255.0/float(screen->w*2) * fabsf(distance));
+ if(loud > 255)
+ return;
+
+ int chan = Mix_PlayChannel(-1, sound, 0);
+ if(chan < 0)
+ return;
+ Mix_SetDistance(chan, loud);
+
+ // very bad way to do this...
+ if(distance > 100)
+ Mix_SetPanning(chan, 230, 24);
+ else if(distance < -100)
+ Mix_SetPanning(chan, 24, 230);
+}
+
+MusicRef
+SoundManager::load_music(const std::string& file)
+{
+ if(!audio_device)
+ return MusicRef(0);
+
+ if(!exists_music(file))
+ st_abort("Couldn't load musicfile ", file.c_str());
+
+ std::map<std::string, MusicResource>::iterator i = musics.find(file);
+ assert(i != musics.end());
+ return MusicRef(& (i->second));
+}
+
+bool
+SoundManager::exists_music(const std::string& file)
+{
+ if(!audio_device)
+ return true;
+
+ // song already loaded?
+ std::map<std::string, MusicResource>::iterator i = musics.find(file);
+ if(i != musics.end()) {
+ return true;
+ }
+
+ Mix_Music* song = Mix_LoadMUS(file.c_str());
+ if(song == 0)
+ return false;
+
+ // insert into music list
+ std::pair<std::map<std::string, MusicResource>::iterator, bool> result =
+ musics.insert(
+ std::make_pair<std::string, MusicResource> (file, MusicResource()));
+ MusicResource& resource = result.first->second;
+ resource.manager = this;
+ resource.music = song;
+
+ return true;
+}
+
+void
+SoundManager::free_music(MusicResource* )
+{
+ // TODO free music, currently we can't do this since SDL_mixer seems to have
+ // some bugs if you load/free alot of mod files.
+}
+
+void
+SoundManager::play_music(const MusicRef& musicref, int loops)
+{
+ if(!audio_device)
+ return;
+
+ if(musicref.music == 0 || current_music == musicref.music)
+ return;
+
+ if(current_music)
+ current_music->refcount--;
+
+ current_music = musicref.music;
+ current_music->refcount++;
+
+ if(music_enabled)
+ Mix_PlayMusic(current_music->music, loops);
+}
+
+void
+SoundManager::halt_music()
+{
+ if(!audio_device)
+ return;
+
+ Mix_HaltMusic();
+
+ if(current_music) {
+ current_music->refcount--;
+ if(current_music->refcount == 0)
+ free_music(current_music);
+ current_music = 0;
+ }
+}
+
+void
+SoundManager::enable_music(bool enable)
+{
+ if(!audio_device)
+ return;
+
+ if(enable == music_enabled)
+ return;
+
+ music_enabled = enable;
+ if(music_enabled == false) {
+ Mix_HaltMusic();
+ } else {
+ Mix_PlayMusic(current_music->music, -1);
+ }
+}
+
+SoundManager::MusicResource::~MusicResource()
+{
+ // don't free music buggy SDL_Mixer crashs for some mod files
+ // Mix_FreeMusic(music);
+}
+
--- /dev/null
+// $Id$
+//
+// SuperTux - A Jump'n Run
+// Copyright (C) 2004 Matthias Braun <matze@braunis.de
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#ifndef SUPERTUX_SOUND_MANAGER_H
+#define SUPERTUX_SOUND_MANAGER_H
+
+#include <string>
+#include <map>
+
+#include "SDL_mixer.h"
+
+#include "math/vector.h"
+
+class MusicRef;
+class MovingObject;
+
+/** This class handles all sounds that are played
+ */
+class SoundManager
+{
+public:
+ SoundManager();
+ ~SoundManager();
+
+ void play_sound(Mix_Chunk* sound);
+ void play_sound(Mix_Chunk* sound, const Vector& pos, const Vector& pos2);
+ void play_sound(Mix_Chunk* sound, const MovingObject* object, const Vector& pos);
+
+ MusicRef load_music(const std::string& file);
+ bool exists_music(const std::string& filename);
+
+ void play_music(const MusicRef& music, int loops = -1);
+ void halt_music();
+
+ void enable_music(bool enable);
+
+private:
+ // music part
+ friend class MusicRef;
+ class MusicResource
+ {
+ public:
+ ~MusicResource();
+
+ SoundManager* manager;
+ Mix_Music* music;
+ int refcount;
+ };
+
+ void free_music(MusicResource* music);
+
+ std::map<std::string, MusicResource> musics;
+ MusicResource* current_music;
+ bool music_enabled;
+};
+
+#endif /*SUPERTUX_SOUND_MANAGER_H*/
+
--- /dev/null
+// $Id$
+//
+// SuperTux
+// Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#include <cstring>
+#include <cstdlib>
+
+#include "app/setup.h"
+#include "video/screen.h"
+#include "video/drawing_context.h"
+#include "app/globals.h"
+#include "gui/button.h"
+
+Timer Button::popup_timer;
+
+Button::Button(Surface* button_image, const std::string& ninfo,
+ SDLKey nshortcut, int x, int y, int mw, int mh)
+{
+ popup_timer.init(false);
+
+ if(button_image)
+ icon.push_back(button_image);
+
+ info = ninfo;
+
+ shortcut = nshortcut;
+
+ rect.x = x;
+ rect.y = y;
+ rect.w = icon[0]->w;
+ rect.h = icon[0]->h;
+ tag = -1;
+ state = BUTTON_NONE;
+ show_info = false;
+}
+
+Button::Button(const std::string& imagefilename, const std::string& ninfo,
+ SDLKey nshortcut, int x, int y, int mw, int mh)
+{
+ popup_timer.init(false);
+
+ add_icon(imagefilename, mw, mh);
+
+ info = ninfo;
+
+ shortcut = nshortcut;
+
+ rect.x = x;
+ rect.y = y;
+ rect.w = icon[0]->w;
+ rect.h = icon[0]->h;
+ tag = -1;
+ state = BUTTON_NONE;
+ show_info = false;
+}
+
+void Button::add_icon(const std::string& icon_file, int mw, int mh)
+{
+ char filename[1024];
+
+ if(!icon_file.empty())
+ {
+ snprintf(filename, 1024, "%s/%s", datadir.c_str(), icon_file.c_str());
+ if(!faccessible(filename))
+ snprintf(filename, 1024, "%s/images/icons/default-icon.png", datadir.c_str());
+ }
+ else
+ {
+ snprintf(filename, 1024, "%s/images/icons/default-icon.png", datadir.c_str());
+ }
+
+ if(mw != -1 || mh != -1)
+ {
+ icon.push_back(new Surface(filename,true));
+ icon.back()->resize(mw,mh);
+ }
+ else
+ icon.push_back(new Surface(filename,true));
+
+}
+
+void Button::draw(DrawingContext& context)
+{
+ if(state == BUTTON_HOVER)
+ if(!popup_timer.check())
+ show_info = true;
+
+ fillrect(rect.x,rect.y,rect.w,rect.h,75,75,75,200);
+ fillrect(rect.x+1,rect.y+1,rect.w-2,rect.h-2,175,175,175,200);
+
+ for(std::vector<Surface*>::iterator it = icon.begin(); it != icon.end(); ++it)
+ context.draw_surface(*it, Vector(rect.x,rect.y), LAYER_GUI);
+
+/* if(drawable)
+ {
+ Camera viewport;
+ viewport.set_translation(Vector(rect.x, rect.y));
+ drawable->draw(viewport, 0);
+ }*/
+
+ if(show_info)
+ {
+ char str[80];
+ int i = -32;
+
+ if(0 > rect.x - white_small_text->get_text_width(info))
+ i = rect.w + (int)white_small_text->get_text_width(info);
+
+ if(!info.empty())
+ context.draw_text(white_small_text, info, Vector(i + rect.x - white_small_text->get_text_width(info), rect.y), LAYER_GUI);
+ sprintf(str,"(%s)", SDL_GetKeyName(shortcut));
+ context.draw_text(white_small_text, str, Vector(i + rect.x - white_small_text->get_text_width(str), rect.y + white_small_text->get_height()+2), LAYER_GUI);
+ }
+ if(state == BUTTON_PRESSED || state == BUTTON_DEACTIVE)
+ fillrect(rect.x,rect.y,rect.w,rect.h,75,75,75,200);
+ else if(state == BUTTON_HOVER)
+ fillrect(rect.x,rect.y,rect.w,rect.h,150,150,150,128);
+}
+
+Button::~Button()
+{
+ for(std::vector<Surface*>::iterator it = icon.begin(); it != icon.end(); ++it)
+ delete (*it);
+ icon.clear();
+ // FIXME TODO XXX: commenting this out fixes the leveleditor quit crash
+ // probably should be deleted somehow, though
+ //delete drawable;
+}
+
+void Button::event(SDL_Event &event)
+{
+ if(state == BUTTON_DEACTIVE)
+ return;
+
+ SDLKey key = event.key.keysym.sym;
+
+ if(event.type == SDL_MOUSEBUTTONDOWN || event.type == SDL_MOUSEBUTTONUP)
+ {
+ if(event.button.x < rect.x || event.button.x >= rect.x + rect.w ||
+ event.button.y < rect.y || event.button.y >= rect.y + rect.h)
+ return;
+
+ if(event.button.button == SDL_BUTTON_RIGHT)
+ {
+ show_info = true;
+ return;
+ }
+ else if(event.type == SDL_MOUSEBUTTONUP && event.button.button == 4) /* Mouse wheel up. */
+ {
+ state = BUTTON_WHEELUP;
+ return;
+ }
+ else if(event.type == SDL_MOUSEBUTTONUP && event.button.button == 5) /* Mouse wheel down. */
+ {
+ state = BUTTON_WHEELDOWN;
+ return;
+ }
+
+ if(event.button.button == SDL_BUTTON_LEFT)
+ if(event.type == SDL_MOUSEBUTTONDOWN)
+ state = BUTTON_PRESSED;
+ else
+ state = BUTTON_CLICKED;
+ }
+ else if(event.type == SDL_MOUSEMOTION)
+ {
+ if(event.motion.x < rect.x || event.motion.x >= rect.x + rect.w ||
+ event.motion.y < rect.y || event.motion.y >= rect.y + rect.h)
+ {
+ state = BUTTON_NONE;
+ }
+ else
+ {
+ state = BUTTON_HOVER;
+ popup_timer.start(1500);
+ }
+
+ if(show_info)
+ {
+ show_info = false;
+ }
+ }
+ else if(event.type == SDL_KEYDOWN)
+ {
+ if(key == shortcut)
+ state = BUTTON_PRESSED;
+ }
+ else if(event.type == SDL_KEYUP)
+ {
+ if(state == BUTTON_PRESSED && key == shortcut)
+ state = BUTTON_CLICKED;
+ }
+}
+
+int Button::get_state()
+{
+ int rstate;
+ switch(state)
+ {
+ case BUTTON_CLICKED:
+ case BUTTON_WHEELUP:
+ case BUTTON_WHEELDOWN:
+ rstate = state;
+ state = BUTTON_NONE;
+ return rstate;
+ default:
+ return state;
+ }
+}
+
+ButtonPanel::ButtonPanel(int x, int y, int w, int h)
+{
+ bw = 32;
+ bh = 32;
+ rect.x = x;
+ rect.y = y;
+ rect.w = w;
+ rect.h = h;
+ hidden = false;
+ hlast = false;
+}
+
+Button* ButtonPanel::event(SDL_Event& event)
+{
+ if(!hidden)
+ {
+ Button* ret = NULL;
+ for(std::vector<Button*>::iterator it = item.begin(); it != item.end(); ++it)
+ {
+ (*it)->event(event);
+ if((*it)->state != BUTTON_NONE)
+ {
+ if(hlast && (*it)->state == BUTTON_CLICKED)
+ last_clicked = it;
+ ret = (*it);
+ }
+ }
+ return ret;
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+ButtonPanel::~ButtonPanel()
+{
+ for(std::vector<Button*>::iterator it = item.begin(); it != item.end(); ++it)
+ {
+ delete (*it);
+ }
+ item.clear();
+}
+
+void ButtonPanel::draw(DrawingContext& context)
+{
+
+ if(hidden == false)
+ {
+ fillrect(rect.x,rect.y,rect.w,rect.h,100,100,100,200);
+ for(std::vector<Button*>::iterator it = item.begin(); it != item.end(); ++it)
+ {
+ (*it)->draw(context);
+ if(hlast && it == last_clicked)
+ {
+ fillrect((*it)->get_pos().x,(*it)->get_pos().y,(*it)->get_pos().w,(*it)->get_pos().h,100,100,100,128);
+ }
+ }
+ }
+}
+
+void ButtonPanel::additem(Button* pbutton, int tag)
+{
+ int max_cols, row, col;
+
+ item.push_back(pbutton);
+
+ /* A button_panel takes control of the buttons it contains and arranges them */
+
+ max_cols = rect.w / bw;
+
+ row = (item.size()-1) / max_cols;
+ col = (item.size()-1) % max_cols;
+
+ item[item.size()-1]->rect.x = rect.x + col * bw;
+ item[item.size()-1]->rect.y = rect.y + row * bh;
+ item[item.size()-1]->tag = tag;
+
+}
+
+void ButtonPanel::set_button_size(int w, int h)
+{
+ bw = w;
+ bh = h;
+}
+
+Button* ButtonPanel::manipulate_button(int i)
+{
+ if(int(item.size())-1 < i)
+ return item[item.size()-1];
+ else
+ return item[i];
+}
+
+void ButtonPanel::highlight_last(bool b)
+{
+ hlast = b;
+}
--- /dev/null
+// $Id$
+//
+// SuperTux
+// Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#ifndef SUPERTUX_BUTTON_H
+#define SUPERTUX_BUTTON_H
+
+#include <vector>
+
+#include "video/surface.h"
+#include "special/timer.h"
+
+enum ButtonState {
+ BUTTON_NONE = -1,
+ BUTTON_CLICKED,
+ BUTTON_PRESSED,
+ BUTTON_HOVER,
+ BUTTON_WHEELUP,
+ BUTTON_WHEELDOWN,
+ BUTTON_DEACTIVE
+};
+
+class ButtonPanel;
+
+class Button
+{
+ friend class ButtonPanel;
+
+public:
+ Button(Surface* icon_file, const std::string& info, SDLKey shortcut,
+ int x, int y, int mw = -1, int h = -1);
+ Button(const std::string& icon_name, const std::string& info, SDLKey shortcut,
+ int x, int y, int mw = -1, int h = -1);
+
+ ~Button();
+ void event(SDL_Event& event);
+ void draw(DrawingContext& context);
+ int get_state();
+ void set_active(bool active) { active ? state = BUTTON_NONE : state = BUTTON_DEACTIVE; };
+ void add_icon(const std::string& imagefile, int mw, int mh);
+ SDL_Rect get_pos() { return rect; }
+ int get_tag(){return tag; }
+// void set_drawable(Drawable* newdrawable)
+// { drawable = newdrawable; }
+
+private:
+ static Timer popup_timer;
+// Drawable* drawable;
+ std::vector<Surface*> icon;
+ std::string info;
+ SDLKey shortcut;
+ SDL_Rect rect;
+ bool show_info;
+ ButtonState state;
+ int tag;
+};
+
+class ButtonPanel
+{
+public:
+ ButtonPanel(int x, int y, int w, int h);
+ ~ButtonPanel();
+ void draw(DrawingContext& context);
+ Button* event(SDL_Event &event);
+ void additem(Button* pbutton, int tag);
+ Button* button_panel_event(SDL_Event& event);
+ void set_button_size(int w, int h);
+ Button* manipulate_button(int i);
+ void highlight_last(bool b);
+ void set_last_clicked(unsigned int last)
+ { if(hlast) { if(item.size() >= last) { last_clicked = item.begin() + last; } } };
+
+private:
+ int bw, bh;
+ bool hlast;
+ bool hidden;
+ SDL_Rect rect;
+ std::vector<Button*> item;
+ std::vector<Button*>::iterator last_clicked;
+};
+
+#endif /*SUPERTUX_BUTTON_H*/
--- /dev/null
+// $Id$
+//
+// SuperTux
+// Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#ifndef WIN32
+#include <sys/types.h>
+#include <ctype.h>
+#endif
+
+#include <iostream>
+#include <sstream>
+#include <cstdlib>
+#include <cstdio>
+#include <string>
+#include <cassert>
+
+#include "app/globals.h"
+#include "gui/menu.h"
+#include "video/screen.h"
+#include "video/drawing_context.h"
+#include "app/setup.h"
+#include "audio/sound.h"
+#include "special/timer.h"
+#include "app/gettext.h"
+
+#define FLICK_CURSOR_TIME 500
+
+Surface* checkbox;
+Surface* checkbox_checked;
+Surface* back;
+Surface* arrow_left;
+Surface* arrow_right;
+
+Menu* main_menu = 0;
+Menu* game_menu = 0;
+Menu* options_menu = 0;
+Menu* options_keys_menu = 0;
+Menu* options_joystick_menu = 0;
+Menu* highscore_menu = 0;
+Menu* load_game_menu = 0;
+Menu* save_game_menu = 0;
+Menu* contrib_menu = 0;
+Menu* contrib_subset_menu = 0;
+
+std::vector<Menu*> Menu::last_menus;
+Menu* Menu::current_ = 0;
+
+/* just displays a Yes/No text that can be used to confirm stuff */
+bool confirm_dialog(Surface *background, std::string text)
+{
+ //Surface* cap_screen = Surface::CaptureScreen();
+
+ Menu* dialog = new Menu;
+ dialog->additem(MN_DEACTIVE, text,0,0);
+ dialog->additem(MN_HL,"",0,0);
+ dialog->additem(MN_ACTION,_("Yes"),0,0,true);
+ dialog->additem(MN_ACTION,_("No"),0,0,false);
+ dialog->additem(MN_HL,"",0,0);
+
+ Menu::set_current(dialog);
+
+ DrawingContext context;
+
+ while(true)
+ {
+ SDL_Event event;
+
+ while (SDL_PollEvent(&event))
+ {
+ dialog->event(event);
+ }
+
+ if(background == NULL)
+ context.draw_gradient(Color(200,240,220), Color(200,200,220), LAYER_BACKGROUND0);
+ else
+ context.draw_surface(background, Vector(0,0), LAYER_BACKGROUND0);
+
+ dialog->draw(context);
+ dialog->action();
+
+ switch (dialog->check())
+ {
+ case true:
+ //delete cap_screen;
+ Menu::set_current(0);
+ delete dialog;
+ return true;
+ break;
+ case false:
+ //delete cap_screen;
+ Menu::set_current(0);
+ delete dialog;
+ return false;
+ break;
+ default:
+ break;
+ }
+
+ mouse_cursor->draw(context);
+ context.do_drawing();
+ SDL_Delay(25);
+ }
+
+ return false;
+}
+
+void
+Menu::push_current(Menu* pmenu)
+{
+ if (current_)
+ last_menus.push_back(current_);
+
+ current_ = pmenu;
+ current_->effect.start(500);
+}
+
+void
+Menu::pop_current()
+{
+ if (!last_menus.empty())
+ {
+ current_ = last_menus.back();
+ current_->effect.start(500);
+
+ last_menus.pop_back();
+ }
+ else
+ {
+ current_ = 0;
+ }
+}
+
+void
+Menu::set_current(Menu* menu)
+{
+ last_menus.clear();
+
+ if (menu)
+ menu->effect.start(500);
+
+ current_ = menu;
+}
+
+/* Return a pointer to a new menu item */
+MenuItem*
+MenuItem::create(MenuItemKind kind_, const char *text_, int init_toggle_, Menu* target_menu_, int id, int* int_p_)
+{
+ MenuItem *pnew_item = new MenuItem;
+
+ pnew_item->kind = kind_;
+ pnew_item->text = (char*) malloc(sizeof(char) * (strlen(text_) + 1));
+ strcpy(pnew_item->text, text_);
+
+ if(kind_ == MN_TOGGLE)
+ pnew_item->toggled = init_toggle_;
+ else
+ pnew_item->toggled = false;
+
+ pnew_item->target_menu = target_menu_;
+ pnew_item->input = (char*) malloc(sizeof(char));
+ pnew_item->input[0] = '\0';
+
+ if(kind_ == MN_STRINGSELECT)
+ {
+ pnew_item->list = (string_list_type*) malloc(sizeof(string_list_type));
+ string_list_init(pnew_item->list);
+ }
+ else
+ pnew_item->list = NULL;
+
+ pnew_item->id = id;
+ pnew_item->int_p = int_p_;
+
+ pnew_item->input_flickering = false;
+ pnew_item->input_flickering_timer.init(true);
+ pnew_item->input_flickering_timer.start(FLICK_CURSOR_TIME);
+
+ return pnew_item;
+}
+
+void
+MenuItem::change_text(const char *text_)
+{
+ if (text_)
+ {
+ free(text);
+ text = (char*) malloc(sizeof(char )*(strlen(text_)+1));
+ strcpy(text, text_);
+ }
+}
+
+void
+MenuItem::change_input(const char *text_)
+{
+ if(text)
+ {
+ free(input);
+ input = (char*) malloc(sizeof(char )*(strlen(text_)+1));
+ strcpy(input, text_);
+ }
+}
+
+std::string MenuItem::get_input_with_symbol(bool active_item)
+{
+ if(!active_item)
+ input_flickering = true;
+ else
+ {
+ if(input_flickering_timer.get_left() < 0)
+ {
+ if(input_flickering)
+ input_flickering = false;
+ else
+ input_flickering = true;
+ input_flickering_timer.start(FLICK_CURSOR_TIME);
+ }
+ }
+
+ char str[1024];
+ if(input_flickering)
+ sprintf(str,"%s ",input);
+ else
+ sprintf(str,"%s_",input);
+
+ std::string string = str;
+
+ return string;
+}
+
+/* Set ControlField for keyboard key */
+void Menu::get_controlfield_key_into_input(MenuItem *item)
+{
+ switch(*item->int_p)
+ {
+ case SDLK_UP:
+ item->change_input(_("Up cursor"));
+ break;
+ case SDLK_DOWN:
+ item->change_input(_("Down cursor"));
+ break;
+ case SDLK_LEFT:
+ item->change_input(_("Left cursor"));
+ break;
+ case SDLK_RIGHT:
+ item->change_input(_("Right cursor"));
+ break;
+ case SDLK_RETURN:
+ item->change_input(_("Return"));
+ break;
+ case SDLK_SPACE:
+ item->change_input(_("Space"));
+ break;
+ case SDLK_RSHIFT:
+ item->change_input(_("Right Shift"));
+ break;
+ case SDLK_LSHIFT:
+ item->change_input(_("Left Shift"));
+ break;
+ case SDLK_RCTRL:
+ item->change_input(_("Right Control"));
+ break;
+ case SDLK_LCTRL:
+ item->change_input(_("Left Control"));
+ break;
+ case SDLK_RALT:
+ item->change_input(_("Right Alt"));
+ break;
+ case SDLK_LALT:
+ item->change_input(_("Left Alt"));
+ break;
+ default:
+ {
+ char tmp[64];
+ snprintf(tmp, 64, "%d", *item->int_p);
+ item->change_input(tmp);
+ }
+ break;
+ }
+}
+
+/* Set ControlField for joystick button */
+void Menu::get_controlfield_js_into_input(MenuItem *item)
+{
+ std::ostringstream oss;
+ oss << "Button " << *item->int_p;
+ item->change_input(oss.str().c_str());
+}
+
+/* Free a menu and all its items */
+Menu::~Menu()
+{
+ if(item.size() != 0)
+ {
+ for(unsigned int i = 0; i < item.size(); ++i)
+ {
+ free(item[i].text);
+ free(item[i].input);
+ string_list_free(item[i].list);
+ }
+ }
+}
+
+
+Menu::Menu()
+{
+ hit_item = -1;
+ menuaction = MENU_ACTION_NONE;
+ delete_character = 0;
+ mn_input_char = '\0';
+
+ pos_x = screen->w/2;
+ pos_y = screen->h/2;
+ arrange_left = 0;
+ active_item = 0;
+ effect.init(false);
+
+ joystick_timer.init(true);
+}
+
+void Menu::set_pos(int x, int y, float rw, float rh)
+{
+ pos_x = x + (int)((float)get_width() * rw);
+ pos_y = y + (int)((float)get_height() * rh);
+}
+
+void
+Menu::additem(MenuItemKind kind_, const std::string& text_, int toggle_, Menu* menu_, int id, int* int_p)
+{
+ additem(MenuItem::create(kind_, text_.c_str(), toggle_, menu_, id, int_p));
+}
+
+/* Add an item to a menu */
+void
+Menu::additem(MenuItem* pmenu_item)
+{
+ item.push_back(*pmenu_item);
+ delete pmenu_item;
+}
+
+void
+Menu::clear()
+{
+ item.clear();
+}
+
+/* Process actions done on the menu */
+void
+Menu::action()
+{
+ hit_item = -1;
+ if(item.size() != 0)
+ {
+ switch(menuaction)
+ {
+ case MENU_ACTION_UP:
+ if (active_item > 0)
+ --active_item;
+ else
+ active_item = int(item.size())-1;
+ break;
+
+ case MENU_ACTION_DOWN:
+ if(active_item < int(item.size())-1)
+ ++active_item;
+ else
+ active_item = 0;
+ break;
+
+ case MENU_ACTION_LEFT:
+ if(item[active_item].kind == MN_STRINGSELECT
+ && item[active_item].list->num_items != 0)
+ {
+ if(item[active_item].list->active_item > 0)
+ --item[active_item].list->active_item;
+ else
+ item[active_item].list->active_item = item[active_item].list->num_items-1;
+ }
+ break;
+
+ case MENU_ACTION_RIGHT:
+ if(item[active_item].kind == MN_STRINGSELECT
+ && item[active_item].list->num_items != 0)
+ {
+ if(item[active_item].list->active_item < item[active_item].list->num_items-1)
+ ++item[active_item].list->active_item;
+ else
+ item[active_item].list->active_item = 0;
+ }
+ break;
+
+ case MENU_ACTION_HIT:
+ {
+ hit_item = active_item;
+ switch (item[active_item].kind)
+ {
+ case MN_GOTO:
+ if (item[active_item].target_menu != NULL)
+ Menu::push_current(item[active_item].target_menu);
+ else
+ puts("NULLL");
+ break;
+
+ case MN_TOGGLE:
+ item[active_item].toggled = !item[active_item].toggled;
+ break;
+
+ case MN_ACTION:
+ Menu::set_current(0);
+ item[active_item].toggled = true;
+ break;
+ case MN_TEXTFIELD:
+ case MN_NUMFIELD:
+ menuaction = MENU_ACTION_DOWN;
+ action();
+ break;
+
+ case MN_BACK:
+ Menu::pop_current();
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+
+ case MENU_ACTION_REMOVE:
+ if(item[active_item].kind == MN_TEXTFIELD
+ || item[active_item].kind == MN_NUMFIELD)
+ {
+ if(item[active_item].input != NULL)
+ {
+ int i = strlen(item[active_item].input);
+
+ while(delete_character > 0) /* remove charactes */
+ {
+ item[active_item].input[i-1] = '\0';
+ delete_character--;
+ }
+ }
+ }
+ break;
+
+ case MENU_ACTION_INPUT:
+ if(item[active_item].kind == MN_TEXTFIELD
+ || (item[active_item].kind == MN_NUMFIELD && mn_input_char >= '0' && mn_input_char <= '9'))
+ {
+ if(item[active_item].input != NULL)
+ {
+ int i = strlen(item[active_item].input);
+ item[active_item].input = (char*) realloc(item[active_item].input,sizeof(char)*(i + 2));
+ item[active_item].input[i] = mn_input_char;
+ item[active_item].input[i+1] = '\0';
+ }
+ else
+ {
+ item[active_item].input = (char*) malloc(2*sizeof(char));
+ item[active_item].input[0] = mn_input_char;
+ item[active_item].input[1] = '\0';
+ }
+ }
+
+ case MENU_ACTION_NONE:
+ break;
+ }
+ }
+
+ MenuItem& new_item = item[active_item];
+ if(new_item.kind == MN_DEACTIVE
+ || new_item.kind == MN_LABEL
+ || new_item.kind == MN_HL)
+ {
+ // Skip the horzontal line item
+ if (menuaction != MENU_ACTION_UP && menuaction != MENU_ACTION_DOWN)
+ menuaction = MENU_ACTION_DOWN;
+
+ if (item.size() > 1)
+ action();
+ }
+
+ menuaction = MENU_ACTION_NONE;
+
+ if (active_item >= int(item.size()))
+ active_item = int(item.size()) - 1;
+}
+
+int
+Menu::check()
+{
+ if (hit_item != -1)
+ return item[hit_item].id;
+ else
+ return -1;
+}
+
+void
+Menu::draw_item(DrawingContext& context,
+ int index, // Position of the current item in the menu
+ int menu_width, int menu_height)
+{
+ MenuItem& pitem = item[index];
+
+ int effect_offset = 0;
+ {
+ int effect_time = 0;
+
+ if(effect.check())
+ effect_time = effect.get_left() / 4;
+
+ effect_offset = (index % 2) ? effect_time : -effect_time;
+ }
+
+ Font* text_font = white_text;
+ int x_pos = pos_x;
+ int y_pos = pos_y + 24*index - menu_height/2 + 12 + effect_offset;
+ int shadow_size = 2;
+ int text_width = int(text_font->get_text_width(pitem.text));
+ int input_width = int(text_font->get_text_width(pitem.input) + 10);
+ int list_width =
+ int(text_font->get_text_width(string_list_active(pitem.list)));
+
+ if (arrange_left)
+ x_pos += 24 - menu_width/2 + (text_width + input_width + list_width)/2;
+
+ if(index == active_item)
+ {
+ shadow_size = 3;
+ text_font = blue_text;
+ }
+
+ switch (pitem.kind)
+ {
+ case MN_DEACTIVE:
+ {
+ context.draw_text_center(gray_text, pitem.text,
+ Vector(0, y_pos - int(blue_text->get_height()/2)),
+ LAYER_GUI);
+ break;
+ }
+
+ case MN_HL:
+ {
+ // TODO
+ int x = pos_x - menu_width/2;
+ int y = y_pos - 12 - effect_offset;
+ /* Draw a horizontal line with a little 3d effect */
+ context.draw_filled_rect(Vector(x, y + 6),
+ Vector(menu_width, 4), Color(150,200,255,225), LAYER_GUI);
+ context.draw_filled_rect(Vector(x, y + 6),
+ Vector(menu_width, 2), Color(255,255,255,255), LAYER_GUI);
+ break;
+ }
+ case MN_LABEL:
+ {
+ context.draw_text_center(white_big_text,
+ pitem.text, Vector(0, y_pos - int(white_big_text->get_height()/2)),
+ LAYER_GUI);
+ break;
+ }
+ case MN_TEXTFIELD:
+ case MN_NUMFIELD:
+ case MN_CONTROLFIELD_KB:
+ case MN_CONTROLFIELD_JS:
+ {
+ int width = text_width + input_width + 5;
+ int text_pos = screen->w/2 - width/2;
+ int input_pos = text_pos + text_width + 10;
+
+ context.draw_filled_rect(
+ Vector(input_pos - 5, y_pos - 10),
+ Vector(input_width + 10, 20),
+ Color(255,255,255,255), LAYER_GUI-5);
+ context.draw_filled_rect(
+ Vector(input_pos - 4, y_pos - 9),
+ Vector(input_width + 8, 18),
+ Color(0,0,0,128), LAYER_GUI-4);
+
+ if(pitem.kind == MN_CONTROLFIELD_KB)
+ get_controlfield_key_into_input(&pitem);
+ else if (pitem.kind == MN_CONTROLFIELD_JS)
+ get_controlfield_js_into_input(&pitem);
+
+ if(pitem.kind == MN_TEXTFIELD || pitem.kind == MN_NUMFIELD)
+ {
+ if(active_item == index)
+ context.draw_text(gold_text,
+ pitem.get_input_with_symbol(true),
+ Vector(input_pos, y_pos - int(gold_text->get_height()/2)),
+ LAYER_GUI);
+ else
+ context.draw_text(gold_text,
+ pitem.get_input_with_symbol(false),
+ Vector(input_pos, y_pos - int(gold_text->get_height()/2)),
+ LAYER_GUI);
+ }
+ else
+ context.draw_text(gold_text, pitem.input,
+ Vector(input_pos, y_pos - int(gold_text->get_height()/2)),
+ LAYER_GUI);
+
+ context.draw_text(text_font, pitem.text,
+ Vector(text_pos, y_pos - int(text_font->get_height()/2)),
+ LAYER_GUI);
+ break;
+ }
+ case MN_STRINGSELECT:
+ {
+ int list_pos_2 = list_width + 16;
+ int list_pos = list_width/2;
+ int text_pos = (text_width + 16)/2;
+
+ /* Draw arrows */
+ context.draw_surface(arrow_left,
+ Vector(x_pos - list_pos + text_pos - 17, y_pos - 8),
+ LAYER_GUI);
+ context.draw_surface(arrow_right,
+ Vector(x_pos - list_pos + text_pos - 1 + list_pos_2, y_pos - 8),
+ LAYER_GUI);
+
+ /* Draw input background */
+ context.draw_filled_rect(
+ Vector(x_pos - list_pos + text_pos - 1, y_pos - 10),
+ Vector(list_pos_2 + 2, 20),
+ Color(255,255,255,255), LAYER_GUI - 4);
+ context.draw_filled_rect(
+ Vector(x_pos - list_pos + text_pos, y_pos - 9),
+ Vector(list_pos_2, 18),
+ Color(0,0,0,128), LAYER_GUI - 5);
+
+ context.draw_text_center(text_font, string_list_active(pitem.list),
+ Vector(text_pos, y_pos - int(text_font->get_height()/2)),
+ LAYER_GUI);
+ context.draw_text_center(text_font, pitem.text,
+ Vector(list_pos_2/2, y_pos - int(text_font->get_height()/2)),
+ LAYER_GUI);
+ break;
+ }
+ case MN_BACK:
+ {
+ context.draw_text_center(text_font, pitem.text,
+ Vector(0, y_pos - int(text_font->get_height()/2)),
+ LAYER_GUI);
+ context.draw_surface(back,
+ Vector(x_pos + text_width/2 + 16, y_pos - 8),
+ LAYER_GUI);
+ break;
+ }
+
+ case MN_TOGGLE:
+ {
+ context.draw_text_center(text_font, pitem.text,
+ Vector(0, y_pos - (text_font->get_height()/2)),
+ LAYER_GUI);
+
+ if(pitem.toggled)
+ context.draw_surface(checkbox_checked,
+ Vector(x_pos + (text_width+16)/2, y_pos - 8),
+ LAYER_GUI + 1);
+ else
+ context.draw_surface(checkbox,
+ Vector(x_pos + (text_width+16)/2, y_pos - 8),
+ LAYER_GUI + 1);
+ break;
+ }
+ case MN_ACTION:
+ context.draw_text_center(text_font, pitem.text,
+ Vector(0, y_pos - int(text_font->get_height()/2)),
+ LAYER_GUI);
+ break;
+
+ case MN_GOTO:
+ context.draw_text_center(text_font, pitem.text,
+ Vector(0, y_pos - int(text_font->get_height()/2)),
+ LAYER_GUI);
+ break;
+ }
+}
+
+int Menu::get_width() const
+{
+ /* The width of the menu has to be more than the width of the text
+ with the most characters */
+ int menu_width = 0;
+ for(unsigned int i = 0; i < item.size(); ++i)
+ {
+ int w = strlen(item[i].text) + (item[i].input ? strlen(item[i].input) + 1 : 0) + strlen(string_list_active(item[i].list));
+ if( w > menu_width )
+ {
+ menu_width = w;
+ if( item[i].kind == MN_TOGGLE)
+ menu_width += 2;
+ }
+ }
+
+ return (menu_width * 16 + 24);
+}
+
+int Menu::get_height() const
+{
+ return item.size() * 24;
+}
+
+/* Draw the current menu. */
+void
+Menu::draw(DrawingContext& context)
+{
+ int menu_height = get_height();
+ int menu_width = get_width();
+
+ /* Draw a transparent background */
+ context.draw_filled_rect(
+ Vector(pos_x - menu_width/2, pos_y - 24*item.size()/2 - 10),
+ Vector(menu_width,menu_height + 20),
+ Color(150,180,200,125), LAYER_GUI-10);
+
+ for(unsigned int i = 0; i < item.size(); ++i)
+ {
+ draw_item(context, i, menu_width, menu_height);
+ }
+}
+
+MenuItem&
+Menu::get_item_by_id(int id)
+{
+ for(std::vector<MenuItem>::iterator i = item.begin(); i != item.end(); ++i)
+ {
+ if(i->id == id)
+ return *i;
+ }
+
+ assert(false);
+ static MenuItem dummyitem;
+ return dummyitem;
+}
+
+int Menu::get_active_item_id()
+{
+ return item[active_item].id;
+}
+
+bool
+Menu::isToggled(int id)
+{
+ return get_item_by_id(id).toggled;
+}
+
+/* Check for menu event */
+void
+Menu::event(SDL_Event& event)
+{
+ switch(event.type)
+ {
+ case SDL_KEYDOWN:
+ {
+ SDLKey key = key = event.key.keysym.sym;
+ SDLMod keymod;
+ char ch[2];
+ keymod = SDL_GetModState();
+
+ /* If the current unicode character is an ASCII character,
+ assign it to ch. */
+ if ( (event.key.keysym.unicode & 0xFF80) == 0 )
+ {
+ ch[0] = event.key.keysym.unicode & 0x7F;
+ ch[1] = '\0';
+ }
+ else
+ {
+ /* An International Character. */
+ }
+
+ if(item[active_item].kind == MN_CONTROLFIELD_KB)
+ {
+ if(key == SDLK_ESCAPE)
+ {
+ Menu::pop_current();
+ return;
+ }
+ *item[active_item].int_p = key;
+ menuaction = MENU_ACTION_DOWN;
+ return;
+ }
+
+
+ switch(key)
+ {
+ case SDLK_UP: /* Menu Up */
+ menuaction = MENU_ACTION_UP;
+ break;
+ case SDLK_DOWN: /* Menu Down */
+ menuaction = MENU_ACTION_DOWN;
+ break;
+ case SDLK_LEFT: /* Menu Up */
+ menuaction = MENU_ACTION_LEFT;
+ break;
+ case SDLK_RIGHT: /* Menu Down */
+ menuaction = MENU_ACTION_RIGHT;
+ break;
+ case SDLK_SPACE:
+ if(item[active_item].kind == MN_TEXTFIELD)
+ {
+ menuaction = MENU_ACTION_INPUT;
+ mn_input_char = ' ';
+ break;
+ }
+ case SDLK_RETURN: /* Menu Hit */
+ menuaction = MENU_ACTION_HIT;
+ break;
+ case SDLK_DELETE:
+ case SDLK_BACKSPACE:
+ menuaction = MENU_ACTION_REMOVE;
+ delete_character++;
+ break;
+ case SDLK_ESCAPE:
+ Menu::pop_current();
+ break;
+ default:
+ if( (key >= SDLK_0 && key <= SDLK_9) || (key >= SDLK_a && key <= SDLK_z) || (key >= SDLK_SPACE && key <= SDLK_SLASH))
+ {
+ menuaction = MENU_ACTION_INPUT;
+ mn_input_char = *ch;
+ }
+ else
+ {
+ mn_input_char = '\0';
+ }
+ break;
+ }
+ }
+ break;
+
+ case SDL_JOYAXISMOTION:
+ if(event.jaxis.axis == joystick_keymap.y_axis)
+ {
+ if (event.jaxis.value > joystick_keymap.dead_zone && !joystick_timer.started())
+ {
+ menuaction = MENU_ACTION_DOWN;
+ joystick_timer.start(JOYSTICK_MENU_DELAY);
+ }
+ else if (event.jaxis.value < -joystick_keymap.dead_zone && !joystick_timer.started())
+ {
+ menuaction = MENU_ACTION_UP;
+ joystick_timer.start(JOYSTICK_MENU_DELAY);
+ }
+ else
+ joystick_timer.stop();
+ }
+ break;
+ case SDL_JOYBUTTONDOWN:
+ if (item[active_item].kind == MN_CONTROLFIELD_JS)
+ {
+ // FIXME: This next line does nothing useable, right?
+ // *item[active_item].int_p = key;
+ menuaction = MENU_ACTION_DOWN;
+ }
+ menuaction = MENU_ACTION_HIT;
+ break;
+
+ case SDL_MOUSEBUTTONDOWN:
+ {
+ int x = event.motion.x;
+ int y = event.motion.y;
+
+ if(x > pos_x - get_width()/2 &&
+ x < pos_x + get_width()/2 &&
+ y > pos_y - get_height()/2 &&
+ y < pos_y + get_height()/2)
+ {
+ menuaction = MENU_ACTION_HIT;
+ }
+ }
+ break;
+
+ case SDL_MOUSEMOTION:
+ {
+ int x = event.motion.x;
+ int y = event.motion.y;
+
+ if(x > pos_x - get_width()/2 &&
+ x < pos_x + get_width()/2 &&
+ y > pos_y - get_height()/2 &&
+ y < pos_y + get_height()/2)
+ {
+ active_item = (y - (pos_y - get_height()/2)) / 24;
+ mouse_cursor->set_state(MC_LINK);
+ }
+ else
+ {
+ mouse_cursor->set_state(MC_NORMAL);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+// EOF //
--- /dev/null
+// $Id$
+//
+// SuperTux
+// Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#ifndef SUPERTUX_MENU_H
+#define SUPERTUX_MENU_H
+
+#include <vector>
+
+#include "SDL.h"
+
+#include "video/surface.h"
+#include "special/timer.h"
+#include "special/base.h"
+#include "special/stringlist.h"
+#include "gui/mousecursor.h"
+
+
+/* Joystick menu delay */
+#define JOYSTICK_MENU_DELAY 500
+
+/* IDs for menus */
+
+bool confirm_dialog(Surface* background, std::string text);
+
+/* Kinds of menu items */
+enum MenuItemKind {
+ MN_ACTION,
+ MN_GOTO,
+ MN_TOGGLE,
+ MN_BACK,
+ MN_DEACTIVE,
+ MN_TEXTFIELD,
+ MN_NUMFIELD,
+ MN_CONTROLFIELD_KB,
+ MN_CONTROLFIELD_JS,
+ MN_STRINGSELECT,
+ MN_LABEL,
+ MN_HL, /* horizontal line */
+};
+
+class Menu;
+
+class MenuItem
+{
+public:
+ MenuItemKind kind;
+ int toggled;
+ char *text;
+ char *input;
+ int *int_p; // used for setting keys (can be used for more stuff...)
+ int id; // item id
+ string_list_type* list;
+ Menu* target_menu;
+
+ void change_text (const char *text);
+ void change_input(const char *text);
+
+ static MenuItem* create(MenuItemKind kind, const char *text, int init_toggle, Menu* target_menu, int id, int* int_p);
+
+ std::string get_input_with_symbol(bool active_item); // returns the text with an input symbol
+private:
+ bool input_flickering;
+ Timer input_flickering_timer;
+};
+
+class Menu
+{
+private:
+ static std::vector<Menu*> last_menus;
+ static Menu* current_;
+
+ static void push_current(Menu* pmenu);
+ static void pop_current();
+
+public:
+ /** Set the current menu, if pmenu is NULL, hide the current menu */
+ static void set_current(Menu* pmenu);
+
+ /** Return the current active menu or NULL if none is active */
+ static Menu* current() { return current_; }
+
+private:
+ /* Action done on the menu */
+ enum MenuAction {
+ MENU_ACTION_NONE = -1,
+ MENU_ACTION_UP,
+ MENU_ACTION_DOWN,
+ MENU_ACTION_LEFT,
+ MENU_ACTION_RIGHT,
+ MENU_ACTION_HIT,
+ MENU_ACTION_INPUT,
+ MENU_ACTION_REMOVE
+ };
+
+ /** Number of the item that got 'hit' (ie. pressed) in the last
+ event()/action() call, -1 if none */
+ int hit_item;
+
+ // position of the menu (ie. center of the menu, not top/left)
+ int pos_x;
+ int pos_y;
+
+ /** input event for the menu (up, down, left, right, etc.) */
+ MenuAction menuaction;
+
+ /* input implementation variables */
+ int delete_character;
+ char mn_input_char;
+ Timer joystick_timer;
+
+public:
+ Timer effect;
+ int arrange_left;
+ int active_item;
+
+ std::vector<MenuItem> item;
+
+ Menu();
+ ~Menu();
+
+ void additem(MenuItem* pmenu_item);
+ void additem(MenuItemKind kind, const std::string& text, int init_toggle, Menu* target_menu, int id = -1, int *int_p = NULL);
+
+ void action ();
+
+ /** Remove all entries from the menu */
+ void clear();
+
+ /** Return the index of the menu item that was 'hit' (ie. the user
+ clicked on it) in the last event() call */
+ int check ();
+
+ MenuItem& get_item(int index) { return item[index]; }
+ MenuItem& get_item_by_id(int id);
+
+ int get_active_item_id();
+
+ bool isToggled(int id);
+
+ void Menu::get_controlfield_key_into_input(MenuItem *item);
+ void Menu::get_controlfield_js_into_input(MenuItem *item);
+
+ void draw(DrawingContext& context);
+ void draw_item(DrawingContext& context,
+ int index, int menu_width, int menu_height);
+ void set_pos(int x, int y, float rw = 0, float rh = 0);
+
+ /** translate a SDL_Event into a menu_action */
+ void event(SDL_Event& event);
+
+ int get_width() const;
+ int get_height() const;
+
+ bool is_toggled(int id) const;
+};
+
+extern Surface* checkbox;
+extern Surface* checkbox_checked;
+extern Surface* back;
+extern Surface* arrow_left;
+extern Surface* arrow_right;
+
+extern Menu* contrib_menu;
+extern Menu* contrib_subset_menu;
+extern Menu* main_menu;
+extern Menu* game_menu;
+extern Menu* options_menu;
+extern Menu* options_keys_menu;
+extern Menu* options_joystick_menu;
+extern Menu* highscore_menu;
+extern Menu* load_game_menu;
+extern Menu* save_game_menu;
+
+#endif /*SUPERTUX_MENU_H*/
+
+/* Local Variables: */
+/* mode: c++ */
+/* End: */
--- /dev/null
+// $Id$
+//
+// SuperTux - A Jump'n Run
+// Copyright (C) 2004 Ricardo Cruz <rick2@aeiou.pt>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#include "video/drawing_context.h"
+#include "gui/mousecursor.h"
+
+MouseCursor* MouseCursor::current_ = 0;
+
+MouseCursor::MouseCursor(std::string cursor_file, int frames) : mid_x(0), mid_y(0)
+{
+ cursor = new Surface(cursor_file, true);
+
+ cur_state = MC_NORMAL;
+ cur_frame = 0;
+ tot_frames = frames;
+
+ timer.init(false);
+ timer.start(MC_FRAME_PERIOD);
+
+ SDL_ShowCursor(SDL_DISABLE);
+}
+
+MouseCursor::~MouseCursor()
+{
+ delete cursor;
+
+ SDL_ShowCursor(SDL_ENABLE);
+}
+
+int MouseCursor::state()
+{
+ return cur_state;
+}
+
+void MouseCursor::set_state(int nstate)
+{
+ cur_state = nstate;
+}
+
+void MouseCursor::set_mid(int x, int y)
+{
+ mid_x = x;
+ mid_y = y;
+}
+
+void MouseCursor::draw(DrawingContext& context)
+{
+ if(cur_state == MC_HIDE)
+ return;
+
+ int x,y,w,h;
+ Uint8 ispressed = SDL_GetMouseState(&x,&y);
+ w = cursor->w / tot_frames;
+ h = cursor->h / MC_STATES_NB;
+ if(ispressed &SDL_BUTTON(1) || ispressed &SDL_BUTTON(2))
+ {
+ if(cur_state != MC_CLICK)
+ {
+ state_before_click = cur_state;
+ cur_state = MC_CLICK;
+ }
+ }
+ else
+ {
+ if(cur_state == MC_CLICK)
+ cur_state = state_before_click;
+ }
+
+ if(timer.get_left() < 0 && tot_frames > 1)
+ {
+ cur_frame++;
+ if(cur_frame++ >= tot_frames)
+ cur_frame = 0;
+
+ timer.start(MC_FRAME_PERIOD);
+ }
+
+ context.draw_surface_part(cursor, Vector(w*cur_frame, h*cur_state), Vector(w,
+ h), Vector(x-mid_x, y-mid_y), LAYER_GUI+100);
+}
--- /dev/null
+// $Id$
+//
+// SuperTux - A Jump'n Run
+// Copyright (C) 2004 Ricardo Cruz <rick2@aeiou.pt>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#ifndef SUPERTUX_MOUSECURSOR_H
+#define SUPERTUX_MOUSECURSOR_H
+
+#include <string>
+
+#include "special/timer.h"
+#include "video/surface.h"
+
+#define MC_FRAME_PERIOD 800 // in ms
+
+#define MC_STATES_NB 3
+enum {
+ MC_NORMAL,
+ MC_CLICK,
+ MC_LINK,
+ MC_HIDE
+};
+
+class MouseCursor
+{
+public:
+ MouseCursor(std::string cursor_file, int frames);
+ ~MouseCursor();
+ int state();
+ void set_state(int nstate);
+ void set_mid(int x, int y);
+ void draw(DrawingContext& context);
+
+ static MouseCursor* current() { return current_; };
+ static void set_current(MouseCursor* pcursor) { current_ = pcursor; };
+
+private:
+ int mid_x, mid_y;
+ static MouseCursor* current_;
+ int state_before_click;
+ int cur_state;
+ int cur_frame, tot_frames;
+ Surface* cursor;
+ Timer timer;
+};
+
+#endif /*SUPERTUX_MOUSECURSOR_H*/
--- /dev/null
+// $Id$
+//
+// SuperTux
+// Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#include <cstdio>
+
+#include "math/physic.h"
+#include "special/timer.h"
+
+Physic::Physic()
+ : ax(0), ay(0), vx(0), vy(0), gravity_enabled(true)
+{
+}
+
+Physic::~Physic()
+{
+}
+
+void
+Physic::reset()
+{
+ ax = ay = vx = vy = 0;
+ gravity_enabled = true;
+}
+
+void
+Physic::set_velocity_x(float nvx)
+{
+ vx = nvx;
+}
+
+void
+Physic::set_velocity_y(float nvy)
+{
+ vy = -nvy;
+}
+
+void
+Physic::set_velocity(float nvx, float nvy)
+{
+ vx = nvx;
+ vy = -nvy;
+}
+
+void Physic::inverse_velocity_x()
+{
+vx = -vx;
+}
+
+void Physic::inverse_velocity_y()
+{
+vy = -vy;
+}
+
+float
+Physic::get_velocity_x()
+{
+ return vx;
+}
+
+float
+Physic::get_velocity_y()
+{
+ return -vy;
+}
+
+void
+Physic::set_acceleration_x(float nax)
+{
+ ax = nax;
+}
+
+void
+Physic::set_acceleration_y(float nay)
+{
+ ay = -nay;
+}
+
+void
+Physic::set_acceleration(float nax, float nay)
+{
+ ax = nax;
+ ay = -nay;
+}
+
+float
+Physic::get_acceleration_x()
+{
+ return ax;
+}
+
+float
+Physic::get_acceleration_y()
+{
+ return -ay;
+}
+
+void
+Physic::enable_gravity(bool enable_gravity)
+{
+ gravity_enabled = enable_gravity;
+}
+
+void
+Physic::apply(float elapsed_time, float &x, float &y, float& gravity)
+{
+ float grav;
+ if(gravity_enabled)
+ grav = gravity / 100.0;
+ else
+ grav = 0;
+
+ x += vx * elapsed_time + ax * elapsed_time * elapsed_time;
+ y += vy * elapsed_time + (ay + grav) * elapsed_time * elapsed_time;
+ vx += ax * elapsed_time;
+ vy += (ay + grav) * elapsed_time;
+}
+
+void
+Physic::apply(Vector& vector, float elapsed_time, float& gravity)
+{
+ apply(elapsed_time, vector.x, vector.y, gravity);
+}
+
--- /dev/null
+// $Id$
+//
+// SuperTux
+// Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#ifndef SUPERTUX_PHYSIC_H
+#define SUPERTUX_PHYSIC_H
+
+#include "math/vector.h"
+
+/** This is a very simplistic physics engine handling accelerated and constant
+ * movement along with gravity.
+ */
+class Physic
+{
+public:
+ Physic();
+ ~Physic();
+
+ /** resets all velocities and accelerations to 0 */
+ void reset();
+
+ /** sets velocity to a fixed value */
+ void set_velocity(float vx, float vy);
+
+ void set_velocity_x(float vx);
+ void set_velocity_y(float vy);
+
+ /** velocities invertion */
+ void inverse_velocity_x();
+ void inverse_velocity_y();
+
+ float get_velocity_x();
+ float get_velocity_y();
+
+ /** sets acceleration applied to the object. (Note that gravity is
+ * eventually added to the vertical acceleration)
+ */
+ void set_acceleration(float ax, float ay);
+
+ void set_acceleration_x(float ax);
+ void set_acceleration_y(float ay);
+
+ float get_acceleration_x();
+ float get_acceleration_y();
+
+ /** enables or disables handling of gravity */
+ void enable_gravity(bool gravity_enabled);
+
+ /** applies the physical simulation to given x and y coordinates */
+ void apply(float frame_ratio, float &x, float &y, float& gravity = 10);
+
+ /** applies the physical simulation to given x and y coordinates */
+ void apply(Vector& vector, float frame_ratio, float& gravity = 10);
+
+private:
+ /// horizontal and vertical acceleration
+ float ax, ay;
+ /// horizontal and vertical velocity
+ float vx, vy;
+ /// should we respect gravity in out calculations?
+ bool gravity_enabled;
+};
+
+#endif /*SUPERTUX_PHYSIC_H*/
--- /dev/null
+// $Id$
+//
+// SuperTux - A Jump'n Run
+// Copyright (C) 2004 Matthias Braun <matze@braunis.de
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#include <cmath>
+
+#include "math/vector.h"
+
+Vector Vector::unit() const
+{
+ return *this / norm();
+}
+
+float Vector::norm() const
+{
+ return sqrt(x*x + y*y);
+}
--- /dev/null
+// $Id$
+//
+// SuperTux - A Jump'n Run
+// Copyright (C) 2004 Matthias Braun <matze@braunis.de
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#ifndef SUPERTUX_VECTOR_H
+#define SUPERTUX_VECTOR_H
+
+class Vector
+{
+public:
+ Vector(float nx, float ny)
+ : x(nx), y(ny)
+ { }
+ Vector(const Vector& other)
+ : x(other.x), y(other.y)
+ { }
+ Vector()
+ : x(0), y(0)
+ { }
+
+ bool operator ==(const Vector& other) const
+ {
+ return x == other.x && y == other.y;
+ }
+
+ const Vector& operator=(const Vector& other)
+ {
+ x = other.x;
+ y = other.y;
+ return *this;
+ }
+
+ Vector operator+(const Vector& other) const
+ {
+ return Vector(x + other.x, y + other.y);
+ }
+
+ Vector operator-(const Vector& other) const
+ {
+ return Vector(x - other.x, y - other.y);
+ }
+
+ Vector operator*(float s) const
+ {
+ return Vector(x * s, y * s);
+ }
+
+ Vector operator/(float s) const
+ {
+ return Vector(x / s, y / s);
+ }
+
+ Vector operator-() const
+ {
+ return Vector(-x, -y);
+ }
+
+ const Vector& operator +=(const Vector& other)
+ {
+ x += other.x;
+ y += other.y;
+ return *this;
+ }
+
+ // scalar product of 2 vectors
+ float operator*(const Vector& other) const
+ {
+ return x*other.x + y*other.y;
+ }
+
+ float norm() const;
+ Vector unit() const;
+
+ // ... add the other operators as needed, I'm too lazy now ...
+
+ float x, y; // leave this public, get/set methods just give me headaches
+ // for such simple stuff :)
+};
+
+#endif /*SUPERTUX_VECTOR_H*/
+
--- /dev/null
+// $Id$
+//
+// SuperTux
+// Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#ifndef SUPERTUX_TYPE_H
+#define SUPERTUX_TYPE_H
+
+#include <string>
+
+#include "SDL.h"
+
+/* 'Base' type for game objects */
+
+struct base_type
+{
+ float x;
+ float y;
+ float width;
+ float height;
+};
+
+
+#endif /*SUPERTUX_TYPE_H*/
+
--- /dev/null
+// $Id$
+//
+// SuperTux - A Jump'n Run
+// Copyright (C) 2004 Matthias Braun <matze@braunis.de
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#include "special/game_object.h"
+
+GameObject::GameObject()
+ : wants_to_die(false)
+{
+}
+
+GameObject::~GameObject()
+{
+}
+
--- /dev/null
+// $Id$
+//
+// SuperTux - A Jump'n Run
+// Copyright (C) 2004 Matthias Braun <matze@braunis.de
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#ifndef SUPERTUX_GAMEOBJECT_H
+#define SUPERTUX_GAMEOBJECT_H
+
+#include <string>
+
+class DrawingContext;
+
+/**
+ * Base class for all game objects. This contains functions for:
+ * -querying the actual type of the object
+ * -a flag that indicates if the object wants to be removed. Objects with this
+ * flag will be removed at the end of each frame. This is alot safer than
+ * having some uncontrollable "delete this" in the code.
+ * -an action function that is called once per frame and allows the object to
+ * update it's state.
+ *
+ * Most GameObjects will also implement the DrawableObject interface so that
+ * they can actually be drawn on screen.
+ */
+class GameObject // TODO rename this once the game has been converted
+{
+public:
+ GameObject();
+ virtual ~GameObject();
+
+ /** This function is called once per frame and allows the object to update
+ * it's state. The elapsed_time is the time since the last frame and should be
+ * the base for all timed things.
+ */
+ virtual void action(float elapsed_time) = 0;
+
+ /** The GameObject should draw itself onto the provided DrawingContext if this
+ * function is called.
+ */
+ virtual void draw(DrawingContext& context) = 0;
+
+ /** returns true if the object is not scheduled to be removed yet */
+ bool is_valid() const
+ { return !wants_to_die; }
+ /** schedules this object to be removed at the end of the frame */
+ void remove_me()
+ { wants_to_die = true; }
+
+private:
+ /** this flag indicates if the object should be removed at the end of the
+ * frame
+ */
+ bool wants_to_die;
+};
+
+#endif /*SUPERTUX_GAMEOBJECT_H*/
+
--- /dev/null
+// $Id$
+//
+// SuperTux - A Jump'n Run
+// Copyright (C) 2004 Matthias Braun <matze@braunis.de
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#include "special/moving_object.h"
+
+MovingObject::MovingObject()
+{
+ base.x = base.y = base.width = base.height = 0;
+ old_base = base;
+}
+
+MovingObject::~MovingObject()
+{
+}
+
--- /dev/null
+// $Id$
+//
+// SuperTux - A Jump'n Run
+// Copyright (C) 2004 Matthias Braun <matze@braunis.de
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#ifndef SUPERTUX_MOVING_OBJECT_H
+#define SUPERTUX_MOVING_OBJECT_H
+
+#include "special/base.h"
+#include "special/game_object.h"
+#include "math/vector.h"
+//#include "rectangle.h"
+
+/**
+ * Base class for all dynamic/moving game objects. This class contains things
+ * for handling the bounding boxes and collision feedback.
+ */
+class MovingObject : public GameObject
+{
+public:
+ MovingObject();
+ virtual ~MovingObject();
+
+ /** this function is called when the object collided with any other object
+ */
+ virtual void collision(const MovingObject& other_object,
+ int collision_type) = 0;
+
+ Vector get_pos() const
+ { return Vector(base.x, base.y); }
+
+ base_type base;
+ base_type old_base;
+
+protected:
+#if 0 // this will be used in my collision detection rewrite later
+ /// the current position of the object
+ Vector pos;
+ /// the position we want to move until next frame
+ Vector new_pos;
+ /// the bounding box relative to the current position
+ Rectangle bounding_box;
+#endif
+};
+
+#endif /*SUPERTUX_MOVING_OBJECT_H*/
+
--- /dev/null
+// $Id$
+//
+// SuperTux
+// Copyright (C) 2004 Ingo Ruhnke <grumbel@gmx.de>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#include <iostream>
+#include <cmath>
+
+#include "app/globals.h"
+#include "app/setup.h"
+#include "special/sprite.h"
+#include "video/drawing_context.h"
+
+Sprite::Sprite(lisp_object_t* cur)
+{
+ init_defaults();
+
+ LispReader reader(cur);
+
+ if(!reader.read_string("name", name))
+ st_abort("Sprite wihtout name", "");
+ reader.read_int("x-hotspot", x_hotspot);
+ reader.read_int("y-hotspot", y_hotspot);
+ reader.read_float("fps", fps);
+
+ std::vector<std::string> images;
+ if(!reader.read_string_vector("images", images))
+ st_abort("Sprite contains no images: ", name.c_str());
+
+ for(std::vector<std::string>::size_type i = 0; i < images.size(); ++i)
+ {
+ surfaces.push_back(
+ new Surface(datadir + "/images/" + images[i], true));
+ }
+
+ frame_delay = 1000.0f/fps;
+}
+
+Sprite::~Sprite()
+{
+ for(std::vector<Surface*>::iterator i = surfaces.begin(); i != surfaces.end();
+ ++i)
+ delete *i;
+}
+
+void
+Sprite::init_defaults()
+{
+ x_hotspot = 0;
+ y_hotspot = 0;
+ fps = 10;
+ time = 0;
+ frame_delay = 1000.0f/fps;
+}
+
+void
+Sprite::update(float /*delta*/)
+{
+ //time += 10*delta;
+ //std::cout << "Delta: " << delta << std::endl;
+}
+
+void
+Sprite::draw(DrawingContext& context, const Vector& pos, int layer,
+ Uint32 drawing_effect)
+{
+ time = SDL_GetTicks();
+ unsigned int frame = get_current_frame();
+
+ if (frame < surfaces.size())
+ {
+ Surface* surface = surfaces[frame];
+
+ context.draw_surface(surface, pos - Vector(x_hotspot, y_hotspot), layer, drawing_effect);
+ }
+}
+
+#if 0
+void
+Sprite::draw_part(float sx, float sy, float x, float y, float w, float h)
+{
+ time = SDL_GetTicks();
+ unsigned int frame = get_current_frame();
+
+ if (frame < surfaces.size())
+ surfaces[frame]->draw_part(sx, sy, x - x_hotspot, y - y_hotspot, w, h);
+}
+#endif
+
+void
+Sprite::reset()
+{
+ time = 0;
+}
+
+int
+Sprite::get_current_frame() const
+{
+ unsigned int frame = static_cast<int>(fmodf(time, surfaces.size()*frame_delay)/frame_delay);
+ return frame % surfaces.size();
+}
+
+int
+Sprite::get_width() const
+{
+ return surfaces[get_current_frame()]->w;
+}
+
+int
+Sprite::get_height() const
+{
+ return surfaces[get_current_frame()]->h;
+}
+
+/* EOF */
--- /dev/null
+// $Id$
+//
+// SuperTux
+// Copyright (C) 2004 Ingo Ruhnke <grumbel@gmx.de>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#ifndef SUPERTUX_SPRITE_H
+#define SUPERTUX_SPRITE_H
+
+#include <string>
+#include <vector>
+
+#include "utils/lispreader.h"
+#include "video/surface.h"
+#include "math/vector.h"
+
+class Sprite
+{
+ private:
+ std::string name;
+
+ int x_hotspot;
+ int y_hotspot;
+
+ /** Frames per second */
+ float fps;
+
+ /** Number of seconds that a frame is displayed until it is switched
+ to the next frame */
+ float frame_delay;
+
+ float time;
+
+ std::vector<Surface*> surfaces;
+
+ void init_defaults();
+ public:
+ /** cur has to be a pointer to data in the form of ((x-hotspot 5)
+ (y-hotspot 10) ...) */
+ Sprite(lisp_object_t* cur);
+ ~Sprite();
+
+ void reset();
+
+ /** Update the sprite and process to the next frame */
+ void update(float delta);
+ void draw(DrawingContext& context, const Vector& pos, int layer,
+ Uint32 drawing_effect = NONE_EFFECT);
+ int get_current_frame() const;
+
+ float get_fps() { return fps; } ;
+ int get_frames() { return surfaces.size(); } ;
+
+ std::string get_name() const { return name; }
+ int get_width() const;
+ int get_height() const;
+
+ Surface* get_frame(unsigned int frame)
+ { if(frame < surfaces.size()) return surfaces[frame];
+ else return surfaces[0]; }
+};
+
+#endif /*SUPERTUX_SPRITE_H*/
+
+/* Local Variables: */
+/* mode:c++ */
+/* End: */
--- /dev/null
+// $Id$
+//
+// SuperTux
+// Copyright (C) 2004 Ingo Ruhnke <grumbel@gmx.de>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#include <iostream>
+
+#include "utils/lispreader.h"
+#include "special/sprite_manager.h"
+
+SpriteManager::SpriteManager(const std::string& filename)
+{
+ load_resfile(filename);
+}
+
+SpriteManager::~SpriteManager()
+{
+ for(std::map<std::string, Sprite*>::iterator i = sprites.begin();
+ i != sprites.end(); ++i) {
+ delete i->second;
+ }
+}
+
+void
+SpriteManager::load_resfile(const std::string& filename)
+{
+ lisp_object_t* root_obj = lisp_read_from_file(filename);
+ if (!root_obj)
+ {
+ std::cout << "SpriteManager: Couldn't load: " << filename << std::endl;
+ return;
+ }
+
+ lisp_object_t* cur = root_obj;
+
+ if (strcmp(lisp_symbol(lisp_car(cur)), "supertux-resources") != 0)
+ return;
+ cur = lisp_cdr(cur);
+
+ while(cur)
+ {
+ lisp_object_t* el = lisp_car(cur);
+
+ if (strcmp(lisp_symbol(lisp_car(el)), "sprite") == 0)
+ {
+ Sprite* sprite = new Sprite(lisp_cdr(el));
+
+ Sprites::iterator i = sprites.find(sprite->get_name());
+ if (i == sprites.end())
+ {
+ sprites[sprite->get_name()] = sprite;
+ }
+ else
+ {
+ delete i->second;
+ i->second = sprite;
+ std::cout << "Warning: dulpicate entry: '" << sprite->get_name() << "'" << std::endl;
+ }
+ }
+ else
+ {
+ std::cout << "SpriteManager: Unknown tag" << std::endl;
+ }
+
+ cur = lisp_cdr(cur);
+ }
+
+ lisp_free(root_obj);
+}
+
+Sprite*
+SpriteManager::load(const std::string& name)
+{
+ Sprites::iterator i = sprites.find(name);
+ if (i != sprites.end())
+ {
+ return i->second;
+ }
+ else
+ {
+ std::cout << "SpriteManager: Sprite '" << name << "' not found" << std::endl;
+ return 0;
+ }
+}
+
+/* EOF */
--- /dev/null
+// $Id$
+//
+// SuperTux
+// Copyright (C) 2004 Ingo Ruhnke <grumbel@gmx.de>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#ifndef SUPERTUX_SPRITE_MANAGER_H
+#define SUPERTUX_SPRITE_MANAGER_H
+
+#include <map>
+
+#include "special/sprite.h"
+
+class SpriteManager
+{
+ private:
+ typedef std::map<std::string, Sprite*> Sprites;
+ Sprites sprites;
+ public:
+ SpriteManager(const std::string& filename);
+ ~SpriteManager();
+
+ void load_resfile(const std::string& filename);
+ /** loads a sprite.
+ * WARNING: You must not delete the returned object.
+ */
+ Sprite* load(const std::string& name);
+};
+
+#endif /*SUPERTUX_SPRITE_MANAGER_H*/
+
+/* Local Variables: */
+/* mode:c++ */
+/* End: */
--- /dev/null
+// $Id$
+//
+// SuperTux
+// Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#include "string.h"
+#include "stdlib.h"
+#include "special/stringlist.h"
+
+void string_list_init(string_list_type* pstring_list)
+{
+ pstring_list->num_items = 0;
+ pstring_list->active_item = -1;
+ pstring_list->item = NULL;
+}
+
+char* string_list_active(string_list_type* pstring_list)
+{
+ if(pstring_list == NULL)
+ return "";
+
+ if(pstring_list->active_item != -1)
+ return pstring_list->item[pstring_list->active_item];
+ else
+ return "";
+}
+
+void string_list_add_item(string_list_type* pstring_list,const char* str)
+{
+ char *pnew_string;
+ pnew_string = (char*) malloc(sizeof(char)*(strlen(str)+1));
+ strcpy(pnew_string,str);
+ ++pstring_list->num_items;
+ pstring_list->item = (char**) realloc(pstring_list->item,sizeof(char**)*pstring_list->num_items);
+ pstring_list->item[pstring_list->num_items-1] = pnew_string;
+ if(pstring_list->active_item == -1)
+ pstring_list->active_item = 0;
+}
+
+void string_list_copy(string_list_type* pstring_list, string_list_type pstring_list_orig)
+{
+ int i;
+ string_list_free(pstring_list);
+ for(i = 0; i < pstring_list_orig.num_items; ++i)
+ string_list_add_item(pstring_list,pstring_list_orig.item[i]);
+}
+
+int string_list_find(string_list_type* pstring_list,const char* str)
+{
+ int i;
+ for(i = 0; i < pstring_list->num_items; ++i)
+ {
+ if(strcmp(pstring_list->item[i],str) == 0)
+ {
+ return i;
+ }
+ }
+ return -1;
+}
+
+void string_list_sort(string_list_type* pstring_list)
+{
+ int i,j,y;
+
+ for(j = 0; j < pstring_list->num_items; ++j)
+ for(i = 0; i < pstring_list->num_items-1; ++i)
+ {
+
+ y = strcmp(pstring_list->item[i],pstring_list->item[i+1]);
+ if(y == 0)
+ {
+ continue;
+ }
+ else if(y < 0)
+ {
+ continue;
+ }
+ else if(y > 0)
+ {
+ char* char_pointer;
+ char_pointer = pstring_list->item[i];
+ pstring_list->item[i] = pstring_list->item[i+1];
+ pstring_list->item[i+1] = char_pointer;
+ continue;
+ }
+
+ }
+
+}
+
+void string_list_free(string_list_type* pstring_list)
+{
+ if(pstring_list != NULL)
+ {
+ int i;
+ for(i=0; i < pstring_list->num_items; ++i)
+ free(pstring_list->item[i]);
+ free(pstring_list->item);
+ pstring_list->item = NULL;
+ pstring_list->num_items = 0;
+ pstring_list->active_item = -1;
+ }
+}
+
--- /dev/null
+// $Id$
+//
+// SuperTux
+// Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#ifndef SUPERTUX_STRINGLIST_H
+#define SUPERTUX_STRINGLIST_H
+
+struct string_list_type
+{
+ int num_items;
+ int active_item;
+ char **item;
+};
+
+void string_list_init(string_list_type* pstring_list);
+char* string_list_active(string_list_type* pstring_list);
+void string_list_copy(string_list_type* pstring_list, string_list_type pstring_list_orig);
+int string_list_find(string_list_type* pstring_list, const char* str);
+void string_list_sort(string_list_type* pstring_list);
+void string_list_add_item(string_list_type* pstring_list, const char* str);
+void string_list_free(string_list_type* pstring_list);
+
+
+
+#endif /*SUPERTUX_STRINGLIST_H*/
+
--- /dev/null
+// $Id$
+//
+// SuperTux
+// Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#include "SDL.h"
+#include "special/timer.h"
+
+unsigned int st_pause_ticks, st_pause_count;
+
+unsigned int st_get_ticks(void)
+{
+ if(st_pause_count != 0)
+ return /*SDL_GetTicks()*/ - st_pause_ticks /*- SDL_GetTicks()*/ + st_pause_count;
+ else
+ return SDL_GetTicks() - st_pause_ticks;
+}
+
+void st_pause_ticks_init(void)
+{
+ st_pause_ticks = 0;
+ st_pause_count = 0;
+}
+
+void st_pause_ticks_start(void)
+{
+ if(st_pause_count == 0)
+ st_pause_count = SDL_GetTicks();
+}
+
+void st_pause_ticks_stop(void)
+{
+if(st_pause_count == 0)
+return;
+
+ st_pause_ticks += SDL_GetTicks() - st_pause_count;
+ st_pause_count = 0;
+}
+
+bool st_pause_ticks_started(void)
+{
+if(st_pause_count == 0)
+return false;
+else
+return true;
+}
+
+Timer::Timer()
+{
+ init(true);
+}
+
+void
+Timer::init(bool st_ticks)
+{
+ period = 0;
+ time = 0;
+ get_ticks = st_ticks ? st_get_ticks : SDL_GetTicks;
+}
+
+void
+Timer::start(unsigned int period_)
+{
+ time = get_ticks();
+ period = period_;
+}
+
+void
+Timer::stop()
+{
+ if(get_ticks == st_get_ticks)
+ init(true);
+ else
+ init(false);
+}
+
+int
+Timer::check()
+{
+ if((time != 0) && (time + period > get_ticks()))
+ return true;
+ else
+ {
+ time = 0;
+ return false;
+ }
+}
+
+int
+Timer::started()
+{
+ if(time != 0)
+ return true;
+ else
+ return false;
+}
+
+int
+Timer::get_left()
+{
+ return (period - (get_ticks() - time));
+}
+
+int
+Timer::get_gone()
+{
+ return (get_ticks() - time);
+}
+
+void
+Timer::fwrite(FILE* fi)
+{
+ unsigned int diff_ticks;
+ int tick_mode;
+ if(time != 0)
+ diff_ticks = get_ticks() - time;
+ else
+ diff_ticks = 0;
+
+ ::fwrite(&period,sizeof(unsigned int),1,fi);
+ ::fwrite(&diff_ticks,sizeof(unsigned int),1,fi);
+ if(get_ticks == st_get_ticks)
+ tick_mode = true;
+ else
+ tick_mode = false;
+ ::fwrite(&tick_mode,sizeof(unsigned int),1,fi);
+}
+
+void
+Timer::fread(FILE* fi)
+{
+ unsigned int diff_ticks;
+ int tick_mode;
+
+ ::fread(&period,sizeof(unsigned int),1,fi);
+ ::fread(&diff_ticks,sizeof(unsigned int),1,fi);
+ ::fread(&tick_mode,sizeof(unsigned int),1,fi);
+
+ if (tick_mode)
+ get_ticks = st_get_ticks;
+ else
+ get_ticks = SDL_GetTicks;
+
+ if (diff_ticks != 0)
+ time = get_ticks() - diff_ticks;
+ else
+ time = 0;
+
+}
+
+/* EOF */
--- /dev/null
+// $Id$
+//
+// SuperTux
+// Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#ifndef SUPERTUX_TIMER_H
+#define SUPERTUX_TIMER_H
+
+extern unsigned int st_pause_ticks, st_pause_count;
+
+unsigned int st_get_ticks(void);
+void st_pause_ticks_init(void);
+void st_pause_ticks_start(void);
+void st_pause_ticks_stop(void);
+bool st_pause_ticks_started(void);
+
+class Timer
+{
+ public:
+ unsigned int period;
+ unsigned int time;
+ unsigned int (*get_ticks) (void);
+
+ public:
+ Timer();
+
+ void init(bool st_ticks);
+ void start(unsigned int period);
+ void stop();
+
+ /*======================================================================
+ return: NO = the timer is not started
+ or it is over
+ YES = otherwise
+ ======================================================================*/
+ int check();
+ int started();
+
+ /*======================================================================
+ return: the time left (in millisecond)
+ note : the returned value can be negative
+ ======================================================================*/
+ int get_left();
+
+ int get_gone();
+ void fwrite(FILE* fi);
+ void fread(FILE* fi);
+};
+
+#endif /*SUPERTUX_TIMER_H*/
+
+/* Local Variables: */
+/* mode:c++ */
+/* End: */
--- /dev/null
+// $Id$
+//
+// SuperTux - A Jump'n Run
+// Copyright (C) 2004 Michael George <mike@georgetech.com>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#include <cstdlib>
+#include <string>
+
+#include "utils/configfile.h"
+#include "app/setup.h"
+#include "app/globals.h"
+
+#ifdef WIN32
+const char * config_filename = "/st_config.dat";
+#else
+const char * config_filename = "/config";
+#endif
+
+Config* config = 0;
+
+static void defaults ()
+{
+ /* Set defaults: */
+ debug_mode = false;
+ audio_device = true;
+
+ use_fullscreen = false;
+ show_fps = false;
+ use_gl = false;
+
+ use_sound = true;
+ use_music = true;
+}
+
+void Config::load()
+{
+ FILE * file = NULL;
+
+ defaults();
+
+ /* override defaults from config file */
+
+ file = opendata(config_filename, "r");
+
+ if (file == NULL)
+ return;
+
+ /* read config file */
+
+ lisp_stream_t stream;
+ lisp_object_t * root_obj = NULL;
+
+ lisp_stream_init_file (&stream, file);
+ root_obj = lisp_read (&stream);
+
+ if (root_obj->type == LISP_TYPE_EOF || root_obj->type == LISP_TYPE_PARSE_ERROR)
+ return;
+
+ if (strcmp(lisp_symbol(lisp_car(root_obj)), "supertux-config") != 0)
+ return;
+
+ LispReader reader(lisp_cdr(root_obj));
+
+ reader.read_bool("fullscreen", use_fullscreen);
+ reader.read_bool("sound", use_sound);
+ reader.read_bool("music", use_music);
+ reader.read_bool("show_fps", show_fps);
+
+ std::string video;
+ reader.read_string ("video", video);
+ if (video == "opengl")
+ use_gl = true;
+ else
+ use_gl = false;
+
+ reader.read_int ("joystick", joystick_num);
+
+ if (joystick_num >= 0)
+ {
+ reader.read_int ("joystick-x", joystick_keymap.x_axis);
+ reader.read_int ("joystick-y", joystick_keymap.y_axis);
+ reader.read_int ("joystick-a", joystick_keymap.a_button);
+ reader.read_int ("joystick-b", joystick_keymap.b_button);
+ reader.read_int ("joystick-start", joystick_keymap.start_button);
+ reader.read_int ("joystick-deadzone", joystick_keymap.dead_zone);
+ }
+
+ customload(reader);
+
+ lisp_free(root_obj);
+}
+
+void Config::save ()
+{
+ /* write settings to config file */
+ FILE * config = opendata(config_filename, "w");
+
+ if(config)
+ {
+ fprintf(config, "(supertux-config\n");
+ fprintf(config, "\t;; the following options can be set to #t or #f:\n");
+ fprintf(config, "\t(fullscreen %s)\n", use_fullscreen ? "#t" : "#f");
+ fprintf(config, "\t(sound %s)\n", use_sound ? "#t" : "#f");
+ fprintf(config, "\t(music %s)\n", use_music ? "#t" : "#f");
+ fprintf(config, "\t(show_fps %s)\n", show_fps ? "#t" : "#f");
+
+ fprintf(config, "\n\t;; either \"opengl\" or \"sdl\"\n");
+ fprintf(config, "\t(video \"%s\")\n", use_gl ? "opengl" : "sdl");
+
+ if(use_joystick)
+ {
+ fprintf(config, "\n\t;; joystick number:\n");
+ fprintf(config, "\t(joystick %d)\n", joystick_num);
+
+ fprintf(config, "\t(joystick-x %d)\n", joystick_keymap.x_axis);
+ fprintf(config, "\t(joystick-y %d)\n", joystick_keymap.y_axis);
+ fprintf(config, "\t(joystick-a %d)\n", joystick_keymap.a_button);
+ fprintf(config, "\t(joystick-b %d)\n", joystick_keymap.b_button);
+ fprintf(config, "\t(joystick-start %d)\n", joystick_keymap.start_button);
+ fprintf(config, "\t(joystick-deadzone %d)\n", joystick_keymap.dead_zone);
+ }
+
+ customsave(config);
+
+ fprintf(config, ")\n");
+ }
+}
+
+/* EOF */
--- /dev/null
+// $Id$
+//
+// SuperTux - A Jump'n Run
+// Copyright (C) 2004 Michael George <mike@georgetech.com>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#ifndef SUPERTUX_CONFIGFILE_H
+#define SUPERTUX_CONFIGFILE_H
+
+#include "utils/lispreader.h"
+
+class Config {
+ public:
+ void load ();
+ void save ();
+ virtual void customload(LispReader& reader) {};
+ virtual void customsave(FILE * config) {};
+};
+
+extern Config* config;
+
+
+#endif
+
+/* Local Variables: */
+/* mode:c++ */
+/* End: */
--- /dev/null
+// $Id$
+//
+// SuperTux - A Jump'n Run
+// Copyright (C) 2003 Tobias Glaesser <tobi.web@gmx.de>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#ifndef SUPERTUX_EXCEPTIONS_H
+#define SUPERTUX_EXCEPTIONS_H
+
+// Exceptions
+#include <exception>
+#include <string>
+
+class SuperTuxException : public std::exception
+{
+ public:
+ SuperTuxException(const char* _message, const char* _file = "", const unsigned int _line = 0)
+ : message(_message), file(_file), line(_line) { };
+ virtual ~SuperTuxException() throw() { };
+
+ const char* what() const throw() { return message; };
+ const char* what_file() const throw() { return file; };
+ const unsigned int what_line() const throw() { return line; };
+
+ private:
+ const char* message;
+ const char* file;
+ const unsigned int line;
+};
+
+#endif /*SUPERTUX_EXCEPTIONS_H*/
--- /dev/null
+/* $Id$ */
+/*
+ * lispreader.c
+ *
+ * Copyright (C) 1998-2000 Mark Probst
+ * Copyright (C) 2002 Ingo Ruhnke <grumbel@gmx.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#include <iostream>
+#include <vector>
+#include <string>
+#include <cctype>
+#include <cstdlib>
+#include <cstring>
+
+#include "app/globals.h"
+#include "app/setup.h"
+#include "utils/lispreader.h"
+
+#define TOKEN_ERROR -1
+#define TOKEN_EOF 0
+#define TOKEN_OPEN_PAREN 1
+#define TOKEN_CLOSE_PAREN 2
+#define TOKEN_SYMBOL 3
+#define TOKEN_STRING 4
+#define TOKEN_INTEGER 5
+#define TOKEN_REAL 6
+#define TOKEN_PATTERN_OPEN_PAREN 7
+#define TOKEN_DOT 8
+#define TOKEN_TRUE 9
+#define TOKEN_FALSE 10
+
+
+#define MAX_TOKEN_LENGTH 4096
+
+static char token_string[MAX_TOKEN_LENGTH + 1] = "";
+static int token_length = 0;
+
+static lisp_object_t end_marker = { LISP_TYPE_EOF, {{0, 0}} };
+static lisp_object_t error_object = { LISP_TYPE_PARSE_ERROR , {{0,0}} };
+static lisp_object_t close_paren_marker = { LISP_TYPE_PARSE_ERROR , {{0,0}} };
+static lisp_object_t dot_marker = { LISP_TYPE_PARSE_ERROR , {{0,0}} };
+
+static void
+_token_clear (void)
+{
+ token_string[0] = '\0';
+ token_length = 0;
+}
+
+static void
+_token_append (char c)
+{
+ if (token_length >= MAX_TOKEN_LENGTH)
+ throw LispReaderException("_token_append()", __FILE__, __LINE__);
+
+ token_string[token_length++] = c;
+ token_string[token_length] = '\0';
+}
+
+static int
+_next_char (lisp_stream_t *stream)
+{
+ switch (stream->type)
+ {
+ case LISP_STREAM_FILE :
+ return getc(stream->v.file);
+
+ case LISP_STREAM_STRING :
+ {
+ char c = stream->v.string.buf[stream->v.string.pos];
+
+ if (c == 0)
+ return EOF;
+
+ ++stream->v.string.pos;
+
+ return c;
+ }
+
+ case LISP_STREAM_ANY:
+ return stream->v.any.next_char(stream->v.any.data);
+ }
+
+ throw LispReaderException("_next_char()", __FILE__, __LINE__);
+ return EOF;
+}
+
+static void
+_unget_char (char c, lisp_stream_t *stream)
+{
+ switch (stream->type)
+ {
+ case LISP_STREAM_FILE :
+ ungetc(c, stream->v.file);
+ break;
+
+ case LISP_STREAM_STRING :
+ --stream->v.string.pos;
+ break;
+
+ case LISP_STREAM_ANY:
+ stream->v.any.unget_char(c, stream->v.any.data);
+ break;
+
+ default :
+ throw LispReaderException("_unget_char()", __FILE__, __LINE__);
+ }
+}
+
+static int
+_scan (lisp_stream_t *stream)
+{
+ static char *delims = "\"();";
+
+ int c;
+
+ _token_clear();
+
+ do
+ {
+ c = _next_char(stream);
+ if (c == EOF)
+ return TOKEN_EOF;
+ else if (c == ';') /* comment start */
+ while (1)
+ {
+ c = _next_char(stream);
+ if (c == EOF)
+ return TOKEN_EOF;
+ else if (c == '\n')
+ break;
+ }
+ }
+ while (isspace(c));
+
+ switch (c)
+ {
+ case '(' :
+ return TOKEN_OPEN_PAREN;
+
+ case ')' :
+ return TOKEN_CLOSE_PAREN;
+
+ case '"' :
+ while (1)
+ {
+ c = _next_char(stream);
+ if (c == EOF)
+ return TOKEN_ERROR;
+ if (c == '"')
+ break;
+ if (c == '\\')
+ {
+ c = _next_char(stream);
+
+ switch (c)
+ {
+ case EOF :
+ return TOKEN_ERROR;
+
+ case 'n' :
+ c = '\n';
+ break;
+
+ case 't' :
+ c = '\t';
+ break;
+ }
+ }
+
+ _token_append(c);
+ }
+ return TOKEN_STRING;
+
+ case '#' :
+ c = _next_char(stream);
+ if (c == EOF)
+ return TOKEN_ERROR;
+
+ switch (c)
+ {
+ case 't' :
+ return TOKEN_TRUE;
+
+ case 'f' :
+ return TOKEN_FALSE;
+
+ case '?' :
+ c = _next_char(stream);
+ if (c == EOF)
+ return TOKEN_ERROR;
+
+ if (c == '(')
+ return TOKEN_PATTERN_OPEN_PAREN;
+ else
+ return TOKEN_ERROR;
+ }
+ return TOKEN_ERROR;
+
+ default :
+ if (isdigit(c) || c == '-')
+ {
+ int have_nondigits = 0;
+ int have_digits = 0;
+ int have_floating_point = 0;
+
+ do
+ {
+ if (isdigit(c))
+ have_digits = 1;
+ else if (c == '.')
+ have_floating_point++;
+ _token_append(c);
+
+ c = _next_char(stream);
+
+ if (c != EOF && !isdigit(c) && !isspace(c) && c != '.' && !strchr(delims, c))
+ have_nondigits = 1;
+ }
+ while (c != EOF && !isspace(c) && !strchr(delims, c));
+
+ if (c != EOF)
+ _unget_char(c, stream);
+
+ if (have_nondigits || !have_digits || have_floating_point > 1)
+ return TOKEN_SYMBOL;
+ else if (have_floating_point == 1)
+ return TOKEN_REAL;
+ else
+ return TOKEN_INTEGER;
+ }
+ else
+ {
+ if (c == '.')
+ {
+ c = _next_char(stream);
+ if (c != EOF && !isspace(c) && !strchr(delims, c))
+ _token_append('.');
+ else
+ {
+ _unget_char(c, stream);
+ return TOKEN_DOT;
+ }
+ }
+ do
+ {
+ _token_append(c);
+ c = _next_char(stream);
+ }
+ while (c != EOF && !isspace(c) && !strchr(delims, c));
+ if (c != EOF)
+ _unget_char(c, stream);
+
+ return TOKEN_SYMBOL;
+ }
+ }
+
+ throw LispReaderException("_scan()", __FILE__, __LINE__);
+ return TOKEN_ERROR;
+}
+
+static lisp_object_t*
+lisp_object_alloc (int type)
+{
+ lisp_object_t *obj = (lisp_object_t*)malloc(sizeof(lisp_object_t));
+
+ obj->type = type;
+
+ return obj;
+}
+
+lisp_stream_t*
+lisp_stream_init_file (lisp_stream_t *stream, FILE *file)
+{
+ stream->type = LISP_STREAM_FILE;
+ stream->v.file = file;
+
+ return stream;
+}
+
+lisp_stream_t*
+lisp_stream_init_string (lisp_stream_t *stream, char *buf)
+{
+ stream->type = LISP_STREAM_STRING;
+ stream->v.string.buf = buf;
+ stream->v.string.pos = 0;
+
+ return stream;
+}
+
+lisp_stream_t*
+lisp_stream_init_any (lisp_stream_t *stream, void *data,
+ int (*next_char) (void *data),
+ void (*unget_char) (char c, void *data))
+{
+ if (next_char == 0 || unget_char == 0)
+ throw LispReaderException("lisp_stream_init_any()", __FILE__, __LINE__);
+
+ stream->type = LISP_STREAM_ANY;
+ stream->v.any.data = data;
+ stream->v.any.next_char= next_char;
+ stream->v.any.unget_char = unget_char;
+
+ return stream;
+}
+
+lisp_object_t*
+lisp_make_integer (int value)
+{
+ lisp_object_t *obj = lisp_object_alloc(LISP_TYPE_INTEGER);
+
+ obj->v.integer = value;
+
+ return obj;
+}
+
+lisp_object_t*
+lisp_make_real (float value)
+{
+ lisp_object_t *obj = lisp_object_alloc(LISP_TYPE_REAL);
+
+ obj->v.real = value;
+
+ return obj;
+}
+
+lisp_object_t*
+lisp_make_symbol (const char *value)
+{
+ lisp_object_t *obj = lisp_object_alloc(LISP_TYPE_SYMBOL);
+
+ obj->v.string = strdup(value);
+
+ return obj;
+}
+
+lisp_object_t*
+lisp_make_string (const char *value)
+{
+ lisp_object_t *obj = lisp_object_alloc(LISP_TYPE_STRING);
+
+ obj->v.string = strdup(value);
+
+ return obj;
+}
+
+lisp_object_t*
+lisp_make_cons (lisp_object_t *car, lisp_object_t *cdr)
+{
+ lisp_object_t *obj = lisp_object_alloc(LISP_TYPE_CONS);
+
+ obj->v.cons.car = car;
+ obj->v.cons.cdr = cdr;
+
+ return obj;
+}
+
+lisp_object_t*
+lisp_make_boolean (int value)
+{
+ lisp_object_t *obj = lisp_object_alloc(LISP_TYPE_BOOLEAN);
+
+ obj->v.integer = value ? 1 : 0;
+
+ return obj;
+}
+
+static lisp_object_t*
+lisp_make_pattern_cons (lisp_object_t *car, lisp_object_t *cdr)
+{
+ lisp_object_t *obj = lisp_object_alloc(LISP_TYPE_PATTERN_CONS);
+
+ obj->v.cons.car = car;
+ obj->v.cons.cdr = cdr;
+
+ return obj;
+}
+
+static lisp_object_t*
+lisp_make_pattern_var (int type, int index, lisp_object_t *sub)
+{
+ lisp_object_t *obj = lisp_object_alloc(LISP_TYPE_PATTERN_VAR);
+
+ obj->v.pattern.type = type;
+ obj->v.pattern.index = index;
+ obj->v.pattern.sub = sub;
+
+ return obj;
+}
+
+lisp_object_t*
+lisp_read (lisp_stream_t *in)
+{
+ int token = _scan(in);
+ lisp_object_t *obj = lisp_nil();
+
+ if (token == TOKEN_EOF)
+ return &end_marker;
+
+ switch (token)
+ {
+ case TOKEN_ERROR :
+ return &error_object;
+
+ case TOKEN_EOF :
+ return &end_marker;
+
+ case TOKEN_OPEN_PAREN :
+ case TOKEN_PATTERN_OPEN_PAREN :
+ {
+ lisp_object_t *last = lisp_nil(), *car;
+
+ do
+ {
+ car = lisp_read(in);
+ if (car == &error_object || car == &end_marker)
+ {
+ lisp_free(obj);
+ return &error_object;
+ }
+ else if (car == &dot_marker)
+ {
+ if (lisp_nil_p(last))
+ {
+ lisp_free(obj);
+ return &error_object;
+ }
+
+ car = lisp_read(in);
+ if (car == &error_object || car == &end_marker)
+ {
+ lisp_free(obj);
+ return car;
+ }
+ else
+ {
+ last->v.cons.cdr = car;
+
+ if (_scan(in) != TOKEN_CLOSE_PAREN)
+ {
+ lisp_free(obj);
+ return &error_object;
+ }
+
+ car = &close_paren_marker;
+ }
+ }
+ else if (car != &close_paren_marker)
+ {
+ if (lisp_nil_p(last))
+ obj = last = (token == TOKEN_OPEN_PAREN ? lisp_make_cons(car, lisp_nil()) : lisp_make_pattern_cons(car, lisp_nil()));
+ else
+ last = last->v.cons.cdr = lisp_make_cons(car, lisp_nil());
+ }
+ }
+ while (car != &close_paren_marker);
+ }
+ return obj;
+
+ case TOKEN_CLOSE_PAREN :
+ return &close_paren_marker;
+
+ case TOKEN_SYMBOL :
+ return lisp_make_symbol(token_string);
+
+ case TOKEN_STRING :
+ return lisp_make_string(token_string);
+
+ case TOKEN_INTEGER :
+ return lisp_make_integer(atoi(token_string));
+
+ case TOKEN_REAL :
+ return lisp_make_real((float)atof(token_string));
+
+ case TOKEN_DOT :
+ return &dot_marker;
+
+ case TOKEN_TRUE :
+ return lisp_make_boolean(1);
+
+ case TOKEN_FALSE :
+ return lisp_make_boolean(0);
+ }
+
+ throw LispReaderException("lisp_read()", __FILE__, __LINE__);
+ return &error_object;
+}
+
+void
+lisp_free (lisp_object_t *obj)
+{
+ if (obj == 0)
+ return;
+
+ /** We have to use this iterative code, because the recursive function
+ * produces a stack overflow and crashs on OSX 10.2
+ */
+ std::vector<lisp_object_t*> objs;
+ objs.push_back(obj);
+
+ while(!objs.empty()) {
+ lisp_object_t* obj = objs.back();
+ objs.pop_back();
+
+ switch (obj->type) {
+ case LISP_TYPE_INTERNAL :
+ case LISP_TYPE_PARSE_ERROR :
+ case LISP_TYPE_EOF :
+ return;
+
+ case LISP_TYPE_SYMBOL :
+ case LISP_TYPE_STRING :
+ free(obj->v.string);
+ break;
+
+ case LISP_TYPE_CONS :
+ case LISP_TYPE_PATTERN_CONS :
+ if(obj->v.cons.car)
+ objs.push_back(obj->v.cons.car);
+ if(obj->v.cons.cdr)
+ objs.push_back(obj->v.cons.cdr);
+ break;
+
+ case LISP_TYPE_PATTERN_VAR :
+ if(obj->v.pattern.sub)
+ objs.push_back(obj->v.pattern.sub);
+ break;
+ }
+
+ free(obj);
+ }
+}
+
+lisp_object_t*
+lisp_read_from_string (const char *buf)
+{
+ lisp_stream_t stream;
+
+ lisp_stream_init_string(&stream, (char*)buf);
+ return lisp_read(&stream);
+}
+
+static int
+_compile_pattern (lisp_object_t **obj, int *index)
+{
+ if (*obj == 0)
+ return 1;
+
+ switch (lisp_type(*obj))
+ {
+ case LISP_TYPE_PATTERN_CONS :
+ {
+ struct
+ {
+ char *name;
+ int type;
+ }
+ types[] =
+ {
+ { "any", LISP_PATTERN_ANY },
+ { "symbol", LISP_PATTERN_SYMBOL },
+ { "string", LISP_PATTERN_STRING },
+ { "integer", LISP_PATTERN_INTEGER },
+ { "real", LISP_PATTERN_REAL },
+ { "boolean", LISP_PATTERN_BOOLEAN },
+ { "list", LISP_PATTERN_LIST },
+ { "or", LISP_PATTERN_OR },
+ { 0, 0 }
+ };
+ char *type_name;
+ int type;
+ int i;
+ lisp_object_t *pattern;
+ type = -1;
+
+ if (lisp_type(lisp_car(*obj)) != LISP_TYPE_SYMBOL)
+ return 0;
+
+ type_name = lisp_symbol(lisp_car(*obj));
+ for (i = 0; types[i].name != 0; ++i)
+ {
+ if (strcmp(types[i].name, type_name) == 0)
+ {
+ type = types[i].type;
+ break;
+ }
+ }
+
+ if (types[i].name == 0)
+ return 0;
+
+ if (type != LISP_PATTERN_OR && lisp_cdr(*obj) != 0)
+ return 0;
+
+ pattern = lisp_make_pattern_var(type, (*index)++, lisp_nil());
+
+ if (type == LISP_PATTERN_OR)
+ {
+ lisp_object_t *cdr = lisp_cdr(*obj);
+
+ if (!_compile_pattern(&cdr, index))
+ {
+ lisp_free(pattern);
+ return 0;
+ }
+
+ pattern->v.pattern.sub = cdr;
+
+ (*obj)->v.cons.cdr = lisp_nil();
+ }
+
+ lisp_free(*obj);
+
+ *obj = pattern;
+ }
+ break;
+
+ case LISP_TYPE_CONS :
+ if (!_compile_pattern(&(*obj)->v.cons.car, index))
+ return 0;
+ if (!_compile_pattern(&(*obj)->v.cons.cdr, index))
+ return 0;
+ break;
+ }
+
+ return 1;
+}
+
+int
+lisp_compile_pattern (lisp_object_t **obj, int *num_subs)
+{
+ int index = 0;
+ int result;
+
+ result = _compile_pattern(obj, &index);
+
+ if (result && num_subs != 0)
+ *num_subs = index;
+
+ return result;
+}
+
+static int _match_pattern (lisp_object_t *pattern, lisp_object_t *obj, lisp_object_t **vars);
+
+static int
+_match_pattern_var (lisp_object_t *pattern, lisp_object_t *obj, lisp_object_t **vars)
+{
+ if (lisp_type(pattern) != LISP_TYPE_PATTERN_VAR)
+ throw LispReaderException("_match_pattern_var", __FILE__, __LINE__);
+
+ switch (pattern->v.pattern.type)
+ {
+ case LISP_PATTERN_ANY :
+ break;
+
+ case LISP_PATTERN_SYMBOL :
+ if (obj == 0 || lisp_type(obj) != LISP_TYPE_SYMBOL)
+ return 0;
+ break;
+
+ case LISP_PATTERN_STRING :
+ if (obj == 0 || lisp_type(obj) != LISP_TYPE_STRING)
+ return 0;
+ break;
+
+ case LISP_PATTERN_INTEGER :
+ if (obj == 0 || lisp_type(obj) != LISP_TYPE_INTEGER)
+ return 0;
+ break;
+
+ case LISP_PATTERN_REAL :
+ if (obj == 0 || lisp_type(obj) != LISP_TYPE_REAL)
+ return 0;
+ break;
+
+ case LISP_PATTERN_BOOLEAN :
+ if (obj == 0 || lisp_type(obj) != LISP_TYPE_BOOLEAN)
+ return 0;
+ break;
+
+ case LISP_PATTERN_LIST :
+ if (obj == 0 || lisp_type(obj) != LISP_TYPE_CONS)
+ return 0;
+ break;
+
+ case LISP_PATTERN_OR :
+ {
+ lisp_object_t *sub;
+ int matched = 0;
+
+ for (sub = pattern->v.pattern.sub; sub != 0; sub = lisp_cdr(sub))
+ {
+ if (lisp_type(sub) != LISP_TYPE_CONS)
+ throw LispReaderException("_match_pattern_var()", __FILE__, __LINE__);
+
+ if (_match_pattern(lisp_car(sub), obj, vars))
+ matched = 1;
+ }
+
+ if (!matched)
+ return 0;
+ }
+ break;
+
+ default :
+ throw LispReaderException("_match_pattern_var()", __FILE__, __LINE__);
+ }
+
+ if (vars != 0)
+ vars[pattern->v.pattern.index] = obj;
+
+ return 1;
+}
+
+static int
+_match_pattern (lisp_object_t *pattern, lisp_object_t *obj, lisp_object_t **vars)
+{
+ if (pattern == 0)
+ return obj == 0;
+
+ if (obj == 0)
+ return 0;
+
+ if (lisp_type(pattern) == LISP_TYPE_PATTERN_VAR)
+ return _match_pattern_var(pattern, obj, vars);
+
+ if (lisp_type(pattern) != lisp_type(obj))
+ return 0;
+
+ switch (lisp_type(pattern))
+ {
+ case LISP_TYPE_SYMBOL :
+ return strcmp(lisp_symbol(pattern), lisp_symbol(obj)) == 0;
+
+ case LISP_TYPE_STRING :
+ return strcmp(lisp_string(pattern), lisp_string(obj)) == 0;
+
+ case LISP_TYPE_INTEGER :
+ return lisp_integer(pattern) == lisp_integer(obj);
+
+ case LISP_TYPE_REAL :
+ return lisp_real(pattern) == lisp_real(obj);
+
+ case LISP_TYPE_CONS :
+ {
+ int result1, result2;
+
+ result1 = _match_pattern(lisp_car(pattern), lisp_car(obj), vars);
+ result2 = _match_pattern(lisp_cdr(pattern), lisp_cdr(obj), vars);
+
+ return result1 && result2;
+ }
+ break;
+
+ default :
+ throw LispReaderException("_match_pattern()", __FILE__, __LINE__);
+ }
+
+ return 0;
+}
+
+int
+lisp_match_pattern (lisp_object_t *pattern, lisp_object_t *obj, lisp_object_t **vars, int num_subs)
+{
+ int i;
+
+ if (vars != 0)
+ for (i = 0; i < num_subs; ++i)
+ vars[i] = &error_object;
+
+ return _match_pattern(pattern, obj, vars);
+}
+
+int
+lisp_match_string (const char *pattern_string, lisp_object_t *obj, lisp_object_t **vars)
+{
+ lisp_object_t *pattern;
+ int result;
+ int num_subs;
+
+ pattern = lisp_read_from_string(pattern_string);
+
+ if (pattern != 0 && (lisp_type(pattern) == LISP_TYPE_EOF
+ || lisp_type(pattern) == LISP_TYPE_PARSE_ERROR))
+ return 0;
+
+ if (!lisp_compile_pattern(&pattern, &num_subs))
+ {
+ lisp_free(pattern);
+ return 0;
+ }
+
+ result = lisp_match_pattern(pattern, obj, vars, num_subs);
+
+ lisp_free(pattern);
+
+ return result;
+}
+
+int
+lisp_type (lisp_object_t *obj)
+{
+ if (obj == 0)
+ return LISP_TYPE_NIL;
+ return obj->type;
+}
+
+int
+lisp_integer (lisp_object_t *obj)
+{
+ if (obj->type != LISP_TYPE_INTEGER)
+ throw LispReaderException("lisp_integer()", __FILE__, __LINE__);
+
+ return obj->v.integer;
+}
+
+char*
+lisp_symbol (lisp_object_t *obj)
+{
+ if (obj->type != LISP_TYPE_SYMBOL)
+ throw LispReaderException("lisp_symbol()", __FILE__, __LINE__);
+
+ return obj->v.string;
+}
+
+char*
+lisp_string (lisp_object_t *obj)
+{
+ if (obj->type != LISP_TYPE_STRING)
+ throw LispReaderException("lisp_string()", __FILE__, __LINE__);
+
+ return obj->v.string;
+}
+
+int
+lisp_boolean (lisp_object_t *obj)
+{
+ if (obj->type != LISP_TYPE_BOOLEAN)
+ throw LispReaderException("lisp_boolean()", __FILE__, __LINE__);
+
+ return obj->v.integer;
+}
+
+float
+lisp_real (lisp_object_t *obj)
+{
+ if (obj->type != LISP_TYPE_REAL && obj->type != LISP_TYPE_INTEGER)
+ throw LispReaderException("lisp_real()", __FILE__, __LINE__);
+
+ if (obj->type == LISP_TYPE_INTEGER)
+ return obj->v.integer;
+ return obj->v.real;
+}
+
+lisp_object_t*
+lisp_car (lisp_object_t *obj)
+{
+ if (obj->type != LISP_TYPE_CONS && obj->type != LISP_TYPE_PATTERN_CONS)
+ throw LispReaderException("lisp_car()", __FILE__, __LINE__);
+
+ return obj->v.cons.car;
+}
+
+lisp_object_t*
+lisp_cdr (lisp_object_t *obj)
+{
+ if (obj->type != LISP_TYPE_CONS && obj->type != LISP_TYPE_PATTERN_CONS)
+ throw LispReaderException("lisp_cdr()", __FILE__, __LINE__);
+
+ return obj->v.cons.cdr;
+}
+
+lisp_object_t*
+lisp_cxr (lisp_object_t *obj, const char *x)
+{
+ int i;
+
+ for (i = strlen(x) - 1; i >= 0; --i)
+ if (x[i] == 'a')
+ obj = lisp_car(obj);
+ else if (x[i] == 'd')
+ obj = lisp_cdr(obj);
+ else
+ throw LispReaderException("lisp_cxr()", __FILE__, __LINE__);
+
+ return obj;
+}
+
+int
+lisp_list_length (lisp_object_t *obj)
+{
+ int length = 0;
+
+ while (obj != 0)
+ {
+ if (obj->type != LISP_TYPE_CONS && obj->type != LISP_TYPE_PATTERN_CONS)
+ throw LispReaderException("lisp_list_length()", __FILE__, __LINE__);
+
+ ++length;
+ obj = obj->v.cons.cdr;
+ }
+
+ return length;
+}
+
+lisp_object_t*
+lisp_list_nth_cdr (lisp_object_t *obj, int index)
+{
+ while (index > 0)
+ {
+ if (obj == 0)
+ throw LispReaderException("lisp_list_nth_cdr()", __FILE__, __LINE__);
+ if (obj->type != LISP_TYPE_CONS && obj->type != LISP_TYPE_PATTERN_CONS)
+ throw LispReaderException("lisp_list_nth_cdr()", __FILE__, __LINE__);
+
+ --index;
+ obj = obj->v.cons.cdr;
+ }
+
+ return obj;
+}
+
+lisp_object_t*
+lisp_list_nth (lisp_object_t *obj, int index)
+{
+ obj = lisp_list_nth_cdr(obj, index);
+
+ if (obj == 0)
+ throw LispReaderException("lisp_list_nth()", __FILE__, __LINE__);
+
+ return obj->v.cons.car;
+}
+
+void
+lisp_dump (lisp_object_t *obj, FILE *out)
+{
+ if (obj == 0)
+ {
+ fprintf(out, "()");
+ return;
+ }
+
+ switch (lisp_type(obj))
+ {
+ case LISP_TYPE_EOF :
+ fputs("#<eof>", out);
+ break;
+
+ case LISP_TYPE_PARSE_ERROR :
+ fputs("#<error>", out);
+ break;
+
+ case LISP_TYPE_INTEGER :
+ fprintf(out, "%d", lisp_integer(obj));
+ break;
+
+ case LISP_TYPE_REAL :
+ fprintf(out, "%f", lisp_real(obj));
+ break;
+
+ case LISP_TYPE_SYMBOL :
+ fputs(lisp_symbol(obj), out);
+ break;
+
+ case LISP_TYPE_STRING :
+ {
+ char *p;
+
+ fputc('"', out);
+ for (p = lisp_string(obj); *p != 0; ++p)
+ {
+ if (*p == '"' || *p == '\\')
+ fputc('\\', out);
+ fputc(*p, out);
+ }
+ fputc('"', out);
+ }
+ break;
+
+ case LISP_TYPE_CONS :
+ case LISP_TYPE_PATTERN_CONS :
+ fputs(lisp_type(obj) == LISP_TYPE_CONS ? "(" : "#?(", out);
+ while (obj != 0)
+ {
+ lisp_dump(lisp_car(obj), out);
+ obj = lisp_cdr(obj);
+ if (obj != 0)
+ {
+ if (lisp_type(obj) != LISP_TYPE_CONS
+ && lisp_type(obj) != LISP_TYPE_PATTERN_CONS)
+ {
+ fputs(" . ", out);
+ lisp_dump(obj, out);
+ break;
+ }
+ else
+ fputc(' ', out);
+ }
+ }
+ fputc(')', out);
+ break;
+
+ case LISP_TYPE_BOOLEAN :
+ if (lisp_boolean(obj))
+ fputs("#t", out);
+ else
+ fputs("#f", out);
+ break;
+
+ default :
+ throw LispReaderException("lisp_dump()", __FILE__, __LINE__);
+ }
+}
+
+using namespace std;
+
+LispReader::LispReader (lisp_object_t* l)
+ : owner(0), lst (l)
+{
+}
+
+LispReader::~LispReader()
+{
+ if(owner)
+ lisp_free(owner);
+}
+
+LispReader*
+LispReader::load(const std::string& filename, const std::string& toplevellist)
+{
+ lisp_object_t* obj = lisp_read_from_file(filename);
+
+ if(obj->type == LISP_TYPE_EOF || obj->type == LISP_TYPE_PARSE_ERROR) {
+ lisp_free(obj);
+ throw LispReaderException("LispReader::load", __FILE__, __LINE__);
+ }
+
+ if(toplevellist != lisp_symbol(lisp_car(obj))) {
+ lisp_car(obj);
+ throw LispReaderException("LispReader::load wrong toplevel symbol",
+ __FILE__, __LINE__);
+ }
+
+ LispReader* reader = new LispReader(lisp_cdr(obj));
+ reader->owner = obj;
+
+ return reader;
+}
+
+lisp_object_t*
+LispReader::search_for(const char* name)
+{
+ //std::cout << "LispReader::search_for(" << name << ")" << std::endl;
+ lisp_object_t* cursor = lst;
+
+ while(!lisp_nil_p(cursor))
+ {
+ lisp_object_t* cur = lisp_car(cursor);
+
+ if (!lisp_cons_p(cur) || !lisp_symbol_p (lisp_car(cur)))
+ {
+ lisp_dump(cur, stdout);
+ //throw ConstruoError (std::string("LispReader: Read error in search_for ") + name);
+ printf("LispReader: Read error in search\n");
+ }
+ else
+ {
+ if (strcmp(lisp_symbol(lisp_car(cur)), name) == 0)
+ {
+ return lisp_cdr(cur);
+ }
+ }
+
+ cursor = lisp_cdr (cursor);
+ }
+ return 0;
+}
+
+bool
+LispReader::read_int (const char* name, int& i)
+{
+ lisp_object_t* obj = search_for (name);
+ if(!obj)
+ return false;
+
+ if (!lisp_integer_p(lisp_car(obj)))
+ return false;
+
+ i = lisp_integer(lisp_car(obj));
+ return true;
+}
+
+bool
+LispReader::read_lisp(const char* name, lisp_object_t*& b)
+{
+ lisp_object_t* obj = search_for (name);
+ if (!obj)
+ return false;
+
+ b = obj;
+ return true;
+}
+
+lisp_object_t*
+LispReader::read_lisp(const char* name)
+{
+ return search_for(name);
+}
+
+bool
+LispReader::read_float (const char* name, float& f)
+{
+ lisp_object_t* obj = search_for (name);
+ if (!obj)
+ return false;
+
+ if (!lisp_real_p(lisp_car(obj)) && !lisp_integer_p(lisp_car(obj)))
+ st_abort("LispReader expected type real at token: ", name);
+
+ f = lisp_real(lisp_car(obj));
+ return true;
+}
+
+bool
+LispReader::read_string_vector (const char* name, std::vector<std::string>& vec)
+{
+ lisp_object_t* obj = search_for (name);
+ if (!obj)
+ return false;
+
+ vec.clear();
+ while(!lisp_nil_p(obj))
+ {
+ if (!lisp_string_p(lisp_car(obj)))
+ st_abort("LispReader expected type string at token: ", name);
+ vec.push_back(lisp_string(lisp_car(obj)));
+ obj = lisp_cdr(obj);
+ }
+ return true;
+}
+
+bool
+LispReader::read_int_vector (const char* name, std::vector<int>& vec)
+{
+ lisp_object_t* obj = search_for (name);
+ if (!obj)
+ return false;
+
+ vec.clear();
+ while(!lisp_nil_p(obj))
+ {
+ if (!lisp_integer_p(lisp_car(obj)))
+ st_abort("LispReader expected type integer at token: ", name);
+ vec.push_back(lisp_integer(lisp_car(obj)));
+ obj = lisp_cdr(obj);
+ }
+ return true;
+}
+
+bool
+LispReader::read_int_vector (const char* name, std::vector<unsigned int>& vec)
+{
+ lisp_object_t* obj = search_for (name);
+ if (!obj)
+ return false;
+
+ vec.clear();
+ while(!lisp_nil_p(obj))
+ {
+ if (!lisp_integer_p(lisp_car(obj)))
+ st_abort("LispReader expected type integer at token: ", name);
+ vec.push_back(lisp_integer(lisp_car(obj)));
+ obj = lisp_cdr(obj);
+ }
+ return true;
+}
+
+bool
+LispReader::read_char_vector (const char* name, std::vector<char>& vec)
+{
+ lisp_object_t* obj = search_for (name);
+ if (!obj)
+ return false;
+
+ vec.clear();
+ while(!lisp_nil_p(obj))
+ {
+ vec.push_back(*lisp_string(lisp_car(obj)));
+ obj = lisp_cdr(obj);
+ }
+ return true;
+}
+
+bool
+LispReader::read_string (const char* name, std::string& str, bool translatable)
+{
+ lisp_object_t* obj;
+ if(translatable)
+ {
+ /* Internationalization support: check for the suffix: str + "-" + $LANG variable.
+ If not found, use the regular string.
+ So, translating a string in a Lisp file would result in something like:
+ (text "Hello World!")
+ (text-fr "Bonjour Monde!")
+ being fr the value of LANG (echo $LANG) for the language we want to translate to */
+
+ char* lang = getenv("LANG");
+
+ char str_[1024]; // check, for instance, for (title-fr_FR "Bonjour")
+ sprintf(str_, "%s-%s", name, lang);
+
+ obj = search_for (str_);
+
+ if(!obj) // check, for instance, for (title-fr "Bonjour")
+ {
+ if(lang != NULL && strlen(lang) >= 2)
+ {
+ char lang_[3];
+ strncpy(lang_, lang, 2);
+ lang_[2] = '\0';
+ sprintf(str_, "%s-%s", name, lang_);
+
+ obj = search_for (str_);
+ }
+ else
+ obj = 0;
+ }
+
+ if(!obj) // check, for instance, for (title "Hello")
+ obj = search_for (name);
+ }
+ else
+ obj = search_for (name);
+
+ if (!obj)
+ return false;
+
+ if (!lisp_string_p(lisp_car(obj)))
+ st_abort("LispReader expected type string at token: ", name);
+ str = lisp_string(lisp_car(obj));
+ return true;
+}
+
+bool
+LispReader::read_bool (const char* name, bool& b)
+{
+ lisp_object_t* obj = search_for (name);
+ if (!obj)
+ return false;
+
+ if (!lisp_boolean_p(lisp_car(obj)))
+ st_abort("LispReader expected type bool at token: ", name);
+ b = lisp_boolean(lisp_car(obj));
+ return true;
+}
+
+lisp_object_t*
+LispReader::get_lisp()
+{
+ return lst;
+}
+
+lisp_object_t* lisp_read_from_file(const std::string& filename)
+{
+ FILE* in = fopen(filename.c_str(), "r");
+
+ if(!in)
+ return 0;
+
+ lisp_stream_t stream;
+ lisp_stream_init_file(&stream, in);
+ lisp_object_t* obj = lisp_read(&stream);
+ fclose(in);
+
+ return obj;
+}
+
+// EOF //
--- /dev/null
+/* $Id$ */
+/*
+ * lispreader.h
+ *
+ * Copyright (C) 1998-2000 Mark Probst
+ * Copyright (C) 2002 Ingo Ruhnke <grumbel@gmx.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef SUPERTUX_LISPREADER_H
+#define SUPERTUX_LISPREADER_H
+
+#include <cstdio>
+#include <string>
+#include <vector>
+#include <exception>
+
+#include <zlib.h>
+
+#include "utils/exceptions.h"
+
+#define LISP_STREAM_FILE 1
+#define LISP_STREAM_STRING 2
+#define LISP_STREAM_ANY 3
+
+#define LISP_TYPE_INTERNAL -3
+#define LISP_TYPE_PARSE_ERROR -2
+#define LISP_TYPE_EOF -1
+#define LISP_TYPE_NIL 0
+#define LISP_TYPE_SYMBOL 1
+#define LISP_TYPE_INTEGER 2
+#define LISP_TYPE_STRING 3
+#define LISP_TYPE_REAL 4
+#define LISP_TYPE_CONS 5
+#define LISP_TYPE_PATTERN_CONS 6
+#define LISP_TYPE_BOOLEAN 7
+#define LISP_TYPE_PATTERN_VAR 8
+
+#define LISP_PATTERN_ANY 1
+#define LISP_PATTERN_SYMBOL 2
+#define LISP_PATTERN_STRING 3
+#define LISP_PATTERN_INTEGER 4
+#define LISP_PATTERN_REAL 5
+#define LISP_PATTERN_BOOLEAN 6
+#define LISP_PATTERN_LIST 7
+#define LISP_PATTERN_OR 8
+
+// Exception
+class LispReaderException : public SuperTuxException
+{
+ public:
+ LispReaderException(const char* _message = "lispreader error", const char* _file = "", const unsigned int _line = 0)
+ : SuperTuxException(_message, _file, _line) { };
+};
+
+typedef struct
+ {
+ int type;
+
+ union
+ {
+ FILE *file;
+ struct
+ {
+ char *buf;
+ int pos;
+ }
+ string;
+ struct
+ {
+ void *data;
+ int (*next_char) (void *data);
+ void (*unget_char) (char c, void *data);
+ }
+ any;
+ } v;
+ }
+lisp_stream_t;
+
+typedef struct _lisp_object_t lisp_object_t;
+struct _lisp_object_t
+ {
+ int type;
+
+ union
+ {
+ struct
+ {
+ struct _lisp_object_t *car;
+ struct _lisp_object_t *cdr;
+ }
+ cons;
+
+ char *string;
+ int integer;
+ float real;
+
+ struct
+ {
+ int type;
+ int index;
+ struct _lisp_object_t *sub;
+ }
+ pattern;
+ } v;
+ };
+
+lisp_stream_t* lisp_stream_init_file (lisp_stream_t *stream, FILE *file);
+lisp_stream_t* lisp_stream_init_string (lisp_stream_t *stream, char *buf);
+lisp_stream_t* lisp_stream_init_any (lisp_stream_t *stream, void *data,
+ int (*next_char) (void *data),
+ void (*unget_char) (char c, void *data));
+
+lisp_object_t* lisp_read (lisp_stream_t *in);
+lisp_object_t* lisp_read_from_file(const std::string& filename);
+void lisp_free (lisp_object_t *obj);
+
+lisp_object_t* lisp_read_from_string (const char *buf);
+
+int lisp_compile_pattern (lisp_object_t **obj, int *num_subs);
+int lisp_match_pattern (lisp_object_t *pattern, lisp_object_t *obj, lisp_object_t **vars, int num_subs);
+int lisp_match_string (const char *pattern_string, lisp_object_t *obj, lisp_object_t **vars);
+
+int lisp_type (lisp_object_t *obj);
+int lisp_integer (lisp_object_t *obj);
+float lisp_real (lisp_object_t *obj);
+char* lisp_symbol (lisp_object_t *obj);
+char* lisp_string (lisp_object_t *obj);
+int lisp_boolean (lisp_object_t *obj);
+lisp_object_t* lisp_car (lisp_object_t *obj);
+lisp_object_t* lisp_cdr (lisp_object_t *obj);
+
+lisp_object_t* lisp_cxr (lisp_object_t *obj, const char *x);
+
+lisp_object_t* lisp_make_integer (int value);
+lisp_object_t* lisp_make_real (float value);
+lisp_object_t* lisp_make_symbol (const char *value);
+lisp_object_t* lisp_make_string (const char *value);
+lisp_object_t* lisp_make_cons (lisp_object_t *car, lisp_object_t *cdr);
+lisp_object_t* lisp_make_boolean (int value);
+
+int lisp_list_length (lisp_object_t *obj);
+lisp_object_t* lisp_list_nth_cdr (lisp_object_t *obj, int index);
+lisp_object_t* lisp_list_nth (lisp_object_t *obj, int index);
+
+void lisp_dump (lisp_object_t *obj, FILE *out);
+
+#define lisp_nil() ((lisp_object_t*)0)
+
+#define lisp_nil_p(obj) (obj == 0)
+#define lisp_integer_p(obj) (lisp_type((obj)) == LISP_TYPE_INTEGER)
+#define lisp_real_p(obj) (lisp_type((obj)) == LISP_TYPE_REAL)
+#define lisp_symbol_p(obj) (lisp_type((obj)) == LISP_TYPE_SYMBOL)
+#define lisp_string_p(obj) (lisp_type((obj)) == LISP_TYPE_STRING)
+#define lisp_cons_p(obj) (lisp_type((obj)) == LISP_TYPE_CONS)
+#define lisp_boolean_p(obj) (lisp_type((obj)) == LISP_TYPE_BOOLEAN)
+
+/** */
+class LispReader
+{
+private:
+ lisp_object_t* owner;
+ lisp_object_t* lst;
+
+ lisp_object_t* search_for(const char* name);
+
+public:
+ /** cur == ((pos 1 2 3) (id 12 3 4)...) */
+ LispReader(lisp_object_t* l);
+ ~LispReader();
+
+ bool read_int_vector(const char* name, std::vector<int>& vec);
+ bool read_int_vector(const char* name, std::vector<unsigned int>& vec);
+ bool read_char_vector(const char* name, std::vector<char>& vec);
+ bool read_string_vector(const char* name, std::vector<std::string>& vec);
+ bool read_string(const char* name, std::string& str, bool translatable = false);
+ bool read_int(const char* name, int& i);
+ bool read_float(const char* name, float& f);
+ bool read_bool(const char* name, bool& b);
+ bool read_lisp(const char* name, lisp_object_t*& b);
+ lisp_object_t* read_lisp(const char* name);
+
+ static LispReader* load(const std::string& filename,
+ const std::string& toplevellist);
+
+ lisp_object_t* get_lisp();
+};
+
+#endif /*SUPERTUX_LISPREADER_H*/
+
--- /dev/null
+// $Id$
+//
+// SuperTux - A Jump'n Run
+// Copyright (C) 2004 Matthias Braun <matze@braunis.de
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#include <iostream>
+
+#include "utils/lispwriter.h"
+
+LispWriter::LispWriter(std::ostream& newout)
+ : out(newout), indent_depth(0)
+{
+}
+
+LispWriter::~LispWriter()
+{
+ if(lists.size() > 0) {
+ std::cerr << "Warning: Not all sections closed in lispwriter!\n";
+ }
+}
+
+void
+LispWriter::write_comment(const std::string& comment)
+{
+ out << "; " << comment << "\n";
+}
+
+void
+LispWriter::start_list(const std::string& listname)
+{
+ indent();
+ out << '(' << listname << '\n';
+ indent_depth += 2;
+
+ lists.push_back(listname);
+}
+
+void
+LispWriter::end_list(const std::string& listname)
+{
+ if(lists.size() == 0) {
+ std::cerr << "Trying to close list '" << listname
+ << "', which is not open.\n";
+ return;
+ }
+ if(lists.back() != listname) {
+ std::cerr << "Warning: trying to close list '" << listname
+ << "' while list '" << lists.back() << "' is open.\n";
+ return;
+ }
+ lists.pop_back();
+
+ indent_depth -= 2;
+ indent();
+ out << ")\n";
+}
+
+void
+LispWriter::write_int(const std::string& name, int value)
+{
+ indent();
+ out << '(' << name << ' ' << value << ")\n";
+}
+
+void
+LispWriter::write_float(const std::string& name, float value)
+{
+ indent();
+ out << '(' << name << ' ' << value << ")\n";
+}
+
+void
+LispWriter::write_string(const std::string& name, const std::string& value)
+{
+ indent();
+ out << '(' << name << " \"" << value << "\")\n";
+}
+
+void
+LispWriter::write_bool(const std::string& name, bool value)
+{
+ indent();
+ out << '(' << name << ' ' << (value ? "#t" : "#f") << ")\n";
+}
+
+void
+LispWriter::write_int_vector(const std::string& name,
+ const std::vector<int>& value)
+{
+ indent();
+ out << '(' << name;
+ for(std::vector<int>::const_iterator i = value.begin(); i != value.end(); ++i)
+ out << " " << *i;
+ out << ")\n";
+}
+
+void
+LispWriter::write_int_vector(const std::string& name,
+ const std::vector<unsigned int>& value)
+{
+ indent();
+ out << '(' << name;
+ for(std::vector<unsigned int>::const_iterator i = value.begin(); i != value.end(); ++i)
+ out << " " << *i;
+ out << ")\n";
+}
+
+void
+LispWriter::indent()
+{
+ for(int i = 0; i<indent_depth; ++i)
+ out << ' ';
+}
+
--- /dev/null
+// $Id$
+//
+// SuperTux - A Jump'n Run
+// Copyright (C) 2004 Matthias Braun <matze@braunis.de
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#ifndef SUPERTUX_LISPWRITER_H
+#define SUPERTUX_LISPWRITER_H
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+class LispWriter
+{
+public:
+ LispWriter(std::ostream& out);
+ ~LispWriter();
+
+ void write_comment(const std::string& comment);
+
+ void start_list(const std::string& listname);
+
+ void write_int(const std::string& name, int value);
+ void write_float(const std::string& name, float value);
+ void write_string(const std::string& name, const std::string& value);
+ void write_bool(const std::string& name, bool value);
+ void write_int_vector(const std::string& name, const std::vector<int>& value);
+ void write_int_vector(const std::string& name, const std::vector<unsigned int>& value);
+ // add more write-functions when needed...
+
+ void end_list(const std::string& listname);
+
+private:
+ void indent();
+
+ std::ostream& out;
+ int indent_depth;
+ std::vector<std::string> lists;
+};
+
+#endif
+
--- /dev/null
+// $Id$
+//
+// SuperTux - A Jump'n Run
+// Copyright (C) 2004 Matthias Braun <matze@braunis.de
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#include <algorithm>
+#include <cassert>
+#include <iostream>
+
+#include "video/drawing_context.h"
+#include "video/surface.h"
+#include "app/globals.h"
+#include "video/font.h"
+
+DrawingContext::DrawingContext()
+{
+transform.draw_effect = NONE_EFFECT;
+}
+
+DrawingContext::~DrawingContext()
+{
+}
+
+void
+DrawingContext::draw_surface(const Surface* surface, const Vector& position,
+ int layer, Uint32 drawing_effect)
+{
+ assert(surface != 0);
+
+ DrawingRequest request;
+
+ request.type = SURFACE;
+ request.layer = layer;
+ request.request_data = const_cast<Surface*> (surface);
+ request.pos = transform.apply(position);
+ request.drawing_effect = drawing_effect;
+ request.drawing_effect = transform.draw_effect | drawing_effect;
+
+ drawingrequests.push_back(request);
+}
+
+void
+DrawingContext::draw_surface_part(const Surface* surface, const Vector& source,
+ const Vector& size, const Vector& dest, int layer, Uint32 drawing_effect)
+{
+ assert(surface != 0);
+
+ DrawingRequest request;
+
+ request.type = SURFACE_PART;
+ request.layer = layer;
+ request.pos = transform.apply(dest);
+ request.drawing_effect = drawing_effect;
+
+ SurfacePartRequest* surfacepartrequest = new SurfacePartRequest();
+ surfacepartrequest->size = size;
+ surfacepartrequest->source = source;
+ surfacepartrequest->surface = surface;
+ request.request_data = surfacepartrequest;
+
+ drawingrequests.push_back(request);
+}
+
+void
+DrawingContext::draw_text(Font* font, const std::string& text,
+ const Vector& position, int layer, Uint32 drawing_effect)
+{
+ DrawingRequest request;
+
+ request.type = TEXT;
+ request.layer = layer;
+ request.pos = transform.apply(position);
+ request.drawing_effect = drawing_effect;
+
+ TextRequest* textrequest = new TextRequest;
+ textrequest->font = font;
+ textrequest->text = text;
+ request.request_data = textrequest;
+
+ drawingrequests.push_back(request);
+}
+
+void
+DrawingContext::draw_text_center(Font* font, const std::string& text,
+ const Vector& position, int layer, Uint32 drawing_effect)
+{
+ DrawingRequest request;
+
+ request.type = TEXT;
+ request.layer = layer;
+ request.pos = transform.apply(position) + Vector(screen->w/2 -
+ font->get_text_width(text)/2, 0);
+ request.drawing_effect = drawing_effect;
+
+ TextRequest* textrequest = new TextRequest;
+ textrequest->font = font;
+ textrequest->text = text;
+ request.request_data = textrequest;
+
+ drawingrequests.push_back(request);
+}
+
+void
+DrawingContext::draw_gradient(Color top, Color bottom, int layer)
+{
+ DrawingRequest request;
+
+ request.type = GRADIENT;
+ request.layer = layer;
+ request.pos = Vector(0,0);
+
+ GradientRequest* gradientrequest = new GradientRequest;
+ gradientrequest->top = top;
+ gradientrequest->bottom = bottom;
+ request.request_data = gradientrequest;
+
+ drawingrequests.push_back(request);
+}
+
+void
+DrawingContext::draw_filled_rect(const Vector& topleft, const Vector& size,
+ Color color, int layer)
+{
+ DrawingRequest request;
+
+ request.type = FILLRECT;
+ request.layer = layer;
+ request.pos = transform.apply(topleft);
+
+ FillRectRequest* fillrectrequest = new FillRectRequest;
+ fillrectrequest->size = size;
+ fillrectrequest->color = color;
+ request.request_data = fillrectrequest;
+
+ drawingrequests.push_back(request);
+}
+
+void
+DrawingContext::draw_surface_part(DrawingRequest& request)
+{
+ SurfacePartRequest* surfacepartrequest
+ = (SurfacePartRequest*) request.request_data;
+
+ surfacepartrequest->surface->impl->draw_part(
+ surfacepartrequest->source.x, surfacepartrequest->source.y,
+ request.pos.x, request.pos.y,
+ surfacepartrequest->size.x, surfacepartrequest->size.y, 255,
+ request.drawing_effect);
+
+ delete surfacepartrequest;
+}
+
+void
+DrawingContext::draw_gradient(DrawingRequest& request)
+{
+ GradientRequest* gradientrequest = (GradientRequest*) request.request_data;
+ const Color& top = gradientrequest->top;
+ const Color& bottom = gradientrequest->bottom;
+
+#ifndef NOOPENGL
+ if(use_gl)
+ {
+ glBegin(GL_QUADS);
+ glColor3ub(top.red, top.green, top.blue);
+ glVertex2f(0, 0);
+ glVertex2f(screen->w, 0);
+ glColor3ub(bottom.red, bottom.green, bottom.blue);
+ glVertex2f(screen->w, screen->h);
+ glVertex2f(0, screen->h);
+ glEnd();
+ }
+ else
+ {
+#endif
+ if(&top == &bottom)
+ {
+ fillrect(0, 0, screen->w, screen->h, top.red, top.green, top.blue);
+ }
+ else
+ {
+ float redstep = (float(bottom.red)-float(top.red)) / float(screen->h);
+ float greenstep = (float(bottom.green)-float(top.green)) / float(screen->h);
+ float bluestep = (float(bottom.blue) - float(top.blue)) / float(screen->h);
+
+ for(float y = 0; y < screen->h; y += 2)
+ fillrect(0, (int)y, screen->w, 2,
+ int(float(top.red) + redstep * y),
+ int(float(top.green) + greenstep * y),
+ int(float(top.blue) + bluestep * y), 255);
+ }
+#ifndef NOOPENGL
+
+ }
+#endif
+
+ delete gradientrequest;
+}
+
+void
+DrawingContext::draw_text(DrawingRequest& request)
+{
+ TextRequest* textrequest = (TextRequest*) request.request_data;
+
+ textrequest->font->draw(textrequest->text, request.pos, request.drawing_effect);
+
+ delete textrequest;
+}
+
+void
+DrawingContext::draw_filled_rect(DrawingRequest& request)
+{
+ FillRectRequest* fillrectrequest = (FillRectRequest*) request.request_data;
+
+ float x = request.pos.x;
+ float y = request.pos.y;
+ float w = fillrectrequest->size.x;
+ float h = fillrectrequest->size.y;
+
+#ifndef NOOPENGL
+ if(use_gl)
+ {
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glColor4ub(fillrectrequest->color.red, fillrectrequest->color.green,
+ fillrectrequest->color.blue, fillrectrequest->color.alpha);
+
+ glBegin(GL_POLYGON);
+ glVertex2f(x, y);
+ glVertex2f(x+w, y);
+ glVertex2f(x+w, y+h);
+ glVertex2f(x, y+h);
+ glEnd();
+ glDisable(GL_BLEND);
+ }
+ else
+ {
+#endif
+ SDL_Rect src, rect;
+ SDL_Surface *temp = NULL;
+
+ rect.x = (int)x;
+ rect.y = (int)y;
+ rect.w = (int)w;
+ rect.h = (int)h;
+
+ if(fillrectrequest->color.alpha != 255)
+ {
+ temp = SDL_CreateRGBSurface(screen->flags, rect.w, rect.h, screen->format->BitsPerPixel,
+ screen->format->Rmask,
+ screen->format->Gmask,
+ screen->format->Bmask,
+ screen->format->Amask);
+
+
+ src.x = 0;
+ src.y = 0;
+ src.w = rect.w;
+ src.h = rect.h;
+
+ SDL_FillRect(temp, &src, SDL_MapRGB(screen->format,
+ fillrectrequest->color.red, fillrectrequest->color.green,
+ fillrectrequest->color.blue));
+
+ SDL_SetAlpha(temp, SDL_SRCALPHA, fillrectrequest->color.alpha);
+
+ SDL_BlitSurface(temp,0,screen,&rect);
+
+ SDL_FreeSurface(temp);
+ }
+ else
+ SDL_FillRect(screen, &rect, SDL_MapRGB(screen->format,
+ fillrectrequest->color.red, fillrectrequest->color.green,
+ fillrectrequest->color.blue));
+
+#ifndef NOOPENGL
+
+ }
+#endif
+
+ delete fillrectrequest;
+}
+
+void
+DrawingContext::do_drawing()
+{
+ std::stable_sort(drawingrequests.begin(), drawingrequests.end());
+
+ for(DrawingRequests::iterator i = drawingrequests.begin();
+ i != drawingrequests.end(); ++i) {
+ switch(i->type) {
+ case SURFACE:
+ {
+ const Surface* surface = (const Surface*) i->request_data;
+ surface->impl->draw(i->pos.x, i->pos.y, 255, i->drawing_effect);
+ break;
+ }
+ case SURFACE_PART:
+ draw_surface_part(*i);
+ break;
+ case GRADIENT:
+ draw_gradient(*i);
+ break;
+ case TEXT:
+ draw_text(*i);
+ break;
+ case FILLRECT:
+ draw_filled_rect(*i);
+ break;
+ }
+ }
+
+ // update screen
+ if(use_gl)
+ SDL_GL_SwapBuffers();
+ else
+ SDL_Flip(screen);
+
+ drawingrequests.clear();
+}
+
+void
+DrawingContext::push_transform()
+{
+ transformstack.push_back(transform);
+}
+
+void
+DrawingContext::pop_transform()
+{
+ assert(!transformstack.empty());
+
+ transform = transformstack.back();
+ transformstack.pop_back();
+}
+
+void
+DrawingContext::set_drawing_effect(int effect)
+{
+ transform.draw_effect = effect;
+}
--- /dev/null
+// $Id$
+//
+// SuperTux - A Jump'n Run
+// Copyright (C) 2004 Matthias Braun <matze@braunis.de
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#ifndef SUPERTUX_DRAWINGCONTEXT_H
+#define SUPERTUX_DRAWINGCONTEXT_H
+
+#include <vector>
+#include <string>
+
+#include "SDL.h"
+
+#include "math/vector.h"
+#include "video/screen.h"
+
+class Surface;
+class Font;
+
+// some constants for predefined layer values
+enum {
+ LAYER_BACKGROUND0 = -300,
+ LAYER_BACKGROUND1 = -200,
+ LAYER_BACKGROUNDTILES = -100,
+ LAYER_TILES = 0,
+ LAYER_OBJECTS = 100,
+ LAYER_FOREGROUNDTILES = 200,
+ LAYER_FOREGROUND0 = 300,
+ LAYER_FOREGROUND1 = 400,
+ LAYER_GUI = 500
+};
+
+/**
+ * This class provides functions for drawing things on screen. It also
+ * maintains a stack of transforms that are applied to graphics.
+ */
+class DrawingContext
+{
+public:
+ DrawingContext();
+ ~DrawingContext();
+
+ /** Adds a drawing request for a surface into the request list */
+ void draw_surface(const Surface* surface, const Vector& position, int layer,
+ Uint32 drawing_effect = NONE_EFFECT);
+ /** Adds a drawing request for part of a surface */
+ void draw_surface_part(const Surface* surface, const Vector& source,
+ const Vector& size, const Vector& dest, int layer,
+ Uint32 drawing_effect = NONE_EFFECT);
+ /** draws a text */
+ void draw_text(Font* font, const std::string& text, const Vector& position,
+ int layer, Uint32 drawing_effect = NONE_EFFECT);
+ /** draws aligned text */
+ void draw_text_center(Font* font, const std::string& text,
+ const Vector& position, int layer, Uint32 drawing_effect = NONE_EFFECT);
+ /** draws a color gradient onto the whole screen */
+ void draw_gradient(Color from, Color to, int layer);
+ /** fills a rectangle */
+ void draw_filled_rect(const Vector& topleft, const Vector& size,
+ Color color, int layer);
+
+ /** Processes all pending drawing requests and flushes the list */
+ void do_drawing();
+
+ const Vector& get_translation() const
+ { return transform.translation; }
+ void set_translation(const Vector& newtranslation)
+ { transform.translation = newtranslation; }
+
+ void push_transform();
+ void pop_transform();
+
+ /** apply that effect in the next draws (effects are listed on surface.h) */
+ void set_drawing_effect(int effect);
+
+private:
+ class Transform
+ {
+ public:
+ Vector translation; // only translation for now...
+
+ Vector apply(const Vector& v) const
+ {
+ return v - translation;
+ }
+
+ int draw_effect;
+ };
+
+ /// the transform stack
+ std::vector<Transform> transformstack;
+ /// the currently active transform
+ Transform transform;
+
+ enum RequestType
+ {
+ SURFACE, SURFACE_PART, TEXT, GRADIENT, FILLRECT
+ };
+
+ struct SurfacePartRequest
+ {
+ const Surface* surface;
+ Vector source, size;
+ };
+
+ struct TextRequest
+ {
+ Font* font;
+ std::string text;
+ };
+
+ struct GradientRequest
+ {
+ Color top, bottom;
+ Vector size;
+ };
+
+ struct FillRectRequest
+ {
+ Color color;
+ Vector size;
+ };
+
+ struct DrawingRequest
+ {
+ int layer;
+ Uint32 drawing_effect;
+
+ RequestType type;
+ Vector pos;
+
+ void* request_data;
+
+ bool operator<(const DrawingRequest& other) const
+ {
+ return layer < other.layer;
+ }
+ };
+
+ void draw_surface_part(DrawingRequest& request);
+ void draw_text(DrawingRequest& request);
+ void draw_gradient(DrawingRequest& request);
+ void draw_filled_rect(DrawingRequest& request);
+
+ typedef std::vector<DrawingRequest> DrawingRequests;
+ DrawingRequests drawingrequests;
+};
+
+#endif /*SUPERTUX_DRAWINGCONTEXT_H*/
+
--- /dev/null
+// $Id$
+//
+// SuperTux
+// Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#include <cstdlib>
+#include <cstring>
+
+#include "app/globals.h"
+#include "video/screen.h"
+#include "video/font.h"
+#include "video/drawing_context.h"
+#include "utils/lispreader.h"
+
+Font::Font(const std::string& file, FontType ntype, int nw, int nh,
+ int nshadowsize)
+ : chars(0), shadow_chars(0), type(ntype), w(nw), h(nh),
+ shadowsize(nshadowsize)
+{
+ chars = new Surface(file, true);
+
+ switch(type) {
+ case TEXT:
+ first_char = 32;
+ break;
+ case NUM:
+ first_char = 48;
+ break;
+ }
+ last_char = first_char + (chars->h / h) * 16;
+ if(last_char > 127) // we have left out some control chars at 128-159
+ last_char += 32;
+
+ // Load shadow font.
+ if(shadowsize > 0) {
+ SDL_Surface* conv = SDL_DisplayFormatAlpha(chars->impl->get_sdl_surface());
+ int pixels = conv->w * conv->h;
+ SDL_LockSurface(conv);
+ for(int i = 0; i < pixels; ++i) {
+ Uint32 *p = (Uint32 *)conv->pixels + i;
+ *p = *p & conv->format->Amask;
+ }
+ SDL_UnlockSurface(conv);
+ SDL_SetAlpha(conv, SDL_SRCALPHA, 128);
+ shadow_chars = new Surface(conv, true);
+ SDL_FreeSurface(conv);
+ }
+}
+
+Font::~Font()
+{
+ delete chars;
+ delete shadow_chars;
+}
+
+float
+Font::get_height() const
+{
+ return h;
+}
+
+float
+Font::get_text_width(const std::string& text) const
+{
+ return text.size() * w;
+}
+
+void
+Font::draw(const std::string& text, const Vector& pos, Uint32 drawing_effect)
+{
+ if(shadowsize > 0)
+ draw_chars(shadow_chars, text, pos + Vector(shadowsize, shadowsize),
+ drawing_effect);
+
+ draw_chars(chars, text, pos, drawing_effect);
+}
+
+void
+Font::draw_chars(Surface* pchars, const std::string& text, const Vector& pos,
+ Uint32 drawing_effect)
+{
+ SurfaceImpl* impl = pchars->impl;
+
+ Vector p = pos;
+ for(size_t i = 0; i < text.size(); ++i)
+ {
+ int c = (unsigned char) text[i];
+ if(c > 127) // correct for the 32 controlchars at 128-159
+ c -= 32;
+ // a non-printable character?
+ if(c == '\n') {
+ p.x = pos.x;
+ p.y += h + 2;
+ continue;
+ }
+ if(c == ' ' || c < first_char || c > last_char) {
+ p.x += w;
+ continue;
+ }
+
+ int index = c - first_char;
+ int source_x = (index % 16) * w;
+ int source_y = (index / 16) * h;
+
+ impl->draw_part(source_x, source_y, p.x, p.y, w, h, 255, drawing_effect);
+ p.x += w;
+ }
+}
+
+/* --- SCROLL TEXT FUNCTION --- */
+
+#define MAX_VEL 10
+#define SPEED_INC 0.01
+#define SCROLL 60
+#define ITEMS_SPACE 4
+
+void display_text_file(const std::string& file, float scroll_speed)
+{
+ std::string text;
+ std::vector<std::string> names;
+
+ LispReader* reader = LispReader::load(datadir + "/" + file, "supertux-text");
+
+ if(!reader)
+ {
+ std::cerr << "Error: Could not open text. Ignoring...\n";
+ return;
+ }
+
+ reader->read_string("text", text, true);
+ std::string background_file;
+ reader->read_string("background", background_file, true);
+ delete reader;
+
+ // Split text string lines into a vector
+ names.clear();
+ unsigned int i, l;
+ i = 0;
+ while(true)
+ {
+ l = text.find("\n", i);
+
+ if(l == std::string::npos)
+ {
+ char temp[1024];
+ temp[text.copy(temp, text.size() - i, i)] = '\0';
+ names.push_back(temp);
+ break;
+ }
+
+ char temp[1024];
+ temp[text.copy(temp, l-i, i)] = '\0';
+ names.push_back(temp);
+
+ i = l+1;
+ }
+
+ // load background image
+ Surface* background = new Surface(datadir + "/images/background/" + background_file, false);
+
+ int done = 0;
+ float scroll = 0;
+ float speed = scroll_speed / 50;
+
+ DrawingContext context;
+ SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
+
+ Uint32 lastticks = SDL_GetTicks();
+ while(!done)
+ {
+ /* in case of input, exit */
+ SDL_Event event;
+ while(SDL_PollEvent(&event))
+ switch(event.type)
+ {
+ case SDL_KEYDOWN:
+ switch(event.key.keysym.sym)
+ {
+ case SDLK_UP:
+ speed -= SPEED_INC;
+ break;
+ case SDLK_DOWN:
+ speed += SPEED_INC;
+ break;
+ case SDLK_SPACE:
+ case SDLK_RETURN:
+ if(speed >= 0)
+ scroll += SCROLL;
+ break;
+ case SDLK_ESCAPE:
+ done = 1;
+ break;
+ default:
+ break;
+ }
+ break;
+ case SDL_QUIT:
+ done = 1;
+ break;
+ default:
+ break;
+ }
+
+ if(speed > MAX_VEL)
+ speed = MAX_VEL;
+ else if(speed < -MAX_VEL)
+ speed = -MAX_VEL;
+
+ /* draw the credits */
+ context.draw_surface(background, Vector(0,0), 0);
+
+ float y = 0;
+ for(size_t i = 0; i < names.size(); i++) {
+ if(names[i].size() == 0) {
+ y += white_text->get_height() + ITEMS_SPACE;
+ continue;
+ }
+
+ Font* font = 0;
+ switch(names[i][0])
+ {
+ case ' ': font = white_small_text; break;
+ case '\t': font = white_text; break;
+ case '-': font = white_big_text; break;
+ case '*': font = blue_text; break;
+ default: font = blue_text; break;
+ }
+
+ context.draw_text_center(font,
+ names[i].substr(1, names[i].size()-1),
+ Vector(0, screen->h + y - scroll), LAYER_FOREGROUND1);
+ y += font->get_height() + ITEMS_SPACE;
+ }
+
+ context.do_drawing();
+
+ if(screen->h+y-scroll < 0 && 20+screen->h+y-scroll < 0)
+ done = 1;
+
+ Uint32 ticks = SDL_GetTicks();
+ scroll += speed * (ticks - lastticks);
+ lastticks = ticks;
+ if(scroll < 0)
+ scroll = 0;
+
+ SDL_Delay(10);
+ }
+
+ SDL_EnableKeyRepeat(0, 0); // disables key repeating
+ delete background;
+}
+
--- /dev/null
+// $Id$
+//
+// SuperTux
+// Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#ifndef SUPERTUX_FONT_H
+#define SUPERTUX_FONT_H
+
+#include <string>
+
+#include "video/surface.h"
+#include "math/vector.h"
+
+/** Reads a text file (using LispReader, so it as to be in its formatting)
+ and displays it in a StarTrek fashion */
+void display_text_file(const std::string& file, float scroll_speed);
+
+/* Text type */
+class Font
+{
+public:
+ /* Kinds of texts. */
+ enum FontType {
+ TEXT, // images for all characters
+ NUM // only images for numbers
+ };
+
+ Font(const std::string& file, FontType type, int w, int h, int shadowsize=2);
+ ~Font();
+
+ /** returns the height of the font */
+ float get_height() const;
+ /** returns the width of a given text. (Note that I won't add a normal
+ * get_width function here, as we might switch to variable width fonts in the
+ * future.
+ */
+ float get_text_width(const std::string& text) const;
+
+private:
+ friend class DrawingContext;
+
+ void draw(const std::string& text, const Vector& pos,
+ Uint32 drawing_effect = NONE_EFFECT);
+ void draw_chars(Surface* pchars, const std::string& text,
+ const Vector& position, Uint32 drawing_effect);
+
+ Surface* chars;
+ Surface* shadow_chars;
+ FontType type;
+ int w;
+ int h;
+ int shadowsize;
+
+ /// the number of the first character that is represented in the font
+ int first_char;
+ /// the number of the last character that is represented in the font
+ int last_char;
+};
+
+#endif /*SUPERTUX_FONT_H*/
+
--- /dev/null
+// $Id$
+//
+// SuperTux - A Jump'n Run
+// Copyright (C) 2000 Bill Kendrick <bill@newbreedsoftware.com>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#include <iostream>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <cerrno>
+
+#include <unistd.h>
+
+#include "SDL.h"
+#include "SDL_image.h"
+
+#ifndef WIN32
+#include <sys/types.h>
+#include <ctype.h>
+#endif
+
+#include "app/globals.h"
+#include "video/screen.h"
+#include "video/drawing_context.h"
+#include "special/base.h"
+
+/* 'Stolen' from the SDL documentation.
+ * Set the pixel at (x, y) to the given value
+ * NOTE: The surface must be locked before calling this!
+ */
+void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
+{
+ int bpp = surface->format->BytesPerPixel;
+ /* Here p is the address to the pixel we want to set */
+ Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
+
+ switch(bpp)
+ {
+ case 1:
+ *p = pixel;
+ break;
+
+ case 2:
+ *(Uint16 *)p = pixel;
+ break;
+
+ case 3:
+ if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
+ {
+ p[0] = (pixel >> 16) & 0xff;
+ p[1] = (pixel >> 8) & 0xff;
+ p[2] = pixel & 0xff;
+ }
+ else
+ {
+ p[0] = pixel & 0xff;
+ p[1] = (pixel >> 8) & 0xff;
+ p[2] = (pixel >> 16) & 0xff;
+ }
+ break;
+
+ case 4:
+ *(Uint32 *)p = pixel;
+ break;
+ }
+}
+
+/* Draw a single pixel on the screen. */
+void drawpixel(int x, int y, Uint32 pixel)
+{
+ /* Lock the screen for direct access to the pixels */
+ if ( SDL_MUSTLOCK(screen) )
+ {
+ if ( SDL_LockSurface(screen) < 0 )
+ {
+ fprintf(stderr, "Can't lock screen: %s\n", SDL_GetError());
+ return;
+ }
+ }
+
+ if(!(x < 0 || y < 0 || x > screen->w || y > screen->h))
+ putpixel(screen, x, y, pixel);
+
+ if ( SDL_MUSTLOCK(screen) )
+ {
+ SDL_UnlockSurface(screen);
+ }
+ /* Update just the part of the display that we've changed */
+ SDL_UpdateRect(screen, x, y, 1, 1);
+}
+
+/* --- FILL A RECT --- */
+
+void fillrect(float x, float y, float w, float h, int r, int g, int b, int a)
+{
+if(w < 0)
+ {
+ x += w;
+ w = -w;
+ }
+if(h < 0)
+ {
+ y += h;
+ h = -h;
+ }
+
+#ifndef NOOPENGL
+ if(use_gl)
+ {
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glColor4ub(r, g, b,a);
+
+ glBegin(GL_POLYGON);
+ glVertex2f(x, y);
+ glVertex2f(x+w, y);
+ glVertex2f(x+w, y+h);
+ glVertex2f(x, y+h);
+ glEnd();
+ glDisable(GL_BLEND);
+ }
+ else
+ {
+#endif
+ SDL_Rect src, rect;
+ SDL_Surface *temp = NULL;
+
+ rect.x = (int)x;
+ rect.y = (int)y;
+ rect.w = (int)w;
+ rect.h = (int)h;
+
+ if(a != 255)
+ {
+ temp = SDL_CreateRGBSurface(screen->flags, rect.w, rect.h, screen->format->BitsPerPixel,
+ screen->format->Rmask,
+ screen->format->Gmask,
+ screen->format->Bmask,
+ screen->format->Amask);
+
+
+ src.x = 0;
+ src.y = 0;
+ src.w = rect.w;
+ src.h = rect.h;
+
+ SDL_FillRect(temp, &src, SDL_MapRGB(screen->format, r, g, b));
+
+ SDL_SetAlpha(temp, SDL_SRCALPHA, a);
+
+ SDL_BlitSurface(temp,0,screen,&rect);
+
+ SDL_FreeSurface(temp);
+ }
+ else
+ SDL_FillRect(screen, &rect, SDL_MapRGB(screen->format, r, g, b));
+
+#ifndef NOOPENGL
+
+ }
+#endif
+}
+
+/* Needed for line calculations */
+#define SGN(x) ((x)>0 ? 1 : ((x)==0 ? 0:(-1)))
+#define ABS(x) ((x)>0 ? (x) : (-x))
+
+void
+draw_line(float x1, float y1, float x2, float y2, int r, int g, int b, int a)
+{
+#ifndef NOOPENGL
+ if(use_gl)
+ {
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glColor4ub(r, g, b,a);
+
+ glBegin(GL_LINES);
+ glVertex2f(x1, y1);
+ glVertex2f(x2, y2);
+ glEnd();
+ glDisable(GL_BLEND);
+ }
+ else
+ {
+#endif
+ /* Basic unantialiased Bresenham line algorithm */
+ int lg_delta, sh_delta, cycle, lg_step, sh_step;
+ Uint32 color = SDL_MapRGBA(screen->format, r, g, b, a);
+
+ lg_delta = (int)(x2 - x1);
+ sh_delta = (int)(y2 - y1);
+ lg_step = SGN(lg_delta);
+ lg_delta = ABS(lg_delta);
+ sh_step = SGN(sh_delta);
+ sh_delta = ABS(sh_delta);
+ if (sh_delta < lg_delta)
+ {
+ cycle = lg_delta >> 1;
+ while (x1 != x2)
+ {
+ drawpixel((int)x1, (int)y1, color);
+ cycle += sh_delta;
+ if (cycle > lg_delta)
+ {
+ cycle -= lg_delta;
+ y1 += sh_step;
+ }
+ x1 += lg_step;
+ }
+ drawpixel((int)x1, (int)y1, color);
+ }
+ cycle = sh_delta >> 1;
+ while (y1 != y2)
+ {
+ drawpixel((int)x1, (int)y1, color);
+ cycle += lg_delta;
+ if (cycle > sh_delta)
+ {
+ cycle -= sh_delta;
+ x1 += lg_step;
+ }
+ y1 += sh_step;
+ }
+ drawpixel((int)x1, (int)y1, color);
+#ifndef NOOPENGL
+
+ }
+#endif
+}
+
+#define LOOP_DELAY 20.0
+
+void fadeout(int fade_time)
+{
+ float alpha_inc = 256 / (fade_time / LOOP_DELAY);
+ float alpha = 256;
+
+ while(alpha > 0)
+ {
+ alpha -= alpha_inc;
+ fillrect(0, 0, screen->w, screen->h, 0,0,0, (int)alpha_inc); // left side
+
+ DrawingContext context; // ugly...
+ context.do_drawing();
+
+ SDL_Delay(int(LOOP_DELAY));
+ }
+
+ fillrect(0, 0, screen->w, screen->h, 0, 0, 0, 255);
+
+ DrawingContext context;
+ context.draw_text_center(white_text, "Loading...",
+ Vector(0, screen->h/2), LAYER_FOREGROUND1);
+ context.do_drawing();
+}
+
+void shrink_fade(const Vector& point, int fade_time)
+{
+ float left_inc = point.x / ((float)fade_time / LOOP_DELAY);
+ float right_inc = (screen->w - point.x) / ((float)fade_time / LOOP_DELAY);
+ float up_inc = point.y / ((float)fade_time / LOOP_DELAY);
+ float down_inc = (screen->h - point.y) / ((float)fade_time / LOOP_DELAY);
+
+ float left_cor = 0, right_cor = 0, up_cor = 0, down_cor = 0;
+
+ while(left_cor < point.x && right_cor < screen->w - point.x &&
+ up_cor < point.y && down_cor < screen->h - point.y)
+ {
+ left_cor += left_inc;
+ right_cor += right_inc;
+ up_cor += up_inc;
+ down_cor += down_inc;
+
+ fillrect(0, 0, left_cor, screen->h, 0,0,0); // left side
+ fillrect(screen->w - right_cor, 0, right_cor, screen->h, 0,0,0); // right side
+ fillrect(0, 0, screen->w, up_cor, 0,0,0); // up side
+ fillrect(0, screen->h - down_cor, screen->w, down_cor+1, 0,0,0); // down side
+ DrawingContext context; // ugly...
+ context.do_drawing();
+
+ SDL_Delay(int(LOOP_DELAY));
+ }
+}
+
--- /dev/null
+// $Id$
+//
+// SuperTux - A Jump'n Run
+// Copyright (C) 2000 Bill Kendrick <bill@newbreedsoftware.com>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#ifndef SUPERTUX_SCREEN_H
+#define SUPERTUX_SCREEN_H
+
+#include <SDL.h>
+#ifndef NOOPENGL
+#include <SDL_opengl.h>
+#endif
+#include <iostream>
+class Color
+{
+public:
+ Color()
+ : red(0), green(0), blue(0), alpha(255)
+ {}
+
+ Color(Uint8 red_, Uint8 green_, Uint8 blue_, Uint8 alpha_ = 255)
+ : red(red_), green(green_), blue(blue_), alpha(alpha_)
+ {}
+
+ Color(const Color& o)
+ : red(o.red), green(o.green), blue(o.blue), alpha(o.alpha)
+ { }
+
+ bool operator==(const Color& o)
+ { if(red == o.red && green == o.green &&
+ blue == o.blue && alpha == o.alpha)
+ return true;
+ return false; }
+
+ Uint8 red, green, blue, alpha;
+};
+
+#include "video/surface.h"
+
+class Vector;
+
+void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel);
+void drawpixel(int x, int y, Uint32 pixel);
+void fillrect(float x, float y, float w, float h, int r, int g, int b, int a = 255);
+void draw_line(float x1, float y1, float x2, int r, int g, int b, int a = 255);
+
+void fadeout(int fade_time);
+void shrink_fade(const Vector& point, int fade_time);
+
+#endif /*SUPERTUX_SCREEN_H*/
--- /dev/null
+// $Id$
+//
+// SuperTux
+// Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#include <cassert>
+#include <iostream>
+#include <algorithm>
+
+#include "SDL.h"
+#include "SDL_image.h"
+
+#include "video/surface.h"
+#include "app/globals.h"
+#include "app/setup.h"
+
+Surface::Surfaces Surface::surfaces;
+
+SurfaceData::SurfaceData(SDL_Surface* temp, bool use_alpha_)
+ : type(SURFACE), surface(0), use_alpha(use_alpha_)
+{
+ // Copy the given surface and make sure that it is not stored in
+ // video memory
+ surface = SDL_CreateRGBSurface(temp->flags & (~SDL_HWSURFACE),
+ temp->w, temp->h,
+ temp->format->BitsPerPixel,
+ temp->format->Rmask,
+ temp->format->Gmask,
+ temp->format->Bmask,
+ temp->format->Amask);
+ if(!surface)
+ st_abort("No memory left.", "");
+ SDL_SetAlpha(temp,0,0);
+ SDL_BlitSurface(temp, NULL, surface, NULL);
+}
+
+SurfaceData::SurfaceData(const std::string& file_, bool use_alpha_)
+ : type(LOAD), surface(0), file(file_), use_alpha(use_alpha_)
+{}
+
+SurfaceData::SurfaceData(const std::string& file_, int x_, int y_, int w_, int h_, bool use_alpha_)
+ : type(LOAD_PART), surface(0), file(file_), use_alpha(use_alpha_),
+ x(x_), y(y_), w(w_), h(h_)
+{}
+
+SurfaceData::SurfaceData(Color top_gradient_, Color bottom_gradient_, int w_, int h_)
+ : type(GRADIENT), surface(0), use_alpha(false), w(w_), h(h_)
+{
+top_gradient = top_gradient_;
+bottom_gradient = bottom_gradient_;
+}
+
+
+SurfaceData::~SurfaceData()
+{
+ SDL_FreeSurface(surface);
+}
+
+SurfaceImpl*
+SurfaceData::create()
+{
+#ifndef NOOPENGL
+ if (use_gl)
+ return create_SurfaceOpenGL();
+ else
+ return create_SurfaceSDL();
+#else
+ return create_SurfaceSDL();
+#endif
+}
+
+SurfaceSDL*
+SurfaceData::create_SurfaceSDL()
+{
+ switch(type)
+ {
+ case LOAD:
+ return new SurfaceSDL(file, use_alpha);
+ case LOAD_PART:
+ return new SurfaceSDL(file, x, y, w, h, use_alpha);
+ case SURFACE:
+ return new SurfaceSDL(surface, use_alpha);
+ case GRADIENT:
+ return new SurfaceSDL(top_gradient, bottom_gradient, w, h);
+ }
+ assert(0);
+}
+
+SurfaceOpenGL*
+SurfaceData::create_SurfaceOpenGL()
+{
+#ifndef NOOPENGL
+ switch(type)
+ {
+ case LOAD:
+ return new SurfaceOpenGL(file, use_alpha);
+ case LOAD_PART:
+ return new SurfaceOpenGL(file, x, y, w, h, use_alpha);
+ case SURFACE:
+ return new SurfaceOpenGL(surface, use_alpha);
+ case GRADIENT:
+ return new SurfaceOpenGL(top_gradient, bottom_gradient, w, h);
+ }
+#endif
+ assert(0);
+}
+
+#ifndef NOOPENGL
+/* Quick utility function for texture creation */
+static int power_of_two(int input)
+{
+ int value = 1;
+
+ while ( value < input )
+ {
+ value <<= 1;
+ }
+ return value;
+}
+#endif
+
+Surface::Surface(SDL_Surface* surf, bool use_alpha)
+ : data(surf, use_alpha), w(0), h(0)
+{
+ impl = data.create();
+ if (impl)
+ {
+ w = impl->w;
+ h = impl->h;
+ }
+ surfaces.push_back(this);
+}
+
+Surface::Surface(const std::string& file, bool use_alpha)
+ : data(file, use_alpha), w(0), h(0)
+{
+ impl = data.create();
+ if (impl)
+ {
+ w = impl->w;
+ h = impl->h;
+ }
+ surfaces.push_back(this);
+}
+
+Surface::Surface(const std::string& file, int x, int y, int w, int h, bool use_alpha)
+ : data(file, x, y, w, h, use_alpha), w(0), h(0)
+{
+ impl = data.create();
+ if (impl)
+ {
+ w = impl->w;
+ h = impl->h;
+ }
+ surfaces.push_back(this);
+}
+
+Surface::Surface(Color top_background, Color bottom_background, int w_, int h_)
+ : data(top_background, bottom_background, 0, 0), w(0), h(0)
+{
+ // FIXME: Gradient surfaces currently don't accept width/height
+ // If nonzero values are passed to data.create(), supertux
+ // crashes.
+ impl = data.create();
+ if (impl)
+ {
+ w = impl->w;
+ h = impl->h;
+ }
+ surfaces.push_back(this);
+}
+
+void
+Surface::reload()
+{
+ delete impl;
+ impl = data.create();
+ if (impl)
+ {
+ w = impl->w;
+ h = impl->h;
+ }
+}
+
+Surface::~Surface()
+{
+#ifdef DEBUG
+ bool found = false;
+ for(std::list<Surface*>::iterator i = surfaces.begin(); i != surfaces.end();
+ ++i)
+ {
+ if(*i == this)
+ {
+ found = true; break;
+ }
+ }
+ if(!found)
+ printf("Error: Surface freed twice!!!\n");
+#endif
+ surfaces.remove(this);
+ delete impl;
+}
+
+void
+Surface::reload_all()
+{
+ for(Surfaces::iterator i = surfaces.begin(); i != surfaces.end(); ++i)
+ {
+ (*i)->reload();
+ }
+}
+
+void
+Surface::debug_check()
+{
+ for(Surfaces::iterator i = surfaces.begin(); i != surfaces.end(); ++i)
+ {
+ printf("Surface not freed: T:%d F:%s.\n", (*i)->data.type,
+ (*i)->data.file.c_str());
+ }
+}
+
+void
+Surface::resize(int w_, int h_)
+{
+ if (impl)
+ {
+ w = w_;
+ h = h_;
+ if (impl->resize(w_,h_) == -2)
+ reload();
+ }
+}
+
+SDL_Surface*
+sdl_surface_part_from_file(const std::string& file, int x, int y, int w, int h, bool use_alpha)
+{
+ SDL_Rect src;
+ SDL_Surface * sdl_surface;
+ SDL_Surface * temp;
+ SDL_Surface * conv;
+
+ temp = IMG_Load(file.c_str());
+
+ if (temp == NULL)
+ st_abort("Can't load", file);
+
+ /* Set source rectangle for conv: */
+
+ src.x = x;
+ src.y = y;
+ src.w = w;
+ src.h = h;
+
+ conv = SDL_CreateRGBSurface(temp->flags, w, h, temp->format->BitsPerPixel,
+ temp->format->Rmask,
+ temp->format->Gmask,
+ temp->format->Bmask,
+ temp->format->Amask);
+
+ /* #if SDL_BYTEORDER == SDL_BIG_ENDIAN
+ 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);
+ #else
+
+ 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
+ #endif*/
+
+ SDL_SetAlpha(temp,0,0);
+
+ SDL_BlitSurface(temp, &src, conv, NULL);
+ if(use_alpha == false && !use_gl)
+ sdl_surface = SDL_DisplayFormat(conv);
+ else
+ sdl_surface = SDL_DisplayFormatAlpha(conv);
+
+ if (sdl_surface == NULL)
+ st_abort("Can't covert to display format", file);
+
+ if (use_alpha == false && !use_gl)
+ SDL_SetAlpha(sdl_surface, 0, 0);
+
+ SDL_FreeSurface(temp);
+ SDL_FreeSurface(conv);
+
+ return sdl_surface;
+}
+
+SDL_Surface*
+sdl_surface_from_file(const std::string& file, bool use_alpha)
+{
+ SDL_Surface* sdl_surface;
+ SDL_Surface* temp;
+
+ temp = IMG_Load(file.c_str());
+
+ if (temp == NULL)
+ st_abort("Can't load", file);
+
+ if(use_alpha == false && !use_gl)
+ sdl_surface = SDL_DisplayFormat(temp);
+ else
+ sdl_surface = SDL_DisplayFormatAlpha(temp);
+
+ if (sdl_surface == NULL)
+ st_abort("Can't covert to display format", file);
+
+ if (use_alpha == false && !use_gl)
+ SDL_SetAlpha(sdl_surface, 0, 0);
+
+ SDL_FreeSurface(temp);
+
+ return sdl_surface;
+}
+
+SDL_Surface*
+sdl_surface_from_sdl_surface(SDL_Surface* sdl_surf, bool use_alpha)
+{
+ SDL_Surface* sdl_surface;
+ Uint32 saved_flags;
+ Uint8 saved_alpha;
+
+ /* Save the alpha blending attributes */
+ saved_flags = sdl_surf->flags&(SDL_SRCALPHA|SDL_RLEACCELOK);
+ saved_alpha = sdl_surf->format->alpha;
+ if ( (saved_flags & SDL_SRCALPHA)
+ == SDL_SRCALPHA )
+ {
+ SDL_SetAlpha(sdl_surf, 0, 0);
+ }
+
+ if(use_alpha == false && !use_gl)
+ sdl_surface = SDL_DisplayFormat(sdl_surf);
+ else
+ sdl_surface = SDL_DisplayFormatAlpha(sdl_surf);
+
+ /* Restore the alpha blending attributes */
+ if ( (saved_flags & SDL_SRCALPHA)
+ == SDL_SRCALPHA )
+ {
+ SDL_SetAlpha(sdl_surface, saved_flags, saved_alpha);
+ }
+
+ if (sdl_surface == NULL)
+ st_abort("Can't covert to display format", "SURFACE");
+
+ if (use_alpha == false && !use_gl)
+ SDL_SetAlpha(sdl_surface, 0, 0);
+
+ return sdl_surface;
+}
+
+SDL_Surface*
+sdl_surface_from_gradient(Color top, Color bottom, int w, int h)
+{
+ SDL_Surface* sdl_surface;
+
+ sdl_surface = SDL_CreateRGBSurface(screen->flags, w, h,
+ screen->format->BitsPerPixel, screen->format->Rmask,
+ screen->format->Gmask, screen->format->Bmask, screen->format->Amask);
+
+ if(sdl_surface == NULL)
+ st_abort("Cannot create surface for the gradient", "SURFACE");
+
+ if(top == bottom)
+ {
+ SDL_FillRect(sdl_surface, NULL, SDL_MapRGB(sdl_surface->format,
+ top.red, top.green, top.blue));
+ }
+ else
+ {
+ float redstep = (float(bottom.red)-float(top.red)) / float(h);
+ float greenstep = (float(bottom.green)-float(top.green)) / float(h);
+ float bluestep = (float(bottom.blue) - float(top.blue)) / float(h);
+
+ SDL_Rect rect;
+ rect.x = 0;
+ rect.w = w;
+ rect.h = 1;
+ for(float y = 0; y < h; y++)
+ {
+ rect.y = (int)y;
+ SDL_FillRect(sdl_surface, &rect, SDL_MapRGB(sdl_surface->format,
+ int(float(top.red) + redstep * y),
+ int(float(top.green) + greenstep * y),
+ int(float(top.blue) + bluestep * y)));
+ }
+ }
+
+ return sdl_surface;
+}
+
+//---------------------------------------------------------------------------
+
+SurfaceImpl::SurfaceImpl()
+{}
+
+SurfaceImpl::~SurfaceImpl()
+{
+ SDL_FreeSurface(sdl_surface);
+}
+
+SDL_Surface* SurfaceImpl::get_sdl_surface() const
+{
+ return sdl_surface;
+}
+
+int SurfaceImpl::resize(int w_, int h_)
+{
+ w = w_;
+ h = h_;
+ SDL_Rect dest;
+ dest.x = 0;
+ dest.y = 0;
+ dest.w = w;
+ dest.h = h;
+ int ret = SDL_SoftStretch(sdl_surface, NULL,
+ sdl_surface, &dest);
+ return ret;
+}
+
+#ifndef NOOPENGL
+SurfaceOpenGL::SurfaceOpenGL(SDL_Surface* surf, bool use_alpha)
+{
+ sdl_surface = sdl_surface_from_sdl_surface(surf, use_alpha);
+ create_gl(sdl_surface,&gl_texture);
+
+ w = sdl_surface->w;
+ h = sdl_surface->h;
+}
+
+SurfaceOpenGL::SurfaceOpenGL(const std::string& file, bool use_alpha)
+{
+ sdl_surface = sdl_surface_from_file(file, use_alpha);
+ create_gl(sdl_surface,&gl_texture);
+
+ w = sdl_surface->w;
+ h = sdl_surface->h;
+}
+
+SurfaceOpenGL::SurfaceOpenGL(const std::string& file_, int x_, int y_, int w_, int h_, bool use_alpha_)
+{
+ sdl_surface = sdl_surface_part_from_file(file_,x_,y_,w_,h_,use_alpha_);
+
+ create_gl(sdl_surface, &gl_texture);
+
+ w = sdl_surface->w;
+ h = sdl_surface->h;
+}
+
+SurfaceOpenGL::SurfaceOpenGL(Color top_gradient, Color bottom_gradient, int w, int h)
+{
+ sdl_surface = sdl_surface_from_gradient(top_gradient, bottom_gradient, w, h);
+ create_gl(sdl_surface, &gl_texture);
+
+ w = sdl_surface->w;
+ h = sdl_surface->h;
+}
+
+SurfaceOpenGL::~SurfaceOpenGL()
+{
+ glDeleteTextures(1, &gl_texture);
+}
+
+void
+SurfaceOpenGL::create_gl(SDL_Surface * surf, GLuint * tex)
+{
+ Uint32 saved_flags;
+ Uint8 saved_alpha;
+ int w, h;
+ SDL_Surface *conv;
+
+ w = power_of_two(surf->w);
+ h = power_of_two(surf->h),
+
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+ conv = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, surf->format->BitsPerPixel,
+ 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);
+#else
+ conv = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, surf->format->BitsPerPixel,
+ 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
+#endif
+
+ /* Save the alpha blending attributes */
+ saved_flags = surf->flags&(SDL_SRCALPHA|SDL_RLEACCELOK);
+ saved_alpha = surf->format->alpha;
+ if ( (saved_flags & SDL_SRCALPHA)
+ == SDL_SRCALPHA )
+ {
+ SDL_SetAlpha(surf, 0, 0);
+ }
+
+ SDL_BlitSurface(surf, 0, conv, 0);
+
+ /* Restore the alpha blending attributes */
+ if ( (saved_flags & SDL_SRCALPHA)
+ == SDL_SRCALPHA )
+ {
+ SDL_SetAlpha(surf, saved_flags, saved_alpha);
+ }
+
+ // We check all the pixels of the surface to figure out which
+ // internal format OpenGL should use for storing it, ie. if no alpha
+ // is present store in RGB instead of RGBA, this saves a few bytes
+ // of memory, but much more importantly it makes the game look
+ // *much* better in 16bit color mode
+ int internal_format = GL_RGB10_A2;
+ bool has_alpha = false;
+
+ unsigned char* buf = static_cast<unsigned char*>(conv->pixels);
+ for (int y = 0; y < surf->h; ++y)
+ for (int x = 0; x < surf->w; ++x)
+ {
+ if (buf[(conv->pitch*y + x*4) + 3] != 255)
+ {
+ has_alpha = true;
+ break;
+ }
+ }
+
+ if (!has_alpha)
+ {
+ internal_format = GL_RGB;
+ }
+
+ glGenTextures(1, &*tex);
+ glBindTexture(GL_TEXTURE_2D , *tex);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, conv->pitch / conv->format->BytesPerPixel);
+ glTexImage2D(GL_TEXTURE_2D, 0, internal_format, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, conv->pixels);
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+
+ SDL_FreeSurface(conv);
+}
+
+int
+SurfaceOpenGL::draw(float x, float y, Uint8 alpha, Uint32 effect)
+{
+ float pw = power_of_two(w);
+ float ph = power_of_two(h);
+
+ if(effect & SEMI_TRANSPARENT)
+ alpha = 128;
+
+ glEnable(GL_TEXTURE_2D);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ glColor4ub(alpha, alpha, alpha, alpha);
+
+ glBindTexture(GL_TEXTURE_2D, gl_texture);
+
+ glBegin(GL_QUADS);
+
+ if(effect & VERTICAL_FLIP)
+ {
+ glTexCoord2f(0, 0);
+ glVertex2f(x, (float)h+y);
+
+ glTexCoord2f((float)w / pw, 0);
+ glVertex2f((float)w+x, (float)h+y);
+
+ glTexCoord2f((float)w / pw, (float)h / ph);
+ glVertex2f((float)w+x, y);
+
+ glTexCoord2f(0, (float)h / ph);
+ glVertex2f(x, y);
+ }
+ else
+ {
+ glTexCoord2f(0, 0);
+ glVertex2f(x, y);
+
+ glTexCoord2f((float)w / pw, 0);
+ glVertex2f((float)w+x, y);
+
+ glTexCoord2f((float)w / pw, (float)h / ph);
+ glVertex2f((float)w+x, (float)h+y);
+
+ glTexCoord2f(0, (float)h / ph);
+ glVertex2f(x, (float)h+y);
+ }
+ glEnd();
+
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_BLEND);
+
+ return 0;
+}
+
+int
+SurfaceOpenGL::draw_part(float sx, float sy, float x, float y, float w, float h, Uint8 alpha, Uint32 effect)
+{
+ float pw = power_of_two(int(this->w));
+ float ph = power_of_two(int(this->h));
+
+ if(effect & SEMI_TRANSPARENT)
+ alpha = 128;
+
+ glBindTexture(GL_TEXTURE_2D, gl_texture);
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ glColor4ub(alpha, alpha, alpha, alpha);
+
+ glEnable(GL_TEXTURE_2D);
+
+
+ glBegin(GL_QUADS);
+
+ if(effect & VERTICAL_FLIP)
+ {
+ glTexCoord2f(sx / pw, sy / ph);
+ glVertex2f(x, y);
+
+ glTexCoord2f((float)(sx + w) / pw, sy / ph);
+ glVertex2f(w+x, y);
+
+ glTexCoord2f((sx+w) / pw, (sy+h) / ph);
+ glVertex2f(w +x, h+y);
+
+ glTexCoord2f(sx / pw, (float)(sy+h) / ph);
+ glVertex2f(x, h+y);
+ }
+ else
+ {
+ glTexCoord2f(sx / pw, (float)(sy+h) / ph);
+ glVertex2f(x, h+y);
+
+ glTexCoord2f((sx+w) / pw, (sy+h) / ph);
+ glVertex2f(w +x, h+y);
+
+ glTexCoord2f((float)(sx + w) / pw, sy / ph);
+ glVertex2f(w+x, y);
+
+ glTexCoord2f(sx / pw, sy / ph);
+ glVertex2f(x, y);
+ }
+
+ glEnd();
+
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_BLEND);
+
+ return 0;
+}
+
+#if 0
+int
+SurfaceOpenGL::draw_stretched(float x, float y, int sw, int sh, Uint8 alpha)
+{
+ float pw = power_of_two(int(this->w));
+ float ph = power_of_two(int(this->h));
+
+ glBindTexture(GL_TEXTURE_2D, gl_texture);
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ glColor4ub(alpha, alpha, alpha, alpha);
+
+ glEnable(GL_TEXTURE_2D);
+
+
+ glBegin(GL_QUADS);
+ glTexCoord2f(0, 0);
+ glVertex2f(x, y);
+ glTexCoord2f((float)w / pw, 0);
+ glVertex2f(sw+x, y);
+ glTexCoord2f((float)w / pw, (float)h / ph); glVertex2f((float)sw+x, (float)sh+y);
+ glVertex2f(sw +x, sh+y);
+ glTexCoord2f(0, (float)h / ph);
+ glVertex2f(x, sh+y);
+ glEnd();
+
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_BLEND);
+
+ return 0;
+}
+#endif
+
+#endif
+
+SurfaceSDL::SurfaceSDL(SDL_Surface* surf, bool use_alpha)
+{
+ sdl_surface = sdl_surface_from_sdl_surface(surf, use_alpha);
+ w = sdl_surface->w;
+ h = sdl_surface->h;
+}
+
+SurfaceSDL::SurfaceSDL(const std::string& file, bool use_alpha)
+{
+ sdl_surface = sdl_surface_from_file(file, use_alpha);
+ w = sdl_surface->w;
+ h = sdl_surface->h;
+}
+
+SurfaceSDL::SurfaceSDL(const std::string& file, int x, int y, int w, int h, bool use_alpha)
+{
+ sdl_surface = sdl_surface_part_from_file(file, x, y, w, h, use_alpha);
+ w = sdl_surface->w;
+ h = sdl_surface->h;
+}
+
+SurfaceSDL::SurfaceSDL(Color top_gradient, Color bottom_gradient, int w, int h)
+{
+ sdl_surface = sdl_surface_from_gradient(top_gradient, bottom_gradient, w, h);
+ w = sdl_surface->w;
+ h = sdl_surface->h;
+}
+
+int
+SurfaceSDL::draw(float x, float y, Uint8 alpha, Uint32 effect)
+{
+ SDL_Rect dest;
+
+ dest.x = (int)x;
+ dest.y = (int)y;
+ dest.w = w;
+ dest.h = h;
+
+ if(effect & SEMI_TRANSPARENT)
+ alpha = 128;
+
+ if(effect & VERTICAL_FLIP) // FIXME: feel free to replace this hack
+ {
+ for(float sy = 0; sy < h; sy++)
+ if(draw_part(0, sy, x, y+(h-sy), w, 1, alpha, NONE_EFFECT) == -2)
+ return -2;
+ return 0;
+ }
+
+ if(alpha != 255)
+ {
+ /* Create a Surface, make it using colorkey, blit surface into temp, apply alpha
+ to temp sur, blit the temp into the screen */
+ /* Note: this has to be done, since SDL doesn't allow to set alpha to surfaces that
+ already have an alpha mask yet... */
+
+ SDL_Surface* sdl_surface_copy = SDL_CreateRGBSurface (sdl_surface->flags,
+ sdl_surface->w, sdl_surface->h, sdl_surface->format->BitsPerPixel,
+ sdl_surface->format->Rmask, sdl_surface->format->Gmask,
+ sdl_surface->format->Bmask,
+ 0);
+ int colorkey = SDL_MapRGB(sdl_surface_copy->format, 255, 0, 255);
+ SDL_FillRect(sdl_surface_copy, NULL, colorkey);
+ SDL_SetColorKey(sdl_surface_copy, SDL_SRCCOLORKEY, colorkey);
+
+
+ SDL_BlitSurface(sdl_surface, NULL, sdl_surface_copy, NULL);
+ SDL_SetAlpha(sdl_surface_copy ,SDL_SRCALPHA,alpha);
+
+ int ret = SDL_BlitSurface(sdl_surface_copy, NULL, screen, &dest);
+
+ SDL_FreeSurface (sdl_surface_copy);
+ return ret;
+ }
+
+ int ret = SDL_BlitSurface(sdl_surface, NULL, screen, &dest);
+
+ return ret;
+}
+
+int
+SurfaceSDL::draw_part(float sx, float sy, float x, float y, float w, float h, Uint8 alpha, Uint32 effect)
+{
+ SDL_Rect src, dest;
+
+ src.x = (int)sx;
+ src.y = (int)sy;
+ src.w = (int)w;
+ src.h = (int)h;
+
+ dest.x = (int)x;
+ dest.y = (int)y;
+ dest.w = (int)w;
+ dest.h = (int)h;
+
+ if(effect & SEMI_TRANSPARENT)
+ alpha = 128;
+
+ if(effect & VERTICAL_FLIP) // FIXME: feel free to replace this hack
+ {
+ for(float sy_ = sy; sy_ < h; sy_++)
+ if(draw_part(sx, sy_, x, y+(h-sy_), w, 1, alpha, NONE_EFFECT) == -2)
+ return -2;
+ return 0;
+ }
+
+ if(alpha != 255)
+ {
+ /* Create a Surface, make it using colorkey, blit surface into temp, apply alpha
+ to temp sur, blit the temp into the screen */
+ /* Note: this has to be done, since SDL doesn't allow to set alpha to surfaces that
+ already have an alpha mask yet... */
+
+ SDL_Surface* sdl_surface_copy = SDL_CreateRGBSurface (sdl_surface->flags,
+ sdl_surface->w, sdl_surface->h, sdl_surface->format->BitsPerPixel,
+ sdl_surface->format->Rmask, sdl_surface->format->Gmask,
+ sdl_surface->format->Bmask,
+ 0);
+ int colorkey = SDL_MapRGB(sdl_surface_copy->format, 255, 0, 255);
+ SDL_FillRect(sdl_surface_copy, NULL, colorkey);
+ SDL_SetColorKey(sdl_surface_copy, SDL_SRCCOLORKEY, colorkey);
+
+
+ SDL_BlitSurface(sdl_surface, NULL, sdl_surface_copy, NULL);
+ SDL_SetAlpha(sdl_surface_copy ,SDL_SRCALPHA,alpha);
+
+ int ret = SDL_BlitSurface(sdl_surface_copy, NULL, screen, &dest);
+
+ SDL_FreeSurface (sdl_surface_copy);
+ return ret;
+ }
+
+ int ret = SDL_BlitSurface(sdl_surface, &src, screen, &dest);
+
+ return ret;
+}
+
+#if 0
+int
+SurfaceSDL::draw_stretched(float x, float y, int sw, int sh, Uint8 alpha, bool update)
+{
+ SDL_Rect dest;
+
+ dest.x = (int)x;
+ dest.y = (int)y;
+ dest.w = (int)sw;
+ dest.h = (int)sh;
+
+ if(alpha != 255)
+ SDL_SetAlpha(sdl_surface ,SDL_SRCALPHA,alpha);
+
+
+ SDL_Surface* sdl_surface_copy = SDL_CreateRGBSurface (sdl_surface->flags,
+ sw, sh, sdl_surface->format->BitsPerPixel,
+ sdl_surface->format->Rmask, sdl_surface->format->Gmask,
+ sdl_surface->format->Bmask,
+ 0);
+
+ SDL_BlitSurface(sdl_surface, NULL, sdl_surface_copy, NULL);
+ SDL_SoftStretch(sdl_surface_copy, NULL, sdl_surface_copy, &dest);
+
+ int ret = SDL_BlitSurface(sdl_surface_copy,NULL,screen,&dest);
+ SDL_FreeSurface(sdl_surface_copy);
+
+ if (update == UPDATE)
+ update_rect(screen, dest.x, dest.y, dest.w, dest.h);
+
+ return ret;
+}
+#endif
+
+SurfaceSDL::~SurfaceSDL()
+{}
+
+/* EOF */
--- /dev/null
+// $Id$
+//
+// SuperTux
+// Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#ifndef SUPERTUX_TEXTURE_H
+#define SUPERTUX_TEXTURE_H
+
+#include <string>
+#include <list>
+
+#ifndef NOOPENGL
+#include "SDL_opengl.h"
+#endif
+
+#include "SDL.h"
+
+#include "video/screen.h"
+#include "math/vector.h"
+
+SDL_Surface* sdl_surface_from_sdl_surface(SDL_Surface* sdl_surf, bool use_alpha);
+SDL_Surface* sdl_surface_from_nothing();
+
+class SurfaceImpl;
+class SurfaceSDL;
+class SurfaceOpenGL;
+class DrawingContext;
+
+/// bitset for drawing effects
+enum {
+ /** Don't apply anything */
+ NONE_EFFECT = 0x0000,
+ /** Draw the Surface upside down */
+ VERTICAL_FLIP = 0x0001,
+ /** Draw the Surface with alpha equal to 128 */
+ SEMI_TRANSPARENT = 0x0002
+ };
+
+/** This class holds all the data necessary to construct a surface */
+class SurfaceData
+{
+public:
+ enum ConstructorType { LOAD, LOAD_PART, SURFACE, GRADIENT };
+ ConstructorType type;
+ SDL_Surface* surface;
+ std::string file;
+ bool use_alpha;
+ int x;
+ int y;
+ int w;
+ int h;
+ Color top_gradient;
+ Color bottom_gradient;
+
+ SurfaceData(SDL_Surface* surf, bool use_alpha_);
+ SurfaceData(const std::string& file_, bool use_alpha_);
+ SurfaceData(const std::string& file_, int x_, int y_, int w_, int h_, bool use_alpha_);
+ SurfaceData(Color top_gradient_, Color bottom_gradient_, int w_, int h_);
+ ~SurfaceData();
+
+ SurfaceSDL* create_SurfaceSDL();
+ SurfaceOpenGL* create_SurfaceOpenGL();
+ SurfaceImpl* create();
+};
+
+/** Container class that holds a surface, necessary so that we can
+ switch Surface implementations (OpenGL, SDL) on the fly */
+class Surface
+{
+public:
+ SurfaceData data;
+ SurfaceImpl* impl;
+ int w;
+ int h;
+
+ typedef std::list<Surface*> Surfaces;
+ static Surfaces surfaces;
+public:
+ static void reload_all();
+ static void debug_check();
+
+ Surface(SDL_Surface* surf, bool use_alpha);
+ Surface(const std::string& file, bool use_alpha);
+ Surface(const std::string& file, int x, int y, int w, int h, bool use_alpha);
+ Surface(Color top_gradient, Color bottom_gradient, int w_, int h_);
+ ~Surface();
+
+ /** Reload the surface, which is necesarry in case of a mode swich */
+ void reload();
+
+ void resize(int widht, int height);
+};
+
+/** Surface implementation, all implementation have to inherit from
+ this class */
+class SurfaceImpl
+{
+protected:
+ SDL_Surface* sdl_surface;
+
+public:
+ int w;
+ int h;
+
+public:
+ SurfaceImpl();
+ virtual ~SurfaceImpl();
+
+ /** Return 0 on success, -2 if surface needs to be reloaded */
+ virtual int draw(float x, float y, Uint8 alpha, Uint32 effect = NONE_EFFECT) = 0;
+ virtual int draw_part(float sx, float sy, float x, float y, float w, float h, Uint8 alpha, Uint32 effect = NONE_EFFECT) = 0;
+#if 0
+ virtual int draw_stretched(float x, float y, int w, int h, Uint8 alpha, bool update) = 0;
+#endif
+ int resize(int w_, int h_);
+
+ SDL_Surface* get_sdl_surface() const; // @evil@ try to avoid this function
+};
+
+class SurfaceSDL : public SurfaceImpl
+{
+public:
+ SurfaceSDL(SDL_Surface* surf, bool use_alpha);
+ SurfaceSDL(const std::string& file, bool use_alpha);
+ SurfaceSDL(const std::string& file, int x, int y, int w, int h, bool use_alpha);
+ SurfaceSDL(Color top_gradient, Color bottom_gradient, int w, int h);
+ virtual ~SurfaceSDL();
+
+ int draw(float x, float y, Uint8 alpha, Uint32 effect = NONE_EFFECT);
+ int draw_part(float sx, float sy, float x, float y, float w, float h, Uint8 alpha, Uint32 effect = NONE_EFFECT);
+#if 0
+ int draw_stretched(float x, float y, int w, int h, Uint8 alpha);
+#endif
+};
+
+#ifndef NOOPENGL
+class SurfaceOpenGL : public SurfaceImpl
+{
+public:
+ GLuint gl_texture;
+
+public:
+ SurfaceOpenGL(SDL_Surface* surf, bool use_alpha);
+ SurfaceOpenGL(const std::string& file, bool use_alpha);
+ SurfaceOpenGL(const std::string& file, int x, int y, int w, int h, bool use_alpha);
+ SurfaceOpenGL(Color top_gradient, Color bottom_gradient, int w, int h);
+
+ virtual ~SurfaceOpenGL();
+
+ int draw(float x, float y, Uint8 alpha, Uint32 effect = NONE_EFFECT);
+ int draw_part(float sx, float sy, float x, float y, float w, float h, Uint8 alpha, Uint32 effect = NONE_EFFECT);
+#if 0
+ int draw_stretched(float x, float y, int w, int h, Uint8 alpha);
+#endif
+
+private:
+ void create_gl(SDL_Surface * surf, GLuint * tex);
+};
+#endif
+
+#endif /*SUPERTUX_TEXTURE_H*/
+
+/* Local Variables: */
+/* mode: c++ */
+/* End: */