DWM: Tangent support for editmesh
authorCampbell Barton <ideasman42@gmail.com>
Mon, 8 May 2017 22:50:45 +0000 (08:50 +1000)
committerCampbell Barton <ideasman42@gmail.com>
Tue, 9 May 2017 00:26:36 +0000 (10:26 +1000)
source/blender/blenkernel/BKE_editmesh_tangent.h [new file with mode: 0644]
source/blender/blenkernel/CMakeLists.txt
source/blender/blenkernel/intern/editderivedmesh.c
source/blender/blenkernel/intern/editmesh_tangent.c [new file with mode: 0644]
source/blender/draw/intern/draw_cache_impl_mesh.c

diff --git a/source/blender/blenkernel/BKE_editmesh_tangent.h b/source/blender/blenkernel/BKE_editmesh_tangent.h
new file mode 100644 (file)
index 0000000..7d6839a
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * ***** 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.
+ *
+ * Contributor(s): Joseph Eagar.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BKE_EDITMESH_TANGENT_H__
+#define __BKE_EDITMESH_TANGENT_H__
+
+/** \file BKE_editmesh_tangent.h
+ *  \ingroup bke
+ */
+
+void BKE_editmesh_loop_tangent_calc(
+        BMEditMesh *em, 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],
+        CustomData *dm_loopdata_out,
+        const uint dm_loopdata_out_len,
+        char *tangent_mask_curr_p);
+
+#endif /* __BKE_EDITMESH_TANGENT_H__ */
index 9fa6b7cc3cfb0a40b87341b88fd12a9f53ad4b95..1acc45c9f007efc72c37cde163c1f137abd1a9d1 100644 (file)
@@ -103,6 +103,7 @@ set(SRC
        intern/editderivedmesh.c
        intern/editmesh.c
        intern/editmesh_bvh.c
+       intern/editmesh_tangent.c
        intern/effect.c
        intern/fcurve.c
        intern/fluidsim.c
@@ -232,6 +233,7 @@ set(SRC
        BKE_dynamicpaint.h
        BKE_editmesh.h
        BKE_editmesh_bvh.h
+       BKE_editmesh_tangent.h
        BKE_effect.h
        BKE_fcurve.h
        BKE_fluidsim.h
index 19a27499ff0f5d40d6b5328e640b0844be8d5be4..320299d1933fc924919a4a9a691032cdaaf0195a 100644 (file)
@@ -50,6 +50,7 @@
 #include "BKE_mesh.h"
 #include "BKE_editmesh.h"
 #include "BKE_editmesh_bvh.h"
+#include "BKE_editmesh_tangent.h"
 
 #include "DNA_scene_types.h"
 #include "DNA_object_types.h"
@@ -238,383 +239,24 @@ static void emDM_calcLoopNormalsSpaceArray(
 #endif
 }
 
-
-/** \name Tangent Space Calculation
- * \{ */
-
-/* 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 BMLoop *(*looptris)[3];
-       int cd_loop_uv_offset;   /* texture coordinates */
-       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
-
-} SGLSLEditMeshToTangent;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
-/* seems weak but only used on quads */
-static const BMLoop *bm_loop_at_face_index(const BMFace *f, int vert_index)
-{
-       const BMLoop *l = BM_FACE_FIRST_LOOP(f);
-       while (vert_index--) {
-               l = l->next;
-       }
-       return l;
-}
-#endif
-
-/* interface */
-#include "mikktspace.h"
-
-static int emdm_ts_GetNumFaces(const SMikkTSpaceContext *pContext)
-{
-       SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
-       return pMesh->num_face_as_quad_map;
-#else
-       return pMesh->numTessFaces;
-#endif
-}
-
-static int emdm_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num)
-{
-#ifdef USE_LOOPTRI_DETECT_QUADS
-       SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
-       if (pMesh->face_as_quad_map) {
-               const BMLoop **lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
-               if (lt[0]->f->len == 4) {
-                       return 4;
-               }
-       }
-       return 3;
-#else
-       UNUSED_VARS(pContext, face_num);
-       return 3;
-#endif
-}
-
-static void emdm_ts_GetPosition(
-        const SMikkTSpaceContext *pContext, float r_co[3],
-        const int face_num, const int vert_index)
-{
-       //assert(vert_index >= 0 && vert_index < 4);
-       SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
-       const BMLoop **lt;
-       const BMLoop *l;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
-       if (pMesh->face_as_quad_map) {
-               lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
-               if (lt[0]->f->len == 4) {
-                       l = bm_loop_at_face_index(lt[0]->f, vert_index);
-                       goto finally;
-               }
-               /* fall through to regular triangle */
-       }
-       else {
-               lt = pMesh->looptris[face_num];
-       }
-#else
-       lt = pMesh->looptris[face_num];
-#endif
-       l = lt[vert_index];
-
-       const float *co;
-
-finally:
-       co = l->v->co;
-       copy_v3_v3(r_co, co);
-}
-
-static void emdm_ts_GetTextureCoordinate(
-        const SMikkTSpaceContext *pContext, float r_uv[2],
-        const int face_num, const int vert_index)
-{
-       //assert(vert_index >= 0 && vert_index < 4);
-       SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
-       const BMLoop **lt;
-       const BMLoop *l;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
-       if (pMesh->face_as_quad_map) {
-               lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
-               if (lt[0]->f->len == 4) {
-                       l = bm_loop_at_face_index(lt[0]->f, vert_index);
-                       goto finally;
-               }
-               /* fall through to regular triangle */
-       }
-       else {
-               lt = pMesh->looptris[face_num];
-       }
-#else
-       lt = pMesh->looptris[face_num];
-#endif
-       l = lt[vert_index];
-
-finally:
-       if (pMesh->cd_loop_uv_offset != -1) {
-               const float *uv = BM_ELEM_CD_GET_VOID_P(l, pMesh->cd_loop_uv_offset);
-               copy_v2_v2(r_uv, uv);
-       }
-       else {
-               const float *orco = pMesh->orco[BM_elem_index_get(l->v)];
-               map_to_sphere(&r_uv[0], &r_uv[1], orco[0], orco[1], orco[2]);
-       }
-}
-
-static void emdm_ts_GetNormal(
-        const SMikkTSpaceContext *pContext, float r_no[3],
-        const int face_num, const int vert_index)
-{
-       //assert(vert_index >= 0 && vert_index < 4);
-       SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
-       const BMLoop **lt;
-       const BMLoop *l;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
-       if (pMesh->face_as_quad_map) {
-               lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
-               if (lt[0]->f->len == 4) {
-                       l = bm_loop_at_face_index(lt[0]->f, vert_index);
-                       goto finally;
-               }
-               /* fall through to regular triangle */
-       }
-       else {
-               lt = pMesh->looptris[face_num];
-       }
-#else
-       lt = pMesh->looptris[face_num];
-#endif
-       l = lt[vert_index];
-
-finally:
-       if (pMesh->precomputedLoopNormals) {
-               copy_v3_v3(r_no, pMesh->precomputedLoopNormals[BM_elem_index_get(l)]);
-       }
-       else if (BM_elem_flag_test(l->f, BM_ELEM_SMOOTH) == 0) {  /* flat */
-               if (pMesh->precomputedFaceNormals) {
-                       copy_v3_v3(r_no, pMesh->precomputedFaceNormals[BM_elem_index_get(l->f)]);
-               }
-               else {
-                       copy_v3_v3(r_no, l->f->no);
-               }
-       }
-       else {
-               copy_v3_v3(r_no, l->v->no);
-       }
-}
-
-static void emdm_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);
-       SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
-       const BMLoop **lt;
-       const BMLoop *l;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
-       if (pMesh->face_as_quad_map) {
-               lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
-               if (lt[0]->f->len == 4) {
-                       l = bm_loop_at_face_index(lt[0]->f, vert_index);
-                       goto finally;
-               }
-               /* fall through to regular triangle */
-       }
-       else {
-               lt = pMesh->looptris[face_num];
-       }
-#else
-       lt = pMesh->looptris[face_num];
-#endif
-       l = lt[vert_index];
-
-       float *pRes;
-
-finally:
-       pRes = pMesh->tangent[BM_elem_index_get(l)];
-       copy_v3_v3(pRes, fvTangent);
-       pRes[3] = fSign;
-}
-
-static void emDM_calc_loop_tangents_thread(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
-{
-       struct SGLSLEditMeshToTangent *mesh2tangent = taskdata;
-       /* new computation method */
-       {
-               SMikkTSpaceContext sContext = {NULL};
-               SMikkTSpaceInterface sInterface = {NULL};
-               sContext.m_pUserData = mesh2tangent;
-               sContext.m_pInterface = &sInterface;
-               sInterface.m_getNumFaces = emdm_ts_GetNumFaces;
-               sInterface.m_getNumVerticesOfFace = emdm_ts_GetNumVertsOfFace;
-               sInterface.m_getPosition = emdm_ts_GetPosition;
-               sInterface.m_getTexCoord = emdm_ts_GetTextureCoordinate;
-               sInterface.m_getNormal = emdm_ts_GetNormal;
-               sInterface.m_setTSpaceBasic = emdm_ts_SetTSpace;
-               /* 0 if failed */
-               genTangSpaceDefault(&sContext);
-       }
-}
-
-/**
- * \see #DM_calc_loop_tangents, 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.
- */
-
 static void emDM_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)
 {
        EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
        BMEditMesh *em = bmdm->em;
-       BMesh *bm = bmdm->em->bm;
-       if (CustomData_number_of_layers(&bm->ldata, 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(
-               &bm->ldata, 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) {
-               for (int i = 0; i < tangent_names_count; i++)
-                       if (tangent_names[i][0])
-                               DM_add_named_tangent_layer_for_uv(&bm->ldata, &dm->loopData, dm->numLoopData, tangent_names[i]);
-               if (calc_act && act_uv_name[0])
-                       DM_add_named_tangent_layer_for_uv(&bm->ldata, &dm->loopData, dm->numLoopData, act_uv_name);
-               if (calc_ren && ren_uv_name[0])
-                       DM_add_named_tangent_layer_for_uv(&bm->ldata, &dm->loopData, dm->numLoopData, ren_uv_name);
-               int totface = em->tottri;
-#ifdef USE_LOOPTRI_DETECT_QUADS
-               int num_face_as_quad_map;
-               int *face_as_quad_map = NULL;
-
-               /* map faces to quads */
-               if (bmdm->em->tottri != bm->totface) {
-                       /* 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 i, j;
-                       for (i = 0, j = 0; j < totface; i++, j++) {
-                               face_as_quad_map[i] = j;
-                               /* step over all quads */
-                               if (em->looptris[j][0]->f->len == 4) {
-                                       j++;  /* skips the nest looptri */
-                               }
-                       }
-                       num_face_as_quad_map = i;
-               }
-               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 */
-                       SGLSLEditMeshToTangent data_array[MAX_MTFACE];
-                       int index = 0;
-                       int n = 0;
-                       CustomData_update_typemap(&dm->loopData);
-                       const int tangent_layer_num = CustomData_number_of_layers(&dm->loopData, CD_TANGENT);
-                       for (n = 0; n < tangent_layer_num; n++) {
-                               index = CustomData_get_layer_index_n(&dm->loopData, CD_TANGENT, n);
-                               BLI_assert(n < MAX_MTFACE);
-                               SGLSLEditMeshToTangent *mesh2tangent = &data_array[n];
-                               mesh2tangent->numTessFaces = em->tottri;
-#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->precomputedFaceNormals = bmdm->polyNos;  /* dm->getPolyDataArray(dm, CD_NORMAL) */
-                               /* 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 = CustomData_get_layer(&dm->loopData, CD_NORMAL);
-                               mesh2tangent->cd_loop_uv_offset = CustomData_get_n_offset(&bm->ldata, CD_MLOOPUV, n);
-
-                               /* needed for indexing loop-tangents */
-                               int htype_index = BM_LOOP;
-                               if (mesh2tangent->cd_loop_uv_offset == -1) {
-                                       mesh2tangent->orco = dm->getVertDataArray(dm, CD_ORCO);
-                                       if (!mesh2tangent->orco)
-                                               continue;
-                                       /* needed for orco lookups */
-                                       htype_index |= BM_VERT;
-                               }
-                               if (mesh2tangent->precomputedFaceNormals) {
-                                       /* needed for face normal lookups */
-                                       htype_index |= BM_FACE;
-                               }
-                               BM_mesh_elem_index_ensure(bm, htype_index);
-
-                               mesh2tangent->looptris = (const BMLoop *(*)[3])em->looptris;
-                               mesh2tangent->tangent = dm->loopData.layers[index].data;
-
-                               /* Fill the resulting tangent_mask */
-                               int uv_ind = CustomData_get_named_layer_index(&bm->ldata, CD_MLOOPUV, dm->loopData.layers[index].name);
-                               int uv_start = CustomData_get_layer_index(&bm->ldata, 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, emDM_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
-       }
-       /* Update active layer index */
-       int uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, act_uv_n);
-       int tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, bm->ldata.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(&bm->ldata, CD_MLOOPUV, ren_uv_n);
-       tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, bm->ldata.layers[uv_index].name);
-       CustomData_set_layer_render_index(&dm->loopData, CD_TANGENT, tan_index);
+       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 */
+       BKE_editmesh_loop_tangent_calc(
+               em, calc_active_tangent,
+               tangent_names, tangent_names_len,
+               poly_normals, loop_normals,
+               vert_orco,
+               &dm->loopData, dm->numLoopData,
+               &dm->tangent_mask);
 }
 
-/** \} */
-
 
 static void emDM_recalcTessellation(DerivedMesh *UNUSED(dm))
 {
diff --git a/source/blender/blenkernel/intern/editmesh_tangent.c b/source/blender/blenkernel/intern/editmesh_tangent.c
new file mode 100644 (file)
index 0000000..501ddb1
--- /dev/null
@@ -0,0 +1,419 @@
+/*
+ * ***** 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 *****
+ */
+
+/** \file blender/blenkernel/intern/editmesh_tangent.c
+ *  \ingroup bke
+ */
+
+#include "BLI_math.h"
+#include "BLI_task.h"
+
+#include "BKE_DerivedMesh.h"
+
+#include "BKE_mesh.h"
+#include "BKE_editmesh.h"
+#include "BKE_editmesh_tangent.h"
+
+#include "MEM_guardedalloc.h"
+
+/* interface */
+#include "mikktspace.h"
+
+/** \name Tangent Space Calculation
+ * \{ */
+
+/* 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 BMLoop *(*looptris)[3];
+       int cd_loop_uv_offset;   /* texture coordinates */
+       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
+
+} SGLSLEditMeshToTangent;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+/* seems weak but only used on quads */
+static const BMLoop *bm_loop_at_face_index(const BMFace *f, int vert_index)
+{
+       const BMLoop *l = BM_FACE_FIRST_LOOP(f);
+       while (vert_index--) {
+               l = l->next;
+       }
+       return l;
+}
+#endif
+
+static int emdm_ts_GetNumFaces(const SMikkTSpaceContext *pContext)
+{
+       SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+       return pMesh->num_face_as_quad_map;
+#else
+       return pMesh->numTessFaces;
+#endif
+}
+
+static int emdm_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num)
+{
+#ifdef USE_LOOPTRI_DETECT_QUADS
+       SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
+       if (pMesh->face_as_quad_map) {
+               const BMLoop **lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
+               if (lt[0]->f->len == 4) {
+                       return 4;
+               }
+       }
+       return 3;
+#else
+       UNUSED_VARS(pContext, face_num);
+       return 3;
+#endif
+}
+
+static void emdm_ts_GetPosition(
+        const SMikkTSpaceContext *pContext, float r_co[3],
+        const int face_num, const int vert_index)
+{
+       //assert(vert_index >= 0 && vert_index < 4);
+       SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
+       const BMLoop **lt;
+       const BMLoop *l;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+       if (pMesh->face_as_quad_map) {
+               lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
+               if (lt[0]->f->len == 4) {
+                       l = bm_loop_at_face_index(lt[0]->f, vert_index);
+                       goto finally;
+               }
+               /* fall through to regular triangle */
+       }
+       else {
+               lt = pMesh->looptris[face_num];
+       }
+#else
+       lt = pMesh->looptris[face_num];
+#endif
+       l = lt[vert_index];
+
+       const float *co;
+
+finally:
+       co = l->v->co;
+       copy_v3_v3(r_co, co);
+}
+
+static void emdm_ts_GetTextureCoordinate(
+        const SMikkTSpaceContext *pContext, float r_uv[2],
+        const int face_num, const int vert_index)
+{
+       //assert(vert_index >= 0 && vert_index < 4);
+       SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
+       const BMLoop **lt;
+       const BMLoop *l;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+       if (pMesh->face_as_quad_map) {
+               lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
+               if (lt[0]->f->len == 4) {
+                       l = bm_loop_at_face_index(lt[0]->f, vert_index);
+                       goto finally;
+               }
+               /* fall through to regular triangle */
+       }
+       else {
+               lt = pMesh->looptris[face_num];
+       }
+#else
+       lt = pMesh->looptris[face_num];
+#endif
+       l = lt[vert_index];
+
+finally:
+       if (pMesh->cd_loop_uv_offset != -1) {
+               const float *uv = BM_ELEM_CD_GET_VOID_P(l, pMesh->cd_loop_uv_offset);
+               copy_v2_v2(r_uv, uv);
+       }
+       else {
+               const float *orco = pMesh->orco[BM_elem_index_get(l->v)];
+               map_to_sphere(&r_uv[0], &r_uv[1], orco[0], orco[1], orco[2]);
+       }
+}
+
+static void emdm_ts_GetNormal(
+        const SMikkTSpaceContext *pContext, float r_no[3],
+        const int face_num, const int vert_index)
+{
+       //assert(vert_index >= 0 && vert_index < 4);
+       SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
+       const BMLoop **lt;
+       const BMLoop *l;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+       if (pMesh->face_as_quad_map) {
+               lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
+               if (lt[0]->f->len == 4) {
+                       l = bm_loop_at_face_index(lt[0]->f, vert_index);
+                       goto finally;
+               }
+               /* fall through to regular triangle */
+       }
+       else {
+               lt = pMesh->looptris[face_num];
+       }
+#else
+       lt = pMesh->looptris[face_num];
+#endif
+       l = lt[vert_index];
+
+finally:
+       if (pMesh->precomputedLoopNormals) {
+               copy_v3_v3(r_no, pMesh->precomputedLoopNormals[BM_elem_index_get(l)]);
+       }
+       else if (BM_elem_flag_test(l->f, BM_ELEM_SMOOTH) == 0) {  /* flat */
+               if (pMesh->precomputedFaceNormals) {
+                       copy_v3_v3(r_no, pMesh->precomputedFaceNormals[BM_elem_index_get(l->f)]);
+               }
+               else {
+                       copy_v3_v3(r_no, l->f->no);
+               }
+       }
+       else {
+               copy_v3_v3(r_no, l->v->no);
+       }
+}
+
+static void emdm_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);
+       SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
+       const BMLoop **lt;
+       const BMLoop *l;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+       if (pMesh->face_as_quad_map) {
+               lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
+               if (lt[0]->f->len == 4) {
+                       l = bm_loop_at_face_index(lt[0]->f, vert_index);
+                       goto finally;
+               }
+               /* fall through to regular triangle */
+       }
+       else {
+               lt = pMesh->looptris[face_num];
+       }
+#else
+       lt = pMesh->looptris[face_num];
+#endif
+       l = lt[vert_index];
+
+       float *pRes;
+
+finally:
+       pRes = pMesh->tangent[BM_elem_index_get(l)];
+       copy_v3_v3(pRes, fvTangent);
+       pRes[3] = fSign;
+}
+
+static void emDM_calc_loop_tangents_thread(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
+{
+       struct SGLSLEditMeshToTangent *mesh2tangent = taskdata;
+       /* new computation method */
+       {
+               SMikkTSpaceContext sContext = {NULL};
+               SMikkTSpaceInterface sInterface = {NULL};
+               sContext.m_pUserData = mesh2tangent;
+               sContext.m_pInterface = &sInterface;
+               sInterface.m_getNumFaces = emdm_ts_GetNumFaces;
+               sInterface.m_getNumVerticesOfFace = emdm_ts_GetNumVertsOfFace;
+               sInterface.m_getPosition = emdm_ts_GetPosition;
+               sInterface.m_getTexCoord = emdm_ts_GetTextureCoordinate;
+               sInterface.m_getNormal = emdm_ts_GetNormal;
+               sInterface.m_setTSpaceBasic = emdm_ts_SetTSpace;
+               /* 0 if failed */
+               genTangSpaceDefault(&sContext);
+       }
+}
+
+/**
+ * \see #DM_calc_loop_tangents, 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.
+ */
+void BKE_editmesh_loop_tangent_calc(
+        BMEditMesh *em, 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)
+{
+       BMesh *bm = em->bm;
+       if (CustomData_number_of_layers(&bm->ldata, 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;
+       char tangent_mask_curr = *tangent_mask_curr_p;
+
+       DM_calc_loop_tangents_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]);
+               if (calc_act && act_uv_name[0])
+                       DM_add_named_tangent_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);
+               int totface = em->tottri;
+#ifdef USE_LOOPTRI_DETECT_QUADS
+               int num_face_as_quad_map;
+               int *face_as_quad_map = NULL;
+
+               /* map faces to quads */
+               if (em->tottri != bm->totface) {
+                       /* 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 i, j;
+                       for (i = 0, j = 0; j < totface; i++, j++) {
+                               face_as_quad_map[i] = j;
+                               /* step over all quads */
+                               if (em->looptris[j][0]->f->len == 4) {
+                                       j++;  /* skips the nest looptri */
+                               }
+                       }
+                       num_face_as_quad_map = i;
+               }
+               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);
+
+                       tangent_mask_curr = 0;
+                       /* Calculate tangent layers */
+                       SGLSLEditMeshToTangent data_array[MAX_MTFACE];
+                       int index = 0;
+                       int n = 0;
+                       CustomData_update_typemap(loopdata_out);
+                       const int tangent_layer_num = CustomData_number_of_layers(loopdata_out, CD_TANGENT);
+                       for (n = 0; n < tangent_layer_num; n++) {
+                               index = CustomData_get_layer_index_n(loopdata_out, CD_TANGENT, n);
+                               BLI_assert(n < MAX_MTFACE);
+                               SGLSLEditMeshToTangent *mesh2tangent = &data_array[n];
+                               mesh2tangent->numTessFaces = em->tottri;
+#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->precomputedFaceNormals = poly_normals;  /* dm->getPolyDataArray(dm, CD_NORMAL) */
+                               /* 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->cd_loop_uv_offset = CustomData_get_n_offset(&bm->ldata, CD_MLOOPUV, n);
+
+                               /* needed for indexing loop-tangents */
+                               int htype_index = BM_LOOP;
+                               if (mesh2tangent->cd_loop_uv_offset == -1) {
+                                       mesh2tangent->orco = vert_orco;
+                                       if (!mesh2tangent->orco)
+                                               continue;
+                                       /* needed for orco lookups */
+                                       htype_index |= BM_VERT;
+                               }
+                               if (mesh2tangent->precomputedFaceNormals) {
+                                       /* needed for face normal lookups */
+                                       htype_index |= BM_FACE;
+                               }
+                               BM_mesh_elem_index_ensure(bm, htype_index);
+
+                               mesh2tangent->looptris = (const BMLoop *(*)[3])em->looptris;
+                               mesh2tangent->tangent = loopdata_out->layers[index].data;
+
+                               /* Fill the resulting tangent_mask */
+                               int uv_ind = CustomData_get_named_layer_index(
+                                       &bm->ldata, CD_MLOOPUV, loopdata_out->layers[index].name);
+                               int uv_start = CustomData_get_layer_index(&bm->ldata, CD_MLOOPUV);
+                               BLI_assert(uv_ind != -1 && uv_start != -1);
+                               BLI_assert(uv_ind - uv_start < MAX_MTFACE);
+                               tangent_mask_curr |= 1 << (uv_ind - uv_start);
+                               BLI_task_pool_push(task_pool, emDM_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;
+
+       /* Update active layer index */
+       int uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, act_uv_n);
+       int tan_index = CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, bm->ldata.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(&bm->ldata, CD_MLOOPUV, ren_uv_n);
+       tan_index = CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, bm->ldata.layers[uv_index].name);
+       CustomData_set_layer_render_index(loopdata_out, CD_TANGENT, tan_index);
+}
+
+/** \} */
\ No newline at end of file
index a9d54da9d08a8b23f16190b369a244f6019626b0..fabb0a3f3a0c03b75510dfa68b10e4fef7739a67 100644 (file)
@@ -43,6 +43,7 @@
 #include "BKE_deform.h"
 #include "BKE_DerivedMesh.h"
 #include "BKE_editmesh.h"
