| 
									
										
										
										
											2017-05-24 22:33:21 +10:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * ***** BEGIN GPL LICENSE BLOCK ***** | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software; you can redistribute it and/or | 
					
						
							|  |  |  |  * modify it under the terms of the GNU General Public License | 
					
						
							|  |  |  |  * as published by the Free Software Foundation; either version 2 | 
					
						
							|  |  |  |  * of the License, or (at your option) any later version. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |  * GNU General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  |  * along with this program; if not, write to the Free Software Foundation, | 
					
						
							|  |  |  |  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. | 
					
						
							|  |  |  |  * All rights reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Contributor(s): Blender Foundation | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * ***** END GPL LICENSE BLOCK ***** | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** \file blender/blenkernel/intern/mesh_tangent.c
 | 
					
						
							|  |  |  |  *  \ingroup bke | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Functions to evaluate mesh tangents. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <limits.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "MEM_guardedalloc.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "DNA_mesh_types.h"
 | 
					
						
							|  |  |  | #include "DNA_meshdata_types.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "BLI_utildefines.h"
 | 
					
						
							|  |  |  | #include "BLI_math.h"
 | 
					
						
							|  |  |  | #include "BLI_stack.h"
 | 
					
						
							|  |  |  | #include "BLI_task.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "BKE_customdata.h"
 | 
					
						
							|  |  |  | #include "BKE_global.h"
 | 
					
						
							|  |  |  | #include "BKE_mesh.h"
 | 
					
						
							|  |  |  | #include "BKE_mesh_tangent.h"
 | 
					
						
							|  |  |  | #include "BKE_report.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "BLI_strict_flags.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "atomic_ops.h"
 | 
					
						
							|  |  |  | #include "mikktspace.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* -------------------------------------------------------------------- */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** \name Mesh Tangent Calculations (Single Layer)
 | 
					
						
							|  |  |  |  * \{ */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Tangent space utils. */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* User data. */ | 
					
						
							|  |  |  | typedef struct { | 
					
						
							|  |  |  | 	const MPoly *mpolys;   /* faces */ | 
					
						
							|  |  |  | 	const MLoop *mloops;   /* faces's vertices */ | 
					
						
							|  |  |  | 	const MVert *mverts;   /* vertices */ | 
					
						
							|  |  |  | 	const MLoopUV *luvs;   /* texture coordinates */ | 
					
						
							|  |  |  | 	float (*lnors)[3];     /* loops' normals */ | 
					
						
							|  |  |  | 	float (*tangents)[4];  /* output tangents */ | 
					
						
							|  |  |  | 	int num_polys;         /* number of polygons */ | 
					
						
							|  |  |  | } BKEMeshToTangent; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Mikktspace's API */ | 
					
						
							|  |  |  | static int get_num_faces(const SMikkTSpaceContext *pContext) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData; | 
					
						
							|  |  |  | 	return p_mesh->num_polys; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int get_num_verts_of_face(const SMikkTSpaceContext *pContext, const int face_idx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData; | 
					
						
							|  |  |  | 	return p_mesh->mpolys[face_idx].totloop; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void get_position(const SMikkTSpaceContext *pContext, float r_co[3], const int face_idx, const int vert_idx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData; | 
					
						
							|  |  |  | 	const int loop_idx = p_mesh->mpolys[face_idx].loopstart + vert_idx; | 
					
						
							|  |  |  | 	copy_v3_v3(r_co, p_mesh->mverts[p_mesh->mloops[loop_idx].v].co); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void get_texture_coordinate(const SMikkTSpaceContext *pContext, float r_uv[2], const int face_idx, | 
					
						
							|  |  |  |                                    const int vert_idx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData; | 
					
						
							|  |  |  | 	copy_v2_v2(r_uv, p_mesh->luvs[p_mesh->mpolys[face_idx].loopstart + vert_idx].uv); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void get_normal(const SMikkTSpaceContext *pContext, float r_no[3], const int face_idx, const int vert_idx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData; | 
					
						
							|  |  |  | 	copy_v3_v3(r_no, p_mesh->lnors[p_mesh->mpolys[face_idx].loopstart + vert_idx]); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void set_tspace(const SMikkTSpaceContext *pContext, const float fv_tangent[3], const float face_sign, | 
					
						
							|  |  |  |                        const int face_idx, const int vert_idx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData; | 
					
						
							|  |  |  | 	float *p_res = p_mesh->tangents[p_mesh->mpolys[face_idx].loopstart + vert_idx]; | 
					
						
							|  |  |  | 	copy_v3_v3(p_res, fv_tangent); | 
					
						
							|  |  |  | 	p_res[3] = face_sign; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * Compute simplified tangent space normals, i.e. tangent vector + sign of bi-tangent one, which combined with | 
					
						
							|  |  |  |  * split normals can be used to recreate the full tangent space. | 
					
						
							|  |  |  |  * Note: * The mesh should be made of only tris and quads! | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | void BKE_mesh_calc_loop_tangent_single_ex( | 
					
						
							|  |  |  |         const MVert *mverts, const int UNUSED(numVerts), const MLoop *mloops, | 
					
						
							|  |  |  |         float (*r_looptangent)[4], float (*loopnors)[3], const MLoopUV *loopuvs, | 
					
						
							|  |  |  |         const int UNUSED(numLoops), const MPoly *mpolys, const int numPolys, | 
					
						
							|  |  |  |         ReportList *reports) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	BKEMeshToTangent mesh_to_tangent = {NULL}; | 
					
						
							|  |  |  | 	SMikkTSpaceContext s_context = {NULL}; | 
					
						
							|  |  |  | 	SMikkTSpaceInterface s_interface = {NULL}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const MPoly *mp; | 
					
						
							|  |  |  | 	int mp_index; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* First check we do have a tris/quads only mesh. */ | 
					
						
							|  |  |  | 	for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) { | 
					
						
							|  |  |  | 		if (mp->totloop > 4) { | 
					
						
							|  |  |  | 			BKE_report(reports, RPT_ERROR, "Tangent space can only be computed for tris/quads, aborting"); | 
					
						
							|  |  |  | 			return; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Compute Mikktspace's tangent normals. */ | 
					
						
							|  |  |  | 	mesh_to_tangent.mpolys = mpolys; | 
					
						
							|  |  |  | 	mesh_to_tangent.mloops = mloops; | 
					
						
							|  |  |  | 	mesh_to_tangent.mverts = mverts; | 
					
						
							|  |  |  | 	mesh_to_tangent.luvs = loopuvs; | 
					
						
							|  |  |  | 	mesh_to_tangent.lnors = loopnors; | 
					
						
							|  |  |  | 	mesh_to_tangent.tangents = r_looptangent; | 
					
						
							|  |  |  | 	mesh_to_tangent.num_polys = numPolys; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	s_context.m_pUserData = &mesh_to_tangent; | 
					
						
							|  |  |  | 	s_context.m_pInterface = &s_interface; | 
					
						
							|  |  |  | 	s_interface.m_getNumFaces = get_num_faces; | 
					
						
							|  |  |  | 	s_interface.m_getNumVerticesOfFace = get_num_verts_of_face; | 
					
						
							|  |  |  | 	s_interface.m_getPosition = get_position; | 
					
						
							|  |  |  | 	s_interface.m_getTexCoord = get_texture_coordinate; | 
					
						
							|  |  |  | 	s_interface.m_getNormal = get_normal; | 
					
						
							|  |  |  | 	s_interface.m_setTSpaceBasic = set_tspace; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* 0 if failed */ | 
					
						
							|  |  |  | 	if (genTangSpaceDefault(&s_context) == false) { | 
					
						
							|  |  |  | 		BKE_report(reports, RPT_ERROR, "Mikktspace failed to generate tangents for this mesh!"); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * Wrapper around BKE_mesh_calc_loop_tangent_single_ex, which takes care of most boiling code. | 
					
						
							|  |  |  |  * \note | 
					
						
							|  |  |  |  * - There must be a valid loop's CD_NORMALS available. | 
					
						
							|  |  |  |  * - The mesh should be made of only tris and quads! | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | void BKE_mesh_calc_loop_tangent_single(Mesh *mesh, const char *uvmap, float (*r_looptangents)[4], ReportList *reports) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	MLoopUV *loopuvs; | 
					
						
							|  |  |  | 	float (*loopnors)[3]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Check we have valid texture coordinates first! */ | 
					
						
							|  |  |  | 	if (uvmap) { | 
					
						
							|  |  |  | 		loopuvs = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvmap); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else { | 
					
						
							|  |  |  | 		loopuvs = CustomData_get_layer(&mesh->ldata, CD_MLOOPUV); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (!loopuvs) { | 
					
						
							|  |  |  | 		BKE_reportf(reports, RPT_ERROR, "Tangent space computation needs an UVMap, \"%s\" not found, aborting", uvmap); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	loopnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL); | 
					
						
							|  |  |  | 	if (!loopnors) { | 
					
						
							|  |  |  | 		BKE_report(reports, RPT_ERROR, "Tangent space computation needs loop normals, none found, aborting"); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	BKE_mesh_calc_loop_tangent_single_ex(mesh->mvert, mesh->totvert, mesh->mloop, r_looptangents, | 
					
						
							|  |  |  | 	                          loopnors, loopuvs, mesh->totloop, mesh->mpoly, mesh->totpoly, reports); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** \} */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* -------------------------------------------------------------------- */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** \name Mesh Tangent Calculations (All Layers)
 | 
					
						
							|  |  |  |  * \{ */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Necessary complexity to handle looptri's as quads for correct tangents */ | 
					
						
							|  |  |  | #define USE_LOOPTRI_DETECT_QUADS
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct { | 
					
						
							|  |  |  | 	const float (*precomputedFaceNormals)[3]; | 
					
						
							|  |  |  | 	const float (*precomputedLoopNormals)[3]; | 
					
						
							|  |  |  | 	const MLoopTri *looptri; | 
					
						
							|  |  |  | 	MLoopUV *mloopuv;   /* texture coordinates */ | 
					
						
							|  |  |  | 	const MPoly *mpoly;       /* indices */ | 
					
						
							|  |  |  | 	const MLoop *mloop;       /* indices */ | 
					
						
							|  |  |  | 	const MVert *mvert;       /* vertices & normals */ | 
					
						
							|  |  |  | 	const float (*orco)[3]; | 
					
						
							|  |  |  | 	float (*tangent)[4];    /* destination */ | 
					
						
							|  |  |  | 	int numTessFaces; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef USE_LOOPTRI_DETECT_QUADS
 | 
					
						
							|  |  |  | 	/* map from 'fake' face index to looptri,
 | 
					
						
							|  |  |  | 	 * quads will point to the first looptri of the quad */ | 
					
						
							|  |  |  | 	const int    *face_as_quad_map; | 
					
						
							|  |  |  | 	int       num_face_as_quad_map; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } SGLSLMeshToTangent; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* interface */ | 
					
						
							|  |  |  | #include "mikktspace.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int dm_ts_GetNumFaces(const SMikkTSpaceContext *pContext) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	SGLSLMeshToTangent *pMesh = pContext->m_pUserData; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef USE_LOOPTRI_DETECT_QUADS
 | 
					
						
							|  |  |  | 	return pMesh->num_face_as_quad_map; | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | 	return pMesh->numTessFaces; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int dm_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | #ifdef USE_LOOPTRI_DETECT_QUADS
 | 
					
						
							|  |  |  | 	SGLSLMeshToTangent *pMesh = pContext->m_pUserData; | 
					
						
							|  |  |  | 	if (pMesh->face_as_quad_map) { | 
					
						
							|  |  |  | 		const MLoopTri *lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]]; | 
					
						
							|  |  |  | 		const MPoly *mp = &pMesh->mpoly[lt->poly]; | 
					
						
							|  |  |  | 		if (mp->totloop == 4) { | 
					
						
							|  |  |  | 			return 4; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 3; | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | 	UNUSED_VARS(pContext, face_num); | 
					
						
							|  |  |  | 	return 3; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void dm_ts_GetPosition( | 
					
						
							|  |  |  |         const SMikkTSpaceContext *pContext, float r_co[3], | 
					
						
							|  |  |  |         const int face_num, const int vert_index) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	//assert(vert_index >= 0 && vert_index < 4);
 | 
					
						
							|  |  |  | 	SGLSLMeshToTangent *pMesh = pContext->m_pUserData; | 
					
						
							|  |  |  | 	const MLoopTri *lt; | 
					
						
							|  |  |  | 	uint loop_index; | 
					
						
							|  |  |  | 	const float *co; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef USE_LOOPTRI_DETECT_QUADS
 | 
					
						
							|  |  |  | 	if (pMesh->face_as_quad_map) { | 
					
						
							|  |  |  | 		lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]]; | 
					
						
							|  |  |  | 		const MPoly *mp = &pMesh->mpoly[lt->poly]; | 
					
						
							|  |  |  | 		if (mp->totloop == 4) { | 
					
						
							|  |  |  | 			loop_index = (uint)(mp->loopstart + vert_index); | 
					
						
							|  |  |  | 			goto finally; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		/* fall through to regular triangle */ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else { | 
					
						
							|  |  |  | 		lt = &pMesh->looptri[face_num]; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | 	lt = &pMesh->looptri[face_num]; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 	loop_index = lt->tri[vert_index]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | finally: | 
					
						
							|  |  |  | 	co = pMesh->mvert[pMesh->mloop[loop_index].v].co; | 
					
						
							|  |  |  | 	copy_v3_v3(r_co, co); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void dm_ts_GetTextureCoordinate( | 
					
						
							|  |  |  |         const SMikkTSpaceContext *pContext, float r_uv[2], | 
					
						
							|  |  |  |         const int face_num, const int vert_index) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	//assert(vert_index >= 0 && vert_index < 4);
 | 
					
						
							|  |  |  | 	SGLSLMeshToTangent *pMesh = pContext->m_pUserData; | 
					
						
							|  |  |  | 	const MLoopTri *lt; | 
					
						
							|  |  |  | 	uint loop_index; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef USE_LOOPTRI_DETECT_QUADS
 | 
					
						
							|  |  |  | 	if (pMesh->face_as_quad_map) { | 
					
						
							|  |  |  | 		lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]]; | 
					
						
							|  |  |  | 		const MPoly *mp = &pMesh->mpoly[lt->poly]; | 
					
						
							|  |  |  | 		if (mp->totloop == 4) { | 
					
						
							|  |  |  | 			loop_index = (uint)(mp->loopstart + vert_index); | 
					
						
							|  |  |  | 			goto finally; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		/* fall through to regular triangle */ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else { | 
					
						
							|  |  |  | 		lt = &pMesh->looptri[face_num]; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | 	lt = &pMesh->looptri[face_num]; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 	loop_index = lt->tri[vert_index]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | finally: | 
					
						
							|  |  |  | 	if (pMesh->mloopuv != NULL) { | 
					
						
							|  |  |  | 		const float *uv = pMesh->mloopuv[loop_index].uv; | 
					
						
							|  |  |  | 		copy_v2_v2(r_uv, uv); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else { | 
					
						
							|  |  |  | 		const float *orco = pMesh->orco[pMesh->mloop[loop_index].v]; | 
					
						
							|  |  |  | 		map_to_sphere(&r_uv[0], &r_uv[1], orco[0], orco[1], orco[2]); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void dm_ts_GetNormal( | 
					
						
							|  |  |  |         const SMikkTSpaceContext *pContext, float r_no[3], | 
					
						
							|  |  |  |         const int face_num, const int vert_index) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	//assert(vert_index >= 0 && vert_index < 4);
 | 
					
						
							|  |  |  | 	SGLSLMeshToTangent *pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData; | 
					
						
							|  |  |  | 	const MLoopTri *lt; | 
					
						
							|  |  |  | 	uint loop_index; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef USE_LOOPTRI_DETECT_QUADS
 | 
					
						
							|  |  |  | 	if (pMesh->face_as_quad_map) { | 
					
						
							|  |  |  | 		lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]]; | 
					
						
							|  |  |  | 		const MPoly *mp = &pMesh->mpoly[lt->poly]; | 
					
						
							|  |  |  | 		if (mp->totloop == 4) { | 
					
						
							|  |  |  | 			loop_index = (uint)(mp->loopstart + vert_index); | 
					
						
							|  |  |  | 			goto finally; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		/* fall through to regular triangle */ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else { | 
					
						
							|  |  |  | 		lt = &pMesh->looptri[face_num]; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | 	lt = &pMesh->looptri[face_num]; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 	loop_index = lt->tri[vert_index]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | finally: | 
					
						
							|  |  |  | 	if (pMesh->precomputedLoopNormals) { | 
					
						
							|  |  |  | 		copy_v3_v3(r_no, pMesh->precomputedLoopNormals[loop_index]); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else if ((pMesh->mpoly[lt->poly].flag & ME_SMOOTH) == 0) {  /* flat */ | 
					
						
							|  |  |  | 		if (pMesh->precomputedFaceNormals) { | 
					
						
							|  |  |  | 			copy_v3_v3(r_no, pMesh->precomputedFaceNormals[lt->poly]); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		else { | 
					
						
							|  |  |  | #ifdef USE_LOOPTRI_DETECT_QUADS
 | 
					
						
							|  |  |  | 			const MPoly *mp = &pMesh->mpoly[lt->poly]; | 
					
						
							|  |  |  | 			if (mp->totloop == 4) { | 
					
						
							|  |  |  | 				normal_quad_v3( | 
					
						
							|  |  |  | 				        r_no, | 
					
						
							|  |  |  | 				        pMesh->mvert[pMesh->mloop[mp->loopstart + 0].v].co, | 
					
						
							|  |  |  | 				        pMesh->mvert[pMesh->mloop[mp->loopstart + 1].v].co, | 
					
						
							|  |  |  | 				        pMesh->mvert[pMesh->mloop[mp->loopstart + 2].v].co, | 
					
						
							|  |  |  | 				        pMesh->mvert[pMesh->mloop[mp->loopstart + 3].v].co); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				normal_tri_v3( | 
					
						
							|  |  |  | 				        r_no, | 
					
						
							|  |  |  | 				        pMesh->mvert[pMesh->mloop[lt->tri[0]].v].co, | 
					
						
							|  |  |  | 				        pMesh->mvert[pMesh->mloop[lt->tri[1]].v].co, | 
					
						
							|  |  |  | 				        pMesh->mvert[pMesh->mloop[lt->tri[2]].v].co); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else { | 
					
						
							|  |  |  | 		const short *no = pMesh->mvert[pMesh->mloop[loop_index].v].no; | 
					
						
							|  |  |  | 		normal_short_to_float_v3(r_no, no); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void dm_ts_SetTSpace( | 
					
						
							|  |  |  |         const SMikkTSpaceContext *pContext, const float fvTangent[3], const float fSign, | 
					
						
							|  |  |  |         const int face_num, const int vert_index) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	//assert(vert_index >= 0 && vert_index < 4);
 | 
					
						
							|  |  |  | 	SGLSLMeshToTangent *pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData; | 
					
						
							|  |  |  | 	const MLoopTri *lt; | 
					
						
							|  |  |  | 	uint loop_index; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef USE_LOOPTRI_DETECT_QUADS
 | 
					
						
							|  |  |  | 	if (pMesh->face_as_quad_map) { | 
					
						
							|  |  |  | 		lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]]; | 
					
						
							|  |  |  | 		const MPoly *mp = &pMesh->mpoly[lt->poly]; | 
					
						
							|  |  |  | 		if (mp->totloop == 4) { | 
					
						
							|  |  |  | 			loop_index = (uint)(mp->loopstart + vert_index); | 
					
						
							|  |  |  | 			goto finally; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		/* fall through to regular triangle */ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else { | 
					
						
							|  |  |  | 		lt = &pMesh->looptri[face_num]; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | 	lt = &pMesh->looptri[face_num]; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 	loop_index = lt->tri[vert_index]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	float *pRes; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | finally: | 
					
						
							|  |  |  | 	pRes = pMesh->tangent[loop_index]; | 
					
						
							|  |  |  | 	copy_v3_v3(pRes, fvTangent); | 
					
						
							|  |  |  | 	pRes[3] = fSign; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void DM_calc_loop_tangents_thread(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid)) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct SGLSLMeshToTangent *mesh2tangent = taskdata; | 
					
						
							|  |  |  | 	/* new computation method */ | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		SMikkTSpaceContext sContext = {NULL}; | 
					
						
							|  |  |  | 		SMikkTSpaceInterface sInterface = {NULL}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		sContext.m_pUserData = mesh2tangent; | 
					
						
							|  |  |  | 		sContext.m_pInterface = &sInterface; | 
					
						
							|  |  |  | 		sInterface.m_getNumFaces = dm_ts_GetNumFaces; | 
					
						
							|  |  |  | 		sInterface.m_getNumVerticesOfFace = dm_ts_GetNumVertsOfFace; | 
					
						
							|  |  |  | 		sInterface.m_getPosition = dm_ts_GetPosition; | 
					
						
							|  |  |  | 		sInterface.m_getTexCoord = dm_ts_GetTextureCoordinate; | 
					
						
							|  |  |  | 		sInterface.m_getNormal = dm_ts_GetNormal; | 
					
						
							|  |  |  | 		sInterface.m_setTSpaceBasic = dm_ts_SetTSpace; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* 0 if failed */ | 
					
						
							|  |  |  | 		genTangSpaceDefault(&sContext); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void BKE_mesh_add_loop_tangent_named_layer_for_uv( | 
					
						
							|  |  |  |         CustomData *uv_data, CustomData *tan_data, int numLoopData, | 
					
						
							|  |  |  |         const char *layer_name) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (CustomData_get_named_layer_index(tan_data, CD_TANGENT, layer_name) == -1 && | 
					
						
							|  |  |  | 	    CustomData_get_named_layer_index(uv_data, CD_MLOOPUV, layer_name) != -1) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		CustomData_add_layer_named( | 
					
						
							|  |  |  | 		        tan_data, CD_TANGENT, CD_CALLOC, NULL, | 
					
						
							|  |  |  | 		        numLoopData, layer_name); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * Here we get some useful information such as active uv layer name and search if it is already in tangent_names. | 
					
						
							|  |  |  |  * Also, we calculate tangent_mask that works as a descriptor of tangents state. | 
					
						
							|  |  |  |  * If tangent_mask has changed, then recalculate tangents. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | void BKE_mesh_calc_loop_tangent_step_0( | 
					
						
							|  |  |  |         const CustomData *loopData, bool calc_active_tangent, | 
					
						
							|  |  |  |         const char (*tangent_names)[MAX_NAME], int tangent_names_count, | 
					
						
							|  |  |  |         bool *rcalc_act, bool *rcalc_ren, int *ract_uv_n, int *rren_uv_n, | 
					
						
							| 
									
										
										
										
											2017-07-03 19:49:35 +03:00
										 |  |  |         char *ract_uv_name, char *rren_uv_name, short *rtangent_mask) { | 
					
						
							| 
									
										
										
										
											2017-05-24 22:33:21 +10:00
										 |  |  | 	/* Active uv in viewport */ | 
					
						
							|  |  |  | 	int layer_index = CustomData_get_layer_index(loopData, CD_MLOOPUV); | 
					
						
							|  |  |  | 	*ract_uv_n = CustomData_get_active_layer(loopData, CD_MLOOPUV); | 
					
						
							|  |  |  | 	ract_uv_name[0] = 0; | 
					
						
							|  |  |  | 	if (*ract_uv_n != -1) { | 
					
						
							|  |  |  | 		strcpy(ract_uv_name, loopData->layers[*ract_uv_n + layer_index].name); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Active tangent in render */ | 
					
						
							|  |  |  | 	*rren_uv_n = CustomData_get_render_layer(loopData, CD_MLOOPUV); | 
					
						
							|  |  |  | 	rren_uv_name[0] = 0; | 
					
						
							|  |  |  | 	if (*rren_uv_n != -1) { | 
					
						
							|  |  |  | 		strcpy(rren_uv_name, loopData->layers[*rren_uv_n + layer_index].name); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* If active tangent not in tangent_names we take it into account */ | 
					
						
							|  |  |  | 	*rcalc_act = false; | 
					
						
							|  |  |  | 	*rcalc_ren = false; | 
					
						
							|  |  |  | 	for (int i = 0; i < tangent_names_count; i++) { | 
					
						
							|  |  |  | 		if (tangent_names[i][0] == 0) { | 
					
						
							|  |  |  | 			calc_active_tangent = true; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (calc_active_tangent) { | 
					
						
							|  |  |  | 		*rcalc_act = true; | 
					
						
							|  |  |  | 		*rcalc_ren = true; | 
					
						
							|  |  |  | 		for (int i = 0; i < tangent_names_count; i++) { | 
					
						
							|  |  |  | 			if (STREQ(ract_uv_name, tangent_names[i])) | 
					
						
							|  |  |  | 				*rcalc_act = false; | 
					
						
							|  |  |  | 			if (STREQ(rren_uv_name, tangent_names[i])) | 
					
						
							|  |  |  | 				*rcalc_ren = false; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	*rtangent_mask = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const int uv_layer_num = CustomData_number_of_layers(loopData, CD_MLOOPUV); | 
					
						
							|  |  |  | 	for (int n = 0; n < uv_layer_num; n++) { | 
					
						
							|  |  |  | 		const char *name = CustomData_get_layer_name(loopData, CD_MLOOPUV, n); | 
					
						
							|  |  |  | 		bool add = false; | 
					
						
							|  |  |  | 		for (int i = 0; i < tangent_names_count; i++) { | 
					
						
							|  |  |  | 			if (tangent_names[i][0] && STREQ(tangent_names[i], name)) { | 
					
						
							|  |  |  | 				add = true; | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-06-07 11:23:59 +02:00
										 |  |  | 		if (!add && ((*rcalc_act && ract_uv_name[0] && STREQ(ract_uv_name, name)) || | 
					
						
							|  |  |  | 		             (*rcalc_ren && rren_uv_name[0] && STREQ(rren_uv_name, name)))) | 
					
						
							| 
									
										
										
										
											2017-05-24 22:33:21 +10:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			add = true; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (add) | 
					
						
							| 
									
										
										
										
											2017-07-03 20:59:02 +02:00
										 |  |  | 			*rtangent_mask |= (short)(1 << n); | 
					
						
							| 
									
										
										
										
											2017-05-24 22:33:21 +10:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-07-03 20:02:39 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (uv_layer_num == 0) | 
					
						
							|  |  |  | 		*rtangent_mask |= DM_TANGENT_MASK_ORCO; | 
					
						
							| 
									
										
										
										
											2017-05-24 22:33:21 +10:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * See: #BKE_editmesh_loop_tangent_calc (matching logic). | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | void BKE_mesh_calc_loop_tangent_ex( | 
					
						
							|  |  |  |         const MVert *mvert, | 
					
						
							|  |  |  |         const MPoly *mpoly, const uint mpoly_len, | 
					
						
							|  |  |  |         const MLoop *mloop, | 
					
						
							|  |  |  |         const MLoopTri *looptri, | 
					
						
							|  |  |  |         const uint looptri_len, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         CustomData *loopdata, | 
					
						
							|  |  |  |         bool calc_active_tangent, | 
					
						
							|  |  |  |         const char (*tangent_names)[MAX_NAME], int tangent_names_len, | 
					
						
							|  |  |  |         const float (*poly_normals)[3], | 
					
						
							|  |  |  |         const float (*loop_normals)[3], | 
					
						
							|  |  |  |         const float (*vert_orco)[3], | 
					
						
							|  |  |  |         /* result */ | 
					
						
							|  |  |  |         CustomData *loopdata_out, | 
					
						
							|  |  |  |         const uint  loopdata_out_len, | 
					
						
							| 
									
										
										
										
											2017-07-03 19:49:35 +03:00
										 |  |  |         short *tangent_mask_curr_p) | 
					
						
							| 
									
										
										
										
											2017-05-24 22:33:21 +10:00
										 |  |  | { | 
					
						
							|  |  |  | 	int act_uv_n = -1; | 
					
						
							|  |  |  | 	int ren_uv_n = -1; | 
					
						
							|  |  |  | 	bool calc_act = false; | 
					
						
							|  |  |  | 	bool calc_ren = false; | 
					
						
							|  |  |  | 	char act_uv_name[MAX_NAME]; | 
					
						
							|  |  |  | 	char ren_uv_name[MAX_NAME]; | 
					
						
							| 
									
										
										
										
											2017-07-03 19:49:35 +03:00
										 |  |  | 	short tangent_mask = 0; | 
					
						
							|  |  |  | 	short tangent_mask_curr = *tangent_mask_curr_p; | 
					
						
							| 
									
										
										
										
											2017-05-24 22:33:21 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	BKE_mesh_calc_loop_tangent_step_0( | 
					
						
							|  |  |  | 	        loopdata, calc_active_tangent, tangent_names, tangent_names_len, | 
					
						
							|  |  |  | 	        &calc_act, &calc_ren, &act_uv_n, &ren_uv_n, act_uv_name, ren_uv_name, &tangent_mask); | 
					
						
							|  |  |  | 	if ((tangent_mask_curr | tangent_mask) != tangent_mask_curr) { | 
					
						
							|  |  |  | 		/* Check we have all the needed layers */ | 
					
						
							|  |  |  | 		/* Allocate needed tangent layers */ | 
					
						
							|  |  |  | 		for (int i = 0; i < tangent_names_len; i++) | 
					
						
							|  |  |  | 			if (tangent_names[i][0]) | 
					
						
							|  |  |  | 				BKE_mesh_add_loop_tangent_named_layer_for_uv(loopdata, loopdata_out, (int)loopdata_out_len, tangent_names[i]); | 
					
						
							| 
									
										
										
										
											2017-07-03 19:49:35 +03:00
										 |  |  | 		if ((tangent_mask & DM_TANGENT_MASK_ORCO) && CustomData_get_named_layer_index(loopdata, CD_TANGENT, "") == -1) | 
					
						
							|  |  |  | 			    CustomData_add_layer_named(loopdata, CD_TANGENT, CD_CALLOC, NULL, (int)loopdata_out_len, ""); | 
					
						
							| 
									
										
										
										
											2017-05-24 22:33:21 +10:00
										 |  |  | 		if (calc_act && act_uv_name[0]) | 
					
						
							|  |  |  | 			BKE_mesh_add_loop_tangent_named_layer_for_uv(loopdata, loopdata_out, (int)loopdata_out_len, act_uv_name); | 
					
						
							|  |  |  | 		if (calc_ren && ren_uv_name[0]) | 
					
						
							|  |  |  | 			BKE_mesh_add_loop_tangent_named_layer_for_uv(loopdata, loopdata_out, (int)loopdata_out_len, ren_uv_name); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef USE_LOOPTRI_DETECT_QUADS
 | 
					
						
							|  |  |  | 		int num_face_as_quad_map; | 
					
						
							|  |  |  | 		int *face_as_quad_map = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* map faces to quads */ | 
					
						
							|  |  |  | 		if (looptri_len != mpoly_len) { | 
					
						
							|  |  |  | 			/* over alloc, since we dont know how many ngon or quads we have */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/* map fake face index to looptri */ | 
					
						
							|  |  |  | 			face_as_quad_map = MEM_mallocN(sizeof(int) * looptri_len, __func__); | 
					
						
							|  |  |  | 			int k, j; | 
					
						
							|  |  |  | 			for (k = 0, j = 0; j < (int)looptri_len; k++, j++) { | 
					
						
							|  |  |  | 				face_as_quad_map[k] = j; | 
					
						
							|  |  |  | 				/* step over all quads */ | 
					
						
							|  |  |  | 				if (mpoly[looptri[j].poly].totloop == 4) { | 
					
						
							|  |  |  | 					j++;  /* skips the nest looptri */ | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			num_face_as_quad_map = k; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		else { | 
					
						
							|  |  |  | 			num_face_as_quad_map = (int)looptri_len; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* Calculation */ | 
					
						
							| 
									
										
										
										
											2017-06-28 20:59:49 +10:00
										 |  |  | 		if (looptri_len != 0) { | 
					
						
							| 
									
										
										
										
											2017-05-24 22:33:21 +10:00
										 |  |  | 			TaskScheduler *scheduler = BLI_task_scheduler_get(); | 
					
						
							|  |  |  | 			TaskPool *task_pool; | 
					
						
							|  |  |  | 			task_pool = BLI_task_pool_create(scheduler, NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			tangent_mask_curr = 0; | 
					
						
							|  |  |  | 			/* Calculate tangent layers */ | 
					
						
							|  |  |  | 			SGLSLMeshToTangent data_array[MAX_MTFACE]; | 
					
						
							|  |  |  | 			const int tangent_layer_num = CustomData_number_of_layers(loopdata_out, CD_TANGENT); | 
					
						
							|  |  |  | 			for (int n = 0; n < tangent_layer_num; n++) { | 
					
						
							|  |  |  | 				int index = CustomData_get_layer_index_n(loopdata_out, CD_TANGENT, n); | 
					
						
							|  |  |  | 				BLI_assert(n < MAX_MTFACE); | 
					
						
							|  |  |  | 				SGLSLMeshToTangent *mesh2tangent = &data_array[n]; | 
					
						
							|  |  |  | 				mesh2tangent->numTessFaces = (int)looptri_len; | 
					
						
							|  |  |  | #ifdef USE_LOOPTRI_DETECT_QUADS
 | 
					
						
							|  |  |  | 				mesh2tangent->face_as_quad_map = face_as_quad_map; | 
					
						
							|  |  |  | 				mesh2tangent->num_face_as_quad_map = num_face_as_quad_map; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 				mesh2tangent->mvert = mvert; | 
					
						
							|  |  |  | 				mesh2tangent->mpoly = mpoly; | 
					
						
							|  |  |  | 				mesh2tangent->mloop = mloop; | 
					
						
							|  |  |  | 				mesh2tangent->looptri = looptri; | 
					
						
							|  |  |  | 				/* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled),
 | 
					
						
							|  |  |  | 				 * have to check this is valid... | 
					
						
							|  |  |  | 				 */ | 
					
						
							|  |  |  | 				mesh2tangent->precomputedLoopNormals = loop_normals; | 
					
						
							|  |  |  | 				mesh2tangent->precomputedFaceNormals = poly_normals; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				mesh2tangent->orco = NULL; | 
					
						
							| 
									
										
										
										
											2017-06-29 21:22:34 +10:00
										 |  |  | 				mesh2tangent->mloopuv = CustomData_get_layer_named(loopdata, CD_MLOOPUV, loopdata_out->layers[index].name); | 
					
						
							| 
									
										
										
										
											2017-07-03 19:49:35 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				/* Fill the resulting tangent_mask */ | 
					
						
							| 
									
										
										
										
											2017-05-24 22:33:21 +10:00
										 |  |  | 				if (!mesh2tangent->mloopuv) { | 
					
						
							| 
									
										
										
										
											2017-07-03 19:49:35 +03:00
										 |  |  | 				    mesh2tangent->orco = vert_orco; | 
					
						
							|  |  |  | 				    if (!mesh2tangent->orco) | 
					
						
							|  |  |  | 					    continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				    *tangent_mask_curr_p |= DM_TANGENT_MASK_ORCO; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				else { | 
					
						
							|  |  |  | 				    int uv_ind = CustomData_get_named_layer_index(loopdata, CD_MLOOPUV, loopdata->layers[index].name); | 
					
						
							|  |  |  | 				    int uv_start = CustomData_get_layer_index(loopdata, CD_MLOOPUV); | 
					
						
							|  |  |  | 				    BLI_assert(uv_ind != -1 && uv_start != -1); | 
					
						
							|  |  |  | 				    BLI_assert(uv_ind - uv_start < MAX_MTFACE); | 
					
						
							| 
									
										
										
										
											2017-07-03 20:59:02 +02:00
										 |  |  | 				    *tangent_mask_curr_p |= (short)(1 << (uv_ind - uv_start)); | 
					
						
							| 
									
										
										
										
											2017-05-24 22:33:21 +10:00
										 |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-03 19:49:35 +03:00
										 |  |  | 				mesh2tangent->tangent = loopdata_out->layers[index].data; | 
					
						
							| 
									
										
										
										
											2017-05-24 22:33:21 +10:00
										 |  |  | 				BLI_task_pool_push(task_pool, DM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			BLI_assert(tangent_mask_curr == tangent_mask); | 
					
						
							|  |  |  | 			BLI_task_pool_work_and_wait(task_pool); | 
					
						
							|  |  |  | 			BLI_task_pool_free(task_pool); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-06-28 20:59:49 +10:00
										 |  |  | 		else { | 
					
						
							|  |  |  | 			tangent_mask_curr = tangent_mask; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-05-24 22:33:21 +10:00
										 |  |  | #ifdef USE_LOOPTRI_DETECT_QUADS
 | 
					
						
							|  |  |  | 		if (face_as_quad_map) { | 
					
						
							|  |  |  | 			MEM_freeN(face_as_quad_map); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | #undef USE_LOOPTRI_DETECT_QUADS
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		*tangent_mask_curr_p = tangent_mask_curr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* Update active layer index */ | 
					
						
							| 
									
										
										
										
											2017-07-03 19:49:35 +03:00
										 |  |  | 		int act_uv_index = CustomData_get_layer_index_n(loopdata, CD_MLOOPUV, act_uv_n); | 
					
						
							|  |  |  | 		if (act_uv_index != -1) { | 
					
						
							|  |  |  | 		    int tan_index = CustomData_get_named_layer_index(loopdata, CD_TANGENT, loopdata->layers[act_uv_index].name); | 
					
						
							|  |  |  | 		    CustomData_set_layer_active_index(loopdata, CD_TANGENT, tan_index); | 
					
						
							|  |  |  | 		}/* else tangent has been built from orco */ | 
					
						
							| 
									
										
										
										
											2017-05-24 22:33:21 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/* Update render layer index */ | 
					
						
							| 
									
										
										
										
											2017-07-03 19:49:35 +03:00
										 |  |  | 		int ren_uv_index = CustomData_get_layer_index_n(loopdata, CD_MLOOPUV, ren_uv_n); | 
					
						
							|  |  |  | 		if (ren_uv_index != -1) { | 
					
						
							|  |  |  | 		    int tan_index = CustomData_get_named_layer_index(loopdata, CD_TANGENT, loopdata->layers[ren_uv_index].name); | 
					
						
							|  |  |  | 		    CustomData_set_layer_render_index(loopdata, CD_TANGENT, tan_index); | 
					
						
							|  |  |  | 		}/* else tangent has been built from orco */ | 
					
						
							| 
									
										
										
										
											2017-05-24 22:33:21 +10:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** \} */ |