1 // Copyright (C) 2002-2012 Nikolaus Gebhardt
2 // This file is part of the "Irrlicht Engine".
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
4 
5 #include "IrrCompileConfig.h"
6 #ifdef _IRR_COMPILE_WITH_MS3D_LOADER_
7 
8 #include "IReadFile.h"
9 #include "os.h"
10 #include "CMS3DMeshFileLoader.h"
11 #include "CSkinnedMesh.h"
12 
13 
14 namespace irr
15 {
16 namespace scene
17 {
18 
19 #ifdef _DEBUG
20 #define _IRR_DEBUG_MS3D_LOADER_
21 #endif
22 
23 // byte-align structures
24 #include "irrpack.h"
25 
26 namespace {
27 // File header
28 struct MS3DHeader
29 {
30 	char ID[10];
31 	int Version;
32 } PACK_STRUCT;
33 
34 // Vertex information
35 struct MS3DVertex
36 {
37 	u8 Flags;
38 	float Vertex[3];
39 	char BoneID;
40 	u8 RefCount;
41 } PACK_STRUCT;
42 
43 // Triangle information
44 struct MS3DTriangle
45 {
46 	u16 Flags;
47 	u16 VertexIndices[3];
48 	float VertexNormals[3][3];
49 	float S[3], T[3];
50 	u8 SmoothingGroup;
51 	u8 GroupIndex;
52 } PACK_STRUCT;
53 
54 // Material information
55 struct MS3DMaterial
56 {
57     char Name[32];
58     float Ambient[4];
59     float Diffuse[4];
60     float Specular[4];
61     float Emissive[4];
62     float Shininess;	// 0.0f - 128.0f
63     float Transparency;	// 0.0f - 1.0f
64     u8 Mode;	// 0, 1, 2 is unused now
65     char Texture[128];
66     char Alphamap[128];
67 } PACK_STRUCT;
68 
69 // Joint information
70 struct MS3DJoint
71 {
72 	u8 Flags;
73 	char Name[32];
74 	char ParentName[32];
75 	float Rotation[3];
76 	float Translation[3];
77 	u16 NumRotationKeyframes;
78 	u16 NumTranslationKeyframes;
79 } PACK_STRUCT;
80 
81 // Keyframe data
82 struct MS3DKeyframe
83 {
84 	float Time;
85 	float Parameter[3];
86 } PACK_STRUCT;
87 
88 // vertex weights in 1.8.x
89 struct MS3DVertexWeights
90 {
91 	char boneIds[3];
92 	u8 weights[3];
93 } PACK_STRUCT;
94 
95 } // end namespace
96 
97 // Default alignment
98 #include "irrunpack.h"
99 
100 struct SGroup
101 {
102 	core::stringc Name;
103 	core::array<u16> VertexIds;
104 	u16 MaterialIdx;
105 };
106 
107 //! Constructor
CMS3DMeshFileLoader(video::IVideoDriver * driver)108 CMS3DMeshFileLoader::CMS3DMeshFileLoader(video::IVideoDriver *driver)
109 : Driver(driver), AnimatedMesh(0)
110 {
111 	#ifdef _DEBUG
112 	setDebugName("CMS3DMeshFileLoader");
113 	#endif
114 }
115 
116 
117 //! returns true if the file maybe is able to be loaded by this class
118 //! based on the file extension (e.g. ".bsp")
isALoadableFileExtension(const io::path & filename) const119 bool CMS3DMeshFileLoader::isALoadableFileExtension(const io::path& filename) const
120 {
121 	return core::hasFileExtension ( filename, "ms3d" );
122 }
123 
124 
125 //! creates/loads an animated mesh from the file.
126 //! \return Pointer to the created mesh. Returns 0 if loading failed.
127 //! If you no longer need the mesh, you should call IAnimatedMesh::drop().
128 //! See IReferenceCounted::drop() for more information.
createMesh(io::IReadFile * file)129 IAnimatedMesh* CMS3DMeshFileLoader::createMesh(io::IReadFile* file)
130 {
131 	if (!file)
132 		return 0;
133 
134 	AnimatedMesh = new CSkinnedMesh();
135 
136 	if ( load(file) )
137 	{
138 		AnimatedMesh->finalize();
139 	}
140 	else
141 	{
142 		AnimatedMesh->drop();
143 		AnimatedMesh = 0;
144 	}
145 
146 	return AnimatedMesh;
147 }
148 
149 
150 //! loads a milkshape file
load(io::IReadFile * file)151 bool CMS3DMeshFileLoader::load(io::IReadFile* file)
152 {
153 	if (!file)
154 		return false;
155 
156 	// find file size
157 	const long fileSize = file->getSize();
158 
159 	// read whole file
160 
161 	u8* buffer = new u8[fileSize];
162 	s32 read = file->read(buffer, fileSize);
163 	if (read != fileSize)
164 	{
165 		delete [] buffer;
166 		os::Printer::log("Could not read full file. Loading failed", file->getFileName(), ELL_ERROR);
167 		return false;
168 	}
169 
170 	// read header
171 
172 	const u8 *pPtr = (u8*)((void*)buffer);
173 	MS3DHeader *pHeader = (MS3DHeader*)pPtr;
174 	pPtr += sizeof(MS3DHeader);
175 
176 	if ( strncmp( pHeader->ID, "MS3D000000", 10 ) != 0 )
177 	{
178 		delete [] buffer;
179 		os::Printer::log("Not a valid Milkshape3D Model File. Loading failed", file->getFileName(), ELL_ERROR);
180 		return false;
181 	}
182 
183 #ifdef __BIG_ENDIAN__
184 	pHeader->Version = os::Byteswap::byteswap(pHeader->Version);
185 #endif
186 	if ( pHeader->Version < 3 || pHeader->Version > 4 )
187 	{
188 		delete [] buffer;
189 		os::Printer::log("Only Milkshape3D version 3 and 4 (1.3 to 1.8) is supported. Loading failed", file->getFileName(), ELL_ERROR);
190 		return false;
191 	}
192 #ifdef _IRR_DEBUG_MS3D_LOADER_
193 	os::Printer::log("Loaded header version", core::stringc(pHeader->Version).c_str());
194 #endif
195 
196 	// get pointers to data
197 
198 	// vertices
199 	u16 numVertices = *(u16*)pPtr;
200 #ifdef __BIG_ENDIAN__
201 	numVertices = os::Byteswap::byteswap(numVertices);
202 #endif
203 #ifdef _IRR_DEBUG_MS3D_LOADER_
204 	os::Printer::log("Load vertices", core::stringc(numVertices).c_str());
205 #endif
206 	pPtr += sizeof(u16);
207 	MS3DVertex *vertices = (MS3DVertex*)pPtr;
208 	pPtr += sizeof(MS3DVertex) * numVertices;
209 	if (pPtr > buffer+fileSize)
210 	{
211 		delete [] buffer;
212 		os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR);
213 		return false;
214 	}
215 	for (u16 tmp=0; tmp<numVertices; ++tmp)
216 	{
217 #ifdef __BIG_ENDIAN__
218 		vertices[tmp].Vertex[0] = os::Byteswap::byteswap(vertices[tmp].Vertex[0]);
219 		vertices[tmp].Vertex[1] = os::Byteswap::byteswap(vertices[tmp].Vertex[1]);
220 		vertices[tmp].Vertex[2] = -os::Byteswap::byteswap(vertices[tmp].Vertex[2]);
221 #else
222 		vertices[tmp].Vertex[2] = -vertices[tmp].Vertex[2];
223 #endif
224 	}
225 
226 	// triangles
227 	u16 numTriangles = *(u16*)pPtr;
228 #ifdef __BIG_ENDIAN__
229 	numTriangles = os::Byteswap::byteswap(numTriangles);
230 #endif
231 #ifdef _IRR_DEBUG_MS3D_LOADER_
232 	os::Printer::log("Load Triangles", core::stringc(numTriangles).c_str());
233 #endif
234 	pPtr += sizeof(u16);
235 	MS3DTriangle *triangles = (MS3DTriangle*)pPtr;
236 	pPtr += sizeof(MS3DTriangle) * numTriangles;
237 	if (pPtr > buffer+fileSize)
238 	{
239 		delete [] buffer;
240 		os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR);
241 		return false;
242 	}
243 	for (u16 tmp=0; tmp<numTriangles; ++tmp)
244 	{
245 #ifdef __BIG_ENDIAN__
246 		triangles[tmp].Flags = os::Byteswap::byteswap(triangles[tmp].Flags);
247 		for (u16 j=0; j<3; ++j)
248 		{
249 			triangles[tmp].VertexIndices[j] = os::Byteswap::byteswap(triangles[tmp].VertexIndices[j]);
250 			triangles[tmp].VertexNormals[j][0] = os::Byteswap::byteswap(triangles[tmp].VertexNormals[j][0]);
251 			triangles[tmp].VertexNormals[j][1] = os::Byteswap::byteswap(triangles[tmp].VertexNormals[j][1]);
252 			triangles[tmp].VertexNormals[j][2] = -os::Byteswap::byteswap(triangles[tmp].VertexNormals[j][2]);
253 			triangles[tmp].S[j] = os::Byteswap::byteswap(triangles[tmp].S[j]);
254 			triangles[tmp].T[j] = os::Byteswap::byteswap(triangles[tmp].T[j]);
255 		}
256 #else
257 		triangles[tmp].VertexNormals[0][2] = -triangles[tmp].VertexNormals[0][2];
258 		triangles[tmp].VertexNormals[1][2] = -triangles[tmp].VertexNormals[1][2];
259 		triangles[tmp].VertexNormals[2][2] = -triangles[tmp].VertexNormals[2][2];
260 #endif
261 	}
262 
263 	// groups
264 	u16 numGroups = *(u16*)pPtr;
265 #ifdef __BIG_ENDIAN__
266 	numGroups = os::Byteswap::byteswap(numGroups);
267 #endif
268 #ifdef _IRR_DEBUG_MS3D_LOADER_
269 	os::Printer::log("Load Groups", core::stringc(numGroups).c_str());
270 #endif
271 	pPtr += sizeof(u16);
272 
273 	core::array<SGroup> groups;
274 	groups.reallocate(numGroups);
275 
276 	//store groups
277 	u32 i;
278 	for (i=0; i<numGroups; ++i)
279 	{
280 		groups.push_back(SGroup());
281 		SGroup& grp = groups.getLast();
282 
283 		// The byte flag is before the name, so add 1
284 		grp.Name = ((const c8*) pPtr) + 1;
285 
286 		pPtr += 33; // name and 1 byte flags
287 		u16 triangleCount = *(u16*)pPtr;
288 #ifdef __BIG_ENDIAN__
289 		triangleCount = os::Byteswap::byteswap(triangleCount);
290 #endif
291 		pPtr += sizeof(u16);
292 		grp.VertexIds.reallocate(triangleCount);
293 
294 		//pPtr += sizeof(u16) * triangleCount; // triangle indices
295 		for (u16 j=0; j<triangleCount; ++j)
296 		{
297 #ifdef __BIG_ENDIAN__
298 			grp.VertexIds.push_back(os::Byteswap::byteswap(*(u16*)pPtr));
299 #else
300 			grp.VertexIds.push_back(*(u16*)pPtr);
301 #endif
302 			pPtr += sizeof (u16);
303 		}
304 
305 		grp.MaterialIdx = *(u8*)pPtr;
306 		if (grp.MaterialIdx == 255)
307 			grp.MaterialIdx = 0;
308 
309 		pPtr += sizeof(c8); // material index
310 		if (pPtr > buffer+fileSize)
311 		{
312 			delete [] buffer;
313 			os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR);
314 			return false;
315 		}
316 	}
317 
318 	// load materials
319 	u16 numMaterials = *(u16*)pPtr;
320 #ifdef __BIG_ENDIAN__
321 	numMaterials = os::Byteswap::byteswap(numMaterials);
322 #endif
323 #ifdef _IRR_DEBUG_MS3D_LOADER_
324 	os::Printer::log("Load Materials", core::stringc(numMaterials).c_str());
325 #endif
326 	pPtr += sizeof(u16);
327 
328 	if(numMaterials == 0)
329 	{
330 		// if there are no materials, add at least one buffer
331 		AnimatedMesh->addMeshBuffer();
332 	}
333 
334 	for (i=0; i<numMaterials; ++i)
335 	{
336 		MS3DMaterial *material = (MS3DMaterial*)pPtr;
337 #ifdef __BIG_ENDIAN__
338 		for (u16 j=0; j<4; ++j)
339 			material->Ambient[j] = os::Byteswap::byteswap(material->Ambient[j]);
340 		for (u16 j=0; j<4; ++j)
341 			material->Diffuse[j] = os::Byteswap::byteswap(material->Diffuse[j]);
342 		for (u16 j=0; j<4; ++j)
343 			material->Specular[j] = os::Byteswap::byteswap(material->Specular[j]);
344 		for (u16 j=0; j<4; ++j)
345 			material->Emissive[j] = os::Byteswap::byteswap(material->Emissive[j]);
346 		material->Shininess = os::Byteswap::byteswap(material->Shininess);
347 		material->Transparency = os::Byteswap::byteswap(material->Transparency);
348 #endif
349 		pPtr += sizeof(MS3DMaterial);
350 		if (pPtr > buffer+fileSize)
351 		{
352 			delete [] buffer;
353 			os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR);
354 			return false;
355 		}
356 
357 		scene::SSkinMeshBuffer *tmpBuffer = AnimatedMesh->addMeshBuffer();
358 
359 		tmpBuffer->Material.MaterialType = video::EMT_SOLID;
360 
361 		tmpBuffer->Material.AmbientColor = video::SColorf(material->Ambient[0], material->Ambient[1], material->Ambient[2], material->Ambient[3]).toSColor ();
362 		tmpBuffer->Material.DiffuseColor = video::SColorf(material->Diffuse[0], material->Diffuse[1], material->Diffuse[2], material->Diffuse[3]).toSColor ();
363 		tmpBuffer->Material.EmissiveColor = video::SColorf(material->Emissive[0], material->Emissive[1], material->Emissive[2], material->Emissive[3]).toSColor ();
364 		tmpBuffer->Material.SpecularColor = video::SColorf(material->Specular[0], material->Specular[1], material->Specular[2], material->Specular[3]).toSColor ();
365 		tmpBuffer->Material.Shininess = material->Shininess;
366 
367 		core::stringc TexturePath(material->Texture);
368 		if (TexturePath.trim()!="")
369 		{
370 			TexturePath=stripPathFromString(file->getFileName(),true) + stripPathFromString(TexturePath,false);
371 			tmpBuffer->Material.setTexture(0, Driver->getTexture(TexturePath));
372 		}
373 
374 		core::stringc AlphamapPath=(const c8*)material->Alphamap;
375 		if (AlphamapPath.trim()!="")
376 		{
377 			AlphamapPath=stripPathFromString(file->getFileName(),true) + stripPathFromString(AlphamapPath,false);
378 			tmpBuffer->Material.setTexture(2, Driver->getTexture(AlphamapPath));
379 		}
380 	}
381 
382 	// animation time
383 	f32 framesPerSecond = *(float*)pPtr;
384 #ifdef __BIG_ENDIAN__
385 	framesPerSecond = os::Byteswap::byteswap(framesPerSecond);
386 #endif
387 #ifdef _IRR_DEBUG_MS3D_LOADER_
388 	os::Printer::log("FPS", core::stringc(framesPerSecond).c_str());
389 #endif
390 	pPtr += sizeof(float) * 2; // fps and current time
391 
392 	if (framesPerSecond<1.f)
393 		framesPerSecond=1.f;
394 	AnimatedMesh->setAnimationSpeed(framesPerSecond);
395 
396 // ignore, calculated inside SkinnedMesh
397 //	s32 frameCount = *(int*)pPtr;
398 #ifdef __BIG_ENDIAN__
399 //	frameCount = os::Byteswap::byteswap(frameCount);
400 #endif
401 	pPtr += sizeof(int);
402 
403 	u16 jointCount = *(u16*)pPtr;
404 #ifdef __BIG_ENDIAN__
405 	jointCount = os::Byteswap::byteswap(jointCount);
406 #endif
407 #ifdef _IRR_DEBUG_MS3D_LOADER_
408 	os::Printer::log("Joints", core::stringc(jointCount).c_str());
409 #endif
410 	pPtr += sizeof(u16);
411 	if (pPtr > buffer+fileSize)
412 	{
413 		delete [] buffer;
414 		os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR);
415 		return false;
416 	}
417 
418 	core::array<core::stringc> parentNames;
419 	parentNames.reallocate(jointCount);
420 
421 	// load joints
422 	for (i=0; i<jointCount; ++i)
423 	{
424 		u32 j;
425 		MS3DJoint *pJoint = (MS3DJoint*)pPtr;
426 #ifdef __BIG_ENDIAN__
427 		for (j=0; j<3; ++j)
428 			pJoint->Rotation[j] = os::Byteswap::byteswap(pJoint->Rotation[j]);
429 		for (j=0; j<3; ++j)
430 			pJoint->Translation[j] = os::Byteswap::byteswap(pJoint->Translation[j]);
431 		pJoint->NumRotationKeyframes= os::Byteswap::byteswap(pJoint->NumRotationKeyframes);
432 		pJoint->NumTranslationKeyframes = os::Byteswap::byteswap(pJoint->NumTranslationKeyframes);
433 #endif
434 		pPtr += sizeof(MS3DJoint);
435 		if (pPtr > buffer+fileSize)
436 		{
437 			delete [] buffer;
438 			os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR);
439 			return false;
440 		}
441 
442 		ISkinnedMesh::SJoint *jnt = AnimatedMesh->addJoint();
443 
444 		jnt->Name = pJoint->Name;
445 #ifdef _IRR_DEBUG_MS3D_LOADER_
446 		os::Printer::log("Joint", jnt->Name.c_str());
447 		os::Printer::log("Rotation keyframes", core::stringc(pJoint->NumRotationKeyframes).c_str());
448 		os::Printer::log("Translation keyframes", core::stringc(pJoint->NumTranslationKeyframes).c_str());
449 #endif
450 		jnt->LocalMatrix.makeIdentity();
451 		jnt->LocalMatrix.setRotationRadians(
452 			core::vector3df(pJoint->Rotation[0], pJoint->Rotation[1], pJoint->Rotation[2]) );
453 		// convert right-handed to left-handed
454 		jnt->LocalMatrix[2]=-jnt->LocalMatrix[2];
455 		jnt->LocalMatrix[6]=-jnt->LocalMatrix[6];
456 		jnt->LocalMatrix[8]=-jnt->LocalMatrix[8];
457 		jnt->LocalMatrix[9]=-jnt->LocalMatrix[9];
458 
459 		jnt->LocalMatrix.setTranslation(
460 			core::vector3df(pJoint->Translation[0], pJoint->Translation[1], -pJoint->Translation[2]) );
461 		jnt->Animatedposition.set(jnt->LocalMatrix.getTranslation());
462 		jnt->Animatedrotation.set(jnt->LocalMatrix.getRotationDegrees());
463 
464 		parentNames.push_back( (c8*)pJoint->ParentName );
465 
466 		/*if (pJoint->NumRotationKeyframes ||
467 			pJoint->NumTranslationKeyframes)
468 			HasAnimation = true;
469 		 */
470 
471 		// get rotation keyframes
472 		const u16 numRotationKeyframes = pJoint->NumRotationKeyframes;
473 		for (j=0; j < numRotationKeyframes; ++j)
474 		{
475 			MS3DKeyframe* kf = (MS3DKeyframe*)pPtr;
476 #ifdef __BIG_ENDIAN__
477 			kf->Time = os::Byteswap::byteswap(kf->Time);
478 			for (u32 l=0; l<3; ++l)
479 				kf->Parameter[l] = os::Byteswap::byteswap(kf->Parameter[l]);
480 #endif
481 			pPtr += sizeof(MS3DKeyframe);
482 			if (pPtr > buffer+fileSize)
483 			{
484 				delete [] buffer;
485 				os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR);
486 				return false;
487 			}
488 
489 			ISkinnedMesh::SRotationKey *k=AnimatedMesh->addRotationKey(jnt);
490 			k->frame = kf->Time * framesPerSecond-1;
491 
492 			core::matrix4 tmpMatrix;
493 
494 			tmpMatrix.setRotationRadians(
495 				core::vector3df(kf->Parameter[0], kf->Parameter[1], kf->Parameter[2]) );
496 			// convert right-handed to left-handed
497 			tmpMatrix[2]=-tmpMatrix[2];
498 			tmpMatrix[6]=-tmpMatrix[6];
499 			tmpMatrix[8]=-tmpMatrix[8];
500 			tmpMatrix[9]=-tmpMatrix[9];
501 
502 			tmpMatrix=jnt->LocalMatrix*tmpMatrix;
503 
504 			// IRR_TEST_BROKEN_QUATERNION_USE: TODO - switched from tmpMatrix to tmpMatrix.getTransposed() for downward compatibility.
505 			//								   Not tested so far if this was correct or wrong before quaternion fix!
506 			k->rotation  = core::quaternion(tmpMatrix.getTransposed());
507 		}
508 
509 		// get translation keyframes
510 		const u16 numTranslationKeyframes = pJoint->NumTranslationKeyframes;
511 		for (j=0; j<numTranslationKeyframes; ++j)
512 		{
513 			MS3DKeyframe* kf = (MS3DKeyframe*)pPtr;
514 #ifdef __BIG_ENDIAN__
515 			kf->Time = os::Byteswap::byteswap(kf->Time);
516 			for (u32 l=0; l<3; ++l)
517 				kf->Parameter[l] = os::Byteswap::byteswap(kf->Parameter[l]);
518 #endif
519 			pPtr += sizeof(MS3DKeyframe);
520 			if (pPtr > buffer+fileSize)
521 			{
522 				delete [] buffer;
523 				os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR);
524 				return false;
525 			}
526 
527 			ISkinnedMesh::SPositionKey *k=AnimatedMesh->addPositionKey(jnt);
528 			k->frame = kf->Time * framesPerSecond-1;
529 
530 			k->position = core::vector3df
531 				(kf->Parameter[0]+pJoint->Translation[0],
532 				 kf->Parameter[1]+pJoint->Translation[1],
533 				 -kf->Parameter[2]-pJoint->Translation[2]);
534 		}
535 	}
536 
537 	core::array<MS3DVertexWeights> vertexWeights;
538 	f32 weightFactor=0;
539 
540 	if (jointCount && (pHeader->Version == 4) && (pPtr < buffer+fileSize))
541 	{
542 		s32 subVersion = *(s32*)pPtr; // comment subVersion, always 1
543 #ifdef __BIG_ENDIAN__
544 		subVersion = os::Byteswap::byteswap(subVersion);
545 #endif
546 		pPtr += sizeof(s32);
547 
548 		for (u32 j=0; j<4; ++j) // four comment groups
549 		{
550 #ifdef _IRR_DEBUG_MS3D_LOADER_
551 			os::Printer::log("Skipping comment group", core::stringc(j+1).c_str());
552 #endif
553 			u32 numComments = *(u32*)pPtr;
554 #ifdef __BIG_ENDIAN__
555 			numComments = os::Byteswap::byteswap(numComments);
556 #endif
557 			pPtr += sizeof(u32);
558 			for (i=0; i<numComments; ++i)
559 			{
560 				// according to scorpiomidget this field does
561 				// not exist for model comments. So avoid to
562 				// read it
563 				if (j!=3)
564 					pPtr += sizeof(s32); // index
565 				s32 commentLength = *(s32*)pPtr;
566 #ifdef __BIG_ENDIAN__
567 				commentLength = os::Byteswap::byteswap(commentLength);
568 #endif
569 				pPtr += sizeof(s32);
570 				pPtr += commentLength;
571 			}
572 
573 			if (pPtr > buffer+fileSize)
574 			{
575 				delete [] buffer;
576 				os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR);
577 				return false;
578 			}
579 		}
580 
581 		if (pPtr < buffer+fileSize)
582 		{
583 			subVersion = *(s32*)pPtr; // vertex subVersion, 1 or 2
584 #ifdef __BIG_ENDIAN__
585 			subVersion = os::Byteswap::byteswap(subVersion);
586 #endif
587 			if (subVersion==1)
588 				weightFactor=1.f/255.f;
589 			else
590 				weightFactor=1.f/100.f;
591 			pPtr += sizeof(s32);
592 
593 #ifdef _IRR_DEBUG_MS3D_LOADER_
594 			os::Printer::log("Reading vertex weights");
595 #endif
596 			// read vertex weights, ignoring data 'extra' from 1.8.2
597 			vertexWeights.reallocate(numVertices);
598 			const char offset = (subVersion==1)?6:10;
599 			for (i=0; i<numVertices; ++i)
600 			{
601 				vertexWeights.push_back(*(MS3DVertexWeights*)pPtr);
602 				pPtr += offset;
603 			}
604 
605 			if (pPtr > buffer+fileSize)
606 			{
607 				delete [] buffer;
608 				os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR);
609 				return false;
610 			}
611 		}
612 
613 		if (pPtr < buffer+fileSize)
614 		{
615 			subVersion = *(s32*)pPtr; // joint subVersion, 1 or 2
616 #ifdef __BIG_ENDIAN__
617 			subVersion = os::Byteswap::byteswap(subVersion);
618 #endif
619 			pPtr += sizeof(s32);
620 			// skip joint colors
621 #ifdef _IRR_DEBUG_MS3D_LOADER_
622 			os::Printer::log("Skip joint color");
623 #endif
624 			pPtr += 3*sizeof(float)*jointCount;
625 
626 			if (pPtr > buffer+fileSize)
627 			{
628 				delete [] buffer;
629 				os::Printer::log("Loading failed. Corrupted data found", file->getFileName(), ELL_ERROR);
630 				return false;
631 			}
632 		}
633 
634 		if (pPtr < buffer+fileSize)
635 		{
636 			subVersion = *(s32*)pPtr; // model subVersion, 1 or 2
637 #ifdef __BIG_ENDIAN__
638 			subVersion = os::Byteswap::byteswap(subVersion);
639 #endif
640 			pPtr += sizeof(s32);
641 #ifdef _IRR_DEBUG_MS3D_LOADER_
642 			os::Printer::log("Skip model extra information");
643 #endif
644 			// now the model extra information would follow
645 			// we also skip this for now
646 		}
647 	}
648 
649 	//find parent of every joint
650 	for (u32 jointnum=0; jointnum<AnimatedMesh->getAllJoints().size(); ++jointnum)
651 	{
652 		for (u32 j2=0; j2<AnimatedMesh->getAllJoints().size(); ++j2)
653 		{
654 			if (jointnum != j2 && parentNames[jointnum] == AnimatedMesh->getAllJoints()[j2]->Name )
655 			{
656 				AnimatedMesh->getAllJoints()[j2]->Children.push_back(AnimatedMesh->getAllJoints()[jointnum]);
657 				break;
658 			}
659 		}
660 	}
661 
662 	// create vertices and indices, attach them to the joints.
663 	video::S3DVertex v;
664 	core::array<video::S3DVertex> *Vertices;
665 	core::array<u16> Indices;
666 
667 	for (i=0; i<numTriangles; ++i)
668 	{
669 		u32 tmp = groups[triangles[i].GroupIndex].MaterialIdx;
670 		Vertices = &AnimatedMesh->getMeshBuffers()[tmp]->Vertices_Standard;
671 
672 		for (s32 j = 2; j!=-1; --j)
673 		{
674 			const u32 vertidx = triangles[i].VertexIndices[j];
675 
676 			v.TCoords.X = triangles[i].S[j];
677 			v.TCoords.Y = triangles[i].T[j];
678 
679 			v.Normal.X = triangles[i].VertexNormals[j][0];
680 			v.Normal.Y = triangles[i].VertexNormals[j][1];
681 			v.Normal.Z = triangles[i].VertexNormals[j][2];
682 
683 			if(triangles[i].GroupIndex < groups.size() &&
684 					groups[triangles[i].GroupIndex].MaterialIdx < AnimatedMesh->getMeshBuffers().size())
685 				v.Color = AnimatedMesh->getMeshBuffers()[groups[triangles[i].GroupIndex].MaterialIdx]->Material.DiffuseColor;
686 			else
687 				v.Color.set(255,255,255,255);
688 
689 			v.Pos.X = vertices[vertidx].Vertex[0];
690 			v.Pos.Y = vertices[vertidx].Vertex[1];
691 			v.Pos.Z = vertices[vertidx].Vertex[2];
692 
693 			// check if we already have this vertex in our vertex array
694 			s32 index = -1;
695 			for (u32 iV = 0; iV < Vertices->size(); ++iV)
696 			{
697 				if (v == (*Vertices)[iV])
698 				{
699 					index = (s32)iV;
700 					break;
701 				}
702 			}
703 
704 			if (index == -1)
705 			{
706 				index = Vertices->size();
707 				const u32 matidx = groups[triangles[i].GroupIndex].MaterialIdx;
708 				if (vertexWeights.size()==0)
709 				{
710 					const s32 boneid = vertices[vertidx].BoneID;
711 					if ((u32)boneid < AnimatedMesh->getAllJoints().size())
712 					{
713 						ISkinnedMesh::SWeight *w=AnimatedMesh->addWeight(AnimatedMesh->getAllJoints()[boneid]);
714 						w->buffer_id = matidx;
715 						w->strength = 1.0f;
716 						w->vertex_id = index;
717 					}
718 				}
719 				else if (jointCount) // new weights from 1.8.x
720 				{
721 					f32 sum = 1.0f;
722 					s32 boneid = vertices[vertidx].BoneID;
723 					if (((u32)boneid < AnimatedMesh->getAllJoints().size()) && (vertexWeights[vertidx].weights[0] != 0))
724 					{
725 						ISkinnedMesh::SWeight *w=AnimatedMesh->addWeight(AnimatedMesh->getAllJoints()[boneid]);
726 						w->buffer_id = matidx;
727 						sum -= (w->strength = vertexWeights[vertidx].weights[0]*weightFactor);
728 						w->vertex_id = index;
729 					}
730 					boneid = vertexWeights[vertidx].boneIds[0];
731 					if (((u32)boneid < AnimatedMesh->getAllJoints().size()) && (vertexWeights[vertidx].weights[1] != 0))
732 					{
733 						ISkinnedMesh::SWeight *w=AnimatedMesh->addWeight(AnimatedMesh->getAllJoints()[boneid]);
734 						w->buffer_id = matidx;
735 						sum -= (w->strength = vertexWeights[vertidx].weights[1]*weightFactor);
736 						w->vertex_id = index;
737 					}
738 					boneid = vertexWeights[vertidx].boneIds[1];
739 					if (((u32)boneid < AnimatedMesh->getAllJoints().size()) && (vertexWeights[vertidx].weights[2] != 0))
740 					{
741 						ISkinnedMesh::SWeight *w=AnimatedMesh->addWeight(AnimatedMesh->getAllJoints()[boneid]);
742 						w->buffer_id = matidx;
743 						sum -= (w->strength = vertexWeights[vertidx].weights[2]*weightFactor);
744 						w->vertex_id = index;
745 					}
746 					boneid = vertexWeights[vertidx].boneIds[2];
747 					if (((u32)boneid < AnimatedMesh->getAllJoints().size()) && (sum > 0.f))
748 					{
749 						ISkinnedMesh::SWeight *w=AnimatedMesh->addWeight(AnimatedMesh->getAllJoints()[boneid]);
750 						w->buffer_id = matidx;
751 						w->strength = sum;
752 						w->vertex_id = index;
753 					}
754 					// fallback, if no bone chosen. Seems to be an error in the specs
755 					boneid = vertices[vertidx].BoneID;
756 					if ((sum == 1.f) && ((u32)boneid < AnimatedMesh->getAllJoints().size()))
757 					{
758 						ISkinnedMesh::SWeight *w=AnimatedMesh->addWeight(AnimatedMesh->getAllJoints()[boneid]);
759 						w->buffer_id = matidx;
760 						w->strength = 1.f;
761 						w->vertex_id = index;
762 					}
763 				}
764 
765 				Vertices->push_back(v);
766 			}
767 			Indices.push_back(index);
768 		}
769 	}
770 
771 	//create groups
772 	s32 iIndex = -1;
773 	for (i=0; i<groups.size(); ++i)
774 	{
775 		SGroup& grp = groups[i];
776 
777 		if (grp.MaterialIdx >= AnimatedMesh->getMeshBuffers().size())
778 			grp.MaterialIdx = 0;
779 
780 		core::array<u16>& indices = AnimatedMesh->getMeshBuffers()[grp.MaterialIdx]->Indices;
781 
782 		for (u32 k=0; k < grp.VertexIds.size(); ++k)
783 			for (u32 l=0; l<3; ++l)
784 				indices.push_back(Indices[++iIndex]);
785 	}
786 
787 	delete [] buffer;
788 
789 	return true;
790 }
791 
792 
stripPathFromString(const core::stringc & inString,bool returnPath) const793 core::stringc CMS3DMeshFileLoader::stripPathFromString(const core::stringc& inString, bool returnPath) const
794 {
795 	s32 slashIndex=inString.findLast('/'); // forward slash
796 	s32 backSlash=inString.findLast('\\'); // back slash
797 
798 	if (backSlash>slashIndex) slashIndex=backSlash;
799 
800 	if (slashIndex==-1)//no slashes found
801 	{
802 		if (returnPath)
803 			return core::stringc(); //no path to return
804 		else
805 			return inString;
806 	}
807 
808 	if (returnPath)
809 		return inString.subString(0, slashIndex + 1);
810 	else
811 		return inString.subString(slashIndex+1, inString.size() - (slashIndex+1));
812 }
813 
814 
815 } // end namespace scene
816 } // end namespace irr
817 
818 #endif
819