Retour
Version Originale

./aip/1.8aipmod/source/Irrlicht/CMD2MeshFileLoader.cpp :


// Copyright (C) 2002-2011 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_MD2_LOADER_

#include "CMD2MeshFileLoader.h"
#include "CAnimatedMeshMD2.h"
#include "os.h"

namespace irr
{
namespace scene
{


#if defined(_MSC_VER) ||  defined(__BORLANDC__) || defined (__BCPLUSPLUS__)
#	pragma pack( push, packing )
#	pragma pack( 1 )
#	define PACK_STRUCT
#elif defined( __GNUC__ )
#	define PACK_STRUCT	__attribute__((packed))
#else
#	error compiler not supported
#endif

	// structs needed to load the md2-format


	const s32 MD2_MAGIC_NUMBER  = 844121161;
	const s32 MD2_VERSION       = 8;
	const s32 MD2_MAX_VERTS     = 2048;

	struct SMD2Header
	{
		s32 magic;           // four character code "IDP2"

		s32 version;         // must be 8

		s32 skinWidth;	     // width of the texture

		s32 skinHeight;      // height of the texture

		s32 frameSize;       // size in bytes of an animation frame

		s32 numSkins;        // number of textures

		s32 numVertices;     // total number of vertices

		s32 numTexcoords;    // number of vertices with texture coords

		s32 numTriangles;    // number of triangles

		s32 numGlCommands;   // number of opengl commands (triangle strip or triangle fan)

		s32 numFrames;       // animation keyframe count

		s32 offsetSkins;     // offset in bytes to 64 character skin names

		s32 offsetTexcoords; // offset in bytes to texture coordinate list

		s32 offsetTriangles; // offset in bytes to triangle list

		s32 offsetFrames;    // offset in bytes to frame list

		s32 offsetGlCommands;// offset in bytes to opengl commands

		s32 offsetEnd;       // offset in bytes to end of file

	} PACK_STRUCT;

	struct SMD2Vertex
	{
		u8 vertex[3];        // [0] = X, [1] = Z, [2] = Y

		u8 lightNormalIndex; // index in the normal table

	} PACK_STRUCT;

	struct SMD2Frame
	{
		f32	scale[3];           // first scale the vertex position

		f32	translate[3];       // then translate the position

		c8	name[16];           // the name of the animation that this key belongs to

		SMD2Vertex vertices[1]; // vertex 1 of SMD2Header.numVertices

	} PACK_STRUCT;

	struct SMD2Triangle
	{
		u16 vertexIndices[3];
		u16 textureIndices[3];
	} PACK_STRUCT;

	struct SMD2TextureCoordinate
	{
		s16 s;
		s16 t;
	} PACK_STRUCT;

