From: Matthias Braun Date: Fri, 26 Nov 2004 17:16:14 +0000 (+0000) Subject: lazily load tile images to speedup startup times X-Git-Url: https://git.verplant.org/?a=commitdiff_plain;h=2d97548e5cded4b201bbc10d6cec6232df03e9a4;p=supertux.git lazily load tile images to speedup startup times SVN-Revision: 2205 --- diff --git a/src/gameloop.cpp b/src/gameloop.cpp index 1b2914bef..326706309 100644 --- a/src/gameloop.cpp +++ b/src/gameloop.cpp @@ -80,10 +80,10 @@ bool compare_last(std::string& haystack, std::string needle) } GameSession::GameSession(const std::string& levelfile_, int mode, - bool flip_level_, Statistics* statistics) + Statistics* statistics) : level(0), currentsector(0), st_gl_mode(mode), end_sequence(NO_ENDSEQUENCE), levelfile(levelfile_), - flip_level(flip_level_), best_level_statistics(statistics) + best_level_statistics(statistics) { current_ = this; @@ -92,9 +92,6 @@ GameSession::GameSession(const std::string& levelfile_, int mode, context = new DrawingContext(); - if(flip_levels_mode) - flip_level = true; - last_swap_point = Vector(-1, -1); last_swap_stats.reset(); @@ -124,8 +121,6 @@ GameSession::restart_level() level = new Level; level->load(levelfile); - if(flip_level) - level->do_vertical_flip(); global_stats.reset(); global_stats.set_total_points(COINS_COLLECTED_STAT, level->get_total_coins()); @@ -209,11 +204,6 @@ GameSession::levelintro(void) Vector(screen->w/2, 350), CENTER_ALLIGN, LAYER_FOREGROUND1); - if(flip_level) - context.draw_text(white_text, - _("Level Vertically Flipped!"), - Vector(screen->w/2, 310), CENTER_ALLIGN, LAYER_FOREGROUND1); - if(best_level_statistics != NULL) best_level_statistics->draw_message_info(context, _("Best Level Statistics")); diff --git a/src/gameloop.h b/src/gameloop.h index d1898be8f..a63a24b05 100644 --- a/src/gameloop.h +++ b/src/gameloop.h @@ -79,7 +79,6 @@ private: bool game_pause; std::string levelfile; - bool flip_level; // the sector and spawnpoint we shoudl spawn after this frame std::string newsector; @@ -93,8 +92,7 @@ public: DrawingContext* context; Timer2 time_left; - GameSession(const std::string& levelfile, int mode, bool flip_level_ = false, - Statistics* statistics = 0); + GameSession(const std::string& levelfile, int mode, Statistics* statistics=0); ~GameSession(); /** Enter the busy loop */ diff --git a/src/level.cpp b/src/level.cpp index 6960828e6..5aa073419 100644 --- a/src/level.cpp +++ b/src/level.cpp @@ -42,6 +42,7 @@ #include "object/gameobjs.h" #include "object/camera.h" #include "object/tilemap.h" +#include "object/coin.h" using namespace std; @@ -155,15 +156,6 @@ Level::~Level() } void -Level::do_vertical_flip() -{ -#if 0 - for(Sectors::iterator i = sectors.begin(); i != sectors.end(); ++i) - i->second->do_vertical_flip(); -#endif -} - -void Level::add_sector(Sector* sector) { sectors.insert(std::make_pair(sector->get_name(), sector)); @@ -233,18 +225,13 @@ Level::get_total_coins() { int total_coins = 0; for(Sectors::iterator i = sectors.begin(); i != sectors.end(); ++i) { - TileMap* solids = i->second->solids; - assert(solids != 0); - for(size_t x = 0; x < solids->get_width(); ++x) - for(size_t y = 0; y < solids->get_height(); ++y) { - const Tile* tile = solids->get_tile(x, y); - if(tile == 0) { - std::cerr << "Invalid tile in sector '" << i->first << "'.\n"; - continue; - } - if(tile->attributes & Tile::COIN) - total_coins++; - } + Sector* sector = i->second; + for(Sector::GameObjects::iterator o = sector->gameobjects.begin(); + o != sector->gameobjects.end(); ++o) { + Coin* coin = dynamic_cast (*o); + if(coin) + total_coins++; + } } return total_coins; } diff --git a/src/level.h b/src/level.h index a26435355..08d71b7df 100644 --- a/src/level.h +++ b/src/level.h @@ -64,9 +64,6 @@ public: const std::string& get_author() const { return author; } - /** Flips the level vertically */ - void do_vertical_flip(); - void add_sector(Sector* sector); Sector* get_sector(const std::string& name); diff --git a/src/leveleditor.cpp b/src/leveleditor.cpp index d6d8a2ecc..42f0fd825 100644 --- a/src/leveleditor.cpp +++ b/src/leveleditor.cpp @@ -110,12 +110,8 @@ LevelEditor::LevelEditor() if(!tile) continue; - Surface* surface; - if(tile->editor_images.size()) - surface = tile->editor_images[0]; - else if(tile->images.size()) - surface = tile->images[0]; - else + Surface* surface = tile->get_editor_image(); + if(!surface) continue; Button button = Button(surface, "", SDLKey(0)); @@ -459,7 +455,7 @@ std::cerr << "previous sector.\n"; { vector.push_back(tilemap->get_tile(x + (int)(((selection_ini.x+scroll.x)*zoom)/32), - y + (int)(((selection_ini.y+scroll.y)*zoom)/32))->id); + y + (int)(((selection_ini.y+scroll.y)*zoom)/32))->getID()); } selection.push_back(vector); } diff --git a/src/sector.cpp b/src/sector.cpp index f9b5ede9c..2cefe8b73 100644 --- a/src/sector.cpp +++ b/src/sector.cpp @@ -331,31 +331,31 @@ Sector::fix_old_tiles() const Tile* tile = solids->get_tile(x, y); Vector pos(x*32, y*32); - if(tile->id == 112) { + if(tile->getID() == 112) { add_object(new InvisibleBlock(pos)); solids->change(x, y, 0); - } else if(tile->id == 295) { + } else if(tile->getID() == 295) { add_object(new Spike(pos, Spike::NORTH)); solids->change(x, y, 0); - } else if(tile->id == 296) { + } else if(tile->getID() == 296) { add_object(new Spike(pos, Spike::EAST)); solids->change(x, y, 0); - } else if(tile->id == 297) { + } else if(tile->getID() == 297) { add_object(new Spike(pos, Spike::SOUTH)); solids->change(x, y, 0); - } else if(tile->id == 298) { + } else if(tile->getID() == 298) { add_object(new Spike(pos, Spike::WEST)); solids->change(x, y, 0); - } else if(tile->attributes & Tile::COIN) { + } else if(tile->getAttributes() & Tile::COIN) { add_object(new Coin(pos)); solids->change(x, y, 0); - } else if(tile->attributes & Tile::FULLBOX) { - add_object(new BonusBlock(pos, tile->data)); + } else if(tile->getAttributes() & Tile::FULLBOX) { + add_object(new BonusBlock(pos, tile->getData())); solids->change(x, y, 0); - } else if(tile->attributes & Tile::BRICK) { - add_object(new Brick(pos, tile->data)); + } else if(tile->getAttributes() & Tile::BRICK) { + add_object(new Brick(pos, tile->getData())); solids->change(x, y, 0); - } else if(tile->attributes & Tile::GOAL) { + } else if(tile->getAttributes() & Tile::GOAL) { add_object(new SequenceTrigger(pos, "endsequence")); solids->change(x, y, 0); } @@ -600,16 +600,16 @@ Sector::collision_tilemap(MovingObject* object, int depth) const Tile* tile = solids->get_tile(x, y); if(!tile) continue; - if(!(tile->attributes & Tile::SOLID)) + if(!(tile->getAttributes() & Tile::SOLID)) continue; - if((tile->attributes & Tile::UNISOLID) && object->movement.y < 0) + if((tile->getAttributes() & Tile::UNISOLID) && object->movement.y < 0) continue; - if(tile->attributes & Tile::SLOPE) { // slope tile + if(tile->getAttributes() & Tile::SLOPE) { // slope tile AATriangle triangle; Vector p1(x*32, y*32); Vector p2((x+1)*32, (y+1)*32); - triangle = AATriangle(p1, p2, tile->data); + triangle = AATriangle(p1, p2, tile->getData()); if(Collision::rectangle_aatriangle(temphit, dest, object->movement, triangle)) { diff --git a/src/tile.cpp b/src/tile.cpp index 7c7204a82..5668fa6d6 100644 --- a/src/tile.cpp +++ b/src/tile.cpp @@ -27,80 +27,13 @@ #include "app/globals.h" #include "tile.h" #include "scene.h" +#include "resources.h" #include "utils/lispreader.h" #include "math/vector.h" #include "video/drawing_context.h" -/** Dirty little helper to create a surface from a snipped of lisp: - * - * "filename" - * (region "filename" x y w h) - */ -static -Surface* create_surface(lisp_object_t* cur) -{ - if (lisp_string_p(cur)) - { - return new Surface(datadir + "/images/tilesets/" + lisp_string(cur), - true); - } - else if (lisp_cons_p(cur) && lisp_symbol_p(lisp_car(cur))) - { - lisp_object_t* sym = lisp_car(cur); - lisp_object_t* data = lisp_cdr(cur); - - if (strcmp(lisp_symbol(sym), "region") == 0) - { - if (lisp_list_length(data) == 5) // (image-region filename x y w h) - { - return new Surface(datadir + "/images/tilesets/" + lisp_string(lisp_car(data)), - lisp_integer(lisp_list_nth(data, 1)), - lisp_integer(lisp_list_nth(data, 2)), - lisp_integer(lisp_list_nth(data, 3)), - lisp_integer(lisp_list_nth(data, 4)), - true); - } - else - { - std::cout << "Tile: Type mispatch, should be '(region \"somestring\" x y w h)'" << std::endl; - return 0; - } - } - else - { - std::cout << "Tile: Unhandled tag: " << lisp_symbol(sym) << std::endl; - return 0; - } - } - - std::cout << "Tile: unhandled element" << std::endl; - return 0; -} - -/** Create a vector of surfaces (aka Sprite) from a piece of lisp: - ((image "bla.png") (image-region "bla.png") ...) - */ -static -std::vector create_surfaces(lisp_object_t* cur) -{ - std::vector surfs; - - while(cur) - { - Surface* surface = create_surface(lisp_car(cur)); - if (surface) - surfs.push_back(surface); - else - std::cout << "Tile: Couldn't create image" << std::endl; - - cur = lisp_cdr(cur); - } - - return surfs; -} - Tile::Tile() - : id(0), attributes(0), data(0), next_tile(0), anim_fps(1) + : id(0), editor_image(0), attributes(0), data(0), anim_fps(1) { } @@ -110,14 +43,11 @@ Tile::~Tile() ++i) { delete *i; } - for(std::vector::iterator i = editor_images.begin(); - i != editor_images.end(); ++i) { - delete *i; - } + delete editor_image; } void -Tile::read(LispReader& reader) +Tile::parse(LispReader& reader) { if(!reader.read_uint("id", id)) { throw std::runtime_error("Missing tile-id."); @@ -147,14 +77,83 @@ Tile::read(LispReader& reader) reader.read_int("data", data); reader.read_float("anim-fps", anim_fps); - reader.read_int("next-tile", next_tile); if(reader.read_int("slope-type", data)) { attributes |= SOLID | SLOPE; } - images = create_surfaces(reader.read_lisp("images")); - editor_images = create_surfaces(reader.read_lisp("editor-images")); + parse_images(reader.read_lisp("images")); + reader.read_string("editor-images", editor_imagefile); +} + +void +Tile::parse_images(lisp_object_t* list) +{ + while(!lisp_nil_p(list)) { + lisp_object_t* cur = lisp_car(list); + if(lisp_string_p(cur)) { + imagespecs.push_back(ImageSpec(lisp_string(cur), Rectangle(0, 0, 0, 0))); + } else if(lisp_cons_p(cur) && lisp_symbol_p(lisp_car(cur))) { + lisp_object_t* sym = lisp_car(cur); + lisp_object_t* data = lisp_cdr(cur); + + if (strcmp(lisp_symbol(sym), "region") == 0) { + float x = lisp_integer(lisp_list_nth(data, 1)); + float y = lisp_integer(lisp_list_nth(data, 2)); + float width = lisp_integer(lisp_list_nth(data, 3)); + float height = lisp_integer(lisp_list_nth(data, 4)); + imagespecs.push_back(ImageSpec(lisp_string(lisp_car(data)), + Rectangle(x, y, x+width, y+height))); + } else { + std::cerr << "Tile: Type mismatch, should be '(region \"somestring\" x y w h)'" << std::endl; + continue; + } + } else { + std::cerr << "Expected string or list in images tag.\n"; + continue; + } + + list = lisp_cdr(list); + } +} + +void +Tile::load_images() +{ + assert(images.size() == 0); + for(std::vector::iterator i = imagespecs.begin(); i != + imagespecs.end(); ++i) { + const ImageSpec& spec = *i; + Surface* surface; + std::string file + = get_resource_filename(std::string("images/tilesets/") + spec.file); + if(spec.rect.get_width() <= 0) { + surface = new Surface(file, true); + } else { + surface = new Surface(file, + (int) spec.rect.p1.x, + (int) spec.rect.p1.y, + (int) spec.rect.get_width(), + (int) spec.rect.get_height(), true); + } + images.push_back(surface); + } + if(editor_imagefile != "") { + editor_image = new Surface( + get_resource_filename( + std::string("images/tilesets/") + editor_imagefile), true); + } +} + +Surface* +Tile::get_editor_image() const +{ + if(editor_image) + return editor_image; + if(images.size() > 0) + return images[0]; + + return 0; } void diff --git a/src/tile.h b/src/tile.h index f943a2395..ff76569a2 100644 --- a/src/tile.h +++ b/src/tile.h @@ -17,79 +17,91 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. - #ifndef TILE_H #define TILE_H #include -#include "SDL.h" #include "video/surface.h" +#include "utils/lispreader.h" +#include "math/rectangle.h" using namespace SuperTux; -namespace SuperTux { -class LispReader; -} - /** Tile Class */ class Tile { public: - Tile(); - ~Tile(); - - /// parses the tile and returns it's id number - void read(LispReader& reader); - + /// bitset for tile attributes + enum { + /** solid tile that is indestructable by Tux */ + SOLID = 0x0001, + /** uni-directional solid tile */ + UNISOLID = 0x0002, + /** a brick that can be destroyed by jumping under it */ + BRICK = 0x0004, + /** an ice brick that makes tux sliding more than usual */ + ICE = 0x0008, + /** a water tile in which tux starts to swim */ + WATER = 0x0010, + /** a tile that hurts the player if he touches it */ + SPIKE = 0x0020, + /** Bonusbox, content is stored in \a data */ + FULLBOX = 0x0040, + /** Tile is a coin */ + COIN = 0x0080, + /** the level should be finished when touching a goaltile. + * if data is 0 then the endsequence should be triggered, if data is 1 + * then we can finish the level instantly. + */ + GOAL = 0x0100, + /** slope tile */ + SLOPE = 0x0200 + }; + +private: unsigned int id; - std::vector images; - std::vector editor_images; - - /// bitset for tileflags - enum { - /** solid tile that is indestructable by Tux */ - SOLID = 0x0001, - /** uni-directional solid tile */ - UNISOLID = 0x0002, - /** a brick that can be destroyed by jumping under it */ - BRICK = 0x0004, - /** an ice brick that makes tux sliding more than usual */ - ICE = 0x0008, - /** a water tile in which tux starts to swim */ - WATER = 0x0010, - /** a tile that hurts the player if he touches it */ - SPIKE = 0x0020, - /** Bonusbox, content is stored in \a data */ - FULLBOX = 0x0040, - /** Tile is a coin */ - COIN = 0x0080, - /** the level should be finished when touching a goaltile. - * if data is 0 then the endsequence should be triggered, if data is 1 - * then we can finish the level instantly. - */ - GOAL = 0x0100, - /** slope tile */ - SLOPE = 0x0200 + struct ImageSpec { + ImageSpec(const std::string& newfile, const Rectangle& newrect) + : file(newfile), rect(newrect) + { } + + std::string file; + Rectangle rect; }; + std::vector imagespecs; + std::vector images; + std::string editor_imagefile; + Surface* editor_image; + /** tile attributes */ Uint32 attributes; /** General purpose data attached to a tile (content of a box, type of coin)*/ int data; - /** Id of the tile that is going to replace this tile once it has - been collected or jumped at */ - int next_tile; - float anim_fps; +public: + ~Tile(); + /** Draw a tile on the screen */ void draw(DrawingContext& context, const Vector& pos, int layer) const; + Surface* get_editor_image() const; + + unsigned int getID() const + { return id; } + + Uint32 getAttributes() const + { return attributes; } + + int getData() const + { return data; } + /// returns the width of the tile in pixels int getWidth() const { @@ -105,8 +117,16 @@ public: return 0; return images[0]->h; } + +protected: + friend class TileManager; + Tile(); + + void load_images(); + + /// parses the tile and returns it's id number + void parse(LispReader& reader); + void parse_images(lisp_object_t* cur); }; #endif - -/* EOF */ diff --git a/src/tile_manager.cpp b/src/tile_manager.cpp index 88ec57986..64cf7c06d 100644 --- a/src/tile_manager.cpp +++ b/src/tile_manager.cpp @@ -44,9 +44,6 @@ TileManager::~TileManager() void TileManager::load_tileset(std::string filename) { - if(filename == current_tileset) - return; - // free old tiles for(Tiles::iterator i = tiles.begin(); i != tiles.end(); ++i) delete *i; @@ -71,7 +68,7 @@ void TileManager::load_tileset(std::string filename) LispReader reader(lisp_cdr(element)); Tile* tile = new Tile; - tile->read(reader); + tile->parse(reader); while(tile->id >= tiles.size()) { tiles.push_back(0); @@ -110,6 +107,5 @@ void TileManager::load_tileset(std::string filename) } lisp_free(root_obj); - current_tileset = filename; } diff --git a/src/tile_manager.h b/src/tile_manager.h index 2faa36224..0e5861314 100644 --- a/src/tile_manager.h +++ b/src/tile_manager.h @@ -27,8 +27,7 @@ #include #include #include - -class Tile; +#include "tile.h" struct TileGroup { @@ -43,7 +42,7 @@ struct TileGroup class TileManager { - private: +private: TileManager(); ~TileManager(); @@ -54,9 +53,7 @@ class TileManager std::set tilegroups; void load_tileset(std::string filename); - std::string current_tileset; - - public: +public: static TileManager* instance() { return instance_ ? instance_ : instance_ = new TileManager(); } static void destroy_instance() @@ -70,16 +67,16 @@ class TileManager const Tile* get(uint32_t id) const { assert(id < tiles.size()); - Tile* t = tiles[id]; - if (t) - { - return t; - } - else - { - std::cout << "TileManager: Invalid tile: " << id << std::endl; - return tiles[0]; - } + Tile* tile = tiles[id]; + if(!tile) { + std::cout << "TileManager: Invalid tile: " << id << std::endl; + return tiles[0]; + } + + if(tile->images.size() == 0 && tile->imagespecs.size() != 0) + tile->load_images(); + + return tile; } uint32_t get_max_tileid() const diff --git a/src/trigger/sequence_trigger.cpp b/src/trigger/sequence_trigger.cpp index b02bb5ebc..98789cd1a 100644 --- a/src/trigger/sequence_trigger.cpp +++ b/src/trigger/sequence_trigger.cpp @@ -10,8 +10,7 @@ SequenceTrigger::SequenceTrigger(LispReader& reader) // TODO } -SequenceTrigger::SequenceTrigger(const Vector& pos, - const std::string& sequence) +SequenceTrigger::SequenceTrigger(const Vector& pos, const std::string& sequence) { bbox.set_pos(pos); bbox.set_size(32, 32); diff --git a/src/worldmap.cpp b/src/worldmap.cpp index 974c75c8c..299fff515 100644 --- a/src/worldmap.cpp +++ b/src/worldmap.cpp @@ -865,8 +865,7 @@ WorldMap::update(float delta) + offset.y)), 500); GameSession session( get_resource_filename(std::string("levels/" + level->name)), - ST_GL_LOAD_LEVEL_FILE, level->vertical_flip, - &level->statistics); + ST_GL_LOAD_LEVEL_FILE, &level->statistics); switch (session.run()) {