Fix T51561: Normal maps fail w/ quad + eevee
authorCampbell Barton <ideasman42@gmail.com>
Wed, 24 May 2017 12:33:21 +0000 (22:33 +1000)
committerCampbell Barton <ideasman42@gmail.com>
Wed, 24 May 2017 12:39:50 +0000 (22:39 +1000)
Generalize derived-mesh tangent calculation so
it can be used by Batch cache creation too.

source/blender/blenkernel/BKE_DerivedMesh.h
source/blender/blenkernel/BKE_mesh.h
source/blender/blenkernel/BKE_mesh_tangent.h [new file with mode: 0644]
source/blender/blenkernel/CMakeLists.txt
source/blender/blenkernel/intern/DerivedMesh.c
source/blender/blenkernel/intern/editderivedmesh.c
source/blender/blenkernel/intern/editmesh_tangent.c
source/blender/blenkernel/intern/mesh_evaluate.c
source/blender/blenkernel/intern/mesh_tangent.c [new file with mode: 0644]
source/blender/draw/intern/draw_cache_impl_mesh.c
source/blender/makesrna/intern/rna_mesh_api.c

index c7bcf036f5bee2a666aba3315d6825849ba4b139..1ac1fd10da64bd9d15b9279e2e76467a7ce18e5e 100644 (file)
@@ -785,17 +785,11 @@ void DM_draw_attrib_vertex_uniforms(const DMVertexAttribs *attribs);
 void DM_calc_tangents_names_from_gpu(
         const struct GPUVertexAttribs *gattribs,
         char (*tangent_names)[MAX_NAME], int *tangent_names_count);
-void DM_add_named_tangent_layer_for_uv(
-        CustomData *uv_data, CustomData *tan_data, int numLoopData,
-        const char *layer_name);
-void DM_calc_loop_tangents_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,
-        char *ract_uv_name, char *rren_uv_name, char *rtangent_mask);
+
 void DM_calc_loop_tangents(
         DerivedMesh *dm, bool calc_active_tangent, const char (*tangent_names)[MAX_NAME],
         int tangent_names_count);
+
 void DM_calc_auto_bump_scale(DerivedMesh *dm);
 
 /** Set object's bounding box based on DerivedMesh min/max data */
index e0f62cfd8942ca9d46756af597e4dff772669c1e..64f71f0ade58f30dc9015624f386de7864acd2dc 100644 (file)
@@ -186,13 +186,6 @@ void BKE_mesh_calc_normals_looptri(
         const struct MLoop *mloop,
         const struct MLoopTri *looptri, int looptri_num,
         float (*r_tri_nors)[3]);
