merge with/from trunk at r35190
[blender.git] / source / blender / blenkernel / intern / DerivedMesh.c
index c9a1cfc4618aaeb7494f8248f4ffccc4c033815b..05c06e86cd0cfde76ed4bb243b893d1eb3e8f3ea 100644 (file)
@@ -1,4 +1,4 @@
-/**
+/*
  * $Id$
  *
  * ***** BEGIN GPL LICENSE BLOCK *****
@@ -44,6 +44,7 @@
 #include "BLI_memarena.h"
 #include "BLI_array.h"
 #include "BLI_pbvh.h"
+#include "BLI_utildefines.h"
 
 #include "BKE_cdderivedmesh.h"
 #include "BKE_displist.h"
 #include "BKE_object.h"
 #include "BKE_paint.h"
 #include "BKE_texture.h"
-#include "BKE_utildefines.h"
+#include "BKE_multires.h"
 #include "BKE_particle.h"
 #include "BKE_tessmesh.h"
 #include "BKE_bvhutils.h"
 
+
 #include "BLO_sys_types.h" // for intptr_t support
 
 #include "BIF_gl.h"
@@ -68,6 +70,8 @@
 #include "GPU_extensions.h"
 #include "GPU_material.h"
 
+#include "ED_sculpt.h" /* for ED_sculpt_modifiers_changed */
+
 ///////////////////////////////////
 ///////////////////////////////////
 
@@ -398,6 +402,15 @@ void DM_to_mesh(DerivedMesh *dm, Mesh *me)
        if(!CustomData_has_layer(&tmp.pdata, CD_MPOLY))
                dm_add_polys_from_iter(&tmp.ldata, &tmp.pdata, dm, totloop);
 
+       /* object had got displacement layer, should copy this layer to save sculpted data */
+       /* NOTE: maybe some other layers should be copied? nazgul */
+       if(CustomData_has_layer(&me->fdata, CD_MDISPS)) {
+               if (totface == me->totface) {
+                       MDisps *mdisps = CustomData_get_layer(&me->fdata, CD_MDISPS);
+                       CustomData_add_layer(&tmp.fdata, CD_MDISPS, CD_DUPLICATE, mdisps, totface);
+               }
+       }
+
        mesh_update_customdata_pointers(&tmp);
 
        CustomData_free(&me->vdata, me->totvert);
@@ -637,7 +650,7 @@ void DM_interp_face_data(DerivedMesh *source, DerivedMesh *dest,
 }
 
 ///
