Sculpting on deformed mesh
authorSergey Sharybin <sergey.vfx@gmail.com>
Sat, 12 Feb 2011 17:51:02 +0000 (17:51 +0000)
committerSergey Sharybin <sergey.vfx@gmail.com>
Sat, 12 Feb 2011 17:51:02 +0000 (17:51 +0000)
==========================

Removed limitation of armatured-only objects for sculpting -- now all
deformation modifiers are allowed in sculpt mode. Use crazyspace corrections
like from transformation modules was used to support all deformation modifiers.

Internal change: all crazyspace-related functions were noved to crazyspace.c

P.S. Brush could make quite unexpected deformation for meshes which are
     deformed in specified way. Got patch for this and discussing with Brecht
 if it's really needed or maybe it could be done in better way.

source/blender/blenkernel/BKE_DerivedMesh.h
source/blender/blenkernel/intern/DerivedMesh.c
source/blender/editors/include/ED_util.h
source/blender/editors/sculpt_paint/sculpt.c
source/blender/editors/transform/transform_conversions.c
source/blender/editors/util/CMakeLists.txt
source/blender/editors/util/crazyspace.c [new file with mode: 0644]

index e7ce3f274310742e18063b820cc2c973abd80bc1..79e9b11d4db0d65352cc78cf2c4fed1b0e588819 100644 (file)
@@ -512,8 +512,9 @@ void makeDerivedMesh(struct Scene *scene, struct Object *ob, struct EditMesh *em
 int editmesh_get_first_deform_matrices(struct Scene *, struct Object *, struct EditMesh *em,
                                                                           float (**deformmats)[3][3], float (**deformcos)[3]);
 
-/* returns an array of deform matrices for crazyspace correction when sculpting */
-void sculpt_get_deform_matrices(struct Scene *scene, struct Object *ob,
+/* returns an array of deform matrices for crazyspace correction when sculpting,
+   and the number of modifiers left */
+int sculpt_get_deform_matrices(struct Scene *scene, struct Object *ob,
                                                                float (**deformmats)[3][3], float (**deformcos)[3]);
 
 void weight_to_rgb(float input, float *fr, float *fg, float *fb);
index be9cda6c58f63270c0e083ed0e4892af6b65b6a5..eedc2636991e92194bcc6deca5d0ba9582163e0d 100644 (file)
@@ -1721,12 +1721,6 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
                        if(useDeform < 0 && mti->dependsOnTime && mti->dependsOnTime(md)) continue;
 
                        if(mti->type == eModifierTypeType_OnlyDeform) {
-                               if(sculpt_mode && !has_multires)
-                                       if(!ELEM(md->type, eModifierType_Armature, eModifierType_ShapeKey)) {
-                                               modifier_setError(md, "Not supported in sculpt mode.");
-                                               continue;
-                                       }
-
                                if(!deformedVerts)
                                        deformedVerts = mesh_getVertexCos(me, &numVerts);
 
@@ -1780,7 +1774,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
                        continue;
                }
                if(sculpt_mode && (!has_multires || multires_applied))
-                       if(md->type != eModifierType_Armature || multires_applied) {
+                       if(mti->type != eModifierTypeType_OnlyDeform || multires_applied) {
                                modifier_setError(md, "Not supported in sculpt mode.");
                                continue;
                        }
@@ -2485,105 +2479,6 @@ float *mesh_get_mapped_verts_nors(Scene *scene, Object *ob)
        return vertexcosnos;
 }
 
-/* ********* crazyspace *************** */
-
-int editmesh_get_first_deform_matrices(Scene *scene, Object *ob, EditMesh *em, float (**deformmats)[3][3], float (**deformcos)[3])
-{
-       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;
-
-       modifiers_clearErrors(ob);
-
-       dm = NULL;
-       md = modifiers_getVirtualModifierList(ob);
-
-       /* 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);
-
-               if(!editmesh_modifier_is_enabled(scene, md, dm))
-                       continue;
-
-               if(mti->type==eModifierTypeType_OnlyDeform && mti->deformMatricesEM) {
-                       if(!defmats) {
-                               dm= editmesh_get_derived(em, NULL);
-                               deformedVerts= editmesh_get_vertex_cos(em, &numVerts);
-                               defmats= MEM_callocN(sizeof(*defmats)*numVerts, "defmats");
-
-                               for(a=0; a<numVerts; a++)
-                                       unit_m3(defmats[a]);
-                       }
-
-                       mti->deformMatricesEM(md, ob, em, dm, deformedVerts, defmats,
-                               numVerts);
-               }
-               else
-                       break;
-       }
-
-       for(; md && i <= cageIndex; md = md->next, i++)
-               if(editmesh_modifier_is_enabled(scene, md, dm) && modifier_isCorrectableDeformed(md))
-                       numleft++;
-
-       if(dm)
-               dm->release(dm);
-       
-       *deformmats= defmats;
-       *deformcos= deformedVerts;
-
-       return numleft;
-}
-
-void sculpt_get_deform_matrices(Scene *scene, Object *ob, float (**deformmats)[3][3], float (**deformcos)[3])
-{
-       ModifierData *md;
-       DerivedMesh *dm;
-       int a, numVerts= 0;
-       float (*defmats)[3][3]= NULL, (*deformedVerts)[3]= NULL;
-       MultiresModifierData *mmd= get_multires_modifier(scene, ob, 0);
-       int has_multires = mmd != NULL && mmd->sculptlvl > 0;
-
-       if(has_multires) {
-               *deformmats= NULL;
-               *deformcos= NULL;
-               return;
-       }
-
-       dm= NULL;
-       md= modifiers_getVirtualModifierList(ob);
-
-       for(; md; md= md->next) {
-               ModifierTypeInfo *mti= modifierType_getInfo(md->type);
-
-               if(!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue;
-
-               if(mti->type==eModifierTypeType_OnlyDeform && mti->deformMatrices) {
-                       if(!defmats) {
-                               Mesh *me= (Mesh*)ob->data;
-                               dm= mesh_create_derived(me, ob, NULL);
-                               deformedVerts= mesh_getVertexCos(me, &numVerts);
-                               defmats= MEM_callocN(sizeof(*defmats)*numVerts, "defmats");
-
-                               for(a=0; a<numVerts; a++)
-                                       unit_m3(defmats[a]);
-                       }
-
-                       mti->deformMatrices(md, ob, dm, deformedVerts, defmats, numVerts);
-               }
-       }
-
-       if(dm)
-               dm->release(dm);
-
-       *deformmats= defmats;
-       *deformcos= deformedVerts;
-}
-
 /* ******************* GLSL ******************** */
 
 void DM_add_tangent_layer(DerivedMesh *dm)
index 1cbf1d0e9982e72889a8afac5762c1cebecc494a..473d889c731ba7fa4dea32c30477f847c29b3e61 100644 (file)
 #ifndef ED_UTIL_H
 #define ED_UTIL_H
 
+struct Scene;
 struct Object;
 struct bContext;
 struct ARegion;
 struct uiBlock;
 struct wmOperator;
 struct wmOperatorType;
+struct EditMesh;
+struct Mesh;
 
 /* ed_util.c */
 
@@ -73,6 +76,15 @@ void undo_editmode_menu                      (struct bContext *C);
 void   undo_editmode_clear                     (void);
 void   undo_editmode_step                      (struct bContext *C, int step);
 
+/* crazyspace.c */
+float *crazyspace_get_mapped_editverts(struct Scene *scene, struct Object *obedit);
+void crazyspace_set_quats_editmesh(struct EditMesh *em, float *origcos, float *mappedcos, float *quats);
+void crazyspace_set_quats_mesh(struct Mesh *me, float *origcos, float *mappedcos, float *quats);
+int editmesh_get_first_deform_matrices(struct Scene *scene, struct Object *ob, struct EditMesh *em, float (**deformmats)[3][3], float (**deformcos)[3]);
+int sculpt_get_first_deform_matrices(struct Scene *scene, struct Object *ob, float (**deformmats)[3][3], float (**deformcos)[3]);
+void crazyspace_build_sculpt(struct Scene *scene, struct Object *ob, float (**deformmats)[3][3], float (**deformcos)[3]);
+
+
 /* ************** XXX OLD CRUFT WARNING ************* */
 
 void apply_keyb_grid(int shift, int ctrl, float *val, float fac1, float fac2, float fac3, int invert);
index f109340d827faf3c584e1b14bd8d3320631e5434..7e72aad8adb36c2bb729e28feba4f55f9f5464bf 100644 (file)
@@ -66,6 +66,7 @@
 #include "WM_types.h"
 #include "ED_screen.h"
 #include "ED_view3d.h"
+#include "ED_util.h" /* for crazyspace correction */
 #include "paint_intern.h"
 #include "sculpt_intern.h"
 
@@ -169,7 +170,7 @@ int sculpt_modifiers_active(Scene *scene, Object *ob)
                if(!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue;
                if(md->type==eModifierType_ShapeKey) continue;
 
-               if(mti->type==eModifierTypeType_OnlyDeform && mti->deformMatrices)
+               if(mti->type==eModifierTypeType_OnlyDeform)
                        return 1;
        }
 
@@ -2642,7 +2643,7 @@ void sculpt_update_mesh_elements(Scene *scene, Object *ob, int need_fmap)
                        if(ss->kb) ss->orig_cos = key_to_vertcos(ob, ss->kb);
                        else ss->orig_cos = mesh_getVertexCos(ob->data, NULL);
 
-                       sculpt_get_deform_matrices(scene, ob, &ss->deform_imats, &ss->deform_cos);
+                       crazyspace_build_sculpt(scene, ob, &ss->deform_imats, &ss->deform_cos);
                        BLI_pbvh_apply_vertCos(ss->pbvh, ss->deform_cos);
 
                        for(a = 0; a < ((Mesh*)ob->data)->totvert; ++a)
index 86da5e0a4b599ec2f7d2bc0b6446567c62ca753f..20374cb8dbedac539be31989f513311731546d67 100644 (file)
@@ -85,6 +85,7 @@
 #include "ED_types.h"
 #include "ED_uvedit.h"
 #include "ED_curve.h" /* for ED_curve_editnurbs */
+#include "ED_util.h"  /* for crazyspace correction */
 
 #include "UI_view2d.h"
 
@@ -1940,147 +1941,6 @@ static void VertsToTransData(TransInfo *t, TransData *td, EditMesh *em, EditVert
        }
 }
 
-/* *********************** CrazySpace correction. Now without doing subsurf optimal ****************** */
-
-static void make_vertexcos__mapFunc(void *userData, int index, float *co, float *UNUSED(no_f), short *UNUSED(no_s))
-{
-       float *vec = userData;
-
-       vec+= 3*index;
-       VECCOPY(vec, co);
-}
-
-static int modifiers_disable_subsurf_temporary(Object *ob)
-{
-       ModifierData *md;
-       int disabled = 0;
-
-       for(md=ob->modifiers.first; md; md=md->next)
-               if(md->type==eModifierType_Subsurf)
-                       if(md->mode & eModifierMode_OnCage) {
-                               md->mode ^= eModifierMode_DisableTemporary;
-                               disabled= 1;
-                       }
-
-       return disabled;
-}
-
-/* disable subsurf temporal, get mapped cos, and enable it */
-static float *get_crazy_mapped_editverts(TransInfo *t)
-{
-       Mesh *me= t->obedit->data;
-       DerivedMesh *dm;
-       float *vertexcos;
-
-       /* disable subsurf temporal, get mapped cos, and enable it */
-       if(modifiers_disable_subsurf_temporary(t->obedit)) {
-               /* need to make new derivemesh */
-               makeDerivedMesh(t->scene, t->obedit, me->edit_mesh, CD_MASK_BAREMESH);
-       }
-
-       /* now get the cage */
-       dm= editmesh_get_derived_cage(t->scene, t->obedit, me->edit_mesh, CD_MASK_BAREMESH);
-
-       vertexcos= MEM_mallocN(3*sizeof(float)*me->edit_mesh->totvert, "vertexcos map");
-       dm->foreachMappedVert(dm, make_vertexcos__mapFunc, vertexcos);
-
-       dm->release(dm);
-
-       /* set back the flag, no new cage needs to be built, transform does it */
-       modifiers_disable_subsurf_temporary(t->obedit);
-
-       return vertexcos;
-}
-
-#define TAN_MAKE_VEC(a, b, c)  a[0]= b[0] + 0.2f*(b[0]-c[0]); a[1]= b[1] + 0.2f*(b[1]-c[1]); a[2]= b[2] + 0.2f*(b[2]-c[2])
-static void set_crazy_vertex_quat(float *quat, float *v1, float *v2, float *v3, float *def1, float *def2, float *def3)
-{
-       float vecu[3], vecv[3];
-       float q1[4], q2[4];
-
-       TAN_MAKE_VEC(vecu, v1, v2);
-       TAN_MAKE_VEC(vecv, v1, v3);
-       tri_to_quat( q1,v1, vecu, vecv);
-
-       TAN_MAKE_VEC(vecu, def1, def2);
-       TAN_MAKE_VEC(vecv, def1, def3);
-       tri_to_quat( q2,def1, vecu, vecv);
-
-       sub_qt_qtqt(quat, q2, q1);
-}
-#undef TAN_MAKE_VEC
-
-static void set_crazyspace_quats(EditMesh *em, float *origcos, float *mappedcos, float *quats)
-{
-       EditVert *eve, *prev;
-       EditFace *efa;
-       float *v1, *v2, *v3, *v4, *co1, *co2, *co3, *co4;
-       intptr_t index= 0;
-
-       /* two abused locations in vertices */
-       for(eve= em->verts.first; eve; eve= eve->next, index++) {
-               eve->tmp.p = NULL;
-               eve->prev= (EditVert *)index;
-       }
-
-       /* first store two sets of tangent vectors in vertices, we derive it just from the face-edges */
-       for(efa= em->faces.first; efa; efa= efa->next) {
-
-               /* retrieve mapped coordinates */
-               v1= mappedcos + 3*(intptr_t)(efa->v1->prev);
-               v2= mappedcos + 3*(intptr_t)(efa->v2->prev);
-               v3= mappedcos + 3*(intptr_t)(efa->v3->prev);
-
-               co1= (origcos)? origcos + 3*(intptr_t)(efa->v1->prev): efa->v1->co;
-               co2= (origcos)? origcos + 3*(intptr_t)(efa->v2->prev): efa->v2->co;
-               co3= (origcos)? origcos + 3*(intptr_t)(efa->v3->prev): efa->v3->co;
-
-               if(efa->v2->tmp.p==NULL && efa->v2->f1) {
-                       set_crazy_vertex_quat(quats, co2, co3, co1, v2, v3, v1);
-                       efa->v2->tmp.p= (void*)quats;
-                       quats+= 4;
-               }
-
-               if(efa->v4) {
-                       v4= mappedcos + 3*(intptr_t)(efa->v4->prev);
-                       co4= (origcos)? origcos + 3*(intptr_t)(efa->v4->prev): efa->v4->co;
-
-                       if(efa->v1->tmp.p==NULL && efa->v1->f1) {
-                               set_crazy_vertex_quat(quats, co1, co2, co4, v1, v2, v4);
-                               efa->v1->tmp.p= (void*)quats;
-                               quats+= 4;
-                       }
-                       if(efa->v3->tmp.p==NULL && efa->v3->f1) {
-                               set_crazy_vertex_quat(quats, co3, co4, co2, v3, v4, v2);
-                               efa->v3->tmp.p= (void*)quats;
-                               quats+= 4;
-                       }
-                       if(efa->v4->tmp.p==NULL && efa->v4->f1) {
-                               set_crazy_vertex_quat(quats, co4, co1, co3, v4, v1, v3);
-                               efa->v4->tmp.p= (void*)quats;
-                               quats+= 4;
-                       }
-               }
-               else {
-                       if(efa->v1->tmp.p==NULL && efa->v1->f1) {
-                               set_crazy_vertex_quat(quats, co1, co2, co3, v1, v2, v3);
-                               efa->v1->tmp.p= (void*)quats;
-                               quats+= 4;
-                       }
-                       if(efa->v3->tmp.p==NULL && efa->v3->f1) {
-                               set_crazy_vertex_quat(quats, co3, co1, co2, v3, v1, v2);
-                               efa->v3->tmp.p= (void*)quats;
-                               quats+= 4;
-                       }
-               }
-       }
-
-       /* restore abused prev pointer */
-       for(prev= NULL, eve= em->verts.first; eve; prev= eve, eve= eve->next)
-               eve->prev= prev;
-
-}
-
 void createTransBMeshVerts(TransInfo *t, BME_Mesh *bm, BME_TransData_Head *td) {
        BME_Vert *v;
        BME_TransData *vtd;
@@ -2200,9 +2060,9 @@ static void createTransEditVerts(bContext *C, TransInfo *t)
                                   correction with quats, relative to the coordinates after
                                   the modifiers that support deform matrices (defcos) */
                                if(totleft > 0) {
-                                       mappedcos= get_crazy_mapped_editverts(t);
+                                       mappedcos= crazyspace_get_mapped_editverts(t->scene, t->obedit);
                                        quats= MEM_mallocN( (t->total)*sizeof(float)*4, "crazy quats");
-                                       set_crazyspace_quats(em, (float*)defcos, mappedcos, quats);
+                                       crazyspace_set_quats_editmesh(em, (float*)defcos, mappedcos, quats);
                                        if(mappedcos)
                                                MEM_freeN(mappedcos);
                                }
index a2e0525cb0e1585575d0cd8cadbdb2f67c9aa0b0..38c0dd7f0ba997bb8f31361fae47f3d00d1f670a 100644 (file)
@@ -34,6 +34,7 @@ set(SRC
        editmode_undo.c
        numinput.c
        undo.c
+       crazyspace.c
 
        util_intern.h
        # general includes
diff --git a/source/blender/editors/util/crazyspace.c b/source/blender/editors/util/crazyspace.c
new file mode 100644 (file)
index 0000000..8b03f18
--- /dev/null
@@ -0,0 +1,394 @@
+/**
+ * $Id$
+ *
+ * ***** 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) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Blender Foundation,
+ *                 Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_DerivedMesh.h"
+#include "BKE_modifier.h"
+#include "BKE_multires.h"
+#include "BKE_mesh.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+#include "BLI_editVert.h"
+
+#define TAN_MAKE_VEC(a, b, c)  a[0]= b[0] + 0.2f*(b[0]-c[0]); a[1]= b[1] + 0.2f*(b[1]-c[1]); a[2]= b[2] + 0.2f*(b[2]-c[2])
+static void set_crazy_vertex_quat(float *quat, float *v1, float *v2, float *v3, float *def1, float *def2, float *def3)
+{
+       float vecu[3], vecv[3];
+       float q1[4], q2[4];
+
+       TAN_MAKE_VEC(vecu, v1, v2);
+       TAN_MAKE_VEC(vecv, v1, v3);
+       tri_to_quat( q1,v1, vecu, vecv);
+
+       TAN_MAKE_VEC(vecu, def1, def2);
+       TAN_MAKE_VEC(vecv, def1, def3);
+       tri_to_quat( q2,def1, vecu, vecv);
+
+       sub_qt_qtqt(quat, q2, q1);
+}
+#undef TAN_MAKE_VEC
+
+static void make_vertexcos__mapFunc(void *userData, int index, float *co, float *UNUSED(no_f), short *UNUSED(no_s))
+{
+       float *vec = userData;
+
+       vec+= 3*index;
+       VECCOPY(vec, co);
+}
+
+static int modifiers_disable_subsurf_temporary(Object *ob)
+{
+       ModifierData *md;
+       int disabled = 0;
+
+       for(md=ob->modifiers.first; md; md=md->next)
+               if(md->type==eModifierType_Subsurf)
+                       if(md->mode & eModifierMode_OnCage) {
+                               md->mode ^= eModifierMode_DisableTemporary;
+                               disabled= 1;
+                       }
+
+       return disabled;
+}
+
+/* disable subsurf temporal, get mapped cos, and enable it */
+float *crazyspace_get_mapped_editverts(Scene *scene, Object *obedit)
+{
+       Mesh *me= obedit->data;
+       DerivedMesh *dm;
+       float *vertexcos;
+
+       /* disable subsurf temporal, get mapped cos, and enable it */
+       if(modifiers_disable_subsurf_temporary(obedit)) {
+               /* need to make new derivemesh */
+               makeDerivedMesh(scene, obedit, me->edit_mesh, CD_MASK_BAREMESH);
+       }
+
+       /* now get the cage */
+       dm= editmesh_get_derived_cage(scene, obedit, me->edit_mesh, CD_MASK_BAREMESH);
+
+       vertexcos= MEM_mallocN(3*sizeof(float)*me->edit_mesh->totvert, "vertexcos map");
+       dm->foreachMappedVert(dm, make_vertexcos__mapFunc, vertexcos);
+
+       dm->release(dm);
+
+       /* set back the flag, no new cage needs to be built, transform does it */
+       modifiers_disable_subsurf_temporary(obedit);
+
+       return vertexcos;
+}
+
+void crazyspace_set_quats_editmesh(EditMesh *em, float *origcos, float *mappedcos, float *quats)
+{
+       EditVert *eve, *prev;
+       EditFace *efa;
+       float *v1, *v2, *v3, *v4, *co1, *co2, *co3, *co4;
+       intptr_t index= 0;
+
+       /* two abused locations in vertices */
+       for(eve= em->verts.first; eve; eve= eve->next, index++) {
+               eve->tmp.p = NULL;
+               eve->prev= (EditVert *)index;
+       }
+
+       /* first store two sets of tangent vectors in vertices, we derive it just from the face-edges */
+       for(efa= em->faces.first; efa; efa= efa->next) {
+
+               /* retrieve mapped coordinates */
+               v1= mappedcos + 3*(intptr_t)(efa->v1->prev);
+               v2= mappedcos + 3*(intptr_t)(efa->v2->prev);
+               v3= mappedcos + 3*(intptr_t)(efa->v3->prev);
+
+               co1= (origcos)? origcos + 3*(intptr_t)(efa->v1->prev): efa->v1->co;
+               co2= (origcos)? origcos + 3*(intptr_t)(efa->v2->prev): efa->v2->co;
+               co3= (origcos)? origcos + 3*(intptr_t)(efa->v3->prev): efa->v3->co;
+
+               if(efa->v2->tmp.p==NULL && efa->v2->f1) {
+                       set_crazy_vertex_quat(quats, co2, co3, co1, v2, v3, v1);
+                       efa->v2->tmp.p= (void*)quats;
+                       quats+= 4;
+               }
+
+               if(efa->v4) {
+                       v4= mappedcos + 3*(intptr_t)(efa->v4->prev);
+                       co4= (origcos)? origcos + 3*(intptr_t)(efa->v4->prev): efa->v4->co;
+
+                       if(efa->v1->tmp.p==NULL && efa->v1->f1) {
+                               set_crazy_vertex_quat(quats, co1, co2, co4, v1, v2, v4);
+                               efa->v1->tmp.p= (void*)quats;
+                               quats+= 4;
+                       }
+                       if(efa->v3->tmp.p==NULL && efa->v3->f1) {
+                               set_crazy_vertex_quat(quats, co3, co4, co2, v3, v4, v2);
+                               efa->v3->tmp.p= (void*)quats;
+                               quats+= 4;
+                       }
+                       if(efa->v4->tmp.p==NULL && efa->v4->f1) {
+                               set_crazy_vertex_quat(quats, co4, co1, co3, v4, v1, v3);
+                               efa->v4->tmp.p= (void*)quats;
+                               quats+= 4;
+                       }
+               }
+               else {
+                       if(efa->v1->tmp.p==NULL && efa->v1->f1) {
+                               set_crazy_vertex_quat(quats, co1, co2, co3, v1, v2, v3);
+                               efa->v1->tmp.p= (void*)quats;
+                               quats+= 4;
+                       }
+                       if(efa->v3->tmp.p==NULL && efa->v3->f1) {
+                               set_crazy_vertex_quat(quats, co3, co1, co2, v3, v1, v2);
+                               efa->v3->tmp.p= (void*)quats;
+                               quats+= 4;
+                       }
+               }
+       }
+
+       /* restore abused prev pointer */
+       for(prev= NULL, eve= em->verts.first; eve; prev= eve, eve= eve->next)
+               eve->prev= prev;
+
+}
+
+void crazyspace_set_quats_mesh(Mesh *me, float *origcos, float *mappedcos, float *quats)
+{
+       int i;
+       MVert *mvert;
+       MFace *mface;
+       float *v1, *v2, *v3, *v4, *co1, *co2, *co3, *co4;
+
+       mvert= me->mvert;
+       for(i=0; i<me->totvert; i++, mvert++)
+               mvert->flag&= ~ME_VERT_TMP_TAG;
+
+       /* first store two sets of tangent vectors in vertices, we derive it just from the face-edges */
+       mvert= me->mvert;
+       mface= me->mface;
+       for(i=0; i<me->totface; i++, mface++) {
+
+               /* retrieve mapped coordinates */
+               v1= mappedcos + 3*mface->v1;
+               v2= mappedcos + 3*mface->v2;
+               v3= mappedcos + 3*mface->v3;
+
+               co1= (origcos)? origcos + 3*mface->v1: mvert[mface->v1].co;
+               co2= (origcos)? origcos + 3*mface->v2: mvert[mface->v2].co;
+               co3= (origcos)? origcos + 3*mface->v3: mvert[mface->v3].co;
+
+               if((mvert[mface->v2].flag&ME_VERT_TMP_TAG)==0) {
+                       set_crazy_vertex_quat(&quats[mface->v2*4], co2, co3, co1, v2, v3, v1);
+                       mvert[mface->v2].flag|= ME_VERT_TMP_TAG;
+               }
+
+               if(mface->v4) {
+                       v4= mappedcos + 3*mface->v4;
+                       co4= (origcos)? origcos + 3*mface->v4: mvert[mface->v4].co;
+
+                       if((mvert[mface->v1].flag&ME_VERT_TMP_TAG)==0) {
+                               set_crazy_vertex_quat(&quats[mface->v1*4], co1, co2, co4, v1, v2, v4);
+                               mvert[mface->v1].flag|= ME_VERT_TMP_TAG;
+                       }
+                       if((mvert[mface->v3].flag&ME_VERT_TMP_TAG)==0) {
+                               set_crazy_vertex_quat(&quats[mface->v3*4], co3, co4, co2, v3, v4, v2);
+                               mvert[mface->v3].flag|= ME_VERT_TMP_TAG;
+                       }
+                       if((mvert[mface->v4].flag&ME_VERT_TMP_TAG)==0) {
+                               set_crazy_vertex_quat(&quats[mface->v4*4], co4, co1, co3, v4, v1, v3);
+                               mvert[mface->v4].flag|= ME_VERT_TMP_TAG;
+                       }
+               }
+               else {
+                       if((mvert[mface->v1].flag&ME_VERT_TMP_TAG)==0) {
+                               set_crazy_vertex_quat(&quats[mface->v1*4], co1, co2, co3, v1, v2, v3);
+                               mvert[mface->v1].flag|= ME_VERT_TMP_TAG;
+                       }
+                       if((mvert[mface->v3].flag&ME_VERT_TMP_TAG)==0) {
+                               set_crazy_vertex_quat(&quats[mface->v3*4], co3, co1, co2, v3, v1, v2);
+                               mvert[mface->v3].flag|= ME_VERT_TMP_TAG;
+                       }
+               }
+       }
+}
+
+int editmesh_get_first_deform_matrices(Scene *scene, Object *ob, EditMesh *em, float (**deformmats)[3][3], float (**deformcos)[3])
+{
+       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;
+
+       modifiers_clearErrors(ob);
+
+       dm = NULL;
+       md = modifiers_getVirtualModifierList(ob);
+
+       /* 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);
+
+               if(!editmesh_modifier_is_enabled(scene, md, dm))
+                       continue;
+
+               if(mti->type==eModifierTypeType_OnlyDeform && mti->deformMatricesEM) {
+                       if(!defmats) {
+                               dm= editmesh_get_derived(em, NULL);
+                               deformedVerts= editmesh_get_vertex_cos(em, &numVerts);
+                               defmats= MEM_callocN(sizeof(*defmats)*numVerts, "defmats");
+
+                               for(a=0; a<numVerts; a++)
+                                       unit_m3(defmats[a]);
+                       }
+
+                       mti->deformMatricesEM(md, ob, em, dm, deformedVerts, defmats,
+                               numVerts);
+               }
+               else
+                       break;
+       }
+
+       for(; md && i <= cageIndex; md = md->next, i++)
+               if(editmesh_modifier_is_enabled(scene, md, dm) && modifier_isCorrectableDeformed(md))
+                       numleft++;
+
+       if(dm)
+               dm->release(dm);
+
+       *deformmats= defmats;
+       *deformcos= deformedVerts;
+
+       return numleft;
+}
+
+int sculpt_get_first_deform_matrices(Scene *scene, Object *ob, float (**deformmats)[3][3], float (**deformcos)[3])
+{
+       ModifierData *md;
+       DerivedMesh *dm;
+       int a, numVerts= 0;
+       float (*defmats)[3][3]= NULL, (*deformedVerts)[3]= NULL;
+       MultiresModifierData *mmd= get_multires_modifier(scene, ob, 0);
+       int has_multires = mmd != NULL && mmd->sculptlvl > 0;
+       int numleft= 0;
+
+       if(has_multires) {
+               *deformmats= NULL;
+               *deformcos= NULL;
+               return numleft;
+       }
+
+       dm= NULL;
+       md= modifiers_getVirtualModifierList(ob);
+
+       for(; md; md= md->next) {
+               ModifierTypeInfo *mti= modifierType_getInfo(md->type);
+
+               if(!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue;
+
+               if(mti->type==eModifierTypeType_OnlyDeform) {
+                       if(!defmats) {
+                               Mesh *me= (Mesh*)ob->data;
+                               dm= mesh_create_derived(me, ob, NULL);
+                               deformedVerts= mesh_getVertexCos(me, &numVerts);
+                               defmats= MEM_callocN(sizeof(*defmats)*numVerts, "defmats");
+
+                               for(a=0; a<numVerts; a++)
+                                       unit_m3(defmats[a]);
+                       }
+
+                       if(mti->deformMatrices) mti->deformMatrices(md, ob, dm, deformedVerts, defmats, numVerts);
+                       else break;
+               }
+       }
+
+       for(; md; md= md->next) {
+               ModifierTypeInfo *mti= modifierType_getInfo(md->type);
+
+               if(!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue;
+
+               if(mti->type==eModifierTypeType_OnlyDeform)
+                       numleft++;
+       }
+
+       if(dm)
+               dm->release(dm);
+
+       *deformmats= defmats;
+       *deformcos= deformedVerts;
+
+       return numleft;
+}
+
+void crazyspace_build_sculpt(Scene *scene, Object *ob, float (**deformmats)[3][3], float (**deformcos)[3])
+{
+       int totleft= sculpt_get_first_deform_matrices(scene, ob, deformmats, deformcos);
+
+       if(totleft) {
+               /* there are deformation modifier which doesn't support deformation matricies
+                  calculation. Need additional crazyspace correction */
+
+               float (*deformedVerts)[3]= *deformcos;
+               float (*origVerts)[3]= MEM_dupallocN(deformedVerts);
+               float *quats= NULL;
+               int i;
+               ModifierData *md= modifiers_getVirtualModifierList(ob);
+               Mesh *me= (Mesh*)ob->data;
+
+               for(; md; md= md->next) {
+                       ModifierTypeInfo *mti= modifierType_getInfo(md->type);
+
+                       if(!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue;
+
+                       if(mti->type==eModifierTypeType_OnlyDeform)
+                               mti->deformVerts(md, ob, NULL, deformedVerts, me->totvert, 0, 0);
+               }
+
+               quats= MEM_mallocN(me->totvert*sizeof(float)*4, "crazy quats");
+
+               crazyspace_set_quats_mesh(me, (float*)origVerts, (float*)deformedVerts, quats);
+
+               for(i=0; i<me->totvert; i++) {
+                       float qmat[3][3], tmat[3][3];
+
+                       quat_to_mat3(qmat, &quats[i*4]);
+                       mul_m3_m3m3(tmat, qmat, (*deformmats)[i]);
+                       copy_m3_m3((*deformmats)[i], tmat);
+               }
+
+               MEM_freeN(origVerts);
+               MEM_freeN(quats);
+       }
+}