1 // Copyright (C) 2002-2012 Nikolaus Gebhardt
\r
2 // This file is part of the "Irrlicht Engine".
\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
\r
5 #include "CMeshManipulator.h"
\r
6 #include "ISkinnedMesh.h"
\r
8 #include "CMeshBuffer.h"
\r
9 #include "SAnimatedMesh.h"
\r
11 #include "triangle3d.h"
\r
18 static inline core::vector3df getAngleWeight(const core::vector3df& v1,
\r
19 const core::vector3df& v2,
\r
20 const core::vector3df& v3)
\r
22 // Calculate this triangle's weight for each of its three vertices
\r
23 // start by calculating the lengths of its sides
\r
24 const f32 a = v2.getDistanceFromSQ(v3);
\r
25 const f32 asqrt = sqrtf(a);
\r
26 const f32 b = v1.getDistanceFromSQ(v3);
\r
27 const f32 bsqrt = sqrtf(b);
\r
28 const f32 c = v1.getDistanceFromSQ(v2);
\r
29 const f32 csqrt = sqrtf(c);
\r
31 // use them to find the angle at each vertex
\r
32 return core::vector3df(
\r
33 acosf((b + c - a) / (2.f * bsqrt * csqrt)),
\r
34 acosf((-b + c + a) / (2.f * asqrt * csqrt)),
\r
35 acosf((b - c + a) / (2.f * bsqrt * asqrt)));
\r
41 template <typename T>
\r
42 void recalculateNormalsT(IMeshBuffer* buffer, bool smooth, bool angleWeighted)
\r
44 const u32 vtxcnt = buffer->getVertexCount();
\r
45 const u32 idxcnt = buffer->getIndexCount();
\r
46 const T* idx = reinterpret_cast<T*>(buffer->getIndices());
\r
50 for (u32 i=0; i<idxcnt; i+=3)
\r
52 const core::vector3df& v1 = buffer->getPosition(idx[i+0]);
\r
53 const core::vector3df& v2 = buffer->getPosition(idx[i+1]);
\r
54 const core::vector3df& v3 = buffer->getPosition(idx[i+2]);
\r
55 const core::vector3df normal = core::plane3d<f32>(v1, v2, v3).Normal;
\r
56 buffer->getNormal(idx[i+0]) = normal;
\r
57 buffer->getNormal(idx[i+1]) = normal;
\r
58 buffer->getNormal(idx[i+2]) = normal;
\r
65 for ( i = 0; i!= vtxcnt; ++i )
\r
66 buffer->getNormal(i).set(0.f, 0.f, 0.f);
\r
68 for ( i=0; i<idxcnt; i+=3)
\r
70 const core::vector3df& v1 = buffer->getPosition(idx[i+0]);
\r
71 const core::vector3df& v2 = buffer->getPosition(idx[i+1]);
\r
72 const core::vector3df& v3 = buffer->getPosition(idx[i+2]);
\r
73 const core::vector3df normal = core::plane3d<f32>(v1, v2, v3).Normal;
\r
75 core::vector3df weight(1.f,1.f,1.f);
\r
77 weight = irr::scene::getAngleWeight(v1,v2,v3); // writing irr::scene:: necessary for borland
\r
79 buffer->getNormal(idx[i+0]) += weight.X*normal;
\r
80 buffer->getNormal(idx[i+1]) += weight.Y*normal;
\r
81 buffer->getNormal(idx[i+2]) += weight.Z*normal;
\r
84 for ( i = 0; i!= vtxcnt; ++i )
\r
85 buffer->getNormal(i).normalize();
\r
91 //! Recalculates all normals of the mesh buffer.
\r
92 /** \param buffer: Mesh buffer on which the operation is performed. */
\r
93 void CMeshManipulator::recalculateNormals(IMeshBuffer* buffer, bool smooth, bool angleWeighted) const
\r
98 if (buffer->getIndexType()==video::EIT_16BIT)
\r
99 recalculateNormalsT<u16>(buffer, smooth, angleWeighted);
\r
101 recalculateNormalsT<u32>(buffer, smooth, angleWeighted);
\r
105 //! Recalculates all normals of the mesh.
\r
106 //! \param mesh: Mesh on which the operation is performed.
\r
107 void CMeshManipulator::recalculateNormals(scene::IMesh* mesh, bool smooth, bool angleWeighted) const
\r
112 if (mesh->getMeshType() == EAMT_SKINNED)
\r
114 ISkinnedMesh *smesh = (ISkinnedMesh *) mesh;
\r
115 smesh->resetAnimation();
\r
118 const u32 bcount = mesh->getMeshBufferCount();
\r
119 for ( u32 b=0; b<bcount; ++b)
\r
120 recalculateNormals(mesh->getMeshBuffer(b), smooth, angleWeighted);
\r
122 if (mesh->getMeshType() == EAMT_SKINNED)
\r
124 ISkinnedMesh *smesh = (ISkinnedMesh *) mesh;
\r
125 smesh->refreshJointCache();
\r
130 //! Clones a static IMesh into a modifyable SMesh.
\r
132 SMesh* CMeshManipulator::createMeshCopy(scene::IMesh* mesh) const
\r
137 SMesh* clone = new SMesh();
\r
139 const u32 meshBufferCount = mesh->getMeshBufferCount();
\r
141 for ( u32 b=0; b<meshBufferCount; ++b)
\r
143 const IMeshBuffer* const mb = mesh->getMeshBuffer(b);
\r
144 switch(mb->getVertexType())
\r
146 case video::EVT_STANDARD:
\r
148 SMeshBuffer* buffer = new SMeshBuffer();
\r
149 buffer->Material = mb->getMaterial();
\r
150 const u32 vcount = mb->getVertexCount();
\r
151 buffer->Vertices.reallocate(vcount);
\r
152 video::S3DVertex* vertices = (video::S3DVertex*)mb->getVertices();
\r
153 for (u32 i=0; i < vcount; ++i)
\r
154 buffer->Vertices.push_back(vertices[i]);
\r
155 const u32 icount = mb->getIndexCount();
\r
156 buffer->Indices.reallocate(icount);
\r
157 const u16* indices = mb->getIndices();
\r
158 for (u32 i=0; i < icount; ++i)
\r
159 buffer->Indices.push_back(indices[i]);
\r
160 clone->addMeshBuffer(buffer);
\r
164 case video::EVT_2TCOORDS:
\r
166 SMeshBufferLightMap* buffer = new SMeshBufferLightMap();
\r
167 buffer->Material = mb->getMaterial();
\r
168 const u32 vcount = mb->getVertexCount();
\r
169 buffer->Vertices.reallocate(vcount);
\r
170 video::S3DVertex2TCoords* vertices = (video::S3DVertex2TCoords*)mb->getVertices();
\r
171 for (u32 i=0; i < vcount; ++i)
\r
172 buffer->Vertices.push_back(vertices[i]);
\r
173 const u32 icount = mb->getIndexCount();
\r
174 buffer->Indices.reallocate(icount);
\r
175 const u16* indices = mb->getIndices();
\r
176 for (u32 i=0; i < icount; ++i)
\r
177 buffer->Indices.push_back(indices[i]);
\r
178 clone->addMeshBuffer(buffer);
\r
182 case video::EVT_TANGENTS:
\r
184 SMeshBufferTangents* buffer = new SMeshBufferTangents();
\r
185 buffer->Material = mb->getMaterial();
\r
186 const u32 vcount = mb->getVertexCount();
\r
187 buffer->Vertices.reallocate(vcount);
\r
188 video::S3DVertexTangents* vertices = (video::S3DVertexTangents*)mb->getVertices();
\r
189 for (u32 i=0; i < vcount; ++i)
\r
190 buffer->Vertices.push_back(vertices[i]);
\r
191 const u32 icount = mb->getIndexCount();
\r
192 buffer->Indices.reallocate(icount);
\r
193 const u16* indices = mb->getIndices();
\r
194 for (u32 i=0; i < icount; ++i)
\r
195 buffer->Indices.push_back(indices[i]);
\r
196 clone->addMeshBuffer(buffer);
\r
202 }// end for all mesh buffers
\r
204 clone->BoundingBox = mesh->getBoundingBox();
\r
209 //! Returns amount of polygons in mesh.
\r
210 s32 CMeshManipulator::getPolyCount(scene::IMesh* mesh) const
\r
215 s32 trianglecount = 0;
\r
217 for (u32 g=0; g<mesh->getMeshBufferCount(); ++g)
\r
218 trianglecount += mesh->getMeshBuffer(g)->getIndexCount() / 3;
\r
220 return trianglecount;
\r
224 //! Returns amount of polygons in mesh.
\r
225 s32 CMeshManipulator::getPolyCount(scene::IAnimatedMesh* mesh) const
\r
227 if (mesh && mesh->getFrameCount() != 0)
\r
228 return getPolyCount(mesh->getMesh(0));
\r
234 //! create a new AnimatedMesh and adds the mesh to it
\r
235 IAnimatedMesh * CMeshManipulator::createAnimatedMesh(scene::IMesh* mesh, scene::E_ANIMATED_MESH_TYPE type) const
\r
237 return new SAnimatedMesh(mesh, type);
\r
241 } // end namespace scene
\r
242 } // end namespace irr
\r