Skip to content

Commit

Permalink
#5346: Extract the IMapExporter interface, and add IMap::createMapExp…
Browse files Browse the repository at this point in the history
…orter method to return an instance to enable the game connection plugin to export the scene.
  • Loading branch information
codereader committed Sep 28, 2020
1 parent d6b6a8f commit 94453b0
Show file tree
Hide file tree
Showing 10 changed files with 88 additions and 27 deletions.
8 changes: 8 additions & 0 deletions include/imap.h
Expand Up @@ -2,6 +2,8 @@

#include "imodule.h"
#include "inode.h"
#include "imapexporter.h"
#include "imapformat.h"
#include "ikeyvaluestore.h"
#include <sigc++/signal.h>

Expand Down Expand Up @@ -152,6 +154,12 @@ class IMap :
// Caution: this is upposed to be called on startup, since it doesn't ask the user
// whether to save the current map. Use the "NewMap" command for regular purposes.
virtual void createNewMap() = 0;

// Create a MapExporter instance which can be used to export a scene,
// including the necessary preparation, info-file handling, etc.
// This is mainly a service method for external code, like the gameconnection.
virtual map::IMapExporter::Ptr createMapExporter(map::IMapWriter& writer,
const scene::IMapRootNodePtr& root, std::ostream& mapStream) = 0;
};
typedef std::shared_ptr<IMap> IMapPtr;

Expand Down
33 changes: 33 additions & 0 deletions include/imapexporter.h
@@ -0,0 +1,33 @@
#pragma once

#include <memory>
#include "inode.h"
#include "imapformat.h"

namespace map
{

/**
* Exporter class used to serialise a map to an output stream.
* Use the given exportMap() method to write a scene to the
* attached stream. For scene traversal the given functor
* is used to allow for custom filtering of the scene nodes.
*
* Use GlobalMapModule().createMapExporter() to acquire an
* instance of IMapExporter.
*
* Note: This is a scoped object by design, which will prepare
* the scene during construction and clean it up on destruction.
*/
class IMapExporter
{
public:
using Ptr = std::shared_ptr<IMapExporter>;

virtual ~IMapExporter() {}

// Export the scene below the given root node using the given traversal function
virtual void exportMap(const scene::INodePtr& root, const GraphTraversalFunc& traverse) = 0;
};

}
11 changes: 9 additions & 2 deletions plugins/dm.gameconnection/GameConnection.cpp
Expand Up @@ -11,6 +11,8 @@
#include "iuimanager.h"
#include "ieventmanager.h"

#include "scene/Traverse.h"

#include <sigc++/signal.h>
#include <sigc++/connection.h>

Expand Down Expand Up @@ -478,8 +480,13 @@ std::string saveMapDiff(const DiffEntityStatuses& entityStatuses)
}

//write added/modified entities as usual
//TODO map::MapExporterPtr exporter(new map::MapExporter(writer, root, outStream, 0));
//TODO exporter->exportMap(root, map::traverseSubset(subsetNodes));
{
// Get a scoped exporter class
auto exporter = GlobalMapModule().createMapExporter(writer, root, outStream);
exporter->exportMap(root, scene::traverseSubset(subsetNodes));

// end the life of the exporter instance here to finish the scene
}

return outStream.str();
}
Expand Down
8 changes: 7 additions & 1 deletion radiantcore/map/Map.cpp
Expand Up @@ -377,6 +377,12 @@ void Map::createNewMap()
focusViews(Vector3(0,0,0), Vector3(0,0,0));
}

IMapExporter::Ptr Map::createMapExporter(IMapWriter& writer,
const scene::IMapRootNodePtr& root, std::ostream& mapStream)
{
return std::make_shared<MapExporter>(writer, root, mapStream, 0);
}

