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 // This file was originally written by ZDimitor.
6 
7 //-----------------------------------------------------------------------------
8 // This tool created by ZDimitor everyone can use it as wants
9 //-----------------------------------------------------------------------------
10 
11 #include "IrrCompileConfig.h"
12 #ifdef _IRR_COMPILE_WITH_MY3D_LOADER_
13 
14 #include "CMY3DMeshFileLoader.h"
15 
16 #include "SAnimatedMesh.h"
17 #include "SMeshBuffer.h"
18 #include "IReadFile.h"
19 #include "IAttributes.h"
20 
21 #include "CMY3DHelper.h"
22 #include "os.h"
23 
24 // v3.15 - May 16, 2005
25 
26 namespace irr
27 {
28 namespace scene
29 {
30 
31 static const u32 MY3D_ID = 0x4d593344;
32 static const u16 MY3D_VER = 0x0003;
33 static const u16 MY3D_SCENE_HEADER_ID = 0x1000;
34 static const u16 MY3D_MAT_LIST_ID = 0x2000;
35 static const u16 MY3D_MAT_HEADER_ID = 0x2100;
36 static const u16 MY3D_TEX_FNAME_ID = 0x2101;
37 static const u16 MY3D_TEXDATA_HEADER_ID = 0x2501;
38 static const u16 MY3D_TEXDATA_RLE_HEADER_ID = 0x2502;
39 static const u16 MY3D_MESH_LIST_ID =  0x3000;
40 static const u16 MY3D_MESH_HEADER_ID = 0x3100;
41 static const u16 MY3D_VERTS_ID = 0x3101;
42 static const u16 MY3D_FACES_ID = 0x3102;
43 static const u16 MY3D_TVERTS_ID = 0x3103;
44 static const u16 MY3D_TFACES_ID = 0x3104;
45 static const u16 MY3D_FILE_END_ID = 0xFFFF;
46 
47 static const unsigned long MY3D_TEXDATA_COMPR_NONE_ID = 0x4e4f4e45;
48 static const unsigned long MY3D_TEXDATA_COMPR_SIMPLE_ID = 0x53494d50;
49 static const unsigned long MY3D_TEXDATA_COMPR_RLE_ID = 0x20524c45;
50 
51 static const unsigned long MY3D_PIXEL_FORMAT_24 = 0x5f32345f;
52 static const unsigned long MY3D_PIXEL_FORMAT_16 = 0x5f31365f;
53 
CMY3DMeshFileLoader(ISceneManager * scmgr,io::IFileSystem * fs)54 CMY3DMeshFileLoader::CMY3DMeshFileLoader(ISceneManager* scmgr, io::IFileSystem* fs)
55 	: SceneManager(scmgr), FileSystem(fs)
56 {
57 	#ifdef _DEBUG
58 	setDebugName("CMY3DMeshFileLoader");
59 	#endif
60 
61 	if (FileSystem)
62 		FileSystem->grab();
63 }
64 
65 
~CMY3DMeshFileLoader()66 CMY3DMeshFileLoader::~CMY3DMeshFileLoader()
67 {
68 	if (FileSystem)
69 		FileSystem->drop();
70 }
71 
72 
isALoadableFileExtension(const io::path & filename) const73 bool CMY3DMeshFileLoader::isALoadableFileExtension(const io::path& filename) const
74 {
75 	return core::hasFileExtension ( filename, "my3d" );
76 }
77 
78 
createMesh(io::IReadFile * file)79 IAnimatedMesh* CMY3DMeshFileLoader::createMesh(io::IReadFile* file)
80 {
81 	MaterialEntry.clear();
82 	MeshBufferEntry.clear();
83 	ChildNodes.clear();
84 
85 	// working directory (from which we load the scene)
86 	core::stringc filepath = FileSystem->getFileDir(file->getFileName());
87 	if (filepath==".")
88 		filepath="";
89 	else
90 		filepath.append("/");
91 
92 	// read file into memory
93 	SMyFileHeader fileHeader;
94 	file->read(&fileHeader, sizeof(SMyFileHeader));
95 #ifdef __BIG_ENDIAN__
96 	fileHeader.MyId = os::Byteswap::byteswap(fileHeader.MyId);
97 	fileHeader.Ver = os::Byteswap::byteswap(fileHeader.Ver);
98 #endif
99 
100 	if (fileHeader.MyId!=MY3D_ID || fileHeader.Ver!=MY3D_VER)
101 	{
102 		os::Printer::log("Bad MY3D file header, loading failed!", ELL_ERROR);
103 		return 0;
104 	}
105 
106 	u16 id;
107 
108 	file->read(&id, sizeof(id));
109 #ifdef __BIG_ENDIAN__
110 	id = os::Byteswap::byteswap(id);
111 #endif
112 
113 	if (id!=MY3D_SCENE_HEADER_ID)
114 	{
115 		os::Printer::log("Cannot find MY3D_SCENE_HEADER_ID, loading failed!", ELL_ERROR);
116 		return 0;
117 	}
118 
119 	SMySceneHeader sceneHeader;
120 	file->read(&sceneHeader, sizeof(SMySceneHeader));
121 #ifdef __BIG_ENDIAN__
122 	sceneHeader.MaterialCount = os::Byteswap::byteswap(sceneHeader.MaterialCount);
123 	sceneHeader.MeshCount = os::Byteswap::byteswap(sceneHeader.MeshCount);
124 #endif
125 
126 	file->read(&id, sizeof(id));
127 #ifdef __BIG_ENDIAN__
128 	id = os::Byteswap::byteswap(id);
129 #endif
130 
131 	if (id!=MY3D_MAT_LIST_ID)
132 	{
133 		os::Printer::log("Can not find MY3D_MAT_LIST_ID, loading failed!", ELL_ERROR);
134 		return 0;
135 	}
136 
137 	core::stringc texturePath =
138 		SceneManager->getParameters()->getAttributeAsString(MY3D_TEXTURE_PATH);
139 
140 	file->read(&id, sizeof(id));
141 #ifdef __BIG_ENDIAN__
142 	id = os::Byteswap::byteswap(id);
143 #endif
144 
145 	c8 namebuf[256];
146 	for (s32 m=0; m<sceneHeader.MaterialCount; ++m)
147 	{
148 		if (id != MY3D_MAT_HEADER_ID)
149 		{
150 			os::Printer::log("Cannot find MY3D_MAT_HEADER_ID, loading failed!", ELL_ERROR);
151 			return 0;
152 		}
153 
154 		// read material header
155 		MaterialEntry.push_back(SMyMaterialEntry());
156 		SMyMaterialEntry& me=MaterialEntry.getLast();
157 		file->read(&(me.Header), sizeof(SMyMaterialHeader));
158 
159 		// read next identificator
160 		file->read(&id, sizeof(id));
161 #ifdef __BIG_ENDIAN__
162 		id = os::Byteswap::byteswap(id);
163 #endif
164 
165 		bool gotLightMap=false, gotMainMap=false;
166 
167 		for (u32 t=0; t<me.Header.TextureCount; ++t)
168 		{
169 			if (id==MY3D_TEX_FNAME_ID)
170 				file->read(namebuf, 256);
171 			else
172 			{
173 				me.Texture2 = readEmbeddedLightmap(file, namebuf);
174 				if (!me.Texture2)
175 					return 0;
176 				gotLightMap = true;
177 			}
178 
179 			const core::stringc name(namebuf);
180 			const s32 pos = name.findLast('.');
181 			const core::stringc LightingMapStr = "LightingMap";
182 			const s32 ls = LightingMapStr.size();
183 			const bool isSubString = (LightingMapStr == name.subString(core::max_(0, (pos - ls)), ls));
184 			if ((isSubString || (name[pos-1]=='m' &&
185 				name[pos-2]=='l' && name[pos-3]=='_')) &&
186 				!gotLightMap)
187 			{
188 				const bool oldMipMapState = SceneManager->getVideoDriver()->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS);
189 				SceneManager->getVideoDriver()->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false);
190 
191 				me.Texture2FileName = texturePath.size() ? texturePath : filepath;
192 				me.Texture2FileName.append("Lightmaps/");
193 				me.Texture2FileName.append(name);
194 
195 				if (name.size())
196 					me.Texture2 = SceneManager->getVideoDriver()->getTexture(me.Texture2FileName);
197 
198 				me.MaterialType = video::EMT_LIGHTMAP_M2;
199 				gotLightMap = true;
200 
201 				SceneManager->getVideoDriver()->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, oldMipMapState);
202 			}
203 			else
204 			if (!gotLightMap && gotMainMap)
205 			{
206 				me.Texture2FileName = texturePath.size() ? texturePath : filepath;
207 				me.Texture2FileName.append(name);
208 
209 				if (name.size())
210 					me.Texture2 = SceneManager->getVideoDriver()->getTexture(me.Texture2FileName);
211 
212 				me.MaterialType = video::EMT_REFLECTION_2_LAYER;
213 			}
214 			else
215 			if (!gotMainMap && !gotLightMap)
216 			{
217 				me.Texture1FileName = filepath;
218 				me.Texture1FileName.append(name);
219 				if (name.size())
220 					me.Texture1 = SceneManager->getVideoDriver()->getTexture(me.Texture1FileName);
221 
222 				gotMainMap = true;
223 				me.MaterialType = video::EMT_SOLID;
224 			}
225 			else
226 			if (gotLightMap)
227 			{
228 				me.MaterialType = video::EMT_LIGHTMAP_M2;
229 			}
230 
231 			file->read(&id, sizeof(id));
232 #ifdef __BIG_ENDIAN__
233 			id = os::Byteswap::byteswap(id);
234 #endif
235 		}
236 
237 		// override material types based on their names
238 		if (!strncmp(me.Header.Name, "AlphaChannel-", 13))
239 			me.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
240 		else
241 		if (!strncmp(me.Header.Name, "SphereMap-", 10))
242 			me.MaterialType = video::EMT_SPHERE_MAP;
243 	}
244 
245 	// loading meshes
246 
247 	if (id!=MY3D_MESH_LIST_ID)
248 	{
249 		os::Printer::log("Can not find MY3D_MESH_LIST_ID, loading failed!", ELL_ERROR);
250 		return 0;
251 	}
252 
253 	file->read(&id, sizeof(id));
254 #ifdef __BIG_ENDIAN__
255 	id = os::Byteswap::byteswap(id);
256 #endif
257 
258 	for (s32 mesh_id=0; mesh_id<sceneHeader.MeshCount; mesh_id++)
259 	{
260 		// Warning!!! In some cases MY3D exporter uncorrectly calculates
261 		// MeshCount (it's a problem, has to be solved) thats why
262 		// i added this code line
263 		if (id!=MY3D_MESH_HEADER_ID)
264 			break;
265 
266 		if (id!=MY3D_MESH_HEADER_ID)
267 		{
268 			os::Printer::log("Can not find MY3D_MESH_HEADER_ID, loading failed!", ELL_ERROR);
269 			return 0;
270 		}
271 
272 		SMyMeshHeader meshHeader;
273 		file->read(&meshHeader, sizeof(SMyMeshHeader));
274 
275 		core::array <SMyVertex> Vertex;
276 		core::array <SMyFace> Face;
277 		core::array <SMyTVertex> TVertex1, TVertex2;
278 		core::array <SMyFace> TFace1, TFace2;
279 
280 		s32 vertsNum=0;
281 		s32 facesNum=0;
282 
283 		// vertices
284 		file->read(&id, sizeof(id));
285 #ifdef __BIG_ENDIAN__
286 	id = os::Byteswap::byteswap(id);
287 #endif
288 		if (id!=MY3D_VERTS_ID)
289 		{
290 			os::Printer::log("Can not find MY3D_VERTS_ID, loading failed!", ELL_ERROR);
291 			return 0;
292 		}
293 
294 		file->read(&vertsNum, sizeof(vertsNum));
295 		Vertex.set_used(vertsNum);
296 		file->read(Vertex.pointer(), sizeof(SMyVertex)*vertsNum);
297 
298 		// faces
299 		file->read(&id, sizeof(id));
300 #ifdef __BIG_ENDIAN__
301 		id = os::Byteswap::byteswap(id);
302 #endif
303 		if (id!=MY3D_FACES_ID)
304 		{
305 			os::Printer::log("Can not find MY3D_FACES_ID, loading failed!", ELL_ERROR);
306 			return 0;
307 		}
308 
309 		file->read(&facesNum, sizeof(facesNum));
310 		Face.set_used(facesNum);
311 		file->read(Face.pointer(), sizeof(SMyFace)*facesNum);
312 
313 		// reading texture channels
314 		for (s32 tex=0; tex<(s32)meshHeader.TChannelCnt; tex++)
315 		{
316 			// Max 2 texture channels allowed (but in format .my3d can be more)
317 			s32 tVertsNum=0, tFacesNum=0;
318 
319 			// reading texture coords
320 			file->read(&id, sizeof(id));
321 #ifdef __BIG_ENDIAN__
322 			id = os::Byteswap::byteswap(id);
323 #endif
324 
325 			if (id!=MY3D_TVERTS_ID)
326 			{
327 				core::stringc msg="Can not find MY3D_TVERTS_ID (";
328 				msg.append(core::stringc(tex));
329 				msg.append("texture channel), loading failed!");
330 				os::Printer::log(msg.c_str(), ELL_ERROR);
331 				return 0;
332 			}
333 
334 			file->read(&tVertsNum, sizeof(tVertsNum));
335 
336 			if (tex==0)
337 			{
338 				// 1st texture channel
339 				TVertex1.set_used(tVertsNum);
340 				file->read(TVertex1.pointer(), sizeof(SMyTVertex)*tVertsNum);
341 			}
342 			else
343 			if (tex==1)
344 			{
345 				// 2nd texture channel
346 				TVertex2.set_used(tVertsNum);
347 				file->read(TVertex2.pointer(), sizeof(SMyTVertex)*tVertsNum);
348 			}
349 			else
350 			{
351 				// skip other texture channels
352 				file->seek(file->getPos()+sizeof(SMyTVertex)*tVertsNum);
353 			}
354 
355 			// reading texture faces
356 			file->read(&id, sizeof(id));
357 #ifdef __BIG_ENDIAN__
358 			id = os::Byteswap::byteswap(id);
359 #endif
360 
361 			if (id!=MY3D_TFACES_ID)
362 			{
363 				core::stringc msg="Can not find MY3D_TFACES_ID (";
364 				msg.append(core::stringc(tex));
365 				msg.append("texture channel), loading failed!");
366 				os::Printer::log(msg.c_str(), ELL_ERROR);
367 				return 0;
368 			}
369 
370 			file->read(&tFacesNum, sizeof(tFacesNum));
371 
372 			if (tex==0)
373 			{
374 				// 1st texture channel
375 				TFace1.set_used(tFacesNum);
376 				file->read(TFace1.pointer(), sizeof(SMyFace)*tFacesNum);
377 			}
378 			else if (tex==1)
379 			{
380 				// 2nd texture channel
381 				TFace2.set_used(tFacesNum);
382 				file->read(TFace2.pointer(), sizeof(SMyFace)*tFacesNum);
383 			}
384 			else
385 			{
386 				// skip other texture channels
387 				file->seek(file->getPos()+sizeof(SMyFace)*tFacesNum);
388 			}
389 		}
390 
391 		// trying to find material
392 
393 		SMyMaterialEntry* matEnt = getMaterialEntryByIndex(meshHeader.MatIndex);
394 
395 		// creating geometry for the mesh
396 
397 		// trying to find mesh buffer for this material
398 		SMeshBufferLightMap* buffer = getMeshBufferByMaterialIndex(meshHeader.MatIndex);
399 
400 		if (!buffer ||
401 			(buffer->Vertices.size()+vertsNum) > SceneManager->getVideoDriver()->getMaximalPrimitiveCount())
402 		{
403 			// creating new mesh buffer for this material
404 			buffer = new scene::SMeshBufferLightMap();
405 
406 			buffer->Material.MaterialType = video::EMT_LIGHTMAP_M2; // EMT_LIGHTMAP_M4 also possible
407 			buffer->Material.Wireframe = false;
408 			buffer->Material.Lighting = false;
409 
410 			if (matEnt)
411 			{
412 				buffer->Material.MaterialType = matEnt->MaterialType;
413 
414 				if (buffer->Material.MaterialType == video::EMT_REFLECTION_2_LAYER)
415 				{
416 					buffer->Material.Lighting = true;
417 					buffer->Material.setTexture(1, matEnt->Texture1);
418 					buffer->Material.setTexture(0, matEnt->Texture2);
419 				}
420 				else
421 				{
422 					buffer->Material.setTexture(0, matEnt->Texture1);
423 					buffer->Material.setTexture(1, matEnt->Texture2);
424 				}
425 
426 				if (buffer->Material.MaterialType == video::EMT_TRANSPARENT_ALPHA_CHANNEL)
427 				{
428 					buffer->Material.BackfaceCulling = true;
429 					buffer->Material.Lighting  = true;
430 				}
431 				else
432 				if (buffer->Material.MaterialType == video::EMT_SPHERE_MAP)
433 				{
434 					buffer->Material.Lighting  = true;
435 				}
436 
437 				buffer->Material.AmbientColor = video::SColor(
438 					matEnt->Header.AmbientColor.A, matEnt->Header.AmbientColor.R,
439 					matEnt->Header.AmbientColor.G, matEnt->Header.AmbientColor.B
440 					);
441 				buffer->Material.DiffuseColor =	video::SColor(
442 					matEnt->Header.DiffuseColor.A, matEnt->Header.DiffuseColor.R,
443 					matEnt->Header.DiffuseColor.G, matEnt->Header.DiffuseColor.B
444 					);
445 				buffer->Material.EmissiveColor = video::SColor(
446 					matEnt->Header.EmissiveColor.A, matEnt->Header.EmissiveColor.R,
447 					matEnt->Header.EmissiveColor.G, matEnt->Header.EmissiveColor.B
448 					);
449 				buffer->Material.SpecularColor = video::SColor(
450 					matEnt->Header.SpecularColor.A, matEnt->Header.SpecularColor.R,
451 					matEnt->Header.SpecularColor.G, matEnt->Header.SpecularColor.B
452 					);
453 			}
454 			else
455 			{
456 				buffer->Material.setTexture(0, 0);
457 				buffer->Material.setTexture(1, 0);
458 
459 				buffer->Material.AmbientColor = video::SColor(255, 255, 255, 255);
460 				buffer->Material.DiffuseColor =	video::SColor(255, 255, 255, 255);
461 				buffer->Material.EmissiveColor = video::SColor(0, 0, 0, 0);
462 				buffer->Material.SpecularColor = video::SColor(0, 0, 0, 0);
463 			}
464 
465 			if (matEnt && matEnt->Header.Transparency!=0)
466 			{
467 				if (buffer->Material.MaterialType == video::EMT_REFLECTION_2_LAYER )
468 				{
469 					buffer->Material.MaterialType = video::EMT_TRANSPARENT_REFLECTION_2_LAYER;
470 					buffer->Material.Lighting  = true;
471 					buffer->Material.BackfaceCulling = true;
472 				}
473 				else
474 				{
475 					buffer->Material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
476 					buffer->Material.Lighting = false;
477 					buffer->Material.BackfaceCulling = false;
478 				}
479 			}
480 			else if (
481 				!buffer->Material.getTexture(1) &&
482 				buffer->Material.MaterialType != video::EMT_TRANSPARENT_ALPHA_CHANNEL &&
483 				buffer->Material.MaterialType != video::EMT_SPHERE_MAP)
484 			{
485 				buffer->Material.MaterialType = video::EMT_SOLID;
486 				buffer->Material.Lighting  = true;
487 			}
488 
489 			MeshBufferEntry.push_back(
490 			SMyMeshBufferEntry(meshHeader.MatIndex, buffer));
491 		}
492 
493 		video::S3DVertex2TCoords VertexA, VertexB, VertexC;
494 
495 		// vertices (A, B, C) color
496 		video::SColor vert_color;
497 		if (matEnt &&
498 			(buffer->Material.MaterialType == video::EMT_TRANSPARENT_VERTEX_ALPHA ||
499 			buffer->Material.MaterialType == video::EMT_TRANSPARENT_REFLECTION_2_LAYER))
500 		{
501 			video::SColor color(
502 			matEnt->Header.DiffuseColor.A, matEnt->Header.DiffuseColor.R,
503 			matEnt->Header.DiffuseColor.G, matEnt->Header.DiffuseColor.B);
504 
505 			vert_color = color.getInterpolated(video::SColor(0,0,0,0),
506 				1-matEnt->Header.Transparency);
507 		}
508 		else
509 		{
510 			vert_color = buffer->Material.DiffuseColor;
511 		}
512 
513 		VertexA.Color = VertexB.Color = VertexC.Color = vert_color;
514 
515 		if (buffer->Material.MaterialType == video::EMT_TRANSPARENT_ALPHA_CHANNEL)
516 		{
517 			buffer->Indices.reallocate(buffer->Indices.size()+6*facesNum);
518 			buffer->Vertices.reallocate(buffer->Vertices.size()+6*facesNum);
519 		}
520 		else
521 		{
522 			buffer->Indices.reallocate(buffer->Indices.size()+3*facesNum);
523 			buffer->Vertices.reallocate(buffer->Vertices.size()+3*facesNum);
524 		}
525 		for (int f=0; f<facesNum; f++)
526 		{
527 			// vertex A
528 
529 			VertexA.Pos.X = Vertex[Face[f].C].Coord.X;
530 			VertexA.Pos.Y = Vertex[Face[f].C].Coord.Y;
531 			VertexA.Pos.Z = Vertex[Face[f].C].Coord.Z;
532 
533 			VertexA.Normal.X = Vertex[Face[f].C].Normal.X;
534 			VertexA.Normal.Y = Vertex[Face[f].C].Normal.Y;
535 			VertexA.Normal.Z = Vertex[Face[f].C].Normal.Z;
536 
537 			if (meshHeader.TChannelCnt>0)
538 			{
539 				VertexA.TCoords.X  = TVertex1[TFace1[f].C].TCoord.X;
540 				VertexA.TCoords.Y  = TVertex1[TFace1[f].C].TCoord.Y;
541 			}
542 
543 			if (meshHeader.TChannelCnt>1)
544 			{
545 				VertexA.TCoords2.X = TVertex2[TFace2[f].C].TCoord.X;
546 				VertexA.TCoords2.Y = TVertex2[TFace2[f].C].TCoord.Y;
547 			}
548 
549 			// vertex B
550 
551 			VertexB.Pos.X = Vertex[Face[f].B].Coord.X;
552 			VertexB.Pos.Y = Vertex[Face[f].B].Coord.Y;
553 			VertexB.Pos.Z = Vertex[Face[f].B].Coord.Z;
554 
555 			VertexB.Normal.X = Vertex[Face[f].B].Normal.X;
556 			VertexB.Normal.Y = Vertex[Face[f].B].Normal.Y;
557 			VertexB.Normal.Z = Vertex[Face[f].B].Normal.Z;
558 
559 			if (meshHeader.TChannelCnt>0)
560 			{
561 				VertexB.TCoords.X  = TVertex1[TFace1[f].B].TCoord.X;
562 				VertexB.TCoords.Y  = TVertex1[TFace1[f].B].TCoord.Y;
563 			}
564 
565 			if (meshHeader.TChannelCnt>1)
566 			{
567 				VertexB.TCoords2.X = TVertex2[TFace2[f].B].TCoord.X;
568 				VertexB.TCoords2.Y = TVertex2[TFace2[f].B].TCoord.Y;
569 			}
570 
571 			// vertex C
572 
573 			VertexC.Pos.X = Vertex[Face[f].A].Coord.X;
574 			VertexC.Pos.Y = Vertex[Face[f].A].Coord.Y;
575 			VertexC.Pos.Z = Vertex[Face[f].A].Coord.Z;
576 
577 			VertexC.Normal.X = Vertex[Face[f].A].Normal.X;
578 			VertexC.Normal.Y = Vertex[Face[f].A].Normal.Y;
579 			VertexC.Normal.Z = Vertex[Face[f].A].Normal.Z;
580 
581 			if (meshHeader.TChannelCnt>0)
582 			{
583 				VertexC.TCoords.X  = TVertex1[TFace1[f].A].TCoord.X;
584 				VertexC.TCoords.Y  = TVertex1[TFace1[f].A].TCoord.Y;
585 			}
586 			if (meshHeader.TChannelCnt>1)
587 			{
588 				VertexC.TCoords2.X = TVertex2[TFace2[f].A].TCoord.X;
589 				VertexC.TCoords2.Y = TVertex2[TFace2[f].A].TCoord.Y;
590 			}
591 
592 			// store 3d data in mesh buffer
593 
594 			buffer->Indices.push_back(buffer->Vertices.size());
595 			buffer->Vertices.push_back(VertexA);
596 
597 			buffer->Indices.push_back(buffer->Vertices.size());
598 			buffer->Vertices.push_back(VertexB);
599 
600 			buffer->Indices.push_back(buffer->Vertices.size());
601 			buffer->Vertices.push_back(VertexC);
602 
603 			//*****************************************************************
604 			//          !!!!!! W A R N I N G !!!!!!!
605 			//*****************************************************************
606 			// For materials with alpha channel we duplicate all faces.
607 			// This has be done for proper lighting calculation of the back faces.
608 			// So you must remember this while you creating your models !!!!!
609 			//*****************************************************************
610 			//          !!!!!! W A R N I N G !!!!!!!
611 			//*****************************************************************
612 
613 			if (buffer->Material.MaterialType == video::EMT_TRANSPARENT_ALPHA_CHANNEL)
614 			{
615 				VertexA.Normal = core::vector3df(-VertexA.Normal.X, -VertexA.Normal.Y, -VertexA.Normal.Z);
616 				VertexB.Normal = core::vector3df(-VertexB.Normal.X, -VertexB.Normal.Y, -VertexB.Normal.Z);
617 				VertexC.Normal = core::vector3df(-VertexC.Normal.X, -VertexC.Normal.Y, -VertexC.Normal.Z);
618 
619 				buffer->Indices.push_back(buffer->Vertices.size());
620 				buffer->Vertices.push_back(VertexC);
621 
622 				buffer->Indices.push_back(buffer->Vertices.size());
623 				buffer->Vertices.push_back(VertexB);
624 
625 				buffer->Indices.push_back(buffer->Vertices.size());
626 				buffer->Vertices.push_back(VertexA);
627 			}
628 		}
629 		file->read(&id, sizeof(id));
630 #ifdef __BIG_ENDIAN__
631 		id = os::Byteswap::byteswap(id);
632 #endif
633 	}
634 
635 	// creating mesh
636 	SMesh* mesh = new SMesh();
637 
638 	for (u32 num=0; num<MeshBufferEntry.size(); ++num)
639 	{
640 		SMeshBufferLightMap* buffer = MeshBufferEntry[num].MeshBuffer;
641 
642 		if (!buffer)
643 			continue;
644 
645 		mesh->addMeshBuffer(buffer);
646 
647 		buffer->recalculateBoundingBox();
648 		buffer->drop();
649 	}
650 
651 	mesh->recalculateBoundingBox();
652 
653 	if (id != MY3D_FILE_END_ID)
654 		os::Printer::log("Loading finished, but can not find MY3D_FILE_END_ID token.", ELL_WARNING);
655 
656 	SAnimatedMesh* am = new SAnimatedMesh();
657 
658 	am->addMesh(mesh);
659 	mesh->drop();
660 	am->recalculateBoundingBox();
661 
662 	return am;
663 }
664 
665 
readEmbeddedLightmap(io::IReadFile * file,char * namebuf)666 video::ITexture* CMY3DMeshFileLoader::readEmbeddedLightmap(io::IReadFile* file, char* namebuf)
667 {
668 	static int LightMapIndex=0;
669 	u16 id;
670 	file->read(&id, sizeof(id));
671 #ifdef __BIG_ENDIAN__
672 	id = os::Byteswap::byteswap(id);
673 #endif
674 	if (id!=MY3D_TEXDATA_HEADER_ID)
675 	{
676 		os::Printer::log("Can not find MY3D_TEXDATA_HEADER_ID, loading failed!", ELL_ERROR);
677 		return 0;
678 	}
679 
680 	SMyTexDataHeader texDataHeader;
681 
682 	file->read(&texDataHeader, sizeof(SMyTexDataHeader));
683 
684 	strcpy(texDataHeader.Name, namebuf);
685 
686 	char LightMapName[255];
687 	sprintf(LightMapName,"My3D.Lightmap.%d",++LightMapIndex);
688 
689 	core::stringc pixFormatStr;
690 	if (texDataHeader.PixelFormat == MY3D_PIXEL_FORMAT_24)
691 		pixFormatStr = "24bit,";
692 	else
693 	if (texDataHeader.PixelFormat == MY3D_PIXEL_FORMAT_16)
694 		pixFormatStr = "16bit,";
695 	else
696 	{
697 		core::stringc msg="Unknown format of image data (";
698 		msg.append(LightMapName);
699 		msg.append("), loading failed!");
700 		os::Printer::log(msg.c_str(), ELL_ERROR);
701 		return 0;
702 	}
703 
704 	if (texDataHeader.ComprMode != MY3D_TEXDATA_COMPR_NONE_ID &&
705 			texDataHeader.ComprMode != MY3D_TEXDATA_COMPR_RLE_ID &&
706 			texDataHeader.ComprMode != MY3D_TEXDATA_COMPR_SIMPLE_ID )
707 	{
708 		os::Printer::log("Unknown method of compression image data, loading failed!", ELL_ERROR);
709 		return 0;
710 	}
711 
712 	const u32 num_pixels = texDataHeader.Width*texDataHeader.Height;
713 
714 	void* data = 0;
715 
716 	if (texDataHeader.ComprMode==MY3D_TEXDATA_COMPR_NONE_ID)
717 	{
718 		// none compressed image data
719 		if (texDataHeader.PixelFormat == MY3D_PIXEL_FORMAT_24)
720 		{
721 			data = (void*) new SMyPixelColor24[num_pixels];
722 			file->read(data, sizeof(SMyPixelColor24)*num_pixels);
723 		}
724 		else
725 		{
726 			data = (void*) new SMyPixelColor16[num_pixels];
727 			file->read(data, sizeof(SMyPixelColor16)*num_pixels);
728 		}
729 	}
730 	else
731 	if (texDataHeader.ComprMode==MY3D_TEXDATA_COMPR_RLE_ID)
732 	{
733 		// read RLE header identificator
734 		file->read(&id, sizeof(id));
735 #ifdef __BIG_ENDIAN__
736 		id = os::Byteswap::byteswap(id);
737 #endif
738 		if (id!=MY3D_TEXDATA_RLE_HEADER_ID)
739 		{
740 			os::Printer::log("Can not find MY3D_TEXDATA_RLE_HEADER_ID, loading failed!", ELL_ERROR);
741 			return 0;
742 		}
743 
744 		// read RLE header
745 		SMyRLEHeader rleHeader;
746 		file->read(&rleHeader, sizeof(SMyRLEHeader));
747 
748 		//allocate memory for input and output buffers
749 		void *input_buffer  = (void*) new unsigned char[rleHeader.nEncodedBytes];
750 		void *output_buffer = (void*) new unsigned char[rleHeader.nDecodedBytes];
751 
752 		// read encoded data
753 		file->read(input_buffer, rleHeader.nEncodedBytes);
754 
755 		// decode data
756 		data = 0;//(void*) new unsigned char[rleHeader.nDecodedBytes];
757 		s32 decodedBytes = core::rle_decode(
758 			(unsigned char*)input_buffer,  rleHeader.nEncodedBytes,
759 			(unsigned char*)output_buffer, rleHeader.nDecodedBytes);
760 
761 		if (decodedBytes!=(s32)rleHeader.nDecodedBytes)
762 		{
763 			os::Printer::log("Error extracting data from RLE compression, loading failed!", ELL_ERROR);
764 			return 0;
765 		}
766 
767 		// free input buffer
768 		delete [] (unsigned char*)input_buffer;
769 
770 		// here decoded data
771 		data = output_buffer;
772 	}
773 	else if (texDataHeader.ComprMode==MY3D_TEXDATA_COMPR_SIMPLE_ID)
774 	{
775 		// simple compressed image data
776 		if (texDataHeader.PixelFormat == MY3D_PIXEL_FORMAT_24)
777 			data = (void*) new SMyPixelColor24[num_pixels];
778 		else
779 			data = (void*) new SMyPixelColor16[num_pixels];
780 
781 		u32 nReadedPixels=0, nToRead=0;
782 		while (true)
783 		{
784 			file->read(&nToRead, sizeof(nToRead));
785 
786 			if ((nReadedPixels+nToRead) > num_pixels)
787 				break;
788 
789 			if (texDataHeader.PixelFormat == MY3D_PIXEL_FORMAT_24)
790 			{
791 				SMyPixelColor24 col24;
792 				file->read(&col24, sizeof(SMyPixelColor24));
793 				for (u32 p=0; p<nToRead; p++)
794 				{
795 					((SMyPixelColor24*)data)[nReadedPixels+p] =
796 						SMyPixelColor24(col24.r, col24.g, col24.b);
797 				}
798 			}
799 			else
800 			{
801 				SMyPixelColor16 col16;
802 				file->read(&col16, sizeof(SMyPixelColor16));
803 				for (u32 p=0; p<nToRead; p++)
804 					((SMyPixelColor16*)data)[nReadedPixels+p].argb = col16.argb;
805 			}
806 
807 			nReadedPixels+=nToRead;
808 
809 			if (nReadedPixels >= num_pixels)
810 				break;
811 		}
812 
813 		if (nReadedPixels != num_pixels)
814 		{
815 			os::Printer::log("Image data seems to be corrupted, loading failed!", ELL_ERROR);
816 			return 0;
817 		}
818 	}
819 
820 	//! Creates a software image from a byte array.
821 	video::IImage* light_img = 0;
822 
823 	if (texDataHeader.PixelFormat == MY3D_PIXEL_FORMAT_24)
824 	{
825 		// 24 bit lightmap format
826 		light_img = SceneManager->getVideoDriver()->createImageFromData(
827 		video::ECF_R8G8B8,
828 		core::dimension2d<u32>(texDataHeader.Width, texDataHeader.Height),
829 			data, true);
830 	}
831 	else
832 	{
833 		// 16 bit lightmap format
834 		light_img = SceneManager->getVideoDriver()->createImageFromData(
835 			video::ECF_A1R5G5B5,
836 			core::dimension2d<u32>(texDataHeader.Width, texDataHeader.Height),
837 			data, true);
838 	}
839 
840 	const bool oldMipMapState = SceneManager->getVideoDriver()->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS);
841 	SceneManager->getVideoDriver()->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false);
842 	video::ITexture* lmtex = SceneManager->getVideoDriver()->addTexture(LightMapName, light_img);
843 	SceneManager->getVideoDriver()->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, oldMipMapState);
844 
845 	light_img->drop();
846 	return lmtex;
847 }
848 
849 
getMaterialEntryByIndex(u32 matInd)850 CMY3DMeshFileLoader::SMyMaterialEntry* CMY3DMeshFileLoader::getMaterialEntryByIndex(u32 matInd)
851 {
852 	for (u32 m=0; m<MaterialEntry.size(); ++m)
853 		if (MaterialEntry[m].Header.Index == matInd)
854 			return &MaterialEntry[m];
855 
856 	return 0;
857 }
858 
859 
860 
getMeshBufferByMaterialIndex(u32 matInd)861 SMeshBufferLightMap* CMY3DMeshFileLoader::getMeshBufferByMaterialIndex(u32 matInd)
862 {
863 	for (u32 m=0; m<MeshBufferEntry.size(); ++m)
864 	{
865 		if (MeshBufferEntry[m].MaterialIndex == (s32)matInd)
866 			return MeshBufferEntry[m].MeshBuffer;
867 	}
868 	return 0;
869 }
870 
871 
getChildNodes() const872 const core::array<ISceneNode*>& CMY3DMeshFileLoader::getChildNodes() const
873 {
874 	return ChildNodes;
875 }
876 
877 
878 } // end namespace scnene
879 } // end namespace irr
880 
881 #endif // _IRR_COMPILE_WITH_MY3D_LOADER_
882 
883