	struct SMD2GLCommand
	{
		f32 s, t;
		s32 vertexIndex;
	} PACK_STRUCT;

// Default alignment

#if defined(_MSC_VER) ||  defined(__BORLANDC__) || defined (__BCPLUSPLUS__)
#	pragma pack( pop, packing )
#endif

#undef PACK_STRUCT

//! Constructor

CMD2MeshFileLoader::CMD2MeshFileLoader()
{
	#ifdef _DEBUG
	setDebugName("CMD2MeshFileLoader");
	#endif
}


//! returns true if the file maybe is able to be loaded by this class

//! based on the file extension (e.g. ".bsp")

bool CMD2MeshFileLoader::isALoadableFileExtension(const io::path& filename) const
{
	return core::hasFileExtension ( filename, "md2" );
}


//! 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* CMD2MeshFileLoader::createMesh(io::IReadFile* file)
{
	IAnimatedMesh* msh = new CAnimatedMeshMD2();
	if (msh)
	{
		if (loadFile(file, (CAnimatedMeshMD2*)msh) )
			return msh;

		msh->drop();
	}

	return 0;
}

//! loads an md2 file

bool CMD2MeshFileLoader::loadFile(io::IReadFile* file, CAnimatedMeshMD2* mesh)
{
	if (!file)
		return false;

	SMD2Header header;

	file->read(&header, sizeof(SMD2Header));

#ifdef __BIG_ENDIAN__
	header.magic = os::Byteswap::byteswap(header.magic);
	header.version = os::Byteswap::byteswap(header.version);
	header.skinWidth = os::Byteswap::byteswap(header.skinWidth);
	header.skinHeight = os::Byteswap::byteswap(header.skinHeight);
	header.frameSize = os::Byteswap::byteswap(header.frameSize);
	header.numSkins = os::Byteswap::byteswap(header.numSkins);
	header.numVertices = os::Byteswap::byteswap(header.numVertices);
	header.numTexcoords = os::Byteswap::byteswap(header.numTexcoords);
	header.numTriangles = os::Byteswap::byteswap(header.numTriangles);
	header.numGlCommands = os::Byteswap::byteswap(header.numGlCommands);
	header.numFrames = os::Byteswap::byteswap(header.numFrames);
	header.offsetSkins = os::Byteswap::byteswap(header.offsetSkins);
	header.offsetTexcoords = os::Byteswap::byteswap(header.offsetTexcoords);
	header.offsetTriangles = os::Byteswap::byteswap(header.offsetTriangles);
	header.offsetFrames = os::Byteswap::byteswap(header.offsetFrames);
	header.offsetGlCommands = os::Byteswap::byteswap(header.offsetGlCommands);
	header.offsetEnd = os::Byteswap::byteswap(header.offsetEnd);
#endif

	if (header.magic != MD2_MAGIC_NUMBER || header.version != MD2_VERSION)
	{
		os::Printer::log("MD2 Loader: Wrong file header", file->getFileName(), ELL_WARNING);
		return false;
	}

	//

	// prepare mesh and allocate memory

	//


	mesh->FrameCount = header.numFrames;

	// create keyframes

	mesh->FrameTransforms.set_used(header.numFrames);

	// create vertex arrays for each keyframe

	if (mesh->FrameList)
		delete [] mesh->FrameList;
	mesh->FrameList = new core::array<CAnimatedMeshMD2::SMD2Vert>[header.numFrames];

	// allocate space in vertex arrays

	s32 i;
	for (i=0; i<header.numFrames; ++i)
		mesh->FrameList[i].reallocate(header.numVertices);

	// allocate interpolation buffer vertices

	mesh->InterpolationBuffer->Vertices.set_used(header.numTriangles*3);

	// populate triangles

	mesh->InterpolationBuffer->Indices.reallocate(header.numTriangles*3);
	const s32 count = header.numTriangles*3;
	for (i=0; i<count; i+=3)
	{
		mesh->InterpolationBuffer->Indices.push_back(i);
		mesh->InterpolationBuffer->Indices.push_back(i+1);
		mesh->InterpolationBuffer->Indices.push_back(i+2);
	}

	//

	// read texture coordinates

	//


	file->seek(header.offsetTexcoords);
	SMD2TextureCoordinate* textureCoords = new SMD2TextureCoordinate[header.numTexcoords];

	if (!file->read(textureCoords, sizeof(SMD2TextureCoordinate)*header.numTexcoords))
	{
		delete[] textureCoords;
		os::Printer::log("MD2 Loader: Error reading TextureCoords.", file->getFileName(), ELL_ERROR);
		return false;
	}

#ifdef __BIG_ENDIAN__
	for (i=0; i<header.numTexcoords; ++i)
	{
		textureCoords[i].s = os::Byteswap::byteswap(textureCoords[i].s);
		textureCoords[i].t = os::Byteswap::byteswap(textureCoords[i].t);
	}
#endif

	// read Triangles


	file->seek(header.offsetTriangles);

	SMD2Triangle *triangles = new SMD2Triangle[header.numTriangles];
	if (!file->read(triangles, header.numTriangles *sizeof(SMD2Triangle)))
	{
		delete[] triangles;
		delete[] textureCoords;

		os::Printer::log("MD2 Loader: Error reading triangles.", file->getFileName(), ELL_ERROR);
		return false;
	}

#ifdef __BIG_ENDIAN__
	for (i=0; i<header.numTriangles; ++i)
	{
		triangles[i].vertexIndices[0] = os::Byteswap::byteswap(triangles[i].vertexIndices[0]);
		triangles[i].vertexIndices[1] = os::Byteswap::byteswap(triangles[i].vertexIndices[1]);
		triangles[i].vertexIndices[2] = os::Byteswap::byteswap(triangles[i].vertexIndices[2]);
		triangles[i].textureIndices[0] = os::Byteswap::byteswap(triangles[i].textureIndices[0]);
		triangles[i].textureIndices[1] = os::Byteswap::byteswap(triangles[i].textureIndices[1]);
		triangles[i].textureIndices[2] = os::Byteswap::byteswap(triangles[i].textureIndices[2]);
	}
#endif

	// read Vertices


	u8 buffer[MD2_MAX_VERTS*4+128];
	SMD2Frame* frame = (SMD2Frame*)buffer;

	file->seek(header.offsetFrames);

	for (i = 0; i<header.numFrames; ++i)
	{
		// read vertices


		file->read(frame, header.frameSize);

#ifdef __BIG_ENDIAN__
		frame->scale[0] = os::Byteswap::byteswap(frame->scale[0]);
		frame->scale[1] = os::Byteswap::byteswap(frame->scale[1]);
		frame->scale[2] = os::Byteswap::byteswap(frame->scale[2]);
		frame->translate[0] = os::Byteswap::byteswap(frame->translate[0]);
		frame->translate[1] = os::Byteswap::byteswap(frame->translate[1]);
		frame->translate[2] = os::Byteswap::byteswap(frame->translate[2]);
#endif
		//

		// store frame data

		//


		CAnimatedMeshMD2::SAnimationData adata;
		adata.begin = i;
		adata.end = i;
		adata.fps = 7;

		// Add new named animation if necessary

		if (frame->name[0])
		{
			// get animation name

			for (s32 s = 0; s < 16 && frame->name[s]!=0 && (frame->name[s] < '0' || frame->name[s] > '9'); ++s)
			{
				adata.name += frame->name[s];
			}

			// Does this keyframe have the same animation name as the current animation?

			if (!mesh->AnimationData.empty() && mesh->AnimationData[mesh->AnimationData.size()-1].name == adata.name)
			{
				// Increase the length of the animation

				++mesh->AnimationData[mesh->AnimationData.size() - 1].end;
			}
			else
			{
				// Add the new animation

				mesh->AnimationData.push_back(adata);
			}
		}

		// save keyframe scale and translation


		mesh->FrameTransforms[i].scale.X = frame->scale[0];
		mesh->FrameTransforms[i].scale.Z = frame->scale[1];
		mesh->FrameTransforms[i].scale.Y = frame->scale[2];
		mesh->FrameTransforms[i].translate.X = frame->translate[0];
		mesh->FrameTransforms[i].translate.Z = frame->translate[1];
		mesh->FrameTransforms[i].translate.Y = frame->translate[2];

		// add vertices

		for (s32 j=0; j<header.numTriangles; ++j)
		{
			for (u32 ti=0; ti<3; ++ti)
			{
				CAnimatedMeshMD2::SMD2Vert v;
				u32 num = triangles[j].vertexIndices[ti];
				v.Pos.X = frame->vertices[num].vertex[0];
				v.Pos.Z = frame->vertices[num].vertex[1];
				v.Pos.Y = frame->vertices[num].vertex[2];
				v.NormalIdx = frame->vertices[num].lightNormalIndex;

				mesh->FrameList[i].push_back(v);
			}
		}

		// calculate bounding boxes

		if (header.numVertices)
		{
			core::aabbox3d<f32> box;
			core::vector3df pos;
			pos.X = f32(mesh->FrameList[i] [0].Pos.X) * mesh->FrameTransforms[i].scale.X + mesh->FrameTransforms[i].translate.X;
			pos.Y = f32(mesh->FrameList[i] [0].Pos.Y) * mesh->FrameTransforms[i].scale.Y + mesh->FrameTransforms[i].translate.Y;
			pos.Z = f32(mesh->FrameList[i] [0].Pos.Z) * mesh->FrameTransforms[i].scale.Z + mesh->FrameTransforms[i].translate.Z;

			box.reset(pos);

			for (s32 j=1; j<header.numTriangles*3; ++j)
			{
				pos.X = f32(mesh->FrameList[i] [j].Pos.X) * mesh->FrameTransforms[i].scale.X + mesh->FrameTransforms[i].translate.X;
				pos.Y = f32(mesh->FrameList[i] [j].Pos.Y) * mesh->FrameTransforms[i].scale.Y + mesh->FrameTransforms[i].translate.Y;
				pos.Z = f32(mesh->FrameList[i] [j].Pos.Z) * mesh->FrameTransforms[i].scale.Z + mesh->FrameTransforms[i].translate.Z;

				box.addInternalPoint(pos);
			}
			mesh->BoxList.push_back(box);
		}
	}

	// populate interpolation buffer with texture coordinates and colours

	if (header.numFrames)
	{
		f32 dmaxs = 1.0f/(header.skinWidth);
		f32 dmaxt = 1.0f/(header.skinHeight);

		for (s32 t=0; t<header.numTriangles; ++t)
		{
			for (s32 n=0; n<3; ++n)
			{
				mesh->InterpolationBuffer->Vertices[t*3 + n].TCoords.X = (textureCoords[triangles[t].textureIndices[n]].s + 0.5f) * dmaxs;
				mesh->InterpolationBuffer->Vertices[t*3 + n].TCoords.Y = (textureCoords[triangles[t].textureIndices[n]].t + 0.5f) * dmaxt;
				mesh->InterpolationBuffer->Vertices[t*3 + n].Color = video::SColor(255,255,255,255);
			}
		}
	}

	// clean up

	delete [] triangles;
	delete [] textureCoords;

	// init buffer with start frame.

	mesh->getMesh(0);
	return true;
}

} // end namespace scene

} // end namespace irr



#endif // _IRR_COMPILE_WITH_MD2_LOADER_


Options Liens officiels Caractéristiques Statistiques Communauté
Corrections
irrlicht
irrklang
irredit
irrxml
xhtml 1.0
css 2.1
Propulsé par FluxBB
Traduit par FluxBB.fr
881 membres
1427 sujets
11117 messages
Dernier membre inscrit: Bidule
21 invités en ligne
Aucun membre connecté
RSS Feed