Coverage Report

Created: 2025-06-22 07:30

/src/assimp/code/AssetLib/Ogre/OgreStructs.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
Open Asset Import Library (assimp)
3
----------------------------------------------------------------------
4
5
Copyright (c) 2006-2025, assimp team
6
7
All rights reserved.
8
9
Redistribution and use of this software in source and binary forms,
10
with or without modification, are permitted provided that the
11
following conditions are met:
12
13
* Redistributions of source code must retain the above
14
  copyright notice, this list of conditions and the
15
  following disclaimer.
16
17
* Redistributions in binary form must reproduce the above
18
  copyright notice, this list of conditions and the
19
  following disclaimer in the documentation and/or other
20
  materials provided with the distribution.
21
22
* Neither the name of the assimp team, nor the names of its
23
  contributors may be used to endorse or promote products
24
  derived from this software without specific prior
25
  written permission of the assimp team.
26
27
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38
39
----------------------------------------------------------------------
40
*/
41
42
#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
43
44
#include "OgreStructs.h"
45
#include <assimp/Exceptional.h>
46
#include <assimp/TinyFormatter.h>
47
#include <assimp/scene.h>
48
#include <assimp/DefaultLogger.hpp>
49
50
namespace Assimp {
51
namespace Ogre {
52
53
// VertexElement
54
55
VertexElement::VertexElement() :
56
0
        index(0),
57
0
        source(0),
58
0
        offset(0),
59
0
        type(VET_FLOAT1),
60
0
        semantic(VES_POSITION) {
61
0
}
62
63
0
size_t VertexElement::Size() const {
64
0
    return TypeSize(type);
65
0
}
66
67
0
size_t VertexElement::ComponentCount() const {
68
0
    return ComponentCount(type);
69
0
}
70
71
0
size_t VertexElement::ComponentCount(Type type) {
72
0
    switch (type) {
73
0
    case VET_COLOUR:
74
0
    case VET_COLOUR_ABGR:
75
0
    case VET_COLOUR_ARGB:
76
0
    case VET_FLOAT1:
77
0
    case VET_DOUBLE1:
78
0
    case VET_SHORT1:
79
0
    case VET_USHORT1:
80
0
    case VET_INT1:
81
0
    case VET_UINT1:
82
0
        return 1;
83
0
    case VET_FLOAT2:
84
0
    case VET_DOUBLE2:
85
0
    case VET_SHORT2:
86
0
    case VET_USHORT2:
87
0
    case VET_INT2:
88
0
    case VET_UINT2:
89
0
        return 2;
90
0
    case VET_FLOAT3:
91
0
    case VET_DOUBLE3:
92
0
    case VET_SHORT3:
93
0
    case VET_USHORT3:
94
0
    case VET_INT3:
95
0
    case VET_UINT3:
96
0
        return 3;
97
0
    case VET_FLOAT4:
98
0
    case VET_DOUBLE4:
99
0
    case VET_SHORT4:
100
0
    case VET_USHORT4:
101
0
    case VET_INT4:
102
0
    case VET_UINT4:
103
0
    case VET_UBYTE4:
104
0
        return 4;
105
0
    }
106
0
    return 0;
107
0
}
108
109
0
size_t VertexElement::TypeSize(Type type) {
110
0
    switch (type) {
111
0
    case VET_COLOUR:
112
0
    case VET_COLOUR_ABGR:
113
0
    case VET_COLOUR_ARGB:
114
0
        return sizeof(unsigned int);
115
0
    case VET_FLOAT1:
116
0
        return sizeof(float);
117
0
    case VET_FLOAT2:
118
0
        return sizeof(float) * 2;
119
0
    case VET_FLOAT3:
120
0
        return sizeof(float) * 3;
121
0
    case VET_FLOAT4:
122
0
        return sizeof(float) * 4;
123
0
    case VET_DOUBLE1:
124
0
        return sizeof(double);
125
0
    case VET_DOUBLE2:
126
0
        return sizeof(double) * 2;
127
0
    case VET_DOUBLE3:
128
0
        return sizeof(double) * 3;
129
0
    case VET_DOUBLE4:
130
0
        return sizeof(double) * 4;
131
0
    case VET_SHORT1:
132
0
        return sizeof(short);
133
0
    case VET_SHORT2:
134
0
        return sizeof(short) * 2;
135
0
    case VET_SHORT3:
136
0
        return sizeof(short) * 3;
137
0
    case VET_SHORT4:
138
0
        return sizeof(short) * 4;
139
0
    case VET_USHORT1:
140
0
        return sizeof(unsigned short);
141
0
    case VET_USHORT2:
142
0
        return sizeof(unsigned short) * 2;
143
0
    case VET_USHORT3:
144
0
        return sizeof(unsigned short) * 3;
145
0
    case VET_USHORT4:
146
0
        return sizeof(unsigned short) * 4;
147
0
    case VET_INT1:
148
0
        return sizeof(int);
149
0
    case VET_INT2:
150
0
        return sizeof(int) * 2;
151
0
    case VET_INT3:
152
0
        return sizeof(int) * 3;
153
0
    case VET_INT4:
154
0
        return sizeof(int) * 4;
155
0
    case VET_UINT1:
156
0
        return sizeof(unsigned int);
157
0
    case VET_UINT2:
158
0
        return sizeof(unsigned int) * 2;
159
0
    case VET_UINT3:
160
0
        return sizeof(unsigned int) * 3;
161
0
    case VET_UINT4:
162
0
        return sizeof(unsigned int) * 4;
163
0
    case VET_UBYTE4:
164
0
        return sizeof(unsigned char) * 4;
165
0
    }
166
0
    return 0;
167
0
}
168
169
0
std::string VertexElement::TypeToString() {
170
0
    return TypeToString(type);
171
0
}
172
173
0
std::string VertexElement::TypeToString(Type type) {
174
0
    switch (type) {
175
0
    case VET_COLOUR: return "COLOUR";
176
0
    case VET_COLOUR_ABGR: return "COLOUR_ABGR";
177
0
    case VET_COLOUR_ARGB: return "COLOUR_ARGB";
178
0
    case VET_FLOAT1: return "FLOAT1";
179
0
    case VET_FLOAT2: return "FLOAT2";
180
0
    case VET_FLOAT3: return "FLOAT3";
181
0
    case VET_FLOAT4: return "FLOAT4";
182
0
    case VET_DOUBLE1: return "DOUBLE1";
183
0
    case VET_DOUBLE2: return "DOUBLE2";
184
0
    case VET_DOUBLE3: return "DOUBLE3";
185
0
    case VET_DOUBLE4: return "DOUBLE4";
186
0
    case VET_SHORT1: return "SHORT1";
187
0
    case VET_SHORT2: return "SHORT2";
188
0
    case VET_SHORT3: return "SHORT3";
189
0
    case VET_SHORT4: return "SHORT4";
190
0
    case VET_USHORT1: return "USHORT1";
191
0
    case VET_USHORT2: return "USHORT2";
192
0
    case VET_USHORT3: return "USHORT3";
193
0
    case VET_USHORT4: return "USHORT4";
194
0
    case VET_INT1: return "INT1";
195
0
    case VET_INT2: return "INT2";
196
0
    case VET_INT3: return "INT3";
197
0
    case VET_INT4: return "INT4";
198
0
    case VET_UINT1: return "UINT1";
199
0
    case VET_UINT2: return "UINT2";
200
0
    case VET_UINT3: return "UINT3";
201
0
    case VET_UINT4: return "UINT4";
202
0
    case VET_UBYTE4: return "UBYTE4";
203
0
    }
204
0
    return "Uknown_VertexElement::Type";
205
0
}
206
207
0
std::string VertexElement::SemanticToString() {
208
0
    return SemanticToString(semantic);
209
0
}
210
211
0
std::string VertexElement::SemanticToString(Semantic semantic) {
212
0
    switch (semantic) {
213
0
    case VES_POSITION: return "POSITION";
214
0
    case VES_BLEND_WEIGHTS: return "BLEND_WEIGHTS";
215
0
    case VES_BLEND_INDICES: return "BLEND_INDICES";
216
0
    case VES_NORMAL: return "NORMAL";
217
0
    case VES_DIFFUSE: return "DIFFUSE";
218
0
    case VES_SPECULAR: return "SPECULAR";
219
0
    case VES_TEXTURE_COORDINATES: return "TEXTURE_COORDINATES";
220
0
    case VES_BINORMAL: return "BINORMAL";
221
0
    case VES_TANGENT: return "TANGENT";
222
0
    }
223
0
    return "Uknown_VertexElement::Semantic";
224
0
}
225
226
// IVertexData
227
228
IVertexData::IVertexData() :
229
0
        count(0) {
230
0
}
231
232
0
bool IVertexData::HasBoneAssignments() const {
233
0
    return !boneAssignments.empty();
234
0
}
235
236
0
void IVertexData::AddVertexMapping(uint32_t oldIndex, uint32_t newIndex) {
237
0
    BoneAssignmentsForVertex(oldIndex, newIndex, boneAssignmentsMap[newIndex]);
238
0
    vertexIndexMapping[oldIndex].push_back(newIndex);
239
0
}
240
241
0
void IVertexData::BoneAssignmentsForVertex(uint32_t currentIndex, uint32_t newIndex, VertexBoneAssignmentList &dest) const {
242
0
    for (const auto &boneAssign : boneAssignments) {
243
0
        if (boneAssign.vertexIndex == currentIndex) {
244
0
            VertexBoneAssignment a = boneAssign;
245
0
            a.vertexIndex = newIndex;
246
0
            dest.push_back(a);
247
0
        }
248
0
    }
249
0
}
250
251
0
AssimpVertexBoneWeightList IVertexData::AssimpBoneWeights(size_t vertices) {
252
0
    AssimpVertexBoneWeightList weights;
253
0
    for (size_t vi = 0; vi < vertices; ++vi) {
254
0
        VertexBoneAssignmentList &vertexWeights = boneAssignmentsMap[static_cast<unsigned int>(vi)];
255
0
        for (VertexBoneAssignmentList::const_iterator iter = vertexWeights.begin(), end = vertexWeights.end();
256
0
                iter != end; ++iter) {
257
0
            std::vector<aiVertexWeight> &boneWeights = weights[iter->boneIndex];
258
0
            boneWeights.emplace_back(static_cast<unsigned int>(vi), iter->weight);
259
0
        }
260
0
    }
261
0
    return weights;
262
0
}
263
264
0
std::set<uint16_t> IVertexData::ReferencedBonesByWeights() const {
265
0
    std::set<uint16_t> referenced;
266
0
    for (const auto &boneAssign : boneAssignments) {
267
0
        referenced.insert(boneAssign.boneIndex);
268
0
    }
269
0
    return referenced;
270
0
}
271
272
// VertexData
273
274
0
VertexData::VertexData() = default;
275
276
0
VertexData::~VertexData() {
277
0
    Reset();
278
0
}
279
280
0
void VertexData::Reset() {
281
    // Releases shared ptr memory streams.
282
0
    vertexBindings.clear();
283
0
    vertexElements.clear();
284
0
}
285
286
0
uint32_t VertexData::VertexSize(uint16_t source) const {
287
0
    uint32_t size = 0;
288
0
    for (const auto &element : vertexElements) {
289
0
        if (element.source == source)
290
0
            size += static_cast<uint32_t>(element.Size());
291
0
    }
292
0
    return size;
293
0
}
294
295
0
MemoryStream *VertexData::VertexBuffer(uint16_t source) {
296
0
    if (vertexBindings.find(source) != vertexBindings.end())
297
0
        return vertexBindings[source].get();
298
0
    return nullptr;
299
0
}
300
301
0
VertexElement *VertexData::GetVertexElement(VertexElement::Semantic semantic, uint16_t index) {
302
0
    for (auto &element : vertexElements) {
303
0
        if (element.semantic == semantic && element.index == index)
304
0
            return &element;
305
0
    }
306
0
    return nullptr;
307
0
}
308
309
// VertexDataXml
310
311
0
VertexDataXml::VertexDataXml() = default;
312
313
0
bool VertexDataXml::HasPositions() const {
314
0
    return !positions.empty();
315
0
}
316
317
0
bool VertexDataXml::HasNormals() const {
318
0
    return !normals.empty();
319
0
}
320
321
0
bool VertexDataXml::HasTangents() const {
322
0
    return !tangents.empty();
323
0
}
324
325
0
bool VertexDataXml::HasUvs() const {
326
0
    return !uvs.empty();
327
0
}
328
329
0
size_t VertexDataXml::NumUvs() const {
330
0
    return uvs.size();
331
0
}
332
333
// IndexData
334
335
IndexData::IndexData() :
336
0
        count(0),
337
0
        faceCount(0),
338
0
        is32bit(false) {
339
0
}
340
341
0
IndexData::~IndexData() {
342
0
    Reset();
343
0
}
344
345
0
void IndexData::Reset() {
346
    // Release shared ptr memory stream.
347
0
    buffer.reset();
348
0
}
349
350
0
size_t IndexData::IndexSize() const {
351
0
    return (is32bit ? sizeof(uint32_t) : sizeof(uint16_t));
352
0
}
353
354
0
size_t IndexData::FaceSize() const {
355
0
    return IndexSize() * 3;
356
0
}
357
358
// Mesh
359
360
Mesh::Mesh() :
361
0
        hasSkeletalAnimations(false),
362
0
        skeleton(nullptr),
363
0
        sharedVertexData(nullptr),
364
0
        subMeshes(),
365
0
        animations(),
366
0
        poses() {
367
0
}
368
369
0
Mesh::~Mesh() {
370
0
    Reset();
371
0
}
372
373
0
void Mesh::Reset() {
374
0
    OGRE_SAFE_DELETE(skeleton)
375
0
    OGRE_SAFE_DELETE(sharedVertexData)
376
377
0
    for (auto &mesh : subMeshes) {
378
0
        OGRE_SAFE_DELETE(mesh)
379
0
    }
380
0
    subMeshes.clear();
381
0
    for (auto &anim : animations) {
382
0
        OGRE_SAFE_DELETE(anim)
383
0
    }
384
0
    animations.clear();
385
0
    for (auto &pose : poses) {
386
0
        OGRE_SAFE_DELETE(pose)
387
0
    }
388
0
    poses.clear();
389
0
}
390
391
0
size_t Mesh::NumSubMeshes() const {
392
0
    return subMeshes.size();
393
0
}
394
395
0
SubMesh *Mesh::GetSubMesh(size_t index) const {
396
0
    for (size_t i = 0; i < subMeshes.size(); ++i) {
397
0
        if (subMeshes[i]->index == index) {
398
0
            return subMeshes[i];
399
0
        }
400
0
    }
401
0
    return nullptr;
402
0
}
403
404
0
void Mesh::ConvertToAssimpScene(aiScene *dest) {
405
0
    if (nullptr == dest) {
406
0
        return;
407
0
    }
408
409
    // Setup
410
0
    dest->mNumMeshes = static_cast<unsigned int>(NumSubMeshes());
411
0
    dest->mMeshes = new aiMesh *[dest->mNumMeshes];
412
413
    // Create root node
414
0
    dest->mRootNode = new aiNode();
415
0
    dest->mRootNode->mNumMeshes = dest->mNumMeshes;
416
0
    dest->mRootNode->mMeshes = new unsigned int[dest->mRootNode->mNumMeshes];
417
418
    // Export meshes
419
0
    for (size_t i = 0; i < dest->mNumMeshes; ++i) {
420
0
        dest->mMeshes[i] = subMeshes[i]->ConvertToAssimpMesh(this);
421
0
        dest->mRootNode->mMeshes[i] = static_cast<unsigned int>(i);
422
0
    }
423
424
    // Export skeleton
425
0
    if (skeleton) {
426
        // Bones
427
0
        if (!skeleton->bones.empty()) {
428
0
            BoneList rootBones = skeleton->RootBones();
429
0
            dest->mRootNode->mNumChildren = static_cast<unsigned int>(rootBones.size());
430
0
            dest->mRootNode->mChildren = new aiNode *[dest->mRootNode->mNumChildren];
431
432
0
            for (size_t i = 0, len = rootBones.size(); i < len; ++i) {
433
0
                dest->mRootNode->mChildren[i] = rootBones[i]->ConvertToAssimpNode(skeleton, dest->mRootNode);
434
0
            }
435
0
        }
436
437
        // Animations
438
0
        if (!skeleton->animations.empty()) {
439
0
            dest->mNumAnimations = static_cast<unsigned int>(skeleton->animations.size());
440
0
            dest->mAnimations = new aiAnimation *[dest->mNumAnimations];
441
442
0
            for (size_t i = 0, len = skeleton->animations.size(); i < len; ++i) {
443
0
                dest->mAnimations[i] = skeleton->animations[i]->ConvertToAssimpAnimation();
444
0
            }
445
0
        }
446
0
    }
447
0
}
448
449
// ISubMesh
450
451
ISubMesh::ISubMesh() :
452
0
        index(0),
453
0
        materialIndex(-1),
454
0
        usesSharedVertexData(false),
455
0
        operationType(OT_POINT_LIST) {
456
0
}
457
458
// SubMesh
459
460
SubMesh::SubMesh() :
461
0
        vertexData(nullptr),
462
0
        indexData(new IndexData()) {
463
0
}
464
465
0
SubMesh::~SubMesh() {
466
0
    Reset();
467
0
}
468
469
0
void SubMesh::Reset(){
470
0
    OGRE_SAFE_DELETE(vertexData)
471
0
            OGRE_SAFE_DELETE(indexData)
472
0
}
473
474
0
aiMesh *SubMesh::ConvertToAssimpMesh(Mesh *parent) {
475
0
    if (operationType != OT_TRIANGLE_LIST) {
476
0
        throw DeadlyImportError("Only mesh operation type OT_TRIANGLE_LIST is supported. Found ", operationType);
477
0
    }
478
479
0
    aiMesh *dest = new aiMesh();
480
0
    dest->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
481
482
0
    if (!name.empty())
483
0
        dest->mName = name;
484
485
    // Material index
486
0
    if (materialIndex != -1)
487
0
        dest->mMaterialIndex = materialIndex;
488
489
    // Pick source vertex data from shader geometry or from internal geometry.
490
0
    VertexData *src = (!usesSharedVertexData ? vertexData : parent->sharedVertexData);
491
492
0
    VertexElement *positionsElement = src->GetVertexElement(VertexElement::VES_POSITION);
493
0
    VertexElement *normalsElement = src->GetVertexElement(VertexElement::VES_NORMAL);
494
0
    VertexElement *uv1Element = src->GetVertexElement(VertexElement::VES_TEXTURE_COORDINATES, 0);
495
0
    VertexElement *uv2Element = src->GetVertexElement(VertexElement::VES_TEXTURE_COORDINATES, 1);
496
497
    // Sanity checks
498
0
    if (!positionsElement) {
499
0
        throw DeadlyImportError("Failed to import Ogre VertexElement::VES_POSITION. Mesh does not have vertex positions!");
500
0
    } else if (positionsElement->type != VertexElement::VET_FLOAT3) {
501
0
        throw DeadlyImportError("Ogre Mesh position vertex element type != VertexElement::VET_FLOAT3. This is not supported.");
502
0
    } else if (normalsElement && normalsElement->type != VertexElement::VET_FLOAT3) {
503
0
        throw DeadlyImportError("Ogre Mesh normal vertex element type != VertexElement::VET_FLOAT3. This is not supported.");
504
0
    }
505
506
    // Faces
507
0
    dest->mNumFaces = indexData->faceCount;
508
0
    dest->mFaces = new aiFace[dest->mNumFaces];
509
510
    // Assimp required unique vertices, we need to convert from Ogres shared indexing.
511
0
    size_t uniqueVertexCount = dest->mNumFaces * 3;
512
0
    dest->mNumVertices = static_cast<unsigned int>(uniqueVertexCount);
513
0
    dest->mVertices = new aiVector3D[dest->mNumVertices];
514
515
    // Source streams
516
0
    MemoryStream *positions = src->VertexBuffer(positionsElement->source);
517
0
    MemoryStream *normals = (normalsElement ? src->VertexBuffer(normalsElement->source) : nullptr);
518
0
    MemoryStream *uv1 = (uv1Element ? src->VertexBuffer(uv1Element->source) : nullptr);
519
0
    MemoryStream *uv2 = (uv2Element ? src->VertexBuffer(uv2Element->source) : nullptr);
520
521
    // Element size
522
0
    const size_t sizePosition = positionsElement->Size();
523
0
    const size_t sizeNormal = (normalsElement ? normalsElement->Size() : 0);
524
0
    const size_t sizeUv1 = (uv1Element ? uv1Element->Size() : 0);
525
0
    const size_t sizeUv2 = (uv2Element ? uv2Element->Size() : 0);
526
527
    // Vertex width
528
0
    const size_t vWidthPosition = src->VertexSize(positionsElement->source);
529
0
    const size_t vWidthNormal = (normalsElement ? src->VertexSize(normalsElement->source) : 0);
530
0
    const size_t vWidthUv1 = (uv1Element ? src->VertexSize(uv1Element->source) : 0);
531
0
    const size_t vWidthUv2 = (uv2Element ? src->VertexSize(uv2Element->source) : 0);
532
533
0
    bool boneAssignments = src->HasBoneAssignments();
534
535
    // Prepare normals
536
0
    if (normals)
537
0
        dest->mNormals = new aiVector3D[dest->mNumVertices];
538
539
    // Prepare UVs, ignoring incompatible UVs.
540
0
    if (uv1) {
541
0
        if (uv1Element->type == VertexElement::VET_FLOAT2 || uv1Element->type == VertexElement::VET_FLOAT3) {
542
0
            dest->mNumUVComponents[0] = static_cast<unsigned int>(uv1Element->ComponentCount());
543
0
            dest->mTextureCoords[0] = new aiVector3D[dest->mNumVertices];
544
0
        } else {
545
0
            ASSIMP_LOG_WARN("Ogre imported UV0 type ", uv1Element->TypeToString(), " is not compatible with Assimp. Ignoring UV.");
546
0
            uv1 = nullptr;
547
0
        }
548
0
    }
549
0
    if (uv2) {
550
0
        if (uv2Element->type == VertexElement::VET_FLOAT2 || uv2Element->type == VertexElement::VET_FLOAT3) {
551
0
            dest->mNumUVComponents[1] = static_cast<unsigned int>(uv2Element->ComponentCount());
552
0
            dest->mTextureCoords[1] = new aiVector3D[dest->mNumVertices];
553
0
        } else {
554
0
            ASSIMP_LOG_WARN("Ogre imported UV0 type ", uv2Element->TypeToString(), " is not compatible with Assimp. Ignoring UV.");
555
0
            uv2 = nullptr;
556
0
        }
557
0
    }
558
559
0
    aiVector3D *uv1Dest = (uv1 ? dest->mTextureCoords[0] : nullptr);
560
0
    aiVector3D *uv2Dest = (uv2 ? dest->mTextureCoords[1] : nullptr);
561
562
0
    MemoryStream *faces = indexData->buffer.get();
563
0
    for (size_t fi = 0, isize = indexData->IndexSize(), fsize = indexData->FaceSize();
564
0
            fi < dest->mNumFaces; ++fi) {
565
        // Source Ogre face
566
0
        aiFace ogreFace;
567
0
        ogreFace.mNumIndices = 3;
568
0
        ogreFace.mIndices = new unsigned int[3];
569
570
0
        faces->Seek(fi * fsize, aiOrigin_SET);
571
0
        if (indexData->is32bit) {
572
0
            faces->Read(&ogreFace.mIndices[0], isize, 3);
573
0
        } else {
574
0
            uint16_t iout = 0;
575
0
            for (size_t ii = 0; ii < 3; ++ii) {
576
0
                faces->Read(&iout, isize, 1);
577
0
                ogreFace.mIndices[ii] = static_cast<unsigned int>(iout);
578
0
            }
579
0
        }
580
581
        // Destination Assimp face
582
0
        aiFace &face = dest->mFaces[fi];
583
0
        face.mNumIndices = 3;
584
0
        face.mIndices = new unsigned int[3];
585
586
0
        const size_t pos = fi * 3;
587
0
        for (size_t v = 0; v < 3; ++v) {
588
0
            const size_t newIndex = pos + v;
589
590
            // Write face index
591
0
            face.mIndices[v] = static_cast<unsigned int>(newIndex);
592
593
            // Ogres vertex index to ref into the source buffers.
594
0
            const size_t ogreVertexIndex = ogreFace.mIndices[v];
595
0
            src->AddVertexMapping(static_cast<uint32_t>(ogreVertexIndex), static_cast<uint32_t>(newIndex));
596
597
            // Position
598
0
            positions->Seek((vWidthPosition * ogreVertexIndex) + positionsElement->offset, aiOrigin_SET);
599
0
            positions->Read(&dest->mVertices[newIndex], sizePosition, 1);
600
601
            // Normal
602
0
            if (normals) {
603
0
                normals->Seek((vWidthNormal * ogreVertexIndex) + normalsElement->offset, aiOrigin_SET);
604
0
                normals->Read(&dest->mNormals[newIndex], sizeNormal, 1);
605
0
            }
606
            // UV0
607
0
            if (uv1 && uv1Dest) {
608
0
                uv1->Seek((vWidthUv1 * ogreVertexIndex) + uv1Element->offset, aiOrigin_SET);
609
0
                uv1->Read(&uv1Dest[newIndex], sizeUv1, 1);
610
0
                uv1Dest[newIndex].y = (uv1Dest[newIndex].y * -1) + 1; // Flip UV from Ogre to Assimp form
611
0
            }
612
            // UV1
613
0
            if (uv2 && uv2Dest) {
614
0
                uv2->Seek((vWidthUv2 * ogreVertexIndex) + uv2Element->offset, aiOrigin_SET);
615
0
                uv2->Read(&uv2Dest[newIndex], sizeUv2, 1);
616
0
                uv2Dest[newIndex].y = (uv2Dest[newIndex].y * -1) + 1; // Flip UV from Ogre to Assimp form
617
0
            }
618
0
        }
619
0
    }
620
621
    // Bones and bone weights
622
0
    if (parent->skeleton && boneAssignments) {
623
0
        AssimpVertexBoneWeightList weights = src->AssimpBoneWeights(dest->mNumVertices);
624
0
        std::set<uint16_t> referencedBones = src->ReferencedBonesByWeights();
625
626
0
        dest->mNumBones = static_cast<unsigned int>(referencedBones.size());
627
0
        dest->mBones = new aiBone *[dest->mNumBones];
628
629
0
        size_t assimpBoneIndex = 0;
630
0
        for (std::set<uint16_t>::const_iterator rbIter = referencedBones.begin(), rbEnd = referencedBones.end(); rbIter != rbEnd; ++rbIter, ++assimpBoneIndex) {
631
0
            Bone *bone = parent->skeleton->BoneById((*rbIter));
632
0
            dest->mBones[assimpBoneIndex] = bone->ConvertToAssimpBone(parent->skeleton, weights[bone->id]);
633
0
        }
634
0
    }
635
636
0
    return dest;
637
0
}
638
639
// MeshXml
640
641
MeshXml::MeshXml() :
642
0
        skeleton(nullptr),
643
0
        sharedVertexData(nullptr) {
644
0
}
645
646
0
MeshXml::~MeshXml() {
647
0
    Reset();
648
0
}
649
650
0
void MeshXml::Reset() {
651
0
    OGRE_SAFE_DELETE(skeleton)
652
0
    OGRE_SAFE_DELETE(sharedVertexData)
653
654
0
    for (auto &mesh : subMeshes) {
655
0
        OGRE_SAFE_DELETE(mesh)
656
0
    }
657
0
    subMeshes.clear();
658
0
}
659
660
0
size_t MeshXml::NumSubMeshes() const {
661
0
    return subMeshes.size();
662
0
}
663
664
0
SubMeshXml *MeshXml::GetSubMesh(uint16_t index) const {
665
0
    for (size_t i = 0; i < subMeshes.size(); ++i)
666
0
        if (subMeshes[i]->index == index)
667
0
            return subMeshes[i];
668
0
    return nullptr;
669
0
}
670
671
0
void MeshXml::ConvertToAssimpScene(aiScene *dest) {
672
    // Setup
673
0
    dest->mNumMeshes = static_cast<unsigned int>(NumSubMeshes());
674
0
    dest->mMeshes = new aiMesh *[dest->mNumMeshes];
675
676
    // Create root node
677
0
    dest->mRootNode = new aiNode();
678
0
    dest->mRootNode->mNumMeshes = dest->mNumMeshes;
679
0
    dest->mRootNode->mMeshes = new unsigned int[dest->mRootNode->mNumMeshes];
680
681
    // Export meshes
682
0
    for (size_t i = 0; i < dest->mNumMeshes; ++i) {
683
0
        dest->mMeshes[i] = subMeshes[i]->ConvertToAssimpMesh(this);
684
0
        dest->mRootNode->mMeshes[i] = static_cast<unsigned int>(i);
685
0
    }
686
687
    // Export skeleton
688
0
    if (skeleton) {
689
        // Bones
690
0
        if (!skeleton->bones.empty()) {
691
0
            BoneList rootBones = skeleton->RootBones();
692
0
            dest->mRootNode->mNumChildren = static_cast<unsigned int>(rootBones.size());
693
0
            dest->mRootNode->mChildren = new aiNode *[dest->mRootNode->mNumChildren];
694
695
0
            for (size_t i = 0, len = rootBones.size(); i < len; ++i) {
696
0
                dest->mRootNode->mChildren[i] = rootBones[i]->ConvertToAssimpNode(skeleton, dest->mRootNode);
697
0
            }
698
0
        }
699
700
        // Animations
701
0
        if (!skeleton->animations.empty()) {
702
0
            dest->mNumAnimations = static_cast<unsigned int>(skeleton->animations.size());
703
0
            dest->mAnimations = new aiAnimation *[dest->mNumAnimations];
704
705
0
            for (size_t i = 0, len = skeleton->animations.size(); i < len; ++i) {
706
0
                dest->mAnimations[i] = skeleton->animations[i]->ConvertToAssimpAnimation();
707
0
            }
708
0
        }
709
0
    }
710
0
}
711
712
// SubMeshXml
713
714
SubMeshXml::SubMeshXml() :
715
0
        indexData(new IndexDataXml()),
716
0
        vertexData(nullptr) {
717
0
}
718
719
0
SubMeshXml::~SubMeshXml() {
720
0
    Reset();
721
0
}
722
723
0
void SubMeshXml::Reset(){
724
0
    OGRE_SAFE_DELETE(indexData)
725
0
            OGRE_SAFE_DELETE(vertexData)
726
0
}
727
728
0
aiMesh *SubMeshXml::ConvertToAssimpMesh(MeshXml *parent) {
729
0
    aiMesh *dest = new aiMesh();
730
0
    dest->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
731
732
0
    if (!name.empty())
733
0
        dest->mName = name;
734
735
    // Material index
736
0
    if (materialIndex != -1)
737
0
        dest->mMaterialIndex = materialIndex;
738
739
    // Faces
740
0
    dest->mNumFaces = indexData->faceCount;
741
0
    dest->mFaces = new aiFace[dest->mNumFaces];
742
743
    // Assimp required unique vertices, we need to convert from Ogres shared indexing.
744
0
    size_t uniqueVertexCount = dest->mNumFaces * 3;
745
0
    dest->mNumVertices = static_cast<unsigned int>(uniqueVertexCount);
746
0
    dest->mVertices = new aiVector3D[dest->mNumVertices];
747
748
0
    VertexDataXml *src = (!usesSharedVertexData ? vertexData : parent->sharedVertexData);
749
0
    bool boneAssignments = src->HasBoneAssignments();
750
0
    bool normals = src->HasNormals();
751
0
    size_t uvs = src->NumUvs();
752
753
    // Prepare normals
754
0
    if (normals)
755
0
        dest->mNormals = new aiVector3D[dest->mNumVertices];
756
757
    // Prepare UVs
758
0
    for (size_t uvi = 0; uvi < uvs; ++uvi) {
759
0
        dest->mNumUVComponents[uvi] = 2;
760
0
        dest->mTextureCoords[uvi] = new aiVector3D[dest->mNumVertices];
761
0
    }
762
763
0
    for (size_t fi = 0; fi < dest->mNumFaces; ++fi) {
764
        // Source Ogre face
765
0
        aiFace &ogreFace = indexData->faces[fi];
766
767
        // Destination Assimp face
768
0
        aiFace &face = dest->mFaces[fi];
769
0
        face.mNumIndices = 3;
770
0
        face.mIndices = new unsigned int[3];
771
772
0
        const size_t pos = fi * 3;
773
0
        for (size_t v = 0; v < 3; ++v) {
774
0
            const size_t newIndex = pos + v;
775
776
            // Write face index
777
0
            face.mIndices[v] = static_cast<unsigned int>(newIndex);
778
779
            // Ogres vertex index to ref into the source buffers.
780
0
            const size_t ogreVertexIndex = ogreFace.mIndices[v];
781
0
            src->AddVertexMapping(static_cast<uint32_t>(ogreVertexIndex), static_cast<uint32_t>(newIndex));
782
783
            // Position
784
0
            dest->mVertices[newIndex] = src->positions[ogreVertexIndex];
785
786
            // Normal
787
0
            if (normals)
788
0
                dest->mNormals[newIndex] = src->normals[ogreVertexIndex];
789
790
            // UVs
791
0
            for (size_t uvi = 0; uvi < uvs; ++uvi) {
792
0
                aiVector3D *uvDest = dest->mTextureCoords[uvi];
793
0
                std::vector<aiVector3D> &uvSrc = src->uvs[uvi];
794
0
                uvDest[newIndex] = uvSrc[ogreVertexIndex];
795
0
            }
796
0
        }
797
0
    }
798
799
    // Bones and bone weights
800
0
    if (parent->skeleton && boneAssignments) {
801
0
        AssimpVertexBoneWeightList weights = src->AssimpBoneWeights(dest->mNumVertices);
802
0
        std::set<uint16_t> referencedBones = src->ReferencedBonesByWeights();
803
804
0
        dest->mNumBones = static_cast<unsigned int>(referencedBones.size());
805
0
        dest->mBones = new aiBone *[dest->mNumBones];
806
807
0
        size_t assimpBoneIndex = 0;
808
0
        for (std::set<uint16_t>::const_iterator rbIter = referencedBones.begin(), rbEnd = referencedBones.end(); rbIter != rbEnd; ++rbIter, ++assimpBoneIndex) {
809
0
            Bone *bone = parent->skeleton->BoneById((*rbIter));
810
0
            dest->mBones[assimpBoneIndex] = bone->ConvertToAssimpBone(parent->skeleton, weights[bone->id]);
811
0
        }
812
0
    }
813
814
0
    return dest;
815
0
}
816
817
// Animation
818
819
Animation::Animation(Skeleton *parent) :
820
0
        parentMesh(nullptr),
821
0
        parentSkeleton(parent),
822
0
        length(0.0f),
823
0
        baseTime(-1.0f) {
824
    // empty
825
0
}
826
827
Animation::Animation(Mesh *parent) :
828
0
        parentMesh(parent),
829
0
        parentSkeleton(nullptr),
830
0
        length(0.0f),
831
0
        baseTime(-1.0f) {
832
    // empty
833
0
}
834
835
0
VertexData *Animation::AssociatedVertexData(VertexAnimationTrack *track) const {
836
0
    if (nullptr == parentMesh) {
837
0
        return nullptr;
838
0
    }
839
840
0
    bool sharedGeom = (track->target == 0);
841
0
    if (sharedGeom) {
842
0
        return parentMesh->sharedVertexData;
843
0
    }
844
845
0
    return parentMesh->GetSubMesh(track->target - 1)->vertexData;
846
0
}
847
848
0
aiAnimation *Animation::ConvertToAssimpAnimation() {
849
0
    aiAnimation *anim = new aiAnimation();
850
0
    anim->mName = name;
851
0
    anim->mDuration = static_cast<double>(length);
852
0
    anim->mTicksPerSecond = 1.0;
853
854
    // Tracks
855
0
    if (!tracks.empty()) {
856
0
        anim->mNumChannels = static_cast<unsigned int>(tracks.size());
857
0
        anim->mChannels = new aiNodeAnim *[anim->mNumChannels];
858
859
0
        for (size_t i = 0, len = tracks.size(); i < len; ++i) {
860
0
            anim->mChannels[i] = tracks[i].ConvertToAssimpAnimationNode(parentSkeleton);
861
0
        }
862
0
    }
863
0
    return anim;
864
0
}
865
866
// Skeleton
867
868
Skeleton::Skeleton() :
869
0
        bones(),
870
0
        animations(),
871
0
        blendMode(ANIMBLEND_AVERAGE) {
872
0
}
873
874
0
Skeleton::~Skeleton() {
875
0
    Reset();
876
0
}
877
878
0
void Skeleton::Reset() {
879
0
    for (auto &bone : bones) {
880
0
        OGRE_SAFE_DELETE(bone)
881
0
    }
882
0
    bones.clear();
883
0
    for (auto &anim : animations) {
884
0
        OGRE_SAFE_DELETE(anim)
885
0
    }
886
0
    animations.clear();
887
0
}
888
889
0
BoneList Skeleton::RootBones() const {
890
0
    BoneList rootBones;
891
0
    for (BoneList::const_iterator iter = bones.begin(); iter != bones.end(); ++iter) {
892
0
        if (!(*iter)->IsParented())
893
0
            rootBones.push_back((*iter));
894
0
    }
895
0
    return rootBones;
896
0
}
897
898
0
size_t Skeleton::NumRootBones() const {
899
0
    size_t num = 0;
900
0
    for (BoneList::const_iterator iter = bones.begin(); iter != bones.end(); ++iter) {
901
0
        if (!(*iter)->IsParented())
902
0
            num++;
903
0
    }
904
0
    return num;
905
0
}
906
907
0
Bone *Skeleton::BoneByName(const std::string &name) const {
908
0
    for (BoneList::const_iterator iter = bones.begin(); iter != bones.end(); ++iter) {
909
0
        if ((*iter)->name == name)
910
0
            return (*iter);
911
0
    }
912
0
    return nullptr;
913
0
}
914
915
0
Bone *Skeleton::BoneById(uint16_t id) const {
916
0
    for (BoneList::const_iterator iter = bones.begin(); iter != bones.end(); ++iter) {
917
0
        if ((*iter)->id == id)
918
0
            return (*iter);
919
0
    }
920
0
    return nullptr;
921
0
}
922
923
// Bone
924
925
Bone::Bone() :
926
0
        id(0),
927
0
        parent(nullptr),
928
0
        parentId(-1),
929
0
        scale(1.0f, 1.0f, 1.0f) {
930
0
}
931
932
0
bool Bone::IsParented() const {
933
0
    return (parentId != -1 && parent != nullptr);
934
0
}
935
936
0
uint16_t Bone::ParentId() const {
937
0
    return static_cast<uint16_t>(parentId);
938
0
}
939
940
0
void Bone::AddChild(Bone *bone) {
941
0
    if (!bone)
942
0
        return;
943
0
    if (bone->IsParented())
944
0
        throw DeadlyImportError("Attaching child Bone that is already parented: ", bone->name);
945
946
0
    bone->parent = this;
947
0
    bone->parentId = id;
948
0
    children.push_back(bone->id);
949
0
}
950
951
0
void Bone::CalculateWorldMatrixAndDefaultPose(Skeleton *skeleton) {
952
0
    if (!IsParented())
953
0
        worldMatrix = aiMatrix4x4(scale, rotation, position).Inverse();
954
0
    else
955
0
        worldMatrix = aiMatrix4x4(scale, rotation, position).Inverse() * parent->worldMatrix;
956
957
0
    defaultPose = aiMatrix4x4(scale, rotation, position);
958
959
    // Recursively for all children now that the parent matrix has been calculated.
960
0
    for (auto boneId : children) {
961
0
        Bone *child = skeleton->BoneById(boneId);
962
0
        if (!child) {
963
0
            throw DeadlyImportError("CalculateWorldMatrixAndDefaultPose: Failed to find child bone ", boneId, " for parent ", id, " ", name);
964
0
        }
965
0
        child->CalculateWorldMatrixAndDefaultPose(skeleton);
966
0
    }
967
0
}
968
969
0
aiNode *Bone::ConvertToAssimpNode(Skeleton *skeleton, aiNode *parentNode) {
970
    // Bone node
971
0
    aiNode *node = new aiNode(name);
972
0
    node->mParent = parentNode;
973
0
    node->mTransformation = defaultPose;
974
975
    // Children
976
0
    if (!children.empty()) {
977
0
        node->mNumChildren = static_cast<unsigned int>(children.size());
978
0
        node->mChildren = new aiNode *[node->mNumChildren];
979
980
0
        for (size_t i = 0, len = children.size(); i < len; ++i) {
981
0
            Bone *child = skeleton->BoneById(children[i]);
982
0
            if (!child) {
983
0
                throw DeadlyImportError("ConvertToAssimpNode: Failed to find child bone ", children[i], " for parent ", id, " ", name);
984
0
            }
985
0
            node->mChildren[i] = child->ConvertToAssimpNode(skeleton, node);
986
0
        }
987
0
    }
988
0
    return node;
989
0
}
990
991
0
aiBone *Bone::ConvertToAssimpBone(Skeleton * /*parent*/, const std::vector<aiVertexWeight> &boneWeights) {
992
0
    aiBone *bone = new aiBone();
993
0
    bone->mName = name;
994
0
    bone->mOffsetMatrix = worldMatrix;
995
996
0
    if (!boneWeights.empty()) {
997
0
        bone->mNumWeights = static_cast<unsigned int>(boneWeights.size());
998
0
        bone->mWeights = new aiVertexWeight[boneWeights.size()];
999
0
        memcpy(bone->mWeights, &boneWeights[0], boneWeights.size() * sizeof(aiVertexWeight));
1000
0
    }
1001
1002
0
    return bone;
1003
0
}
1004
1005
// VertexAnimationTrack
1006
1007
VertexAnimationTrack::VertexAnimationTrack() :
1008
0
        type(VAT_NONE),
1009
0
        target(0) {
1010
0
}
1011
1012
0
aiNodeAnim *VertexAnimationTrack::ConvertToAssimpAnimationNode(Skeleton *skeleton) {
1013
0
    if (boneName.empty() || type != VAT_TRANSFORM) {
1014
0
        throw DeadlyImportError("VertexAnimationTrack::ConvertToAssimpAnimationNode: Cannot convert track that has no target bone name or is not type of VAT_TRANSFORM");
1015
0
    }
1016
1017
0
    aiNodeAnim *nodeAnim = new aiNodeAnim();
1018
0
    nodeAnim->mNodeName = boneName;
1019
1020
0
    Bone *bone = skeleton->BoneByName(boneName);
1021
0
    if (!bone) {
1022
0
        throw DeadlyImportError("VertexAnimationTrack::ConvertToAssimpAnimationNode: Failed to find bone ", boneName, " from parent Skeleton");
1023
0
    }
1024
1025
    // Keyframes
1026
0
    size_t numKeyframes = transformKeyFrames.size();
1027
1028
0
    nodeAnim->mPositionKeys = new aiVectorKey[numKeyframes];
1029
0
    nodeAnim->mRotationKeys = new aiQuatKey[numKeyframes];
1030
0
    nodeAnim->mScalingKeys = new aiVectorKey[numKeyframes];
1031
0
    nodeAnim->mNumPositionKeys = static_cast<unsigned int>(numKeyframes);
1032
0
    nodeAnim->mNumRotationKeys = static_cast<unsigned int>(numKeyframes);
1033
0
    nodeAnim->mNumScalingKeys = static_cast<unsigned int>(numKeyframes);
1034
1035
0
    for (size_t kfi = 0; kfi < numKeyframes; ++kfi) {
1036
0
        TransformKeyFrame &kfSource = transformKeyFrames[kfi];
1037
1038
        // Calculate the complete transformation from world space to bone space
1039
0
        aiVector3D pos;
1040
0
        aiQuaternion rot;
1041
0
        aiVector3D scale;
1042
1043
0
        aiMatrix4x4 finalTransform = bone->defaultPose * kfSource.Transform();
1044
0
        finalTransform.Decompose(scale, rot, pos);
1045
1046
0
        double t = static_cast<double>(kfSource.timePos);
1047
0
        nodeAnim->mPositionKeys[kfi].mTime = t;
1048
0
        nodeAnim->mRotationKeys[kfi].mTime = t;
1049
0
        nodeAnim->mScalingKeys[kfi].mTime = t;
1050
1051
0
        nodeAnim->mPositionKeys[kfi].mValue = pos;
1052
0
        nodeAnim->mRotationKeys[kfi].mValue = rot;
1053
0
        nodeAnim->mScalingKeys[kfi].mValue = scale;
1054
0
    }
1055
1056
0
    return nodeAnim;
1057
0
}
1058
1059
// TransformKeyFrame
1060
1061
TransformKeyFrame::TransformKeyFrame() :
1062
0
        timePos(0.0f),
1063
0
        scale(1.0f, 1.0f, 1.0f) {
1064
0
}
1065
1066
0
aiMatrix4x4 TransformKeyFrame::Transform() {
1067
0
    return aiMatrix4x4(scale, rotation, position);
1068
0
}
1069
1070
} // namespace Ogre
1071
} // namespace Assimp
1072
1073
#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER