244 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			244 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright (C) 2002-2012 Nikolaus Gebhardt
 | |
| // This file is part of the "Irrlicht Engine".
 | |
| // For conditions of distribution and use, see copyright notice in irrlicht.h
 | |
| 
 | |
| #include "CMeshManipulator.h"
 | |
| #include "ISkinnedMesh.h"
 | |
| #include "SMesh.h"
 | |
| #include "CMeshBuffer.h"
 | |
| #include "SAnimatedMesh.h"
 | |
| #include "os.h"
 | |
| #include "triangle3d.h"
 | |
| 
 | |
| namespace irr
 | |
| {
 | |
| namespace scene
 | |
| {
 | |
| 
 | |
| static inline core::vector3df getAngleWeight(const core::vector3df& v1,
 | |
| 		const core::vector3df& v2,
 | |
| 		const core::vector3df& v3)
 | |
| {
 | |
| 	// Calculate this triangle's weight for each of its three vertices
 | |
| 	// start by calculating the lengths of its sides
 | |
| 	const f32 a = v2.getDistanceFromSQ(v3);
 | |
| 	const f32 asqrt = sqrtf(a);
 | |
| 	const f32 b = v1.getDistanceFromSQ(v3);
 | |
| 	const f32 bsqrt = sqrtf(b);
 | |
| 	const f32 c = v1.getDistanceFromSQ(v2);
 | |
| 	const f32 csqrt = sqrtf(c);
 | |
| 
 | |
| 	// use them to find the angle at each vertex
 | |
| 	return core::vector3df(
 | |
| 		acosf((b + c - a) / (2.f * bsqrt * csqrt)),
 | |
| 		acosf((-b + c + a) / (2.f * asqrt * csqrt)),
 | |
| 		acosf((b - c + a) / (2.f * bsqrt * asqrt)));
 | |
| }
 | |
| 
 | |
| 
 | |
| namespace
 | |
| {
 | |
| template <typename T>
 | |
| void recalculateNormalsT(IMeshBuffer* buffer, bool smooth, bool angleWeighted)
 | |
| {
 | |
| 	const u32 vtxcnt = buffer->getVertexCount();
 | |
| 	const u32 idxcnt = buffer->getIndexCount();
 | |
| 	const T* idx = reinterpret_cast<T*>(buffer->getIndices());
 | |
| 
 | |
| 	if (!smooth)
 | |
| 	{
 | |
| 		for (u32 i=0; i<idxcnt; i+=3)
 | |
| 		{
 | |
| 			const core::vector3df& v1 = buffer->getPosition(idx[i+0]);
 | |
| 			const core::vector3df& v2 = buffer->getPosition(idx[i+1]);
 | |
| 			const core::vector3df& v3 = buffer->getPosition(idx[i+2]);
 | |
| 			const core::vector3df normal = core::plane3d<f32>(v1, v2, v3).Normal;
 | |
| 			buffer->getNormal(idx[i+0]) = normal;
 | |
| 			buffer->getNormal(idx[i+1]) = normal;
 | |
| 			buffer->getNormal(idx[i+2]) = normal;
 | |
| 		}
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		u32 i;
 | |
| 
 | |
| 		for ( i = 0; i!= vtxcnt; ++i )
 | |
| 			buffer->getNormal(i).set(0.f, 0.f, 0.f);
 | |
| 
 | |
| 		for ( i=0; i<idxcnt; i+=3)
 | |
| 		{
 | |
| 			const core::vector3df& v1 = buffer->getPosition(idx[i+0]);
 | |
| 			const core::vector3df& v2 = buffer->getPosition(idx[i+1]);
 | |
| 			const core::vector3df& v3 = buffer->getPosition(idx[i+2]);
 | |
| 			const core::vector3df normal = core::plane3d<f32>(v1, v2, v3).Normal;
 | |
| 
 | |
| 			core::vector3df weight(1.f,1.f,1.f);
 | |
| 			if (angleWeighted)
 | |
| 				weight = irr::scene::getAngleWeight(v1,v2,v3); // writing irr::scene:: necessary for borland
 | |
| 
 | |
| 			buffer->getNormal(idx[i+0]) += weight.X*normal;
 | |
| 			buffer->getNormal(idx[i+1]) += weight.Y*normal;
 | |
| 			buffer->getNormal(idx[i+2]) += weight.Z*normal;
 | |
| 		}
 | |
| 
 | |
| 		for ( i = 0; i!= vtxcnt; ++i )
 | |
| 			buffer->getNormal(i).normalize();
 | |
| 	}
 | |
| }
 | |
| }
 | |
| 
 | |
| 
 | |
| //! Recalculates all normals of the mesh buffer.
 | |
| /** \param buffer: Mesh buffer on which the operation is performed. */
 | |
| void CMeshManipulator::recalculateNormals(IMeshBuffer* buffer, bool smooth, bool angleWeighted) const
 | |
| {
 | |
| 	if (!buffer)
 | |
| 		return;
 | |
| 
 | |
| 	if (buffer->getIndexType()==video::EIT_16BIT)
 | |
| 		recalculateNormalsT<u16>(buffer, smooth, angleWeighted);
 | |
| 	else
 | |
| 		recalculateNormalsT<u32>(buffer, smooth, angleWeighted);
 | |
| }
 | |
| 
 | |
| 
 | |
| //! Recalculates all normals of the mesh.
 | |
| //! \param mesh: Mesh on which the operation is performed.
 | |
| void CMeshManipulator::recalculateNormals(scene::IMesh* mesh, bool smooth, bool angleWeighted) const
 | |
| {
 | |
| 	if (!mesh)
 | |
| 		return;
 | |
| 
 | |
| 	if (mesh->getMeshType() == EAMT_SKINNED)
 | |
| 	{
 | |
| 		ISkinnedMesh *smesh = (ISkinnedMesh *) mesh;
 | |
| 		smesh->resetAnimation();
 | |
| 	}
 | |
| 
 | |
| 	const u32 bcount = mesh->getMeshBufferCount();
 | |
| 	for ( u32 b=0; b<bcount; ++b)
 | |
| 		recalculateNormals(mesh->getMeshBuffer(b), smooth, angleWeighted);
 | |
| 
 | |
| 	if (mesh->getMeshType() == EAMT_SKINNED)
 | |
| 	{
 | |
| 		ISkinnedMesh *smesh = (ISkinnedMesh *) mesh;
 | |
| 		smesh->refreshJointCache();
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| //! Clones a static IMesh into a modifyable SMesh.
 | |
| // not yet 32bit
 | |
| SMesh* CMeshManipulator::createMeshCopy(scene::IMesh* mesh) const
 | |
| {
 | |
| 	if (!mesh)
 | |
| 		return 0;
 | |
| 
 | |
| 	SMesh* clone = new SMesh();
 | |
| 
 | |
| 	const u32 meshBufferCount = mesh->getMeshBufferCount();
 | |
| 
 | |
| 	for ( u32 b=0; b<meshBufferCount; ++b)
 | |
| 	{
 | |
| 		const IMeshBuffer* const mb = mesh->getMeshBuffer(b);
 | |
| 		switch(mb->getVertexType())
 | |
| 		{
 | |
| 		case video::EVT_STANDARD:
 | |
| 			{
 | |
| 				SMeshBuffer* buffer = new SMeshBuffer();
 | |
| 				buffer->Material = mb->getMaterial();
 | |
| 				const u32 vcount = mb->getVertexCount();
 | |
| 				buffer->Vertices.reallocate(vcount);
 | |
| 				video::S3DVertex* vertices = (video::S3DVertex*)mb->getVertices();
 | |
| 				for (u32 i=0; i < vcount; ++i)
 | |
| 					buffer->Vertices.push_back(vertices[i]);
 | |
| 				const u32 icount = mb->getIndexCount();
 | |
| 				buffer->Indices.reallocate(icount);
 | |
| 				const u16* indices = mb->getIndices();
 | |
| 				for (u32 i=0; i < icount; ++i)
 | |
| 					buffer->Indices.push_back(indices[i]);
 | |
| 				clone->addMeshBuffer(buffer);
 | |
| 				buffer->drop();
 | |
| 			}
 | |
| 			break;
 | |
| 		case video::EVT_2TCOORDS:
 | |
| 			{
 | |
| 				SMeshBufferLightMap* buffer = new SMeshBufferLightMap();
 | |
| 				buffer->Material = mb->getMaterial();
 | |
| 				const u32 vcount = mb->getVertexCount();
 | |
| 				buffer->Vertices.reallocate(vcount);
 | |
| 				video::S3DVertex2TCoords* vertices = (video::S3DVertex2TCoords*)mb->getVertices();
 | |
| 				for (u32 i=0; i < vcount; ++i)
 | |
| 					buffer->Vertices.push_back(vertices[i]);
 | |
| 				const u32 icount = mb->getIndexCount();
 | |
| 				buffer->Indices.reallocate(icount);
 | |
| 				const u16* indices = mb->getIndices();
 | |
| 				for (u32 i=0; i < icount; ++i)
 | |
| 					buffer->Indices.push_back(indices[i]);
 | |
| 				clone->addMeshBuffer(buffer);
 | |
| 				buffer->drop();
 | |
| 			}
 | |
| 			break;
 | |
| 		case video::EVT_TANGENTS:
 | |
| 			{
 | |
| 				SMeshBufferTangents* buffer = new SMeshBufferTangents();
 | |
| 				buffer->Material = mb->getMaterial();
 | |
| 				const u32 vcount = mb->getVertexCount();
 | |
| 				buffer->Vertices.reallocate(vcount);
 | |
| 				video::S3DVertexTangents* vertices = (video::S3DVertexTangents*)mb->getVertices();
 | |
| 				for (u32 i=0; i < vcount; ++i)
 | |
| 					buffer->Vertices.push_back(vertices[i]);
 | |
| 				const u32 icount = mb->getIndexCount();
 | |
| 				buffer->Indices.reallocate(icount);
 | |
| 				const u16* indices = mb->getIndices();
 | |
| 				for (u32 i=0; i < icount; ++i)
 | |
| 					buffer->Indices.push_back(indices[i]);
 | |
| 				clone->addMeshBuffer(buffer);
 | |
| 				buffer->drop();
 | |
| 			}
 | |
| 			break;
 | |
| 		}// end switch
 | |
| 
 | |
| 	}// end for all mesh buffers
 | |
| 
 | |
| 	clone->BoundingBox = mesh->getBoundingBox();
 | |
| 	return clone;
 | |
| }
 | |
| 
 | |
| 
 | |
| //! Returns amount of polygons in mesh.
 | |
| s32 CMeshManipulator::getPolyCount(scene::IMesh* mesh) const
 | |
| {
 | |
| 	if (!mesh)
 | |
| 		return 0;
 | |
| 
 | |
| 	s32 trianglecount = 0;
 | |
| 
 | |
| 	for (u32 g=0; g<mesh->getMeshBufferCount(); ++g)
 | |
| 		trianglecount += mesh->getMeshBuffer(g)->getIndexCount() / 3;
 | |
| 
 | |
| 	return trianglecount;
 | |
| }
 | |
| 
 | |
| 
 | |
| //! Returns amount of polygons in mesh.
 | |
| s32 CMeshManipulator::getPolyCount(scene::IAnimatedMesh* mesh) const
 | |
| {
 | |
| 	if (mesh && mesh->getFrameCount() != 0)
 | |
| 		return getPolyCount(mesh->getMesh(0));
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| //! create a new AnimatedMesh and adds the mesh to it
 | |
| IAnimatedMesh * CMeshManipulator::createAnimatedMesh(scene::IMesh* mesh, scene::E_ANIMATED_MESH_TYPE type) const
 | |
| {
 | |
| 	return new SAnimatedMesh(mesh, type);
 | |
| }
 | |
| 
 | |
| 
 | |
| } // end namespace scene
 | |
| } // end namespace irr
 | |
| 
 |