Skip to content

Commit

Permalink
Added support for .world files in tmxrasterizer (mapeditor#2067)
Browse files Browse the repository at this point in the history
  • Loading branch information
RainingChain authored and Ruin0x11 committed May 15, 2019
1 parent 1231574 commit 33a8ca6
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 55 deletions.
8 changes: 4 additions & 4 deletions src/libtiled/worldmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,14 +160,14 @@ std::unique_ptr<World> WorldManager::privateLoadWorld(const QString &fileName,
/**
* Loads the world with the given \a fileName.
*
* \returns whether the world was loaded succesfully, optionally setting
* \returns the world if it was loaded succesfully, optionally setting
* \a errorString when not.
*/
bool WorldManager::loadWorld(const QString &fileName, QString *errorString)
World *WorldManager::loadWorld(const QString &fileName, QString *errorString)
{
auto world = privateLoadWorld(fileName, errorString);
if (!world)
return false;
return nullptr;

if (mWorlds.contains(fileName))
delete mWorlds.take(fileName);
Expand All @@ -177,7 +177,7 @@ bool WorldManager::loadWorld(const QString &fileName, QString *errorString)
mWorlds.insert(fileName, world.release());
emit worldsChanged();

return true;
return mWorlds.value(fileName);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/libtiled/worldmanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ class TILEDSHARED_EXPORT WorldManager : public QObject
static WorldManager &instance();
static void deleteInstance();

bool loadWorld(const QString &fileName, QString *errorString = nullptr);
World *loadWorld(const QString &fileName, QString *errorString = nullptr);
void unloadWorld(const QString &fileName);

const QMap<QString, World*> &worlds() const { return mWorlds; }
Expand Down
2 changes: 1 addition & 1 deletion src/tmxrasterizer/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ int main(int argc, char *argv[])
app.setApplicationVersion(QLatin1String("1.0"));

QCommandLineParser parser;
parser.setApplicationDescription(QCoreApplication::translate("main", "Renders a Tiled map (TMX format) to an image."));
parser.setApplicationDescription(QCoreApplication::translate("main", "Renders a Tiled map (TMX format) or a World map (WORLD format) to an image."));
parser.addHelpOption();
parser.addVersionOption();
parser.addOptions({
Expand Down
188 changes: 141 additions & 47 deletions src/tmxrasterizer/tmxrasterizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "orthogonalrenderer.h"
#include "staggeredrenderer.h"
#include "tilelayer.h"
#include "worldmanager.h"

#include <QDebug>
#include <QImageWriter>
Expand All @@ -45,6 +46,21 @@

using namespace Tiled;

static std::unique_ptr<MapRenderer> createRenderer(Map &map)
{
switch (map.orientation()) {
case Map::Isometric:
return std::unique_ptr<MapRenderer>(new IsometricRenderer(&map));
case Map::Staggered:
return std::unique_ptr<MapRenderer>(new StaggeredRenderer(&map));
case Map::Hexagonal:
return std::unique_ptr<MapRenderer>(new HexagonalRenderer(&map));
case Map::Orthogonal:
default:
return std::unique_ptr<MapRenderer>(new OrthogonalRenderer(&map));
}
}

TmxRasterizer::TmxRasterizer():
mScale(1.0),
mTileSize(0),
Expand All @@ -55,6 +71,34 @@ TmxRasterizer::TmxRasterizer():
{
}

void TmxRasterizer::drawMapLayers(MapRenderer &renderer,
QPainter &painter,
Map &map,
QPoint mapOffset) const
{
// Perform a similar rendering than found in exportasimagedialog.cpp
LayerIterator iterator(&map);
while (const Layer *layer = iterator.next()) {
if (!shouldDrawLayer(layer))
continue;

const auto offset = layer->totalOffset() + mapOffset;
painter.setOpacity(layer->effectiveOpacity());
painter.translate(offset);

const TileLayer *tileLayer = dynamic_cast<const TileLayer*>(layer);
const ImageLayer *imageLayer = dynamic_cast<const ImageLayer*>(layer);

if (tileLayer) {
renderer.drawTileLayer(&painter, tileLayer);
} else if (imageLayer) {
renderer.drawImageLayer(&painter, imageLayer);
}

painter.translate(-offset);
}
}

bool TmxRasterizer::shouldDrawLayer(const Layer *layer) const
{
if (layer->isObjectGroup() || layer->isGroupLayer())
Expand All @@ -69,8 +113,17 @@ bool TmxRasterizer::shouldDrawLayer(const Layer *layer) const
return !layer->isHidden();
}

int TmxRasterizer::render(const QString &mapFileName,
int TmxRasterizer::render(const QString &fileName,
const QString &imageFileName)
{
if (fileName.endsWith(".world", Qt::CaseInsensitive))
return renderWorld(fileName, imageFileName);
else
return renderMap(fileName, imageFileName);
}

int TmxRasterizer::renderMap(const QString &mapFileName,
const QString &imageFileName)
{
MapReader reader;
std::unique_ptr<Map> map { reader.readMap(mapFileName) };
Expand All @@ -81,36 +134,19 @@ int TmxRasterizer::render(const QString &mapFileName,
return 1;
}

std::unique_ptr<MapRenderer> renderer;

switch (map->orientation()) {
case Map::Isometric:
renderer.reset(new IsometricRenderer(map.get()));
break;
case Map::Staggered:
renderer.reset(new StaggeredRenderer(map.get()));
break;
case Map::Hexagonal:
renderer.reset(new HexagonalRenderer(map.get()));
break;
case Map::Orthogonal:
default:
renderer.reset(new OrthogonalRenderer(map.get()));
break;
}

std::unique_ptr<MapRenderer> renderer = createRenderer(*map);
QRect mapBoundingRect = renderer->mapBoundingRect();
QSize mapSize = mapBoundingRect.size();
QPoint mapOffset = mapBoundingRect.topLeft();
qreal xScale, yScale;

if (mSize > 0) {
xScale = (qreal) mSize / mapSize.width();
yScale = (qreal) mSize / mapSize.height();
xScale = static_cast<qreal>(mSize) / mapSize.width();
yScale = static_cast<qreal>(mSize) / mapSize.height();
xScale = yScale = qMin(1.0, qMin(xScale, yScale));
} else if (mTileSize > 0) {
xScale = (qreal) mTileSize / map->tileWidth();
yScale = (qreal) mTileSize / map->tileHeight();
xScale = static_cast<qreal>(mTileSize) / map->tileWidth();
yScale = static_cast<qreal>(mTileSize) / map->tileHeight();
} else {
xScale = yScale = mScale;
}
Expand All @@ -133,32 +169,15 @@ int TmxRasterizer::render(const QString &mapFileName,
painter.translate(margins.left(), margins.top());
painter.translate(-mapOffset);

// Perform a similar rendering than found in exportasimagedialog.cpp
LayerIterator iterator(map.get());
while (const Layer *layer = iterator.next()) {
if (!shouldDrawLayer(layer))
continue;

const auto offset = layer->totalOffset();

painter.setOpacity(layer->effectiveOpacity());
painter.translate(offset);

const TileLayer *tileLayer = dynamic_cast<const TileLayer*>(layer);
const ImageLayer *imageLayer = dynamic_cast<const ImageLayer*>(layer);

if (tileLayer) {
renderer->drawTileLayer(&painter, tileLayer);
} else if (imageLayer) {
renderer->drawImageLayer(&painter, imageLayer);
}

painter.translate(-offset);
}

drawMapLayers(*renderer, painter, *map);
map.reset();
return saveImage(imageFileName, image);
}


// Save image
int TmxRasterizer::saveImage(const QString &imageFileName,
const QImage &image) const
{
QImageWriter imageWriter(imageFileName);

if (!imageWriter.canWrite())
Expand All @@ -173,3 +192,78 @@ int TmxRasterizer::render(const QString &mapFileName,

return 0;
}

int TmxRasterizer::renderWorld(const QString &worldFileName,
const QString &imageFileName)
{
WorldManager &worldManager = WorldManager::instance();
QString errorString;
const World *world = worldManager.loadWorld(worldFileName, &errorString);
if (!world) {
qWarning("Error loading the world file \"%s\":\n%s",
qUtf8Printable(worldFileName),
qUtf8Printable(errorString));
return 1;
}

auto const maps = world->allMaps();
if (maps.isEmpty()) {
qWarning("Error: The world file to rasterize contains no maps : \"%s\"",
qUtf8Printable(worldFileName));
return 1;
}
QRect worldBoundingRect;
MapReader reader;
for (const World::MapEntry &mapEntry : maps) {
std::unique_ptr<Map> map { reader.readMap(mapEntry.fileName) };
if (!map) {
qWarning("Error while reading \"%s\":\n%s",
qUtf8Printable(mapEntry.fileName),
qUtf8Printable(reader.errorString()));
continue;
}
std::unique_ptr<MapRenderer> renderer = createRenderer(*map);
QRect mapBoundingRect = renderer->mapBoundingRect();
mapBoundingRect.translate(mapEntry.rect.topLeft());

worldBoundingRect = worldBoundingRect.united(mapBoundingRect);
}

QSize worldSize = worldBoundingRect.size();
qreal xScale, yScale;
if (mSize > 0) {
xScale = static_cast<qreal>(mSize) / worldSize.width();
yScale = static_cast<qreal>(mSize) / worldSize.height();
xScale = yScale = qMin(1.0, qMin(xScale, yScale));
} else {
xScale = yScale = mScale;
}

worldSize.rwidth() *= xScale;
worldSize.rheight() *= yScale;
QImage image(worldSize, QImage::Format_ARGB32);
image.fill(Qt::transparent);
QPainter painter(&image);

painter.setRenderHint(QPainter::Antialiasing, mUseAntiAliasing);
painter.setRenderHint(QPainter::SmoothPixmapTransform, mSmoothImages);
painter.setTransform(QTransform::fromScale(xScale, yScale));

painter.translate(-worldBoundingRect.topLeft());

for (const World::MapEntry &mapEntry : maps) {
MapReader reader;
std::unique_ptr<Map> map { reader.readMap(mapEntry.fileName) };
if (!map) {
qWarning("Error while reading \"%s\":\n%s",
qUtf8Printable(mapEntry.fileName),
qUtf8Printable(reader.errorString()));
return 1;
}

std::unique_ptr<MapRenderer> renderer = createRenderer(*map);
drawMapLayers(*renderer, painter, *map, mapEntry.rect.topLeft());
}

return saveImage(imageFileName, image);
}
13 changes: 11 additions & 2 deletions src/tmxrasterizer/tmxrasterizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,16 @@

#include "layer.h"

#include "map.h"
#include "mapreader.h"
#include <QString>
#include <QStringList>

using namespace Tiled;

class QImage;
class QPainter;

class TmxRasterizer
{

Expand All @@ -46,7 +51,7 @@ class TmxRasterizer
int size() const { return mSize; }
bool useAntiAliasing() const { return mUseAntiAliasing; }
bool smoothImages() const { return mSmoothImages; }
bool IgnoreVisibility() const { return mIgnoreVisibility; }
bool ignoreVisibility() const { return mIgnoreVisibility; }

void setScale(qreal scale) { mScale = scale; }
void setTileSize(int tileSize) { mTileSize = tileSize; }
Expand All @@ -57,7 +62,7 @@ class TmxRasterizer

void setLayersToHide(QStringList layersToHide) { mLayersToHide = layersToHide; }

int render(const QString &mapFileName, const QString &imageFileName);
int render(const QString &fileName, const QString &imageFileName);

private:
qreal mScale;
Expand All @@ -68,5 +73,9 @@ class TmxRasterizer
bool mIgnoreVisibility;
QStringList mLayersToHide;

void drawMapLayers(MapRenderer &renderer, QPainter &painter, Map &map, QPoint mapOffset = QPoint(0, 0)) const;
int renderMap(const QString &mapFileName, const QString &imageFileName);
int renderWorld(const QString &worldFileName, const QString &imageFileName);
int saveImage(const QString &imageFileName, const QImage &image) const;
bool shouldDrawLayer(const Layer *layer) const;
};

0 comments on commit 33a8ca6

Please sign in to comment.