Skip to content

Commit

Permalink
#5996: First implementation attempt. Store the default skin on the Sk…
Browse files Browse the repository at this point in the history
…innedModel instance, it will be used if the explicitly set skin is empty
  • Loading branch information
codereader committed Jan 14, 2024
1 parent e7056c9 commit b2b2889
Show file tree
Hide file tree
Showing 8 changed files with 50 additions and 23 deletions.
21 changes: 13 additions & 8 deletions include/modelskin.h
Expand Up @@ -73,19 +73,24 @@ class ISkin :
class SkinnedModel
{
public:
// destructor
virtual ~SkinnedModel() {}
using Ptr = std::shared_ptr<SkinnedModel>;

// greebo: Updates the model's surface remaps. Pass the new skin name (can be empty).
virtual void skinChanged(const std::string& newSkinName) = 0;
virtual ~SkinnedModel() {}

// Returns the name of the currently active skin
virtual std::string getSkin() const = 0;
// greebo: Updates the model's surface remaps. Pass the new skin name (can be empty).
virtual void skinChanged(const std::string& newSkinName) = 0;

// Returns the name of the currently active skin
// If no explicit skin has been defined through skinChanged, this returns the default skin
virtual std::string getSkin() const = 0;

// Define the skin that is active when an empty skin name is active
// This is basically referring to the skin value in the modelDefs
virtual void setDefaultSkin(const std::string& defaultSkin) = 0;
};
typedef std::shared_ptr<SkinnedModel> SkinnedModelPtr;

// Model skinlist typedef
typedef std::vector<std::string> StringList;
using StringList = std::vector<std::string>;

constexpr const char* const MODULE_MODELSKINCACHE("ModelSkinCache");

Expand Down
4 changes: 2 additions & 2 deletions plugins/script/interfaces/ModelInterface.cpp
Expand Up @@ -101,9 +101,9 @@ model::StringList ScriptModelNode::getActiveMaterials()
model::StringList materials = modelNode->getIModel().getActiveMaterials();

// Check if the model is a skinned one, so let's check for active skins
SkinnedModelPtr skinnedModel = std::dynamic_pointer_cast<SkinnedModel>(modelNode);
auto skinnedModel = std::dynamic_pointer_cast<SkinnedModel>(modelNode);

if (skinnedModel != NULL)
if (skinnedModel)
{
// This is a skinned model, get the surface remap
std::string curSkin = skinnedModel->getSkin();
Expand Down
8 changes: 7 additions & 1 deletion radiantcore/entity/ModelKey.cpp
Expand Up @@ -102,6 +102,12 @@ void ModelKey::attachModelNode()
// Assign idle pose to modelDef meshes
if (modelDef)
{
// Set the default skin to the one defined in the modelDef
if (auto skinned = std::dynamic_pointer_cast<SkinnedModel>(_model.node); skinned)
{
skinned->setDefaultSkin(modelDef->getSkin());
}

scene::applyIdlePose(_model.node, modelDef);
}

Expand Down Expand Up @@ -129,7 +135,7 @@ void ModelKey::attachModelNodeKeepinSkin()
if (_model.node)
{
// Check if we have a skinnable model and remember the skin
SkinnedModelPtr skinned = std::dynamic_pointer_cast<SkinnedModel>(_model.node);
auto skinned = std::dynamic_pointer_cast<SkinnedModel>(_model.node);

std::string skin = skinned ? skinned->getSkin() : "";

Expand Down
11 changes: 7 additions & 4 deletions radiantcore/model/StaticModelNode.cpp
Expand Up @@ -108,24 +108,27 @@ bool StaticModelNode::getIntersection(const Ray& ray, Vector3& intersection)
return _model->getIntersection(ray, intersection, localToWorld());
}

// Skin changed notify
void StaticModelNode::skinChanged(const std::string& newSkinName)
{
// The new skin name is stored locally
_skin = newSkinName;

// greebo: Acquire the ModelSkin reference from the SkinCache (might return null)
// Applying the skin might trigger onModelShadersChanged()
_model->applySkin(GlobalModelSkinCache().findSkin(_skin));
_model->applySkin(GlobalModelSkinCache().findSkin(getSkin()));

// Refresh the scene (TODO: get rid of that)
GlobalSceneGraph().sceneChanged();
}

// Returns the name of the currently active skin
std::string StaticModelNode::getSkin() const
{
return _skin;
return !_skin.empty() ? _skin : _defaultSkin;
}

void StaticModelNode::setDefaultSkin(const std::string& defaultSkin)
{
_defaultSkin = defaultSkin;
}

void StaticModelNode::_onTransformationChanged()
Expand Down
4 changes: 4 additions & 0 deletions radiantcore/model/StaticModelNode.h
Expand Up @@ -38,6 +38,9 @@ class StaticModelNode final :
// The name of this model's skin
std::string _skin;

// The default skin used when no skin has otherwise been set from the outside
std::string _defaultSkin;

public:
typedef std::shared_ptr<StaticModelNode> Ptr;

Expand All @@ -58,6 +61,7 @@ class StaticModelNode final :
void skinChanged(const std::string& newSkinName) override;
// Returns the name of the currently active skin
std::string getSkin() const override;
void setDefaultSkin(const std::string& defaultSkin) override;

// Bounded implementation
const AABB& localAABB() const override;
Expand Down
9 changes: 7 additions & 2 deletions radiantcore/model/md5/MD5ModelNode.cpp
Expand Up @@ -109,7 +109,7 @@ void MD5ModelNode::onPreRender(const VolumeTest& volume)

std::string MD5ModelNode::getSkin() const
{
return _skin;
return !_skin.empty() ? _skin : _defaultSkin;
}

void MD5ModelNode::skinChanged(const std::string& newSkinName)
Expand All @@ -119,12 +119,17 @@ void MD5ModelNode::skinChanged(const std::string& newSkinName)

// greebo: Acquire the ModelSkin reference from the SkinCache (might return null)
// Applying the skin might trigger onModelShadersChanged()
_model->applySkin(GlobalModelSkinCache().findSkin(_skin));
_model->applySkin(GlobalModelSkinCache().findSkin(getSkin()));

// Refresh the scene
GlobalSceneGraph().sceneChanged();
}

