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