/*
								+----------------------------------+
								|                                  |
								|  ***  Texcoords generators  ***  |
								|                                  |
								|   Copyright © -tHE SWINe- 2007   |
								|                                  |
								|           TexCoords.h            |
								|                                  |
								+----------------------------------+
*/

#pragma once
#ifndef __TEXCOORDS_GENERATOR_INCLUDED
#define __TEXCOORDS_GENERATOR_INCLUDED

/**
 *	@file lml/TexCoords.h
 *	@date 2007
 *	@author -tHE SWINe-
 *	@brief texcoords generators
 *
 *	@date 2008-06-24
 *
 *	renamed CPolygon2::r_t_Vertex() and CPolyMesh::r_t_Vertex() to
 *	CPolygon2::r_Vertex() and CPolyMesh::r_Vertex() respectively
 *
 *	@date 2008-08-21
 *
 *	unified gizmo semantics, unit gizmo matrix should transform mesh bounding
 *	box to axis-aligned unit cube with one of corners at O and some other one at (1, 1, 1)
 *
 *	removed map_Cylinder_Caps cap texcoord scaling
 *
 *	added CTexCoordGen::t_Gizmo() for calculating unit gizmo matrix
 *
 *	@date 2009-05-23
 *
 *	removed all instances of std::vector::reserve and replaced them by stl_ut::Reserve_*
 *
 *	@date 2009-10-20
 *
 *	fixed some warnings when compiling under VC 2005, implemented "Security
 *	Enhancements in the CRT" for VC 2008. compare against MyProjects_2009-10-19_
 *
 *	@date 2012-06-19
 *
 *	Moved multiple inclusion guard before file documentation comment.
 *
 */

#include "PolyMesh.h"

/**
 *	@brief texture coordinate generators class
 */
class CTexCoordGen {
public:
	/**
	 *	@brief mapping types
	 */
	enum {
		map_Plane, /**< @brief plane mapping */
		map_Box, /**< @brief box mapping */
		map_Sphere, /**< @brief spherical mapping */
		map_Cylinder, /**< @brief cylindrical mapping */
		map_Cylinder_Caps /**< @brief cylindrical mapping with an additional plane mapping for cylinder caps */
	};

	/**
	 *	@brief creates (unit) textcoord mapping gizmo for a given mesh
	 *	@param[in] r_mesh is a mesh for which to calculate the mapping gizmo
	 *	@return Returns a matrix for transforming vertex positions to positions
	 *		inside the mapping gizmo. It wraps the entire mesh.
	 *	@note This calls CPolyMesh::BoundingBox() internally, in case the bounding box is available,
	 *		a call to t_Gizmo(Vector3f, Vector3f) should be more efficient.
	 */
	static Matrix4f t_Gizmo(const CPolyMesh &r_mesh);

	/**
	 *	@brief creates (unit) textcoord mapping gizmo for a given bounding box
	 *
	 *	@param[in] v_min is the minimal coordinate of the bounding box
	 *	@param[in] v_max is the maximal coordinate of the bounding box
	 *
	 *	@return Returns a matrix for transforming vertex positions to positions
	 *		inside the mapping gizmo. It wraps the entire bounding box.
	 */
	static Matrix4f t_Gizmo(Vector3f v_min, Vector3f v_max);

	/**
	 *	@brief calculates 2D texcoords for a given mesh
	 *
	 *	@param[in,out] r_mesh is a mesh for which to calculate the texture coordinates
	 *	@param[in] t_gizmo_transform is a matrix for transforming vertex positions to positions
	 *		inside the mapping gizmo (such transformation that vertex coordinates are transformed
	 *		to unit cube with center at (.5, .5, .5))
	 *	@param[in] n_map_type is the type of mapping (one of map_Plane, map_Box, map_Sphere,
	 *		map_Cylinder or map_Cylinder_Caps)
	 *	@param[in] n_channel is zero-based index of the output texture channel
	 *		(see CMesh::_TyVertex for the number of texture channels)
	 *	@param[in] n_coord_s is zero-based index of vector component to store the s coordinate (0 - 3)
	 *	@param[in] n_coord_t is zero-based index of vector component to store the t coordinate (0 - 3)
	 *
	 *	@return Returns true on success, false on failure (not enough memory for auxiliary tables).
	 *
	 *	@note Note that map_Box and map_Cylinder_Caps require correct polygon normals.
	 *	@note All the mapping types except map_Plane explode vertices.
	 */
	static bool CalcTexcoords(CPolyMesh &r_mesh, Matrix4f t_gizmo_transform,
		int n_map_type, int n_channel, int n_coord_s = 0, int n_coord_t = 1);

	/**
	 *	@brief calculates tangent vectors of a given texture coordinates
	 *
	 *	This takes 2D texture coordinates as input, and given vertex positions and normals,
	 *	it calculates tangent vectors of the texture coordinates (vectors pointing in the
	 *	direction of the positive s axis of the texture as it is mapped in the vicinity
	 *	of each particular vertex). Note that the face normals are also needed.
	 *
	 *	This also performs some smoothing of the tangents as each vertex possibly belongs
	 *	to several different faces, each of which can have (slightly) different binormal
	 *	vector. To avoid unwanted smoothing, this function defines maximal angular threshold
	 *	beyond which it will not attempt to smooth, and also defines masks for material
	 *	and for surface flags comparison in order to avoid smoothing vertices from different
	 *	face groups. If all should be smoothed, the masks should be set to zero and the angle
	 *	threshold should be set to f_pi.
	 *
	 *	@param[in,out] r_mesh is a mesh for which to calculate the tangent vectors
	 *	@param[in] n_channel_in is the channel containing the input texture coordinates
	 *	@param[in] n_coord_s is the input s texture coordinate
	 *	@param[in] n_coord_t is the input t texture coordinate
	 *	@param[in] n_channel_out is zero-based index of a channel to contain (normalized)
	 *		binormal direction and texture polarity (takes up the whole channel)
	 *	@param[in] f_angle_thresh is the minimal angle between tangents of faces
	 *		for their vertices to break
	 *	@param[in] n_face_flags_mask is mask for face flags that contains significant
	 *		bits that identify the same material group
	 *	@param[in] n_face_material_mask is mask for material that contains significant
	 *		bits that identify the same material group
	 *
	 *	@return Returns true on success, false on failure (not enough memory for auxiliary tables).
	 *
	 *	@note Make sure to call CPolyMesh::ExplodeVertices() on r_mesh before calling
	 *		this function.
	 *	@note The texture polarity is set to either 1 or -1, and both face and vertex normals
	 *		must be up to date in order to be able to calculate it properly.
	 */
	static bool CalcTangents(CPolyMesh &r_mesh, int n_channel_in,
		int n_coord_s, int n_coord_t, int n_channel_out, float f_angle_thresh = f_pi * .125f,
		CPolyMesh::TSurfaceFlags n_surface_flags_mask = -1,
		CPolyMesh::TMaterialId n_face_material_mask = -1);

protected:
	template <class CCoordSelector>
	static void CalcAzimuth(const std::vector<Vector3f> &r_pos_list,
		std::vector<float> &r_azimuth_list, CCoordSelector selector);
};

#endif // !__TEXCOORDS_GENERATOR_INCLUDED
