Fix crash when an object whose mesh is attached to another mesh is removed

stable-5.4
Armin Burgmeier 2013-05-27 15:52:50 +02:00
parent de75275f61
commit 90ee4d2380
6 changed files with 120 additions and 5 deletions

View File

@ -641,12 +641,30 @@ void StdMeshInstance::AnimationNode::DenumeratePointers()
break;
case LinearInterpolationNode:
value_provider = dynamic_cast<SerializableValueProvider*>(LinearInterpolation.Weight);
// non-recursive, StdMeshInstance::DenumeratePointers walks over all nodes
break;
}
if(value_provider) value_provider->DenumeratePointers();
}
void StdMeshInstance::AnimationNode::ClearPointers(class C4Object* pObj)
{
SerializableValueProvider* value_provider = NULL;
switch(Type)
{
case LeafNode:
value_provider = dynamic_cast<SerializableValueProvider*>(Leaf.Position);
break;
case LinearInterpolationNode:
value_provider = dynamic_cast<SerializableValueProvider*>(LinearInterpolation.Weight);
// non-recursive, StdMeshInstance::ClearPointers walks over all nodes
break;
}
if(value_provider) value_provider->ClearPointers(pObj);
}
StdMeshInstance::AttachedMesh::AttachedMesh():
Number(0), Parent(NULL), Child(NULL), OwnChild(true), ChildDenumerator(NULL), ParentBone(0), ChildBone(0), FinalTransformDirty(false)
{
@ -725,6 +743,11 @@ void StdMeshInstance::AttachedMesh::DenumeratePointers()
ChildDenumerator->DenumeratePointers(this);
}
bool StdMeshInstance::AttachedMesh::ClearPointers(class C4Object* pObj)
{
ChildDenumerator->ClearPointers(pObj);
}
StdMeshInstance::StdMeshInstance(const StdMesh& mesh, float completion):
Mesh(&mesh), SharedVertices(mesh.GetSharedVertices().size()), Completion(completion),
BoneTransforms(Mesh->GetNumBones(), StdMeshMatrix::Identity()),
@ -1294,6 +1317,21 @@ void StdMeshInstance::DenumeratePointers()
AttachChildren[i]->DenumeratePointers();
}
void StdMeshInstance::ClearPointers(class C4Object* pObj)
{
for(unsigned int i = 0; i < AnimationNodes.size(); ++i)
if(AnimationNodes[i])
AnimationNodes[i]->ClearPointers(pObj);
std::vector<unsigned int> Removal;
for(unsigned int i = 0; i < AttachChildren.size(); ++i)
if(!AttachChildren[i]->ClearPointers(pObj))
Removal.push_back(AttachChildren[i]->Number);
for(unsigned int i = 0; i < Removal.size(); ++i)
DetachMesh(Removal[i]);
}
StdMeshInstance::AnimationNodeList::iterator StdMeshInstance::GetStackIterForSlot(int slot, bool create)
{
// TODO: bsearch

View File

@ -361,6 +361,7 @@ public:
virtual void CompileFunc(StdCompiler* pComp);
virtual void DenumeratePointers() {}
virtual void ClearPointers(class C4Object* pObj) {}
};
// A node in the animation tree
@ -395,6 +396,7 @@ public:
void CompileFunc(StdCompiler* pComp, const StdMesh* Mesh);
void DenumeratePointers();
void ClearPointers(class C4Object* pObj);
protected:
int Slot;
@ -432,6 +434,7 @@ public:
virtual void CompileFunc(StdCompiler* pComp, AttachedMesh* attach) = 0;
virtual void DenumeratePointers(AttachedMesh* attach) {}
virtual bool ClearPointers(class C4Object* pObj) { return true; }
};
typedef Denumerator*(*DenumeratorFactoryFunc)();
@ -458,6 +461,7 @@ public:
void CompileFunc(StdCompiler* pComp, DenumeratorFactoryFunc Factory);
void DenumeratePointers();
bool ClearPointers(class C4Object* pObj);
private:
unsigned int ParentBone;
@ -541,6 +545,7 @@ public:
void CompileFunc(StdCompiler* pComp, AttachedMesh::DenumeratorFactoryFunc Factory);
void DenumeratePointers();
void ClearPointers(class C4Object* pObj);
const StdMesh& GetMesh() const { assert(Mesh != NULL); return *Mesh; }

