|
|
@@ -4,25 +4,178 @@
|
|
|
|
|
|
namespace anki {
|
|
|
|
|
|
+//==============================================================================
|
|
|
+// ModelPatchNodeInstance =
|
|
|
+//==============================================================================
|
|
|
+
|
|
|
+//==============================================================================
|
|
|
+ModelPatchNodeInstance::ModelPatchNodeInstance(
|
|
|
+ const char* name, SceneGraph* scene, SceneNode* parent, // Scene
|
|
|
+ U32 movableFlags, // Movable
|
|
|
+ const ModelPatchBase* modelPatchResource) // Self
|
|
|
+ : SceneNode(name, scene, parent),
|
|
|
+ Movable(movableFlags, this),
|
|
|
+ Spatial(&obb, getSceneAllocator()),
|
|
|
+ modelPatch(modelPatchResource)
|
|
|
+{
|
|
|
+ sceneNodeProtected.movable = this;
|
|
|
+
|
|
|
+ // Dont mark it as spatial because it's sub-spatial and don't want to
|
|
|
+ // be updated by the scene
|
|
|
+ sceneNodeProtected.spatial = nullptr;
|
|
|
+
|
|
|
+ ANKI_ASSERT(modelPatch);
|
|
|
+}
|
|
|
+
|
|
|
+//==============================================================================
|
|
|
+void ModelPatchNodeInstance::movableUpdate()
|
|
|
+{
|
|
|
+ ANKI_ASSERT(modelPatch);
|
|
|
+
|
|
|
+ // Update the obb of self
|
|
|
+ obb = modelPatch->getBoundingShape().getTransformed(
|
|
|
+ getWorldTransform());
|
|
|
+ spatialMarkForUpdate();
|
|
|
+
|
|
|
+ // If this instance is the last update the parent's collision shape
|
|
|
+ SceneNode* parentNode = getParent();
|
|
|
+ ANKI_ASSERT(parentNode);
|
|
|
+
|
|
|
+ ModelPatchNode* modelPatchNode =
|
|
|
+#if ANKI_DEBUG
|
|
|
+ dynamic_cast<ModelPatchNode*>(parentNode);
|
|
|
+ ANKI_ASSERT(modelPatchNode);
|
|
|
+#else
|
|
|
+ static_cast<ModelPatchNode*>(parentNode);
|
|
|
+#endif
|
|
|
+
|
|
|
+ ANKI_ASSERT(modelPatchNode->instances.size() > 0);
|
|
|
+ if(this == modelPatchNode->instances.back())
|
|
|
+ {
|
|
|
+ modelPatchNode->updateSpatialCs();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
//==============================================================================
|
|
|
// ModelPatchNode =
|
|
|
//==============================================================================
|
|
|
|
|
|
//==============================================================================
|
|
|
-ModelPatchNode::ModelPatchNode(const ModelPatchBase *modelPatch_,
|
|
|
- const char* name, SceneGraph* scene,
|
|
|
- U32 movableFlags, Movable* movParent)
|
|
|
- : SceneNode(name, scene),
|
|
|
- Movable(movableFlags, movParent, *this, getSceneAllocator()),
|
|
|
+ModelPatchNode::ModelPatchNode(
|
|
|
+ const char* name, SceneGraph* scene, SceneNode* parent,
|
|
|
+ U32 movableFlags,
|
|
|
+ const ModelPatchBase* modelPatch_, U instancesCount)
|
|
|
+ : SceneNode(name, scene, parent),
|
|
|
+ Movable(movableFlags, this),
|
|
|
Renderable(getSceneAllocator()),
|
|
|
Spatial(&obb, getSceneAllocator()),
|
|
|
- modelPatch(modelPatch_)
|
|
|
+ modelPatch(modelPatch_),
|
|
|
+ instances(getSceneAllocator()),
|
|
|
+ transforms(getSceneAllocator())
|
|
|
{
|
|
|
sceneNodeProtected.movable = this;
|
|
|
sceneNodeProtected.renderable = this;
|
|
|
sceneNodeProtected.spatial = this;
|
|
|
|
|
|
Renderable::init(*this);
|
|
|
+
|
|
|
+ // Create the instances as ModelPatchNodeInstance
|
|
|
+ if(instancesCount > 1)
|
|
|
+ {
|
|
|
+ spatialProtected.subSpatials.resize(instancesCount, nullptr);
|
|
|
+ instances.resize(instancesCount, nullptr);
|
|
|
+ transforms.resize(instancesCount, Transform::getIdentity());
|
|
|
+
|
|
|
+ Vec3 pos = Vec3(0.0);
|
|
|
+
|
|
|
+ for(U i = 0; i < instancesCount; i++)
|
|
|
+ {
|
|
|
+ ModelPatchNodeInstance* instance = ANKI_NEW(
|
|
|
+ ModelPatchNodeInstance, getSceneAllocator(),
|
|
|
+ nullptr, scene, this, Movable::MF_NONE,
|
|
|
+ modelPatch);
|
|
|
+
|
|
|
+ instance->setLocalOrigin(pos);
|
|
|
+ pos.x() += 2.0;
|
|
|
+
|
|
|
+ spatialProtected.subSpatials[i] = instance;
|
|
|
+ instances[i] = instance;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//==============================================================================
|
|
|
+ModelPatchNode::~ModelPatchNode()
|
|
|
+{
|
|
|
+ for(ModelPatchNodeInstance* instance : instances)
|
|
|
+ {
|
|
|
+ ANKI_DELETE(instance, getSceneAllocator());
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//==============================================================================
|
|
|
+const Transform* ModelPatchNode::getRenderableWorldTransforms()
|
|
|
+{
|
|
|
+ if(transforms.size() == 0)
|
|
|
+ {
|
|
|
+ // NO instancing
|
|
|
+ return &getWorldTransform();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // Instancing
|
|
|
+
|
|
|
+ ANKI_ASSERT(transforms.size() == instances.size());
|
|
|
+
|
|
|
+ // Set the transforms
|
|
|
+ for(U i = 0; i < instances.size(); i++)
|
|
|
+ {
|
|
|
+ transforms[i] = instances[i]->getWorldTransform();
|
|
|
+ }
|
|
|
+
|
|
|
+ return &transforms[0];
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//==============================================================================
|
|
|
+void ModelPatchNode::movableUpdate()
|
|
|
+{
|
|
|
+ Movable::movableUpdate();
|
|
|
+
|
|
|
+ if(instances.size() == 0)
|
|
|
+ {
|
|
|
+ // NO instancing
|
|
|
+
|
|
|
+ obb = modelPatch->getBoundingShape().getTransformed(
|
|
|
+ getWorldTransform());
|
|
|
+
|
|
|
+ spatialMarkForUpdate();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // Instancing
|
|
|
+
|
|
|
+ // Do nothing. You cannot update the obb because the instances have
|
|
|
+ // not been updated their CSs yet. The update will be triggered by the
|
|
|
+ // last instance.
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//==============================================================================
|
|
|
+void ModelPatchNode::updateSpatialCs()
|
|
|
+{
|
|
|
+ ANKI_ASSERT(instances.size() > 0);
|
|
|
+
|
|
|
+ obb = instances[0]->obb;
|
|
|
+
|
|
|
+ for(U i = 1; i < instances.size(); i++)
|
|
|
+ {
|
|
|
+ ANKI_ASSERT(instances[i]);
|
|
|
+
|
|
|
+ obb = obb.getCompoundShape(instances[i]->obb);
|
|
|
+ }
|
|
|
+
|
|
|
+ spatialMarkForUpdate();
|
|
|
}
|
|
|
|
|
|
//==============================================================================
|
|
|
@@ -30,11 +183,12 @@ ModelPatchNode::ModelPatchNode(const ModelPatchBase *modelPatch_,
|
|
|
//==============================================================================
|
|
|
|
|
|
//==============================================================================
|
|
|
-ModelNode::ModelNode(const char* modelFname,
|
|
|
- const char* name, SceneGraph* scene,
|
|
|
- uint movableFlags, Movable* movParent)
|
|
|
- : SceneNode(name, scene),
|
|
|
- Movable(movableFlags, movParent, *this, getSceneAllocator()),
|
|
|
+ModelNode::ModelNode(
|
|
|
+ const char* name, SceneGraph* scene, SceneNode* parent,
|
|
|
+ U32 movableFlags,
|
|
|
+ const char* modelFname, U instances)
|
|
|
+ : SceneNode(name, scene, parent),
|
|
|
+ Movable(movableFlags, this),
|
|
|
patches(getSceneAllocator())
|
|
|
{
|
|
|
sceneNodeProtected.movable = this;
|
|
|
@@ -49,8 +203,8 @@ ModelNode::ModelNode(const char* modelFname,
|
|
|
std::string name_ = name + std::to_string(i);
|
|
|
|
|
|
ModelPatchNode* mpn = ANKI_NEW(ModelPatchNode, getSceneAllocator(),
|
|
|
- patch, name_.c_str(),
|
|
|
- scene, Movable::MF_IGNORE_LOCAL_TRANSFORM, this);
|
|
|
+ name_.c_str(), scene, this,
|
|
|
+ Movable::MF_IGNORE_LOCAL_TRANSFORM, patch, instances);
|
|
|
|
|
|
patches.push_back(mpn);
|
|
|
++i;
|