-void BKE_mesh_loop_tangents_ex(
-        const struct MVert *mverts, const int numVerts, const struct MLoop *mloops,
-        float (*r_looptangent)[4], float (*loopnors)[3], const struct MLoopUV *loopuv,
-        const int numLoops, const struct MPoly *mpolys, const int numPolys,
-        struct ReportList *reports);
-void BKE_mesh_loop_tangents(
-        struct Mesh *mesh, const char *uvmap, float (*r_looptangents)[4], struct ReportList *reports);
 
 /**
  * References a contiguous loop-fan with normal offset vars.
diff --git a/source/blender/blenkernel/BKE_mesh_tangent.h b/source/blender/blenkernel/BKE_mesh_tangent.h
new file mode 100644 (file)
index 0000000..66b8a26
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * ***** 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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef __BKE_MESH_TANGENT_H__
+#define __BKE_MESH_TANGENT_H__
+
+void BKE_mesh_calc_loop_tangent_single_ex(
+        const struct MVert *mverts, const int numVerts, const struct MLoop *mloops,
+        float (*r_looptangent)[4], float (*loopnors)[3], const struct MLoopUV *loopuv,
+        const int numLoops, const struct MPoly *mpolys, const int numPolys,
+        struct ReportList *reports);
+void BKE_mesh_calc_loop_tangent_single(
+        struct Mesh *mesh, const char *uvmap, float (*r_looptangents)[4], struct ReportList *reports);
+
+void BKE_mesh_calc_loop_tangent_ex(
+        const struct MVert *mvert,
+        const struct MPoly *mpoly, const uint mpoly_len,
+        const struct MLoop *mloop,
+        const struct MLoopTri *looptri, const uint looptri_len,
+
+        struct CustomData *loopdata,
+        bool calc_active_tangent,
+        const char (*tangent_names)[64], int tangent_names_len,
+        const float (*poly_normals)[3],
+        const float (*loop_normals)[3],
+        const float (*vert_orco)[3],
+        /* result */
+        struct CustomData *loopdata_out,
+        const uint  loopdata_out_len,
+        char *tangent_mask_curr_p);
+
+/* Helpers */
+void BKE_mesh_add_loop_tangent_named_layer_for_uv(
+        struct CustomData *uv_data, struct CustomData *tan_data, int numLoopData,
+        const char *layer_name);
+void BKE_mesh_calc_loop_tangent_step_0(
+        const struct CustomData *loopData, bool calc_active_tangent,
+        const char (*tangent_names)[64], int tangent_names_count,
+        bool *rcalc_act, bool *rcalc_ren, int *ract_uv_n, int *rren_uv_n,
+        char *ract_uv_name, char *rren_uv_name, char *rtangent_mask);
+
+#endif /* __BKE_MESH_TANGENT_H__ */
+
index 1acc45c9f007efc72c37cde163c1f137abd1a9d1..7af0b5d092ac970bdcd55c2bb724b6d2c7c84a66 100644 (file)
@@ -136,6 +136,7 @@ set(SRC
        intern/mesh_evaluate.c
        intern/mesh_mapping.c
        intern/mesh_remap.c
+       intern/mesh_tangent.c
        intern/mesh_validate.c
        intern/modifier.c
        intern/modifiers_bmesh.c
@@ -263,6 +264,7 @@ set(SRC
        BKE_mesh.h
        BKE_mesh_mapping.h
        BKE_mesh_remap.h
+       BKE_mesh_tangent.h
        BKE_modifier.h
        BKE_movieclip.h
        BKE_multires.h
index 150a919bf6b794496d38870c73e7746b574b31d9..a6b9a0487636bd5be4f7add5a57771c48fe546ab 100644 (file)
@@ -60,6 +60,7 @@
 #include "BKE_modifier.h"
 #include "BKE_mesh.h"
 #include "BKE_mesh_mapping.h"
+#include "BKE_mesh_tangent.h"
 #include "BKE_object.h"
 #include "BKE_object_deform.h"
 #include "BKE_paint.h"
@@ -3038,234 +3039,6 @@ void mesh_get_mapped_verts_coords(DerivedMesh *dm, float (*r_cos)[3], const int
 
 /* ******************* GLSL ******************** */
 
-/** \name Tangent Space Calculation
- * \{ */
-
-/* Necessary complexity to handle looptri's as quads for correct tangents */
-#define USE_LOOPTRI_DETECT_QUADS
-
-typedef struct {
-       float (*precomputedFaceNormals)[3];
-       float (*precomputedLoopNormals)[3];
-       const MLoopTri *looptri;
-       MLoopUV *mloopuv;   /* texture coordinates */
-       MPoly *mpoly;       /* indices */
-       MLoop *mloop;       /* indices */
-       MVert *mvert;       /* vertices & normals */
-       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;
-       int 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 = 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;
-       int 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 = 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;
-       int 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 = 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;
-       int 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 = 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;
-}
-
 void DM_calc_tangents_names_from_gpu(
         const GPUVertexAttribs *gattribs,
         char (*tangent_names)[MAX_NAME], int *r_tangent_names_count)
@@ -3279,240 +3052,29 @@ void DM_calc_tangents_names_from_gpu(
        *r_tangent_names_count = count;
 }
 
-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 DM_add_named_tangent_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 DM_calc_loop_tangents_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,
-        char *ract_uv_name, char *rren_uv_name, char *rtangent_mask) {
-       /* 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;
-                       }
-               }
-               if ((*rcalc_act && ract_uv_name[0] && STREQ(ract_uv_name, name)) ||
-                   (*rcalc_ren && rren_uv_name[0] && STREQ(rren_uv_name, name)))
-               {
-                       add = true;
-               }
-               if (add)
-                       *rtangent_mask |= 1 << n;
-       }
-}
-
 void DM_calc_loop_tangents(
         DerivedMesh *dm, bool calc_active_tangent,
-        const char (*tangent_names)[MAX_NAME], int tangent_names_count)
+        const char (*tangent_names)[MAX_NAME], int tangent_names_len)
 {
-       if (CustomData_number_of_layers(&dm->loopData, CD_MLOOPUV) == 0)
+       if (CustomData_number_of_layers(&dm->loopData, CD_MLOOPUV) == 0) {
                return;
-       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];
-       char tangent_mask = 0;
-       DM_calc_loop_tangents_step_0(
-               &dm->loopData, calc_active_tangent, tangent_names, tangent_names_count,
-               &calc_act, &calc_ren, &act_uv_n, &ren_uv_n, act_uv_name, ren_uv_name, &tangent_mask);
-       if ((dm->tangent_mask | tangent_mask) != dm->tangent_mask) {
-               /* Check we have all the needed layers */
-               MPoly *mpoly = dm->getPolyArray(dm);
-               const MLoopTri *looptri = dm->getLoopTriArray(dm);
-               int totface = dm->getNumLoopTri(dm);
-               /* Allocate needed tangent layers */
-               for (int i = 0; i < tangent_names_count; i++)
-                       if (tangent_names[i][0])
-                               DM_add_named_tangent_layer_for_uv(&dm->loopData, &dm->loopData, dm->numLoopData, tangent_names[i]);
-               if (calc_act && act_uv_name[0])
-                       DM_add_named_tangent_layer_for_uv(&dm->loopData, &dm->loopData, dm->numLoopData, act_uv_name);
-               if (calc_ren && ren_uv_name[0])
-                       DM_add_named_tangent_layer_for_uv(&dm->loopData, &dm->loopData, dm->numLoopData, 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 (totface != dm->getNumPolys(dm)) {
-                       /* 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) * totface, __func__);
-                       int k, j;
-                       for (k = 0, j = 0; j < totface; 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 = totface;
-               }
-#endif
-
-               /* Calculation */
-               {
-                       TaskScheduler *scheduler = BLI_task_scheduler_get();
-                       TaskPool *task_pool;
-                       task_pool = BLI_task_pool_create(scheduler, NULL);
-
-                       dm->tangent_mask = 0;
-                       /* Calculate tangent layers */
-                       SGLSLMeshToTangent data_array[MAX_MTFACE];
-                       const int tangent_layer_num = CustomData_number_of_layers(&dm->loopData, CD_TANGENT);
-                       for (int n = 0; n < tangent_layer_num; n++) {
-                               int index = CustomData_get_layer_index_n(&dm->loopData, CD_TANGENT, n);
-                               BLI_assert(n < MAX_MTFACE);
-                               SGLSLMeshToTangent *mesh2tangent = &data_array[n];
-                               mesh2tangent->numTessFaces = totface;
-#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 = dm->getVertArray(dm);
-                               mesh2tangent->mpoly = dm->getPolyArray(dm);
-                               mesh2tangent->mloop = dm->getLoopArray(dm);
-                               mesh2tangent->looptri = dm->getLoopTriArray(dm);
-                               /* 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 = dm->getLoopDataArray(dm, CD_NORMAL);
-                               mesh2tangent->precomputedFaceNormals = CustomData_get_layer(&dm->polyData, CD_NORMAL);
-
-                               mesh2tangent->orco = NULL;
-                               mesh2tangent->mloopuv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, dm->loopData.layers[index].name);
-                               if (!mesh2tangent->mloopuv) {
-                                       mesh2tangent->orco = dm->getVertDataArray(dm, CD_ORCO);
-                                       if (!mesh2tangent->orco)
-                                               continue;
-                               }
-                               mesh2tangent->tangent = dm->loopData.layers[index].data;
-
-                               /* Fill the resulting tangent_mask */
-                               int uv_ind = CustomData_get_named_layer_index(&dm->loopData, CD_MLOOPUV, dm->loopData.layers[index].name);
-                               int uv_start = CustomData_get_layer_index(&dm->loopData, CD_MLOOPUV);
-                               BLI_assert(uv_ind != -1 && uv_start != -1);
-                               BLI_assert(uv_ind - uv_start < MAX_MTFACE);
-                               dm->tangent_mask |= 1 << (uv_ind - uv_start);
-                               BLI_task_pool_push(task_pool, DM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW);
-                       }
-
-                       BLI_assert(dm->tangent_mask == tangent_mask);
-                       BLI_task_pool_work_and_wait(task_pool);
-                       BLI_task_pool_free(task_pool);
-               }
-#ifdef USE_LOOPTRI_DETECT_QUADS
-               if (face_as_quad_map) {
-                       MEM_freeN(face_as_quad_map);
-               }
-#undef USE_LOOPTRI_DETECT_QUADS
-
-#endif
-
-               int uv_index, tan_index;
-
-               /* Update active layer index */
-               uv_index = CustomData_get_layer_index_n(&dm->loopData, CD_MLOOPUV, act_uv_n);
-               if (uv_index != -1) {
-                       tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, dm->loopData.layers[uv_index].name);
-                       CustomData_set_layer_active_index(&dm->loopData, CD_TANGENT, tan_index);
-               }
-
-               /* Update render layer index */
-               uv_index = CustomData_get_layer_index_n(&dm->loopData, CD_MLOOPUV, ren_uv_n);
-               if (uv_index != -1) {
-                       tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, dm->loopData.layers[uv_index].name);
-                       CustomData_set_layer_render_index(&dm->loopData, CD_TANGENT, tan_index);
-               }
        }
-}
-
-/** \} */
 
+       BKE_mesh_calc_loop_tangent_ex(
+               dm->getVertArray(dm),
+               dm->getPolyArray(dm), dm->getNumPolys(dm),
+               dm->getLoopArray(dm),
+               dm->getLoopTriArray(dm), dm->getNumLoopTri(dm),
+               &dm->loopData,
+               calc_active_tangent,
+               tangent_names, tangent_names_len,
+               CustomData_get_layer(&dm->polyData, CD_NORMAL),
+               dm->getLoopDataArray(dm, CD_NORMAL),
+               dm->getVertDataArray(dm, CD_ORCO),  /* may be NULL */
+               /* result */
+               &dm->loopData, dm->getNumLoops(dm),
+               &dm->tangent_mask);
+}
 
 void DM_calc_auto_bump_scale(DerivedMesh *dm)
 {
index 320299d1933fc924919a4a9a691032cdaaf0195a..74cc260836ab157180b2aee84b708262d55ea295 100644 (file)
@@ -245,6 +245,11 @@ static void emDM_calc_loop_tangents(
 {
        EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
        BMEditMesh *em = bmdm->em;
+
+       if (CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPUV) == 0) {
+               return;
+       }
+
        const float (*poly_normals)[3] = bmdm->polyNos;
        const float (*loop_normals)[3] = CustomData_get_layer(&dm->loopData, CD_NORMAL);
        const float (*vert_orco)[3] = dm->getVertDataArray(dm, CD_ORCO);  /* can be NULL */
index 501ddb10d4ff43bfd3e0e3cc9eb82604eceace3f..b04fc753f7a08e64ec71400bbe10c7cea8196666 100644 (file)
@@ -28,6 +28,7 @@
 #include "BKE_DerivedMesh.h"
 
 #include "BKE_mesh.h"
+#include "BKE_mesh_tangent.h"  /* for utility functions */
 #include "BKE_editmesh.h"
 #include "BKE_editmesh_tangent.h"
 
@@ -268,7 +269,7 @@ static void emDM_calc_loop_tangents_thread(TaskPool * __restrict UNUSED(pool), v
 }
 
 /**
- * \see #DM_calc_loop_tangents, same logic but used arrays instead of #BMesh data.
+ * \see #BKE_mesh_calc_loop_tangent, same logic but used arrays instead of #BMesh data.
  *
  * \note This function is not so normal, its using `bm->ldata` as input, but output's to `dm->loopData`.
  * This is done because #CD_TANGENT is cache data used only for drawing.
@@ -285,8 +286,8 @@ void BKE_editmesh_loop_tangent_calc(
         char *tangent_mask_curr_p)
 {
        BMesh *bm = em->bm;
-       if (CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV) == 0)
-               return;
+
+       BLI_assert(CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV) != 0);
 
        int act_uv_n = -1;
        int ren_uv_n = -1;
@@ -297,18 +298,18 @@ void BKE_editmesh_loop_tangent_calc(
        char tangent_mask = 0;
        char tangent_mask_curr = *tangent_mask_curr_p;
 
-       DM_calc_loop_tangents_step_0(
+       BKE_mesh_calc_loop_tangent_step_0(
                &bm->ldata, 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) {
                for (int i = 0; i < tangent_names_len; i++)
                        if (tangent_names[i][0])
-                               DM_add_named_tangent_layer_for_uv(&bm->ldata, loopdata_out, loopdata_out_len, tangent_names[i]);
+                               BKE_mesh_add_loop_tangent_named_layer_for_uv(&bm->ldata, loopdata_out, loopdata_out_len, tangent_names[i]);
                if (calc_act && act_uv_name[0])
-                       DM_add_named_tangent_layer_for_uv(&bm->ldata, loopdata_out, loopdata_out_len, act_uv_name);
+                       BKE_mesh_add_loop_tangent_named_layer_for_uv(&bm->ldata, loopdata_out, loopdata_out_len, act_uv_name);
                if (calc_ren && ren_uv_name[0])
-                       DM_add_named_tangent_layer_for_uv(&bm->ldata, loopdata_out, loopdata_out_len, ren_uv_name);
+                       BKE_mesh_add_loop_tangent_named_layer_for_uv(&bm->ldata, loopdata_out, loopdata_out_len, ren_uv_name);
                int totface = em->tottri;
 #ifdef USE_LOOPTRI_DETECT_QUADS
                int num_face_as_quad_map;
index 37f4477febf5ef16aadd26dbf192f714ba89fe28..7e3791acc263feccd29070305f29b4e4a140c812 100644 (file)
@@ -1663,152 +1663,6 @@ void BKE_mesh_normals_loop_to_vertex(
 /** \} */
 
 
-/* -------------------------------------------------------------------- */
-
-/** \name Mesh Tangent Calculations
- * \{ */
-
-/* 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_loop_tangents_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_loop_tangents_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_loop_tangents(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_loop_tangents_ex(mesh->mvert, mesh->totvert, mesh->mloop, r_looptangents,
-                                 loopnors, loopuvs, mesh->totloop, mesh->mpoly, mesh->totpoly, reports);
-}
-
-/** \} */
-
-
 /* -------------------------------------------------------------------- */
 
 /** \name Polygon Calculations
diff --git a/source/blender/blenkernel/intern/mesh_tangent.c b/source/blender/blenkernel/intern/mesh_tangent.c
new file mode 100644 (file)
index 0000000..7b95333
--- /dev/null
@@ -0,0 +1,684 @@
+/*
+ * ***** 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,
+        char *ract_uv_name, char *rren_uv_name, char *rtangent_mask) {
+       /* 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;
+                       }
+               }
+               if ((*rcalc_act && ract_uv_name[0] && STREQ(ract_uv_name, name)) ||
+                   (*rcalc_ren && rren_uv_name[0] && STREQ(rren_uv_name, name)))
+               {
+                       add = true;
+               }
+               if (add)
+                       *rtangent_mask |= (char)(1 << n);
+       }
+}
+
+/**
+ * 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,
+        char *tangent_mask_curr_p)
+{
+       BLI_assert(CustomData_number_of_layers(loopdata, CD_MLOOPUV) != 0);
+
+       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];
+       char tangent_mask = 0;
+       char tangent_mask_curr = *tangent_mask_curr_p;
+
+       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]);
+               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 */
+               {
+                       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;
+                               mesh2tangent->mloopuv = CustomData_get_layer_named(loopdata, CD_MLOOPUV, loopdata->layers[index].name);
+                               if (!mesh2tangent->mloopuv) {
+                                       mesh2tangent->orco = vert_orco;
+                                       if (!mesh2tangent->orco)
+                                               continue;
+                               }
+                               mesh2tangent->tangent = loopdata_out->layers[index].data;
+
+                               /* Fill the resulting tangent_mask */
+                               int uv_ind = CustomData_get_named_layer_index(
+                                       loopdata, CD_MLOOPUV, loopdata_out->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);
+                               tangent_mask_curr |= (char)(1 << (uv_ind - uv_start));
+                               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);
+               }
+#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;
+
+               int uv_index, tan_index;
+
+               /* Update active layer index */
+               uv_index = CustomData_get_layer_index_n(loopdata, CD_MLOOPUV, act_uv_n);
+               if (uv_index != -1) {
+                       tan_index = CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, loopdata->layers[uv_index].name);
+                       CustomData_set_layer_active_index(loopdata_out, CD_TANGENT, tan_index);
+               }
+
+               /* Update render layer index */
+               uv_index = CustomData_get_layer_index_n(loopdata, CD_MLOOPUV, ren_uv_n);
+               if (uv_index != -1) {
+                       tan_index = CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, loopdata->layers[uv_index].name);
+                       CustomData_set_layer_render_index(loopdata_out, CD_TANGENT, tan_index);
+               }
+       }
+}
+
+/** \} */
index 2758095850447986399d4b3de79aad3aeb07fe61..62be8bab7cea54415edb089b5a417fa1ed6e6aaa 100644 (file)
@@ -45,6 +45,7 @@
 #include "BKE_editmesh.h"
 #include "BKE_editmesh_tangent.h"
 #include "BKE_mesh.h"
