Skip to content

Commit

Permalink
Expand the map marge/import code to handle incoming selection group a…
Browse files Browse the repository at this point in the history
…ssignments, assigning new group IDs not in conflict with the target scene.
  • Loading branch information
codereader committed Mar 10, 2020
1 parent 51aa21b commit 9b07599
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 11 deletions.
2 changes: 1 addition & 1 deletion include/iselectiongroup.h
Expand Up @@ -30,7 +30,7 @@ class IGroupSelectable :

// Returns all group assignments of this node
// The most recently added group is at the back of the list
virtual const GroupIds& getGroupIds() = 0;
virtual const GroupIds& getGroupIds() const = 0;

// Special overload to control whether this selectable should propagate
// the status change to the group it belongs to.
Expand Down
2 changes: 1 addition & 1 deletion libs/scene/SelectableNode.cpp
Expand Up @@ -126,7 +126,7 @@ std::size_t SelectableNode::getMostRecentGroupId()
return _groups.back();
}

const SelectableNode::GroupIds& SelectableNode::getGroupIds()
const SelectableNode::GroupIds& SelectableNode::getGroupIds() const
{
return _groups;
}
Expand Down
2 changes: 1 addition & 1 deletion libs/scene/SelectableNode.h
Expand Up @@ -51,7 +51,7 @@ class SelectableNode :

virtual bool isGroupMember() override;
virtual std::size_t getMostRecentGroupId() override;
virtual const GroupIds& getGroupIds() override;
virtual const GroupIds& getGroupIds() const override;
virtual void setSelected(bool select, bool changeGroupStatus) override;
virtual bool isSelected() const override;

Expand Down
104 changes: 96 additions & 8 deletions radiant/map/algorithm/Import.cpp
@@ -1,8 +1,11 @@
#include "Import.h"

#include <map>

#include "imap.h"
#include "imapformat.h"
#include "inamespace.h"
#include "iselectiongroup.h"
#include "ientity.h"
#include "iscenegraph.h"
#include "scene/BasicRootNode.h"
Expand All @@ -12,30 +15,112 @@
#include "entitylib.h"
#include "wxutil/dialog/MessageBox.h"

#include "string/join.h"

namespace map
{

namespace algorithm
{

// Will map source group IDs to new groups created in the target map
class SelectionGroupRemapper :
private std::map<std::size_t, selection::ISelectionGroupPtr>
{
private:
selection::ISelectionGroupManager& _targetGroupManager;

public:
// The given groupManager will be used to create one corresponding group
// for each distinct group found in the source nodes
SelectionGroupRemapper(selection::ISelectionGroupManager& targetGroupManager) :
_targetGroupManager(targetGroupManager)
{}

void assignRemappedGroups(const scene::INodePtr& node, const IGroupSelectable::GroupIds& oldGroupIds)
{
rMessage() << "Node " << node->name() << " had the groups " << string::join(oldGroupIds, "|");

// Get the Groups the source node was assigned to, and add the
// cloned node to the mapped group, one by one, keeping the order intact
for (std::size_t id : oldGroupIds)
{
// Try to insert the ID, ignore if already exists
// Get a new mapping for the given group ID
const selection::ISelectionGroupPtr& mappedGroup = getMappedGroup(id);

// Assign the new group ID to this clone
mappedGroup->addNode(node);
}

rMessage() << " => " << string::join(std::dynamic_pointer_cast<IGroupSelectable>(node)->getGroupIds(), "|") << std::endl;
}

void remapSelectionGroups(const scene::INodePtr& node)
{
std::shared_ptr<IGroupSelectable> groupSelectable = std::dynamic_pointer_cast<IGroupSelectable>(node);

if (groupSelectable)
{
auto sourceRoot = node->getRootNode();
assert(sourceRoot);

// Save the current set of group IDs
IGroupSelectable::GroupIds oldGroupIds = groupSelectable->getGroupIds();

// Remove the node from all its groups
for (auto id : oldGroupIds)
{
auto group = sourceRoot->getSelectionGroupManager().getSelectionGroup(id);

group->removeNode(node);
}

// Assign the new set of groups for this node
assignRemappedGroups(node, oldGroupIds);
}
}

private:
const selection::ISelectionGroupPtr& getMappedGroup(std::size_t id)
{
auto found = emplace(id, selection::ISelectionGroupPtr());

if (!found.second)
{
// We already covered this ID, return the mapped group
return found.first->second;
}

// Insertion was successful, so we didn't cover this ID yet
found.first->second = _targetGroupManager.createSelectionGroup();

return found.first->second;
}
};

class PrimitiveMerger :
public scene::PrimitiveReparentor
{
private:
SelectionGroupRemapper _groupRemapper;

public:
PrimitiveMerger(const scene::INodePtr& newParent) :
PrimitiveReparentor(newParent)
PrimitiveMerger(const scene::INodePtr& newParent, SelectionGroupRemapper& remapper) :
PrimitiveReparentor(newParent),
_groupRemapper(remapper)
{}

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

// Re-generate the group IDs of this node
_groupRemapper.remapSelectionGroups(node);

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

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

Expand All @@ -46,9 +131,12 @@ class EntityMerger :
// The target path
mutable scene::Path _path;

SelectionGroupRemapper _groupRemapper;

public:
EntityMerger(const scene::INodePtr& root) :
_path(scene::Path(root))
_path(scene::Path(root)),
_groupRemapper(root->getRootNode()->getSelectionGroupManager())
{}

bool pre(const scene::INodePtr& originalNode) override
Expand Down Expand Up @@ -93,7 +181,7 @@ class EntityMerger :
_path.push(worldSpawn);

// Move all children of this node to the target worldspawn
PrimitiveMerger visitor(worldSpawn);
PrimitiveMerger visitor(worldSpawn, _groupRemapper);
node->traverseChildren(visitor);
}
}
Expand Down Expand Up @@ -124,7 +212,7 @@ class EntityMerger :
void post(const scene::INodePtr& node) override
{
// Re-generate the group IDs of this entity node
// TODO
_groupRemapper.remapSelectionGroups(node);

_path.pop();
}
Expand Down

0 comments on commit 9b07599

Please sign in to comment.