rev |
line source |
nuclear@0
|
1 /*
|
nuclear@0
|
2 ---------------------------------------------------------------------------
|
nuclear@0
|
3 Open Asset Import Library (assimp)
|
nuclear@0
|
4 ---------------------------------------------------------------------------
|
nuclear@0
|
5
|
nuclear@0
|
6 Copyright (c) 2006-2012, assimp team
|
nuclear@0
|
7
|
nuclear@0
|
8 All rights reserved.
|
nuclear@0
|
9
|
nuclear@0
|
10 Redistribution and use of this software in source and binary forms,
|
nuclear@0
|
11 with or without modification, are permitted provided that the following
|
nuclear@0
|
12 conditions are met:
|
nuclear@0
|
13
|
nuclear@0
|
14 * Redistributions of source code must retain the above
|
nuclear@0
|
15 copyright notice, this list of conditions and the
|
nuclear@0
|
16 following disclaimer.
|
nuclear@0
|
17
|
nuclear@0
|
18 * Redistributions in binary form must reproduce the above
|
nuclear@0
|
19 copyright notice, this list of conditions and the
|
nuclear@0
|
20 following disclaimer in the documentation and/or other
|
nuclear@0
|
21 materials provided with the distribution.
|
nuclear@0
|
22
|
nuclear@0
|
23 * Neither the name of the assimp team, nor the names of its
|
nuclear@0
|
24 contributors may be used to endorse or promote products
|
nuclear@0
|
25 derived from this software without specific prior
|
nuclear@0
|
26 written permission of the assimp team.
|
nuclear@0
|
27
|
nuclear@0
|
28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
nuclear@0
|
29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
nuclear@0
|
30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
nuclear@0
|
31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
nuclear@0
|
32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
nuclear@0
|
33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
nuclear@0
|
34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
nuclear@0
|
35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
nuclear@0
|
36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
nuclear@0
|
37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
nuclear@0
|
38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
nuclear@0
|
39 ---------------------------------------------------------------------------
|
nuclear@0
|
40 */
|
nuclear@0
|
41
|
nuclear@0
|
42 /** @file MS3DLoader.cpp
|
nuclear@0
|
43 * @brief Implementation of the Ms3D importer class.
|
nuclear@0
|
44 * Written against http://chumbalum.swissquake.ch/ms3d/ms3dspec.txt
|
nuclear@0
|
45 */
|
nuclear@0
|
46
|
nuclear@0
|
47 #include "AssimpPCH.h"
|
nuclear@0
|
48 #ifndef ASSIMP_BUILD_NO_MS3D_IMPORTER
|
nuclear@0
|
49
|
nuclear@0
|
50 // internal headers
|
nuclear@0
|
51 #include "MS3DLoader.h"
|
nuclear@0
|
52 #include "StreamReader.h"
|
nuclear@0
|
53 using namespace Assimp;
|
nuclear@0
|
54
|
nuclear@0
|
55 static const aiImporterDesc desc = {
|
nuclear@0
|
56 "Milkshape 3D Importer",
|
nuclear@0
|
57 "",
|
nuclear@0
|
58 "",
|
nuclear@0
|
59 "http://chumbalum.swissquake.ch/",
|
nuclear@0
|
60 aiImporterFlags_SupportBinaryFlavour,
|
nuclear@0
|
61 0,
|
nuclear@0
|
62 0,
|
nuclear@0
|
63 0,
|
nuclear@0
|
64 0,
|
nuclear@0
|
65 "ms3d"
|
nuclear@0
|
66 };
|
nuclear@0
|
67
|
nuclear@0
|
68 // ASSIMP_BUILD_MS3D_ONE_NODE_PER_MESH
|
nuclear@0
|
69 // (enable old code path, which generates extra nodes per mesh while
|
nuclear@0
|
70 // the newer code uses aiMesh::mName to express the name of the
|
nuclear@0
|
71 // meshes (a.k.a. groups in MS3D))
|
nuclear@0
|
72
|
nuclear@0
|
73 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
74 // Constructor to be privately used by Importer
|
nuclear@0
|
75 MS3DImporter::MS3DImporter()
|
nuclear@0
|
76 {}
|
nuclear@0
|
77
|
nuclear@0
|
78 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
79 // Destructor, private as well
|
nuclear@0
|
80 MS3DImporter::~MS3DImporter()
|
nuclear@0
|
81 {}
|
nuclear@0
|
82
|
nuclear@0
|
83 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
84 // Returns whether the class can handle the format of the given file.
|
nuclear@0
|
85 bool MS3DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
|
nuclear@0
|
86 {
|
nuclear@0
|
87 // first call - simple extension check
|
nuclear@0
|
88 const std::string extension = GetExtension(pFile);
|
nuclear@0
|
89 if (extension == "ms3d") {
|
nuclear@0
|
90 return true;
|
nuclear@0
|
91 }
|
nuclear@0
|
92
|
nuclear@0
|
93 // second call - check for magic identifiers
|
nuclear@0
|
94 else if (!extension.length() || checkSig) {
|
nuclear@0
|
95 if (!pIOHandler) {
|
nuclear@0
|
96 return true;
|
nuclear@0
|
97 }
|
nuclear@0
|
98 const char* tokens[] = {"MS3D000000"};
|
nuclear@0
|
99 return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
|
nuclear@0
|
100 }
|
nuclear@0
|
101 return false;
|
nuclear@0
|
102 }
|
nuclear@0
|
103
|
nuclear@0
|
104 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
105 const aiImporterDesc* MS3DImporter::GetInfo () const
|
nuclear@0
|
106 {
|
nuclear@0
|
107 return &desc;
|
nuclear@0
|
108 }
|
nuclear@0
|
109
|
nuclear@0
|
110 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
111 void ReadColor(StreamReaderLE& stream, aiColor4D& ambient)
|
nuclear@0
|
112 {
|
nuclear@0
|
113 // aiColor4D is packed on gcc, implicit binding to float& fails therefore.
|
nuclear@0
|
114 stream >> (float&)ambient.r >> (float&)ambient.g >> (float&)ambient.b >> (float&)ambient.a;
|
nuclear@0
|
115 }
|
nuclear@0
|
116
|
nuclear@0
|
117 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
118 void ReadVector(StreamReaderLE& stream, aiVector3D& pos)
|
nuclear@0
|
119 {
|
nuclear@0
|
120 // See note in ReadColor()
|
nuclear@0
|
121 stream >> (float&)pos.x >> (float&)pos.y >> (float&)pos.z;
|
nuclear@0
|
122 }
|
nuclear@0
|
123
|
nuclear@0
|
124 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
125 template<typename T>
|
nuclear@0
|
126 void MS3DImporter :: ReadComments(StreamReaderLE& stream, std::vector<T>& outp)
|
nuclear@0
|
127 {
|
nuclear@0
|
128 uint16_t cnt;
|
nuclear@0
|
129 stream >> cnt;
|
nuclear@0
|
130
|
nuclear@0
|
131 for(unsigned int i = 0; i < cnt; ++i) {
|
nuclear@0
|
132 uint32_t index, clength;
|
nuclear@0
|
133 stream >> index >> clength;
|
nuclear@0
|
134
|
nuclear@0
|
135 if(index >= outp.size()) {
|
nuclear@0
|
136 DefaultLogger::get()->warn("MS3D: Invalid index in comment section");
|
nuclear@0
|
137 }
|
nuclear@0
|
138 else if (clength > stream.GetRemainingSize()) {
|
nuclear@0
|
139 throw DeadlyImportError("MS3D: Failure reading comment, length field is out of range");
|
nuclear@0
|
140 }
|
nuclear@0
|
141 else {
|
nuclear@0
|
142 outp[index].comment = std::string(reinterpret_cast<char*>(stream.GetPtr()),clength);
|
nuclear@0
|
143 }
|
nuclear@0
|
144 stream.IncPtr(clength);
|
nuclear@0
|
145 }
|
nuclear@0
|
146 }
|
nuclear@0
|
147
|
nuclear@0
|
148 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
149 template <typename T, typename T2, typename T3> bool inrange(const T& in, const T2& lower, const T3& higher)
|
nuclear@0
|
150 {
|
nuclear@0
|
151 return in > lower && in <= higher;
|
nuclear@0
|
152 }
|
nuclear@0
|
153
|
nuclear@0
|
154 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
155 void MS3DImporter :: CollectChildJoints(const std::vector<TempJoint>& joints,
|
nuclear@0
|
156 std::vector<bool>& hadit,
|
nuclear@0
|
157 aiNode* nd,
|
nuclear@0
|
158 const aiMatrix4x4& absTrafo)
|
nuclear@0
|
159 {
|
nuclear@0
|
160 unsigned int cnt = 0;
|
nuclear@0
|
161 for(size_t i = 0; i < joints.size(); ++i) {
|
nuclear@0
|
162 if (!hadit[i] && !strcmp(joints[i].parentName,nd->mName.data)) {
|
nuclear@0
|
163 ++cnt;
|
nuclear@0
|
164 }
|
nuclear@0
|
165 }
|
nuclear@0
|
166
|
nuclear@0
|
167 nd->mChildren = new aiNode*[nd->mNumChildren = cnt];
|
nuclear@0
|
168 cnt = 0;
|
nuclear@0
|
169 for(size_t i = 0; i < joints.size(); ++i) {
|
nuclear@0
|
170 if (!hadit[i] && !strcmp(joints[i].parentName,nd->mName.data)) {
|
nuclear@0
|
171 aiNode* ch = nd->mChildren[cnt++] = new aiNode(joints[i].name);
|
nuclear@0
|
172 ch->mParent = nd;
|
nuclear@0
|
173
|
nuclear@0
|
174 ch->mTransformation = aiMatrix4x4::Translation(joints[i].position,aiMatrix4x4()=aiMatrix4x4())*
|
nuclear@0
|
175 // XXX actually, I don't *know* why we need the inverse here. Probably column vs. row order?
|
nuclear@0
|
176 aiMatrix4x4().FromEulerAnglesXYZ(joints[i].rotation).Transpose();
|
nuclear@0
|
177
|
nuclear@0
|
178 const aiMatrix4x4 abs = absTrafo*ch->mTransformation;
|
nuclear@0
|
179 for(unsigned int a = 0; a < mScene->mNumMeshes; ++a) {
|
nuclear@0
|
180 aiMesh* const msh = mScene->mMeshes[a];
|
nuclear@0
|
181 for(unsigned int n = 0; n < msh->mNumBones; ++n) {
|
nuclear@0
|
182 aiBone* const bone = msh->mBones[n];
|
nuclear@0
|
183
|
nuclear@0
|
184 if(bone->mName == ch->mName) {
|
nuclear@0
|
185 bone->mOffsetMatrix = aiMatrix4x4(abs).Inverse();
|
nuclear@0
|
186 }
|
nuclear@0
|
187 }
|
nuclear@0
|
188 }
|
nuclear@0
|
189
|
nuclear@0
|
190 hadit[i] = true;
|
nuclear@0
|
191 CollectChildJoints(joints,hadit,ch,abs);
|
nuclear@0
|
192 }
|
nuclear@0
|
193 }
|
nuclear@0
|
194 }
|
nuclear@0
|
195
|
nuclear@0
|
196 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
197 void MS3DImporter :: CollectChildJoints(const std::vector<TempJoint>& joints, aiNode* nd)
|
nuclear@0
|
198 {
|
nuclear@0
|
199 std::vector<bool> hadit(joints.size(),false);
|
nuclear@0
|
200 aiMatrix4x4 trafo;
|
nuclear@0
|
201
|
nuclear@0
|
202 CollectChildJoints(joints,hadit,nd,trafo);
|
nuclear@0
|
203 }
|
nuclear@0
|
204
|
nuclear@0
|
205 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
206 // Imports the given file into the given scene structure.
|
nuclear@0
|
207 void MS3DImporter::InternReadFile( const std::string& pFile,
|
nuclear@0
|
208 aiScene* pScene, IOSystem* pIOHandler)
|
nuclear@0
|
209 {
|
nuclear@0
|
210 StreamReaderLE stream(pIOHandler->Open(pFile,"rb"));
|
nuclear@0
|
211
|
nuclear@0
|
212 // CanRead() should have done this already
|
nuclear@0
|
213 char head[10];
|
nuclear@0
|
214 int32_t version;
|
nuclear@0
|
215
|
nuclear@0
|
216 mScene = pScene;
|
nuclear@0
|
217
|
nuclear@0
|
218
|
nuclear@0
|
219 // 1 ------------ read into temporary data structures mirroring the original file
|
nuclear@0
|
220
|
nuclear@0
|
221 stream.CopyAndAdvance(head,10);
|
nuclear@0
|
222 stream >> version;
|
nuclear@0
|
223 if (strncmp(head,"MS3D000000",10)) {
|
nuclear@0
|
224 throw DeadlyImportError("Not a MS3D file, magic string MS3D000000 not found: "+pFile);
|
nuclear@0
|
225 }
|
nuclear@0
|
226
|
nuclear@0
|
227 if (version != 4) {
|
nuclear@0
|
228 throw DeadlyImportError("MS3D: Unsupported file format version, 4 was expected");
|
nuclear@0
|
229 }
|
nuclear@0
|
230
|
nuclear@0
|
231 uint16_t verts;
|
nuclear@0
|
232 stream >> verts;
|
nuclear@0
|
233
|
nuclear@0
|
234 std::vector<TempVertex> vertices(verts);
|
nuclear@0
|
235 for (unsigned int i = 0; i < verts; ++i) {
|
nuclear@0
|
236 TempVertex& v = vertices[i];
|
nuclear@0
|
237
|
nuclear@0
|
238 stream.IncPtr(1);
|
nuclear@0
|
239 ReadVector(stream,v.pos);
|
nuclear@0
|
240 v.bone_id[0] = stream.GetI1();
|
nuclear@0
|
241 v.ref_cnt = stream.GetI1();
|
nuclear@0
|
242
|
nuclear@0
|
243 v.bone_id[1] = v.bone_id[2] = v.bone_id[3] = UINT_MAX;
|
nuclear@0
|
244 v.weights[1] = v.weights[2] = v.weights[3] = 0.f;
|
nuclear@0
|
245 v.weights[0] = 1.f;
|
nuclear@0
|
246 }
|
nuclear@0
|
247
|
nuclear@0
|
248 uint16_t tris;
|
nuclear@0
|
249 stream >> tris;
|
nuclear@0
|
250
|
nuclear@0
|
251 std::vector<TempTriangle> triangles(tris);
|
nuclear@0
|
252 for (unsigned int i = 0;i < tris; ++i) {
|
nuclear@0
|
253 TempTriangle& t = triangles[i];
|
nuclear@0
|
254
|
nuclear@0
|
255 stream.IncPtr(2);
|
nuclear@0
|
256 for (unsigned int i = 0; i < 3; ++i) {
|
nuclear@0
|
257 t.indices[i] = stream.GetI2();
|
nuclear@0
|
258 }
|
nuclear@0
|
259
|
nuclear@0
|
260 for (unsigned int i = 0; i < 3; ++i) {
|
nuclear@0
|
261 ReadVector(stream,t.normals[i]);
|
nuclear@0
|
262 }
|
nuclear@0
|
263
|
nuclear@0
|
264 for (unsigned int i = 0; i < 3; ++i) {
|
nuclear@0
|
265 stream >> (float&)(t.uv[i].x); // see note in ReadColor()
|
nuclear@0
|
266 }
|
nuclear@0
|
267 for (unsigned int i = 0; i < 3; ++i) {
|
nuclear@0
|
268 stream >> (float&)(t.uv[i].y);
|
nuclear@0
|
269 }
|
nuclear@0
|
270
|
nuclear@0
|
271 t.sg = stream.GetI1();
|
nuclear@0
|
272 t.group = stream.GetI1();
|
nuclear@0
|
273 }
|
nuclear@0
|
274
|
nuclear@0
|
275 uint16_t grp;
|
nuclear@0
|
276 stream >> grp;
|
nuclear@0
|
277
|
nuclear@0
|
278 bool need_default = false;
|
nuclear@0
|
279 std::vector<TempGroup> groups(grp);
|
nuclear@0
|
280 for (unsigned int i = 0;i < grp; ++i) {
|
nuclear@0
|
281 TempGroup& t = groups[i];
|
nuclear@0
|
282
|
nuclear@0
|
283 stream.IncPtr(1);
|
nuclear@0
|
284 stream.CopyAndAdvance(t.name,32);
|
nuclear@0
|
285
|
nuclear@0
|
286 t.name[32] = '\0';
|
nuclear@0
|
287 uint16_t num;
|
nuclear@0
|
288 stream >> num;
|
nuclear@0
|
289
|
nuclear@0
|
290 t.triangles.resize(num);
|
nuclear@0
|
291 for (unsigned int i = 0; i < num; ++i) {
|
nuclear@0
|
292 t.triangles[i] = stream.GetI2();
|
nuclear@0
|
293 }
|
nuclear@0
|
294 t.mat = stream.GetI1();
|
nuclear@0
|
295 if (t.mat == UINT_MAX) {
|
nuclear@0
|
296 need_default = true;
|
nuclear@0
|
297 }
|
nuclear@0
|
298 }
|
nuclear@0
|
299
|
nuclear@0
|
300 uint16_t mat;
|
nuclear@0
|
301 stream >> mat;
|
nuclear@0
|
302
|
nuclear@0
|
303 std::vector<TempMaterial> materials(mat);
|
nuclear@0
|
304 for (unsigned int i = 0;i < mat; ++i) {
|
nuclear@0
|
305 TempMaterial& t = materials[i];
|
nuclear@0
|
306
|
nuclear@0
|
307 stream.CopyAndAdvance(t.name,32);
|
nuclear@0
|
308 t.name[32] = '\0';
|
nuclear@0
|
309
|
nuclear@0
|
310 ReadColor(stream,t.ambient);
|
nuclear@0
|
311 ReadColor(stream,t.diffuse);
|
nuclear@0
|
312 ReadColor(stream,t.specular);
|
nuclear@0
|
313 ReadColor(stream,t.emissive);
|
nuclear@0
|
314 stream >> t.shininess >> t.transparency;
|
nuclear@0
|
315
|
nuclear@0
|
316 stream.IncPtr(1);
|
nuclear@0
|
317
|
nuclear@0
|
318 stream.CopyAndAdvance(t.texture,128);
|
nuclear@0
|
319 t.texture[128] = '\0';
|
nuclear@0
|
320
|
nuclear@0
|
321 stream.CopyAndAdvance(t.alphamap,128);
|
nuclear@0
|
322 t.alphamap[128] = '\0';
|
nuclear@0
|
323 }
|
nuclear@0
|
324
|
nuclear@0
|
325 float animfps, currenttime;
|
nuclear@0
|
326 uint32_t totalframes;
|
nuclear@0
|
327 stream >> animfps >> currenttime >> totalframes;
|
nuclear@0
|
328
|
nuclear@0
|
329 uint16_t joint;
|
nuclear@0
|
330 stream >> joint;
|
nuclear@0
|
331
|
nuclear@0
|
332 std::vector<TempJoint> joints(joint);
|
nuclear@0
|
333 for(unsigned int i = 0; i < joint; ++i) {
|
nuclear@0
|
334 TempJoint& j = joints[i];
|
nuclear@0
|
335
|
nuclear@0
|
336 stream.IncPtr(1);
|
nuclear@0
|
337 stream.CopyAndAdvance(j.name,32);
|
nuclear@0
|
338 j.name[32] = '\0';
|
nuclear@0
|
339
|
nuclear@0
|
340 stream.CopyAndAdvance(j.parentName,32);
|
nuclear@0
|
341 j.parentName[32] = '\0';
|
nuclear@0
|
342
|
nuclear@0
|
343 // DefaultLogger::get()->debug(j.name);
|
nuclear@0
|
344 // DefaultLogger::get()->debug(j.parentName);
|
nuclear@0
|
345
|
nuclear@0
|
346 ReadVector(stream,j.rotation);
|
nuclear@0
|
347 ReadVector(stream,j.position);
|
nuclear@0
|
348
|
nuclear@0
|
349 j.rotFrames.resize(stream.GetI2());
|
nuclear@0
|
350 j.posFrames.resize(stream.GetI2());
|
nuclear@0
|
351
|
nuclear@0
|
352 for(unsigned int a = 0; a < j.rotFrames.size(); ++a) {
|
nuclear@0
|
353 TempKeyFrame& kf = j.rotFrames[a];
|
nuclear@0
|
354 stream >> kf.time;
|
nuclear@0
|
355 ReadVector(stream,kf.value);
|
nuclear@0
|
356 }
|
nuclear@0
|
357 for(unsigned int a = 0; a < j.posFrames.size(); ++a) {
|
nuclear@0
|
358 TempKeyFrame& kf = j.posFrames[a];
|
nuclear@0
|
359 stream >> kf.time;
|
nuclear@0
|
360 ReadVector(stream,kf.value);
|
nuclear@0
|
361 }
|
nuclear@0
|
362 }
|
nuclear@0
|
363
|
nuclear@0
|
364 if(stream.GetRemainingSize() > 4) {
|
nuclear@0
|
365 uint32_t subversion;
|
nuclear@0
|
366 stream >> subversion;
|
nuclear@0
|
367 if (subversion == 1) {
|
nuclear@0
|
368 ReadComments<TempGroup>(stream,groups);
|
nuclear@0
|
369 ReadComments<TempMaterial>(stream,materials);
|
nuclear@0
|
370 ReadComments<TempJoint>(stream,joints);
|
nuclear@0
|
371
|
nuclear@0
|
372 // model comment - print it for we have such a nice log.
|
nuclear@0
|
373 if (stream.GetI4()) {
|
nuclear@0
|
374 const size_t len = static_cast<size_t>(stream.GetI4());
|
nuclear@0
|
375 if (len > stream.GetRemainingSize()) {
|
nuclear@0
|
376 throw DeadlyImportError("MS3D: Model comment is too long");
|
nuclear@0
|
377 }
|
nuclear@0
|
378
|
nuclear@0
|
379 const std::string& s = std::string(reinterpret_cast<char*>(stream.GetPtr()),len);
|
nuclear@0
|
380 DefaultLogger::get()->debug("MS3D: Model comment: " + s);
|
nuclear@0
|
381 }
|
nuclear@0
|
382
|
nuclear@0
|
383 if(stream.GetRemainingSize() > 4 && inrange((stream >> subversion,subversion),1u,3u)) {
|
nuclear@0
|
384 for(unsigned int i = 0; i < verts; ++i) {
|
nuclear@0
|
385 TempVertex& v = vertices[i];
|
nuclear@0
|
386 v.weights[3]=1.f;
|
nuclear@0
|
387 for(unsigned int n = 0; n < 3; v.weights[3]-=v.weights[n++]) {
|
nuclear@0
|
388 v.bone_id[n+1] = stream.GetI1();
|
nuclear@0
|
389 v.weights[n] = static_cast<float>(static_cast<unsigned int>(stream.GetI1()))/255.f;
|
nuclear@0
|
390 }
|
nuclear@0
|
391 stream.IncPtr((subversion-1)<<2u);
|
nuclear@0
|
392 }
|
nuclear@0
|
393
|
nuclear@0
|
394 // even further extra data is not of interest for us, at least now now.
|
nuclear@0
|
395 }
|
nuclear@0
|
396 }
|
nuclear@0
|
397 }
|
nuclear@0
|
398
|
nuclear@0
|
399 // 2 ------------ convert to proper aiXX data structures -----------------------------------
|
nuclear@0
|
400
|
nuclear@0
|
401 if (need_default && materials.size()) {
|
nuclear@0
|
402 DefaultLogger::get()->warn("MS3D: Found group with no material assigned, spawning default material");
|
nuclear@0
|
403 // if one of the groups has no material assigned, but there are other
|
nuclear@0
|
404 // groups with materials, a default material needs to be added (
|
nuclear@0
|
405 // scenepreprocessor adds a default material only if nummat==0).
|
nuclear@0
|
406 materials.push_back(TempMaterial());
|
nuclear@0
|
407 TempMaterial& m = materials.back();
|
nuclear@0
|
408
|
nuclear@0
|
409 strcpy(m.name,"<MS3D_DefaultMat>");
|
nuclear@0
|
410 m.diffuse = aiColor4D(0.6f,0.6f,0.6f,1.0);
|
nuclear@0
|
411 m.transparency = 1.f;
|
nuclear@0
|
412 m.shininess = 0.f;
|
nuclear@0
|
413
|
nuclear@0
|
414 // this is because these TempXXX struct's have no c'tors.
|
nuclear@0
|
415 m.texture[0] = m.alphamap[0] = '\0';
|
nuclear@0
|
416
|
nuclear@0
|
417 for (unsigned int i = 0; i < groups.size(); ++i) {
|
nuclear@0
|
418 TempGroup& g = groups[i];
|
nuclear@0
|
419 if (g.mat == UINT_MAX) {
|
nuclear@0
|
420 g.mat = materials.size()-1;
|
nuclear@0
|
421 }
|
nuclear@0
|
422 }
|
nuclear@0
|
423 }
|
nuclear@0
|
424
|
nuclear@0
|
425 // convert materials to our generic key-value dict-alike
|
nuclear@0
|
426 if (materials.size()) {
|
nuclear@0
|
427 pScene->mMaterials = new aiMaterial*[materials.size()];
|
nuclear@0
|
428 for (size_t i = 0; i < materials.size(); ++i) {
|
nuclear@0
|
429
|
nuclear@0
|
430 aiMaterial* mo = new aiMaterial();
|
nuclear@0
|
431 pScene->mMaterials[pScene->mNumMaterials++] = mo;
|
nuclear@0
|
432
|
nuclear@0
|
433 const TempMaterial& mi = materials[i];
|
nuclear@0
|
434
|
nuclear@0
|
435 aiString tmp;
|
nuclear@0
|
436 if (0[mi.alphamap]) {
|
nuclear@0
|
437 tmp = aiString(mi.alphamap);
|
nuclear@0
|
438 mo->AddProperty(&tmp,AI_MATKEY_TEXTURE_OPACITY(0));
|
nuclear@0
|
439 }
|
nuclear@0
|
440 if (0[mi.texture]) {
|
nuclear@0
|
441 tmp = aiString(mi.texture);
|
nuclear@0
|
442 mo->AddProperty(&tmp,AI_MATKEY_TEXTURE_DIFFUSE(0));
|
nuclear@0
|
443 }
|
nuclear@0
|
444 if (0[mi.name]) {
|
nuclear@0
|
445 tmp = aiString(mi.name);
|
nuclear@0
|
446 mo->AddProperty(&tmp,AI_MATKEY_NAME);
|
nuclear@0
|
447 }
|
nuclear@0
|
448
|
nuclear@0
|
449 mo->AddProperty(&mi.ambient,1,AI_MATKEY_COLOR_AMBIENT);
|
nuclear@0
|
450 mo->AddProperty(&mi.diffuse,1,AI_MATKEY_COLOR_DIFFUSE);
|
nuclear@0
|
451 mo->AddProperty(&mi.specular,1,AI_MATKEY_COLOR_SPECULAR);
|
nuclear@0
|
452 mo->AddProperty(&mi.emissive,1,AI_MATKEY_COLOR_EMISSIVE);
|
nuclear@0
|
453
|
nuclear@0
|
454 mo->AddProperty(&mi.shininess,1,AI_MATKEY_SHININESS);
|
nuclear@0
|
455 mo->AddProperty(&mi.transparency,1,AI_MATKEY_OPACITY);
|
nuclear@0
|
456
|
nuclear@0
|
457 const int sm = mi.shininess>0.f?aiShadingMode_Phong:aiShadingMode_Gouraud;
|
nuclear@0
|
458 mo->AddProperty(&sm,1,AI_MATKEY_SHADING_MODEL);
|
nuclear@0
|
459 }
|
nuclear@0
|
460 }
|
nuclear@0
|
461
|
nuclear@0
|
462 // convert groups to meshes
|
nuclear@0
|
463 if (groups.empty()) {
|
nuclear@0
|
464 throw DeadlyImportError("MS3D: Didn't get any group records, file is malformed");
|
nuclear@0
|
465 }
|
nuclear@0
|
466
|
nuclear@0
|
467 pScene->mMeshes = new aiMesh*[pScene->mNumMeshes=static_cast<unsigned int>(groups.size())]();
|
nuclear@0
|
468 for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
|
nuclear@0
|
469
|
nuclear@0
|
470 aiMesh* m = pScene->mMeshes[i] = new aiMesh();
|
nuclear@0
|
471 const TempGroup& g = groups[i];
|
nuclear@0
|
472
|
nuclear@0
|
473 if (pScene->mNumMaterials && g.mat > pScene->mNumMaterials) {
|
nuclear@0
|
474 throw DeadlyImportError("MS3D: Encountered invalid material index, file is malformed");
|
nuclear@0
|
475 } // no error if no materials at all - scenepreprocessor adds one then
|
nuclear@0
|
476
|
nuclear@0
|
477 m->mMaterialIndex = g.mat;
|
nuclear@0
|
478 m->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
|
nuclear@0
|
479
|
nuclear@0
|
480 m->mFaces = new aiFace[m->mNumFaces = g.triangles.size()];
|
nuclear@0
|
481 m->mNumVertices = m->mNumFaces*3;
|
nuclear@0
|
482
|
nuclear@0
|
483 // storage for vertices - verbose format, as requested by the postprocessing pipeline
|
nuclear@0
|
484 m->mVertices = new aiVector3D[m->mNumVertices];
|
nuclear@0
|
485 m->mNormals = new aiVector3D[m->mNumVertices];
|
nuclear@0
|
486 m->mTextureCoords[0] = new aiVector3D[m->mNumVertices];
|
nuclear@0
|
487 m->mNumUVComponents[0] = 2;
|
nuclear@0
|
488
|
nuclear@0
|
489 typedef std::map<unsigned int,unsigned int> BoneSet;
|
nuclear@0
|
490 BoneSet mybones;
|
nuclear@0
|
491
|
nuclear@0
|
492 for (unsigned int i = 0,n = 0; i < m->mNumFaces; ++i) {
|
nuclear@0
|
493 aiFace& f = m->mFaces[i];
|
nuclear@0
|
494 if (g.triangles[i]>triangles.size()) {
|
nuclear@0
|
495 throw DeadlyImportError("MS3D: Encountered invalid triangle index, file is malformed");
|
nuclear@0
|
496 }
|
nuclear@0
|
497
|
nuclear@0
|
498 TempTriangle& t = triangles[g.triangles[i]];
|
nuclear@0
|
499 f.mIndices = new unsigned int[f.mNumIndices=3];
|
nuclear@0
|
500
|
nuclear@0
|
501 for (unsigned int i = 0; i < 3; ++i,++n) {
|
nuclear@0
|
502 if (t.indices[i]>vertices.size()) {
|
nuclear@0
|
503 throw DeadlyImportError("MS3D: Encountered invalid vertex index, file is malformed");
|
nuclear@0
|
504 }
|
nuclear@0
|
505
|
nuclear@0
|
506 const TempVertex& v = vertices[t.indices[i]];
|
nuclear@0
|
507 for(unsigned int a = 0; a < 4; ++a) {
|
nuclear@0
|
508 if (v.bone_id[a] != UINT_MAX) {
|
nuclear@0
|
509 if (v.bone_id[a] >= joints.size()) {
|
nuclear@0
|
510 throw DeadlyImportError("MS3D: Encountered invalid bone index, file is malformed");
|
nuclear@0
|
511 }
|
nuclear@0
|
512 if (mybones.find(v.bone_id[a]) == mybones.end()) {
|
nuclear@0
|
513 mybones[v.bone_id[a]] = 1;
|
nuclear@0
|
514 }
|
nuclear@0
|
515 else ++mybones[v.bone_id[a]];
|
nuclear@0
|
516 }
|
nuclear@0
|
517 }
|
nuclear@0
|
518
|
nuclear@0
|
519 // collect vertex components
|
nuclear@0
|
520 m->mVertices[n] = v.pos;
|
nuclear@0
|
521
|
nuclear@0
|
522 m->mNormals[n] = t.normals[i];
|
nuclear@0
|
523 m->mTextureCoords[0][n] = aiVector3D(t.uv[i].x,1.f-t.uv[i].y,0.0);
|
nuclear@0
|
524 f.mIndices[i] = n;
|
nuclear@0
|
525 }
|
nuclear@0
|
526 }
|
nuclear@0
|
527
|
nuclear@0
|
528 // allocate storage for bones
|
nuclear@0
|
529 if(mybones.size()) {
|
nuclear@0
|
530 std::vector<unsigned int> bmap(joints.size());
|
nuclear@0
|
531 m->mBones = new aiBone*[mybones.size()]();
|
nuclear@0
|
532 for(BoneSet::const_iterator it = mybones.begin(); it != mybones.end(); ++it) {
|
nuclear@0
|
533 aiBone* const bn = m->mBones[m->mNumBones] = new aiBone();
|
nuclear@0
|
534 const TempJoint& jnt = joints[(*it).first];
|
nuclear@0
|
535
|
nuclear@0
|
536 bn->mName.Set(jnt.name);
|
nuclear@0
|
537 bn->mWeights = new aiVertexWeight[(*it).second];
|
nuclear@0
|
538
|
nuclear@0
|
539 bmap[(*it).first] = m->mNumBones++;
|
nuclear@0
|
540 }
|
nuclear@0
|
541
|
nuclear@0
|
542 // .. and collect bone weights
|
nuclear@0
|
543 for (unsigned int i = 0,n = 0; i < m->mNumFaces; ++i) {
|
nuclear@0
|
544 TempTriangle& t = triangles[g.triangles[i]];
|
nuclear@0
|
545
|
nuclear@0
|
546 for (unsigned int i = 0; i < 3; ++i,++n) {
|
nuclear@0
|
547 const TempVertex& v = vertices[t.indices[i]];
|
nuclear@0
|
548 for(unsigned int a = 0; a < 4; ++a) {
|
nuclear@0
|
549 const unsigned int bone = v.bone_id[a];
|
nuclear@0
|
550 if(bone==UINT_MAX){
|
nuclear@0
|
551 continue;
|
nuclear@0
|
552 }
|
nuclear@0
|
553
|
nuclear@0
|
554 aiBone* const outbone = m->mBones[bmap[bone]];
|
nuclear@0
|
555 aiVertexWeight& outwght = outbone->mWeights[outbone->mNumWeights++];
|
nuclear@0
|
556
|
nuclear@0
|
557 outwght.mVertexId = n;
|
nuclear@0
|
558 outwght.mWeight = v.weights[a];
|
nuclear@0
|
559 }
|
nuclear@0
|
560 }
|
nuclear@0
|
561 }
|
nuclear@0
|
562 }
|
nuclear@0
|
563 }
|
nuclear@0
|
564
|
nuclear@0
|
565 // ... add dummy nodes under a single root, each holding a reference to one
|
nuclear@0
|
566 // mesh. If we didn't do this, we'd loose the group name.
|
nuclear@0
|
567 aiNode* rt = pScene->mRootNode = new aiNode("<MS3DRoot>");
|
nuclear@0
|
568
|
nuclear@0
|
569 #ifdef ASSIMP_BUILD_MS3D_ONE_NODE_PER_MESH
|
nuclear@0
|
570 rt->mChildren = new aiNode*[rt->mNumChildren=pScene->mNumMeshes+(joints.size()?1:0)]();
|
nuclear@0
|
571
|
nuclear@0
|
572 for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
|
nuclear@0
|
573 aiNode* nd = rt->mChildren[i] = new aiNode();
|
nuclear@0
|
574
|
nuclear@0
|
575 const TempGroup& g = groups[i];
|
nuclear@0
|
576
|
nuclear@0
|
577 // we need to generate an unique name for all mesh nodes.
|
nuclear@0
|
578 // since we want to keep the group name, a prefix is
|
nuclear@0
|
579 // prepended.
|
nuclear@0
|
580 nd->mName = aiString("<MS3DMesh>_");
|
nuclear@0
|
581 nd->mName.Append(g.name);
|
nuclear@0
|
582 nd->mParent = rt;
|
nuclear@0
|
583
|
nuclear@0
|
584 nd->mMeshes = new unsigned int[nd->mNumMeshes = 1];
|
nuclear@0
|
585 nd->mMeshes[0] = i;
|
nuclear@0
|
586 }
|
nuclear@0
|
587 #else
|
nuclear@0
|
588 rt->mMeshes = new unsigned int[pScene->mNumMeshes];
|
nuclear@0
|
589 for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
|
nuclear@0
|
590 rt->mMeshes[rt->mNumMeshes++] = i;
|
nuclear@0
|
591 }
|
nuclear@0
|
592 #endif
|
nuclear@0
|
593
|
nuclear@0
|
594 // convert animations as well
|
nuclear@0
|
595 if(joints.size()) {
|
nuclear@0
|
596 #ifndef ASSIMP_BUILD_MS3D_ONE_NODE_PER_MESH
|
nuclear@0
|
597 rt->mChildren = new aiNode*[1]();
|
nuclear@0
|
598 rt->mNumChildren = 1;
|
nuclear@0
|
599
|
nuclear@0
|
600 aiNode* jt = rt->mChildren[0] = new aiNode();
|
nuclear@0
|
601 #else
|
nuclear@0
|
602 aiNode* jt = rt->mChildren[pScene->mNumMeshes] = new aiNode();
|
nuclear@0
|
603 #endif
|
nuclear@0
|
604 jt->mParent = rt;
|
nuclear@0
|
605 CollectChildJoints(joints,jt);
|
nuclear@0
|
606 jt->mName.Set("<MS3DJointRoot>");
|
nuclear@0
|
607
|
nuclear@0
|
608 pScene->mAnimations = new aiAnimation*[ pScene->mNumAnimations = 1 ];
|
nuclear@0
|
609 aiAnimation* const anim = pScene->mAnimations[0] = new aiAnimation();
|
nuclear@0
|
610
|
nuclear@0
|
611 anim->mName.Set("<MS3DMasterAnim>");
|
nuclear@0
|
612
|
nuclear@0
|
613 // carry the fps info to the user by scaling all times with it
|
nuclear@0
|
614 anim->mTicksPerSecond = animfps;
|
nuclear@0
|
615
|
nuclear@0
|
616 // leave duration at its default, so ScenePreprocessor will fill an appropriate
|
nuclear@0
|
617 // value (the values taken from some MS3D files seem to be too unreliable
|
nuclear@0
|
618 // to pass the validation)
|
nuclear@0
|
619 // anim->mDuration = totalframes/animfps;
|
nuclear@0
|
620
|
nuclear@0
|
621 anim->mChannels = new aiNodeAnim*[joints.size()]();
|
nuclear@0
|
622 for(std::vector<TempJoint>::const_iterator it = joints.begin(); it != joints.end(); ++it) {
|
nuclear@0
|
623 if ((*it).rotFrames.empty() && (*it).posFrames.empty()) {
|
nuclear@0
|
624 continue;
|
nuclear@0
|
625 }
|
nuclear@0
|
626
|
nuclear@0
|
627 aiNodeAnim* nd = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim();
|
nuclear@0
|
628 nd->mNodeName.Set((*it).name);
|
nuclear@0
|
629
|
nuclear@0
|
630 if ((*it).rotFrames.size()) {
|
nuclear@0
|
631 nd->mRotationKeys = new aiQuatKey[(*it).rotFrames.size()];
|
nuclear@0
|
632 for(std::vector<TempKeyFrame>::const_iterator rot = (*it).rotFrames.begin(); rot != (*it).rotFrames.end(); ++rot) {
|
nuclear@0
|
633 aiQuatKey& q = nd->mRotationKeys[nd->mNumRotationKeys++];
|
nuclear@0
|
634
|
nuclear@0
|
635 q.mTime = (*rot).time*animfps;
|
nuclear@0
|
636
|
nuclear@0
|
637 // XXX it seems our matrix&quaternion code has faults in its conversion routines --
|
nuclear@0
|
638 // aiQuaternion(x,y,z) seems to besomething different as quat(matrix.fromeuler(x,y,z)).
|
nuclear@0
|
639 q.mValue = aiQuaternion(aiMatrix3x3(aiMatrix4x4().FromEulerAnglesXYZ((*rot).value)*
|
nuclear@0
|
640 aiMatrix4x4().FromEulerAnglesXYZ((*it).rotation)).Transpose());
|
nuclear@0
|
641 }
|
nuclear@0
|
642 }
|
nuclear@0
|
643
|
nuclear@0
|
644 if ((*it).posFrames.size()) {
|
nuclear@0
|
645 nd->mPositionKeys = new aiVectorKey[(*it).posFrames.size()];
|
nuclear@0
|
646
|
nuclear@0
|
647 aiQuatKey* qu = nd->mRotationKeys;
|
nuclear@0
|
648 for(std::vector<TempKeyFrame>::const_iterator pos = (*it).posFrames.begin(); pos != (*it).posFrames.end(); ++pos,++qu) {
|
nuclear@0
|
649 aiVectorKey& v = nd->mPositionKeys[nd->mNumPositionKeys++];
|
nuclear@0
|
650
|
nuclear@0
|
651 v.mTime = (*pos).time*animfps;
|
nuclear@0
|
652 v.mValue = (*it).position + (*pos).value;
|
nuclear@0
|
653 }
|
nuclear@0
|
654 }
|
nuclear@0
|
655 }
|
nuclear@0
|
656 // fixup to pass the validation if not a single animation channel is non-trivial
|
nuclear@0
|
657 if (!anim->mNumChannels) {
|
nuclear@0
|
658 anim->mChannels = NULL;
|
nuclear@0
|
659 }
|
nuclear@0
|
660 }
|
nuclear@0
|
661 }
|
nuclear@0
|
662
|
nuclear@0
|
663 #endif
|