1 //
2 // Copyright (c) 2008-2017 the Urho3D project.
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21 //
22 
23 #include "../Precompiled.h"
24 
25 #include "../Core/Context.h"
26 #include "../Core/Profiler.h"
27 #include "../Graphics/Geometry.h"
28 #include "../Graphics/IndexBuffer.h"
29 #include "../Graphics/Model.h"
30 #include "../Graphics/Graphics.h"
31 #include "../Graphics/VertexBuffer.h"
32 #include "../IO/Log.h"
33 #include "../IO/File.h"
34 #include "../IO/FileSystem.h"
35 #include "../Resource/ResourceCache.h"
36 #include "../Resource/XMLFile.h"
37 
38 #include "../DebugNew.h"
39 
40 namespace Urho3D
41 {
42 
LookupVertexBuffer(VertexBuffer * buffer,const Vector<SharedPtr<VertexBuffer>> & buffers)43 unsigned LookupVertexBuffer(VertexBuffer* buffer, const Vector<SharedPtr<VertexBuffer> >& buffers)
44 {
45     for (unsigned i = 0; i < buffers.Size(); ++i)
46     {
47         if (buffers[i] == buffer)
48             return i;
49     }
50     return 0;
51 }
52 
LookupIndexBuffer(IndexBuffer * buffer,const Vector<SharedPtr<IndexBuffer>> & buffers)53 unsigned LookupIndexBuffer(IndexBuffer* buffer, const Vector<SharedPtr<IndexBuffer> >& buffers)
54 {
55     for (unsigned i = 0; i < buffers.Size(); ++i)
56     {
57         if (buffers[i] == buffer)
58             return i;
59     }
60     return 0;
61 }
62 
Model(Context * context)63 Model::Model(Context* context) :
64     ResourceWithMetadata(context)
65 {
66 }
67 
~Model()68 Model::~Model()
69 {
70 }
71 
RegisterObject(Context * context)72 void Model::RegisterObject(Context* context)
73 {
74     context->RegisterFactory<Model>();
75 }
76 
BeginLoad(Deserializer & source)77 bool Model::BeginLoad(Deserializer& source)
78 {
79     // Check ID
80     String fileID = source.ReadFileID();
81     if (fileID != "UMDL" && fileID != "UMD2")
82     {
83         URHO3D_LOGERROR(source.GetName() + " is not a valid model file");
84         return false;
85     }
86 
87     bool hasVertexDeclarations = (fileID == "UMD2");
88 
89     geometries_.Clear();
90     geometryBoneMappings_.Clear();
91     geometryCenters_.Clear();
92     morphs_.Clear();
93     vertexBuffers_.Clear();
94     indexBuffers_.Clear();
95 
96     unsigned memoryUse = sizeof(Model);
97     bool async = GetAsyncLoadState() == ASYNC_LOADING;
98 
99     // Read vertex buffers
100     unsigned numVertexBuffers = source.ReadUInt();
101     vertexBuffers_.Reserve(numVertexBuffers);
102     morphRangeStarts_.Resize(numVertexBuffers);
103     morphRangeCounts_.Resize(numVertexBuffers);
104     loadVBData_.Resize(numVertexBuffers);
105     for (unsigned i = 0; i < numVertexBuffers; ++i)
106     {
107         VertexBufferDesc& desc = loadVBData_[i];
108 
109         desc.vertexCount_ = source.ReadUInt();
110         if (!hasVertexDeclarations)
111         {
112             unsigned elementMask = source.ReadUInt();
113             desc.vertexElements_ = VertexBuffer::GetElements(elementMask);
114         }
115         else
116         {
117             desc.vertexElements_.Clear();
118             unsigned numElements = source.ReadUInt();
119             for (unsigned j = 0; j < numElements; ++j)
120             {
121                 unsigned elementDesc = source.ReadUInt();
122                 VertexElementType type = (VertexElementType)(elementDesc & 0xff);
123                 VertexElementSemantic semantic = (VertexElementSemantic)((elementDesc >> 8) & 0xff);
124                 unsigned char index = (unsigned char)((elementDesc >> 16) & 0xff);
125                 desc.vertexElements_.Push(VertexElement(type, semantic, index));
126             }
127         }
128 
129         morphRangeStarts_[i] = source.ReadUInt();
130         morphRangeCounts_[i] = source.ReadUInt();
131 
132         SharedPtr<VertexBuffer> buffer(new VertexBuffer(context_));
133         unsigned vertexSize = VertexBuffer::GetVertexSize(desc.vertexElements_);
134         desc.dataSize_ = desc.vertexCount_ * vertexSize;
135 
136         // Prepare vertex buffer data to be uploaded during EndLoad()
137         if (async)
138         {
139             desc.data_ = new unsigned char[desc.dataSize_];
140             source.Read(desc.data_.Get(), desc.dataSize_);
141         }
142         else
143         {
144             // If not async loading, use locking to avoid extra allocation & copy
145             desc.data_.Reset(); // Make sure no previous data
146             buffer->SetShadowed(true);
147             buffer->SetSize(desc.vertexCount_, desc.vertexElements_);
148             void* dest = buffer->Lock(0, desc.vertexCount_);
149             source.Read(dest, desc.vertexCount_ * vertexSize);
150             buffer->Unlock();
151         }
152 
153         memoryUse += sizeof(VertexBuffer) + desc.vertexCount_ * vertexSize;
154         vertexBuffers_.Push(buffer);
155     }
156 
157     // Read index buffers
158     unsigned numIndexBuffers = source.ReadUInt();
159     indexBuffers_.Reserve(numIndexBuffers);
160     loadIBData_.Resize(numIndexBuffers);
161     for (unsigned i = 0; i < numIndexBuffers; ++i)
162     {
163         unsigned indexCount = source.ReadUInt();
164         unsigned indexSize = source.ReadUInt();
165 
166         SharedPtr<IndexBuffer> buffer(new IndexBuffer(context_));
167 
168         // Prepare index buffer data to be uploaded during EndLoad()
169         if (async)
170         {
171             loadIBData_[i].indexCount_ = indexCount;
172             loadIBData_[i].indexSize_ = indexSize;
173             loadIBData_[i].dataSize_ = indexCount * indexSize;
174             loadIBData_[i].data_ = new unsigned char[loadIBData_[i].dataSize_];
175             source.Read(loadIBData_[i].data_.Get(), loadIBData_[i].dataSize_);
176         }
177         else
178         {
179             // If not async loading, use locking to avoid extra allocation & copy
180             loadIBData_[i].data_.Reset(); // Make sure no previous data
181             buffer->SetShadowed(true);
182             buffer->SetSize(indexCount, indexSize > sizeof(unsigned short));
183             void* dest = buffer->Lock(0, indexCount);
184             source.Read(dest, indexCount * indexSize);
185             buffer->Unlock();
186         }
187 
188         memoryUse += sizeof(IndexBuffer) + indexCount * indexSize;
189         indexBuffers_.Push(buffer);
190     }
191 
192     // Read geometries
193     unsigned numGeometries = source.ReadUInt();
194     geometries_.Reserve(numGeometries);
195     geometryBoneMappings_.Reserve(numGeometries);
196     geometryCenters_.Reserve(numGeometries);
197     loadGeometries_.Resize(numGeometries);
198     for (unsigned i = 0; i < numGeometries; ++i)
199     {
200         // Read bone mappings
201         unsigned boneMappingCount = source.ReadUInt();
202         PODVector<unsigned> boneMapping(boneMappingCount);
203         for (unsigned j = 0; j < boneMappingCount; ++j)
204             boneMapping[j] = source.ReadUInt();
205         geometryBoneMappings_.Push(boneMapping);
206 
207         unsigned numLodLevels = source.ReadUInt();
208         Vector<SharedPtr<Geometry> > geometryLodLevels;
209         geometryLodLevels.Reserve(numLodLevels);
210         loadGeometries_[i].Resize(numLodLevels);
211 
212         for (unsigned j = 0; j < numLodLevels; ++j)
213         {
214             float distance = source.ReadFloat();
215             PrimitiveType type = (PrimitiveType)source.ReadUInt();
216 
217             unsigned vbRef = source.ReadUInt();
218             unsigned ibRef = source.ReadUInt();
219             unsigned indexStart = source.ReadUInt();
220             unsigned indexCount = source.ReadUInt();
221 
222             if (vbRef >= vertexBuffers_.Size())
223             {
224                 URHO3D_LOGERROR("Vertex buffer index out of bounds");
225                 loadVBData_.Clear();
226                 loadIBData_.Clear();
227                 loadGeometries_.Clear();
228                 return false;
229             }
230             if (ibRef >= indexBuffers_.Size())
231             {
232                 URHO3D_LOGERROR("Index buffer index out of bounds");
233                 loadVBData_.Clear();
234                 loadIBData_.Clear();
235                 loadGeometries_.Clear();
236                 return false;
237             }
238 
239             SharedPtr<Geometry> geometry(new Geometry(context_));
240             geometry->SetLodDistance(distance);
241 
242             // Prepare geometry to be defined during EndLoad()
243             loadGeometries_[i][j].type_ = type;
244             loadGeometries_[i][j].vbRef_ = vbRef;
245             loadGeometries_[i][j].ibRef_ = ibRef;
246             loadGeometries_[i][j].indexStart_ = indexStart;
247             loadGeometries_[i][j].indexCount_ = indexCount;
248 
249             geometryLodLevels.Push(geometry);
250             memoryUse += sizeof(Geometry);
251         }
252 
253         geometries_.Push(geometryLodLevels);
254     }
255 
256     // Read morphs
257     unsigned numMorphs = source.ReadUInt();
258     morphs_.Reserve(numMorphs);
259     for (unsigned i = 0; i < numMorphs; ++i)
260     {
261         ModelMorph newMorph;
262 
263         newMorph.name_ = source.ReadString();
264         newMorph.nameHash_ = newMorph.name_;
265         newMorph.weight_ = 0.0f;
266         unsigned numBuffers = source.ReadUInt();
267 
268         for (unsigned j = 0; j < numBuffers; ++j)
269         {
270             VertexBufferMorph newBuffer;
271             unsigned bufferIndex = source.ReadUInt();
272 
273             newBuffer.elementMask_ = source.ReadUInt();
274             newBuffer.vertexCount_ = source.ReadUInt();
275 
276             // Base size: size of each vertex index
277             unsigned vertexSize = sizeof(unsigned);
278             // Add size of individual elements
279             if (newBuffer.elementMask_ & MASK_POSITION)
280                 vertexSize += sizeof(Vector3);
281             if (newBuffer.elementMask_ & MASK_NORMAL)
282                 vertexSize += sizeof(Vector3);
283             if (newBuffer.elementMask_ & MASK_TANGENT)
284                 vertexSize += sizeof(Vector3);
285             newBuffer.dataSize_ = newBuffer.vertexCount_ * vertexSize;
286             newBuffer.morphData_ = new unsigned char[newBuffer.dataSize_];
287 
288             source.Read(&newBuffer.morphData_[0], newBuffer.vertexCount_ * vertexSize);
289 
290             newMorph.buffers_[bufferIndex] = newBuffer;
291             memoryUse += sizeof(VertexBufferMorph) + newBuffer.vertexCount_ * vertexSize;
292         }
293 
294         morphs_.Push(newMorph);
295         memoryUse += sizeof(ModelMorph);
296     }
297 
298     // Read skeleton
299     skeleton_.Load(source);
300     memoryUse += skeleton_.GetNumBones() * sizeof(Bone);
301 
302     // Read bounding box
303     boundingBox_ = source.ReadBoundingBox();
304 
305     // Read geometry centers
306     for (unsigned i = 0; i < geometries_.Size() && !source.IsEof(); ++i)
307         geometryCenters_.Push(source.ReadVector3());
308     while (geometryCenters_.Size() < geometries_.Size())
309         geometryCenters_.Push(Vector3::ZERO);
310     memoryUse += sizeof(Vector3) * geometries_.Size();
311 
312     // Read metadata
313     ResourceCache* cache = GetSubsystem<ResourceCache>();
314     String xmlName = ReplaceExtension(GetName(), ".xml");
315     SharedPtr<XMLFile> file(cache->GetTempResource<XMLFile>(xmlName, false));
316     if (file)
317         LoadMetadataFromXML(file->GetRoot());
318 
319     SetMemoryUse(memoryUse);
320     return true;
321 }
322 
EndLoad()323 bool Model::EndLoad()
324 {
325     // Upload vertex buffer data
326     for (unsigned i = 0; i < vertexBuffers_.Size(); ++i)
327     {
328         VertexBuffer* buffer = vertexBuffers_[i];
329         VertexBufferDesc& desc = loadVBData_[i];
330         if (desc.data_)
331         {
332             buffer->SetShadowed(true);
333             buffer->SetSize(desc.vertexCount_, desc.vertexElements_);
334             buffer->SetData(desc.data_.Get());
335         }
336     }
337 
338     // Upload index buffer data
339     for (unsigned i = 0; i < indexBuffers_.Size(); ++i)
340     {
341         IndexBuffer* buffer = indexBuffers_[i];
342         IndexBufferDesc& desc = loadIBData_[i];
343         if (desc.data_)
344         {
345             buffer->SetShadowed(true);
346             buffer->SetSize(desc.indexCount_, desc.indexSize_ > sizeof(unsigned short));
347             buffer->SetData(desc.data_.Get());
348         }
349     }
350 
351     // Set up geometries
352     for (unsigned i = 0; i < geometries_.Size(); ++i)
353     {
354         for (unsigned j = 0; j < geometries_[i].Size(); ++j)
355         {
356             Geometry* geometry = geometries_[i][j];
357             GeometryDesc& desc = loadGeometries_[i][j];
358             geometry->SetVertexBuffer(0, vertexBuffers_[desc.vbRef_]);
359             geometry->SetIndexBuffer(indexBuffers_[desc.ibRef_]);
360             geometry->SetDrawRange(desc.type_, desc.indexStart_, desc.indexCount_);
361         }
362     }
363 
364     loadVBData_.Clear();
365     loadIBData_.Clear();
366     loadGeometries_.Clear();
367     return true;
368 }
369 
Save(Serializer & dest) const370 bool Model::Save(Serializer& dest) const
371 {
372     // Write ID
373     if (!dest.WriteFileID("UMD2"))
374         return false;
375 
376     // Write vertex buffers
377     dest.WriteUInt(vertexBuffers_.Size());
378     for (unsigned i = 0; i < vertexBuffers_.Size(); ++i)
379     {
380         VertexBuffer* buffer = vertexBuffers_[i];
381         dest.WriteUInt(buffer->GetVertexCount());
382         const PODVector<VertexElement>& elements = buffer->GetElements();
383         dest.WriteUInt(elements.Size());
384         for (unsigned j = 0; j < elements.Size(); ++j)
385         {
386             unsigned elementDesc = ((unsigned)elements[j].type_) |
387                 (((unsigned)elements[j].semantic_) << 8) |
388                 (((unsigned)elements[j].index_) << 16);
389             dest.WriteUInt(elementDesc);
390         }
391         dest.WriteUInt(morphRangeStarts_[i]);
392         dest.WriteUInt(morphRangeCounts_[i]);
393         dest.Write(buffer->GetShadowData(), buffer->GetVertexCount() * buffer->GetVertexSize());
394     }
395     // Write index buffers
396     dest.WriteUInt(indexBuffers_.Size());
397     for (unsigned i = 0; i < indexBuffers_.Size(); ++i)
398     {
399         IndexBuffer* buffer = indexBuffers_[i];
400         dest.WriteUInt(buffer->GetIndexCount());
401         dest.WriteUInt(buffer->GetIndexSize());
402         dest.Write(buffer->GetShadowData(), buffer->GetIndexCount() * buffer->GetIndexSize());
403     }
404     // Write geometries
405     dest.WriteUInt(geometries_.Size());
406     for (unsigned i = 0; i < geometries_.Size(); ++i)
407     {
408         // Write bone mappings
409         dest.WriteUInt(geometryBoneMappings_[i].Size());
410         for (unsigned j = 0; j < geometryBoneMappings_[i].Size(); ++j)
411             dest.WriteUInt(geometryBoneMappings_[i][j]);
412 
413         // Write the LOD levels
414         dest.WriteUInt(geometries_[i].Size());
415         for (unsigned j = 0; j < geometries_[i].Size(); ++j)
416         {
417             Geometry* geometry = geometries_[i][j];
418             dest.WriteFloat(geometry->GetLodDistance());
419             dest.WriteUInt(geometry->GetPrimitiveType());
420             dest.WriteUInt(LookupVertexBuffer(geometry->GetVertexBuffer(0), vertexBuffers_));
421             dest.WriteUInt(LookupIndexBuffer(geometry->GetIndexBuffer(), indexBuffers_));
422             dest.WriteUInt(geometry->GetIndexStart());
423             dest.WriteUInt(geometry->GetIndexCount());
424         }
425     }
426 
427     // Write morphs
428     dest.WriteUInt(morphs_.Size());
429     for (unsigned i = 0; i < morphs_.Size(); ++i)
430     {
431         dest.WriteString(morphs_[i].name_);
432         dest.WriteUInt(morphs_[i].buffers_.Size());
433 
434         // Write morph vertex buffers
435         for (HashMap<unsigned, VertexBufferMorph>::ConstIterator j = morphs_[i].buffers_.Begin();
436              j != morphs_[i].buffers_.End(); ++j)
437         {
438             dest.WriteUInt(j->first_);
439             dest.WriteUInt(j->second_.elementMask_);
440             dest.WriteUInt(j->second_.vertexCount_);
441 
442             // Base size: size of each vertex index
443             unsigned vertexSize = sizeof(unsigned);
444             // Add size of individual elements
445             if (j->second_.elementMask_ & MASK_POSITION)
446                 vertexSize += sizeof(Vector3);
447             if (j->second_.elementMask_ & MASK_NORMAL)
448                 vertexSize += sizeof(Vector3);
449             if (j->second_.elementMask_ & MASK_TANGENT)
450                 vertexSize += sizeof(Vector3);
451 
452             dest.Write(j->second_.morphData_.Get(), vertexSize * j->second_.vertexCount_);
453         }
454     }
455 
456     // Write skeleton
457     skeleton_.Save(dest);
458 
459     // Write bounding box
460     dest.WriteBoundingBox(boundingBox_);
461 
462     // Write geometry centers
463     for (unsigned i = 0; i < geometryCenters_.Size(); ++i)
464         dest.WriteVector3(geometryCenters_[i]);
465 
466     // Write metadata
467     if (HasMetadata())
468     {
469         File* destFile = dynamic_cast<File*>(&dest);
470         if (destFile)
471         {
472             String xmlName = ReplaceExtension(destFile->GetName(), ".xml");
473 
474             SharedPtr<XMLFile> xml(new XMLFile(context_));
475             XMLElement rootElem = xml->CreateRoot("model");
476             SaveMetadataToXML(rootElem);
477 
478             File xmlFile(context_, xmlName, FILE_WRITE);
479             xml->Save(xmlFile);
480         }
481         else
482             URHO3D_LOGWARNING("Can not save model metadata when not saving into a file");
483     }
484 
485     return true;
486 }
487 
SetBoundingBox(const BoundingBox & box)488 void Model::SetBoundingBox(const BoundingBox& box)
489 {
490     boundingBox_ = box;
491 }
492 
SetVertexBuffers(const Vector<SharedPtr<VertexBuffer>> & buffers,const PODVector<unsigned> & morphRangeStarts,const PODVector<unsigned> & morphRangeCounts)493 bool Model::SetVertexBuffers(const Vector<SharedPtr<VertexBuffer> >& buffers, const PODVector<unsigned>& morphRangeStarts,
494     const PODVector<unsigned>& morphRangeCounts)
495 {
496     for (unsigned i = 0; i < buffers.Size(); ++i)
497     {
498         if (!buffers[i])
499         {
500             URHO3D_LOGERROR("Null model vertex buffers specified");
501             return false;
502         }
503         if (!buffers[i]->IsShadowed())
504         {
505             URHO3D_LOGERROR("Model vertex buffers must be shadowed");
506             return false;
507         }
508     }
509 
510     vertexBuffers_ = buffers;
511     morphRangeStarts_.Resize(buffers.Size());
512     morphRangeCounts_.Resize(buffers.Size());
513 
514     // If morph ranges are not specified for buffers, assume to be zero
515     for (unsigned i = 0; i < buffers.Size(); ++i)
516     {
517         morphRangeStarts_[i] = i < morphRangeStarts.Size() ? morphRangeStarts[i] : 0;
518         morphRangeCounts_[i] = i < morphRangeCounts.Size() ? morphRangeCounts[i] : 0;
519     }
520 
521     return true;
522 }
523 
SetIndexBuffers(const Vector<SharedPtr<IndexBuffer>> & buffers)524 bool Model::SetIndexBuffers(const Vector<SharedPtr<IndexBuffer> >& buffers)
525 {
526     for (unsigned i = 0; i < buffers.Size(); ++i)
527     {
528         if (!buffers[i])
529         {
530             URHO3D_LOGERROR("Null model index buffers specified");
531             return false;
532         }
533         if (!buffers[i]->IsShadowed())
534         {
535             URHO3D_LOGERROR("Model index buffers must be shadowed");
536             return false;
537         }
538     }
539 
540     indexBuffers_ = buffers;
541     return true;
542 }
543 
SetNumGeometries(unsigned num)544 void Model::SetNumGeometries(unsigned num)
545 {
546     geometries_.Resize(num);
547     geometryBoneMappings_.Resize(num);
548     geometryCenters_.Resize(num);
549 
550     // For easier creation of from-scratch geometry, ensure that all geometries start with at least 1 LOD level (0 makes no sense)
551     for (unsigned i = 0; i < geometries_.Size(); ++i)
552     {
553         if (geometries_[i].Empty())
554             geometries_[i].Resize(1);
555     }
556 }
557 
SetNumGeometryLodLevels(unsigned index,unsigned num)558 bool Model::SetNumGeometryLodLevels(unsigned index, unsigned num)
559 {
560     if (index >= geometries_.Size())
561     {
562         URHO3D_LOGERROR("Geometry index out of bounds");
563         return false;
564     }
565     if (!num)
566     {
567         URHO3D_LOGERROR("Zero LOD levels not allowed");
568         return false;
569     }
570 
571     geometries_[index].Resize(num);
572     return true;
573 }
574 
SetGeometry(unsigned index,unsigned lodLevel,Geometry * geometry)575 bool Model::SetGeometry(unsigned index, unsigned lodLevel, Geometry* geometry)
576 {
577     if (index >= geometries_.Size())
578     {
579         URHO3D_LOGERROR("Geometry index out of bounds");
580         return false;
581     }
582     if (lodLevel >= geometries_[index].Size())
583     {
584         URHO3D_LOGERROR("LOD level index out of bounds");
585         return false;
586     }
587 
588     geometries_[index][lodLevel] = geometry;
589     return true;
590 }
591 
SetGeometryCenter(unsigned index,const Vector3 & center)592 bool Model::SetGeometryCenter(unsigned index, const Vector3& center)
593 {
594     if (index >= geometryCenters_.Size())
595     {
596         URHO3D_LOGERROR("Geometry index out of bounds");
597         return false;
598     }
599 
600     geometryCenters_[index] = center;
601     return true;
602 }
603 
SetSkeleton(const Skeleton & skeleton)604 void Model::SetSkeleton(const Skeleton& skeleton)
605 {
606     skeleton_ = skeleton;
607 }
608 
SetGeometryBoneMappings(const Vector<PODVector<unsigned>> & geometryBoneMappings)609 void Model::SetGeometryBoneMappings(const Vector<PODVector<unsigned> >& geometryBoneMappings)
610 {
611     geometryBoneMappings_ = geometryBoneMappings;
612 }
613 
SetMorphs(const Vector<ModelMorph> & morphs)614 void Model::SetMorphs(const Vector<ModelMorph>& morphs)
615 {
616     morphs_ = morphs;
617 }
618 
Clone(const String & cloneName) const619 SharedPtr<Model> Model::Clone(const String& cloneName) const
620 {
621     SharedPtr<Model> ret(new Model(context_));
622 
623     ret->SetName(cloneName);
624     ret->boundingBox_ = boundingBox_;
625     ret->skeleton_ = skeleton_;
626     ret->geometryBoneMappings_ = geometryBoneMappings_;
627     ret->geometryCenters_ = geometryCenters_;
628     ret->morphs_ = morphs_;
629     ret->morphRangeStarts_ = morphRangeStarts_;
630     ret->morphRangeCounts_ = morphRangeCounts_;
631 
632     // Deep copy vertex/index buffers
633     HashMap<VertexBuffer*, VertexBuffer*> vbMapping;
634     for (Vector<SharedPtr<VertexBuffer> >::ConstIterator i = vertexBuffers_.Begin(); i != vertexBuffers_.End(); ++i)
635     {
636         VertexBuffer* origBuffer = *i;
637         SharedPtr<VertexBuffer> cloneBuffer;
638 
639         if (origBuffer)
640         {
641             cloneBuffer = new VertexBuffer(context_);
642             cloneBuffer->SetSize(origBuffer->GetVertexCount(), origBuffer->GetElementMask(), origBuffer->IsDynamic());
643             cloneBuffer->SetShadowed(origBuffer->IsShadowed());
644             if (origBuffer->IsShadowed())
645                 cloneBuffer->SetData(origBuffer->GetShadowData());
646             else
647             {
648                 void* origData = origBuffer->Lock(0, origBuffer->GetVertexCount());
649                 if (origData)
650                     cloneBuffer->SetData(origData);
651                 else
652                     URHO3D_LOGERROR("Failed to lock original vertex buffer for copying");
653             }
654             vbMapping[origBuffer] = cloneBuffer;
655         }
656 
657         ret->vertexBuffers_.Push(cloneBuffer);
658     }
659 
660     HashMap<IndexBuffer*, IndexBuffer*> ibMapping;
661     for (Vector<SharedPtr<IndexBuffer> >::ConstIterator i = indexBuffers_.Begin(); i != indexBuffers_.End(); ++i)
662     {
663         IndexBuffer* origBuffer = *i;
664         SharedPtr<IndexBuffer> cloneBuffer;
665 
666         if (origBuffer)
667         {
668             cloneBuffer = new IndexBuffer(context_);
669             cloneBuffer->SetSize(origBuffer->GetIndexCount(), origBuffer->GetIndexSize() == sizeof(unsigned),
670                 origBuffer->IsDynamic());
671             cloneBuffer->SetShadowed(origBuffer->IsShadowed());
672             if (origBuffer->IsShadowed())
673                 cloneBuffer->SetData(origBuffer->GetShadowData());
674             else
675             {
676                 void* origData = origBuffer->Lock(0, origBuffer->GetIndexCount());
677                 if (origData)
678                     cloneBuffer->SetData(origData);
679                 else
680                     URHO3D_LOGERROR("Failed to lock original index buffer for copying");
681             }
682             ibMapping[origBuffer] = cloneBuffer;
683         }
684 
685         ret->indexBuffers_.Push(cloneBuffer);
686     }
687 
688     // Deep copy all the geometry LOD levels and refer to the copied vertex/index buffers
689     ret->geometries_.Resize(geometries_.Size());
690     for (unsigned i = 0; i < geometries_.Size(); ++i)
691     {
692         ret->geometries_[i].Resize(geometries_[i].Size());
693         for (unsigned j = 0; j < geometries_[i].Size(); ++j)
694         {
695             SharedPtr<Geometry> cloneGeometry;
696             Geometry* origGeometry = geometries_[i][j];
697 
698             if (origGeometry)
699             {
700                 cloneGeometry = new Geometry(context_);
701                 cloneGeometry->SetIndexBuffer(ibMapping[origGeometry->GetIndexBuffer()]);
702                 unsigned numVbs = origGeometry->GetNumVertexBuffers();
703                 for (unsigned k = 0; k < numVbs; ++k)
704                 {
705                     cloneGeometry->SetVertexBuffer(k, vbMapping[origGeometry->GetVertexBuffer(k)]);
706                 }
707                 cloneGeometry->SetDrawRange(origGeometry->GetPrimitiveType(), origGeometry->GetIndexStart(),
708                     origGeometry->GetIndexCount(), origGeometry->GetVertexStart(), origGeometry->GetVertexCount(), false);
709                 cloneGeometry->SetLodDistance(origGeometry->GetLodDistance());
710             }
711 
712             ret->geometries_[i][j] = cloneGeometry;
713         }
714     }
715 
716 
717     // Deep copy the morph data (if any) to allow modifying it
718     for (Vector<ModelMorph>::Iterator i = ret->morphs_.Begin(); i != ret->morphs_.End(); ++i)
719     {
720         ModelMorph& morph = *i;
721         for (HashMap<unsigned, VertexBufferMorph>::Iterator j = morph.buffers_.Begin(); j != morph.buffers_.End(); ++j)
722         {
723             VertexBufferMorph& vbMorph = j->second_;
724             if (vbMorph.dataSize_)
725             {
726                 SharedArrayPtr<unsigned char> cloneData(new unsigned char[vbMorph.dataSize_]);
727                 memcpy(cloneData.Get(), vbMorph.morphData_.Get(), vbMorph.dataSize_);
728                 vbMorph.morphData_ = cloneData;
729             }
730         }
731     }
732 
733     ret->SetMemoryUse(GetMemoryUse());
734 
735     return ret;
736 }
737 
GetNumGeometryLodLevels(unsigned index) const738 unsigned Model::GetNumGeometryLodLevels(unsigned index) const
739 {
740     return index < geometries_.Size() ? geometries_[index].Size() : 0;
741 }
742 
GetGeometry(unsigned index,unsigned lodLevel) const743 Geometry* Model::GetGeometry(unsigned index, unsigned lodLevel) const
744 {
745     if (index >= geometries_.Size() || geometries_[index].Empty())
746         return 0;
747 
748     if (lodLevel >= geometries_[index].Size())
749         lodLevel = geometries_[index].Size() - 1;
750 
751     return geometries_[index][lodLevel];
752 }
753 
GetMorph(unsigned index) const754 const ModelMorph* Model::GetMorph(unsigned index) const
755 {
756     return index < morphs_.Size() ? &morphs_[index] : 0;
757 }
758 
GetMorph(const String & name) const759 const ModelMorph* Model::GetMorph(const String& name) const
760 {
761     return GetMorph(StringHash(name));
762 }
763 
GetMorph(StringHash nameHash) const764 const ModelMorph* Model::GetMorph(StringHash nameHash) const
765 {
766     for (Vector<ModelMorph>::ConstIterator i = morphs_.Begin(); i != morphs_.End(); ++i)
767     {
768         if (i->nameHash_ == nameHash)
769             return &(*i);
770     }
771 
772     return 0;
773 }
774 
GetMorphRangeStart(unsigned bufferIndex) const775 unsigned Model::GetMorphRangeStart(unsigned bufferIndex) const
776 {
777     return bufferIndex < vertexBuffers_.Size() ? morphRangeStarts_[bufferIndex] : 0;
778 }
779 
GetMorphRangeCount(unsigned bufferIndex) const780 unsigned Model::GetMorphRangeCount(unsigned bufferIndex) const
781 {
782     return bufferIndex < vertexBuffers_.Size() ? morphRangeCounts_[bufferIndex] : 0;
783 }
784 
785 }
786