X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fsupertux%2Ftile_set_parser.cpp;h=fee700b76e9565d92e7001e82de1997b3f344cb9;hb=5240d812e12e6b53dc3c36bf313361d2d457382a;hp=e3fe52e5f40b37513c5673afe6cf251ce92ce5d1;hpb=ab14b1de1b9f6a5a691a70e618f590b048e3f2e0;p=supertux.git diff --git a/src/supertux/tile_set_parser.cpp b/src/supertux/tile_set_parser.cpp index e3fe52e5f..fee700b76 100644 --- a/src/supertux/tile_set_parser.cpp +++ b/src/supertux/tile_set_parser.cpp @@ -1,6 +1,6 @@ // SuperTux // Copyright (C) 2008 Matthias Braun -// Ingo Ruhnke +// Ingo Ruhnke // // 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 @@ -29,7 +29,7 @@ TileSetParser::TileSetParser(TileSet& tileset, const std::string& filename) : m_tileset(tileset), m_filename(filename), m_tiles_path() -{ +{ } void @@ -38,7 +38,7 @@ TileSetParser::parse() m_tiles_path = FileSystem::dirname(m_filename); m_tileset.tiles.resize(1, 0); - m_tileset.tiles[0] = new Tile(m_tileset); + m_tileset.tiles[0] = new Tile(); lisp::Parser parser; const lisp::Lisp* root = parser.parse(m_filename); @@ -48,198 +48,129 @@ TileSetParser::parse() throw std::runtime_error("file is not a supertux tiles file."); lisp::ListIterator iter(tiles_lisp); - while(iter.next()) { - if(iter.item() == "tile") { - std::auto_ptr tile(new Tile(m_tileset)); - uint32_t id = parse_tile(*tile, *iter.lisp()); - - if(id >= m_tileset.tiles.size()) - m_tileset.tiles.resize(id+1, 0); - - if(m_tileset.tiles[id] != 0) { - log_warning << "Tile with ID " << id << " redefined" << std::endl; - } else { - m_tileset.tiles[id] = tile.release(); - } - } else if(iter.item() == "tilegroup") { + while(iter.next()) + { + if (iter.item() == "tile") + { + parse_tile(*iter.lisp()); + } + else if (iter.item() == "tilegroup") + { /* tilegroups are only interesting for the editor */ - } else if (iter.item() == "tiles") { - // List of ids (use 0 if the tile should be ignored) - std::vector ids; - // List of attributes of the tile - std::vector attributes; - // List of data for the tiles - std::vector datas; - //List of frames that the tiles come in - std::vector images; - - // width and height of the image in tile units, this is used for two - // purposes: - // a) so we don't have to load the image here to know its dimensions - // b) so that the resulting 'tiles' entry is more robust, - // ie. enlarging the image won't break the tile id mapping - // FIXME: height is actually not used, since width might be enough for - // all purposes, still feels somewhat more natural this way - unsigned int width = 0; - unsigned int height = 0; - - iter.lisp()->get("ids", ids); - bool has_attributes = iter.lisp()->get("attributes", attributes); - bool has_datas = iter.lisp()->get("datas", datas); - - if (!iter.lisp()->get("image", images)) - { - iter.lisp()->get( "images", images); - } - - // make the image path absolute - for(std::vector::iterator i = images.begin(); i != images.end(); ++i) - { - *i = m_tiles_path + *i; - } - - iter.lisp()->get("width", width); - iter.lisp()->get("height", height); - - float animfps = 10; - iter.lisp()->get("anim-fps", animfps); - - if(images.size() <= 0) { - throw std::runtime_error("No images in tile."); - } - if(animfps < 0) { - throw std::runtime_error("Negative fps."); - } - if (ids.size() != width*height) { - std::ostringstream err; - err << "Number of ids (" << ids.size() << ") and size of image (" << width*height - << ") mismatch for image '" << images[0] << "', but must be equal"; - throw std::runtime_error(err.str()); - } - - if (has_attributes && ids.size() != attributes.size()) { - std::ostringstream err; - err << "Number of ids (" << ids.size() << ") and attributes (" << attributes.size() - << ") mismatch for image '" << images[0] << "', but must be equal"; - throw std::runtime_error(err.str()); - } - - if (has_datas && ids.size() != datas.size()) { - std::ostringstream err; - err << "Number of ids (" << ids.size() << ") and datas (" << datas.size() - << ") mismatch for image '" << images[0] << "', but must be equal"; - throw std::runtime_error(err.str()); - } - - for(std::vector::size_type i = 0; i < ids.size() && i < width*height; ++i) { - if (ids[i] == 0) - continue; - - if(ids[i] >= m_tileset.tiles.size()) - m_tileset.tiles.resize(ids[i]+1, 0); - - int x = 32*(i % width); - int y = 32*(i / width); - std::auto_ptr tile(new Tile(m_tileset, images, Rect(x, y, x + 32, y + 32), - (has_attributes ? attributes[i] : 0), (has_datas ? datas[i] : 0), animfps)); - if (m_tileset.tiles[ids[i]] == 0) { - m_tileset.tiles[ids[i]] = tile.release(); - } else { - log_warning << "Tile with ID " << ids[i] << " redefined" << std::endl; - } - } - } else if(iter.item() == "properties") { - // deprecated - } else { + } + else if (iter.item() == "tiles") + { + parse_tiles(*iter.lisp()); + } + else + { log_warning << "Unknown symbol '" << iter.item() << "' in tileset file" << std::endl; } } } -uint32_t -TileSetParser::parse_tile(Tile& tile, const Reader& reader) +void +TileSetParser::parse_tile(const Reader& reader) { uint32_t id; - if(!reader.get("id", id)) { + if (!reader.get("id", id)) + { throw std::runtime_error("Missing tile-id."); } + uint32_t attributes = 0; + bool value = false; if(reader.get("solid", value) && value) - tile.attributes |= Tile::SOLID; + attributes |= Tile::SOLID; if(reader.get("unisolid", value) && value) - tile.attributes |= Tile::UNISOLID | Tile::SOLID; + attributes |= Tile::UNISOLID | Tile::SOLID; if(reader.get("brick", value) && value) - tile.attributes |= Tile::BRICK; + attributes |= Tile::BRICK; if(reader.get("ice", value) && value) - tile.attributes |= Tile::ICE; + attributes |= Tile::ICE; if(reader.get("water", value) && value) - tile.attributes |= Tile::WATER; + attributes |= Tile::WATER; if(reader.get("hurts", value) && value) - tile.attributes |= Tile::HURTS; + attributes |= Tile::HURTS; if(reader.get("fire", value) && value) - tile.attributes |= Tile::FIRE; + attributes |= Tile::FIRE; if(reader.get("fullbox", value) && value) - tile.attributes |= Tile::FULLBOX; + attributes |= Tile::FULLBOX; if(reader.get("coin", value) && value) - tile.attributes |= Tile::COIN; + attributes |= Tile::COIN; if(reader.get("goal", value) && value) - tile.attributes |= Tile::GOAL; + attributes |= Tile::GOAL; + + uint32_t data = 0; if(reader.get("north", value) && value) - tile.data |= Tile::WORLDMAP_NORTH; + data |= Tile::WORLDMAP_NORTH; if(reader.get("south", value) && value) - tile.data |= Tile::WORLDMAP_SOUTH; + data |= Tile::WORLDMAP_SOUTH; if(reader.get("west", value) && value) - tile.data |= Tile::WORLDMAP_WEST; + data |= Tile::WORLDMAP_WEST; if(reader.get("east", value) && value) - tile.data |= Tile::WORLDMAP_EAST; + data |= Tile::WORLDMAP_EAST; if(reader.get("stop", value) && value) - tile.data |= Tile::WORLDMAP_STOP; + data |= Tile::WORLDMAP_STOP; + + reader.get("data", data); - reader.get("data", tile.data); - reader.get("anim-fps", tile.anim_fps); + float fps = 10; + reader.get("fps", fps); - if(reader.get("slope-type", tile.data)) { - tile.attributes |= Tile::SOLID | Tile::SLOPE; + if(reader.get("slope-type", data)) + { + attributes |= Tile::SOLID | Tile::SLOPE; } + std::vector editor_imagespecs; + const lisp::Lisp* editor_images; + editor_images = reader.get_lisp("editor-images"); + if(editor_images) + editor_imagespecs = parse_tile_images(*editor_images); + + std::vector imagespecs; const lisp::Lisp* images; -#ifndef NDEBUG - images = reader.get_lisp("editor-images"); + images = reader.get_lisp("images"); if(images) - parse_tile_images(tile, *images); - else { -#endif - images = reader.get_lisp("images"); - if(images) - parse_tile_images(tile, *images); -#ifndef NDEBUG - } -#endif + imagespecs = parse_tile_images(*images); - tile.correct_attributes(); + std::unique_ptr tile(new Tile(imagespecs, editor_imagespecs, attributes, data, fps)); - return id; + if (id >= m_tileset.tiles.size()) + m_tileset.tiles.resize(id+1, 0); + + if (m_tileset.tiles[id] != 0) + { + log_warning << "Tile with ID " << id << " redefined" << std::endl; + } + else + { + m_tileset.tiles[id] = tile.release(); + } } -void -TileSetParser::parse_tile_images(Tile& tile, const Reader& images_lisp) +std::vector +TileSetParser::parse_tile_images(const Reader& images_lisp) { + std::vector imagespecs; + const lisp::Lisp* list = &images_lisp; - while(list) + while(list) { const lisp::Lisp* cur = list->get_car(); - if(cur->get_type() == lisp::Lisp::TYPE_STRING) + if(cur->get_type() == lisp::Lisp::TYPE_STRING) { std::string file; cur->get(file); - tile.imagespecs.push_back(Tile::ImageSpec(m_tiles_path + file, Rect(0, 0, 0, 0))); + imagespecs.push_back(Tile::ImageSpec(m_tiles_path + file, Rectf(0, 0, 0, 0))); } else if(cur->get_type() == lisp::Lisp::TYPE_CONS && cur->get_car()->get_type() == lisp::Lisp::TYPE_SYMBOL && - cur->get_car()->get_symbol() == "region") + cur->get_car()->get_symbol() == "region") { const lisp::Lisp* ptr = cur->get_cdr(); @@ -253,15 +184,131 @@ TileSetParser::parse_tile_images(Tile& tile, const Reader& images_lisp) ptr->get_car()->get(y); ptr = ptr->get_cdr(); ptr->get_car()->get(w); ptr = ptr->get_cdr(); ptr->get_car()->get(h); - tile.imagespecs.push_back(Tile::ImageSpec(m_tiles_path + file, Rect(x, y, x+w, y+h))); - } - else + imagespecs.push_back(Tile::ImageSpec(m_tiles_path + file, Rectf(x, y, x+w, y+h))); + } + else { log_warning << "Expected string or list in images tag" << std::endl; } list = list->get_cdr(); } + + return imagespecs; +} + +void +TileSetParser::parse_tiles(const Reader& reader) +{ + // List of ids (use 0 if the tile should be ignored) + std::vector ids; + // List of attributes of the tile + std::vector attributes; + // List of data for the tiles + std::vector datas; + //List of frames that the tiles come in + std::vector images; + //List of frames that the editor tiles come in + std::vector editor_images; + // Name used to report errors. + std::string image_name; + + // width and height of the image in tile units, this is used for two + // purposes: + // a) so we don't have to load the image here to know its dimensions + // b) so that the resulting 'tiles' entry is more robust, + // ie. enlarging the image won't break the tile id mapping + // FIXME: height is actually not used, since width might be enough for + // all purposes, still feels somewhat more natural this way + unsigned int width = 0; + unsigned int height = 0; + + reader.get("ids", ids); + bool has_attributes = reader.get("attributes", attributes); + bool has_datas = reader.get("datas", datas); + + reader.get("image", images) || reader.get("images", images); + reader.get("editor-images", editor_images); + + if (images.size() > 0) + image_name = images[0]; + else + image_name = "(no image)"; + + reader.get("width", width); + reader.get("height", height); + + float fps = 10; + reader.get("fps", fps); + + if (width == 0) + { + throw std::runtime_error("Width is zero."); + } + else if (height == 0) + { + throw std::runtime_error("Height is zero."); + } + else if (fps < 0) + { + throw std::runtime_error("Negative fps."); + } + else if (ids.size() != width*height) + { + std::ostringstream err; + err << "Number of ids (" << ids.size() << ") and " + "dimensions of image (" << width << "x" << height << " = " << width*height << ") " + "differ for image " << image_name; + throw std::runtime_error(err.str()); + } + else if (has_attributes && (ids.size() != attributes.size())) + { + std::ostringstream err; + err << "Number of ids (" << ids.size() << ") and attributes (" << attributes.size() + << ") mismatch for image '" << image_name << "', but must be equal"; + throw std::runtime_error(err.str()); + } + else if (has_datas && ids.size() != datas.size()) + { + std::ostringstream err; + err << "Number of ids (" << ids.size() << ") and datas (" << datas.size() + << ") mismatch for image '" << image_name << "', but must be equal"; + throw std::runtime_error(err.str()); + } + else + { + for(std::vector::size_type i = 0; i < ids.size() && i < width*height; ++i) + { + if (ids[i] != 0) + { + if (ids[i] >= m_tileset.tiles.size()) + m_tileset.tiles.resize(ids[i]+1, 0); + + int x = 32*(i % width); + int y = 32*(i / width); + + std::vector imagespecs; + for(std::vector::const_iterator j = images.begin(); j != images.end(); ++j) + { + imagespecs.push_back(Tile::ImageSpec(m_tiles_path + *j, Rectf(x, y, x + 32, y + 32))); + } + + std::vector editor_imagespecs; + for(std::vector::const_iterator j = editor_images.begin(); j != editor_images.end(); ++j) + { + editor_imagespecs.push_back(Tile::ImageSpec(m_tiles_path + *j, Rectf(x, y, x + 32, y + 32))); + } + + std::unique_ptr tile(new Tile(imagespecs, editor_imagespecs, + (has_attributes ? attributes[i] : 0), (has_datas ? datas[i] : 0), fps)); + if (m_tileset.tiles[ids[i]] == 0) { + m_tileset.tiles[ids[i]] = tile.release(); + } else { + log_warning << "Tile with ID " << ids[i] << " redefined" << std::endl; + } + } + } + } } /* EOF */