+#include "BKE_editmesh_tangent.h"
 #include "BKE_mesh.h"
 #include "BKE_texture.h"
 
@@ -153,9 +154,16 @@ typedef struct MeshRenderData {
                int bweight;
                int *uv;
                int *vcol;
-               int *tangent;
+//             int *tangent;
        } cd_offset;
 
+       /* for certain cases we need an output loop-data storage (bmesh tangents) */
+       struct {
+               CustomData ldata;
+               /* grr, special case variable (use in place of 'dm->tangent_mask') */
+               char tangent_mask;
+       } cd_output;
+
        char (*auto_names)[32];
        char (*uv_names)[32];
        char (*vcol_names)[32];
@@ -223,6 +231,8 @@ static MeshRenderData *mesh_render_data_create(Mesh *me, const int types)
        rdata->types = types;
        rdata->mat_len = mesh_render_mat_len_get(me);
 
+       CustomData_reset(&rdata->cd_output.ldata);
+
        if (me->edit_btmesh) {
                BMEditMesh *embm = me->edit_btmesh;
                BMesh *bm = embm->bm;
@@ -334,8 +344,46 @@ static MeshRenderData *mesh_render_data_create(Mesh *me, const int types)
        }
 
        if (types & MR_DATATYPE_SHADING) {
-               rdata->uv_len = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
-               rdata->vcol_len = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
+               CustomData *cd_vdata, *cd_ldata;
+
+               if (me->edit_btmesh) {
+                       BMesh *bm = me->edit_btmesh->bm;
+                       cd_vdata = &bm->vdata;
+                       cd_ldata = &bm->ldata;
+               }
+               else {
+                       cd_vdata = &me->vdata;
+                       cd_ldata = &me->ldata;
+               }
+
+               rdata->orco = CustomData_get_layer(cd_vdata, CD_ORCO);
+               /* If orco is not available compute it ourselves */
+               if (!rdata->orco) {
+                       if (me->edit_btmesh) {
+                               BMesh *bm = me->edit_btmesh->bm;
+                               rdata->orco = MEM_mallocN(sizeof(*rdata->orco) * rdata->vert_len, "orco mesh");
+                               BLI_assert((bm->elem_table_dirty & BM_VERT) == 0);
+                               BMVert **vtable = bm->vtable;
+                               for (int i = 0; i < bm->totvert; i++) {
+                                       copy_v3_v3(rdata->orco[i], vtable[i]->co);
+                               }
+                               BKE_mesh_orco_verts_transform(me, rdata->orco, rdata->vert_len, 0);
+                       }
+                       else {
+                               rdata->orco = MEM_mallocN(sizeof(*rdata->orco) * rdata->vert_len, "orco mesh");
+                               MVert *mvert = rdata->mvert;
+                               for (int a = 0; a < rdata->vert_len; a++, mvert++) {
+                                       copy_v3_v3(rdata->orco[a], mvert->co);
+                               }
+                               BKE_mesh_orco_verts_transform(me, rdata->orco, rdata->vert_len, 0);
+                       }
+               }
+
+               /* don't access mesh directly, instead use vars taken from BMesh or Mesh */
+#define me DONT_USE_THIS
+
+               rdata->uv_len = CustomData_number_of_layers(cd_ldata, CD_MLOOPUV);
+               rdata->vcol_len = CustomData_number_of_layers(cd_ldata, CD_MLOOPCOL);
 
                rdata->mloopuv = MEM_mallocN(sizeof(*rdata->mloopuv) * rdata->uv_len, "rdata->mloopuv");
                rdata->mloopcol = MEM_mallocN(sizeof(*rdata->mloopcol) * rdata->vcol_len, "rdata->mloopcol");
@@ -347,7 +395,6 @@ static MeshRenderData *mesh_render_data_create(Mesh *me, const int types)
 
                rdata->cd_offset.uv = MEM_mallocN(sizeof(*rdata->cd_offset.uv) * rdata->uv_len, "rdata->uv_ofs");
                rdata->cd_offset.vcol = MEM_mallocN(sizeof(*rdata->cd_offset.vcol) * rdata->vcol_len, "rdata->vcol_ofs");
-               rdata->cd_offset.tangent = MEM_mallocN(sizeof(*rdata->cd_offset.tangent) * rdata->uv_len, "rdata->tangent_ofs");
 
                /* Allocate max */
                rdata->auto_vcol = MEM_callocN(
@@ -363,32 +410,32 @@ static MeshRenderData *mesh_render_data_create(Mesh *me, const int types)
                 * to a safe glsl var name, but without name clash.
                 * NOTE 2 : Replicate changes to code_generate_vertex_new() in gpu_codegen.c */
                for (int i = 0; i < rdata->vcol_len; ++i) {
-                       const char *name = CustomData_get_layer_name(&me->ldata, CD_MLOOPCOL, i);
+                       const char *name = CustomData_get_layer_name(cd_ldata, CD_MLOOPCOL, i);
                        unsigned int hash = BLI_ghashutil_strhash_p(name);
                        BLI_snprintf(rdata->vcol_names[i], sizeof(*rdata->vcol_names), "c%u", hash);
-                       rdata->mloopcol[i] = CustomData_get_layer_n(&me->ldata, CD_MLOOPCOL, i);
+                       rdata->mloopcol[i] = CustomData_get_layer_n(cd_ldata, CD_MLOOPCOL, i);
                        if (rdata->edit_bmesh) {
                                rdata->cd_offset.vcol[i] = CustomData_get_n_offset(&rdata->edit_bmesh->bm->ldata, CD_MLOOPCOL, i);
                        }
 
                        /* Gather number of auto layers. */
                        /* We only do vcols that are not overridden by uvs */
-                       if (CustomData_get_named_layer_index(&me->ldata, CD_MLOOPUV, name) == -1) {
+                       if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, name) == -1) {
                                BLI_snprintf(rdata->auto_names[rdata->uv_len + i], sizeof(*rdata->auto_names), "a%u", hash);
                                rdata->auto_vcol[i] = true;
                        }
                }
 
                /* Start Fresh */
-               CustomData_free_layers(&me->ldata, CD_MLOOPTANGENT, me->totloop);
+               CustomData_free_layers(cd_ldata, CD_MLOOPTANGENT, rdata->loop_len);
                for (int i = 0; i < rdata->uv_len; ++i) {
-                       const char *name = CustomData_get_layer_name(&me->ldata, CD_MLOOPUV, i);
+                       const char *name = CustomData_get_layer_name(cd_ldata, CD_MLOOPUV, i);
                        unsigned int hash = BLI_ghashutil_strhash_p(name);
 
                        {
                                /* UVs */
                                BLI_snprintf(rdata->uv_names[i], sizeof(*rdata->uv_names), "u%u", hash);
-                               rdata->mloopuv[i] = CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, i);
+                               rdata->mloopuv[i] = CustomData_get_layer_n(cd_ldata, CD_MLOOPUV, i);
                                if (rdata->edit_bmesh) {
                                        rdata->cd_offset.uv[i] = CustomData_get_n_offset(&rdata->edit_bmesh->bm->ldata, CD_MLOOPUV, i);
                                }
@@ -400,70 +447,64 @@ static MeshRenderData *mesh_render_data_create(Mesh *me, const int types)
                                BLI_snprintf(rdata->tangent_names[i], sizeof(*rdata->tangent_names), "t%u", hash);
 
                                if (rdata->edit_bmesh) {
-#if 0 /* TODO Waiting for the port of emDM_calc_loop_tangents */
-                                       BMesh *bm = rdata->edit_bmesh->bm;
-
-                                       float (*loopnors)[3] = CustomData_get_layer(&bm->ldata, CD_NORMAL);
+                                       BMEditMesh *em = rdata->edit_bmesh;
+                                       BMesh *bm = em->bm;
+
+                                       if (!CustomData_has_layer(&rdata->cd_output.ldata, CD_MLOOPTANGENT)) {
+                                               bool calc_active_tangent = false;
+                                               float (*poly_normals)[3] = rdata->poly_normals;
+                                               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->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);
+                                               }
 
-                                       rdata->mtangent[i] = CustomData_add_layer(
-                                               &bm->ldata, CD_MLOOPTANGENT, CD_CALLOC, NULL, bm->totloop);
-                                       CustomData_set_layer_flag(&bm->ldata, CD_MLOOPTANGENT, CD_FLAG_TEMPORARY);
+                                               BKE_editmesh_loop_tangent_calc(
+                                                       em, calc_active_tangent,
+                                                       tangent_names, tangent_names_len,
+                                                       poly_normals, loop_normals,
+                                                       rdata->orco,
+                                                       &rdata->cd_output.ldata, bm->totloop,
+                                                       &rdata->cd_output.tangent_mask);
+                                       }
 
-                                       BKE_mesh_loop_tangents_ex(bm->mvert, bm->totvert, bm->mloop, rdata->mtangent[i],
-                                             loopnors, rdata->mloopuv[i], bm->totloop, bm->mpoly, bm->totpoly, NULL);
+                                       /* note: BKE_editmesh_loop_tangent_calc calculates 'CD_TANGENT',
+                                        * not 'CD_MLOOPTANGENT' (as done below). It's OK, they're compatible. */
+                                       rdata->mtangent[i] = CustomData_get_layer_n(&rdata->cd_output.ldata, CD_TANGENT, i);
+                                       BLI_assert(rdata->mtangent[i] != NULL);
 
-                                       rdata->tangent_ofs[i] = CustomData_get_n_offset(&bm->ldata, CD_MLOOPTANGENT, i);
-#else
-                                       rdata->cd_offset.tangent[i] = -1;
-#endif
+                                       /* special case, we don't use offsets here */
                                }
                                else {
-                                       if (!CustomData_has_layer(&me->ldata, CD_NORMAL)) {
+#undef me
+                                       if (!CustomData_has_layer(cd_ldata, CD_NORMAL)) {
                                                BKE_mesh_calc_normals_split(me);
                                        }
 
-                                       float (*loopnors)[3] = CustomData_get_layer(&me->ldata, CD_NORMAL);
+                                       float (*loopnors)[3] = CustomData_get_layer(cd_ldata, CD_NORMAL);
 
                                        rdata->mtangent[i] = CustomData_add_layer(
-                                               &me->ldata, CD_MLOOPTANGENT, CD_CALLOC, NULL, me->totloop);
-                                       CustomData_set_layer_flag(&me->ldata, CD_MLOOPTANGENT, CD_FLAG_TEMPORARY);
+                                               cd_ldata, CD_MLOOPTANGENT, CD_CALLOC, NULL, me->totloop);
+                                       CustomData_set_layer_flag(cd_ldata, CD_MLOOPTANGENT, CD_FLAG_TEMPORARY);
 
                                        BKE_mesh_loop_tangents_ex(me->mvert, me->totvert, me->mloop, rdata->mtangent[i],
                                              loopnors, rdata->mloopuv[i], me->totloop, me->mpoly, me->totpoly, NULL);
+#define me DONT_USE_THIS
                                }
                        }
                }
 
                rdata->uv_active = CustomData_get_active_layer_index(
-                       &me->ldata, CD_MLOOPUV) - CustomData_get_layer_index(&me->ldata, CD_MLOOPUV);
+                       cd_ldata, CD_MLOOPUV) - CustomData_get_layer_index(cd_ldata, CD_MLOOPUV);
                rdata->vcol_active = CustomData_get_active_layer_index(
-                       &me->ldata, CD_MLOOPCOL) - CustomData_get_layer_index(&me->ldata, CD_MLOOPCOL);
+                       cd_ldata, CD_MLOOPCOL) - CustomData_get_layer_index(cd_ldata, CD_MLOOPCOL);
                rdata->tangent_active = CustomData_get_active_layer_index(
-                       &me->ldata, CD_MLOOPTANGENT) - CustomData_get_layer_index(&me->ldata, CD_MLOOPTANGENT);
-
-               rdata->orco = CustomData_get_layer(&me->vdata, CD_ORCO);
+                       cd_ldata, CD_MLOOPTANGENT) - CustomData_get_layer_index(cd_ldata, CD_MLOOPTANGENT);
 