-static DerivedMesh *getMeshDerivedMesh(Mesh *me, Object *ob, float (*vertCos)[3])
+DerivedMesh *mesh_create_derived(Mesh *me, Object *ob, float (*vertCos)[3])
 {
        DerivedMesh *dm = CDDM_from_mesh(me, ob);
        
@@ -670,11 +683,11 @@ DerivedMesh *mesh_create_derived_for_modifier(Scene *scene, Object *ob, Modifier
                float (*deformedVerts)[3] = mesh_getVertexCos(me, &numVerts);
 
                mti->deformVerts(md, ob, NULL, deformedVerts, numVerts, 0, 0);
-               dm = getMeshDerivedMesh(me, ob, deformedVerts);
+               dm = mesh_create_derived(me, ob, deformedVerts);
 
                MEM_freeN(deformedVerts);
        } else {
-               DerivedMesh *tdm = getMeshDerivedMesh(me, ob, NULL);
+               DerivedMesh *tdm = mesh_create_derived(me, ob, NULL);
                dm = mti->applyModifier(md, ob, tdm, 0, 0);
 
                if(tdm != dm) tdm->release(tdm);
@@ -920,17 +933,32 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
        DerivedMesh *dm, *orcodm, *clothorcodm, *finaldm;
        int numVerts = me->totvert;
        int required_mode;
+       int isPrevDeform= FALSE;
+       int skipVirtualArmature = (useDeform < 0);
+       MultiresModifierData *mmd= get_multires_modifier(scene, ob, 0);
+       int has_multires = mmd != NULL, multires_applied = 0;
+       int sculpt_mode = ob->mode & OB_MODE_SCULPT && ob->sculpt;
+
+       if(mmd && !mmd->sculptlvl)
+               has_multires = 0;
+
+       if(!skipVirtualArmature) {
+               firstmd = modifiers_getVirtualModifierList(ob);
+       }
+       else {
+               /* game engine exception */
+               firstmd = ob->modifiers.first;
+               if(firstmd && firstmd->type == eModifierType_Armature)
+                       firstmd = firstmd->next;
+       }
 
-       md = firstmd = (useDeform<0) ? ob->modifiers.first : modifiers_getVirtualModifierList(ob);
+       md = firstmd;
 
        modifiers_clearErrors(ob);
 
        if(useRenderParams) required_mode = eModifierMode_Render;
        else required_mode = eModifierMode_Realtime;
 
-       /* we always want to keep original indices */
-       dataMask |= CD_MASK_ORIGINDEX;
-
        datamasks = modifiers_calcDataMasks(scene, ob, md, dataMask, required_mode);
        curr = datamasks;
 
@@ -996,13 +1024,18 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
                ModifierTypeInfo *mti = modifierType_getInfo(md->type);
 
                md->scene= scene;
-               
+
                if(!modifier_isEnabled(scene, md, required_mode)) continue;
                if(mti->type == eModifierTypeType_OnlyDeform && !useDeform) continue;
                if((mti->flags & eModifierTypeFlag_RequiresOriginalData) && dm) {
                        modifier_setError(md, "Modifier requires original data, bad stack position.");
                        continue;
                }
+               if(sculpt_mode && (!has_multires || multires_applied))
+                       if(mti->type != eModifierTypeType_OnlyDeform || multires_applied) {
+                               modifier_setError(md, "Not supported in sculpt mode.");
+                               continue;
+                       }
                if(needMapping && !modifier_supportsMapping(md)) continue;
                if(useDeform < 0 && mti->dependsOnTime && mti->dependsOnTime(md)) continue;
 
@@ -1037,10 +1070,26 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
                                }
                        }
 
