1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
|
#include "ModelScalePreserver.h"
#include "ientity.h"
#include "itransformable.h"
#include "imapresource.h"
#include "itextstream.h"
#include "string/convert.h"
namespace map
{
namespace
{
const char* const MODELSCALE_KEY = "editor_modelScale";
}
ModelScalePreserver::ModelScalePreserver() :
_modelScaleKey(MODELSCALE_KEY)
{
// #5220: To cover having the scale of resized models preserved in
// auto-saves and prefabs, we subscribe to the exporting events
// and check for any models that still have a modified scale on it.
// That scale value is then written to the hosting entity's spawnargs.
GlobalMapResourceManager().signal_onResourceExporting().connect(
sigc::mem_fun(this, &ModelScalePreserver::onResourceExporting)
);
GlobalMapResourceManager().signal_onResourceExported().connect(
sigc::mem_fun(this, &ModelScalePreserver::onResourceExported)
);
// After map loading this class will try to reconstruct the scale
GlobalMapModule().signal_mapEvent().connect(
sigc::mem_fun(this, &ModelScalePreserver::onMapEvent)
);
}
void ModelScalePreserver::forEachScaledModel(const scene::IMapRootNodePtr& root,
const std::function<void(Entity&, model::ModelNode&)>& func)
{
root->foreachNode([&](const scene::INodePtr& node)
{
if (Node_isEntity(node))
{
// Find any model nodes below that one
node->foreachNode([&](const scene::INodePtr& child)
{
model::ModelNodePtr model = Node_getModel(child);
if (model && model->hasModifiedScale())
{
// Found a model with modified scale
func(*Node_getEntity(node), *model);
}
return true;
});
}
return true;
});
}
void ModelScalePreserver::onResourceExporting(const scene::IMapRootNodePtr& root)
{
// Traverse the exported scene and check for any models that are still scaled, to
// persist that value in the exported scene.
// In "regular" map saves, all models already have been processed here at this point,
// and their scale is reset, so in this case the following traversal does nothing.
forEachScaledModel(root, [this](Entity& entity, model::ModelNode& model)
{
// Persist the modified scale by placing a special editor spawnarg
entity.setKeyValue(_modelScaleKey, string::to_string(model.getModelScale()));
});
}
void ModelScalePreserver::onResourceExported(const scene::IMapRootNodePtr& root)
{
// In this post-export event, we remove any scale spawnargs added earlier
forEachScaledModel(root, [this](Entity& entity, model::ModelNode& model)
{
if (!entity.getKeyValue(_modelScaleKey).empty())
{
entity.setKeyValue(_modelScaleKey, "");
}
});
}
void ModelScalePreserver::restoreModelScale(const scene::IMapRootNodePtr& root)
{
root->foreachNode([this](const scene::INodePtr& node)
{
if (Node_isEntity(node))
{
Entity* entity = Node_getEntity(node);
// Search for the editor_ key and apply the scale if found
auto savedScale = entity->getKeyValue(_modelScaleKey);
if (!savedScale.empty())
{
Vector3 scale = string::convert<Vector3>(savedScale);
// Find any model nodes below that one
node->foreachNode([&](const scene::INodePtr& child)
{
model::ModelNodePtr model = Node_getModel(child);
ITransformablePtr transformable = scene::node_cast<ITransformable>(child);
if (model && transformable)
{
rMessage() << "Restoring model scale on node " << child->name() << std::endl;
transformable->setType(TRANSFORM_PRIMITIVE);
transformable->setScale(scale);
transformable->freezeTransform();
}
return true;
});
// Clear the spawnarg now that we've applied it
entity->setKeyValue(_modelScaleKey, "");
}
}
return true;
});
}
void ModelScalePreserver::onMapEvent(IMap::MapEvent ev)
{
if (ev == IMap::MapLoaded)
{
// After loading, restore the scale if it gets recovered
restoreModelScale(GlobalMapModule().getRoot());
}
}
}
|