View File

@ -201,6 +201,9 @@ C4ValueProviderX::C4ValueProviderX(C4Object* object, C4Real pos, C4Real begin, C
bool C4ValueProviderX::Execute()
{
// Object might have been removed
if(!Object) return false;
Value += (End - Begin) * (Object->xdir) / Length;
if (End > Begin)
@ -242,6 +245,9 @@ C4ValueProviderY::C4ValueProviderY(C4Object* object, C4Real pos, C4Real begin, C
bool C4ValueProviderY::Execute()
{
// Object might have been removed
if(!Object) return false;
Value += (End - Begin) * (Object->ydir) / Length;
if (End > Begin)
@ -283,6 +289,9 @@ C4ValueProviderR::C4ValueProviderR(C4Object* object, C4Real begin, C4Real end):
bool C4ValueProviderR::Execute()
{
// Object might have been removed
if(!Object) return false;
C4Real r = Object->fix_r;
if(r < 0) r += 360;
@ -309,6 +318,9 @@ C4ValueProviderAbsX::C4ValueProviderAbsX(C4Object* object, C4Real pos, C4Real be
bool C4ValueProviderAbsX::Execute()
{
// Object might have been removed
if(!Object) return false;
Value += (End - Begin) * Abs(Object->xdir) / Length;
assert( (End >= Begin && Value >= Begin) || (End <= Begin && Value <= Begin));
@ -339,6 +351,9 @@ C4ValueProviderAbsY::C4ValueProviderAbsY(C4Object* object, C4Real pos, C4Real be
bool C4ValueProviderAbsY::Execute()
{
// Object might have been removed
if(!Object) return false;
Value += (End - Begin) * Abs(Object->ydir) / Length;
assert( (End >= Begin && Value >= Begin) || (End <= Begin && Value <= Begin));
@ -369,6 +384,9 @@ C4ValueProviderXDir::C4ValueProviderXDir(C4Object* object, C4Real begin, C4Real
bool C4ValueProviderXDir::Execute()
{
// Object might have been removed
if(!Object) return false;
Value = Begin + (End - Begin) * Min<C4Real>(Abs(Object->xdir/MaxXDir), itofix(1));
return true;
}
@ -394,6 +412,9 @@ C4ValueProviderYDir::C4ValueProviderYDir(C4Object* object, C4Real begin, C4Real
bool C4ValueProviderYDir::Execute()
{
// Object might have been removed
if(!Object) return false;
Value = Begin + (End - Begin) * Min<C4Real>(Abs(Object->ydir/MaxYDir), itofix(1));
return true;
}
@ -419,6 +440,9 @@ C4ValueProviderRDir::C4ValueProviderRDir(C4Object* object, C4Real begin, C4Real
bool C4ValueProviderRDir::Execute()
{
// Object might have been removed
if(!Object) return false;
Value = Begin + (End - Begin) * Min<C4Real>(Abs(Object->rdir/MaxRDir), itofix(1));
return true;
}
@ -444,6 +468,9 @@ C4ValueProviderCosR::C4ValueProviderCosR(C4Object* object, C4Real begin, C4Real
bool C4ValueProviderCosR::Execute()
{
// Object might have been removed
if(!Object) return false;
Value = Begin + (End - Begin) * Cos(Object->fix_r + Offset);
return true;
}
@ -469,6 +496,9 @@ C4ValueProviderSinR::C4ValueProviderSinR(C4Object* object, C4Real begin, C4Real
bool C4ValueProviderSinR::Execute()
{
// Object might have been removed
if(!Object) return false;
Value = Begin + (End - Begin) * Sin(Object->fix_r + Offset);
return true;
}
@ -494,6 +524,9 @@ C4ValueProviderCosV::C4ValueProviderCosV(C4Object* object, C4Real begin, C4Real
bool C4ValueProviderCosV::Execute()
{
// Object might have been removed
if(!Object) return false;
// TODO: Maybe we can optimize this by using cos(r) = x/sqrt(x*x+y*y), sin(r)=y/sqrt(x*x+y*y)
// plus addition theorems for sin or cos.
@ -523,6 +556,9 @@ C4ValueProviderSinV::C4ValueProviderSinV(C4Object* object, C4Real begin, C4Real
bool C4ValueProviderSinV::Execute()
{
// Object might have been removed
if(!Object) return false;
// TODO: Maybe we can optimize this by using cos(r) = x/sqrt(x*x+y*y), sin(r)=y/sqrt(x*x+y*y),
// plus addition theorems for sin or cos.
@ -551,6 +587,9 @@ C4ValueProviderAction::C4ValueProviderAction(C4Object* object):
bool C4ValueProviderAction::Execute()
{
// Object might have been removed
if(!Object) return false;
const C4Action& Action = Object->Action;
C4PropList* pActionDef = Object->GetAction();

View File

@ -87,6 +87,7 @@ public:
virtual void CompileFunc(StdCompiler* pComp);
virtual void DenumeratePointers() { Object.DenumeratePointers(); }
virtual void ClearPointers(C4Object* pObj) { if(Object == pObj) Object = NULL; }
private:
C4ObjectPtr Object;
C4Real Begin;
@ -103,6 +104,7 @@ public:
virtual void CompileFunc(StdCompiler* pComp);
virtual void DenumeratePointers() { Object.DenumeratePointers(); }
virtual void ClearPointers(C4Object* pObj) { if(Object == pObj) Object = NULL; }
private:
C4ObjectPtr Object;
C4Real Begin;
@ -119,6 +121,7 @@ public:
virtual void CompileFunc(StdCompiler* pComp);
virtual void DenumeratePointers() { Object.DenumeratePointers(); }
virtual void ClearPointers(C4Object* pObj) { if(Object == pObj) Object = NULL; }
private:
C4ObjectPtr Object;
C4Real Begin;
@ -134,6 +137,7 @@ public:
virtual void CompileFunc(StdCompiler* pComp);
virtual void DenumeratePointers() { Object.DenumeratePointers(); }
virtual void ClearPointers(C4Object* pObj) { if(Object == pObj) Object = NULL; }
private:
C4ObjectPtr Object;
C4Real Begin;
@ -150,6 +154,7 @@ public:
virtual void CompileFunc(StdCompiler* pComp);
virtual void DenumeratePointers() { Object.DenumeratePointers(); }
virtual void ClearPointers(C4Object* pObj) { if(Object == pObj) Object = NULL; }
private:
C4ObjectPtr Object;
C4Real Begin;
@ -166,6 +171,7 @@ public:
virtual void CompileFunc(StdCompiler* pComp);
virtual void DenumeratePointers() { Object.DenumeratePointers(); }
virtual void ClearPointers(C4Object* pObj) { if(Object == pObj) Object = NULL; }
private:
C4ObjectPtr Object;
C4Real Begin;
@ -182,6 +188,7 @@ public:
virtual void CompileFunc(StdCompiler* pComp);
virtual void DenumeratePointers() { Object.DenumeratePointers(); }
virtual void ClearPointers(C4Object* pObj) { if(Object == pObj) Object = NULL; }
private:
C4ObjectPtr Object;
C4Real Begin;
@ -198,6 +205,7 @@ public:
virtual void CompileFunc(StdCompiler* pComp);
virtual void DenumeratePointers() { Object.DenumeratePointers(); }
virtual void ClearPointers(C4Object* pObj) { if(Object == pObj) Object = NULL; }
private:
C4ObjectPtr Object;
C4Real Begin;
@ -214,6 +222,7 @@ public:
virtual void CompileFunc(StdCompiler* pComp);
virtual void DenumeratePointers() { Object.DenumeratePointers(); }
virtual void ClearPointers(C4Object* pObj) { if(Object == pObj) Object = NULL; }
private:
C4ObjectPtr Object;
C4Real Begin;
@ -230,6 +239,7 @@ public:
virtual void CompileFunc(StdCompiler* pComp);
virtual void DenumeratePointers() { Object.DenumeratePointers(); }
virtual void ClearPointers(C4Object* pObj) { if(Object == pObj) Object = NULL; }
private:
C4ObjectPtr Object;
C4Real Begin;
@ -246,6 +256,7 @@ public:
virtual void CompileFunc(StdCompiler* pComp);
virtual void DenumeratePointers() { Object.DenumeratePointers(); }
virtual void ClearPointers(C4Object* pObj) { if(Object == pObj) Object = NULL; }
private:
C4ObjectPtr Object;
C4Real Begin;
@ -262,6 +273,7 @@ public:
virtual void CompileFunc(StdCompiler* pComp);
virtual void DenumeratePointers() { Object.DenumeratePointers(); }
virtual void ClearPointers(C4Object* pObj) { if(Object == pObj) Object = NULL; }
private:
C4ObjectPtr Object;
C4Real Begin;
@ -278,6 +290,7 @@ public:
virtual void CompileFunc(StdCompiler* pComp);
virtual void DenumeratePointers() { Object.DenumeratePointers(); }
virtual void ClearPointers(C4Object* pObj) { if(Object == pObj) Object = NULL; }
private:
C4ObjectPtr Object;
};

View File

@ -127,6 +127,18 @@ void C4MeshDenumerator::DenumeratePointers(StdMeshInstance::AttachedMesh* attach
}
}
bool C4MeshDenumerator::ClearPointers(C4Object* pObj)
{
if(Object == pObj)
{
Object = NULL;
// Return false causes the attached mesh to be deleted by StdMeshInstance
return false;
}
return true;
}
static void DrawVertex(C4Facet &cgo, float tx, float ty, int32_t col, int32_t contact)
{
if (Inside<int32_t>(tx,cgo.X,cgo.X+cgo.Wdt) && Inside<int32_t>(ty,cgo.Y,cgo.Y+cgo.Hgt))
@ -479,10 +491,19 @@ void C4Object::UpdateGraphics(bool fGraphicsChanged, bool fTemp)
}
// Keep mesh instance if it uses the same underlying mesh
if(!pMeshInstance || !pGraphics->Type == C4DefGraphics::TYPE_Mesh ||
if(!pMeshInstance || pGraphics->Type != C4DefGraphics::TYPE_Mesh ||
&pMeshInstance->GetMesh() != pGraphics->Mesh)
{
// If this mesh is attached somewhere, detach it before deletion
if(pMeshInstance && pMeshInstance->GetAttachParent() != NULL)
{
// TODO: If the new mesh has a bone with the same name, we could try updating...
StdMeshInstance::AttachedMesh* attach_parent = pMeshInstance->GetAttachParent();
attach_parent->Parent->DetachMesh(attach_parent->Number);
}
delete pMeshInstance;
if (pGraphics->Type == C4DefGraphics::TYPE_Mesh)
{
pMeshInstance = new StdMeshInstance(*pGraphics->Mesh, Def->GrowthType ? 1.0f : static_cast<float>(Con)/static_cast<float>(FullCon));
@ -1815,10 +1836,8 @@ bool C4Object::Promote(int32_t torank, bool exception, bool fForceRankName)
void C4Object::ClearPointers(C4Object *pObj)
{
// TODO: Clear pointers on mesh instance:
// Check for attach children using pObj's mesh instance
// Check for animation nodes refering to pObj (Anim_X, ...).
// mesh attachments and animation nodes
if(pMeshInstance) pMeshInstance->ClearPointers(pObj);
// effects
if (pEffects) pEffects->ClearPointers(pObj);
// contents/contained: not necessary, because it's done in AssignRemoval and StatusDeactivate

View File

@ -90,6 +90,7 @@ public:
virtual void CompileFunc(StdCompiler* pComp, StdMeshInstance::AttachedMesh* attach);
virtual void DenumeratePointers(StdMeshInstance::AttachedMesh* attach);
virtual bool ClearPointers(C4Object* pObj);
};
class C4Action