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 #ifndef __I_MESH_MANIPULATOR_H_INCLUDED__
\r
6 #define __I_MESH_MANIPULATOR_H_INCLUDED__
\r
8 #include "IReferenceCounted.h"
\r
9 #include "vector3d.h"
\r
10 #include "aabbox3d.h"
\r
11 #include "matrix4.h"
\r
12 #include "IAnimatedMesh.h"
\r
13 #include "IMeshBuffer.h"
\r
14 #include "SVertexManipulator.h"
\r
23 //! An interface for easy manipulation of meshes.
\r
24 /** Scale, set alpha value, flip surfaces, and so on. This exists for
\r
25 fixing problems with wrong imported or exported meshes quickly after
\r
26 loading. It is not intended for doing mesh modifications and/or
\r
27 animations during runtime.
\r
29 class IMeshManipulator : public virtual IReferenceCounted
\r
33 //! Flips the direction of surfaces.
\r
34 /** Changes backfacing triangles to frontfacing
\r
35 triangles and vice versa.
\r
36 \param mesh Mesh on which the operation is performed. */
\r
37 virtual void flipSurfaces(IMesh* mesh) const = 0;
\r
39 //! Sets the alpha vertex color value of the whole mesh to a new value.
\r
40 /** \param mesh Mesh on which the operation is performed.
\r
41 \param alpha New alpha value. Must be a value between 0 and 255. */
\r
42 void setVertexColorAlpha(IMesh* mesh, s32 alpha) const
\r
44 apply(scene::SVertexColorSetAlphaManipulator(alpha), mesh);
\r
47 //! Sets the alpha vertex color value of the whole mesh to a new value.
\r
48 /** \param buffer Meshbuffer on which the operation is performed.
\r
49 \param alpha New alpha value. Must be a value between 0 and 255. */
\r
50 void setVertexColorAlpha(IMeshBuffer* buffer, s32 alpha) const
\r
52 apply(scene::SVertexColorSetAlphaManipulator(alpha), buffer);
\r
55 //! Sets the colors of all vertices to one color
\r
56 /** \param mesh Mesh on which the operation is performed.
\r
57 \param color New color. */
\r
58 void setVertexColors(IMesh* mesh, video::SColor color) const
\r
60 apply(scene::SVertexColorSetManipulator(color), mesh);
\r
63 //! Sets the colors of all vertices to one color
\r
64 /** \param buffer Meshbuffer on which the operation is performed.
\r
65 \param color New color. */
\r
66 void setVertexColors(IMeshBuffer* buffer, video::SColor color) const
\r
68 apply(scene::SVertexColorSetManipulator(color), buffer);
\r
71 //! Recalculates all normals of the mesh.
\r
72 /** \param mesh: Mesh on which the operation is performed.
\r
73 \param smooth: If the normals shall be smoothed.
\r
74 \param angleWeighted: If the normals shall be smoothed in relation to their angles. More expensive, but also higher precision. */
\r
75 virtual void recalculateNormals(IMesh* mesh, bool smooth = false,
\r
76 bool angleWeighted = false) const=0;
\r
78 //! Recalculates all normals of the mesh buffer.
\r
79 /** \param buffer: Mesh buffer on which the operation is performed.
\r
80 \param smooth: If the normals shall be smoothed.
\r
81 \param angleWeighted: If the normals shall be smoothed in relation to their angles. More expensive, but also higher precision. */
\r
82 virtual void recalculateNormals(IMeshBuffer* buffer,
\r
83 bool smooth = false, bool angleWeighted = false) const=0;
\r
85 //! Recalculates tangents, requires a tangent mesh
\r
86 /** \param mesh Mesh on which the operation is performed.
\r
87 \param recalculateNormals If the normals shall be recalculated, otherwise original normals of the mesh are used unchanged.
\r
88 \param smooth If the normals shall be smoothed.
\r
89 \param angleWeighted If the normals shall be smoothed in relation to their angles. More expensive, but also higher precision.
\r
91 virtual void recalculateTangents(IMesh* mesh,
\r
92 bool recalculateNormals=false, bool smooth=false,
\r
93 bool angleWeighted=false) const=0;
\r
95 //! Recalculates tangents, requires a tangent mesh buffer
\r
96 /** \param buffer Meshbuffer on which the operation is performed.
\r
97 \param recalculateNormals If the normals shall be recalculated, otherwise original normals of the buffer are used unchanged.
\r
98 \param smooth If the normals shall be smoothed.
\r
99 \param angleWeighted If the normals shall be smoothed in relation to their angles. More expensive, but also higher precision.
\r
101 virtual void recalculateTangents(IMeshBuffer* buffer,
\r
102 bool recalculateNormals=false, bool smooth=false,
\r
103 bool angleWeighted=false) const=0;
\r
105 //! Scales the actual mesh, not a scene node.
\r
106 /** \param mesh Mesh on which the operation is performed.
\r
107 \param factor Scale factor for each axis. */
\r
108 void scale(IMesh* mesh, const core::vector3df& factor) const
\r
110 apply(SVertexPositionScaleManipulator(factor), mesh, true);
\r
113 //! Scales the actual meshbuffer, not a scene node.
\r
114 /** \param buffer Meshbuffer on which the operation is performed.
\r
115 \param factor Scale factor for each axis. */
\r
116 void scale(IMeshBuffer* buffer, const core::vector3df& factor) const
\r
118 apply(SVertexPositionScaleManipulator(factor), buffer, true);
\r
121 //! Scales the actual mesh, not a scene node.
\r
122 /** \deprecated Use scale() instead. This method may be removed by Irrlicht 1.9
\r
123 \param mesh Mesh on which the operation is performed.
\r
124 \param factor Scale factor for each axis. */
\r
125 _IRR_DEPRECATED_ void scaleMesh(IMesh* mesh, const core::vector3df& factor) const {return scale(mesh,factor);}
\r
127 //! Scale the texture coords of a mesh.
\r
128 /** \param mesh Mesh on which the operation is performed.
\r
129 \param factor Vector which defines the scale for each axis.
\r
130 \param level Number of texture coord, starting from 1. Support for level 2 exists for LightMap buffers. */
\r
131 void scaleTCoords(scene::IMesh* mesh, const core::vector2df& factor, u32 level=1) const
\r
133 apply(SVertexTCoordsScaleManipulator(factor, level), mesh);
\r
136 //! Scale the texture coords of a meshbuffer.
\r
137 /** \param buffer Meshbuffer on which the operation is performed.
\r
138 \param factor Vector which defines the scale for each axis.
\r
139 \param level Number of texture coord, starting from 1. Support for level 2 exists for LightMap buffers. */
\r
140 void scaleTCoords(scene::IMeshBuffer* buffer, const core::vector2df& factor, u32 level=1) const
\r
142 apply(SVertexTCoordsScaleManipulator(factor, level), buffer);
\r
145 //! Applies a transformation to a mesh
\r
146 /** \param mesh Mesh on which the operation is performed.
\r
147 \param m transformation matrix.
\r
148 \param normalsUpdate When 0 - don't update normals.
\r
149 When 1 - update normals with inverse transposed of the transformation matrix
\r
151 void transform(IMesh* mesh, const core::matrix4& m, u32 normalsUpdate = 0) const
\r
153 apply(SVertexPositionTransformManipulator(m), mesh, true);
\r
155 if ( normalsUpdate == 1 )
\r
157 core::matrix4 invT;
\r
158 if ( m.getInverse(invT) )
\r
160 invT = invT.getTransposed();
\r
161 apply(SVertexNormalTransformManipulator(invT), mesh, false);
\r
166 //! Applies a transformation to a meshbuffer
\r
167 /** \param buffer Meshbuffer on which the operation is performed.
\r
168 \param m transformation matrix.
\r
169 \param normalsUpdate When 0 - don't update normals.
\r
170 When 1 - update normals with inverse transposed of the transformation matrix
\r
172 void transform(IMeshBuffer* buffer, const core::matrix4& m, u32 normalsUpdate = 0) const
\r
174 apply(SVertexPositionTransformManipulator(m), buffer, true);
\r
176 if ( normalsUpdate == 1 )
\r
178 core::matrix4 invT;
\r
179 if ( m.getInverse(invT) )
\r
181 invT = invT.getTransposed();
\r
182 apply(SVertexNormalTransformManipulator(invT), buffer, false);
\r
187 //! Applies a transformation to a mesh
\r
188 /** \deprecated Use transform() instead. This method may be removed by Irrlicht 1.9
\r
189 \param mesh Mesh on which the operation is performed.
\r
190 \param m transformation matrix. */
\r
191 _IRR_DEPRECATED_ virtual void transformMesh(IMesh* mesh, const core::matrix4& m) const {return transform(mesh,m);}
\r
193 //! Creates a planar texture mapping on the mesh
\r
194 /** \param mesh: Mesh on which the operation is performed.
\r
195 \param resolution: resolution of the planar mapping. This is
\r
196 the value specifying which is the relation between world space
\r
197 and texture coordinate space. */
\r
198 virtual void makePlanarTextureMapping(IMesh* mesh, f32 resolution=0.001f) const=0;
\r
200 //! Creates a planar texture mapping on the meshbuffer
\r
201 /** \param meshbuffer: Buffer on which the operation is performed.
\r
202 \param resolution: resolution of the planar mapping. This is
\r
203 the value specifying which is the relation between world space
\r
204 and texture coordinate space. */
\r
205 virtual void makePlanarTextureMapping(scene::IMeshBuffer* meshbuffer, f32 resolution=0.001f) const=0;
\r
207 //! Creates a planar texture mapping on the buffer
\r
208 /** This method is currently implemented towards the LWO planar mapping. A more general biasing might be required.
\r
209 \param mesh Mesh on which the operation is performed.
\r
210 \param resolutionS Resolution of the planar mapping in horizontal direction. This is the ratio between object space and texture space.
\r
211 \param resolutionT Resolution of the planar mapping in vertical direction. This is the ratio between object space and texture space.
\r
212 \param axis The axis along which the texture is projected. The allowed values are 0 (X), 1(Y), and 2(Z).
\r
213 \param offset Vector added to the vertex positions (in object coordinates).
\r
215 virtual void makePlanarTextureMapping(scene::IMesh* mesh,
\r
216 f32 resolutionS, f32 resolutionT,
\r
217 u8 axis, const core::vector3df& offset) const=0;
\r
219 //! Creates a planar texture mapping on the meshbuffer
\r
220 /** This method is currently implemented towards the LWO planar mapping. A more general biasing might be required.
\r
221 \param buffer Buffer on which the operation is performed.
\r
222 \param resolutionS Resolution of the planar mapping in horizontal direction. This is the ratio between object space and texture space.
\r
223 \param resolutionT Resolution of the planar mapping in vertical direction. This is the ratio between object space and texture space.
\r
224 \param axis The axis along which the texture is projected. The allowed values are 0 (X), 1(Y), and 2(Z).
\r
225 \param offset Vector added to the vertex positions (in object coordinates).
\r
227 virtual void makePlanarTextureMapping(scene::IMeshBuffer* buffer,
\r
228 f32 resolutionS, f32 resolutionT,
\r
229 u8 axis, const core::vector3df& offset) const=0;
\r
231 //! Clones a static IMesh into a modifiable SMesh.
\r
232 /** All meshbuffers in the returned SMesh
\r
233 are of type SMeshBuffer or SMeshBufferLightMap.
\r
234 \param mesh Mesh to copy.
\r
235 \return Cloned mesh. If you no longer need the
\r
236 cloned mesh, you should call SMesh::drop(). See
\r
237 IReferenceCounted::drop() for more information. */
\r
238 virtual SMesh* createMeshCopy(IMesh* mesh) const = 0;
\r
240 //! Creates a copy of the mesh, which will only consist of S3DVertexTangents vertices.
\r
241 /** This is useful if you want to draw tangent space normal
\r
242 mapped geometry because it calculates the tangent and binormal
\r
243 data which is needed there.
\r
244 \param mesh Input mesh
\r
245 \param recalculateNormals The normals are recalculated if set,
\r
246 otherwise the original ones are kept. Note that keeping the
\r
247 normals may introduce inaccurate tangents if the normals are
\r
248 very different to those calculated from the faces.
\r
249 \param smooth The normals/tangents are smoothed across the
\r
250 meshbuffer's faces if this flag is set.
\r
251 \param angleWeighted Improved smoothing calculation used
\r
252 \param recalculateTangents Whether are actually calculated, or just the mesh with proper type is created.
\r
253 \return Mesh consisting only of S3DVertexTangents vertices. If
\r
254 you no longer need the cloned mesh, you should call
\r
255 IMesh::drop(). See IReferenceCounted::drop() for more
\r
257 virtual IMesh* createMeshWithTangents(IMesh* mesh,
\r
258 bool recalculateNormals=false, bool smooth=false,
\r
259 bool angleWeighted=false, bool recalculateTangents=true) const=0;
\r
261 //! Creates a copy of the mesh, which will only consist of S3DVertex2TCoord vertices.
\r
262 /** \param mesh Input mesh
\r
263 \return Mesh consisting only of S3DVertex2TCoord vertices. If
\r
264 you no longer need the cloned mesh, you should call
\r
265 IMesh::drop(). See IReferenceCounted::drop() for more
\r
267 virtual IMesh* createMeshWith2TCoords(IMesh* mesh) const = 0;
\r
269 //! Creates a copy of the mesh, which will only consist of S3DVertex vertices.
\r
270 /** \param mesh Input mesh
\r
271 \return Mesh consisting only of S3DVertex vertices. If
\r
272 you no longer need the cloned mesh, you should call
\r
273 IMesh::drop(). See IReferenceCounted::drop() for more
\r
275 virtual IMesh* createMeshWith1TCoords(IMesh* mesh) const = 0;
\r
277 //! Creates a copy of a mesh with all vertices unwelded
\r
278 /** \param mesh Input mesh
\r
279 \return Mesh consisting only of unique faces. All vertices
\r
280 which were previously shared are now duplicated. If you no
\r
281 longer need the cloned mesh, you should call IMesh::drop(). See
\r
282 IReferenceCounted::drop() for more information. */
\r
283 virtual IMesh* createMeshUniquePrimitives(IMesh* mesh) const = 0;
\r
285 //! Creates a copy of a mesh with vertices welded
\r
286 /** \param mesh Input mesh
\r
287 \param tolerance The threshold for vertex comparisons.
\r
288 \return Mesh without redundant vertices. If you no longer need
\r
289 the cloned mesh, you should call IMesh::drop(). See
\r
290 IReferenceCounted::drop() for more information. */
\r
291 virtual IMesh* createMeshWelded(IMesh* mesh, f32 tolerance=core::ROUNDING_ERROR_f32) const = 0;
\r
293 //! Get amount of polygons in mesh.
\r
294 /** \param mesh Input mesh
\r
295 \return Number of polygons in mesh. */
\r
296 virtual s32 getPolyCount(IMesh* mesh) const = 0;
\r
298 //! Get amount of polygons in mesh.
\r
299 /** \param mesh Input mesh
\r
300 \return Number of polygons in mesh. */
\r
301 virtual s32 getPolyCount(IAnimatedMesh* mesh) const = 0;
\r
303 //! Create a new AnimatedMesh and adds the mesh to it
\r
304 /** \param mesh Input mesh
\r
305 \param type The type of the animated mesh to create.
\r
306 \return Newly created animated mesh with mesh as its only
\r
307 content. When you don't need the animated mesh anymore, you
\r
308 should call IAnimatedMesh::drop(). See
\r
309 IReferenceCounted::drop() for more information. */
\r
310 virtual IAnimatedMesh * createAnimatedMesh(IMesh* mesh,
\r
311 scene::E_ANIMATED_MESH_TYPE type = scene::EAMT_UNKNOWN) const = 0;
\r
313 //! Vertex cache optimization according to the Forsyth paper
\r
314 /** More information can be found at
\r
315 http://home.comcast.net/~tom_forsyth/papers/fast_vert_cache_opt.html
\r
317 The function is thread-safe (read: you can optimize several
\r
318 meshes in different threads).
\r
320 \param mesh Source mesh for the operation.
\r
321 \return A new mesh optimized for the vertex cache. */
\r
322 virtual IMesh* createForsythOptimizedMesh(const IMesh *mesh) const = 0;
\r
324 //! Optimize the mesh with an algorithm tuned for heightmaps.
\r
326 This differs from usual simplification methods in two ways:
\r
327 - it's intended to be lossless
\r
328 - it has special care for the borders, which are useful with heightmap tiles
\r
330 This function is thread-safe. Remember to weld afterwards - this
\r
331 function only moves vertices, it does not weld.
\r
333 \param mesh Mesh to operate on.
\r
335 virtual void heightmapOptimizeMesh(IMesh * const mesh, const f32 tolerance = core::ROUNDING_ERROR_f32) const = 0;
\r
337 //! Optimize the meshbuffer with an algorithm tuned for heightmaps.
\r
339 This differs from usual simplification methods in two ways:
\r
340 - it's intended to be lossless
\r
341 - it has special care for the borders, which are useful with heightmap tiles
\r
343 This function is thread-safe. Remember to weld afterward - this
\r
344 function only moves vertices, it does not weld.
\r
346 \param mb Meshbuffer to operate on.
\r
348 virtual void heightmapOptimizeMesh(IMeshBuffer * const mb, const f32 tolerance = core::ROUNDING_ERROR_f32) const = 0;
\r
350 //! Apply a manipulator on the Meshbuffer
\r
351 /** \param func A functor defining the mesh manipulation.
\r
352 \param buffer The Meshbuffer to apply the manipulator to.
\r
353 \param boundingBoxUpdate Specifies if the bounding box should be updated during manipulation.
\r
354 \return True if the functor was successfully applied, else false. */
\r
355 template <typename Functor>
\r
356 bool apply(const Functor& func, IMeshBuffer* buffer, bool boundingBoxUpdate=false) const
\r
358 return apply_(func, buffer, boundingBoxUpdate, func);
\r
362 //! Apply a manipulator on the Mesh
\r
363 /** \param func A functor defining the mesh manipulation.
\r
364 \param mesh The Mesh to apply the manipulator to.
\r
365 \param boundingBoxUpdate Specifies if the bounding box should be updated during manipulation.
\r
366 \return True if the functor was successfully applied, else false. */
\r
367 template <typename Functor>
\r
368 bool apply(const Functor& func, IMesh* mesh, bool boundingBoxUpdate=false) const
\r
372 bool result = true;
\r
373 core::aabbox3df bufferbox;
\r
374 for (u32 i=0; i<mesh->getMeshBufferCount(); ++i)
\r
376 result &= apply(func, mesh->getMeshBuffer(i), boundingBoxUpdate);
\r
377 if (boundingBoxUpdate)
\r
380 bufferbox.reset(mesh->getMeshBuffer(i)->getBoundingBox());
\r
382 bufferbox.addInternalBox(mesh->getMeshBuffer(i)->getBoundingBox());
\r
385 if (boundingBoxUpdate)
\r
386 mesh->setBoundingBox(bufferbox);
\r
391 //! Apply a manipulator based on the type of the functor
\r
392 /** \param func A functor defining the mesh manipulation.
\r
393 \param buffer The Meshbuffer to apply the manipulator to.
\r
394 \param boundingBoxUpdate Specifies if the bounding box should be updated during manipulation.
\r
395 \param typeTest Unused parameter, which handles the proper call selection based on the type of the Functor which is passed in two times.
\r
396 \return True if the functor was successfully applied, else false. */
\r
397 template <typename Functor>
\r
398 bool apply_(const Functor& func, IMeshBuffer* buffer, bool boundingBoxUpdate, const IVertexManipulator& typeTest) const
\r
403 core::aabbox3df bufferbox;
\r
404 for (u32 i=0; i<buffer->getVertexCount(); ++i)
\r
406 switch (buffer->getVertexType())
\r
408 case video::EVT_STANDARD:
\r
410 video::S3DVertex* verts = (video::S3DVertex*)buffer->getVertices();
\r
414 case video::EVT_2TCOORDS:
\r
416 video::S3DVertex2TCoords* verts = (video::S3DVertex2TCoords*)buffer->getVertices();
\r
420 case video::EVT_TANGENTS:
\r
422 video::S3DVertexTangents* verts = (video::S3DVertexTangents*)buffer->getVertices();
\r
427 if (boundingBoxUpdate)
\r
430 bufferbox.reset(buffer->getPosition(0));
\r
432 bufferbox.addInternalPoint(buffer->getPosition(i));
\r
435 if (boundingBoxUpdate)
\r
436 buffer->setBoundingBox(bufferbox);
\r
441 } // end namespace scene
\r
442 } // end namespace irr
\r