summaryrefslogtreecommitdiff
path: root/tools/tmxcopy
diff options
context:
space:
mode:
Diffstat (limited to 'tools/tmxcopy')
-rw-r--r--tools/tmxcopy/main.cpp68
-rw-r--r--tools/tmxcopy/map.cpp121
-rw-r--r--tools/tmxcopy/map.hpp51
-rw-r--r--tools/tmxcopy/readme.txt18
4 files changed, 233 insertions, 25 deletions
diff --git a/tools/tmxcopy/main.cpp b/tools/tmxcopy/main.cpp
index ac18ce04..4926d69f 100644
--- a/tools/tmxcopy/main.cpp
+++ b/tools/tmxcopy/main.cpp
@@ -1,6 +1,7 @@
/*
* TMXCopy
* Copyright (C) 2007 Philipp Sehmisch
+ * Copyright (C) 2009 Steve Cotton
*
* 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
@@ -19,34 +20,70 @@
#include <iostream>
#include <string>
+#include <unistd.h>
#include "map.hpp"
+void printUsage()
+{
+ std::cerr<<"Usage: tmxcopy [-c] [-n] srcFile x y width height tgtFile x y [outfile]"<<std::endl
+ <<" -c create layers, if they don't already exist in the target"<<std::endl
+ <<" -n copy layers by number, not name"<<std::endl;
+}
+
int main(int argc, char * argv[] )
{
- // parsing command line options
- if (argc < 9 || argc > 10)
+ ConfigurationOptions config = {0};
+ int opt;
+ while ((opt = getopt(argc, argv, "cn")) != -1)
+ {
+ switch (opt)
+ {
+ case 'c':
+ config.createMissingLayers = true;
+ break;
+ case 'n':
+ config.copyLayersByOrdinal = true;
+ break;
+ case '?':
+ std::cerr<<"Unrecognized option"<<std::endl;
+ printUsage();
+ return -1;
+ }
+ }
+
+ if ((argc-optind) < 8)
+ {
+ std::cerr<<"Too few args"<<std::endl;
+ printUsage();
+ return -1;
+ }
+ if ((argc-optind) > 9)
{
- std::cerr<<"Usage: srcFile x y width height tgtFile x y [outfile]\n";
+ std::cerr<<"Too many args"<<std::endl;
+ printUsage();
return -1;
}
- std::string srcFile = argv[1];
- int srcX= atoi(argv[2]);
- int srcY= atoi(argv[3]);
- int width= atoi(argv[4]);
- int height=atoi(argv[5]);
- std::string tgtFile = argv[6];
- int destX=atoi(argv[7]);
- int destY=atoi(argv[8]);
+ std::string srcFile = argv[optind+0];
+ int srcX= atoi(argv[optind+1]);
+ int srcY= atoi(argv[optind+2]);
+ int width= atoi(argv[optind+3]);
+ int height=atoi(argv[optind+4]);
+ std::string tgtFile = argv[optind+5];
+ int destX=atoi(argv[optind+6]);
+ int destY=atoi(argv[optind+7]);
std::string outFile = tgtFile;
- if (argc == 10) outFile = argv[9];
+ if (argc == optind+9)
+ {
+ outFile = argv[optind+8];
+ }
// plausibility check of command line options
if (height < 1 || width < 1 || srcX < 0 || srcY < 0 || destX < 0 || destY < 0)
{
std::cerr<<"Illegal coordinates!"<<std::endl;
- std::cerr<<"Usage: sourceFile x y height width targetFile x y [outputFile]"<<std::endl;
+ printUsage();
return -1;
}
@@ -54,16 +91,17 @@ int main(int argc, char * argv[] )
{
Map* srcMap = new Map(srcFile);
Map* tgtMap = new Map(tgtFile);
- if (tgtMap->overwrite(srcMap, srcX, srcY, width, height, destX, destY))
+ if (tgtMap->overwrite(srcMap, srcX, srcY, width, height, destX, destY, config))
{
tgtMap->save(outFile);
} else {
return -1;
}
+ delete srcMap;
+ delete tgtMap;
}
catch (int)
{
return -1;
}
-
}
diff --git a/tools/tmxcopy/map.cpp b/tools/tmxcopy/map.cpp
index d9fc8ada..75cbecbb 100644
--- a/tools/tmxcopy/map.cpp
+++ b/tools/tmxcopy/map.cpp
@@ -1,6 +1,7 @@
/*
* TMXCopy
* Copyright (C) 2007 Philipp Sehmisch
+ * Copyright (C) 2009 Steve Cotton
*
* 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
@@ -24,6 +25,7 @@
#include <string.h>
#include <zlib.h>
+#include <cassert>
#include "xmlutils.h"
#include "zlibutils.h"
@@ -80,9 +82,19 @@ Map::Map(std::string filename):
{
if (xmlStrEqual(node->name, BAD_CAST "layer"))
{
- Layer* layer = new Layer;
- layer->resize(mWidth * mHeight);
//build layer information
+ std::string name = XML::getProperty(node, "name", "");
+ Layer* layer = new Layer(name, mWidth * mHeight);
+ if (
+ (mWidth != XML::getProperty(node, "width" , 0)) ||
+ (mHeight != XML::getProperty(node, "height", 0)) ||
+ (0 != XML::getProperty(node, "x" , 0)) ||
+ (0 != XML::getProperty(node, "y" , 0)))
+ {
+ std::cerr<<"Error: layer size does not match map size for layer \""<<name<<"\" in "<<filename<<std::endl;
+ throw 1;
+ }
+
for_each_xml_child_node(dataNode, node)
{
if (!xmlStrEqual(dataNode->name, BAD_CAST "data")) continue;
@@ -155,7 +167,7 @@ Map::Map(std::string filename):
{
for (int s = mTilesets.size()-1; s >= 0; s--)
{
- if (mTilesets.at(s)->firstgid < gid)
+ if (mTilesets.at(s)->firstgid <= gid)
{
layer->at(c).tileset = s;
layer->at(c).index = gid - mTilesets.at(s)->firstgid;
@@ -184,7 +196,8 @@ Map::Map(std::string filename):
bool Map::overwrite( Map* srcMap,
int srcX, int srcY, int srcWidth, int srcHeight,
- int destX, int destY)
+ int destX, int destY,
+ const ConfigurationOptions& config)
{
//plausibility check of coordinates
bool checkPassed = true;
@@ -204,6 +217,32 @@ bool Map::overwrite( Map* srcMap,
std::cerr<<"Error: Area exceeds lower map border of target map!"<<std::endl;
checkPassed = false;
}
+ if (!config.createMissingLayers)
+ {
+ if (config.copyLayersByOrdinal)
+ {
+ if (srcMap->getNumberOfLayers() > mLayers.size()) {
+ std::cerr<<"Error: Source has more layers than target map"<<std::endl
+ <<"(and the command-line \"create layers\" option was not used)"<<std::endl;
+ checkPassed = false;
+ }
+ }
+ else
+ {
+ for (int i = 0; i < srcMap->getNumberOfLayers(); i++)
+ {
+ Layer* srcLayer = srcMap->getLayer(i);
+ Layer* destLayer = getLayer(srcLayer->getName());
+ if (!destLayer)
+ {
+ std::cerr<<"Error: target map has no layer named \""<<srcLayer->getName()<<"\""<<std::endl
+ <<"(and the command-line \"create layers\" option was not used)"<<std::endl;
+ checkPassed = false;
+ }
+ }
+ }
+ }
+
if (!checkPassed) return false;
std::map<int, int> translation;
@@ -234,7 +273,43 @@ bool Map::overwrite( Map* srcMap,
for (int i = 0; i < srcMap->getNumberOfLayers(); i++)
{
Layer* srcLayer = srcMap->getLayer(i);
- Layer* destLayer = mLayers.at(i);
+ Layer* destLayer = NULL;
+ if (config.copyLayersByOrdinal)
+ {
+ if (i < mLayers.size())
+ {
+ destLayer = mLayers.at(i);
+ }
+ }
+ else
+ {
+ destLayer = getLayer(srcLayer->getName());
+ }
+
+ if (!destLayer)
+ {
+ assert(config.createMissingLayers); /* Tested earlier, in the checkPassed section */
+ /* Generate a name for the new layer, which must be
+ * unique in the target map, and should be unique in
+ * the source map (to avoid collisions later in the
+ * copying process).
+ * Start by trying the name of the source layer.
+ */
+ std::string name = srcLayer->getName();
+ if (getLayer(name))
+ {
+ int k=0;
+ do
+ {
+ name = "Layer" + toString(k);
+ k++;
+ } while (getLayer(name) || srcMap->getLayer(name));
+ }
+
+ destLayer = new Layer(name, mWidth * mHeight);
+ mLayers.push_back(destLayer);
+ std::cout<<"Created new layer "<<name<<std::endl;
+ }
for (int y=0; y<srcHeight; y++)
{
@@ -340,7 +415,7 @@ int Map::save(std::string filename)
xmlNodePtr newNode;
xmlAddChild(rootNode, xmlNewDocText(mXmlDoc, BAD_CAST " "));
newNode = xmlNewNode(NULL, BAD_CAST "layer");
- xmlNewProp(newNode, BAD_CAST "name", BAD_CAST ("Layer" + toString(i)).c_str());
+ xmlNewProp(newNode, BAD_CAST "name", BAD_CAST (mLayers.at(i)->getName()).c_str());
xmlNewProp(newNode, BAD_CAST "width", BAD_CAST toString(mWidth).c_str());
xmlNewProp(newNode, BAD_CAST "height", BAD_CAST toString(mHeight).c_str());
xmlAddChild(newNode, xmlNewDocText(mXmlDoc, BAD_CAST "\n "));
@@ -354,6 +429,9 @@ int Map::save(std::string filename)
xmlAddChild(newNode, xmlNewDocText(mXmlDoc, BAD_CAST "\n "));
xmlAddChild(rootNode, newNode);
xmlAddChild(rootNode, xmlNewDocText(mXmlDoc, BAD_CAST "\n"));
+
+ free(base64Data);
+ free(binData);
}
//save XML tree
@@ -370,3 +448,34 @@ int Map::save(std::string filename)
return true;
}
}
+
+Layer* Map::getLayer(std::string name)
+{
+ for (std::vector<Layer*>::iterator layer = mLayers.begin();
+ layer != mLayers.end();
+ layer++)
+ {
+ if ((*layer)->getName() == name)
+ return *layer;
+ }
+ return NULL;
+}
+
+Map::~Map()
+{
+ for (std::vector<Layer*>::iterator layer = mLayers.begin();
+ layer != mLayers.end();
+ layer++)
+ {
+ delete *layer;
+ }
+
+ for (std::vector<Tileset*>::iterator tileset = mTilesets.begin();
+ tileset != mTilesets.end();
+ tileset++)
+ {
+ delete *tileset;
+ }
+
+ xmlFreeDoc(mXmlDoc);
+}
diff --git a/tools/tmxcopy/map.hpp b/tools/tmxcopy/map.hpp
index 2ca9061a..af2f5385 100644
--- a/tools/tmxcopy/map.hpp
+++ b/tools/tmxcopy/map.hpp
@@ -1,6 +1,7 @@
/*
* TMXCopy
* Copyright (C) 2007 Philipp Sehmisch
+ * Copyright (C) 2009 Steve Cotton
*
* 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
@@ -22,6 +23,22 @@
#include <set>
#include <libxml/parser.h>
+struct ConfigurationOptions
+{
+ /* When copying map layers, how to match source layer to
+ * destination layer.
+ *
+ * True: Pair the first layer to the first layer, the second
+ * to the second, etc.
+ *
+ * False: Pair up layers with matching names.
+ */
+ bool copyLayersByOrdinal;
+
+ /* Create extra layers in the target as necessary. */
+ bool createMissingLayers;
+};
+
struct Tileset
{
std::string imagefile;
@@ -45,22 +62,50 @@ struct Tile
size_t index; // index in said tileset
};
-typedef std::vector<Tile> Layer;
+typedef std::vector<Tile> LayerTiles;
+
+/* This represents an empty tile in the layer.
+ * Note that {0,0} would be the first tile in the first tileset.
+ */
+const Tile defaultTile = {-1, 0};
+
+class Layer
+{
+ public:
+ /* name - the name of the layer, as shown in Tiled
+ * tileCount - total number of tiles (width*height)
+ */
+ Layer(std::string name, LayerTiles::size_type tileCount)
+ : mTiles(tileCount, defaultTile),
+ mName (name)
+ {
+ }
+
+ std::string getName() { return mName; }
+ Tile& at(LayerTiles::size_type c) { return mTiles.at(c); }
+
+ private:
+ LayerTiles mTiles;
+ std::string mName;
+};
class Map
{
public:
Map(std::string filename);
+ ~Map();
- bool overwrite( Map* srcMap,
+ bool overwrite(Map* srcMap,
int srcX, int srcY, int srcWidth, int srcHeight,
- int destX, int destY);
+ int destX, int destY,
+ const ConfigurationOptions& config);
int save(std::string filename);
int getNumberOfLayers() { return mLayers.size(); }
Layer* getLayer(size_t num) { return mLayers.at(num); }
+ Layer* getLayer(std::string name);
std::vector<Tileset*>* getTilesets() { return &mTilesets; }
diff --git a/tools/tmxcopy/readme.txt b/tools/tmxcopy/readme.txt
index e4235b94..e8ec830a 100644
--- a/tools/tmxcopy/readme.txt
+++ b/tools/tmxcopy/readme.txt
@@ -23,6 +23,22 @@ But when you enter this command the mapB will be overwritten. This could be a pr
Now we can check temp.tmx to see if the copying worked correctly.
+Which layer gets copied to which:
+By default layers are copied to layers of the same name. The -n option will make it copy by layer number instead.
+
+ mapA: Ground, Fringe, Over, Collision, Object
+ mapB: Ground, Fencing, Fringe, Over, Collision, Object
+ The default copies Ground->Ground, Fringe->Fringe, Over->Over, Collision->Collision (the object layer is not affected)
+ -n copies Ground->Ground, Fringe->Fencing, Over->Fringe, Collision->Over (mapB's collision and object layers are not affected)
+
+ mapA: Ground, Fringe, Over, Collision, Object
+ mapC: Ground, Fringe, Overhead, Collision, Object
+ The default quits with an error
+ -n copies Over->Overhead
+
+The -c option creates layers as needed. Using it to copy mapB to mapA will add a Fencing layer to mapA.
+
+
The program works so far but there are still some minor problems:
-Only tested for TMW-compilant maps. I don't guarantee that it works with Tiled maps that are made for other games and thus use different features. It is assumed that the target map and the source maps have the same number of layers, for example.
@@ -31,4 +47,4 @@ The program works so far but there are still some minor problems:
-Layer data of output file isn't gzip-compressed yet
-Created TMX file is a bit malformated (but working properly)
-The last 2 problems can be solved easily by opening and saving the map in Tiled. \ No newline at end of file
+The last 2 problems can be solved easily by opening and saving the map in Tiled.