vrshoot

view libs/assimp/BlenderModifier.cpp @ 0:b2f14e535253

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 01 Feb 2014 19:58:19 +0200
parents
children
line source
1 /*
2 Open Asset Import Library (assimp)
3 ----------------------------------------------------------------------
5 Copyright (c) 2006-2012, assimp team
6 All rights reserved.
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:
12 * Redistributions of source code must retain the above
13 copyright notice, this list of conditions and the
14 following disclaimer.
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.
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.
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.
38 ----------------------------------------------------------------------
39 */
41 /** @file BlenderModifier.cpp
42 * @brief Implementation of some blender modifiers (i.e subdivision, mirror).
43 */
44 #include "AssimpPCH.h"
46 #ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
47 #include "BlenderModifier.h"
48 #include "SceneCombiner.h"
49 #include "Subdivision.h"
51 #include <functional>
53 using namespace Assimp;
54 using namespace Assimp::Blender;
56 template <typename T> BlenderModifier* god() {
57 return new T();
58 }
60 // add all available modifiers here
61 typedef BlenderModifier* (*fpCreateModifier)();
62 static const fpCreateModifier creators[] = {
63 &god<BlenderModifier_Mirror>,
64 &god<BlenderModifier_Subdivision>,
66 NULL // sentinel
67 };
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__))
74 #define ASSIMP_LOG_ERROR_F(string,...)\
75 DefaultLogger::get()->error((Formatter::format(string),__VA_ARGS__))
77 #define ASSIMP_LOG_DEBUG_F(string,...)\
78 DefaultLogger::get()->debug((Formatter::format(string),__VA_ARGS__))
80 #define ASSIMP_LOG_INFO_F(string,...)\
81 DefaultLogger::get()->info((Formatter::format(string),__VA_ARGS__))
84 #define ASSIMP_LOG_WARN(string)\
85 DefaultLogger::get()->warn(string)
87 #define ASSIMP_LOG_ERROR(string)\
88 DefaultLogger::get()->error(string)
90 #define ASSIMP_LOG_DEBUG(string)\
91 DefaultLogger::get()->debug(string)
93 #define ASSIMP_LOG_INFO(string)\
94 DefaultLogger::get()->info(string)
97 // ------------------------------------------------------------------------------------------------
98 struct SharedModifierData : ElemBase
99 {
100 ModifierData modifier;
101 };
103 // ------------------------------------------------------------------------------------------------
104 void BlenderModifierShowcase::ApplyModifiers(aiNode& out, ConversionData& conv_data, const Scene& in, const Object& orig_object )
105 {
106 size_t cnt = 0u, ful = 0u;
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);
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 }
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 }
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 }
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;
139 const fpCreateModifier* curgod = creators;
140 std::vector< BlenderModifier* >::iterator curmod = cached_modifiers->begin(), endmod = cached_modifiers->end();
142 for (;*curgod;++curgod,++curmod) { // allocate modifiers on the fly
143 if (curmod == endmod) {
144 cached_modifiers->push_back((*curgod)());
146 endmod = cached_modifiers->end();
147 curmod = endmod-1;
148 }
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++;
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 }
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 }
175 // ------------------------------------------------------------------------------------------------
176 bool BlenderModifier_Mirror :: IsActive (const ModifierData& modin)
177 {
178 return modin.type == ModifierData::eModifierType_Mirror;
179 }
181 // ------------------------------------------------------------------------------------------------
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);
190 conv_data.meshes->reserve(conv_data.meshes->size() + out.mNumMeshes);
192 // XXX not entirely correct, mirroring on two axes results in 4 distinct objects in blender ...
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]]);
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;
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];
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 }
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 }
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 }
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 }
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;
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 }
251 conv_data.meshes->push_back(mesh);
252 }
253 unsigned int* nind = new unsigned int[out.mNumMeshes*2];
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));
259 delete[] out.mMeshes;
260 out.mMeshes = nind;
261 out.mNumMeshes *= 2;
263 ASSIMP_LOG_INFO_F("BlendModifier: Applied the `Mirror` modifier to `",
264 orig_object.id.name,"`");
265 }
270 // ------------------------------------------------------------------------------------------------
271 bool BlenderModifier_Subdivision :: IsActive (const ModifierData& modin)
272 {
273 return modin.type == ModifierData::eModifierType_Subsurf;
274 }
276 // ------------------------------------------------------------------------------------------------
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);
285 Subdivider::Algorithm algo;
286 switch (mir.subdivType)
287 {
288 case SubsurfModifierData::TYPE_CatmullClarke:
289 algo = Subdivider::CATMULL_CLARKE;
290 break;
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;
297 default:
298 ASSIMP_LOG_WARN_F("BlendModifier: Unrecognized subdivision algorithm: ",mir.subdivType);
299 return;
300 };
302 boost::scoped_ptr<Subdivider> subd(Subdivider::Create(algo));
303 ai_assert(subd);
305 aiMesh** const meshes = &conv_data.meshes[conv_data.meshes->size() - out.mNumMeshes];
306 boost::scoped_array<aiMesh*> tempmeshes(new aiMesh*[out.mNumMeshes]());
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);
311 ASSIMP_LOG_INFO_F("BlendModifier: Applied the `Subdivision` modifier to `",
312 orig_object.id.name,"`");
313 }
315 #endif