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