Added Clone() function to Model, which deep-copies all data including vertex/index buffers, so that the clone can be individually animated. Closes #402.
This commit is contained in:
Родитель
6efadd91a2
Коммит
b80fbc8817
|
@ -139,7 +139,7 @@ public:
|
|||
void RemoveShaderParameter(const String& name);
|
||||
/// Reset all shader pointers.
|
||||
void ReleaseShaders();
|
||||
/// Clone material.
|
||||
/// Clone the material.
|
||||
SharedPtr<Material> Clone(const String& cloneName = String::EMPTY) const;
|
||||
/// Ensure that material techniques are listed in correct order.
|
||||
void SortTechniques();
|
||||
|
|
|
@ -200,9 +200,9 @@ bool Model::Load(Deserializer& source)
|
|||
newMorph.name_ = source.ReadString();
|
||||
newMorph.nameHash_ = newMorph.name_;
|
||||
newMorph.weight_ = 0.0f;
|
||||
unsigned nubuffers_ = source.ReadUInt();
|
||||
unsigned numBuffers = source.ReadUInt();
|
||||
|
||||
for (unsigned j = 0; j < nubuffers_; ++j)
|
||||
for (unsigned j = 0; j < numBuffers; ++j)
|
||||
{
|
||||
VertexBufferMorph newBuffer;
|
||||
unsigned bufferIndex = source.ReadUInt();
|
||||
|
@ -219,7 +219,8 @@ bool Model::Load(Deserializer& source)
|
|||
vertexSize += sizeof(Vector3);
|
||||
if (newBuffer.elementMask_ & MASK_TANGENT)
|
||||
vertexSize += sizeof(Vector3);
|
||||
newBuffer.morphData_ = new unsigned char[newBuffer.vertexCount_ * vertexSize];
|
||||
newBuffer.dataSize_ = newBuffer.vertexCount_ * vertexSize;
|
||||
newBuffer.morphData_ = new unsigned char[newBuffer.dataSize_];
|
||||
|
||||
source.Read(&newBuffer.morphData_[0], newBuffer.vertexCount_ * vertexSize);
|
||||
|
||||
|
@ -463,6 +464,125 @@ void Model::SetMorphs(const Vector<ModelMorph>& morphs)
|
|||
morphs_ = morphs;
|
||||
}
|
||||
|
||||
SharedPtr<Model> Model::Clone(const String& cloneName) const
|
||||
{
|
||||
SharedPtr<Model> ret(new Model(context_));
|
||||
|
||||
ret->SetName(cloneName);
|
||||
ret->boundingBox_ = boundingBox_;
|
||||
ret->skeleton_ = skeleton_;
|
||||
ret->geometryBoneMappings_ = geometryBoneMappings_;
|
||||
ret->geometryCenters_ = geometryCenters_;
|
||||
ret->morphs_ = morphs_;
|
||||
ret->morphRangeStarts_ = morphRangeStarts_;
|
||||
ret->morphRangeCounts_ = morphRangeCounts_;
|
||||
|
||||
// Deep copy vertex/index buffers
|
||||
HashMap<VertexBuffer*, VertexBuffer*> vbMapping;
|
||||
for (Vector<SharedPtr<VertexBuffer> >::ConstIterator i = vertexBuffers_.Begin(); i != vertexBuffers_.End(); ++i)
|
||||
{
|
||||
VertexBuffer* origBuffer = *i;
|
||||
SharedPtr<VertexBuffer> cloneBuffer;
|
||||
|
||||
if (origBuffer)
|
||||
{
|
||||
cloneBuffer = new VertexBuffer(context_);
|
||||
cloneBuffer->SetSize(origBuffer->GetVertexCount(), origBuffer->GetElementMask(), origBuffer->IsDynamic());
|
||||
cloneBuffer->SetShadowed(origBuffer->IsShadowed());
|
||||
if (origBuffer->IsShadowed())
|
||||
cloneBuffer->SetData(origBuffer->GetShadowData());
|
||||
else
|
||||
{
|
||||
void* origData = origBuffer->Lock(0, origBuffer->GetVertexCount());
|
||||
if (origData)
|
||||
cloneBuffer->SetData(origData);
|
||||
else
|
||||
LOGERROR("Failed to lock original vertex buffer for copying");
|
||||
}
|
||||
vbMapping[origBuffer] = cloneBuffer;
|
||||
}
|
||||
|
||||
ret->vertexBuffers_.Push(cloneBuffer);
|
||||
}
|
||||
|
||||
HashMap<IndexBuffer*, IndexBuffer*> ibMapping;
|
||||
for (Vector<SharedPtr<IndexBuffer> >::ConstIterator i = indexBuffers_.Begin(); i != indexBuffers_.End(); ++i)
|
||||
{
|
||||
IndexBuffer* origBuffer = *i;
|
||||
SharedPtr<IndexBuffer> cloneBuffer;
|
||||
|
||||
if (origBuffer)
|
||||
{
|
||||
cloneBuffer = new IndexBuffer(context_);
|
||||
cloneBuffer->SetSize(origBuffer->GetIndexCount(), origBuffer->GetIndexSize() == sizeof(unsigned), origBuffer->IsDynamic());
|
||||
cloneBuffer->SetShadowed(origBuffer->IsShadowed());
|
||||
if (origBuffer->IsShadowed())
|
||||
cloneBuffer->SetData(origBuffer->GetShadowData());
|
||||
else
|
||||
{
|
||||
void* origData = origBuffer->Lock(0, origBuffer->GetIndexCount());
|
||||
if (origData)
|
||||
cloneBuffer->SetData(origData);
|
||||
else
|
||||
LOGERROR("Failed to lock original index buffer for copying");
|
||||
}
|
||||
ibMapping[origBuffer] = cloneBuffer;
|
||||
}
|
||||
|
||||
ret->indexBuffers_.Push(cloneBuffer);
|
||||
}
|
||||
|
||||
// Deep copy all the geometry LOD levels and refer to the copied vertex/index buffers
|
||||
ret->geometries_.Resize(geometries_.Size());
|
||||
for (unsigned i = 0; i < geometries_.Size(); ++i)
|
||||
{
|
||||
ret->geometries_[i].Resize(geometries_[i].Size());
|
||||
for (unsigned j = 0; j < geometries_[i].Size(); ++j)
|
||||
{
|
||||
SharedPtr<Geometry> cloneGeometry;
|
||||
Geometry* origGeometry = geometries_[i][j];
|
||||
|
||||
if (origGeometry)
|
||||
{
|
||||
cloneGeometry = new Geometry(context_);
|
||||
cloneGeometry->SetIndexBuffer(ibMapping[origGeometry->GetIndexBuffer()]);
|
||||
unsigned numVbs = origGeometry->GetNumVertexBuffers();
|
||||
for (unsigned k = 0; k < numVbs; ++k)
|
||||
{
|
||||
cloneGeometry->SetVertexBuffer(k, vbMapping[origGeometry->GetVertexBuffer(k)],
|
||||
origGeometry->GetVertexElementMask(k));
|
||||
}
|
||||
cloneGeometry->SetDrawRange(origGeometry->GetPrimitiveType(), origGeometry->GetIndexStart(),
|
||||
origGeometry->GetIndexCount(), origGeometry->GetVertexStart(), origGeometry->GetVertexCount(), false);
|
||||
cloneGeometry->SetLodDistance(origGeometry->GetLodDistance());
|
||||
}
|
||||
|
||||
ret->geometries_[i][j] = cloneGeometry;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Deep copy the morph data (if any) to allow modifying it
|
||||
for (Vector<ModelMorph>::Iterator i = ret->morphs_.Begin(); i != ret->morphs_.End(); ++i)
|
||||
{
|
||||
ModelMorph& morph = *i;
|
||||
for (HashMap<unsigned, VertexBufferMorph>::Iterator j = morph.buffers_.Begin(); j != morph.buffers_.End(); ++j)
|
||||
{
|
||||
VertexBufferMorph& vbMorph = j->second_;
|
||||
if (vbMorph.dataSize_)
|
||||
{
|
||||
SharedArrayPtr<unsigned char> cloneData(new unsigned char[vbMorph.dataSize_]);
|
||||
memcpy(cloneData.Get(), vbMorph.morphData_.Get(), vbMorph.dataSize_);
|
||||
vbMorph.morphData_ = cloneData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret->SetMemoryUse(GetMemoryUse());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned Model::GetNumGeometryLodLevels(unsigned index) const
|
||||
{
|
||||
return index < geometries_.Size() ? geometries_[index].Size() : 0;
|
||||
|
|
|
@ -43,6 +43,8 @@ struct VertexBufferMorph
|
|||
unsigned elementMask_;
|
||||
/// Number of vertices.
|
||||
unsigned vertexCount_;
|
||||
/// Morphed vertices data size as bytes.
|
||||
unsigned dataSize_;
|
||||
/// Morphed vertices. Stored packed as <index, data> pairs.
|
||||
SharedArrayPtr<unsigned char> morphData_;
|
||||
};
|
||||
|
@ -98,6 +100,8 @@ public:
|
|||
void SetGeometryBoneMappings(const Vector<PODVector<unsigned> >& mappings);
|
||||
/// Set vertex morphs.
|
||||
void SetMorphs(const Vector<ModelMorph>& morphs);
|
||||
/// Clone the model. The geometry data is deep-copied and can be modified in the clone without affecting the original.
|
||||
SharedPtr<Model> Clone(const String& cloneName = String::EMPTY) const;
|
||||
|
||||
/// Return bounding box.
|
||||
const BoundingBox& GetBoundingBox() const { return boundingBox_; }
|
||||
|
|
|
@ -2,6 +2,9 @@ $#include "Model.h"
|
|||
|
||||
class Model : public Resource
|
||||
{
|
||||
// SharedPtr<Model> Clone(const String cloneName = String::EMPTY) const;
|
||||
tolua_outside Model* ModelClone @ Clone(const String cloneName = String::EMPTY) const;
|
||||
|
||||
const BoundingBox& GetBoundingBox() const;
|
||||
Skeleton& GetSkeleton();
|
||||
unsigned GetNumGeometries() const;
|
||||
|
@ -13,9 +16,23 @@ class Model : public Resource
|
|||
const ModelMorph* GetMorph(unsigned index) const;
|
||||
unsigned GetMorphRangeStart(unsigned bufferIndex) const;
|
||||
unsigned GetMorphRangeCount(unsigned bufferIndex) const;
|
||||
|
||||
|
||||
tolua_readonly tolua_property__get_set BoundingBox& boundingBox;
|
||||
tolua_readonly tolua_property__get_set Skeleton skeleton;
|
||||
tolua_readonly tolua_property__get_set unsigned numGeometries;
|
||||
tolua_readonly tolua_property__get_set unsigned numMorphs;
|
||||
};
|
||||
|
||||
${
|
||||
static Model* ModelClone(const Model* model, const String& cloneName = String::EMPTY)
|
||||
{
|
||||
if (!model)
|
||||
return 0;
|
||||
|
||||
SharedPtr<Model> clonedModelPtr = model->Clone(cloneName);
|
||||
Model* clonedModel = clonedModelPtr.Get();
|
||||
clonedModelPtr.Detach();
|
||||
|
||||
return clonedModel;
|
||||
}
|
||||
$}
|
||||
|
|
|
@ -663,9 +663,19 @@ static void RegisterMaterial(asIScriptEngine* engine)
|
|||
engine->RegisterGlobalFunction("String GetTextureUnitName(TextureUnit)", asFUNCTION(Material::GetTextureUnitName), asCALL_CDECL);
|
||||
}
|
||||
|
||||
static Model* ModelClone(const String& cloneName, Model* ptr)
|
||||
{
|
||||
SharedPtr<Model> clone = ptr->Clone(cloneName);
|
||||
// The shared pointer will go out of scope, so have to increment the reference count
|
||||
// (here an auto handle can not be used)
|
||||
clone->AddRef();
|
||||
return clone.Get();
|
||||
}
|
||||
|
||||
static void RegisterModel(asIScriptEngine* engine)
|
||||
{
|
||||
RegisterResource<Model>(engine, "Model");
|
||||
engine->RegisterObjectMethod("Model", "Model@ Clone(const String&in cloneName = String()) const", asFUNCTION(ModelClone), asCALL_CDECL_OBJLAST);
|
||||
engine->RegisterObjectMethod("Model", "const BoundingBox& get_boundingBox() const", asMETHOD(Model, GetBoundingBox), asCALL_THISCALL);
|
||||
engine->RegisterObjectMethod("Model", "Skeleton@+ get_skeleton()", asMETHOD(Model, GetSkeleton), asCALL_THISCALL);
|
||||
engine->RegisterObjectMethod("Model", "uint get_numGeometries() const", asMETHOD(Model, GetNumGeometries), asCALL_THISCALL);
|
||||
|
|
Загрузка…
Ссылка в новой задаче