+                       /* if this is not the last modifier in the stack then recalculate the normals
+                        * to avoid giving bogus normals to the next modifier see: [#23673] */
+                       if(isPrevDeform &&  mti->dependsOnNormals && mti->dependsOnNormals(md)) {
+                               /* XXX, this covers bug #23673, but we may need normal calc for other types */
+                               if(dm->type == DM_TYPE_CDDM) {
+                                       CDDM_apply_vert_coords(dm, deformedVerts);
+                                       CDDM_calc_normals(dm);
+                               }
+                       }
+
                        mti->deformVerts(md, ob, dm, deformedVerts, numVerts, useRenderParams, useDeform);
                } else {
                        DerivedMesh *ndm;
 
+                       /* determine which data layers are needed by following modifiers */
+                       if(curr->next)
+                               nextmask= (CustomDataMask)GET_INT_FROM_POINTER(curr->next->link);
+                       else
+                               nextmask= dataMask;
+
                        /* apply vertex coordinates or build a DerivedMesh as necessary */
                        if(dm) {
                                if(deformedVerts) {
@@ -1062,28 +1111,30 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
                                if((dataMask & CD_MASK_WEIGHT_MCOL) && (ob->mode & OB_MODE_WEIGHT_PAINT))
                                        add_weight_mcol_dm(ob, dm);
 
-                               /* constructive modifiers need to have an origindex
-                                * otherwise they wont have anywhere to copy the data from */
-                               if(needMapping) {
-                                       int *index, i;
+                               /* Constructive modifiers need to have an origindex
+                                * otherwise they wont have anywhere to copy the data from.
+                                *
+                                * Also create ORIGINDEX data if any of the following modifiers
+                                * requests it, this way Mirror, Solidify etc will keep ORIGINDEX
+                                * data by using generic DM_copy_vert_data() functions.
+                                */
+                               if(needMapping || (nextmask & CD_MASK_ORIGINDEX)) {
+                                       int i, *orig;
+                                       
+                                       /* calc */
                                        DM_add_vert_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
                                        DM_add_edge_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
                                        DM_add_face_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
 
-                                       index = DM_get_vert_data_layer(dm, CD_ORIGINDEX);
-                                       for(i=0; i<dm->numVertData; i++) *index++= i;
-                                       index = DM_get_edge_data_layer(dm, CD_ORIGINDEX);
-                                       for(i=0; i<dm->numEdgeData; i++) *index++= i;
-                                       index = DM_get_face_data_layer(dm, CD_ORIGINDEX);
-                                       for(i=0; i<dm->numPolyData; i++) *index++= i;
+                                       orig = DM_get_vert_data_layer(dm, CD_ORIGINDEX);
+                                       for(i=0; i<dm->numVertData; i++) *orig++= i;
+                                       orig = DM_get_edge_data_layer(dm, CD_ORIGINDEX);
+                                       for(i=0; i<dm->numEdgeData; i++) *orig++= i;
+                                       orig = DM_get_face_data_layer(dm, CD_ORIGINDEX);
+                                       for(i=0; i<dm->numPolyData; i++) *orig++= i;
                                }
                        }
 
-                       /* determine which data layers are needed by following modifiers */
-                       if(curr->next)
-                               nextmask= (CustomDataMask)GET_INT_FROM_POINTER(curr->next->link);
-                       else
-                               nextmask= dataMask;
                        
                        /* set the DerivedMesh to only copy needed data */
                        mask= (CustomDataMask)GET_INT_FROM_POINTER(curr->link);
@@ -1120,7 +1171,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
                                        orcodm= create_orco_dm(ob, me, NULL, CD_ORCO);
 
                                nextmask &= ~CD_MASK_ORCO;
-                               DM_set_only_copy(orcodm, nextmask);
+                               DM_set_only_copy(orcodm, nextmask | CD_MASK_ORIGINDEX);
                                ndm = mti->applyModifier(md, ob, orcodm, useRenderParams, 0);
 
                                if(ndm) {
@@ -1136,7 +1187,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
                                        clothorcodm= create_orco_dm(ob, me, NULL, CD_CLOTH_ORCO);
 
                                nextmask &= ~CD_MASK_CLOTH_ORCO;
-                               DM_set_only_copy(clothorcodm, nextmask);
+                               DM_set_only_copy(clothorcodm, nextmask | CD_MASK_ORIGINDEX);
                                ndm = mti->applyModifier(md, ob, clothorcodm, useRenderParams, 0);
 
                                if(ndm) {
@@ -1147,9 +1198,14 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
                        }
                }
 
+               isPrevDeform= (mti->type == eModifierTypeType_OnlyDeform);
+
                /* grab modifiers until index i */
                if((index >= 0) && (modifiers_indexInObject(ob, md) >= index))
                        break;
+
+               if(sculpt_mode && md->type == eModifierType_Multires)
+                       multires_applied = 1;
        }
 
        for(md=firstmd; md; md=md->next)
@@ -1204,7 +1260,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
        BLI_linklist_free(datamasks, NULL);
 }
 
-static float (*editbmesh_getVertexCos(BMEditMesh *em, int *numVerts_r))[3]
+float (*editbmesh_get_vertex_cos(BMEditMesh *em, int *numVerts_r))[3]
 {
        int i, numVerts = *numVerts_r = em->bm->totvert;
        float (*cos)[3];
@@ -1221,7 +1277,7 @@ static float (*editbmesh_getVertexCos(BMEditMesh *em, int *numVerts_r))[3]
        return cos;
 }
 
-static int editbmesh_modifier_is_enabled(Scene *scene, ModifierData *md, DerivedMesh *dm)
+int editbmesh_modifier_is_enabled(Scene *scene, ModifierData *md, DerivedMesh *dm)
 {
        ModifierTypeInfo *mti = modifierType_getInfo(md->type);
        int required_mode = eModifierMode_Realtime | eModifierMode_Editmode;
@@ -1255,9 +1311,6 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D
 
        dm = NULL;
        md = modifiers_getVirtualModifierList(ob);
-       
-       /* we always want to keep original indices */
-       dataMask |= CD_MASK_ORIGINDEX;
 
        datamasks = modifiers_calcDataMasks(scene, ob, md, dataMask, required_mode);
 
@@ -1295,7 +1348,7 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D
                                                MEM_mallocN(sizeof(*deformedVerts) * numVerts, "dfmv");
                                        dm->getVertCos(dm, deformedVerts);
                                } else {
-                                       deformedVerts = editbmesh_getVertexCos(em, &numVerts);
+                                       deformedVerts = editbmesh_get_vertex_cos(em, &numVerts);
                                }
                        }
 