+#include "BKE_mesh_tangent.h"
 #include "BKE_texture.h"
 
 #include "bmesh.h"
@@ -497,18 +498,45 @@ static MeshRenderData *mesh_render_data_create(Mesh *me, const int types)
                                }
                                else {
 #undef me
-                                       if (!CustomData_has_layer(cd_ldata, CD_NORMAL)) {
-                                               BKE_mesh_calc_normals_split(me);
-                                       }
 
-                                       float (*loopnors)[3] = CustomData_get_layer(cd_ldata, CD_NORMAL);
+                                       if (!CustomData_has_layer(&rdata->cd.output.ldata, CD_MLOOPTANGENT)) {
+                                               if (!CustomData_has_layer(cd_ldata, CD_NORMAL)) {
+                                                       BKE_mesh_calc_normals_split(me);
+                                               }
+
+                                               bool calc_active_tangent = false;
+                                               const float (*poly_normals)[3] = rdata->poly_normals;
+                                               const float (*loop_normals)[3] = CustomData_get_layer(cd_ldata, CD_NORMAL);
+                                               char tangent_names[MAX_MTFACE][MAX_NAME];
+                                               int tangent_names_len = 0;
+                                               for (tangent_names_len = 0; tangent_names_len < rdata->cd.layers.uv_len; tangent_names_len++) {
+                                                       BLI_strncpy(
+                                                               tangent_names[tangent_names_len],
+                                                               CustomData_get_layer_name(cd_ldata, CD_MLOOPUV, tangent_names_len), MAX_NAME);
+                                               }
+
+                                               BKE_mesh_calc_loop_tangent_ex(
+                                                       me->mvert,
+                                                       me->mpoly, me->totpoly,
+                                                       me->mloop,
+                                                       rdata->mlooptri, rdata->tri_len,
+                                                       cd_ldata,
+                                                       calc_active_tangent,
+                                                       tangent_names, tangent_names_len,
+                                                       poly_normals, loop_normals,
+                                                       rdata->orco,
+                                                       &rdata->cd.output.ldata, me->totloop,
+                                                       &rdata->cd.output.tangent_mask);
 
-                                       rdata->cd.layers.tangent[i] = CustomData_add_layer(
-                                               cd_ldata, CD_MLOOPTANGENT, CD_CALLOC, NULL, me->totloop);
-                                       CustomData_set_layer_flag(cd_ldata, CD_MLOOPTANGENT, CD_FLAG_TEMPORARY);
+                                               /* If we store tangents in the mesh, set temporary. */
+#if 0
+                                               CustomData_set_layer_flag(cd_ldata, CD_MLOOPTANGENT, CD_FLAG_TEMPORARY);
+#endif
+                                       }
+
+                                       rdata->cd.layers.tangent[i] = CustomData_get_layer_n(&rdata->cd.output.ldata, CD_TANGENT, i);
+                                       BLI_assert(rdata->cd.layers.tangent[i] != NULL);
 
-                                       BKE_mesh_loop_tangents_ex(me->mvert, me->totvert, me->mloop, rdata->cd.layers.tangent[i],
-                                             loopnors, rdata->cd.layers.uv[i], me->totloop, me->mpoly, me->totpoly, NULL);
 #define me DONT_USE_THIS
 #ifdef  me /* quiet warning */
 #endif
@@ -526,7 +554,7 @@ static MeshRenderData *mesh_render_data_create(Mesh *me, const int types)
 #undef me
        }
 
-       return rdata;
+               return rdata;
 }
 
 static void mesh_render_data_free(MeshRenderData *rdata)
index 9b0a25560f99f24a94ad6e4a1c78409883045809..677397eb859f0f1e39bd32c5276c6ddc4cfaba7a 100644 (file)
@@ -48,6 +48,7 @@
 #include "DNA_mesh_types.h"
 
 #include "BKE_mesh.h"
+#include "BKE_mesh_tangent.h"
 #include "BKE_mesh_mapping.h"
 #include "ED_mesh.h"
 
@@ -92,7 +93,7 @@ static void rna_Mesh_calc_tangents(Mesh *mesh, ReportList *reports, const char *
                BKE_mesh_calc_normals_split(mesh);
        }
 
-       BKE_mesh_loop_tangents(mesh, uvmap, r_looptangents, reports);
+       BKE_mesh_calc_loop_tangent_single(mesh, uvmap, r_looptangents, reports);
 }
 
 static void rna_Mesh_free_tangents(Mesh *mesh)