00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "supertux/tile_set_parser.hpp"
00019
00020 #include <stdexcept>
00021 #include <sstream>
00022
00023 #include "lisp/list_iterator.hpp"
00024 #include "lisp/parser.hpp"
00025 #include "supertux/tile_set.hpp"
00026 #include "util/file_system.hpp"
00027
00028 TileSetParser::TileSetParser(TileSet& tileset, const std::string& filename) :
00029 m_tileset(tileset),
00030 m_filename(filename),
00031 m_tiles_path()
00032 {
00033 }
00034
00035 void
00036 TileSetParser::parse()
00037 {
00038 m_tiles_path = FileSystem::dirname(m_filename);
00039
00040 m_tileset.tiles.resize(1, 0);
00041 m_tileset.tiles[0] = new Tile();
00042
00043 lisp::Parser parser;
00044 const lisp::Lisp* root = parser.parse(m_filename);
00045
00046 const lisp::Lisp* tiles_lisp = root->get_lisp("supertux-tiles");
00047 if(!tiles_lisp)
00048 throw std::runtime_error("file is not a supertux tiles file.");
00049
00050 lisp::ListIterator iter(tiles_lisp);
00051 while(iter.next())
00052 {
00053 if (iter.item() == "tile")
00054 {
00055 parse_tile(*iter.lisp());
00056 }
00057 else if (iter.item() == "tilegroup")
00058 {
00059
00060 }
00061 else if (iter.item() == "tiles")
00062 {
00063 parse_tiles(*iter.lisp());
00064 }
00065 else
00066 {
00067 log_warning << "Unknown symbol '" << iter.item() << "' in tileset file" << std::endl;
00068 }
00069 }
00070 }
00071
00072 void
00073 TileSetParser::parse_tile(const Reader& reader)
00074 {
00075 uint32_t id;
00076 if (!reader.get("id", id))
00077 {
00078 throw std::runtime_error("Missing tile-id.");
00079 }
00080
00081 uint32_t attributes = 0;
00082
00083 bool value = false;
00084 if(reader.get("solid", value) && value)
00085 attributes |= Tile::SOLID;
00086 if(reader.get("unisolid", value) && value)
00087 attributes |= Tile::UNISOLID | Tile::SOLID;
00088 if(reader.get("brick", value) && value)
00089 attributes |= Tile::BRICK;
00090 if(reader.get("ice", value) && value)
00091 attributes |= Tile::ICE;
00092 if(reader.get("water", value) && value)
00093 attributes |= Tile::WATER;
00094 if(reader.get("hurts", value) && value)
00095 attributes |= Tile::HURTS;
00096 if(reader.get("fire", value) && value)
00097 attributes |= Tile::FIRE;
00098 if(reader.get("fullbox", value) && value)
00099 attributes |= Tile::FULLBOX;
00100 if(reader.get("coin", value) && value)
00101 attributes |= Tile::COIN;
00102 if(reader.get("goal", value) && value)
00103 attributes |= Tile::GOAL;
00104
00105 uint32_t data = 0;
00106
00107 if(reader.get("north", value) && value)
00108 data |= Tile::WORLDMAP_NORTH;
00109 if(reader.get("south", value) && value)
00110 data |= Tile::WORLDMAP_SOUTH;
00111 if(reader.get("west", value) && value)
00112 data |= Tile::WORLDMAP_WEST;
00113 if(reader.get("east", value) && value)
00114 data |= Tile::WORLDMAP_EAST;
00115 if(reader.get("stop", value) && value)
00116 data |= Tile::WORLDMAP_STOP;
00117
00118 reader.get("data", data);
00119
00120 float fps = 10;
00121 reader.get("fps", fps);
00122
00123 if(reader.get("slope-type", data))
00124 {
00125 attributes |= Tile::SOLID | Tile::SLOPE;
00126 }
00127
00128 std::vector<Tile::ImageSpec> editor_imagespecs;
00129 const lisp::Lisp* editor_images;
00130 editor_images = reader.get_lisp("editor-images");
00131 if(editor_images)
00132 editor_imagespecs = parse_tile_images(*editor_images);
00133
00134 std::vector<Tile::ImageSpec> imagespecs;
00135 const lisp::Lisp* images;
00136 images = reader.get_lisp("images");
00137 if(images)
00138 imagespecs = parse_tile_images(*images);
00139
00140 std::auto_ptr<Tile> tile(new Tile(imagespecs, editor_imagespecs, attributes, data, fps));
00141
00142 if (id >= m_tileset.tiles.size())
00143 m_tileset.tiles.resize(id+1, 0);
00144
00145 if (m_tileset.tiles[id] != 0)
00146 {
00147 log_warning << "Tile with ID " << id << " redefined" << std::endl;
00148 }
00149 else
00150 {
00151 m_tileset.tiles[id] = tile.release();
00152 }
00153 }
00154
00155 std::vector<Tile::ImageSpec>
00156 TileSetParser::parse_tile_images(const Reader& images_lisp)
00157 {
00158 std::vector<Tile::ImageSpec> imagespecs;
00159
00160 const lisp::Lisp* list = &images_lisp;
00161 while(list)
00162 {
00163 const lisp::Lisp* cur = list->get_car();
00164
00165 if(cur->get_type() == lisp::Lisp::TYPE_STRING)
00166 {
00167 std::string file;
00168 cur->get(file);
00169 imagespecs.push_back(Tile::ImageSpec(m_tiles_path + file, Rectf(0, 0, 0, 0)));
00170 }
00171 else if(cur->get_type() == lisp::Lisp::TYPE_CONS &&
00172 cur->get_car()->get_type() == lisp::Lisp::TYPE_SYMBOL &&
00173 cur->get_car()->get_symbol() == "region")
00174 {
00175 const lisp::Lisp* ptr = cur->get_cdr();
00176
00177 std::string file;
00178 float x = 0;
00179 float y = 0;
00180 float w = 0;
00181 float h = 0;
00182 ptr->get_car()->get(file); ptr = ptr->get_cdr();
00183 ptr->get_car()->get(x); ptr = ptr->get_cdr();
00184 ptr->get_car()->get(y); ptr = ptr->get_cdr();
00185 ptr->get_car()->get(w); ptr = ptr->get_cdr();
00186 ptr->get_car()->get(h);
00187 imagespecs.push_back(Tile::ImageSpec(m_tiles_path + file, Rectf(x, y, x+w, y+h)));
00188 }
00189 else
00190 {
00191 log_warning << "Expected string or list in images tag" << std::endl;
00192 }
00193
00194 list = list->get_cdr();
00195 }
00196
00197 return imagespecs;
00198 }
00199
00200 void
00201 TileSetParser::parse_tiles(const Reader& reader)
00202 {
00203
00204 std::vector<uint32_t> ids;
00205
00206 std::vector<uint32_t> attributes;
00207
00208 std::vector<uint32_t> datas;
00209
00210 std::vector<std::string> images;
00211
00212 std::vector<std::string> editor_images;
00213
00214 std::string image_name;
00215
00216
00217
00218
00219
00220
00221
00222
00223 unsigned int width = 0;
00224 unsigned int height = 0;
00225
00226 reader.get("ids", ids);
00227 bool has_attributes = reader.get("attributes", attributes);
00228 bool has_datas = reader.get("datas", datas);
00229
00230 reader.get("image", images) || reader.get("images", images);
00231 reader.get("editor-images", editor_images);
00232
00233 if (images.size() > 0)
00234 image_name = images[0];
00235 else
00236 image_name = "(no image)";
00237
00238 reader.get("width", width);
00239 reader.get("height", height);
00240
00241 float fps = 10;
00242 reader.get("fps", fps);
00243
00244 if (width <= 0)
00245 {
00246 throw std::runtime_error("Width is zero.");
00247 }
00248 else if (height <= 0)
00249 {
00250 throw std::runtime_error("Height is zero.");
00251 }
00252 else if (fps < 0)
00253 {
00254 throw std::runtime_error("Negative fps.");
00255 }
00256 else if (ids.size() != width*height)
00257 {
00258 std::ostringstream err;
00259 err << "Number of ids (" << ids.size() << ") and "
00260 "dimensions of image (" << width << "x" << height << " = " << width*height << ") "
00261 "differ for image " << image_name;
00262 throw std::runtime_error(err.str());
00263 }
00264 else if (has_attributes && (ids.size() != attributes.size()))
00265 {
00266 std::ostringstream err;
00267 err << "Number of ids (" << ids.size() << ") and attributes (" << attributes.size()
00268 << ") mismatch for image '" << image_name << "', but must be equal";
00269 throw std::runtime_error(err.str());
00270 }
00271 else if (has_datas && ids.size() != datas.size())
00272 {
00273 std::ostringstream err;
00274 err << "Number of ids (" << ids.size() << ") and datas (" << datas.size()
00275 << ") mismatch for image '" << image_name << "', but must be equal";
00276 throw std::runtime_error(err.str());
00277 }
00278 else
00279 {
00280 for(std::vector<uint32_t>::size_type i = 0; i < ids.size() && i < width*height; ++i)
00281 {
00282 if (ids[i] != 0)
00283 {
00284 if (ids[i] >= m_tileset.tiles.size())
00285 m_tileset.tiles.resize(ids[i]+1, 0);
00286
00287 int x = 32*(i % width);
00288 int y = 32*(i / width);
00289
00290 std::vector<Tile::ImageSpec> imagespecs;
00291 for(std::vector<std::string>::const_iterator j = images.begin(); j != images.end(); ++j)
00292 {
00293 imagespecs.push_back(Tile::ImageSpec(m_tiles_path + *j, Rectf(x, y, x + 32, y + 32)));
00294 }
00295
00296 std::vector<Tile::ImageSpec> editor_imagespecs;
00297 for(std::vector<std::string>::const_iterator j = editor_images.begin(); j != editor_images.end(); ++j)
00298 {
00299 editor_imagespecs.push_back(Tile::ImageSpec(m_tiles_path + *j, Rectf(x, y, x + 32, y + 32)));
00300 }
00301
00302 std::auto_ptr<Tile> tile(new Tile(imagespecs, editor_imagespecs,
00303 (has_attributes ? attributes[i] : 0), (has_datas ? datas[i] : 0), fps));
00304 if (m_tileset.tiles[ids[i]] == 0) {
00305 m_tileset.tiles[ids[i]] = tile.release();
00306 } else {
00307 log_warning << "Tile with ID " << ids[i] << " redefined" << std::endl;
00308 }
00309 }
00310 }
00311 }
00312 }
00313
00314