1 /*
2 Open Asset Import Library (assimp)
3 ----------------------------------------------------------------------
4 
5 Copyright (c) 2006-2016, assimp team
6 All rights reserved.
7 
8 Redistribution and use of this software in source and binary forms,
9 with or without modification, are permitted provided that the
10 following conditions are met:
11 
12 * Redistributions of source code must retain the above
13   copyright notice, this list of conditions and the
14   following disclaimer.
15 
16 * Redistributions in binary form must reproduce the above
17   copyright notice, this list of conditions and the
18   following disclaimer in the documentation and/or other
19   materials provided with the distribution.
20 
21 * Neither the name of the assimp team, nor the names of its
22   contributors may be used to endorse or promote products
23   derived from this software without specific prior
24   written permission of the assimp team.
25 
26 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 
38 ----------------------------------------------------------------------
39 */
40 
41 /** @file  BlenderModifier.cpp
42  *  @brief Implementation of some blender modifiers (i.e subdivision, mirror).
43  */
44 
45 
46 #ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
47 #include "BlenderModifier.h"
48 #include "SceneCombiner.h"
49 #include "Subdivision.h"
50 #include <assimp/scene.h>
51 #include <memory>
52 
53 #include <functional>
54 
55 using namespace Assimp;
56 using namespace Assimp::Blender;
57 
god()58 template <typename T> BlenderModifier* god() {
59     return new T();
60 }
61 
62 // add all available modifiers here
63 typedef BlenderModifier* (*fpCreateModifier)();
64 static const fpCreateModifier creators[] = {
65         &god<BlenderModifier_Mirror>,
66         &god<BlenderModifier_Subdivision>,
67 
68         NULL // sentinel
69 };
70 
71 // ------------------------------------------------------------------------------------------------
72 // just testing out some new macros to simplify logging
73 #define ASSIMP_LOG_WARN_F(string,...)\
74     DefaultLogger::get()->warn((Formatter::format(string),__VA_ARGS__))
75 
76 #define ASSIMP_LOG_ERROR_F(string,...)\
77     DefaultLogger::get()->error((Formatter::format(string),__VA_ARGS__))
78 
79 #define ASSIMP_LOG_DEBUG_F(string,...)\
80     DefaultLogger::get()->debug((Formatter::format(string),__VA_ARGS__))
81 
82 #define ASSIMP_LOG_INFO_F(string,...)\
83     DefaultLogger::get()->info((Formatter::format(string),__VA_ARGS__))
84 
85 
86 #define ASSIMP_LOG_WARN(string)\
87     DefaultLogger::get()->warn(string)
88 
89 #define ASSIMP_LOG_ERROR(string)\
90     DefaultLogger::get()->error(string)
91 
92 #define ASSIMP_LOG_DEBUG(string)\
93     DefaultLogger::get()->debug(string)
94 
95 #define ASSIMP_LOG_INFO(string)\
96     DefaultLogger::get()->info(string)
97 
98 
99 // ------------------------------------------------------------------------------------------------
100 struct SharedModifierData : ElemBase
101 {
102     ModifierData modifier;
103 };
104 
105 // ------------------------------------------------------------------------------------------------
ApplyModifiers(aiNode & out,ConversionData & conv_data,const Scene & in,const Object & orig_object)106 void BlenderModifierShowcase::ApplyModifiers(aiNode& out, ConversionData& conv_data, const Scene& in, const Object& orig_object )
107 {
108     size_t cnt = 0u, ful = 0u;
109 
110     // NOTE: this cast is potentially unsafe by design, so we need to perform type checks before
111     // we're allowed to dereference the pointers without risking to crash. We might still be
112     // invoking UB btw - we're assuming that the ModifierData member of the respective modifier
113     // structures is at offset sizeof(vftable) with no padding.
114     const SharedModifierData* cur = static_cast<const SharedModifierData *> ( orig_object.modifiers.first.get() );
115     for (; cur; cur =  static_cast<const SharedModifierData *> ( cur->modifier.next.get() ), ++ful) {
116         ai_assert(cur->dna_type);
117 
118         const Structure* s = conv_data.db.dna.Get( cur->dna_type );
119         if (!s) {
120             ASSIMP_LOG_WARN_F("BlendModifier: could not resolve DNA name: ",cur->dna_type);
121             continue;
122         }
123 
124         // this is a common trait of all XXXMirrorData structures in BlenderDNA
125         const Field* f = s->Get("modifier");
126         if (!f || f->offset != 0) {
127             ASSIMP_LOG_WARN("BlendModifier: expected a `modifier` member at offset 0");
128             continue;
129         }
130 
131         s = conv_data.db.dna.Get( f->type );
132         if (!s || s->name != "ModifierData") {
133             ASSIMP_LOG_WARN("BlendModifier: expected a ModifierData structure as first member");
134             continue;
135         }
136 
137         // now, we can be sure that we should be fine to dereference *cur* as
138         // ModifierData (with the above note).
139         const ModifierData& dat = cur->modifier;
140 
141         const fpCreateModifier* curgod = creators;
142         std::vector< BlenderModifier* >::iterator curmod = cached_modifiers->begin(), endmod = cached_modifiers->end();
143 
144         for (;*curgod;++curgod,++curmod) { // allocate modifiers on the fly
145             if (curmod == endmod) {
146                 cached_modifiers->push_back((*curgod)());
147 
148                 endmod = cached_modifiers->end();
149                 curmod = endmod-1;
150             }
151 
152             BlenderModifier* const modifier = *curmod;
153             if(modifier->IsActive(dat)) {
154                 modifier->DoIt(out,conv_data,*static_cast<const ElemBase *>(cur),in,orig_object);
155                 cnt++;
156 
157                 curgod = NULL;
158                 break;
159             }
160         }
161         if (curgod) {
162             ASSIMP_LOG_WARN_F("Couldn't find a handler for modifier: ",dat.name);
163         }
164     }
165 
166     // Even though we managed to resolve some or all of the modifiers on this
167     // object, we still can't say whether our modifier implementations were
168     // able to fully do their job.
169     if (ful) {
170         ASSIMP_LOG_DEBUG_F("BlendModifier: found handlers for ",cnt," of ",ful," modifiers on `",orig_object.id.name,
171             "`, check log messages above for errors");
172     }
173 }
174 
175 
176 
177 // ------------------------------------------------------------------------------------------------
IsActive(const ModifierData & modin)178 bool BlenderModifier_Mirror :: IsActive (const ModifierData& modin)
179 {
180     return modin.type == ModifierData::eModifierType_Mirror;
181 }
182 
183 // ------------------------------------------------------------------------------------------------
DoIt(aiNode & out,ConversionData & conv_data,const ElemBase & orig_modifier,const Scene &,const Object & orig_object)184 void  BlenderModifier_Mirror :: DoIt(aiNode& out, ConversionData& conv_data,  const ElemBase& orig_modifier,
185     const Scene& /*in*/,
186     const Object& orig_object )
187 {
188     // hijacking the ABI, see the big note in BlenderModifierShowcase::ApplyModifiers()
189     const MirrorModifierData& mir = static_cast<const MirrorModifierData&>(orig_modifier);
190     ai_assert(mir.modifier.type == ModifierData::eModifierType_Mirror);
191 
192     conv_data.meshes->reserve(conv_data.meshes->size() + out.mNumMeshes);
193 
194     // XXX not entirely correct, mirroring on two axes results in 4 distinct objects in blender ...
195 
196     // take all input meshes and clone them
197     for (unsigned int i = 0; i < out.mNumMeshes; ++i) {
198         aiMesh* mesh;
199         SceneCombiner::Copy(&mesh,conv_data.meshes[out.mMeshes[i]]);
200 
201         const float xs = mir.flag & MirrorModifierData::Flags_AXIS_X ? -1.f : 1.f;
202         const float ys = mir.flag & MirrorModifierData::Flags_AXIS_Y ? -1.f : 1.f;
203         const float zs = mir.flag & MirrorModifierData::Flags_AXIS_Z ? -1.f : 1.f;
204 
205         if (mir.mirror_ob) {
206             const aiVector3D center( mir.mirror_ob->obmat[3][0],mir.mirror_ob->obmat[3][1],mir.mirror_ob->obmat[3][2] );
207             for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
208                 aiVector3D& v = mesh->mVertices[i];
209 
210                 v.x = center.x + xs*(center.x - v.x);
211                 v.y = center.y + ys*(center.y - v.y);
212                 v.z = center.z + zs*(center.z - v.z);
213             }
214         }
215         else {
216             for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
217                 aiVector3D& v = mesh->mVertices[i];
218                 v.x *= xs;v.y *= ys;v.z *= zs;
219             }
220         }
221 
222         if (mesh->mNormals) {
223             for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
224                 aiVector3D& v = mesh->mNormals[i];
225                 v.x *= xs;v.y *= ys;v.z *= zs;
226             }
227         }
228 
229         if (mesh->mTangents) {
230             for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
231                 aiVector3D& v = mesh->mTangents[i];
232                 v.x *= xs;v.y *= ys;v.z *= zs;
233             }
234         }
235 
236         if (mesh->mBitangents) {
237             for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
238                 aiVector3D& v = mesh->mBitangents[i];
239                 v.x *= xs;v.y *= ys;v.z *= zs;
240             }
241         }
242 
243         const float us = mir.flag & MirrorModifierData::Flags_MIRROR_U ? -1.f : 1.f;
244         const float vs = mir.flag & MirrorModifierData::Flags_MIRROR_V ? -1.f : 1.f;
245 
246         for (unsigned int n = 0; mesh->HasTextureCoords(n); ++n) {
247             for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
248                 aiVector3D& v = mesh->mTextureCoords[n][i];
249                 v.x *= us;v.y *= vs;
250             }
251         }
252 
253         // Only reverse the winding order if an odd number of axes were mirrored.
254         if (xs * ys * zs < 0) {
255             for( unsigned int i = 0; i < mesh->mNumFaces; i++) {
256                 aiFace& face = mesh->mFaces[i];
257                 for( unsigned int fi = 0; fi < face.mNumIndices / 2; ++fi)
258                     std::swap( face.mIndices[fi], face.mIndices[face.mNumIndices - 1 - fi]);
259             }
260         }
261 
262         conv_data.meshes->push_back(mesh);
263     }
264     unsigned int* nind = new unsigned int[out.mNumMeshes*2];
265 
266     std::copy(out.mMeshes,out.mMeshes+out.mNumMeshes,nind);
267     std::transform(out.mMeshes,out.mMeshes+out.mNumMeshes,nind+out.mNumMeshes,
268         std::bind1st(std::plus< unsigned int >(),out.mNumMeshes));
269 
270     delete[] out.mMeshes;
271     out.mMeshes = nind;
272     out.mNumMeshes *= 2;
273 
274     ASSIMP_LOG_INFO_F("BlendModifier: Applied the `Mirror` modifier to `",
275         orig_object.id.name,"`");
276 }
277 
278 
279 
280 
281 // ------------------------------------------------------------------------------------------------
IsActive(const ModifierData & modin)282 bool BlenderModifier_Subdivision :: IsActive (const ModifierData& modin)
283 {
284     return modin.type == ModifierData::eModifierType_Subsurf;
285 }
286 
287 // ------------------------------------------------------------------------------------------------
DoIt(aiNode & out,ConversionData & conv_data,const ElemBase & orig_modifier,const Scene &,const Object & orig_object)288 void  BlenderModifier_Subdivision :: DoIt(aiNode& out, ConversionData& conv_data,  const ElemBase& orig_modifier,
289     const Scene& /*in*/,
290     const Object& orig_object )
291 {
292     // hijacking the ABI, see the big note in BlenderModifierShowcase::ApplyModifiers()
293     const SubsurfModifierData& mir = static_cast<const SubsurfModifierData&>(orig_modifier);
294     ai_assert(mir.modifier.type == ModifierData::eModifierType_Subsurf);
295 
296     Subdivider::Algorithm algo;
297     switch (mir.subdivType)
298     {
299     case SubsurfModifierData::TYPE_CatmullClarke:
300         algo = Subdivider::CATMULL_CLARKE;
301         break;
302 
303     case SubsurfModifierData::TYPE_Simple:
304         ASSIMP_LOG_WARN("BlendModifier: The `SIMPLE` subdivision algorithm is not currently implemented, using Catmull-Clarke");
305         algo = Subdivider::CATMULL_CLARKE;
306         break;
307 
308     default:
309         ASSIMP_LOG_WARN_F("BlendModifier: Unrecognized subdivision algorithm: ",mir.subdivType);
310         return;
311     };
312 
313     std::unique_ptr<Subdivider> subd(Subdivider::Create(algo));
314     ai_assert(subd);
315 
316     aiMesh** const meshes = &conv_data.meshes[conv_data.meshes->size() - out.mNumMeshes];
317     std::unique_ptr<aiMesh*[]> tempmeshes(new aiMesh*[out.mNumMeshes]());
318 
319     subd->Subdivide(meshes,out.mNumMeshes,tempmeshes.get(),std::max( mir.renderLevels, mir.levels ),true);
320     std::copy(tempmeshes.get(),tempmeshes.get()+out.mNumMeshes,meshes);
321 
322     ASSIMP_LOG_INFO_F("BlendModifier: Applied the `Subdivision` modifier to `",
323         orig_object.id.name,"`");
324 }
325 
326 #endif
327