@@ -1336,7 +1389,7 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D
                                        orcodm= create_orco_dm(ob, ob->data, em, CD_ORCO);
 
                                mask &= ~CD_MASK_ORCO;
-                               DM_set_only_copy(orcodm, mask);
+                               DM_set_only_copy(orcodm, mask | CD_MASK_ORIGINDEX);
 
                                if (mti->applyModifierEM)
                                        ndm = mti->applyModifierEM(md, ob, em, orcodm);
@@ -1351,9 +1404,11 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D
                        }
 
                        /* set the DerivedMesh to only copy needed data */
-                       DM_set_only_copy(dm, (CustomDataMask)GET_INT_FROM_POINTER(curr->link));
+                       mask= (CustomDataMask)GET_INT_FROM_POINTER(curr->link); /* CD_MASK_ORCO may have been cleared above */
 
-                       if(((CustomDataMask)GET_INT_FROM_POINTER(curr->link)) & CD_MASK_ORIGSPACE)
+                       DM_set_only_copy(dm, mask | CD_MASK_ORIGINDEX);
+
+                       if(mask & CD_MASK_ORIGSPACE)
                                if(!CustomData_has_layer(&dm->faceData, CD_ORIGSPACE))
                                        DM_add_tessface_layer(dm, CD_ORIGSPACE, CD_DEFAULT, NULL);
                        
@@ -1448,14 +1503,9 @@ static void clear_mesh_caches(Object *ob)
                ob->derivedDeform->release(ob->derivedDeform);
                ob->derivedDeform= NULL;
        }
-       /* we free pbvh on changes, except during sculpt since it can't deal with
-          changing PVBH node organization, we hope topology does not change in
-          the meantime .. weak */
-       if(ob->sculpt && ob->sculpt->pbvh) {
-               if(!ob->sculpt->cache) {
-                       BLI_pbvh_free(ob->sculpt->pbvh);
-                       ob->sculpt->pbvh= NULL;
-               }
+
+       if(ob->sculpt) {
+               ED_sculpt_modifiers_changed(ob);
        }
 }
 
@@ -1463,8 +1513,8 @@ static void mesh_build_data(Scene *scene, Object *ob, CustomDataMask dataMask)
 {
        Object *obact = scene->basact?scene->basact->object:NULL;
        int editing = paint_facesel_test(ob);
-       /* weight paint and face select need original indicies because of selection buffer drawing */
-       int needMapping = (ob==obact) && (editing || (ob->mode & (OB_MODE_WEIGHT_PAINT|OB_MODE_VERTEX_PAINT)) || editing);
+       /* weight paint and face select need original indices because of selection buffer drawing */
+       int needMapping = (ob==obact) && (editing || (ob->mode & (OB_MODE_WEIGHT_PAINT|OB_MODE_VERTEX_PAINT)));
 
        clear_mesh_caches(ob);
 
@@ -1584,6 +1634,16 @@ DerivedMesh *mesh_create_derived_no_virtual(Scene *scene, Object *ob, float (*ve
        return final;
 }
 
+DerivedMesh *mesh_create_derived_physics(Scene *scene, Object *ob, float (*vertCos)[3],
+                                                                                       CustomDataMask dataMask)
+{
+       DerivedMesh *final;
+       
+       mesh_calc_modifiers(scene, ob, vertCos, NULL, &final, 0, -1, 1, dataMask, -1, 0);
+
+       return final;
+}
+
 DerivedMesh *mesh_create_derived_no_deform_render(Scene *scene, Object *ob,
                                                                                                  float (*vertCos)[3],
                                                                                                  CustomDataMask dataMask)
@@ -1685,61 +1745,112 @@ float *mesh_get_mapped_verts_nors(Scene *scene, Object *ob)
        return vertexcosnos;
 }
 
-/* ********* crazyspace *************** */
+/* ******************* GLSL ******************** */
 
-int editbmesh_get_first_deform_matrices(Scene *scene, Object *ob, BMEditMesh *em, float (**deformmats)[3][3], float (**deformcos)[3])
+typedef struct
 {
-       ModifierData *md;
-       DerivedMesh *dm;
-       int i, a, numleft = 0, numVerts = 0;
-       int cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1);
-       float (*defmats)[3][3] = NULL, (*deformedVerts)[3] = NULL;
+       float * precomputedFaceNormals;
+       MTFace * mtface;        // texture coordinates
+       MFace * mface;          // indices
+       MVert * mvert;          // vertices & normals
+       float (*orco)[3];
+       float (*tangent)[4];    // destination
+       int numFaces;
 
-       modifiers_clearErrors(ob);
+} SGLSLMeshToTangent;
 
