All pastes #969053 Raw Edit

Miscellany

public cpp v1 · immutable
·published 2008-04-03 13:30 UTC
rendered paste body
// Copyright (C) 2002-2007 Nikolaus Gebhardt// This file is part of the "Irrlicht Engine".// For conditions of distribution and use, see copyright notice in irrlicht.h#include "IrrCompileConfig.h"#ifdef _IRR_COMPILE_WITH_3DS_LOADER_#include "C3DSMeshFileLoader.h"#include "os.h"#include "SMeshBuffer.h"#include "SAnimatedMesh.h"#include "IReadFile.h"#include "IVideoDriver.h"#include "IMeshManipulator.h"namespace irr{namespace scene{// Primary chunkconst u16 C3DS_MAIN3DS = 0x4D4D;// Main Chunksconst u16 C3DS_EDIT3DS = 0x3D3D;const u16 C3DS_KEYF3DS = 0xB000;const u16 C3DS_VERSION = 0x0002;const u16 C3DS_MESHVERSION = 0x3D3E;// sub chunks of C3DS_EDIT3DSconst u16 C3DS_EDIT_MATERIAL = 0xAFFF;const u16 C3DS_EDIT_OBJECT   = 0x4000;// sub chunks of C3DS_EDIT_MATERIALconst u16 C3DS_MATNAME       = 0xA000; const u16 C3DS_MATAMBIENT    = 0xA010;const u16 C3DS_MATDIFFUSE    = 0xA020;const u16 C3DS_MATSPECULAR   = 0xA030;const u16 C3DS_MATSHININESS  = 0xA040;const u16 C3DS_MATSHIN2PCT   = 0xA041;const u16 C3DS_TRANSPARENCY  = 0xA050;const u16 C3DS_TRANSPARENCY_FALLOFF  = 0xA052;const u16 C3DS_REFL_BLUR     = 0xA053;const u16 C3DS_TWO_SIDE      = 0xA081;const u16 C3DS_WIRE          = 0xA085;const u16 C3DS_SHADING       = 0xA100;const u16 C3DS_MATTEXMAP     = 0xA200;const u16 C3DS_MATSPECMAP    = 0xA204;const u16 C3DS_MATOPACMAP    = 0xA210;const u16 C3DS_MATREFLMAP    = 0xA220;const u16 C3DS_MATBUMPMAP    = 0xA230;const u16 C3DS_MATMAPFILE    = 0xA300;const u16 C3DS_MAT_TEXTILING = 0xA351;const u16 C3DS_MAT_USCALE    = 0xA354;const u16 C3DS_MAT_VSCALE    = 0xA356;const u16 C3DS_MAT_UOFFSET   = 0xA358;const u16 C3DS_MAT_VOFFSET   = 0xA35A;// subs of C3DS_EDIT_OBJECTconst u16 C3DS_OBJTRIMESH    = 0x4100;// subs of C3DS_OBJTRIMESHconst u16 C3DS_TRIVERT       = 0x4110;const u16 C3DS_POINTFLAGARRAY= 0x4111;const u16 C3DS_TRIFACE       = 0x4120;const u16 C3DS_TRIFACEMAT    = 0x4130;const u16 C3DS_TRIUV         = 0x4140;const u16 C3DS_TRISMOOTH     = 0x4150;const u16 C3DS_TRIMATRIX     = 0x4160;const u16 C3DS_MESHCOLOR     = 0x4165;const u16 C3DS_DIRECT_LIGHT  = 0x4600;const u16 C3DS_DL_INNER_RANGE= 0x4659;const u16 C3DS_DL_OUTER_RANGE= 0x465A;const u16 C3DS_DL_MULTIPLIER = 0x465B;const u16 C3DS_CAMERA        = 0x4700;const u16 C3DS_CAM_SEE_CONE  = 0x4710;const u16 C3DS_CAM_RANGES    = 0x4720;// subs of C3DS_KEYF3DSconst u16 C3DS_KF_HDR        = 0xB00A;const u16 C3DS_AMBIENT_TAG   = 0xB001;const u16 C3DS_OBJECT_TAG    = 0xB002;const u16 C3DS_CAMERA_TAG    = 0xB003;const u16 C3DS_TARGET_TAG    = 0xB004;const u16 C3DS_LIGHTNODE_TAG = 0xB005;const u16 C3DS_KF_SEG        = 0xB008;const u16 C3DS_KF_CURTIME    = 0xB009;const u16 C3DS_KF_NODE_HDR   = 0xB010;const u16 C3DS_PIVOTPOINT    = 0xB013;const u16 C3DS_BOUNDBOX      = 0xB014;const u16 C3DS_POS_TRACK_TAG = 0xB020;const u16 C3DS_ROT_TRACK_TAG = 0xB021;const u16 C3DS_SCL_TRACK_TAG = 0xB022;const u16 C3DS_NODE_ID       = 0xB030;// different color chunk typesconst u16 C3DS_COL_RGB    = 0x0010;const u16 C3DS_COL_TRU    = 0x0011;const u16 C3DS_COL_LIN_24 = 0x0012;const u16 C3DS_COL_LIN_F  = 0x0013;// percentage chunk typesconst u16 C3DS_PERCENTAGE_I = 0x0030;const u16 C3DS_PERCENTAGE_F = 0x0031;//! ConstructorC3DSMeshFileLoader::C3DSMeshFileLoader(ISceneManager* smgr, io::IFileSystem* fs): SceneManager(smgr), FileSystem(fs), Vertices(0), Indices(0), SmoothingGroups(0), TCoords(0),	CountVertices(0), CountFaces(0), CountTCoords(0), Mesh(0){	TransformationMatrix.makeIdentity();	if (FileSystem)		FileSystem->grab();}//! destructorC3DSMeshFileLoader::~C3DSMeshFileLoader(){	cleanUp();	if (FileSystem)		FileSystem->drop();	if (Mesh)		Mesh->drop();}//! returns true if the file maybe is able to be loaded by this class//! based on the file extension (e.g. ".bsp")bool C3DSMeshFileLoader::isALoadableFileExtension(const c8* filename) const{	return strstr(filename, ".3ds")!=0;}//! creates/loads an animated mesh from the file.//! \return Pointer to the created mesh. Returns 0 if loading failed.//! If you no longer need the mesh, you should call IAnimatedMesh::drop().//! See IReferenceCounted::drop() for more information.IAnimatedMesh* C3DSMeshFileLoader::createMesh(io::IReadFile* file){	ChunkData data;	readChunkData(file, data);	if (data.header.id != C3DS_MAIN3DS )		return 0;	CurrentMaterial.clear();	Materials.clear();	MeshBufferNames.clear();	cleanUp();	if (Mesh)		Mesh->drop();	Mesh = new SMesh();	if (readChunk(file, &data))	{		// success		for (u32 i=0; i<Mesh->getMeshBufferCount(); ++i)		{			SMeshBuffer* mb = ((SMeshBuffer*)Mesh->getMeshBuffer(i));			// drop empty buffers			if (mb->getIndexCount() == 0 || mb->getVertexCount() == 0)			{				Mesh->MeshBuffers.erase(i--);				mb->drop();			}			else			{				if (mb->Material.MaterialType == video::EMT_PARALLAX_MAP_SOLID)				{					SMesh tmp;					tmp.addMeshBuffer(mb);					IMesh* tangentMesh = SceneManager->getMeshManipulator()->createMeshWithTangents(&tmp);					mb->drop();					Mesh->MeshBuffers[i]=tangentMesh->getMeshBuffer(0);				}				Mesh->MeshBuffers[i]->recalculateBoundingBox();			}		}		Mesh->recalculateBoundingBox();		SAnimatedMesh* am = new SAnimatedMesh();		am->Type = EAMT_3DS;		am->addMesh(Mesh);		am->recalculateBoundingBox();		Mesh->drop();		Mesh = 0;		return am;	}	Mesh->drop();	Mesh = 0;	return 0;}bool C3DSMeshFileLoader::readPercentageChunk(io::IReadFile* file,					ChunkData* chunk, f32& percentage){	ChunkData data;	readChunkData(file, data);	short intpercentage;	float fpercentage;	switch(data.header.id)	{	case C3DS_PERCENTAGE_I:	{		// read short		file->read(&intpercentage, 2);#ifdef __BIG_ENDIAN__		intpercentage = os::Byteswap::byteswap(intpercentage);#endif		percentage=intpercentage/100.0f;		data.read += 2;	}	break;	case C3DS_PERCENTAGE_F:	{		// read float		file->read(&fpercentage, sizeof(float));		data.read += sizeof(float);#ifdef __BIG_ENDIAN__		percentage = os::Byteswap::byteswap(fpercentage);#else		percentage = (f32)fpercentage;#endif	}	break;	default:	{		// unknown percentage chunk		os::Printer::log("Unknown percentage chunk in 3Ds file.", ELL_WARNING);		file->seek(data.header.length - data.read, true);		data.read += data.header.length - data.read;	}	}	chunk->read += data.read;	return true;}bool C3DSMeshFileLoader::readColorChunk(io::IReadFile* file, ChunkData* chunk,					video::SColor& out){	ChunkData data;	readChunkData(file, data);	u8 c[3];	f32 cf[3];	switch(data.header.id)	{	case C3DS_COL_TRU:	case C3DS_COL_LIN_24:	{		// read 8 bit data		file->read(c, sizeof(c));		out.set(255, c[0], c[1], c[2]); 		data.read += sizeof(c);	}	break;	case C3DS_COL_RGB:	case C3DS_COL_LIN_F:	{		// read float data		file->read(cf, sizeof(cf));#ifdef __BIG_ENDIAN__		cf[0] = os::Byteswap::byteswap(cf[0]);		cf[1] = os::Byteswap::byteswap(cf[1]);		cf[2] = os::Byteswap::byteswap(cf[2]);#endif		out.set(255, (s32)(cf[0]*255.0f), (s32)(cf[1]*255.0f), (s32)(cf[2]*255.0f)); 		data.read += sizeof(cf);	}	break;	default:	{		// unknown color chunk size		os::Printer::log("Unknown size of color chunk in 3Ds file.", ELL_WARNING);		file->seek(data.header.length - data.read, true);		data.read += data.header.length - data.read;	}	}	chunk->read += data.read;	return true;}bool C3DSMeshFileLoader::readMaterialChunk(io::IReadFile* file, ChunkData* parent){	u16 matSection=0;	while(parent->read < parent->header.length)	{		ChunkData data;		readChunkData(file, data);		switch(data.header.id)		{		case C3DS_MATNAME:			{				c8* c = new c8[data.header.length - data.read];				file->read(c, data.header.length - data.read);				if (strlen(c))					CurrentMaterial.Name = c;				data.read += data.header.length - data.read;				delete [] c;			}			break;		case C3DS_MATAMBIENT:			readColorChunk(file, &data, CurrentMaterial.Material.AmbientColor);			break;		case C3DS_MATDIFFUSE:			readColorChunk(file, &data, CurrentMaterial.Material.DiffuseColor);			break;		case C3DS_MATSPECULAR:			readColorChunk(file, &data, CurrentMaterial.Material.SpecularColor);			break;		case C3DS_MATSHININESS:			readPercentageChunk(file, &data, CurrentMaterial.Material.Shininess);			break;		case C3DS_TRANSPARENCY:			{				f32 percentage;				readPercentageChunk(file, &data, percentage);				if (percentage>0.0f)				{					CurrentMaterial.Material.MaterialTypeParam=percentage;					CurrentMaterial.Material.MaterialType=video::EMT_TRANSPARENT_VERTEX_ALPHA;				}				else				{					CurrentMaterial.Material.MaterialType=video::EMT_SOLID;				}			}			break;		case C3DS_WIRE:			CurrentMaterial.Material.Wireframe=true;			break;		case C3DS_TWO_SIDE:			CurrentMaterial.Material.BackfaceCulling=false;			break;		case C3DS_SHADING:			{				s16 flags;				file->read(&flags, 2);#ifdef __BIG_ENDIAN__				flags = os::Byteswap::byteswap(flags);#endif				switch (flags)				{					case 0:						CurrentMaterial.Material.Wireframe=true;						break;					case 1:						CurrentMaterial.Material.Wireframe=false;						CurrentMaterial.Material.GouraudShading=false;						break;					case 2:						CurrentMaterial.Material.Wireframe=false;						CurrentMaterial.Material.GouraudShading=true;						break;					default:						// phong and metal missing						break;				}				data.read += data.header.length - data.read;			}			break;		case C3DS_MATTEXMAP:		case C3DS_MATSPECMAP:		case C3DS_MATOPACMAP:		case C3DS_MATREFLMAP:		case C3DS_MATBUMPMAP:			{				matSection=data.header.id;				// Should contain a percentage chunk, but does				// not always have it				s16 testval;				const long pos = file->getPos();				file->read(&testval, 2);#ifdef __BIG_ENDIAN__				testval = os::Byteswap::byteswap(testval);#endif				file->seek(pos, false);				if ((testval == C3DS_PERCENTAGE_I) ||					(testval == C3DS_PERCENTAGE_F))				switch (matSection)				{				case C3DS_MATTEXMAP:					readPercentageChunk(file, &data, CurrentMaterial.Strength[0]);				break;				case C3DS_MATSPECMAP:					readPercentageChunk(file, &data, CurrentMaterial.Strength[1]);				break;				case C3DS_MATOPACMAP:					readPercentageChunk(file, &data, CurrentMaterial.Strength[2]);				break;				case C3DS_MATBUMPMAP:					readPercentageChunk(file, &data, CurrentMaterial.Strength[4]);				break;				}			}			break;		case C3DS_MATMAPFILE:			{				// read texture file name				c8* c = new c8[data.header.length - data.read];				file->read(c, data.header.length - data.read);				switch (matSection)				{				case C3DS_MATTEXMAP:					CurrentMaterial.Filename[0] = c;				break;				case C3DS_MATSPECMAP:					CurrentMaterial.Filename[1] = c;				break;				case C3DS_MATOPACMAP:					CurrentMaterial.Filename[2] = c;				break;				case C3DS_MATREFLMAP:					CurrentMaterial.Filename[3] = c;				break;				case C3DS_MATBUMPMAP:					CurrentMaterial.Filename[4] = c;				break;				}				data.read += data.header.length - data.read;				delete [] c;			}			break;		case C3DS_MAT_TEXTILING:			{				s16 flags;				file->read(&flags, 2);#ifdef __BIG_ENDIAN__				flags = os::Byteswap::byteswap(flags);#endif				data.read += 2;			}			break;		case C3DS_MAT_USCALE:		case C3DS_MAT_VSCALE:		case C3DS_MAT_UOFFSET:		case C3DS_MAT_VOFFSET:			{				f32 value;				file->read(&value, 4);#ifdef __BIG_ENDIAN__				value = os::Byteswap::byteswap(value);#endif				u32 i=0;				if (matSection != C3DS_MATTEXMAP)					i=1;				u32 j=0,k=0;				if (data.header.id == C3DS_MAT_VSCALE)				{					j=1;					k=1;				}				else if (data.header.id == C3DS_MAT_UOFFSET)				{					j=2;					k=0;				}				else if (data.header.id == C3DS_MAT_VOFFSET)				{					j=2;					k=1;				}				CurrentMaterial.Material.getTextureMatrix(i)(j,k)=value;				data.read += 4;			}			break;		default:			// ignore chunk			file->seek(data.header.length - data.read, true);			data.read += data.header.length - data.read;		}		parent->read += data.read;	}	Materials.push_back(CurrentMaterial);	CurrentMaterial.clear();	return true;}bool C3DSMeshFileLoader::readTrackChunk(io::IReadFile* file, ChunkData& data,					IMeshBuffer* mb, const core::vector3df& pivot){	u16 flags;	u32 flags2;	// Track flags	file->read(&flags, 2);#ifdef __BIG_ENDIAN__	flags = os::Byteswap::byteswap(flags);#endif	file->read(&flags2, 4);#ifdef __BIG_ENDIAN__	flags2 = os::Byteswap::byteswap(flags2);#endif	file->read(&flags2, 4);#ifdef __BIG_ENDIAN__	flags2 = os::Byteswap::byteswap(flags2);#endif	// Num keys	file->read(&flags2, 4);#ifdef __BIG_ENDIAN__	flags2 = os::Byteswap::byteswap(flags2);#endif	file->read(&flags2, 4);#ifdef __BIG_ENDIAN__	flags2 = os::Byteswap::byteswap(flags2);#endif	// TCB flags	file->read(&flags, 2);#ifdef __BIG_ENDIAN__	flags = os::Byteswap::byteswap(flags);#endif	data.read += 20;	f32 angle=0.0f;	if (data.header.id== C3DS_ROT_TRACK_TAG)	{		// Angle		file->read(&angle, sizeof(f32));#ifdef __BIG_ENDIAN__		angle = os::Byteswap::byteswap(angle);#endif		data.read += sizeof(f32);	}	core::vector3df vec;	file->read(&vec.X, sizeof(f32));	file->read(&vec.Y, sizeof(f32));	file->read(&vec.Z, sizeof(f32));#ifdef __BIG_ENDIAN__	vec.X = os::Byteswap::byteswap(vec.X);	vec.Y = os::Byteswap::byteswap(vec.X);	vec.Z = os::Byteswap::byteswap(vec.X);#endif	data.read += 12;	vec-=pivot;	// apply transformation to mesh buffer	if (false)//mb)	{		video::S3DVertex *vertices=(video::S3DVertex*)mb->getVertices();		if (data.header.id==C3DS_POS_TRACK_TAG)		{			for (u32 i=0; i<mb->getVertexCount(); ++i)				vertices[i].Pos+=vec;		}		else if (data.header.id==C3DS_ROT_TRACK_TAG)		{			//TODO		}		else if (data.header.id==C3DS_SCL_TRACK_TAG)		{			//TODO		}	}	// skip further frames	file->seek(data.header.length - data.read, true);	data.read += data.header.length - data.read;	return true;}bool C3DSMeshFileLoader::readFrameChunk(io::IReadFile* file, ChunkData* parent){	ChunkData data;	//KF_HDR is always at the beginning	readChunkData(file, data);	if (data.header.id != C3DS_KF_HDR)		return false;	else	{		u16 flags;		file->read(&flags, 2);#ifdef __BIG_ENDIAN__		flags = os::Byteswap::byteswap(flags);#endif		c8* c = new c8[data.header.length - data.read-4];		file->read(c, data.header.length - data.read-4);		file->read(&flags, 2);#ifdef __BIG_ENDIAN__		flags = os::Byteswap::byteswap(flags);#endif		data.read += data.header.length - data.read;		parent->read += data.read;		delete [] c;	}	IMeshBuffer* mb=0;	core::vector3df pivot,bboxCenter;	while(parent->read < parent->header.length)	{		readChunkData(file, data);		switch(data.header.id)		{		case C3DS_OBJECT_TAG:			{				mb=0;				pivot.set(0.0f, 0.0f, 0.0f);			}			break;		case C3DS_KF_SEG:			{				u32 flags;				file->read(&flags, 4);#ifdef __BIG_ENDIAN__		flags = os::Byteswap::byteswap(flags);#endif				file->read(&flags, 4);#ifdef __BIG_ENDIAN__		flags = os::Byteswap::byteswap(flags);#endif				data.read += 8;			}			break;		case C3DS_KF_NODE_HDR:			{				s16 flags;				c8* c = new c8[data.header.length - data.read-6];				file->read(c, data.header.length - data.read-6);				// search mesh buffer to apply these transformations to				for (u32 i=0; i<MeshBufferNames.size(); ++i)				{					if (MeshBufferNames[i]==c)					{						mb=Mesh->getMeshBuffer(i);						break;					}				}				file->read(&flags, 2);#ifdef __BIG_ENDIAN__				flags = os::Byteswap::byteswap(flags);#endif				file->read(&flags, 2);#ifdef __BIG_ENDIAN__				flags = os::Byteswap::byteswap(flags);#endif				file->read(&flags, 2);#ifdef __BIG_ENDIAN__				flags = os::Byteswap::byteswap(flags);#endif				data.read += data.header.length - data.read;				delete [] c;			}			break;		case C3DS_KF_CURTIME:			{				u32 flags;				file->read(&flags, 4);#ifdef __BIG_ENDIAN__				flags = os::Byteswap::byteswap(flags);#endif				data.read += 4;			}			break;		case C3DS_NODE_ID:			{				u16 flags;				file->read(&flags, 2);#ifdef __BIG_ENDIAN__				flags = os::Byteswap::byteswap(flags);#endif				data.read += 2;			}			break;		case C3DS_PIVOTPOINT:			{				file->read(&pivot.X, sizeof(f32));				file->read(&pivot.Y, sizeof(f32));				file->read(&pivot.Z, sizeof(f32));#ifdef __BIG_ENDIAN__				pivot.X = os::Byteswap::byteswap(pivot.X);				pivot.Y = os::Byteswap::byteswap(pivot.Y);				pivot.Z = os::Byteswap::byteswap(pivot.Z);#endif				data.read += 12;			}			break;		case C3DS_BOUNDBOX:			{				core::aabbox3df bbox;				// abuse bboxCenter as temporary variable				file->read(&bboxCenter.X, sizeof(f32));				file->read(&bboxCenter.Y, sizeof(f32));				file->read(&bboxCenter.Z, sizeof(f32));#ifdef __BIG_ENDIAN__				bboxCenter.X = os::Byteswap::byteswap(bboxCenter.X);				bboxCenter.Y = os::Byteswap::byteswap(bboxCenter.Y);				bboxCenter.Z = os::Byteswap::byteswap(bboxCenter.Z);#endif				bbox.reset(bboxCenter);				file->read(&bboxCenter.X, sizeof(f32));				file->read(&bboxCenter.Y, sizeof(f32));				file->read(&bboxCenter.Z, sizeof(f32));#ifdef __BIG_ENDIAN__				bboxCenter.X = os::Byteswap::byteswap(bboxCenter.X);				bboxCenter.Y = os::Byteswap::byteswap(bboxCenter.Y);				bboxCenter.Z = os::Byteswap::byteswap(bboxCenter.Z);#endif				bbox.addInternalPoint(bboxCenter);				bboxCenter=bbox.getCenter();				data.read += 24;			}			break;		case C3DS_POS_TRACK_TAG:		case C3DS_ROT_TRACK_TAG:		case C3DS_SCL_TRACK_TAG:			readTrackChunk(file, data, mb, bboxCenter-pivot);			break;		default:			// ignore chunk			file->seek(data.header.length - data.read, true);			data.read += data.header.length - data.read;		}		parent->read += data.read;		data.read=0;	}	return true;}bool C3DSMeshFileLoader::readChunk(io::IReadFile* file, ChunkData* parent){	while(parent->read < parent->header.length)	{		ChunkData data;		readChunkData(file, data);		switch(data.header.id)		{		case C3DS_VERSION:			{				u16 version;				file->read(&version, sizeof(u16));#ifdef __BIG_ENDIAN__				version = os::Byteswap::byteswap(version);#endif				file->seek(data.header.length - data.read - 2, true);				data.read += data.header.length - data.read;				if (version != 0x03)					os::Printer::log("3ds file version is other than 3.", ELL_ERROR);			}			break;		case C3DS_EDIT_MATERIAL:			readMaterialChunk(file, &data);			break;		case C3DS_KEYF3DS:			readFrameChunk(file, &data);			break;		case C3DS_EDIT3DS:			break;		case C3DS_MESHVERSION:		case 0x01:			{				u32 version;				file->read(&version, sizeof(u32));#ifdef __BIG_ENDIAN__				version = os::Byteswap::byteswap(version);#endif				data.read += sizeof(u32);			}			break;		case C3DS_EDIT_OBJECT:			{				core::stringc name;				readString(file, data, name);				readObjectChunk(file, &data);				composeObject(file, name);			}			break;		default:			// ignore chunk			file->seek(data.header.length - data.read, true);			data.read += data.header.length - data.read;		}		parent->read += data.read;	}	return true;}bool C3DSMeshFileLoader::readObjectChunk(io::IReadFile* file, ChunkData* parent){	while(parent->read < parent->header.length)	{		ChunkData data;		readChunkData(file, data);		switch(data.header.id)		{		case C3DS_OBJTRIMESH:			readObjectChunk(file, &data);			break;		case C3DS_TRIVERT: 			readVertices(file, data);			break;		case C3DS_POINTFLAGARRAY:			{				u16 numVertex, flags;				file->read(&numVertex, sizeof(u16));#ifdef __BIG_ENDIAN__				numVertex= os::Byteswap::byteswap(numVertex);#endif				for (u16 i=0; i<numVertex; ++i)				{					file->read(&flags, sizeof(u16));#ifdef __BIG_ENDIAN__					flags = os::Byteswap::byteswap(flags);#endif				}				data.read += (numVertex+1)*sizeof(u16);			}			break;		case C3DS_TRIFACE: 			readIndices(file, data);			readObjectChunk(file, &data); // read smooth and material groups			break;		case C3DS_TRIFACEMAT: 			readMaterialGroup(file, data);			break;		case C3DS_TRIUV: // getting texture coordinates			readTextureCoords(file, data);			break;		case C3DS_TRIMATRIX:			{				f32 mat[4][3];				file->read(&mat, 12*sizeof(f32));				TransformationMatrix.makeIdentity();				for (int i=0; i<4; ++i)				{					for (int j=0; j<3; ++j)					{#ifdef __BIG_ENDIAN__						TransformationMatrix(i,j)=os::Byteswap::byteswap(mat[i][j]);#else						TransformationMatrix(i,j)=mat[i][j];#endif					}				}				data.read += 12*sizeof(f32);			}			break;		case C3DS_MESHCOLOR:			{				u8 flag;				file->read(&flag, sizeof(u8));				++data.read;			}			break;		case C3DS_TRISMOOTH: // TODO			{				SmoothingGroups = new u32[CountFaces];				file->read(SmoothingGroups, CountFaces*sizeof(u32));#ifdef __BIG_ENDIAN__				for (u16 i=0; i<CountFaces; ++i)					SmoothingGroups[i] = os::Byteswap::byteswap(SmoothingGroups[i]);#endif				data.read += CountFaces*sizeof(u32);			}			break;		default:			// ignore chunk			file->seek(data.header.length - data.read, true);			data.read += data.header.length - data.read;		}		parent->read += data.read;	}	return true;}void C3DSMeshFileLoader::composeObject(io::IReadFile* file, const core::stringc& name){	if (Mesh->getMeshBufferCount() != Materials.size())		loadMaterials(file);	if (MaterialGroups.empty())	{		// no material group, so add all		SMaterialGroup group;		group.faceCount = CountFaces;		group.faces = new u16[group.faceCount];		for (u32 i=0; i<group.faceCount; ++i)			group.faces[i] = i;		MaterialGroups.push_back(group);		// if we've got no material, add one without a texture		if (Materials.empty())		{			SCurrentMaterial m;			Materials.push_back(m);			SMeshBuffer* mb = new scene::SMeshBuffer();			Mesh->addMeshBuffer(mb);			mb->getMaterial() = Materials[0].Material;			mb->drop();			// add an empty mesh buffer name			MeshBufferNames.push_back("");		}	}	for (u32 i=0; i<MaterialGroups.size(); ++i)	{		SMeshBuffer* mb = 0;		video::SMaterial* mat=0;		u32 mbPos;		// -3 because we add three vertices at once		u32 maxPrimitives = core::min_(SceneManager->getVideoDriver()->getMaximalPrimitiveCount(), (u32)((1<<16)-1))-3; // currently hardcoded s16 max value for index pointers		// find mesh buffer for this group		for (mbPos=0; mbPos<Materials.size(); ++mbPos)		{			if (MaterialGroups[i].MaterialName == Materials[mbPos].Name)			{				mb = (SMeshBuffer*)Mesh->getMeshBuffer(mbPos);				mat=&Materials[mbPos].Material;				MeshBufferNames[mbPos]=name;				break;			}		}		if (mb != 0)		{			// add geometry to the buffer.			video::S3DVertex vtx;			core::vector3df vec;			vtx.Color=mat->DiffuseColor;			if (mat->MaterialType==video::EMT_TRANSPARENT_VERTEX_ALPHA)			{				vtx.Color.setAlpha((int)(255.0f*mat->MaterialTypeParam));			}			vtx.Normal.set(0,0,0);			for (s32 f=0; f<MaterialGroups[i].faceCount; ++f)			{				u32 vtxCount = mb->Vertices.size();				if (vtxCount>maxPrimitives)				{							IMeshBuffer* tmp = mb;					mb = new SMeshBuffer();					Mesh->addMeshBuffer(mb);					mb->drop();					Mesh->MeshBuffers[mbPos] = Mesh->MeshBuffers.getLast();					Mesh->MeshBuffers[Mesh->MeshBuffers.size()-1] = tmp;					mb->getMaterial() = tmp->getMaterial();					vtxCount=0;				}				for (s32 v=0; v<3; ++v)				{					s32 idx = Indices[MaterialGroups[i].faces[f]*4 +v];					if (CountVertices > idx)					{						vtx.Pos.X = Vertices[idx*3 + 0];						vtx.Pos.Z = Vertices[idx*3 + 1];						vtx.Pos.Y = Vertices[idx*3 + 2];//						TransformationMatrix.transformVect(vtx.Pos);					}					if (CountTCoords > idx)					{						vtx.TCoords.X = TCoords[idx*2 + 0];						vtx.TCoords.Y = 1.0f -TCoords[idx*2 + 1];					}					mb->Vertices.push_back(vtx);				}				// compute normal				core::plane3d<f32> pl(mb->Vertices[vtxCount].Pos, mb->Vertices[vtxCount+2].Pos,						mb->Vertices[vtxCount+1].Pos);				mb->Vertices[vtxCount].Normal = pl.Normal;				mb->Vertices[vtxCount+1].Normal = pl.Normal;				mb->Vertices[vtxCount+2].Normal = pl.Normal;				// add indices				mb->Indices.push_back(vtxCount);				mb->Indices.push_back(vtxCount+2);				mb->Indices.push_back(vtxCount+1);			}		}		else			os::Printer::log("Found no matching material for Group in 3ds file.", ELL_WARNING);	}	cleanUp();}void C3DSMeshFileLoader::loadMaterials(io::IReadFile* file){	// create a mesh buffer for every material	core::stringc modelFilename = file->getFileName();	if (Materials.empty())		os::Printer::log("No materials found in 3ds file.", ELL_INFORMATION);	MeshBufferNames.reallocate(Materials.size());	for (u32 i=0; i<Materials.size(); ++i)	{		MeshBufferNames.push_back("");		SMeshBuffer* m = new scene::SMeshBuffer();		Mesh->addMeshBuffer(m);		m->getMaterial() = Materials[i].Material;		if (Materials[i].Filename[0].size())		{			video::ITexture* texture = 0;			if (FileSystem->existFile(Materials[i].Filename[0].c_str()))				texture = SceneManager->getVideoDriver()->getTexture(Materials[i].Filename[0].c_str());			if (!texture)			{				const core::stringc fname = FileSystem->getFileDir(modelFilename) + "/" + FileSystem->getFileBasename(Materials[i].Filename[0]);				if (FileSystem->existFile(fname.c_str()))					texture = SceneManager->getVideoDriver()->getTexture(fname.c_str());							}			if (!texture)				os::Printer::log("Could not load a texture for entry in 3ds file",					Materials[i].Filename[0].c_str(), ELL_WARNING);			else				m->getMaterial().setTexture(0, texture);		}		if (Materials[i].Filename[2].size())		{			video::ITexture* texture = 0;			if (FileSystem->existFile(Materials[i].Filename[2].c_str()))				texture = SceneManager->getVideoDriver()->getTexture(Materials[i].Filename[2].c_str());			if (!texture)			{				const core::stringc fname = FileSystem->getFileDir(modelFilename) + "/" + FileSystem->getFileBasename(Materials[i].Filename[2]);				if (FileSystem->existFile(fname.c_str()))					texture = SceneManager->getVideoDriver()->getTexture(fname.c_str());							}			if (!texture)			{				os::Printer::log("Could not load a texture for entry in 3ds file",					Materials[i].Filename[2].c_str(), ELL_WARNING);			}			else			{				m->getMaterial().setTexture(0, texture);				m->getMaterial().MaterialType = video::EMT_TRANSPARENT_ADD_COLOR;			}		}		if (Materials[i].Filename[3].size())		{			video::ITexture* texture = 0;			if (FileSystem->existFile(Materials[i].Filename[3].c_str()))				texture = SceneManager->getVideoDriver()->getTexture(Materials[i].Filename[3].c_str());			if (!texture)			{				const core::stringc fname = FileSystem->getFileDir(modelFilename) + "/" + FileSystem->getFileBasename(Materials[i].Filename[3]);				if (FileSystem->existFile(fname.c_str()))					texture = SceneManager->getVideoDriver()->getTexture(fname.c_str());							}			if (!texture)			{				os::Printer::log("Could not load a texture for entry in 3ds file",					Materials[i].Filename[3].c_str(), ELL_WARNING);			}			else			{				m->getMaterial().setTexture(1, m->getMaterial().getTexture(0));				m->getMaterial().setTexture(0, texture);				m->getMaterial().MaterialType = video::EMT_REFLECTION_2_LAYER;			}		}		if (Materials[i].Filename[4].size())		{			video::ITexture* texture = 0;			if (FileSystem->existFile(Materials[i].Filename[4].c_str()))				texture = SceneManager->getVideoDriver()->getTexture(Materials[i].Filename[4].c_str());			if (!texture)			{				const core::stringc fname = FileSystem->getFileDir(modelFilename) + "/" + FileSystem->getFileBasename(Materials[i].Filename[4]);				if (FileSystem->existFile(fname.c_str()))					texture = SceneManager->getVideoDriver()->getTexture(fname.c_str());							}			if (!texture)				os::Printer::log("Could not load a texture for entry in 3ds file",					Materials[i].Filename[4].c_str(), ELL_WARNING);			else			{				m->getMaterial().setTexture(1, texture);				SceneManager->getVideoDriver()->makeNormalMapTexture(texture, Materials[i].Strength[4]*10.f);				m->getMaterial().MaterialType=video::EMT_PARALLAX_MAP_SOLID;				m->getMaterial().MaterialTypeParam=.035f;			}		}		m->drop();	}}void C3DSMeshFileLoader::cleanUp(){	delete [] Vertices;	CountVertices = 0;	Vertices = 0;	delete [] Indices;	Indices = 0;	CountFaces = 0;	delete [] SmoothingGroups;	SmoothingGroups = 0;	delete [] TCoords;	TCoords = 0;	CountTCoords = 0;	MaterialGroups.clear();}void C3DSMeshFileLoader::readTextureCoords(io::IReadFile* file, ChunkData& data){	file->read(&CountTCoords, sizeof(CountTCoords));#ifdef __BIG_ENDIAN__	CountTCoords = os::Byteswap::byteswap(CountTCoords);#endif	data.read += sizeof(CountTCoords);	s32 tcoordsBufferByteSize = CountTCoords * sizeof(f32) * 2;	if (data.header.length - data.read != tcoordsBufferByteSize)	{		os::Printer::log("Invalid size of tcoords found in 3ds file.", ELL_WARNING);		return;	}	TCoords = new f32[CountTCoords * 3];	file->read(TCoords, tcoordsBufferByteSize);#ifdef __BIG_ENDIAN__	for (int i=0;i<CountTCoords*2;i++) TCoords[i] = os::Byteswap::byteswap(TCoords[i]);#endif	data.read += tcoordsBufferByteSize;}void C3DSMeshFileLoader::readMaterialGroup(io::IReadFile* file, ChunkData& data){	SMaterialGroup group;	readString(file, data, group.MaterialName);	file->read(&group.faceCount, sizeof(group.faceCount));#ifdef __BIG_ENDIAN__	group.faceCount = os::Byteswap::byteswap(group.faceCount);#endif	data.read += sizeof(group.faceCount);	// read faces	group.faces = new u16[group.faceCount];	file->read(group.faces, sizeof(u16) * group.faceCount);#ifdef __BIG_ENDIAN__	for (u32 i=0;i<group.faceCount;++i)		group.faces[i] = os::Byteswap::byteswap(group.faces[i]);#endif	data.read += sizeof(u16) * group.faceCount;	MaterialGroups.push_back(group);}void C3DSMeshFileLoader::readIndices(io::IReadFile* file, ChunkData& data){	file->read(&CountFaces, sizeof(CountFaces));#ifdef __BIG_ENDIAN__	CountFaces = os::Byteswap::byteswap(CountFaces);#endif	data.read += sizeof(CountFaces);	s32 indexBufferByteSize = CountFaces * sizeof(u16) * 4;	// Indices are u16s.	// After every 3 Indices in the array, there follows an edge flag.	Indices = new u16[CountFaces * 4];	file->read(Indices, indexBufferByteSize);#ifdef __BIG_ENDIAN__	for (int i=0;i<CountFaces*4;++i)		Indices[i] = os::Byteswap::byteswap(Indices[i]);#endif	data.read += indexBufferByteSize;}void C3DSMeshFileLoader::readVertices(io::IReadFile* file, ChunkData& data){	file->read(&CountVertices, sizeof(CountVertices));#ifdef __BIG_ENDIAN__	CountVertices = os::Byteswap::byteswap(CountVertices);#endif	data.read += sizeof(CountVertices);	s32 vertexBufferByteSize = CountVertices * sizeof(f32) * 3;	if (data.header.length - data.read != vertexBufferByteSize)	{		os::Printer::log("Invalid size of vertices found in 3ds file.", ELL_WARNING);		return;	}	Vertices = new f32[CountVertices * 3];	file->read(Vertices, vertexBufferByteSize);#ifdef __BIG_ENDIAN__	for (int i=0;i<CountVertices*3;i++) Vertices[i] = os::Byteswap::byteswap(Vertices[i]);#endif	data.read += vertexBufferByteSize;}void C3DSMeshFileLoader::readChunkData(io::IReadFile* file, ChunkData& data){	file->read(&data.header, sizeof(ChunkHeader));#ifdef __BIG_ENDIAN__	data.header.id = os::Byteswap::byteswap(data.header.id);	data.header.length = os::Byteswap::byteswap(data.header.length);#endif	data.read += sizeof(ChunkHeader);}void C3DSMeshFileLoader::readString(io::IReadFile* file, ChunkData& data, core::stringc& out){	c8 c = 1;	out = "";	while (c)	{		file->read(&c, sizeof(c8));		if (c)			out.append(c);		++data.read;	}}} // end namespace scene} // end namespace irr#endif // _IRR_COMPILE_WITH_3DS_LOADER_