-               /* If orco is not available compute it ourselves */
-               if (!rdata->orco) {
-                       if (me->edit_btmesh) {
-                               BMesh *bm = me->edit_btmesh->bm;
-                               rdata->orco = MEM_mallocN(sizeof(*rdata->orco) * rdata->vert_len, "orco mesh");
-                               BLI_assert((bm->elem_table_dirty & BM_VERT) == 0);
-                               BMVert **vtable = bm->vtable;
-                               for (int i = 0; i < bm->totvert; i++) {
-                                       copy_v3_v3(rdata->orco[i], vtable[i]->co);
-                               }
-                               BKE_mesh_orco_verts_transform(me, rdata->orco, rdata->vert_len, 0);
-                       }
-                       else {
-                               rdata->orco = MEM_mallocN(sizeof(*rdata->orco) * rdata->vert_len, "orco mesh");
-                               MVert *mvert = rdata->mvert;
-                               for (int a = 0; a < rdata->vert_len; a++, mvert++) {
-                                       copy_v3_v3(rdata->orco[a], mvert->co);
-                               }
-                               BKE_mesh_orco_verts_transform(me, rdata->orco, rdata->vert_len, 0);
-                       }
-               }
+#undef me
        }
 
        return rdata;
@@ -475,7 +516,6 @@ static void mesh_render_data_free(MeshRenderData *rdata)
        MEM_SAFE_FREE(rdata->auto_names);
        MEM_SAFE_FREE(rdata->cd_offset.uv);
        MEM_SAFE_FREE(rdata->cd_offset.vcol);
