From: Matthias Braun Date: Wed, 28 Feb 2007 18:16:37 +0000 (+0000) Subject: - Use obstacks for memory allocation for lispfiles and DrawingRequests, X-Git-Url: https://git.verplant.org/?a=commitdiff_plain;h=7b74666be6929322c6a603a6edd0131378f4c144;p=supertux.git - Use obstacks for memory allocation for lispfiles and DrawingRequests, this should speedup the game a bit (esp. on windows where malloc is slow) - fixed a bunch of memory leaks - some experiments with the camera (disable and they didn't work out too well) SVN-Revision: 4882 --- diff --git a/src/Jamfile b/src/Jamfile index ef1370683..637125168 100644 --- a/src/Jamfile +++ b/src/Jamfile @@ -20,6 +20,7 @@ sources = [ Wildcard trigger : *.cpp *.hpp ] [ Wildcard video : *.cpp *.hpp ] [ Wildcard worldmap : *.cpp *.hpp ] + [ Wildcard obstack : *.c *.h ] ; TRANSLATABLE_SOURCES += [ SearchSource $(sources) ] ; diff --git a/src/audio/stream_sound_source.cpp b/src/audio/stream_sound_source.cpp index 958ef6f58..5a0172362 100644 --- a/src/audio/stream_sound_source.cpp +++ b/src/audio/stream_sound_source.cpp @@ -132,12 +132,12 @@ StreamSoundSource::fillBufferAndQueue(ALuint buffer) if(bytesread > 0) { ALenum format = SoundManager::get_sample_format(file); alBufferData(buffer, format, bufferdata, bytesread, file->rate); - delete[] bufferdata; SoundManager::check_al_error("Couldn't refill audio buffer: "); alSourceQueueBuffers(source, 1, &buffer); SoundManager::check_al_error("Couldn't queue audio buffer: "); } + delete[] bufferdata; // return false if there aren't more buffers to fill return bytesread >= STREAMFRAGMENTSIZE; diff --git a/src/game_session.cpp b/src/game_session.cpp index 2abb68c5f..014dc2ddb 100644 --- a/src/game_session.cpp +++ b/src/game_session.cpp @@ -432,6 +432,11 @@ GameSession::setup() Menu::set_current(NULL); current_ = this; + if(currentsector != Sector::current()) { + currentsector->activate(currentsector->player->get_pos()); + } + currentsector->play_music(LEVEL_MUSIC); + // Eat unneeded events SDL_Event event; while(SDL_PollEvent(&event)) diff --git a/src/gameconfig.cpp b/src/gameconfig.cpp index 43f2ce0a0..8947005ac 100644 --- a/src/gameconfig.cpp +++ b/src/gameconfig.cpp @@ -57,7 +57,7 @@ void Config::load() { lisp::Parser parser; - std::auto_ptr root (parser.parse("config")); + const lisp::Lisp* root = parser.parse("config"); const lisp::Lisp* config_lisp = root->get_lisp("supertux-config"); if(!config_lisp) diff --git a/src/level.cpp b/src/level.cpp index c0f5b2582..1c740e780 100644 --- a/src/level.cpp +++ b/src/level.cpp @@ -58,7 +58,7 @@ Level::load(const std::string& filepath) { try { lisp::Parser parser; - std::auto_ptr root (parser.parse(filepath)); + const lisp::Lisp* root = parser.parse(filepath); const lisp::Lisp* level = root->get_lisp("supertux-level"); if(!level) diff --git a/src/lisp/lexer.cpp b/src/lisp/lexer.cpp index 7352c8212..4e4f2fb6d 100644 --- a/src/lisp/lexer.cpp +++ b/src/lisp/lexer.cpp @@ -16,7 +16,6 @@ // 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 #include diff --git a/src/lisp/lexer.hpp b/src/lisp/lexer.hpp index f541abdd1..1cd062b0d 100644 --- a/src/lisp/lexer.hpp +++ b/src/lisp/lexer.hpp @@ -16,7 +16,6 @@ // 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 __LISPLEXER_H__ #define __LISPLEXER_H__ diff --git a/src/lisp/lisp.cpp b/src/lisp/lisp.cpp index 39313d21f..f5d886447 100644 --- a/src/lisp/lisp.cpp +++ b/src/lisp/lisp.cpp @@ -31,22 +31,17 @@ Lisp::Lisp(LispType newtype) Lisp::~Lisp() { - if(type == TYPE_SYMBOL || type == TYPE_STRING) - delete[] v.string; - if(type == TYPE_CONS) { - delete v.cons.cdr; - delete v.cons.car; - } + // resources should be on parser obstack, so no need to delete anything } -Lisp* +const Lisp* Lisp::get_lisp(const char* name) const { for(const Lisp* p = this; p != 0; p = p->get_cdr()) { - Lisp* child = p->get_car(); + const Lisp* child = p->get_car(); if(!child || child->get_type() != TYPE_CONS) continue; - Lisp* childname = child->get_car(); + const Lisp* childname = child->get_car(); if(!childname) continue; std::string childName; diff --git a/src/lisp/lisp.hpp b/src/lisp/lisp.hpp index 2f1464155..38d6605d4 100644 --- a/src/lisp/lisp.hpp +++ b/src/lisp/lisp.hpp @@ -44,9 +44,9 @@ public: LispType get_type() const { return type; } - Lisp* get_car() const + const Lisp* get_car() const { return v.cons.car; } - Lisp* get_cdr() const + const Lisp* get_cdr() const { return v.cons.cdr; } bool get(std::string& val) const @@ -162,8 +162,8 @@ public: return true; } - Lisp* get_lisp(const char* name) const; - Lisp* get_lisp(const std::string& name) const + const Lisp* get_lisp(const char* name) const; + const Lisp* get_lisp(const std::string& name) const { return get_lisp(name.c_str()); } // for debugging @@ -178,8 +178,8 @@ private: { struct { - Lisp* car; - Lisp* cdr; + const Lisp* car; + const Lisp* cdr; } cons; char* string; diff --git a/src/lisp/list_iterator.hpp b/src/lisp/list_iterator.hpp index 092b6728b..0cb5b54b9 100644 --- a/src/lisp/list_iterator.hpp +++ b/src/lisp/list_iterator.hpp @@ -36,15 +36,15 @@ public: const std::string& item() const { return current_item; } - lisp::Lisp* lisp() const + const lisp::Lisp* lisp() const { return current_lisp; } - lisp::Lisp* value() const + const lisp::Lisp* value() const { return current_lisp->get_car(); } bool next(); private: std::string current_item; - lisp::Lisp* current_lisp; + const lisp::Lisp* current_lisp; const lisp::Lisp* cur; }; diff --git a/src/lisp/parser.cpp b/src/lisp/parser.cpp index 526d57a3c..52e87b297 100644 --- a/src/lisp/parser.cpp +++ b/src/lisp/parser.cpp @@ -16,7 +16,6 @@ // 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 #include @@ -29,6 +28,7 @@ #include "physfs/physfs_stream.hpp" #include "parser.hpp" #include "lisp.hpp" +#include "obstack/obstackpp.hpp" namespace lisp { @@ -40,15 +40,18 @@ Parser::Parser(bool translate) dictionary_manager = new TinyGetText::DictionaryManager(); dictionary_manager->set_charset("UTF-8"); } + + obstack_init(&obst); } Parser::~Parser() { + obstack_free(&obst, NULL); delete lexer; delete dictionary_manager; } -static std::string dirname(std::string filename) +static std::string dirname(const std::string& filename) { std::string::size_type p = filename.find_last_of('/'); if(p == std::string::npos) @@ -57,13 +60,12 @@ static std::string dirname(std::string filename) return filename.substr(0, p+1); } -Lisp* +const Lisp* Parser::parse(const std::string& filename) { IFileStreambuf ins(filename); std::istream in(&ins); - this->filename = filename; if(!in.good()) { std::stringstream msg; msg << "Parser problem: Couldn't open file '" << filename << "'."; @@ -75,17 +77,19 @@ Parser::parse(const std::string& filename) dictionary = & (dictionary_manager->get_dictionary()); } - return parse(in); + return parse(in, filename); } -Lisp* -Parser::parse(std::istream& stream) +const Lisp* +Parser::parse(std::istream& stream, const std::string& sourcename) { delete lexer; lexer = new Lexer(stream); + this->filename = sourcename; token = lexer->getNextToken(); - Lisp* result = new Lisp(Lisp::TYPE_CONS); + + Lisp* result = new(obst) Lisp(Lisp::TYPE_CONS); result->v.cons.car = read(); result->v.cons.cdr = 0; @@ -96,7 +100,7 @@ Parser::parse(std::istream& stream) } void -Parser::parse_error(const char* msg) +Parser::parse_error(const char* msg) const { std::stringstream emsg; emsg << "Parse Error at '" << filename << "' line " << lexer->getLineNumber() @@ -104,7 +108,7 @@ Parser::parse_error(const char* msg) throw std::runtime_error(emsg.str()); } -Lisp* +const Lisp* Parser::read() { Lisp* result; @@ -116,7 +120,7 @@ Parser::read() parse_error("Unexpected ')'."); } case Lexer::TOKEN_OPEN_PAREN: { - result = new Lisp(Lisp::TYPE_CONS); + result = new(obst) Lisp(Lisp::TYPE_CONS); token = lexer->getNextToken(); if(token == Lexer::TOKEN_CLOSE_PAREN) { @@ -132,14 +136,14 @@ Parser::read() if(token != Lexer::TOKEN_STRING) parse_error("Expected string after '(_'"); - result = new Lisp(Lisp::TYPE_STRING); + result = new(obst) Lisp(Lisp::TYPE_STRING); if(dictionary) { std::string translation = dictionary->translate(lexer->getString()); - result->v.string = new char[translation.size()+1]; + result->v.string = new(obst) char[translation.size()+1]; memcpy(result->v.string, translation.c_str(), translation.size()+1); } else { size_t len = strlen(lexer->getString()) + 1; - result->v.string = new char[len]; + result->v.string = new(obst) char[len]; memcpy(result->v.string, lexer->getString(), len); } token = lexer->getNextToken(); @@ -155,40 +159,41 @@ Parser::read() cur->v.cons.cdr = 0; break; } - cur->v.cons.cdr = new Lisp(Lisp::TYPE_CONS); - cur = cur->v.cons.cdr; + Lisp *newcur = new(obst) Lisp(Lisp::TYPE_CONS); + cur->v.cons.cdr = newcur; + cur = newcur; } while(1); break; } case Lexer::TOKEN_SYMBOL: { - result = new Lisp(Lisp::TYPE_SYMBOL); + result = new(obst) Lisp(Lisp::TYPE_SYMBOL); size_t len = strlen(lexer->getString()) + 1; - result->v.string = new char[len]; + result->v.string = new(obst) char[len]; memcpy(result->v.string, lexer->getString(), len); break; } case Lexer::TOKEN_STRING: { - result = new Lisp(Lisp::TYPE_STRING); + result = new(obst) Lisp(Lisp::TYPE_STRING); size_t len = strlen(lexer->getString()) + 1; - result->v.string = new char[len]; + result->v.string = new(obst) char[len]; memcpy(result->v.string, lexer->getString(), len); break; } case Lexer::TOKEN_INTEGER: - result = new Lisp(Lisp::TYPE_INTEGER); + result = new(obst) Lisp(Lisp::TYPE_INTEGER); sscanf(lexer->getString(), "%d", &result->v.integer); break; case Lexer::TOKEN_REAL: - result = new Lisp(Lisp::TYPE_REAL); + result = new(obst) Lisp(Lisp::TYPE_REAL); sscanf(lexer->getString(), "%f", &result->v.real); break; case Lexer::TOKEN_TRUE: - result = new Lisp(Lisp::TYPE_BOOLEAN); + result = new(obst) Lisp(Lisp::TYPE_BOOLEAN); result->v.boolean = true; break; case Lexer::TOKEN_FALSE: - result = new Lisp(Lisp::TYPE_BOOLEAN); + result = new(obst) Lisp(Lisp::TYPE_BOOLEAN); result->v.boolean = false; break; diff --git a/src/lisp/parser.hpp b/src/lisp/parser.hpp index 5f0ad0f4e..d4a986e48 100644 --- a/src/lisp/parser.hpp +++ b/src/lisp/parser.hpp @@ -22,6 +22,7 @@ #include #include "lexer.hpp" +#include "obstack/obstack.h" namespace TinyGetText { class Dictionary; @@ -32,6 +33,7 @@ namespace lisp { class Lisp; +class LispFile; class Parser { @@ -39,18 +41,29 @@ public: Parser(bool translate = true); ~Parser(); - Lisp* parse(const std::string& filename); - Lisp* parse(std::istream& stream); + /** + * Parses a lispfile and returns the s-expression structure. + * Note that all memory is held by the parser so don't destroy the parser + * before you are finished with the lisp tree + */ + const Lisp* parse(const std::string& filename); + /** + * Same as parse but reads from a generic std::istream. The sourcename is + * used for errormessages to indicate the source of the data. + */ + const Lisp* parse(std::istream& stream, const std::string& sourcename); private: - void parse_error(const char* msg); - Lisp* read(); + void parse_error(const char* msg) const; + const Lisp* read(); Lexer* lexer; std::string filename; TinyGetText::DictionaryManager* dictionary_manager; TinyGetText::Dictionary* dictionary; Lexer::TokenType token; + + struct obstack obst; }; } // end of namespace lisp diff --git a/src/main.cpp b/src/main.cpp index 730809896..d1d58602f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -204,8 +204,10 @@ static void init_physfs(const char* argv0) PHYSFS_permitSymbolicLinks(1); //show search Path - for(char** i = PHYSFS_getSearchPath(); *i != NULL; i++) + char** searchpath = PHYSFS_getSearchPath(); + for(char** i = searchpath; *i != NULL; i++) log_info << "[" << *i << "] is in the search path" << std::endl; + PHYSFS_freeList(searchpath); } static void print_usage(const char* argv0) @@ -503,7 +505,9 @@ int main(int argc, char** argv) { int result = 0; +#ifndef NO_CATCH try { +#endif if(pre_parse_commandline(argc, argv)) return 0; @@ -567,6 +571,7 @@ int main(int argc, char** argv) //init_rand(); PAK: this call might subsume the above 3, but I'm chicken! main_loop->run(); +#ifndef NO_CATCH } catch(std::exception& e) { log_fatal << "Unexpected exception: " << e.what() << std::endl; result = 1; @@ -574,6 +579,7 @@ int main(int argc, char** argv) log_fatal << "Unexpected exception" << std::endl; result = 1; } +#endif delete main_loop; main_loop = NULL; diff --git a/src/mainloop.cpp b/src/mainloop.cpp index 5f9230fdb..07d853619 100644 --- a/src/mainloop.cpp +++ b/src/mainloop.cpp @@ -49,7 +49,7 @@ static const int MAX_FRAME_SKIP = 2; MainLoop* main_loop = NULL; MainLoop::MainLoop() - : speed(1.0), nextpop(false), nextpush(false) + : speed(1.0), nextpop(false), nextpush(false), fps(0) { using namespace Scripting; TimeScheduler::instance = new TimeScheduler(); diff --git a/src/object/camera.cpp b/src/object/camera.cpp index b6f2a01cd..e4fd50ae7 100644 --- a/src/object/camera.cpp +++ b/src/object/camera.cpp @@ -16,7 +16,6 @@ // 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 #include @@ -40,8 +39,8 @@ #include "path_walker.hpp" namespace { - enum CameraStyle { CameraStyleYI, CameraStyleKD }; - const CameraStyle cameraStyle = CameraStyleKD; + enum CameraStyle { CameraStyleYI, CameraStyleKD, CameraStyleEXP }; + const CameraStyle cameraStyle = CameraStyleYI; } Camera::Camera(Sector* newsector, std::string name) @@ -261,9 +260,53 @@ Camera::update_scroll_normal_kd(float elapsed_time) shake(); } +template +T clamp(T min, T max, T val) +{ + if(val < min) + return min; + if(val > max) + return max; + + return val; +} + +void +Camera::update_scroll_normal_exp(float elapsed_time) +{ + static const Vector camera_speed = Vector(300, 100); + + Player* player = sector->player; + const Vector& player_pos = player->get_bbox().get_middle(); + static Vector last_player_pos = player_pos; + static Vector camera_delta = Vector(0, 0); + + (void) elapsed_time; + + Vector player_delta_x = player_pos - last_player_pos; + last_player_pos = player_pos; + + Vector camera_delta_antic = Vector(0, 0) + player_delta_x * 25; + Vector myspeed = (camera_delta_antic - camera_delta) / elapsed_time; + myspeed.x = clamp(-camera_speed.x, camera_speed.x, myspeed.x); + myspeed.y = clamp(-camera_speed.y, camera_speed.y, myspeed.y); + + camera_delta += myspeed * elapsed_time; + + translation.x = camera_delta.x + player_pos.x - 0.5f * SCREEN_WIDTH; + translation.y = camera_delta.y + player_pos.y - 0.5f * SCREEN_HEIGHT; + + keep_in_bounds(translation); + shake(); +} + void Camera::update_scroll_normal(float elapsed_time) { + if (cameraStyle == CameraStyleEXP) { + update_scroll_normal_exp(elapsed_time); + return; + } if (cameraStyle == CameraStyleKD) { update_scroll_normal_kd(elapsed_time); return; diff --git a/src/object/camera.hpp b/src/object/camera.hpp index e02c30696..260a612ca 100644 --- a/src/object/camera.hpp +++ b/src/object/camera.hpp @@ -90,6 +90,7 @@ public: private: void update_scroll_normal(float elapsed_time); void update_scroll_normal_kd(float elapsed_time); + void update_scroll_normal_exp(float elapsed_time); void update_scroll_autoscroll(float elapsed_time); void update_scroll_to(float elapsed_time); void keep_in_bounds(Vector& vector); diff --git a/src/object/player.cpp b/src/object/player.cpp index 5fa91de51..d070c2952 100644 --- a/src/object/player.cpp +++ b/src/object/player.cpp @@ -56,20 +56,33 @@ static const float SHOOTING_TIME = .150f; /// time before idle animation starts static const float IDLE_TIME = 2.5f; +/** acceleration in horizontal direction when walking + * (all acceleratiosn are in pixel/s^2) */ static const float WALK_ACCELERATION_X = 300; +/** acceleration in horizontal direction when running */ static const float RUN_ACCELERATION_X = 400; +/** acceleration when skidding */ static const float SKID_XM = 200; +/** time of skidding in seconds */ static const float SKID_TIME = .3f; +/** maximum walk velocity (pixel/s) */ static const float MAX_WALK_XM = 230; +/** maximum run velcoity (pixel/s) */ static const float MAX_RUN_XM = 320; +/** maximum horizontal climb velocity */ static const float MAX_CLIMB_XM = 48; +/** maximum vertical climb velocity */ static const float MAX_CLIMB_YM = 128; +/** instant velocity when tux starts to walk */ static const float WALK_SPEED = 100; +/** time of the kick (kicking mriceblock) animation */ static const float KICK_TIME = .3f; +/** time of tux cheering (currently unused) */ static const float CHEER_TIME = 1.0f; -static const float UNDUCK_HURT_TIME = 0.25f; /**< if Tux cannot unduck for this long, he will get hurt */ +/** if Tux cannot unduck for this long, he will get hurt */ +static const float UNDUCK_HURT_TIME = 0.25f; // growing animation Surface* growingtux_left[GROWING_FRAMES]; diff --git a/src/object_factory.cpp b/src/object_factory.cpp index 0b6916961..4e40fd68b 100644 --- a/src/object_factory.cpp +++ b/src/object_factory.cpp @@ -48,6 +48,8 @@ GameObject* create_object(const std::string& name, const Vector& pos) << " (y " << pos.y << "))"; lisp::Parser parser; - std::auto_ptr lisp (parser.parse(lisptext)); - return create_object(name, *lisp); + const lisp::Lisp* lisp = parser.parse(lisptext, "create_object"); + GameObject* object = create_object(name, *lisp); + + return object; } diff --git a/src/obstack/obstack.c b/src/obstack/obstack.c new file mode 100644 index 000000000..75440d9c7 --- /dev/null +++ b/src/obstack/obstack.c @@ -0,0 +1,441 @@ +/* obstack.c - subroutines used implicitly by object stack macros + Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, + 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + + +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef _LIBC +# include +# include +#else +# include "obstack.h" +#endif + +/* NOTE BEFORE MODIFYING THIS FILE: This version number must be + incremented whenever callers compiled using an old obstack.h can no + longer properly call the functions in this obstack.c. */ +#define OBSTACK_INTERFACE_VERSION 1 + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself, and the installed library + supports the same library interface we do. This code is part of the GNU + C Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object + files, it is simpler to just do this in the source for each such file. */ + +#include /* Random thing to get __GNU_LIBRARY__. */ +#if !defined _LIBC && defined __GNU_LIBRARY__ && __GNU_LIBRARY__ > 1 +# include +# if _GNU_OBSTACK_INTERFACE_VERSION == OBSTACK_INTERFACE_VERSION +# define ELIDE_CODE +# endif +#endif + +#include + +#ifndef ELIDE_CODE + + +# if HAVE_INTTYPES_H +# include +# endif +# if HAVE_STDINT_H || defined _LIBC +# include +# endif + +/* Determine default alignment. */ +union fooround +{ + uintmax_t i; + long double d; + void *p; +}; +struct fooalign +{ + char c; + union fooround u; +}; +/* If malloc were really smart, it would round addresses to DEFAULT_ALIGNMENT. + But in fact it might be less smart and round addresses to as much as + DEFAULT_ROUNDING. So we prepare for it to do that. */ +enum + { + DEFAULT_ALIGNMENT = offsetof (struct fooalign, u), + DEFAULT_ROUNDING = sizeof (union fooround) + }; + +/* When we copy a long block of data, this is the unit to do it with. + On some machines, copying successive ints does not work; + in such a case, redefine COPYING_UNIT to `long' (if that works) + or `char' as a last resort. */ +# ifndef COPYING_UNIT +# define COPYING_UNIT int +# endif + + +/* The functions allocating more room by calling `obstack_chunk_alloc' + jump to the handler pointed to by `obstack_alloc_failed_handler'. + This can be set to a user defined function which should either + abort gracefully or use longjump - but shouldn't return. This + variable by default points to the internal function + `print_and_abort'. */ +static void print_and_abort (void); +void (*obstack_alloc_failed_handler) (void) = print_and_abort; + +/* Exit value used when `print_and_abort' is used. */ +# include +# ifdef _LIBC +int obstack_exit_failure = EXIT_FAILURE; +# else +# include "exitfail.h" +# define obstack_exit_failure exit_failure +# endif + +# ifdef _LIBC +# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3_4) +/* A looong time ago (before 1994, anyway; we're not sure) this global variable + was used by non-GNU-C macros to avoid multiple evaluation. The GNU C + library still exports it because somebody might use it. */ +struct obstack *_obstack_compat; +compat_symbol (libc, _obstack_compat, _obstack, GLIBC_2_0); +# endif +# endif + +/* Define a macro that either calls functions with the traditional malloc/free + calling interface, or calls functions with the mmalloc/mfree interface + (that adds an extra first argument), based on the state of use_extra_arg. + For free, do not use ?:, since some compilers, like the MIPS compilers, + do not allow (expr) ? void : void. */ + +# define CALL_CHUNKFUN(h, size) \ + (((h) -> use_extra_arg) \ + ? (*(h)->chunkfun) ((h)->extra_arg, (size)) \ + : (*(struct _obstack_chunk *(*) (long)) (h)->chunkfun) ((size))) + +# define CALL_FREEFUN(h, old_chunk) \ + do { \ + if ((h) -> use_extra_arg) \ + (*(h)->freefun) ((h)->extra_arg, (old_chunk)); \ + else \ + (*(void (*) (void *)) (h)->freefun) ((old_chunk)); \ + } while (0) + + +/* Initialize an obstack H for use. Specify chunk size SIZE (0 means default). + Objects start on multiples of ALIGNMENT (0 means use default). + CHUNKFUN is the function to use to allocate chunks, + and FREEFUN the function to free them. + + Return nonzero if successful, calls obstack_alloc_failed_handler if + allocation fails. */ + +int +_obstack_begin (struct obstack *h, + int size, int alignment, + void *(*chunkfun) (long), + void (*freefun) (void *)) +{ + register struct _obstack_chunk *chunk; /* points to new chunk */ + + if (alignment == 0) + alignment = DEFAULT_ALIGNMENT; + if (size == 0) + /* Default size is what GNU malloc can fit in a 4096-byte block. */ + { + /* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc. + Use the values for range checking, because if range checking is off, + the extra bytes won't be missed terribly, but if range checking is on + and we used a larger request, a whole extra 4096 bytes would be + allocated. + + These number are irrelevant to the new GNU malloc. I suspect it is + less sensitive to the size of the request. */ + int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1)) + + 4 + DEFAULT_ROUNDING - 1) + & ~(DEFAULT_ROUNDING - 1)); + size = 4096 - extra; + } + + h->chunkfun = (struct _obstack_chunk * (*)(void *, long)) chunkfun; + h->freefun = (void (*) (void *, struct _obstack_chunk *)) freefun; + h->chunk_size = size; + h->alignment_mask = alignment - 1; + h->use_extra_arg = 0; + + chunk = h->chunk = CALL_CHUNKFUN (h, h -> chunk_size); + if (!chunk) + (*obstack_alloc_failed_handler) (); + h->next_free = h->object_base = __PTR_ALIGN ((char *) chunk, chunk->contents, + alignment - 1); + h->chunk_limit = chunk->limit + = (char *) chunk + h->chunk_size; + chunk->prev = 0; + /* The initial chunk now contains no empty object. */ + h->maybe_empty_object = 0; + h->alloc_failed = 0; + return 1; +} + +int +_obstack_begin_1 (struct obstack *h, int size, int alignment, + void *(*chunkfun) (void *, long), + void (*freefun) (void *, void *), + void *arg) +{ + register struct _obstack_chunk *chunk; /* points to new chunk */ + + if (alignment == 0) + alignment = DEFAULT_ALIGNMENT; + if (size == 0) + /* Default size is what GNU malloc can fit in a 4096-byte block. */ + { + /* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc. + Use the values for range checking, because if range checking is off, + the extra bytes won't be missed terribly, but if range checking is on + and we used a larger request, a whole extra 4096 bytes would be + allocated. + + These number are irrelevant to the new GNU malloc. I suspect it is + less sensitive to the size of the request. */ + int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1)) + + 4 + DEFAULT_ROUNDING - 1) + & ~(DEFAULT_ROUNDING - 1)); + size = 4096 - extra; + } + + h->chunkfun = (struct _obstack_chunk * (*)(void *,long)) chunkfun; + h->freefun = (void (*) (void *, struct _obstack_chunk *)) freefun; + h->chunk_size = size; + h->alignment_mask = alignment - 1; + h->extra_arg = arg; + h->use_extra_arg = 1; + + chunk = h->chunk = CALL_CHUNKFUN (h, h -> chunk_size); + if (!chunk) + (*obstack_alloc_failed_handler) (); + h->next_free = h->object_base = __PTR_ALIGN ((char *) chunk, chunk->contents, + alignment - 1); + h->chunk_limit = chunk->limit + = (char *) chunk + h->chunk_size; + chunk->prev = 0; + /* The initial chunk now contains no empty object. */ + h->maybe_empty_object = 0; + h->alloc_failed = 0; + return 1; +} + +/* Allocate a new current chunk for the obstack *H + on the assumption that LENGTH bytes need to be added + to the current object, or a new object of length LENGTH allocated. + Copies any partial object from the end of the old chunk + to the beginning of the new one. */ + +void +_obstack_newchunk (struct obstack *h, int length) +{ + register struct _obstack_chunk *old_chunk = h->chunk; + register struct _obstack_chunk *new_chunk; + register long new_size; + register long obj_size = h->next_free - h->object_base; + register long i; + long already; + char *object_base; + + /* Compute size for new chunk. */ + new_size = (obj_size + length) + (obj_size >> 3) + h->alignment_mask + 100; + if (new_size < h->chunk_size) + new_size = h->chunk_size; + + /* Allocate and initialize the new chunk. */ + new_chunk = CALL_CHUNKFUN (h, new_size); + if (!new_chunk) + (*obstack_alloc_failed_handler) (); + h->chunk = new_chunk; + new_chunk->prev = old_chunk; + new_chunk->limit = h->chunk_limit = (char *) new_chunk + new_size; + + /* Compute an aligned object_base in the new chunk */ + object_base = + __PTR_ALIGN ((char *) new_chunk, new_chunk->contents, h->alignment_mask); + + /* Move the existing object to the new chunk. + Word at a time is fast and is safe if the object + is sufficiently aligned. */ + if (h->alignment_mask + 1 >= DEFAULT_ALIGNMENT) + { + for (i = obj_size / sizeof (COPYING_UNIT) - 1; + i >= 0; i--) + ((COPYING_UNIT *)object_base)[i] + = ((COPYING_UNIT *)h->object_base)[i]; + /* We used to copy the odd few remaining bytes as one extra COPYING_UNIT, + but that can cross a page boundary on a machine + which does not do strict alignment for COPYING_UNITS. */ + already = obj_size / sizeof (COPYING_UNIT) * sizeof (COPYING_UNIT); + } + else + already = 0; + /* Copy remaining bytes one by one. */ + for (i = already; i < obj_size; i++) + object_base[i] = h->object_base[i]; + + /* If the object just copied was the only data in OLD_CHUNK, + free that chunk and remove it from the chain. + But not if that chunk might contain an empty object. */ + if (! h->maybe_empty_object + && (h->object_base + == __PTR_ALIGN ((char *) old_chunk, old_chunk->contents, + h->alignment_mask))) + { + new_chunk->prev = old_chunk->prev; + CALL_FREEFUN (h, old_chunk); + } + + h->object_base = object_base; + h->next_free = h->object_base + obj_size; + /* The new chunk certainly contains no empty object yet. */ + h->maybe_empty_object = 0; +} +# ifdef _LIBC +libc_hidden_def (_obstack_newchunk) +# endif + +/* Return nonzero if object OBJ has been allocated from obstack H. + This is here for debugging. + If you use it in a program, you are probably losing. */ + +/* Suppress -Wmissing-prototypes warning. We don't want to declare this in + obstack.h because it is just for debugging. */ +int _obstack_allocated_p (struct obstack *h, void *obj); + +int +_obstack_allocated_p (struct obstack *h, void *obj) +{ + register struct _obstack_chunk *lp; /* below addr of any objects in this chunk */ + register struct _obstack_chunk *plp; /* point to previous chunk if any */ + + lp = (h)->chunk; + /* We use >= rather than > since the object cannot be exactly at + the beginning of the chunk but might be an empty object exactly + at the end of an adjacent chunk. */ + while (lp != 0 && ((void *) lp >= obj || (void *) (lp)->limit < obj)) + { + plp = lp->prev; + lp = plp; + } + return lp != 0; +} + +/* Free objects in obstack H, including OBJ and everything allocate + more recently than OBJ. If OBJ is zero, free everything in H. */ + +# undef obstack_free + +void +obstack_free (struct obstack *h, void *obj) +{ + register struct _obstack_chunk *lp; /* below addr of any objects in this chunk */ + register struct _obstack_chunk *plp; /* point to previous chunk if any */ + + lp = h->chunk; + /* We use >= because there cannot be an object at the beginning of a chunk. + But there can be an empty object at that address + at the end of another chunk. */ + while (lp != 0 && ((void *) lp >= obj || (void *) (lp)->limit < obj)) + { + plp = lp->prev; + CALL_FREEFUN (h, lp); + lp = plp; + /* If we switch chunks, we can't tell whether the new current + chunk contains an empty object, so assume that it may. */ + h->maybe_empty_object = 1; + } + if (lp) + { + h->object_base = h->next_free = (char *) (obj); + h->chunk_limit = lp->limit; + h->chunk = lp; + } + else if (obj != 0) + /* obj is not in any of the chunks! */ + abort (); +} + +# ifdef _LIBC +/* Older versions of libc used a function _obstack_free intended to be + called by non-GCC compilers. */ +strong_alias (obstack_free, _obstack_free) +# endif + +int +_obstack_memory_used (struct obstack *h) +{ + register struct _obstack_chunk* lp; + register int nbytes = 0; + + for (lp = h->chunk; lp != 0; lp = lp->prev) + { + nbytes += lp->limit - (char *) lp; + } + return nbytes; +} + +/* Define the error handler. */ +# ifdef _LIBC +# include +# else +# include "gettext.h" +# endif +# ifndef _ +# define _(msgid) gettext (msgid) +# endif + +# ifdef _LIBC +# include +# endif + +# ifndef __attribute__ +/* This feature is available in gcc versions 2.5 and later. */ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) +# define __attribute__(Spec) /* empty */ +# endif +# endif + +static void +__attribute__ ((noreturn)) +print_and_abort (void) +{ + /* Don't change any of these strings. Yes, it would be possible to add + the newline to the string and use fputs or so. But this must not + happen because the "memory exhausted" message appears in other places + like this and the translation should be reused instead of creating + a very similar string which requires a separate translation. */ +# ifdef _LIBC + (void) __fxprintf (NULL, "%s\n", _("memory exhausted")); +# else + fprintf (stderr, "%s\n", _("memory exhausted")); +# endif + exit (obstack_exit_failure); +} + +#endif /* !ELIDE_CODE */ diff --git a/src/obstack/obstack.h b/src/obstack/obstack.h new file mode 100644 index 000000000..206fe5505 --- /dev/null +++ b/src/obstack/obstack.h @@ -0,0 +1,509 @@ +/* obstack.h - object stack macros + Copyright (C) 1988-1994,1996-1999,2003,2004,2005 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +/* Summary: + +All the apparent functions defined here are macros. The idea +is that you would use these pre-tested macros to solve a +very specific set of problems, and they would run fast. +Caution: no side-effects in arguments please!! They may be +evaluated MANY times!! + +These macros operate a stack of objects. Each object starts life +small, and may grow to maturity. (Consider building a word syllable +by syllable.) An object can move while it is growing. Once it has +been "finished" it never changes address again. So the "top of the +stack" is typically an immature growing object, while the rest of the +stack is of mature, fixed size and fixed address objects. + +These routines grab large chunks of memory, using a function you +supply, called `obstack_chunk_alloc'. On occasion, they free chunks, +by calling `obstack_chunk_free'. You must define them and declare +them before using any obstack macros. + +Each independent stack is represented by a `struct obstack'. +Each of the obstack macros expects a pointer to such a structure +as the first argument. + +One motivation for this package is the problem of growing char strings +in symbol tables. Unless you are "fascist pig with a read-only mind" +--Gosper's immortal quote from HAKMEM item 154, out of context--you +would not like to put any arbitrary upper limit on the length of your +symbols. + +In practice this often means you will build many short symbols and a +few long symbols. At the time you are reading a symbol you don't know +how long it is. One traditional method is to read a symbol into a +buffer, realloc()ating the buffer every time you try to read a symbol +that is longer than the buffer. This is beaut, but you still will +want to copy the symbol from the buffer to a more permanent +symbol-table entry say about half the time. + +With obstacks, you can work differently. Use one obstack for all symbol +names. As you read a symbol, grow the name in the obstack gradually. +When the name is complete, finalize it. Then, if the symbol exists already, +free the newly read name. + +The way we do this is to take a large chunk, allocating memory from +low addresses. When you want to build a symbol in the chunk you just +add chars above the current "high water mark" in the chunk. When you +have finished adding chars, because you got to the end of the symbol, +you know how long the chars are, and you can create a new object. +Mostly the chars will not burst over the highest address of the chunk, +because you would typically expect a chunk to be (say) 100 times as +long as an average object. + +In case that isn't clear, when we have enough chars to make up +the object, THEY ARE ALREADY CONTIGUOUS IN THE CHUNK (guaranteed) +so we just point to it where it lies. No moving of chars is +needed and this is the second win: potentially long strings need +never be explicitly shuffled. Once an object is formed, it does not +change its address during its lifetime. + +When the chars burst over a chunk boundary, we allocate a larger +chunk, and then copy the partly formed object from the end of the old +chunk to the beginning of the new larger chunk. We then carry on +accreting characters to the end of the object as we normally would. + +A special macro is provided to add a single char at a time to a +growing object. This allows the use of register variables, which +break the ordinary 'growth' macro. + +Summary: + We allocate large chunks. + We carve out one object at a time from the current chunk. + Once carved, an object never moves. + We are free to append data of any size to the currently + growing object. + Exactly one object is growing in an obstack at any one time. + You can run one obstack per control block. + You may have as many control blocks as you dare. + Because of the way we do it, you can `unwind' an obstack + back to a previous state. (You may remove objects much + as you would with a stack.) +*/ + + +/* Don't do the contents of this file more than once. */ + +#ifndef _OBSTACK_H +#define _OBSTACK_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* We need the type of a pointer subtraction. If __PTRDIFF_TYPE__ is + defined, as with GNU C, use that; that way we don't pollute the + namespace with 's symbols. Otherwise, include + and use ptrdiff_t. */ + +#ifdef __PTRDIFF_TYPE__ +# define PTR_INT_TYPE __PTRDIFF_TYPE__ +#else +# include +# define PTR_INT_TYPE ptrdiff_t +#endif + +/* If B is the base of an object addressed by P, return the result of + aligning P to the next multiple of A + 1. B and P must be of type + char *. A + 1 must be a power of 2. */ + +#define __BPTR_ALIGN(B, P, A) ((B) + (((P) - (B) + (A)) & ~(A))) + +/* Similiar to _BPTR_ALIGN (B, P, A), except optimize the common case + where pointers can be converted to integers, aligned as integers, + and converted back again. If PTR_INT_TYPE is narrower than a + pointer (e.g., the AS/400), play it safe and compute the alignment + relative to B. Otherwise, use the faster strategy of computing the + alignment relative to 0. */ + +#define __PTR_ALIGN(B, P, A) \ + __BPTR_ALIGN (sizeof (PTR_INT_TYPE) < sizeof (void *) ? (B) : (char *) 0, \ + P, A) + +#include + +struct _obstack_chunk /* Lives at front of each chunk. */ +{ + char *limit; /* 1 past end of this chunk */ + struct _obstack_chunk *prev; /* address of prior chunk or NULL */ + char contents[4]; /* objects begin here */ +}; + +struct obstack /* control current object in current chunk */ +{ + long chunk_size; /* preferred size to allocate chunks in */ + struct _obstack_chunk *chunk; /* address of current struct obstack_chunk */ + char *object_base; /* address of object we are building */ + char *next_free; /* where to add next char to current object */ + char *chunk_limit; /* address of char after current chunk */ + union + { + PTR_INT_TYPE tempint; + void *tempptr; + } temp; /* Temporary for some macros. */ + int alignment_mask; /* Mask of alignment for each object. */ + /* These prototypes vary based on `use_extra_arg', and we use + casts to the prototypeless function type in all assignments, + but having prototypes here quiets -Wstrict-prototypes. */ + struct _obstack_chunk *(*chunkfun) (void *, long); + void (*freefun) (void *, struct _obstack_chunk *); + void *extra_arg; /* first arg for chunk alloc/dealloc funcs */ + unsigned use_extra_arg:1; /* chunk alloc/dealloc funcs take extra arg */ + unsigned maybe_empty_object:1;/* There is a possibility that the current + chunk contains a zero-length object. This + prevents freeing the chunk if we allocate + a bigger chunk to replace it. */ + unsigned alloc_failed:1; /* No longer used, as we now call the failed + handler on error, but retained for binary + compatibility. */ +}; + +/* Declare the external functions we use; they are in obstack.c. */ + +extern void _obstack_newchunk (struct obstack *, int); +extern int _obstack_begin (struct obstack *, int, int, + void *(*) (long), void (*) (void *)); +extern int _obstack_begin_1 (struct obstack *, int, int, + void *(*) (void *, long), + void (*) (void *, void *), void *); +extern int _obstack_memory_used (struct obstack *); + +void obstack_free (struct obstack *obstack, void *block); + + +/* Error handler called when `obstack_chunk_alloc' failed to allocate + more memory. This can be set to a user defined function which + should either abort gracefully or use longjump - but shouldn't + return. The default action is to print a message and abort. */ +extern void (*obstack_alloc_failed_handler) (void); + +/* Exit value used when `print_and_abort' is used. */ +extern int obstack_exit_failure; + +/* Pointer to beginning of object being allocated or to be allocated next. + Note that this might not be the final address of the object + because a new chunk might be needed to hold the final size. */ + +#define obstack_base(h) ((void *) (h)->object_base) + +/* Size for allocating ordinary chunks. */ + +#define obstack_chunk_size(h) ((h)->chunk_size) + +/* Pointer to next byte not yet allocated in current chunk. */ + +#define obstack_next_free(h) ((h)->next_free) + +/* Mask specifying low bits that should be clear in address of an object. */ + +#define obstack_alignment_mask(h) ((h)->alignment_mask) + +/* To prevent prototype warnings provide complete argument list. */ +#define obstack_init(h) \ + _obstack_begin ((h), 0, 0, \ + (void *(*) (long)) obstack_chunk_alloc, \ + (void (*) (void *)) obstack_chunk_free) + +#define obstack_begin(h, size) \ + _obstack_begin ((h), (size), 0, \ + (void *(*) (long)) obstack_chunk_alloc, \ + (void (*) (void *)) obstack_chunk_free) + +#define obstack_specify_allocation(h, size, alignment, chunkfun, freefun) \ + _obstack_begin ((h), (size), (alignment), \ + (void *(*) (long)) (chunkfun), \ + (void (*) (void *)) (freefun)) + +#define obstack_specify_allocation_with_arg(h, size, alignment, chunkfun, freefun, arg) \ + _obstack_begin_1 ((h), (size), (alignment), \ + (void *(*) (void *, long)) (chunkfun), \ + (void (*) (void *, void *)) (freefun), (arg)) + +#define obstack_chunkfun(h, newchunkfun) \ + ((h) -> chunkfun = (struct _obstack_chunk *(*)(void *, long)) (newchunkfun)) + +#define obstack_freefun(h, newfreefun) \ + ((h) -> freefun = (void (*)(void *, struct _obstack_chunk *)) (newfreefun)) + +#define obstack_1grow_fast(h,achar) (*((h)->next_free)++ = (achar)) + +#define obstack_blank_fast(h,n) ((h)->next_free += (n)) + +#define obstack_memory_used(h) _obstack_memory_used (h) + +#if defined __GNUC__ && defined __STDC__ && __STDC__ +/* NextStep 2.0 cc is really gcc 1.93 but it defines __GNUC__ = 2 and + does not implement __extension__. But that compiler doesn't define + __GNUC_MINOR__. */ +# if __GNUC__ < 2 || (__NeXT__ && !__GNUC_MINOR__) +# define __extension__ +# endif + +/* For GNU C, if not -traditional, + we can define these macros to compute all args only once + without using a global variable. + Also, we can avoid using the `temp' slot, to make faster code. */ + +# define obstack_object_size(OBSTACK) \ + __extension__ \ + ({ struct obstack const *__o = (OBSTACK); \ + (unsigned) (__o->next_free - __o->object_base); }) + +# define obstack_room(OBSTACK) \ + __extension__ \ + ({ struct obstack const *__o = (OBSTACK); \ + (unsigned) (__o->chunk_limit - __o->next_free); }) + +# define obstack_make_room(OBSTACK,length) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + int __len = (length); \ + if (__o->chunk_limit - __o->next_free < __len) \ + _obstack_newchunk (__o, __len); \ + (void) 0; }) + +# define obstack_empty_p(OBSTACK) \ + __extension__ \ + ({ struct obstack const *__o = (OBSTACK); \ + (__o->chunk->prev == 0 \ + && __o->next_free == __PTR_ALIGN ((char *) __o->chunk, \ + __o->chunk->contents, \ + __o->alignment_mask)); }) + +# define obstack_grow(OBSTACK,where,length) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + int __len = (length); \ + if (__o->next_free + __len > __o->chunk_limit) \ + _obstack_newchunk (__o, __len); \ + memcpy (__o->next_free, where, __len); \ + __o->next_free += __len; \ + (void) 0; }) + +# define obstack_grow0(OBSTACK,where,length) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + int __len = (length); \ + if (__o->next_free + __len + 1 > __o->chunk_limit) \ + _obstack_newchunk (__o, __len + 1); \ + memcpy (__o->next_free, where, __len); \ + __o->next_free += __len; \ + *(__o->next_free)++ = 0; \ + (void) 0; }) + +# define obstack_1grow(OBSTACK,datum) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + if (__o->next_free + 1 > __o->chunk_limit) \ + _obstack_newchunk (__o, 1); \ + obstack_1grow_fast (__o, datum); \ + (void) 0; }) + +/* These assume that the obstack alignment is good enough for pointers + or ints, and that the data added so far to the current object + shares that much alignment. */ + +# define obstack_ptr_grow(OBSTACK,datum) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + if (__o->next_free + sizeof (void *) > __o->chunk_limit) \ + _obstack_newchunk (__o, sizeof (void *)); \ + obstack_ptr_grow_fast (__o, datum); }) \ + +# define obstack_int_grow(OBSTACK,datum) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + if (__o->next_free + sizeof (int) > __o->chunk_limit) \ + _obstack_newchunk (__o, sizeof (int)); \ + obstack_int_grow_fast (__o, datum); }) + +# define obstack_ptr_grow_fast(OBSTACK,aptr) \ +__extension__ \ +({ struct obstack *__o1 = (OBSTACK); \ + *(const void **) __o1->next_free = (aptr); \ + __o1->next_free += sizeof (const void *); \ + (void) 0; }) + +# define obstack_int_grow_fast(OBSTACK,aint) \ +__extension__ \ +({ struct obstack *__o1 = (OBSTACK); \ + *(int *) __o1->next_free = (aint); \ + __o1->next_free += sizeof (int); \ + (void) 0; }) + +# define obstack_blank(OBSTACK,length) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + int __len = (length); \ + if (__o->chunk_limit - __o->next_free < __len) \ + _obstack_newchunk (__o, __len); \ + obstack_blank_fast (__o, __len); \ + (void) 0; }) + +# define obstack_alloc(OBSTACK,length) \ +__extension__ \ +({ struct obstack *__h = (OBSTACK); \ + obstack_blank (__h, (length)); \ + obstack_finish (__h); }) + +# define obstack_copy(OBSTACK,where,length) \ +__extension__ \ +({ struct obstack *__h = (OBSTACK); \ + obstack_grow (__h, (where), (length)); \ + obstack_finish (__h); }) + +# define obstack_copy0(OBSTACK,where,length) \ +__extension__ \ +({ struct obstack *__h = (OBSTACK); \ + obstack_grow0 (__h, (where), (length)); \ + obstack_finish (__h); }) + +/* The local variable is named __o1 to avoid a name conflict + when obstack_blank is called. */ +# define obstack_finish(OBSTACK) \ +__extension__ \ +({ struct obstack *__o1 = (OBSTACK); \ + void *__value = (void *) __o1->object_base; \ + if (__o1->next_free == __value) \ + __o1->maybe_empty_object = 1; \ + __o1->next_free \ + = __PTR_ALIGN (__o1->object_base, __o1->next_free, \ + __o1->alignment_mask); \ + if (__o1->next_free - (char *)__o1->chunk \ + > __o1->chunk_limit - (char *)__o1->chunk) \ + __o1->next_free = __o1->chunk_limit; \ + __o1->object_base = __o1->next_free; \ + __value; }) + +# define obstack_free(OBSTACK, OBJ) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + void *__obj = (OBJ); \ + if (__obj > (void *)__o->chunk && __obj < (void *)__o->chunk_limit) \ + __o->next_free = __o->object_base = (char *)__obj; \ + else (obstack_free) (__o, __obj); }) + +#else /* not __GNUC__ or not __STDC__ */ + +# define obstack_object_size(h) \ + (unsigned) ((h)->next_free - (h)->object_base) + +# define obstack_room(h) \ + (unsigned) ((h)->chunk_limit - (h)->next_free) + +# define obstack_empty_p(h) \ + ((h)->chunk->prev == 0 \ + && (h)->next_free == __PTR_ALIGN ((char *) (h)->chunk, \ + (h)->chunk->contents, \ + (h)->alignment_mask)) + +/* Note that the call to _obstack_newchunk is enclosed in (..., 0) + so that we can avoid having void expressions + in the arms of the conditional expression. + Casting the third operand to void was tried before, + but some compilers won't accept it. */ + +# define obstack_make_room(h,length) \ +( (h)->temp.tempint = (length), \ + (((h)->next_free + (h)->temp.tempint > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), (h)->temp.tempint), 0) : 0)) + +# define obstack_grow(h,where,length) \ +( (h)->temp.tempint = (length), \ + (((h)->next_free + (h)->temp.tempint > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), (h)->temp.tempint), 0) : 0), \ + memcpy ((h)->next_free, where, (h)->temp.tempint), \ + (h)->next_free += (h)->temp.tempint) + +# define obstack_grow0(h,where,length) \ +( (h)->temp.tempint = (length), \ + (((h)->next_free + (h)->temp.tempint + 1 > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), (h)->temp.tempint + 1), 0) : 0), \ + memcpy ((h)->next_free, where, (h)->temp.tempint), \ + (h)->next_free += (h)->temp.tempint, \ + *((h)->next_free)++ = 0) + +# define obstack_1grow(h,datum) \ +( (((h)->next_free + 1 > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), 1), 0) : 0), \ + obstack_1grow_fast (h, datum)) + +# define obstack_ptr_grow(h,datum) \ +( (((h)->next_free + sizeof (char *) > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), sizeof (char *)), 0) : 0), \ + obstack_ptr_grow_fast (h, datum)) + +# define obstack_int_grow(h,datum) \ +( (((h)->next_free + sizeof (int) > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), sizeof (int)), 0) : 0), \ + obstack_int_grow_fast (h, datum)) + +# define obstack_ptr_grow_fast(h,aptr) \ + (((const void **) ((h)->next_free += sizeof (void *)))[-1] = (aptr)) + +# define obstack_int_grow_fast(h,aint) \ + (((int *) ((h)->next_free += sizeof (int)))[-1] = (aint)) + +# define obstack_blank(h,length) \ +( (h)->temp.tempint = (length), \ + (((h)->chunk_limit - (h)->next_free < (h)->temp.tempint) \ + ? (_obstack_newchunk ((h), (h)->temp.tempint), 0) : 0), \ + obstack_blank_fast (h, (h)->temp.tempint)) + +# define obstack_alloc(h,length) \ + (obstack_blank ((h), (length)), obstack_finish ((h))) + +# define obstack_copy(h,where,length) \ + (obstack_grow ((h), (where), (length)), obstack_finish ((h))) + +# define obstack_copy0(h,where,length) \ + (obstack_grow0 ((h), (where), (length)), obstack_finish ((h))) + +# define obstack_finish(h) \ +( ((h)->next_free == (h)->object_base \ + ? (((h)->maybe_empty_object = 1), 0) \ + : 0), \ + (h)->temp.tempptr = (h)->object_base, \ + (h)->next_free \ + = __PTR_ALIGN ((h)->object_base, (h)->next_free, \ + (h)->alignment_mask), \ + (((h)->next_free - (char *) (h)->chunk \ + > (h)->chunk_limit - (char *) (h)->chunk) \ + ? ((h)->next_free = (h)->chunk_limit) : 0), \ + (h)->object_base = (h)->next_free, \ + (h)->temp.tempptr) + +# define obstack_free(h,obj) \ +( (h)->temp.tempint = (char *) (obj) - (char *) (h)->chunk, \ + ((((h)->temp.tempint > 0 \ + && (h)->temp.tempint < (h)->chunk_limit - (char *) (h)->chunk)) \ + ? (int) ((h)->next_free = (h)->object_base \ + = (h)->temp.tempint + (char *) (h)->chunk) \ + : (((obstack_free) ((h), (h)->temp.tempint + (char *) (h)->chunk), 0), 0))) + +#endif /* not __GNUC__ or not __STDC__ */ + +#ifdef __cplusplus +} /* C++ */ +#endif + +#endif /* obstack.h */ diff --git a/src/obstack/obstackpp.hpp b/src/obstack/obstackpp.hpp new file mode 100644 index 000000000..6c345f551 --- /dev/null +++ b/src/obstack/obstackpp.hpp @@ -0,0 +1,49 @@ +// $Id$ +// +// SuperTux +// Copyright (C) 2007 Matthias Braun +// +// 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 OBSTACKPP_H_ +#define OBSTACKPP_H_ + +#include "obstack.h" + +inline void* +operator new (size_t bytes, struct obstack& obst) +{ + return obstack_alloc(&obst, bytes); +} + +inline void* +operator new[] (size_t bytes, struct obstack& obst) +{ + return obstack_alloc(&obst, bytes); +} + +static inline void* obstack_chunk_alloc(size_t size) +{ + return new char[size]; +} + +static inline void obstack_chunk_free(void* data) +{ + char* ptr = static_cast (data); + delete[] ptr; +} + +#endif + diff --git a/src/resources.cpp b/src/resources.cpp index 5dee002de..f0e603714 100644 --- a/src/resources.cpp +++ b/src/resources.cpp @@ -122,6 +122,7 @@ void unload_shared() { /* Free global images: */ delete gold_text; + delete gold_fixed_text; delete white_text; delete blue_text; delete gray_text; @@ -145,4 +146,7 @@ void unload_shared() /* Free mouse-cursor */ delete mouse_cursor; + + delete player_status; + player_status = NULL; } diff --git a/src/sprite/sprite_manager.cpp b/src/sprite/sprite_manager.cpp index 0878e62e7..f1de683d8 100644 --- a/src/sprite/sprite_manager.cpp +++ b/src/sprite/sprite_manager.cpp @@ -69,15 +69,15 @@ SpriteData* SpriteManager::load(const std::string& filename) { lisp::Parser parser; - std::auto_ptr root; + const lisp::Lisp* root; try { - root.reset(parser.parse(filename)); + root = parser.parse(filename); } catch(const std::exception& e) { - std::ostringstream msg; - msg << "Parse error when trying to load sprite '" << filename - << "': " << e.what() << "\n"; - throw std::runtime_error(msg.str()); + std::ostringstream msg; + msg << "Parse error when trying to load sprite '" << filename + << "': " << e.what() << "\n"; + throw std::runtime_error(msg.str()); } const lisp::Lisp* sprite = root->get_lisp("supertux-sprite"); diff --git a/src/textscroller.cpp b/src/textscroller.cpp index bca514c5d..759a9c704 100644 --- a/src/textscroller.cpp +++ b/src/textscroller.cpp @@ -51,7 +51,7 @@ TextScroller::TextScroller(const std::string& filename) lisp::Parser parser; try { - std::auto_ptr root (parser.parse(filename)); + const lisp::Lisp* root = parser.parse(filename); const lisp::Lisp* text_lisp = root->get_lisp("supertux-text"); if(!text_lisp) diff --git a/src/tile_manager.cpp b/src/tile_manager.cpp index 391fc5549..df1f90d7a 100644 --- a/src/tile_manager.cpp +++ b/src/tile_manager.cpp @@ -69,7 +69,7 @@ void TileManager::load_tileset(std::string filename) } lisp::Parser parser; - std::auto_ptr root (parser.parse(filename)); + const lisp::Lisp* root = parser.parse(filename); const lisp::Lisp* tiles_lisp = root->get_lisp("supertux-tiles"); if(!tiles_lisp) diff --git a/src/title.cpp b/src/title.cpp index 79bc57450..56b1e4517 100644 --- a/src/title.cpp +++ b/src/title.cpp @@ -146,7 +146,7 @@ TitleScreen::get_level_name(const std::string& filename) { try { lisp::Parser parser; - std::auto_ptr root (parser.parse(filename)); + const lisp::Lisp* root = parser.parse(filename); const lisp::Lisp* level = root->get_lisp("supertux-level"); if(!level) @@ -474,7 +474,7 @@ TitleScreen::get_slotinfo(int slot) try { lisp::Parser parser; - std::auto_ptr root (parser.parse(slotfile)); + const lisp::Lisp* root = parser.parse(slotfile); const lisp::Lisp* savegame = root->get_lisp("supertux-savegame"); if(!savegame) diff --git a/src/video/drawing_context.cpp b/src/video/drawing_context.cpp index 4c5f17927..89a92f247 100644 --- a/src/video/drawing_context.cpp +++ b/src/video/drawing_context.cpp @@ -16,9 +16,9 @@ // 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 +#include #include #include #include @@ -33,8 +33,69 @@ #include "glutil.hpp" #include "texture.hpp" #include "texture_manager.hpp" +#include "obstack/obstackpp.hpp" #define LIGHTMAP_DIV 5 +enum RequestType +{ + SURFACE, SURFACE_PART, TEXT, GRADIENT, FILLRECT, LIGHTMAPREQUEST, GETLIGHT +}; + +struct SurfacePartRequest +{ + const Surface* surface; + Vector source, size; +}; + +struct TextRequest +{ + const Font* font; + std::string text; + FontAlignment alignment; +}; + +struct GradientRequest +{ + Color top, bottom; + Vector size; +}; + +struct FillRectRequest +{ + Color color; + Vector size; +}; + +struct DrawingRequest +{ + RequestType type; + Vector pos; + + int layer; + DrawingEffect drawing_effect; + float alpha; + Blend blend; + float angle; + Color color; + + void* request_data; + + DrawingRequest() + : angle(0.0f), + color(1.0f, 1.0f, 1.0f, 1.0f) + {} + + bool operator<(const DrawingRequest& other) const + { + return layer < other.layer; + } +}; + +struct GetLightRequest +{ + Color* color_ptr; +}; + static inline int next_po2(int val) { int result = 1; @@ -45,7 +106,7 @@ static inline int next_po2(int val) } DrawingContext::DrawingContext() - : ambient_color( 1.0f, 1.0f, 1.0f, 1.0f ) + : ambient_color(1.0f, 1.0f, 1.0f, 1.0f), target(NORMAL) { screen = SDL_GetVideoSurface(); @@ -61,10 +122,14 @@ DrawingContext::DrawingContext() texture_manager->register_texture(lightmap); requests = &drawing_requests; + + obstack_init(&obst); } DrawingContext::~DrawingContext() { + obstack_free(&obst, NULL); + texture_manager->remove_texture(lightmap); delete lightmap; } @@ -76,24 +141,24 @@ DrawingContext::draw_surface(const Surface* surface, const Vector& position, { assert(surface != 0); - DrawingRequest request; + DrawingRequest* request = new(obst) DrawingRequest(); - request.type = SURFACE; - request.pos = transform.apply(position); + request->type = SURFACE; + request->pos = transform.apply(position); - if(request.pos.x >= SCREEN_WIDTH || request.pos.y >= SCREEN_HEIGHT - || request.pos.x + surface->get_width() < 0 - || request.pos.y + surface->get_height() < 0) + if(request->pos.x >= SCREEN_WIDTH || request->pos.y >= SCREEN_HEIGHT + || request->pos.x + surface->get_width() < 0 + || request->pos.y + surface->get_height() < 0) return; - request.layer = layer; - request.drawing_effect = transform.drawing_effect; - request.alpha = transform.alpha; - request.angle = angle; - request.color = color; - request.blend = blend; + request->layer = layer; + request->drawing_effect = transform.drawing_effect; + request->alpha = transform.alpha; + request->angle = angle; + request->color = color; + request->blend = blend; - request.request_data = const_cast (surface); + request->request_data = const_cast (surface); requests->push_back(request); } @@ -111,35 +176,35 @@ DrawingContext::draw_surface_part(const Surface* surface, const Vector& source, { assert(surface != 0); - DrawingRequest request; + DrawingRequest* request = new(obst) DrawingRequest(); - request.type = SURFACE_PART; - request.pos = transform.apply(dest); - request.layer = layer; - request.drawing_effect = transform.drawing_effect; - request.alpha = transform.alpha; + request->type = SURFACE_PART; + request->pos = transform.apply(dest); + request->layer = layer; + request->drawing_effect = transform.drawing_effect; + request->alpha = transform.alpha; - SurfacePartRequest* surfacepartrequest = new SurfacePartRequest(); + SurfacePartRequest* surfacepartrequest = new(obst) SurfacePartRequest(); surfacepartrequest->size = size; surfacepartrequest->source = source; surfacepartrequest->surface = surface; // clip on screen borders - if(request.pos.x < 0) { - surfacepartrequest->size.x += request.pos.x; + if(request->pos.x < 0) { + surfacepartrequest->size.x += request->pos.x; if(surfacepartrequest->size.x <= 0) return; - surfacepartrequest->source.x -= request.pos.x; - request.pos.x = 0; + surfacepartrequest->source.x -= request->pos.x; + request->pos.x = 0; } - if(request.pos.y < 0) { - surfacepartrequest->size.y += request.pos.y; + if(request->pos.y < 0) { + surfacepartrequest->size.y += request->pos.y; if(surfacepartrequest->size.y <= 0) return; - surfacepartrequest->source.y -= request.pos.y; - request.pos.y = 0; + surfacepartrequest->source.y -= request->pos.y; + request->pos.y = 0; } - request.request_data = surfacepartrequest; + request->request_data = surfacepartrequest; requests->push_back(request); } @@ -148,19 +213,19 @@ void DrawingContext::draw_text(const Font* font, const std::string& text, const Vector& position, FontAlignment alignment, int layer) { - DrawingRequest request; + DrawingRequest* request = new(obst) DrawingRequest(); - request.type = TEXT; - request.pos = transform.apply(position); - request.layer = layer; - request.drawing_effect = transform.drawing_effect; - request.alpha = transform.alpha; + request->type = TEXT; + request->pos = transform.apply(position); + request->layer = layer; + request->drawing_effect = transform.drawing_effect; + request->alpha = transform.alpha; - TextRequest* textrequest = new TextRequest; + TextRequest* textrequest = new(obst) TextRequest(); textrequest->font = font; textrequest->text = text; textrequest->alignment = alignment; - request.request_data = textrequest; + request->request_data = textrequest; requests->push_back(request); } @@ -176,19 +241,19 @@ DrawingContext::draw_center_text(const Font* font, const std::string& text, void DrawingContext::draw_gradient(const Color& top, const Color& bottom, int layer) { - DrawingRequest request; + DrawingRequest* request = new(obst) DrawingRequest(); - request.type = GRADIENT; - request.pos = Vector(0,0); - request.layer = layer; + request->type = GRADIENT; + request->pos = Vector(0,0); + request->layer = layer; - request.drawing_effect = transform.drawing_effect; - request.alpha = transform.alpha; + request->drawing_effect = transform.drawing_effect; + request->alpha = transform.alpha; - GradientRequest* gradientrequest = new GradientRequest; + GradientRequest* gradientrequest = new(obst) GradientRequest(); gradientrequest->top = top; gradientrequest->bottom = bottom; - request.request_data = gradientrequest; + request->request_data = gradientrequest; requests->push_back(request); } @@ -197,20 +262,20 @@ void DrawingContext::draw_filled_rect(const Vector& topleft, const Vector& size, const Color& color, int layer) { - DrawingRequest request; + DrawingRequest* request = new(obst) DrawingRequest(); - request.type = FILLRECT; - request.pos = transform.apply(topleft); - request.layer = layer; + request->type = FILLRECT; + request->pos = transform.apply(topleft); + request->layer = layer; - request.drawing_effect = transform.drawing_effect; - request.alpha = transform.alpha; + request->drawing_effect = transform.drawing_effect; + request->alpha = transform.alpha; - FillRectRequest* fillrectrequest = new FillRectRequest; + FillRectRequest* fillrectrequest = new(obst) FillRectRequest(); fillrectrequest->size = size; fillrectrequest->color = color; fillrectrequest->color.alpha = color.alpha * transform.alpha; - request.request_data = fillrectrequest; + request->request_data = fillrectrequest; requests->push_back(request); } @@ -219,20 +284,20 @@ void DrawingContext::draw_filled_rect(const Rect& rect, const Color& color, int layer) { - DrawingRequest request; + DrawingRequest* request = new(obst) DrawingRequest(); - request.type = FILLRECT; - request.pos = transform.apply(rect.p1); - request.layer = layer; + request->type = FILLRECT; + request->pos = transform.apply(rect.p1); + request->layer = layer; - request.drawing_effect = transform.drawing_effect; - request.alpha = transform.alpha; + request->drawing_effect = transform.drawing_effect; + request->alpha = transform.alpha; - FillRectRequest* fillrectrequest = new FillRectRequest; + FillRectRequest* fillrectrequest = new(obst) FillRectRequest; fillrectrequest->size = Vector(rect.get_width(), rect.get_height()); fillrectrequest->color = color; fillrectrequest->color.alpha = color.alpha * transform.alpha; - request.request_data = fillrectrequest; + request->request_data = fillrectrequest; requests->push_back(request); } @@ -246,28 +311,29 @@ DrawingContext::get_light(const Vector& position, Color* color) return; } - DrawingRequest request; - request.type = GETLIGHT; - request.pos = transform.apply(position); + DrawingRequest* request = new(obst) DrawingRequest(); + request->type = GETLIGHT; + request->pos = transform.apply(position); //There is no light offscreen. - if(request.pos.x >= SCREEN_WIDTH || request.pos.y >= SCREEN_HEIGHT - || request.pos.x < 0 || request.pos.y < 0){ + if(request->pos.x >= SCREEN_WIDTH || request->pos.y >= SCREEN_HEIGHT + || request->pos.x < 0 || request->pos.y < 0){ *color = Color( 0, 0, 0); return; } - request.layer = LAYER_GUI; //make sure all get_light requests are handled last. - GetLightRequest* getlightrequest = new GetLightRequest; + request->layer = LAYER_GUI; //make sure all get_light requests are handled last. + GetLightRequest* getlightrequest = new(obst) GetLightRequest(); getlightrequest->color_ptr = color; - request.request_data = getlightrequest; + request->request_data = getlightrequest; lightmap_requests.push_back(request); } void -DrawingContext::get_light(DrawingRequest& request) +DrawingContext::get_light(const DrawingRequest& request) const { - GetLightRequest* getlightrequest = (GetLightRequest*) request.request_data; + const GetLightRequest* getlightrequest + = (GetLightRequest*) request.request_data; float pixels[3]; for( int i = 0; i<3; i++) @@ -278,14 +344,12 @@ DrawingContext::get_light(DrawingRequest& request) glReadPixels((GLint) posX, (GLint) posY , 1, 1, GL_RGB, GL_FLOAT, pixels); *(getlightrequest->color_ptr) = Color( pixels[0], pixels[1], pixels[2]); //printf("get_light %f/%f =>%f/%f r%f g%f b%f\n", request.pos.x, request.pos.y, posX, posY, pixels[0], pixels[1], pixels[2]); - - delete getlightrequest; } void -DrawingContext::draw_surface_part(DrawingRequest& request) +DrawingContext::draw_surface_part(const DrawingRequest& request) const { - SurfacePartRequest* surfacepartrequest + const SurfacePartRequest* surfacepartrequest = (SurfacePartRequest*) request.request_data; surfacepartrequest->surface->draw_part( @@ -293,14 +357,13 @@ DrawingContext::draw_surface_part(DrawingRequest& request) request.pos.x, request.pos.y, surfacepartrequest->size.x, surfacepartrequest->size.y, request.alpha, request.drawing_effect); - - delete surfacepartrequest; } void -DrawingContext::draw_gradient(DrawingRequest& request) +DrawingContext::draw_gradient(const DrawingRequest& request) const { - GradientRequest* gradientrequest = (GradientRequest*) request.request_data; + const GradientRequest* gradientrequest + = (GradientRequest*) request.request_data; const Color& top = gradientrequest->top; const Color& bottom = gradientrequest->bottom; @@ -314,25 +377,22 @@ DrawingContext::draw_gradient(DrawingRequest& request) glVertex2f(0, SCREEN_HEIGHT); glEnd(); glEnable(GL_TEXTURE_2D); - - delete gradientrequest; } void -DrawingContext::draw_text(DrawingRequest& request) +DrawingContext::draw_text(const DrawingRequest& request) const { - TextRequest* textrequest = (TextRequest*) request.request_data; + const TextRequest* textrequest = (TextRequest*) request.request_data; textrequest->font->draw(textrequest->text, request.pos, textrequest->alignment, request.drawing_effect, request.alpha); - - delete textrequest; } void -DrawingContext::draw_filled_rect(DrawingRequest& request) +DrawingContext::draw_filled_rect(const DrawingRequest& request) const { - FillRectRequest* fillrectrequest = (FillRectRequest*) request.request_data; + const FillRectRequest* fillrectrequest + = (FillRectRequest*) request.request_data; float x = request.pos.x; float y = request.pos.y; @@ -350,12 +410,10 @@ DrawingContext::draw_filled_rect(DrawingRequest& request) glVertex2f(x, y+h); glEnd(); glEnable(GL_TEXTURE_2D); - - delete fillrectrequest; } void -DrawingContext::draw_lightmap(DrawingRequest& request) +DrawingContext::draw_lightmap(const DrawingRequest& request) const { const Texture* texture = reinterpret_cast (request.request_data); @@ -423,57 +481,77 @@ DrawingContext::do_drawing() glEnable(GL_BLEND); // add a lightmap drawing request into the queue - DrawingRequest request; - request.type = LIGHTMAPREQUEST; - request.layer = LAYER_HUD - 1; - request.request_data = lightmap; + DrawingRequest* request = new(obst) DrawingRequest(); + request->type = LIGHTMAPREQUEST; + request->layer = LAYER_HUD - 1; + request->request_data = lightmap; requests->push_back(request); } //glClear(GL_COLOR_BUFFER_BIT); handle_drawing_requests(drawing_requests); drawing_requests.clear(); + obstack_free(&obst, NULL); + obstack_init(&obst); assert_gl("drawing"); SDL_GL_SwapBuffers(); } +class RequestPtrCompare + : public std::binary_function +{ +public: + bool operator()(const DrawingRequest* r1, const DrawingRequest* r2) const + { + return *r1 < *r2; + } +}; + void -DrawingContext::handle_drawing_requests(DrawingRequests& requests) +DrawingContext::handle_drawing_requests(DrawingRequests& requests) const { - std::stable_sort(requests.begin(), requests.end()); + std::stable_sort(requests.begin(), requests.end(), RequestPtrCompare()); + + DrawingRequests::const_iterator i; + for(i = requests.begin(); i != requests.end(); ++i) { + const DrawingRequest& request = **i; - for(DrawingRequests::iterator i = requests.begin(); - i != requests.end(); ++i) { - switch(i->type) { + switch(request.type) { case SURFACE: { - const Surface* surface = (const Surface*) i->request_data; - if (i->angle == 0.0f && - i->color.red == 1.0f && i->color.green == 1.0f && - i->color.blue == 1.0f && i->color.alpha == 1.0f ) - surface->draw(i->pos.x, i->pos.y, i->alpha, i->drawing_effect); - else - surface->draw(i->pos.x, i->pos.y, i->alpha, i->angle, i->color, i->blend, i->drawing_effect); + const Surface* surface = (const Surface*) request.request_data; + if (request.angle == 0.0f && + request.color.red == 1.0f && request.color.green == 1.0f && + request.color.blue == 1.0f && request.color.alpha == 1.0f) { + surface->draw(request.pos.x, request.pos.y, request.alpha, + request.drawing_effect); + } else { + surface->draw(request.pos.x, request.pos.y, + request.alpha, request.angle, request.color, + request.blend, request.drawing_effect); + } break; } case SURFACE_PART: - draw_surface_part(*i); + draw_surface_part(request); break; case GRADIENT: - draw_gradient(*i); + draw_gradient(request); break; case TEXT: - draw_text(*i); + draw_text(request); break; case FILLRECT: - draw_filled_rect(*i); + draw_filled_rect(request); break; case LIGHTMAPREQUEST: - draw_lightmap(*i); + draw_lightmap(request); break; case GETLIGHT: - get_light(*i); + get_light(request); break; } } @@ -535,10 +613,12 @@ void DrawingContext::set_target(Target target) { this->target = target; - if(target == LIGHTMAP) + if(target == LIGHTMAP) { requests = &lightmap_requests; - else + } else { + assert(target == NORMAL); requests = &drawing_requests; + } } void diff --git a/src/video/drawing_context.hpp b/src/video/drawing_context.hpp index 4839239dc..de882a739 100644 --- a/src/video/drawing_context.hpp +++ b/src/video/drawing_context.hpp @@ -16,7 +16,6 @@ // 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 @@ -29,6 +28,7 @@ #include #include +#include "obstack/obstack.h" #include "math/vector.hpp" #include "math/rect.hpp" #include "surface.hpp" @@ -37,6 +37,7 @@ class Surface; class Texture; +struct DrawingRequest; // some constants for predefined layer values enum { @@ -163,76 +164,16 @@ private: std::vector blend_stack; Blend blend_mode; - enum RequestType - { - SURFACE, SURFACE_PART, TEXT, GRADIENT, FILLRECT, LIGHTMAPREQUEST, GETLIGHT - }; - - struct SurfacePartRequest - { - const Surface* surface; - Vector source, size; - }; - - struct TextRequest - { - const Font* font; - std::string text; - FontAlignment alignment; - }; - - struct GradientRequest - { - Color top, bottom; - Vector size; - }; - - struct FillRectRequest - { - Color color; - Vector size; - }; - - struct DrawingRequest - { - RequestType type; - Vector pos; - - int layer; - DrawingEffect drawing_effect; - float alpha; - Blend blend; - float angle; - Color color; - - void* request_data; - - DrawingRequest() - : angle(0.0f), - color(1.0f, 1.0f, 1.0f, 1.0f) - {} - - bool operator<(const DrawingRequest& other) const - { - return layer < other.layer; - } - }; - - struct GetLightRequest - { - Color* color_ptr; - }; - - typedef std::vector DrawingRequests; + typedef std::vector DrawingRequests; - void handle_drawing_requests(DrawingRequests& requests); - void draw_surface_part(DrawingRequest& request); - void draw_text(DrawingRequest& request); - void draw_text_center(DrawingRequest& request); - void draw_gradient(DrawingRequest& request); - void draw_filled_rect(DrawingRequest& request); - void draw_lightmap(DrawingRequest& request); - void get_light(DrawingRequest& request); + void handle_drawing_requests(DrawingRequests& requests) const; + void draw_surface_part(const DrawingRequest& request) const; + void draw_text(const DrawingRequest& request) const; + void draw_text_center(const DrawingRequest& request) const; + void draw_gradient(const DrawingRequest& request) const; + void draw_filled_rect(const DrawingRequest& request) const; + void draw_lightmap(const DrawingRequest& request) const; + void get_light(const DrawingRequest& request) const; DrawingRequests drawing_requests; DrawingRequests lightmap_requests; @@ -246,6 +187,10 @@ private: Texture* lightmap; int lightmap_width, lightmap_height; float lightmap_uv_right, lightmap_uv_bottom; + + /* obstack holding the memory of the drawing requests */ + struct obstack obst; }; #endif + diff --git a/src/video/texture_manager.cpp b/src/video/texture_manager.cpp index d45eb84f8..6326d0455 100644 --- a/src/video/texture_manager.cpp +++ b/src/video/texture_manager.cpp @@ -120,8 +120,10 @@ TextureManager::create_image_texture(const std::string& filename) 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); #endif - if(convert == 0) + if(convert == 0) { + SDL_FreeSurface(image); throw std::runtime_error("Couldn't create texture: out of memory"); + } SDL_SetAlpha(image, 0, 0); SDL_BlitSurface(image, 0, convert, 0); @@ -134,10 +136,12 @@ TextureManager::create_image_texture(const std::string& filename) result->image_height = image->h; } catch(...) { delete result; + SDL_FreeSurface(image); SDL_FreeSurface(convert); throw; } + SDL_FreeSurface(image); SDL_FreeSurface(convert); return result; } diff --git a/src/world.cpp b/src/world.cpp index 9301adcfa..8fd459934 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -86,7 +86,7 @@ World::load(const std::string& filename) basedir = FileSystem::dirname(filename); lisp::Parser parser; - std::auto_ptr root (parser.parse(filename)); + const lisp::Lisp* root = parser.parse(filename); const lisp::Lisp* info = root->get_lisp("supertux-world"); if(info == NULL) @@ -198,7 +198,7 @@ World::load_state() try { lisp::Parser parser; - std::auto_ptr root (parser.parse(savegame_filename)); + const lisp::Lisp* root = parser.parse(savegame_filename); const lisp::Lisp* lisp = root->get_lisp("supertux-savegame"); if(lisp == NULL) diff --git a/src/worldmap/worldmap.cpp b/src/worldmap/worldmap.cpp index cc4ec202f..65cb1f074 100644 --- a/src/worldmap/worldmap.cpp +++ b/src/worldmap/worldmap.cpp @@ -247,7 +247,7 @@ WorldMap::load(const std::string& filename) try { lisp::Parser parser; - std::auto_ptr root (parser.parse(map_filename)); + const lisp::Lisp* root = parser.parse(map_filename); const lisp::Lisp* lisp = root->get_lisp("supertux-level"); if(!lisp) @@ -323,7 +323,7 @@ WorldMap::get_level_title(LevelTile& level) try { lisp::Parser parser; - std::auto_ptr root (parser.parse(levels_path + level.get_name())); + const lisp::Lisp* root = parser.parse(levels_path + level.get_name()); const lisp::Lisp* level_lisp = root->get_lisp("supertux-level"); if(!level_lisp)