void MD5ModelNode::setDefaultSkin(const std::string& defaultSkin)
{
_defaultSkin = defaultSkin;
}

void MD5ModelNode::onModelShadersChanged()
{
// Detach from existing shaders, re-acquire them in onPreRender
Expand Down
12 changes: 8 additions & 4 deletions radiantcore/model/md5/MD5ModelNode.h
Expand Up @@ -27,6 +27,9 @@ class MD5ModelNode :
// The name of this model's skin
std::string _skin;

// The default skin in case _skin is set to an empty string
std::string _defaultSkin;

sigc::connection _animationUpdateConnection;
sigc::connection _modelShadersChangedConnection;

Expand All @@ -36,7 +39,7 @@ class MD5ModelNode :

public:
MD5ModelNode(const MD5ModelPtr& model);
virtual ~MD5ModelNode();
~MD5ModelNode() override;

// ModelNode implementation
const model::IModel& getIModel() const override;
Expand All @@ -49,9 +52,9 @@ class MD5ModelNode :
const MD5ModelPtr& getModel() const;

// Bounded implementation
virtual const AABB& localAABB() const override;
const AABB& localAABB() const override;

virtual std::string name() const override;
std::string name() const override;

// SelectionTestable implementation
void testSelect(Selector& selector, SelectionTest& test) override;
Expand All @@ -63,8 +66,9 @@ class MD5ModelNode :
void onPreRender(const VolumeTest& volume) override;

// Returns the name of the currently active skin
virtual std::string getSkin() const override;
std::string getSkin() const override;
void skinChanged(const std::string& newSkinName) override;
void setDefaultSkin(const std::string& defaultSkin) override;

protected:
void createRenderableSurfaces() override;
Expand Down
4 changes: 2 additions & 2 deletions test/Skin.cpp
Expand Up @@ -700,9 +700,9 @@ IEntityNodePtr createStaticEntityWithModel(const std::string& model)
return entity;
}

SkinnedModelPtr getSkinnedModel(const IEntityNodePtr& entity)
SkinnedModel::Ptr getSkinnedModel(const IEntityNodePtr& entity)
{
SkinnedModelPtr foundModelNode;
SkinnedModel::Ptr foundModelNode;

entity->foreachNode([&](const auto& child)
{
Expand Down

0 comments on commit b2b2889

Please sign in to comment.