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; }