1 /*
2 Open Asset Import Library (assimp)
3 ----------------------------------------------------------------------
4 
5 Copyright (c) 2006-2015, 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 "../include/assimp/scene.h"
51 #include <boost/scoped_ptr.hpp>
52 #include <boost/scoped_array.hpp>
53 #include <boost/pointer_cast.hpp>
54 
55 #include <functional>
56 
57 using namespace Assimp;
58 using namespace Assimp::Blender;
59 
god()60 template <typename T> BlenderModifier* god() {
61     return new T();
62 }
63 
64 // add all available modifiers here
65 typedef BlenderModifier* (*fpCreateModifier)();
66 static const fpCreateModifier creators[] = {
67         &god<BlenderModifier_Mirror>,
68         &god<BlenderModifier_Subdivision>,
69 
70         NULL // sentinel
71 };
72 
73 // ------------------------------------------------------------------------------------------------
74 // just testing out some new macros to simplify logging
75 #define ASSIMP_LOG_WARN_F(string,...)\
76     DefaultLogger::get()->warn((Formatter::format(string),__VA_ARGS__))
77 
78 #define ASSIMP_LOG_ERROR_F(string,...)\
79     DefaultLogger::get()->error((Formatter::format(string),__VA_ARGS__))
80 
81 #define ASSIMP_LOG_DEBUG_F(string,...)\
82     DefaultLogger::get()->debug((Formatter::format(string),__VA_ARGS__))
83 
84 #define ASSIMP_LOG_INFO_F(string,...)\
85     DefaultLogger::get()->info((Formatter::format(string),__VA_ARGS__))
86 
87 
88 #define ASSIMP_LOG_WARN(string)\
89     DefaultLogger::get()->warn(string)
90 
91 #define ASSIMP_LOG_ERROR(string)\
92     DefaultLogger::get()->error(string)
93 
94 #define ASSIMP_LOG_DEBUG(string)\
95     DefaultLogger::get()->debug(string)
96 
97 #define ASSIMP_LOG_INFO(string)\
98     DefaultLogger::get()->info(string)
99 
100 
101 // ------------------------------------------------------------------------------------------------
102 struct SharedModifierData : ElemBase
103 {
104     ModifierData modifier;
105 };
106 
107 // ------------------------------------------------------------------------------------------------
ApplyModifiers(aiNode & out,ConversionData & conv_data,const Scene & in,const Object & orig_object)108 void BlenderModifierShowcase::ApplyModifiers(aiNode& out, ConversionData& conv_data, const Scene& in, const Object& orig_object )
109 {
110     size_t cnt = 0u, ful = 0u;
111 
112     // NOTE: this cast is potentially unsafe by design, so we need to perform type checks before
113     // we're allowed to dereference the pointers without risking to crash. We might still be
114     // invoking UB btw - we're assuming that the ModifierData member of the respective modifier
115     // structures is at offset sizeof(vftable) with no padding.
116     const SharedModifierData* cur = boost::static_pointer_cast<const SharedModifierData> ( orig_object.modifiers.first.get() );
117     for (; cur; cur =  boost::static_pointer_cast<const SharedModifierData> ( cur->modifier.next.get() ), ++ful) {
118         ai_assert(cur->dna_type);
119 
120         const Structure* s = conv_data.db.dna.Get( cur->dna_type );
121         if (!s) {
122             ASSIMP_LOG_WARN_F("BlendModifier: could not resolve DNA name: ",cur->dna_type);
123             continue;
124         }
125 
126         // this is a common trait of all XXXMirrorData structures in BlenderDNA
127         const Field* f = s->Get("modifier");
128         if (!f || f->offset != 0) {
129             ASSIMP_LOG_WARN("BlendModifier: expected a `modifier` member at offset 0");
130             continue;
131         }
132 
133         s = conv_data.db.dna.Get( f->type );
134         if (!s || s->name != "ModifierData") {
135             ASSIMP_LOG_WARN("BlendModifier: expected a ModifierData structure as first member");
136             continue;
137         }
138 
139         // now, we can be sure that we should be fine to dereference *cur* as
140         // ModifierData (with the above note).
141         const ModifierData& dat = cur->modifier;
142 
143         const fpCreateModifier* curgod = creators;
144         std::vector< BlenderModifier* >::iterator curmod = cached_modifiers->begin(), endmod = cached_modifiers->end();
145 
146         for (;*curgod;++curgod,++curmod) { // allocate modifiers on the fly
147             if (curmod == endmod) {
148                 cached_modifiers->push_back((*curgod)());
149 
150                 endmod = cached_modifiers->end();
151                 curmod = endmod-1;
152             }
153 
154             BlenderModifier* const modifier = *curmod;
155             if(modifier->IsActive(dat)) {
156                 modifier->DoIt(out,conv_data,*boost::static_pointer_cast<const ElemBase>(cur),in,orig_object);
157                 cnt++;
158 
159                 curgod = NULL;
160                 break;
161             }
162         }
163         if (curgod) {
164             ASSIMP_LOG_WARN_F("Couldn't find a handler for modifier: ",dat.name);
165         }
166     }
167 
168     // Even though we managed to resolve some or all of the modifiers on this
169     // object, we still can't say whether our modifier implementations were
170     // able to fully do their job.
171     if (ful) {
172         ASSIMP_LOG_DEBUG_F("BlendModifier: found handlers for ",cnt," of ",ful," modifiers on `",orig_object.id.name,
173             "`, check log messages above for errors");
174     }
175 }
176 
177 
178 
179 // ------------------------------------------------------------------------------------------------
IsActive(const ModifierData & modin)180 bool BlenderModifier_Mirror :: IsActive (const ModifierData& modin)
181 {
182     return modin.type == ModifierData::eModifierType_Mirror;
183 }
184 
185 // ------------------------------------------------------------------------------------------------
DoIt(aiNode & out,ConversionData & conv_data,const ElemBase & orig_modifier,const Scene &,const Object & orig_object)186 void  BlenderModifier_Mirror :: DoIt(aiNode& out, ConversionData& conv_data,  const ElemBase& orig_modifier,
187     const Scene& /*in*/,
188     const Object& orig_object )
189 {
190     // hijacking the ABI, see the big note in BlenderModifierShowcase::ApplyModifiers()
191     const MirrorModifierData& mir = static_cast<const MirrorModifierData&>(orig_modifier);
192     ai_assert(mir.modifier.type == ModifierData::eModifierType_Mirror);
193 
194     conv_data.meshes->reserve(conv_data.meshes->size() + out.mNumMeshes);
195 
196     // XXX not entirely correct, mirroring on two axes results in 4 distinct objects in blender ...
197 
198     // take all input meshes and clone them
199     for (unsigned int i = 0; i < out.mNumMeshes; ++i) {
200         aiMesh* mesh;
201         SceneCombiner::Copy(&mesh,conv_data.meshes[out.mMeshes[i]]);
202 
203         const float xs = mir.flag & MirrorModifierData::Flags_AXIS_X ? -1.f : 1.f;
204         const float ys = mir.flag & MirrorModifierData::Flags_AXIS_Y ? -1.f : 1.f;
205         const float zs = mir.flag & MirrorModifierData::Flags_AXIS_Z ? -1.f : 1.f;
206 
207         if (mir.mirror_ob) {
208             const aiVector3D center( mir.mirror_ob->obmat[3][0],mir.mirror_ob->obmat[3][1],mir.mirror_ob->obmat[3][2] );
209             for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
210                 aiVector3D& v = mesh->mVertices[i];
211 
212                 v.x = center.x + xs*(center.x - v.x);
213                 v.y = center.y + ys*(center.y - v.y);
214                 v.z = center.z + zs*(center.z - v.z);
215             }
216         }
217         else {
218             for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
219                 aiVector3D& v = mesh->mVertices[i];
220                 v.x *= xs;v.y *= ys;v.z *= zs;
221             }
222         }
223 
224         if (mesh->mNormals) {
225             for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
226                 aiVector3D& v = mesh->mNormals[i];
227                 v.x *= xs;v.y *= ys;v.z *= zs;
228             }
229         }
230 
231         if (mesh->mTangents) {
232             for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
233                 aiVector3D& v = mesh->mTangents[i];
234                 v.x *= xs;v.y *= ys;v.z *= zs;
235             }
236         }
237 
238         if (mesh->mBitangents) {
239             for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
240                 aiVector3D& v = mesh->mBitangents[i];
241                 v.x *= xs;v.y *= ys;v.z *= zs;
242             }
243         }
244 
245         const float us = mir.flag & MirrorModifierData::Flags_MIRROR_U ? -1.f : 1.f;
246         const float vs = mir.flag & MirrorModifierData::Flags_MIRROR_V ? -1.f : 1.f;
247 
248         for (unsigned int n = 0; mesh->HasTextureCoords(n); ++n) {
249             for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
250                 aiVector3D& v = mesh->mTextureCoords[n][i];
251                 v.x *= us;v.y *= vs;
252             }
253         }
254 
255         // Only reverse the winding order if an odd number of axes were mirrored.
256         if (xs * ys * zs < 0) {
257             for( unsigned int i = 0; i < mesh->mNumFaces; i++) {
258                 aiFace& face = mesh->mFaces[i];
259                 for( unsigned int fi = 0; fi < face.mNumIndices / 2; ++fi)
260                     std::swap( face.mIndices[fi], face.mIndices[face.mNumIndices - 1 - fi]);
261             }
262         }
263 
264         conv_data.meshes->push_back(mesh);
265     }
266     unsigned int* nind = new unsigned int[out.mNumMeshes*2];
267 
268     std::copy(out.mMeshes,out.mMeshes+out.mNumMeshes,nind);
269     std::transform(out.mMeshes,out.mMeshes+out.mNumMeshes,nind+out.mNumMeshes,
270         std::bind1st(std::plus< unsigned int >(),out.mNumMeshes));
271 
272     delete[] out.mMeshes;
273     out.mMeshes = nind;
274     out.mNumMeshes *= 2;
275 
276     ASSIMP_LOG_INFO_F("BlendModifier: Applied the `Mirror` modifier to `",
277         orig_object.id.name,"`");
278 }
279 
280 
281 
282 
283 // ------------------------------------------------------------------------------------------------
IsActive(const ModifierData & modin)284 bool BlenderModifier_Subdivision :: IsActive (const ModifierData& modin)
285 {
286     return modin.type == ModifierData::eModifierType_Subsurf;
287 }
288 
289 // ------------------------------------------------------------------------------------------------
DoIt(aiNode & out,ConversionData & conv_data,const ElemBase & orig_modifier,const Scene &,const Object & orig_object)290 void  BlenderModifier_Subdivision :: DoIt(aiNode& out, ConversionData& conv_data,  const ElemBase& orig_modifier,
291     const Scene& /*in*/,
292     const Object& orig_object )
293 {
294     // hijacking the ABI, see the big note in BlenderModifierShowcase::ApplyModifiers()
295     const SubsurfModifierData& mir = static_cast<const SubsurfModifierData&>(orig_modifier);
296     ai_assert(mir.modifier.type == ModifierData::eModifierType_Subsurf);
297 
298     Subdivider::Algorithm algo;
299     switch (mir.subdivType)
300     {
301     case SubsurfModifierData::TYPE_CatmullClarke:
302         algo = Subdivider::CATMULL_CLARKE;
303         break;
304 
305     case SubsurfModifierData::TYPE_Simple:
306         ASSIMP_LOG_WARN("BlendModifier: The `SIMPLE` subdivision algorithm is not currently implemented, using Catmull-Clarke");
307         algo = Subdivider::CATMULL_CLARKE;
308         break;
309 
310     default:
311         ASSIMP_LOG_WARN_F("BlendModifier: Unrecognized subdivision algorithm: ",mir.subdivType);
312         return;
313     };
314 
315     boost::scoped_ptr<Subdivider> subd(Subdivider::Create(algo));
316     ai_assert(subd);
317 
318     aiMesh** const meshes = &conv_data.meshes[conv_data.meshes->size() - out.mNumMeshes];
319     boost::scoped_array<aiMesh*> tempmeshes(new aiMesh*[out.mNumMeshes]());
320 
321     subd->Subdivide(meshes,out.mNumMeshes,tempmeshes.get(),std::max( mir.renderLevels, mir.levels ),true);
322     std::copy(tempmeshes.get(),tempmeshes.get()+out.mNumMeshes,meshes);
323 
324     ASSIMP_LOG_INFO_F("BlendModifier: Applied the `Subdivision` modifier to `",
325         orig_object.id.name,"`");
326 }
327 
328 #endif
329