-       MEM_SAFE_FREE(rdata->cd_offset.tangent);
        MEM_SAFE_FREE(rdata->orco);
        MEM_SAFE_FREE(rdata->mloopuv);
        MEM_SAFE_FREE(rdata->mloopcol);
@@ -493,6 +533,9 @@ static void mesh_render_data_free(MeshRenderData *rdata)
        MEM_SAFE_FREE(rdata->vert_weight_color);
        MEM_SAFE_FREE(rdata->edge_selection);
        MEM_SAFE_FREE(rdata->vert_color);
+
+       CustomData_free(&rdata->cd_output.ldata, rdata->loop_len);
+
        MEM_freeN(rdata);
 }
 
@@ -1108,17 +1151,10 @@ static void mesh_render_data_looptri_tans_get(
         float *(*r_vert_tans)[3])
 {
        if (rdata->edit_bmesh) {
-#if 0 /* waiting for edit mesh tangent calculation */
                const BMLoop **bm_looptri = (const BMLoop **)rdata->edit_bmesh->looptris[tri_idx];
-               (*r_vert_tans)[0] = ((float *)BM_ELEM_CD_GET_VOID_P(bm_looptri[0], rdata->cd_offset.tangent[tangent_layer]));
-               (*r_vert_tans)[1] = ((float *)BM_ELEM_CD_GET_VOID_P(bm_looptri[1], rdata->cd_offset.tangent[tangent_layer]));
-               (*r_vert_tans)[2] = ((float *)BM_ELEM_CD_GET_VOID_P(bm_looptri[2], rdata->cd_offset.tangent[tangent_layer]));
-#else
-               static float tan[4] = {0.0f};
-               (*r_vert_tans)[0] = tan;
-               (*r_vert_tans)[1] = tan;
-               (*r_vert_tans)[2] = tan;
-#endif
+               (*r_vert_tans)[0] = rdata->mtangent[tangent_layer][BM_elem_index_get(bm_looptri[0])];
+               (*r_vert_tans)[1] = rdata->mtangent[tangent_layer][BM_elem_index_get(bm_looptri[1])];
+               (*r_vert_tans)[2] = rdata->mtangent[tangent_layer][BM_elem_index_get(bm_looptri[2])];
        }
        else {
                const MLoopTri *mlt = &rdata->mlooptri[tri_idx];