Esempio n. 1
0
bool TMXSceneEncoder::parseTmx(const XMLDocument& xmlDoc, TMXMap& map, const string& inputDirectory) const
{
    const XMLElement* xmlMap = xmlDoc.FirstChildElement("map");
    if (!xmlMap)
    {
        LOG(1, "Missing root <map> element.\n");
        return false;
    }

    // Read in the map values //XXX should compact this so XML attribute parsing is a little nicer
    unsigned int uiValue;
    int iValue;
    const char* attValue = xmlMap->Attribute("width");
    sscanf(attValue, "%u", &uiValue);
    map.setWidth(uiValue);

    attValue = xmlMap->Attribute("height");
    sscanf(attValue, "%u", &uiValue);
    map.setHeight(uiValue);

    float fValue;
    attValue = xmlMap->Attribute("tilewidth");
    sscanf(attValue, "%f", &fValue);
    map.setTileWidth(fValue);

    attValue = xmlMap->Attribute("tileheight");
    sscanf(attValue, "%f", &fValue);
    map.setTileHeight(fValue);

    // Now we load all tilesets
    const XMLElement* xmlTileSet = xmlMap->FirstChildElement("tileset");
    while (xmlTileSet)
    {
        TMXTileSet tileSet;

        attValue = xmlTileSet->Attribute("firstgid");
        sscanf(attValue, "%u", &uiValue);
        tileSet.setFirstGid(uiValue);

        XMLDocument sourceXmlDoc;
        const XMLElement* xmlTileSetToLoad;
        attValue = xmlTileSet->Attribute("source");
        if (attValue)
        {
            XMLError err;
            string tsxLocation = buildFilePath(inputDirectory, attValue);
            if ((err = sourceXmlDoc.LoadFile(tsxLocation.c_str())) != XML_NO_ERROR)
            {
                LOG(1, "Could not load tileset's source TSX.\n");
                return false;
            }
            xmlTileSetToLoad = sourceXmlDoc.RootElement();
        }
        else
        {
            xmlTileSetToLoad = xmlTileSet;
        }

        // Maximum tile size
        attValue = xmlTileSetToLoad->Attribute("tilewidth");
        if (attValue)
        {
            sscanf(attValue, "%u", &uiValue);
            tileSet.setMaxTileWidth(uiValue);
        }
        else
        {
            tileSet.setMaxTileWidth(map.getTileWidth());
        }
        attValue = xmlTileSetToLoad->Attribute("tileheight");
        if (attValue)
        {
            sscanf(attValue, "%u", &uiValue);
            tileSet.setMaxTileHeight(uiValue);
        }
        else
        {
            tileSet.setMaxTileHeight(map.getTileHeight());
        }

        // Spacing and margin
        attValue = xmlTileSetToLoad->Attribute("spacing");
        if (attValue)
        {
            sscanf(attValue, "%u", &uiValue);
            tileSet.setSpacing(uiValue);
        }
        attValue = xmlTileSetToLoad->Attribute("margin");
        if (attValue)
        {
            sscanf(attValue, "%u", &uiValue);
            tileSet.setMargin(uiValue);
        }

        // Tile offset
        const XMLElement* xmlTileOffset = xmlTileSetToLoad->FirstChildElement("tileoffset");
        if (xmlTileOffset)
        {
            Vector2 offset;

            attValue = xmlTileOffset->Attribute("x");
            sscanf(attValue, "%d", &iValue);
            offset.x = iValue;
            attValue = xmlTileOffset->Attribute("y");
            sscanf(attValue, "%d", &iValue);
            offset.y = iValue;

            tileSet.setOffset(offset);
        }

        // Load image source. Don't worry about <data> or trans
        const XMLElement* xmlTileSetImage = xmlTileSetToLoad->FirstChildElement("image");
        if (!xmlTileSetImage)
        {
            LOG(1, "Could not find <image> element for tileset.\n");
            return false;
        }
        tileSet.setImagePath(xmlTileSetImage->Attribute("source"));

        if (xmlTileSetImage->Attribute("width") && xmlTileSetImage->Attribute("height"))
        {
            attValue = xmlTileSetImage->Attribute("width");
            sscanf(attValue, "%u", &uiValue);
            tileSet.setImageWidth(uiValue);

            attValue = xmlTileSetImage->Attribute("height");
            sscanf(attValue, "%u", &uiValue);
            tileSet.setImageHeight(uiValue);
        }
        else
        {
            // Load the image itself to get the width
            string imageLocation = buildFilePath(inputDirectory, tileSet.getImagePath());
            int pos = imageLocation.find_last_of('.');
            if (imageLocation.substr(pos).compare(".png") != 0)
            {
                LOG(1, "TileSet image must be a PNG. %s\n", imageLocation.c_str());
                return false;
            }

            Image* img = Image::create(imageLocation.c_str());
            if (!img)
            {
                LOG(1, "Could not load TileSet image. %s\n", imageLocation.c_str());
                return false;
            }
            tileSet.setImageWidth(img->getWidth());
            tileSet.setImageHeight(img->getHeight());
            SAFE_DELETE(img);
        }

        //TODO: tiles (specifically, tile animations) if possible. May require marking tiles as special tiles, and spinning them off to Sprites
        //<tile id="relId"><animation><frame tileid="relId" duration="numInMS"></...></...></...>

        // Save the tileset
        map.addTileSet(tileSet);

        xmlTileSet = xmlTileSet->NextSiblingElement("tileset");
    }

    // Load the layers
    const XMLElement* xmlLayer = xmlMap->FirstChildElement("layer");
    while (xmlLayer)
    {
        TMXLayer* layer = new TMXLayer();

        parseBaseLayerProperties(xmlLayer, layer);

        // Load properties
        attValue = xmlLayer->Attribute("width");
        if (attValue)
        {
            sscanf(attValue, "%u", &uiValue);
            layer->setWidth(uiValue);
        }
        else
        {
            layer->setWidth(map.getWidth());
        }

        attValue = xmlLayer->Attribute("height");
        if (attValue)
        {
            sscanf(attValue, "%u", &uiValue);
            layer->setHeight(uiValue);
        }
        else
        {
            layer->setHeight(map.getHeight());
        }

        // Load tiles
        layer->setupTiles();
        auto data = loadDataElement(xmlLayer->FirstChildElement("data"));
        size_t dataSize = data.size();
        for (int i = 0; i < dataSize; i++)
        {
            //XXX this might depend on map's renderorder... not sure
            unsigned int x = i % layer->getWidth();
            unsigned int y = i / layer->getWidth();
            layer->setTile(x, y, data[i]);
        }

        // Save layer
        map.addLayer(layer);

        xmlLayer = xmlLayer->NextSiblingElement("layer");
    }

    // Load image layers
    const XMLElement* xmlImgLayer = xmlMap->FirstChildElement("imagelayer");
    while (xmlImgLayer)
    {
        TMXImageLayer* imgLayer = new TMXImageLayer();

        parseBaseLayerProperties(xmlImgLayer, imgLayer);

        // Load properties
        attValue = xmlImgLayer->Attribute("x");
        if (attValue)
        {
            sscanf(attValue, "%d", &iValue);
            imgLayer->setX(iValue);
        }
        attValue = xmlImgLayer->Attribute("y");
        if (attValue)
        {
            sscanf(attValue, "%d", &iValue);
            imgLayer->setY(iValue);
        }

        // Load image source. Don't worry about <data>, trans, width, or height
        const XMLElement* xmlImage = xmlImgLayer->FirstChildElement("image");
        if (!xmlImage)
        {
            LOG(1, "Could not find <image> element for the image layer.\n");
            return false;
        }
        imgLayer->setImagePath(xmlImage->Attribute("source"));

        // Save image layer
        map.addLayer(imgLayer);

        xmlImgLayer = xmlImgLayer->NextSiblingElement("imagelayer");
    }

    return true;
}