Skip to content

Commit

Permalink
Move map merge functions to Import.h file. Rename and refactor a few …
Browse files Browse the repository at this point in the history
…classes to reduce code duplication.
  • Loading branch information
codereader committed Mar 10, 2020
1 parent 84c8feb commit f0ed1c9
Show file tree
Hide file tree
Showing 7 changed files with 155 additions and 189 deletions.
33 changes: 18 additions & 15 deletions libs/scenelib.h
Expand Up @@ -23,45 +23,48 @@ inline bool Node_isPrimitive(const scene::INodePtr& node)
namespace scene
{

class ParentPrimitives :
// Reparents every visited primitive to the parent in the constructor arguments
class PrimitiveReparentor :
public scene::NodeVisitor
{
private:
scene::INodePtr _parent;

public:
ParentPrimitives(const scene::INodePtr& parent) :
PrimitiveReparentor(const scene::INodePtr& parent) :
_parent(parent)
{}

virtual bool pre(const scene::INodePtr& node)
virtual bool pre(const scene::INodePtr& node) override
{
return false;
}

virtual void post(const scene::INodePtr& node)
virtual void post(const scene::INodePtr& node) override
{
if (Node_isPrimitive(node))
if (!Node_isPrimitive(node))
{
// We need to keep the hard reference to the node, such that the refcount doesn't reach 0
scene::INodePtr nodeRef = node;
return;
}

scene::INodePtr oldParent = nodeRef->getParent();
// We need to keep the hard reference to the node, such that the refcount doesn't reach 0
scene::INodePtr nodeRef = node;

if (oldParent)
{
// greebo: remove the node from the old parent first
oldParent->removeChildNode(nodeRef);
}
scene::INodePtr oldParent = nodeRef->getParent();

_parent->addChildNode(nodeRef);
if (oldParent)
{
// greebo: remove the node from the old parent first
oldParent->removeChildNode(nodeRef);
}

_parent->addChildNode(nodeRef);
}
};

inline void parentPrimitives(const scene::INodePtr& subgraph, const scene::INodePtr& parent)
{
ParentPrimitives visitor(parent);
PrimitiveReparentor visitor(parent);
subgraph->traverseChildren(visitor);
}

Expand Down
3 changes: 1 addition & 2 deletions radiant/map/Map.cpp
Expand Up @@ -39,7 +39,6 @@
#include "map/StartupMapLoader.h"
#include "map/RootNode.h"
#include "map/MapResource.h"
#include "map/algorithm/Merge.h"
#include "map/algorithm/Import.h"
#include "map/algorithm/Export.h"
#include "map/algorithm/Traverse.h"
Expand Down Expand Up @@ -480,7 +479,7 @@ bool Map::import(const std::string& filename)
// Adjust all new names to fit into the existing map namespace
algorithm::prepareNamesForImport(getRoot(), otherRoot);

MergeMap(otherRoot);
algorithm::mergeMap(otherRoot);
success = true;
}
}
Expand Down
139 changes: 133 additions & 6 deletions radiant/map/algorithm/Import.cpp
Expand Up @@ -4,11 +4,12 @@
#include "imapformat.h"
#include "inamespace.h"
#include "ientity.h"
#include "iscenegraph.h"
#include "scene/BasicRootNode.h"
#include "map/algorithm/ChildPrimitives.h"
#include "map/algorithm/Merge.h"
#include "map/Map.h"
#include "scenelib.h"
#include "entitylib.h"
#include "wxutil/dialog/MessageBox.h"

namespace map
Expand All @@ -17,6 +18,134 @@ namespace map
namespace algorithm
{

class PrimitiveMerger :
public scene::PrimitiveReparentor
{
public:
PrimitiveMerger(const scene::INodePtr& newParent) :
PrimitiveReparentor(newParent)
{}

void post(const scene::INodePtr& node) override
{
// Base class is doing the reparenting
PrimitiveReparentor::post(node);

// After reparenting, highlight the imported node
Node_setSelected(node, true);

// Re-generate the group IDs of this node
// TODO
}
};

class EntityMerger :
public scene::NodeVisitor
{
private:
// The target path
mutable scene::Path _path;

public:
EntityMerger(const scene::INodePtr& root) :
_path(scene::Path(root))
{}

bool pre(const scene::INodePtr& originalNode) override
{
// The removeChildNode below might destroy the instance - push the refcount
scene::INodePtr node = originalNode;

// greebo: Check if the visited node is the worldspawn of the other map
if (Node_isWorldspawn(node))
{
// Find the worldspawn of the target map
const scene::INodePtr& worldSpawn = GlobalMap().getWorldspawn();

if (!worldSpawn)
{
// Set the worldspawn to the new node
GlobalMap().setWorldspawn(node);

// greebo: Un-register the node from its previous parent first to be clean
scene::INodePtr oldParent = node->getParent();

if (oldParent)
{
oldParent->removeChildNode(node);
}

// Insert the visited node at the target path
_path.top()->addChildNode(node);

_path.push(node);

// Select all the children of the visited node (these are primitives)
node->foreachNode([](const scene::INodePtr& child)->bool
{
Node_setSelected(child, true);
return true;
});
}
else
{
// The target map already has a worldspawn
_path.push(worldSpawn);

// Move all children of this node to the target worldspawn
PrimitiveMerger visitor(worldSpawn);
node->traverseChildren(visitor);
}
}
else
{
// This is an ordinary entity, not worldspawn

// greebo: Un-register the entity from its previous root node first to be clean
scene::INodePtr oldParent = node->getParent();

if (oldParent)
{
oldParent->removeChildNode(node);
}

// Insert this node at the target path
_path.top()->addChildNode(node);
_path.push(node);

// Select the visited node
Node_setSelected(node, true);
}

// Only traverse top-level entities, don't traverse the children
return false;
}

void post(const scene::INodePtr& node) override
{
// Re-generate the group IDs of this entity node
// TODO

_path.pop();
}
};

void mergeMap(const scene::INodePtr& node)
{
// Discard all layer information found in the data to be merged
// We move everything into the active layer
{
scene::LayerList layers;
layers.insert(GlobalLayerSystem().getActiveLayer());

scene::AssignNodeToLayersWalker walker(layers);
node->traverse(walker);
}

EntityMerger merger(GlobalSceneGraph().root());
node->traverseChildren(merger);
}

void prepareNamesForImport(const scene::IMapRootNodePtr& targetRoot, const scene::INodePtr& foreignRoot)
{
const auto& nspace = targetRoot->getNamespace();
Expand Down Expand Up @@ -91,10 +220,8 @@ class SimpleMapImportFilter :
entity->addChildNode(primitive);
return true;
}
else
{
return false;
}

return false;
}
};

Expand Down Expand Up @@ -125,7 +252,7 @@ void importFromStream(std::istream& stream)
// Adjust all new names to fit into the existing map namespace
prepareNamesForImport(GlobalMap().getRoot(), importFilter.getRootNode());

MergeMap(importFilter.getRootNode());
mergeMap(importFilter.getRootNode());
}
catch (IMapReader::FailureException& ex)
{
Expand Down
3 changes: 3 additions & 0 deletions radiant/map/algorithm/Import.h
Expand Up @@ -20,6 +20,9 @@ typedef std::shared_ptr<MapFormat> MapFormatPtr;
namespace algorithm
{

// Merges the map graph rooted at \p node into the global scene-graph.
void mergeMap(const scene::INodePtr& node);

/**
* Ensures that all names in the foreign root node are adjusted such that
* they don't conflict with any names in the target root's namespace, while keeping
Expand Down

0 comments on commit f0ed1c9

Please sign in to comment.