bool Map::import(const std::string& filename)
{
radiant::ScopedLongRunningOperation blocker(_("Importing..."));
Expand Down Expand Up @@ -819,7 +825,7 @@ void Map::exportSelected(std::ostream& out, const MapFormatPtr& format)
assert(format);

// Create our main MapExporter walker for traversal
MapExporter exporter(*format, GlobalSceneGraph().root(), out);
MapExporter exporter(*format->getMapWriter(), GlobalSceneGraph().root(), out);

// Pass the traverseSelected function and start writing selected nodes
exporter.exportMap(GlobalSceneGraph().root(), scene::traverseSelected);
Expand Down
3 changes: 3 additions & 0 deletions radiantcore/map/Map.h
Expand Up @@ -172,6 +172,9 @@ class Map :
// greebo: Creates a new, empty map file.
void createNewMap() override;

IMapExporter::Ptr createMapExporter(IMapWriter& writer,
const scene::IMapRootNodePtr& root, std::ostream& mapStream) override;

// Accessor methods for the worldspawn node
void setWorldspawn(const scene::INodePtr& node);

Expand Down
7 changes: 4 additions & 3 deletions radiantcore/map/MapResource.cpp
Expand Up @@ -513,14 +513,15 @@ void MapResource::saveFile(const MapFormat& format, const scene::IMapRootNodePtr
// and the destructor will clean it up afterwards. That way
// we ensure a nice and tidy scene when exceptions are thrown.
MapExporterPtr exporter;

auto mapWriter = format.getMapWriter();

if (format.allowInfoFileCreation())
{
exporter.reset(new MapExporter(format, root, outFileStream, *auxFileStream, counter.getCount()));
exporter.reset(new MapExporter(*mapWriter, root, outFileStream, *auxFileStream, counter.getCount()));
}
else
{
exporter.reset(new MapExporter(format, root, outFileStream, counter.getCount())); // no aux stream
exporter.reset(new MapExporter(*mapWriter, root, outFileStream, counter.getCount())); // no aux stream
}

try
Expand Down
24 changes: 12 additions & 12 deletions radiantcore/map/algorithm/MapExporter.cpp
Expand Up @@ -25,8 +25,8 @@ namespace map
const char* const RKEY_MAP_SAVE_STATUS_INTERLEAVE = "user/ui/map/saveStatusInterleave";
}

MapExporter::MapExporter(const MapFormat& format, const scene::IMapRootNodePtr& root, std::ostream& mapStream, std::size_t nodeCount) :
_writer(format.getMapWriter()),
MapExporter::MapExporter(IMapWriter& writer, const scene::IMapRootNodePtr& root, std::ostream& mapStream, std::size_t nodeCount) :
_writer(writer),
_mapStream(mapStream),
_root(root),
_dialogEventLimiter(registry::getValue<int>(RKEY_MAP_SAVE_STATUS_INTERLEAVE)),
Expand All @@ -38,9 +38,9 @@ MapExporter::MapExporter(const MapFormat& format, const scene::IMapRootNodePtr&
construct();
}

MapExporter::MapExporter(const MapFormat& format, const scene::IMapRootNodePtr& root,
MapExporter::MapExporter(IMapWriter& writer, const scene::IMapRootNodePtr& root,
std::ostream& mapStream, std::ostream& auxStream, std::size_t nodeCount) :
_writer(format.getMapWriter()),
_writer(writer),
_mapStream(mapStream),
_infoFileExporter(new InfoFileExporter(auxStream)),
_root(root),
Expand Down Expand Up @@ -93,7 +93,7 @@ void MapExporter::exportMap(const scene::INodePtr& root, const GraphTraversalFun
throw std::logic_error("Map node is not a scene::IMapRootNode");
}

_writer->beginWriteMap(mapRoot, _mapStream);
_writer.beginWriteMap(mapRoot, _mapStream);

if (_infoFileExporter)
{
Expand All @@ -117,7 +117,7 @@ void MapExporter::exportMap(const scene::INodePtr& root, const GraphTraversalFun
throw std::logic_error("Map node is not a scene::IMapRootNode");
}

_writer->endWriteMap(mapRoot, _mapStream);
_writer.endWriteMap(mapRoot, _mapStream);

if (_infoFileExporter)
{
Expand All @@ -143,7 +143,7 @@ bool MapExporter::pre(const scene::INodePtr& node)
// Progress dialog handling
onNodeProgress();

_writer->beginWriteEntity(entity, _mapStream);
_writer.beginWriteEntity(entity, _mapStream);

if (_infoFileExporter) _infoFileExporter->visitEntity(node, _entityNum);

Expand All @@ -157,7 +157,7 @@ bool MapExporter::pre(const scene::INodePtr& node)
// Progress dialog handling
onNodeProgress();

_writer->beginWriteBrush(brush, _mapStream);
_writer.beginWriteBrush(brush, _mapStream);

if (_infoFileExporter) _infoFileExporter->visitPrimitive(node, _entityNum, _primitiveNum);

Expand All @@ -171,7 +171,7 @@ bool MapExporter::pre(const scene::INodePtr& node)
// Progress dialog handling
onNodeProgress();

_writer->beginWritePatch(patch, _mapStream);
_writer.beginWritePatch(patch, _mapStream);

if (_infoFileExporter) _infoFileExporter->visitPrimitive(node, _entityNum, _primitiveNum);

Expand All @@ -194,7 +194,7 @@ void MapExporter::post(const scene::INodePtr& node)

if (entity)
{
_writer->endWriteEntity(entity, _mapStream);
_writer.endWriteEntity(entity, _mapStream);

_entityNum++;
return;
Expand All @@ -204,7 +204,7 @@ void MapExporter::post(const scene::INodePtr& node)

if (brush && brush->getIBrush().hasContributingFaces())
{
_writer->endWriteBrush(brush, _mapStream);
_writer.endWriteBrush(brush, _mapStream);
_primitiveNum++;
return;
}
Expand All @@ -213,7 +213,7 @@ void MapExporter::post(const scene::INodePtr& node)

if (patch)
{
_writer->endWritePatch(patch, _mapStream);
_writer.endWritePatch(patch, _mapStream);
_primitiveNum++;
return;
}
Expand Down
12 changes: 7 additions & 5 deletions radiantcore/map/algorithm/MapExporter.h
@@ -1,6 +1,7 @@
#pragma once

#include "inode.h"
#include "imapexporter.h"
#include "imapformat.h"
#include "imap.h"
#include "igame.h"
Expand All @@ -25,11 +26,12 @@ namespace map
* the calling code needs to be able to handle that.
*/
class MapExporter :
public IMapExporter,
public scene::NodeVisitor
{
private:
// The map format exporter
IMapWriterPtr _writer;
// For writing nodes to the stream
IMapWriter& _writer;

// The stream we're writing to
std::ostream& _mapStream;
Expand All @@ -53,18 +55,18 @@ class MapExporter :

public:
// The constructor prepares the scene and the output stream
MapExporter(const MapFormat& format, const scene::IMapRootNodePtr& root,
MapExporter(IMapWriter& writer, const scene::IMapRootNodePtr& root,
std::ostream& mapStream, std::size_t nodeCount = 0);

// Additional constructor allowed to write to the auxiliary .darkradiant file
MapExporter(const MapFormat& format, const scene::IMapRootNodePtr& root,
MapExporter(IMapWriter& writer, const scene::IMapRootNodePtr& root,
std::ostream& mapStream, std::ostream& auxStream, std::size_t nodeCount = 0);

// Cleans up the scene on destruction
~MapExporter();

// Entry point for traversing the given root node using the given traversal function
void exportMap(const scene::INodePtr& root, const GraphTraversalFunc& traverse);
void exportMap(const scene::INodePtr& root, const GraphTraversalFunc& traverse) override;

// NodeVisitor implementation, is called by the traversal func passed to MapResource
bool pre(const scene::INodePtr& node) override;
Expand Down
8 changes: 4 additions & 4 deletions tools/msvc/dm.gameconnection.vcxproj
Expand Up @@ -89,30 +89,30 @@
<ClCompile />
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>scenelib.lib;wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile />
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>scenelib.lib;wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile />
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>scenelib.lib;wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile />
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>scenelib.lib;wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
Expand Down
1 change: 1 addition & 0 deletions tools/msvc/include.vcxproj
Expand Up @@ -139,6 +139,7 @@
<ClInclude Include="..\..\include\imainframe.h" />
<ClInclude Include="..\..\include\imainframelayout.h" />
<ClInclude Include="..\..\include\imap.h" />
<ClInclude Include="..\..\include\imapexporter.h" />
<ClInclude Include="..\..\include\imapformat.h" />
<ClInclude Include="..\..\include\imapinfofile.h" />
<ClInclude Include="..\..\include\imapresource.h" />
Expand Down

0 comments on commit 94453b0

Please sign in to comment.