1 // Copyright (C) 2002-2012 Nikolaus Gebhardt
2 // This file is part of the "Irrlicht Engine".
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
4 
5 #ifndef __I_MESH_MANIPULATOR_H_INCLUDED__
6 #define __I_MESH_MANIPULATOR_H_INCLUDED__
7 
8 #include "IReferenceCounted.h"
9 #include "vector3d.h"
10 #include "aabbox3d.h"
11 #include "matrix4.h"
12 #include "IAnimatedMesh.h"
13 #include "IMeshBuffer.h"
14 #include "SVertexManipulator.h"
15 
16 namespace irr
17 {
18 namespace scene
19 {
20 
21 	struct SMesh;
22 
23 	//! An interface for easy manipulation of meshes.
24 	/** Scale, set alpha value, flip surfaces, and so on. This exists for
25 	fixing problems with wrong imported or exported meshes quickly after
26 	loading. It is not intended for doing mesh modifications and/or
27 	animations during runtime.
28 	*/
29 	class IMeshManipulator : public virtual IReferenceCounted
30 	{
31 	public:
32 
33 		//! Flips the direction of surfaces.
34 		/** Changes backfacing triangles to frontfacing
35 		triangles and vice versa.
36 		\param mesh Mesh on which the operation is performed. */
37 		virtual void flipSurfaces(IMesh* mesh) const = 0;
38 
39 		//! Sets the alpha vertex color value of the whole mesh to a new value.
40 		/** \param mesh Mesh on which the operation is performed.
41 		\param alpha New alpha value. Must be a value between 0 and 255. */
setVertexColorAlpha(IMesh * mesh,s32 alpha)42 		void setVertexColorAlpha(IMesh* mesh, s32 alpha) const
43 		{
44 			apply(scene::SVertexColorSetAlphaManipulator(alpha), mesh);
45 		}
46 
47 		//! Sets the alpha vertex color value of the whole mesh to a new value.
48 		/** \param buffer Meshbuffer on which the operation is performed.
49 		\param alpha New alpha value. Must be a value between 0 and 255. */
setVertexColorAlpha(IMeshBuffer * buffer,s32 alpha)50 		void setVertexColorAlpha(IMeshBuffer* buffer, s32 alpha) const
51 		{
52 			apply(scene::SVertexColorSetAlphaManipulator(alpha), buffer);
53 		}
54 
55 		//! Sets the colors of all vertices to one color
56 		/** \param mesh Mesh on which the operation is performed.
57 		\param color New color. */
setVertexColors(IMesh * mesh,video::SColor color)58 		void setVertexColors(IMesh* mesh, video::SColor color) const
59 		{
60 			apply(scene::SVertexColorSetManipulator(color), mesh);
61 		}
62 
63 		//! Sets the colors of all vertices to one color
64 		/** \param buffer Meshbuffer on which the operation is performed.
65 		\param color New color. */
setVertexColors(IMeshBuffer * buffer,video::SColor color)66 		void setVertexColors(IMeshBuffer* buffer, video::SColor color) const
67 		{
68 			apply(scene::SVertexColorSetManipulator(color), buffer);
69 		}
70 
71 		//! Recalculates all normals of the mesh.
72 		/** \param mesh: Mesh on which the operation is performed.
73 		\param smooth: If the normals shall be smoothed.
74 		\param angleWeighted: If the normals shall be smoothed in relation to their angles. More expensive, but also higher precision. */
75 		virtual void recalculateNormals(IMesh* mesh, bool smooth = false,
76 				bool angleWeighted = false) const=0;
77 
78 		//! Recalculates all normals of the mesh buffer.
79 		/** \param buffer: Mesh buffer on which the operation is performed.
80 		\param smooth: If the normals shall be smoothed.
81 		\param angleWeighted: If the normals shall be smoothed in relation to their angles. More expensive, but also higher precision. */
82 		virtual void recalculateNormals(IMeshBuffer* buffer,
83 				bool smooth = false, bool angleWeighted = false) const=0;
84 
85 		//! Recalculates tangents, requires a tangent mesh
86 		/** \param mesh Mesh on which the operation is performed.
87 		\param recalculateNormals If the normals shall be recalculated, otherwise original normals of the mesh are used unchanged.
88 		\param smooth If the normals shall be smoothed.
89 		\param angleWeighted If the normals shall be smoothed in relation to their angles. More expensive, but also higher precision.
90 		*/
91 		virtual void recalculateTangents(IMesh* mesh,
92 				bool recalculateNormals=false, bool smooth=false,
93 				bool angleWeighted=false) const=0;
94 
95 		//! Recalculates tangents, requires a tangent mesh buffer
96 		/** \param buffer Meshbuffer on which the operation is performed.
97 		\param recalculateNormals If the normals shall be recalculated, otherwise original normals of the buffer are used unchanged.
98 		\param smooth If the normals shall be smoothed.
99 		\param angleWeighted If the normals shall be smoothed in relation to their angles. More expensive, but also higher precision.
100 		*/
101 		virtual void recalculateTangents(IMeshBuffer* buffer,
102 				bool recalculateNormals=false, bool smooth=false,
103 				bool angleWeighted=false) const=0;
104 
105 		//! Scales the actual mesh, not a scene node.
106 		/** \param mesh Mesh on which the operation is performed.
107 		\param factor Scale factor for each axis. */
scale(IMesh * mesh,const core::vector3df & factor)108 		void scale(IMesh* mesh, const core::vector3df& factor) const
109 		{
110 			apply(SVertexPositionScaleManipulator(factor), mesh, true);
111 		}
112 
113 		//! Scales the actual meshbuffer, not a scene node.
114 		/** \param buffer Meshbuffer on which the operation is performed.
115 		\param factor Scale factor for each axis. */
scale(IMeshBuffer * buffer,const core::vector3df & factor)116 		void scale(IMeshBuffer* buffer, const core::vector3df& factor) const
117 		{
118 			apply(SVertexPositionScaleManipulator(factor), buffer, true);
119 		}
120 
121 		//! Scales the actual mesh, not a scene node.
122 		/** \deprecated Use scale() instead. This method may be removed by Irrlicht 1.9
123 		\param mesh Mesh on which the operation is performed.
124 		\param factor Scale factor for each axis. */
scaleMesh(IMesh * mesh,const core::vector3df & factor)125 		_IRR_DEPRECATED_ void scaleMesh(IMesh* mesh, const core::vector3df& factor) const {return scale(mesh,factor);}
126 
127 		//! Scale the texture coords of a mesh.
128 		/** \param mesh Mesh on which the operation is performed.
129 		\param factor Vector which defines the scale for each axis.
130 		\param level Number of texture coord, starting from 1. Support for level 2 exists for LightMap buffers. */
131 		void scaleTCoords(scene::IMesh* mesh, const core::vector2df& factor, u32 level=1) const
132 		{
133 			apply(SVertexTCoordsScaleManipulator(factor, level), mesh);
134 		}
135 
136 		//! Scale the texture coords of a meshbuffer.
137 		/** \param buffer Meshbuffer on which the operation is performed.
138 		\param factor Vector which defines the scale for each axis.
139 		\param level Number of texture coord, starting from 1. Support for level 2 exists for LightMap buffers. */
140 		void scaleTCoords(scene::IMeshBuffer* buffer, const core::vector2df& factor, u32 level=1) const
141 		{
142 			apply(SVertexTCoordsScaleManipulator(factor, level), buffer);
143 		}
144 
145 		//! Applies a transformation to a mesh
146 		/** \param mesh Mesh on which the operation is performed.
147 		\param m transformation matrix. */
transform(IMesh * mesh,const core::matrix4 & m)148 		void transform(IMesh* mesh, const core::matrix4& m) const
149 		{
150 			apply(SVertexPositionTransformManipulator(m), mesh, true);
151 		}
152 
153 		//! Applies a transformation to a meshbuffer
154 		/** \param buffer Meshbuffer on which the operation is performed.
155 		\param m transformation matrix. */
transform(IMeshBuffer * buffer,const core::matrix4 & m)156 		void transform(IMeshBuffer* buffer, const core::matrix4& m) const
157 		{
158 			apply(SVertexPositionTransformManipulator(m), buffer, true);
159 		}
160 
161 		//! Applies a transformation to a mesh
162 		/** \deprecated Use transform() instead. This method may be removed by Irrlicht 1.9
163 		\param mesh Mesh on which the operation is performed.
164 		\param m transformation matrix. */
transformMesh(IMesh * mesh,const core::matrix4 & m)165 		_IRR_DEPRECATED_ virtual void transformMesh(IMesh* mesh, const core::matrix4& m) const {return transform(mesh,m);}
166 
167 		//! Creates a planar texture mapping on the mesh
168 		/** \param mesh: Mesh on which the operation is performed.
169 		\param resolution: resolution of the planar mapping. This is
170 		the value specifying which is the relation between world space
171 		and texture coordinate space. */
172 		virtual void makePlanarTextureMapping(IMesh* mesh, f32 resolution=0.001f) const=0;
173 
174 		//! Creates a planar texture mapping on the meshbuffer
175 		/** \param meshbuffer: Buffer on which the operation is performed.
176 		\param resolution: resolution of the planar mapping. This is
177 		the value specifying which is the relation between world space
178 		and texture coordinate space. */
179 		virtual void makePlanarTextureMapping(scene::IMeshBuffer* meshbuffer, f32 resolution=0.001f) const=0;
180 
181 		//! Creates a planar texture mapping on the buffer
182 		/** This method is currently implemented towards the LWO planar mapping. A more general biasing might be required.
183 		\param mesh Mesh on which the operation is performed.
184 		\param resolutionS Resolution of the planar mapping in horizontal direction. This is the ratio between object space and texture space.
185 		\param resolutionT Resolution of the planar mapping in vertical direction. This is the ratio between object space and texture space.
186 		\param axis The axis along which the texture is projected. The allowed values are 0 (X), 1(Y), and 2(Z).
187 		\param offset Vector added to the vertex positions (in object coordinates).
188 		*/
189 		virtual void makePlanarTextureMapping(scene::IMesh* mesh,
190 				f32 resolutionS, f32 resolutionT,
191 				u8 axis, const core::vector3df& offset) const=0;
192 
193 		//! Creates a planar texture mapping on the meshbuffer
194 		/** This method is currently implemented towards the LWO planar mapping. A more general biasing might be required.
195 		\param buffer Buffer on which the operation is performed.
196 		\param resolutionS Resolution of the planar mapping in horizontal direction. This is the ratio between object space and texture space.
197 		\param resolutionT Resolution of the planar mapping in vertical direction. This is the ratio between object space and texture space.
198 		\param axis The axis along which the texture is projected. The allowed values are 0 (X), 1(Y), and 2(Z).
199 		\param offset Vector added to the vertex positions (in object coordinates).
200 		*/
201 		virtual void makePlanarTextureMapping(scene::IMeshBuffer* buffer,
202 				f32 resolutionS, f32 resolutionT,
203 				u8 axis, const core::vector3df& offset) const=0;
204 
205 		//! Clones a static IMesh into a modifiable SMesh.
206 		/** All meshbuffers in the returned SMesh
207 		are of type SMeshBuffer or SMeshBufferLightMap.
208 		\param mesh Mesh to copy.
209 		\return Cloned mesh. If you no longer need the
210 		cloned mesh, you should call SMesh::drop(). See
211 		IReferenceCounted::drop() for more information. */
212 		virtual SMesh* createMeshCopy(IMesh* mesh) const = 0;
213 
214 		//! Creates a copy of the mesh, which will only consist of S3DVertexTangents vertices.
215 		/** This is useful if you want to draw tangent space normal
216 		mapped geometry because it calculates the tangent and binormal
217 		data which is needed there.
218 		\param mesh Input mesh
219 		\param recalculateNormals The normals are recalculated if set,
220 		otherwise the original ones are kept. Note that keeping the
221 		normals may introduce inaccurate tangents if the normals are
222 		very different to those calculated from the faces.
223 		\param smooth The normals/tangents are smoothed across the
224 		meshbuffer's faces if this flag is set.
225 		\param angleWeighted Improved smoothing calculation used
226 		\param recalculateTangents Whether are actually calculated, or just the mesh with proper type is created.
227 		\return Mesh consisting only of S3DVertexTangents vertices. If
228 		you no longer need the cloned mesh, you should call
229 		IMesh::drop(). See IReferenceCounted::drop() for more
230 		information. */
231 		virtual IMesh* createMeshWithTangents(IMesh* mesh,
232 				bool recalculateNormals=false, bool smooth=false,
233 				bool angleWeighted=false, bool recalculateTangents=true) const=0;
234 
235 		//! Creates a copy of the mesh, which will only consist of S3DVertex2TCoord vertices.
236 		/** \param mesh Input mesh
237 		\return Mesh consisting only of S3DVertex2TCoord vertices. If
238 		you no longer need the cloned mesh, you should call
239 		IMesh::drop(). See IReferenceCounted::drop() for more
240 		information. */
241 		virtual IMesh* createMeshWith2TCoords(IMesh* mesh) const = 0;
242 
243 		//! Creates a copy of the mesh, which will only consist of S3DVertex vertices.
244 		/** \param mesh Input mesh
245 		\return Mesh consisting only of S3DVertex vertices. If
246 		you no longer need the cloned mesh, you should call
247 		IMesh::drop(). See IReferenceCounted::drop() for more
248 		information. */
249 		virtual IMesh* createMeshWith1TCoords(IMesh* mesh) const = 0;
250 
251 		//! Creates a copy of a mesh with all vertices unwelded
252 		/** \param mesh Input mesh
253 		\return Mesh consisting only of unique faces. All vertices
254 		which were previously shared are now duplicated. If you no
255 		longer need the cloned mesh, you should call IMesh::drop(). See
256 		IReferenceCounted::drop() for more information. */
257 		virtual IMesh* createMeshUniquePrimitives(IMesh* mesh) const = 0;
258 
259 		//! Creates a copy of a mesh with vertices welded
260 		/** \param mesh Input mesh
261 		\param tolerance The threshold for vertex comparisons.
262 		\return Mesh without redundant vertices. If you no longer need
263 		the cloned mesh, you should call IMesh::drop(). See
264 		IReferenceCounted::drop() for more information. */
265 		virtual IMesh* createMeshWelded(IMesh* mesh, f32 tolerance=core::ROUNDING_ERROR_f32) const = 0;
266 
267 		//! Get amount of polygons in mesh.
268 		/** \param mesh Input mesh
269 		\return Number of polygons in mesh. */
270 		virtual s32 getPolyCount(IMesh* mesh) const = 0;
271 
272 		//! Get amount of polygons in mesh.
273 		/** \param mesh Input mesh
274 		\return Number of polygons in mesh. */
275 		virtual s32 getPolyCount(IAnimatedMesh* mesh) const = 0;
276 
277 		//! Create a new AnimatedMesh and adds the mesh to it
278 		/** \param mesh Input mesh
279 		\param type The type of the animated mesh to create.
280 		\return Newly created animated mesh with mesh as its only
281 		content. When you don't need the animated mesh anymore, you
282 		should call IAnimatedMesh::drop(). See
283 		IReferenceCounted::drop() for more information. */
284 		virtual IAnimatedMesh * createAnimatedMesh(IMesh* mesh,
285 			scene::E_ANIMATED_MESH_TYPE type = scene::EAMT_UNKNOWN) const = 0;
286 
287 		//! Vertex cache optimization according to the Forsyth paper
288 		/** More information can be found at
289 		http://home.comcast.net/~tom_forsyth/papers/fast_vert_cache_opt.html
290 
291 		The function is thread-safe (read: you can optimize several
292 		meshes in different threads).
293 
294 		\param mesh Source mesh for the operation.
295 		\return A new mesh optimized for the vertex cache. */
296 		virtual IMesh* createForsythOptimizedMesh(const IMesh *mesh) const = 0;
297 
298 		//! Apply a manipulator on the Meshbuffer
299 		/** \param func A functor defining the mesh manipulation.
300 		\param buffer The Meshbuffer to apply the manipulator to.
301 		\param boundingBoxUpdate Specifies if the bounding box should be updated during manipulation.
302 		\return True if the functor was successfully applied, else false. */
303 		template <typename Functor>
304 		bool apply(const Functor& func, IMeshBuffer* buffer, bool boundingBoxUpdate=false) const
305 		{
306 			return apply_(func, buffer, boundingBoxUpdate, func);
307 		}
308 
309 
310 		//! Apply a manipulator on the Mesh
311 		/** \param func A functor defining the mesh manipulation.
312 		\param mesh The Mesh to apply the manipulator to.
313 		\param boundingBoxUpdate Specifies if the bounding box should be updated during manipulation.
314 		\return True if the functor was successfully applied, else false. */
315 		template <typename Functor>
316 		bool apply(const Functor& func, IMesh* mesh, bool boundingBoxUpdate=false) const
317 		{
318 			if (!mesh)
319 				return true;
320 			bool result = true;
321 			core::aabbox3df bufferbox;
322 			for (u32 i=0; i<mesh->getMeshBufferCount(); ++i)
323 			{
324 				result &= apply(func, mesh->getMeshBuffer(i), boundingBoxUpdate);
325 				if (boundingBoxUpdate)
326 				{
327 					if (0==i)
328 						bufferbox.reset(mesh->getMeshBuffer(i)->getBoundingBox());
329 					else
330 						bufferbox.addInternalBox(mesh->getMeshBuffer(i)->getBoundingBox());
331 				}
332 			}
333 			if (boundingBoxUpdate)
334 				mesh->setBoundingBox(bufferbox);
335 			return result;
336 		}
337 
338 protected:
339 		//! Apply a manipulator based on the type of the functor
340 		/** \param func A functor defining the mesh manipulation.
341 		\param buffer The Meshbuffer to apply the manipulator to.
342 		\param boundingBoxUpdate Specifies if the bounding box should be updated during manipulation.
343 		\param typeTest Unused parameter, which handles the proper call selection based on the type of the Functor which is passed in two times.
344 		\return True if the functor was successfully applied, else false. */
345 		template <typename Functor>
apply_(const Functor & func,IMeshBuffer * buffer,bool boundingBoxUpdate,const IVertexManipulator & typeTest)346 		bool apply_(const Functor& func, IMeshBuffer* buffer, bool boundingBoxUpdate, const IVertexManipulator& typeTest) const
347 		{
348 			if (!buffer)
349 				return true;
350 
351 			core::aabbox3df bufferbox;
352 			for (u32 i=0; i<buffer->getVertexCount(); ++i)
353 			{
354 				switch (buffer->getVertexType())
355 				{
356 				case video::EVT_STANDARD:
357 					{
358 						video::S3DVertex* verts = (video::S3DVertex*)buffer->getVertices();
359 						func(verts[i]);
360 					}
361 					break;
362 				case video::EVT_2TCOORDS:
363 					{
364 						video::S3DVertex2TCoords* verts = (video::S3DVertex2TCoords*)buffer->getVertices();
365 						func(verts[i]);
366 					}
367 					break;
368 				case video::EVT_TANGENTS:
369 					{
370 						video::S3DVertexTangents* verts = (video::S3DVertexTangents*)buffer->getVertices();
371 						func(verts[i]);
372 					}
373 					break;
374 				}
375 				if (boundingBoxUpdate)
376 				{
377 					if (0==i)
378 						bufferbox.reset(buffer->getPosition(0));
379 					else
380 						bufferbox.addInternalPoint(buffer->getPosition(i));
381 				}
382 			}
383 			if (boundingBoxUpdate)
384 				buffer->setBoundingBox(bufferbox);
385 			return true;
386 		}
387 };
388 
389 } // end namespace scene
390 } // end namespace irr
391 
392 
393 #endif
394