lazily load tile images to speedup startup times
authorMatthias Braun <matze@braunis.de>
Fri, 26 Nov 2004 17:16:14 +0000 (17:16 +0000)
committerMatthias Braun <matze@braunis.de>
Fri, 26 Nov 2004 17:16:14 +0000 (17:16 +0000)
SVN-Revision: 2205

12 files changed:
src/gameloop.cpp
src/gameloop.h
src/level.cpp
src/level.h
src/leveleditor.cpp
src/sector.cpp
src/tile.cpp
src/tile.h
src/tile_manager.cpp
src/tile_manager.h
src/trigger/sequence_trigger.cpp
src/worldmap.cpp

index 1b2914b..3267063 100644 (file)
@@ -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"));
 
index d1898be..a63a24b 100644 (file)
@@ -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 */
index 6960828..5aa0734 100644 (file)
@@ -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<Coin*> (*o);
+      if(coin)
+        total_coins++;
+    }
   }
   return total_coins;
 }
index a264353..08d71b7 100644 (file)
@@ -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);
index d6d8a2e..42f0fd8 100644 (file)
@@ -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);
             }
index f9b5ede..2cefe8b 100644 (file)
@@ -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)) {
index 7c7204a..5668fa6 100644 (file)
 #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<Surface*> create_surfaces(lisp_object_t* cur)
-{
-  std::vector<Surface*> 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<Surface*>::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<ImageSpec>::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
index f943a23..ff76569 100644 (file)
 //  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 <vector>
-#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<Surface*> images;
-  std::vector<Surface*> 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<ImageSpec> imagespecs;
+  std::vector<Surface*> 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 */
index 88ec579..64cf7c0 100644 (file)
@@ -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;
 }
 
index 2faa362..0e58613 100644 (file)
@@ -27,8 +27,7 @@
 #include <map>
 #include <stdint.h>
 #include <assert.h>
-
-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<TileGroup> 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
index b02bb5e..98789cd 100644 (file)
@@ -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);
index 974c75c..299fff5 100644 (file)
@@ -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())
                 {