-       dm = NULL;
-       md = modifiers_getVirtualModifierList(ob);
+// interface
+#include "mikktspace.h"
 
-       /* compute the deformation matrices and coordinates for the first
-          modifiers with on cage editing that are enabled and support computing
-          deform matrices */
-       for(i = 0; md && i <= cageIndex; i++, md = md->next) {
-               ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+static int GetNumFaces(const SMikkTSpaceContext * pContext)
+{
+       SGLSLMeshToTangent * pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData;
+       return pMesh->numFaces;
+}
 
-               if(!editbmesh_modifier_is_enabled(scene, md, dm))
-                       continue;
+static int GetNumVertsOfFace(const SMikkTSpaceContext * pContext, const int face_num)
+{
+       SGLSLMeshToTangent * pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData;
+       return pMesh->mface[face_num].v4!=0 ? 4 : 3;
+}
 
-               if(mti->type==eModifierTypeType_OnlyDeform && mti->deformMatricesEM) {
-                       if(!defmats) {
-                               dm= getEditDerivedBMesh(em, ob, NULL);
-                               deformedVerts= editbmesh_getVertexCos(em, &numVerts);
-                               defmats= MEM_callocN(sizeof(*defmats)*numVerts, "defmats");
+static void GetPosition(const SMikkTSpaceContext * pContext, float fPos[], const int face_num, const int vert_index)
+{
+       //assert(vert_index>=0 && vert_index<4);
+       SGLSLMeshToTangent * pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData;
+       unsigned int indices[] = {      pMesh->mface[face_num].v1, pMesh->mface[face_num].v2,
+                                                               pMesh->mface[face_num].v3, pMesh->mface[face_num].v4 };
+       VECCOPY(fPos, pMesh->mvert[indices[vert_index]].co);
+}
 
-                               for(a=0; a<numVerts; a++)
-                                       unit_m3(defmats[a]);
-                       }
+static void GetTextureCoordinate(const SMikkTSpaceContext * pContext, float fUV[], const int face_num, const int vert_index)
+{
+       //assert(vert_index>=0 && vert_index<4);
+       SGLSLMeshToTangent * pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData;
 
-                       mti->deformMatricesEM(md, ob, em, dm, deformedVerts, defmats,
-                               numVerts);
-               }
-               else
-                       break;
+       if(pMesh->mtface!=NULL)
+       {
+               float * uv = pMesh->mtface[face_num].uv[vert_index];
+               fUV[0]=uv[0]; fUV[1]=uv[1];
        }
+       else
+       {
+               unsigned int indices[] = {      pMesh->mface[face_num].v1, pMesh->mface[face_num].v2,
+                                                                       pMesh->mface[face_num].v3, pMesh->mface[face_num].v4 };
 
-       for(; md && i <= cageIndex; md = md->next, i++)
-               if(editbmesh_modifier_is_enabled(scene, md, dm) && modifier_isCorrectableDeformed(md))
-                       numleft++;
+               map_to_sphere( &fUV[0], &fUV[1],pMesh->orco[indices[vert_index]][0], pMesh->orco[indices[vert_index]][1], pMesh->orco[indices[vert_index]][2]);
+       }
+}
 
-       if(dm)
-               dm->release(dm);
-       
-       *deformmats= defmats;
-       *deformcos= deformedVerts;
+static void GetNormal(const SMikkTSpaceContext * pContext, float fNorm[], const int face_num, const int vert_index)
+{
+       //assert(vert_index>=0 && vert_index<4);
+       SGLSLMeshToTangent * pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData;
+       unsigned int indices[] = {      pMesh->mface[face_num].v1, pMesh->mface[face_num].v2,
+                                                               pMesh->mface[face_num].v3, pMesh->mface[face_num].v4 };
 
-       return numleft;
+       const int smoothnormal = (pMesh->mface[face_num].flag & ME_SMOOTH);
+       if(!smoothnormal)       // flat
+       {
+               if(pMesh->precomputedFaceNormals)
+               {
+                       VECCOPY(fNorm, &pMesh->precomputedFaceNormals[3*face_num]);
+               }
+               else
+               {
+                       float nor[3];
+                       float * p0, * p1, * p2;
+                       const int iGetNrVerts = pMesh->mface[face_num].v4!=0 ? 4 : 3;
+                       p0 = pMesh->mvert[indices[0]].co; p1 = pMesh->mvert[indices[1]].co; p2 = pMesh->mvert[indices[2]].co;
+                       if(iGetNrVerts==4)
+                       {
+                               float * p3 = pMesh->mvert[indices[3]].co;
+                               normal_quad_v3( nor, p0, p1, p2, p3);
+                       }
+                       else {
+                               normal_tri_v3(nor, p0, p1, p2);
+                       }
+                       VECCOPY(fNorm, nor);
+               }
+       }
+       else
+       {
+               int i=0;
+               short * no = pMesh->mvert[indices[vert_index]].no;
+               for(i=0; i<3; i++)
+                       fNorm[i]=no[i]/32767.0f;
+               normalize_v3(fNorm);
+       }
+}
+static void SetTSpace(const SMikkTSpaceContext * pContext, const float fvTangent[], const float fSign, const int face_num, const int iVert)
+{
+       //assert(vert_index>=0 && vert_index<4);
+       SGLSLMeshToTangent * pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData;
+       float * pRes = pMesh->tangent[4*face_num+iVert];
+       VECCOPY(pRes, fvTangent);
+       pRes[3]=fSign;
 }
 
-/* ******************* GLSL ******************** */
 
 void DM_add_tangent_layer(DerivedMesh *dm)
 {
@@ -1749,14 +1860,17 @@ void DM_add_tangent_layer(DerivedMesh *dm)
        MVert *mvert, *v1, *v2, *v3, *v4;
        MemArena *arena= NULL;
        VertexTangent **vtangents= NULL;
-       float (*orco)[3]= NULL, (*tangent)[3];
+       float (*orco)[3]= NULL, (*tangent)[4];
        float *uv1, *uv2, *uv3, *uv4, *vtang;
        float fno[3], tang[3], uv[4][2];
-       int i, j, len, mf_vi[4], totvert, totface;
+       int i, j, len, mf_vi[4], totvert, totface, iCalcNewMethod;
+       float *nors;
 
        if(CustomData_get_layer_index(&dm->faceData, CD_TANGENT) != -1)
                return;
 
+       nors = dm->getTessFaceDataArray(dm, CD_NORMAL);
+
        /* check we have all the needed layers */
        totvert= dm->getNumVerts(dm);
        totface= dm->getNumTessFaces(dm);
@@ -1779,79 +1893,108 @@ void DM_add_tangent_layer(DerivedMesh *dm)
        arena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "tangent layer arena");
        BLI_memarena_use_calloc(arena);
        vtangents= MEM_callocN(sizeof(VertexTangent*)*totvert, "VertexTangent");
-       
-       /* sum tangents at connected vertices */
-       for(i=0, tf=mtface, mf=mface; i < totface; mf++, tf++, i++) {
-               v1= &mvert[mf->v1];
-               v2= &mvert[mf->v2];
-               v3= &mvert[mf->v3];
-
-               if (mf->v4) {
-                       v4= &mvert[mf->v4];
-                       normal_quad_v3( fno,v4->co, v3->co, v2->co, v1->co);
-               }
-               else {
-                       v4= NULL;
-                       normal_tri_v3( fno,v3->co, v2->co, v1->co);
-               }
-               
-               if(mtface) {
-                       uv1= tf->uv[0];
-                       uv2= tf->uv[1];
-                       uv3= tf->uv[2];
-                       uv4= tf->uv[3];
-               }
-               else {
-                       uv1= uv[0]; uv2= uv[1]; uv3= uv[2]; uv4= uv[3];
-                       map_to_sphere( &uv[0][0], &uv[0][1],orco[mf->v1][0], orco[mf->v1][1], orco[mf->v1][2]);
-                       map_to_sphere( &uv[1][0], &uv[1][1],orco[mf->v2][0], orco[mf->v2][1], orco[mf->v2][2]);
-                       map_to_sphere( &uv[2][0], &uv[2][1],orco[mf->v3][0], orco[mf->v3][1], orco[mf->v3][2]);
-                       if(v4)
-                               map_to_sphere( &uv[3][0], &uv[3][1],orco[mf->v4][0], orco[mf->v4][1], orco[mf->v4][2]);
-               }
+
+       // new computation method
+       iCalcNewMethod = 1;
+       if(iCalcNewMethod!=0)
+       {
+               SGLSLMeshToTangent mesh2tangent;
+               SMikkTSpaceContext sContext;
+               SMikkTSpaceInterface sInterface;
+               memset(&mesh2tangent, 0, sizeof(SGLSLMeshToTangent));
+               memset(&sContext, 0, sizeof(SMikkTSpaceContext));
+               memset(&sInterface, 0, sizeof(SMikkTSpaceInterface));
+
+               mesh2tangent.precomputedFaceNormals = nors;
+               mesh2tangent.mtface = mtface;
+               mesh2tangent.mface = mface;
+               mesh2tangent.mvert = mvert;
+               mesh2tangent.orco = orco;
+               mesh2tangent.tangent = tangent;
+               mesh2tangent.numFaces = totface;
+
+               sContext.m_pUserData = &mesh2tangent;
+               sContext.m_pInterface = &sInterface;
+               sInterface.m_getNumFaces = GetNumFaces;
+               sInterface.m_getNumVerticesOfFace = GetNumVertsOfFace;
+               sInterface.m_getPosition = GetPosition;
+               sInterface.m_getTexCoord = GetTextureCoordinate;
+               sInterface.m_getNormal = GetNormal;
+               sInterface.m_setTSpaceBasic = SetTSpace;
+
+               // 0 if failed
+               iCalcNewMethod = genTangSpaceDefault(&sContext);
+       }
+
+       if(!iCalcNewMethod)
+       {
+               /* sum tangents at connected vertices */
+               for(i=0, tf=mtface, mf=mface; i < totface; mf++, tf++, i++) {
+                       v1= &mvert[mf->v1];
+                       v2= &mvert[mf->v2];
+                       v3= &mvert[mf->v3];
+
+                       if (mf->v4) {
+                               v4= &mvert[mf->v4];
+                               normal_quad_v3( fno,v4->co, v3->co, v2->co, v1->co);
+                       }
+                       else {
+                               v4= NULL;
+                               normal_tri_v3( fno,v3->co, v2->co, v1->co);
+                       }
                
-               tangent_from_uv(uv1, uv2, uv3, v1->co, v2->co, v3->co, fno, tang);
-               sum_or_add_vertex_tangent(arena, &vtangents[mf->v1], tang, uv1);
-               sum_or_add_vertex_tangent(arena, &vtangents[mf->v2], tang, uv2);
-               sum_or_add_vertex_tangent(arena, &vtangents[mf->v3], tang, uv3);
+                       if(mtface) {
+                               uv1= tf->uv[0];
+                               uv2= tf->uv[1];
+                               uv3= tf->uv[2];
+                               uv4= tf->uv[3];
+                       }
+                       else {
+                               uv1= uv[0]; uv2= uv[1]; uv3= uv[2]; uv4= uv[3];
+                               map_to_sphere( &uv[0][0], &uv[0][1],orco[mf->v1][0], orco[mf->v1][1], orco[mf->v1][2]);
+                               map_to_sphere( &uv[1][0], &uv[1][1],orco[mf->v2][0], orco[mf->v2][1], orco[mf->v2][2]);
+                               map_to_sphere( &uv[2][0], &uv[2][1],orco[mf->v3][0], orco[mf->v3][1], orco[mf->v3][2]);
+                               if(v4)
+                                       map_to_sphere( &uv[3][0], &uv[3][1],orco[mf->v4][0], orco[mf->v4][1], orco[mf->v4][2]);
+                       }
                
-               if(mf->v4) {
-                       v4= &mvert[mf->v4];
-                       
-                       tangent_from_uv(uv1, uv3, uv4, v1->co, v3->co, v4->co, fno, tang);
+                       tangent_from_uv(uv1, uv2, uv3, v1->co, v2->co, v3->co, fno, tang);
                        sum_or_add_vertex_tangent(arena, &vtangents[mf->v1], tang, uv1);
+                       sum_or_add_vertex_tangent(arena, &vtangents[mf->v2], tang, uv2);
                        sum_or_add_vertex_tangent(arena, &vtangents[mf->v3], tang, uv3);
-                       sum_or_add_vertex_tangent(arena, &vtangents[mf->v4], tang, uv4);
-               }
-       }
-       
-       /* write tangent to layer */
-       for(i=0, tf=mtface, mf=mface; i < totface; mf++, tf++, i++, tangent+=4) {
-               len= (mf->v4)? 4 : 3; 
                
-               if(mtface) {
-                       uv1= tf->uv[0];
-                       uv2= tf->uv[1];
-                       uv3= tf->uv[2];
-                       uv4= tf->uv[3];
-               }
-               else {
-                       uv1= uv[0]; uv2= uv[1]; uv3= uv[2]; uv4= uv[3];
-                       map_to_sphere( &uv[0][0], &uv[0][1],orco[mf->v1][0], orco[mf->v1][1], orco[mf->v1][2]);
-                       map_to_sphere( &uv[1][0], &uv[1][1],orco[mf->v2][0], orco[mf->v2][1], orco[mf->v2][2]);
-                       map_to_sphere( &uv[2][0], &uv[2][1],orco[mf->v3][0], orco[mf->v3][1], orco[mf->v3][2]);
-                       if(len==4)
-                               map_to_sphere( &uv[3][0], &uv[3][1],orco[mf->v4][0], orco[mf->v4][1], orco[mf->v4][2]);
+                       if(mf->v4) {
+                               v4= &mvert[mf->v4];
+                       
+                               tangent_from_uv(uv1, uv3, uv4, v1->co, v3->co, v4->co, fno, tang);
+                               sum_or_add_vertex_tangent(arena, &vtangents[mf->v1], tang, uv1);
+                               sum_or_add_vertex_tangent(arena, &vtangents[mf->v3], tang, uv3);
+                               sum_or_add_vertex_tangent(arena, &vtangents[mf->v4], tang, uv4);
+                       }
                }
+       
+               /* write tangent to layer */
+               for(i=0, tf=mtface, mf=mface; i < totface; mf++, tf++, i++, tangent+=4) {
+                       len= (mf->v4)? 4 : 3; 
+
+                       if(mtface == NULL) {
+                               map_to_sphere( &uv[0][0], &uv[0][1],orco[mf->v1][0], orco[mf->v1][1], orco[mf->v1][2]);
+                               map_to_sphere( &uv[1][0], &uv[1][1],orco[mf->v2][0], orco[mf->v2][1], orco[mf->v2][2]);
+                               map_to_sphere( &uv[2][0], &uv[2][1],orco[mf->v3][0], orco[mf->v3][1], orco[mf->v3][2]);
+                               if(len==4)
+                                       map_to_sphere( &uv[3][0], &uv[3][1],orco[mf->v4][0], orco[mf->v4][1], orco[mf->v4][2]);
+                       }
                
-               mf_vi[0]= mf->v1;
-               mf_vi[1]= mf->v2;
-               mf_vi[2]= mf->v3;
-               mf_vi[3]= mf->v4;
+                       mf_vi[0]= mf->v1;
+                       mf_vi[1]= mf->v2;
+                       mf_vi[2]= mf->v3;
+                       mf_vi[3]= mf->v4;
                
-               for(j=0; j<len; j++) {
-                       vtang= find_vertex_tangent(vtangents[mf_vi[j]], mtface ? tf->uv[j] : uv[j]);
-                       normalize_v3_v3(tangent[j], vtang);
+                       for(j=0; j<len; j++) {
+                               vtang= find_vertex_tangent(vtangents[mf_vi[j]], mtface ? tf->uv[j] : uv[j]);
+                               normalize_v3_v3(tangent[j], vtang);
+                               ((float *) tangent[j])[3]=1.0f;
+                       }
                }
        }