diff options
Diffstat (limited to 'source/blender/blenkernel/intern/crazyspace.c')
-rw-r--r-- | source/blender/blenkernel/intern/crazyspace.c | 448 |
1 files changed, 448 insertions, 0 deletions
diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c new file mode 100644 index 00000000000..610a0fe0fbc --- /dev/null +++ b/source/blender/blenkernel/intern/crazyspace.c @@ -0,0 +1,448 @@ +/* + * ***** 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 ***** + */ + +/** \file blender/blenkernel/intern/crazyspace.c + * \ingroup bke + */ + + +#include "MEM_guardedalloc.h" + +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_modifier_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BLI_utildefines.h" +#include "BLI_math.h" +#include "BLI_bitmap.h" + +#include "BKE_crazyspace.h" +#include "BKE_DerivedMesh.h" +#include "BKE_modifier.h" +#include "BKE_multires.h" +#include "BKE_mesh.h" +#include "BKE_editmesh.h" + +typedef struct { + float (*vertexcos)[3]; + BLI_bitmap *vertex_visit; +} MappedUserData; + +BLI_INLINE void tan_calc_quat_v3( + float r_quat[4], + const float co_1[3], const float co_2[3], const float co_3[3]) +{ + float vec_u[3], vec_v[3]; + float nor[3]; + + sub_v3_v3v3(vec_u, co_1, co_2); + sub_v3_v3v3(vec_v, co_1, co_3); + + cross_v3_v3v3(nor, vec_u, vec_v); + + if (normalize_v3(nor) > FLT_EPSILON) { + const float zero_vec[3] = {0.0f}; + tri_to_quat_ex(r_quat, zero_vec, vec_u, vec_v, nor); + } + else { + unit_qt(r_quat); + } +} + +static void set_crazy_vertex_quat( + float r_quat[4], + const float co_1[3], const float co_2[3], const float co_3[3], + const float vd_1[3], const float vd_2[3], const float vd_3[3]) +{ + float q1[4], q2[4]; + + tan_calc_quat_v3(q1, co_1, co_2, co_3); + tan_calc_quat_v3(q2, vd_1, vd_2, vd_3); + + sub_qt_qtqt(r_quat, q2, q1); +} + +static void make_vertexcos__mapFunc(void *userData, int index, const float co[3], + const float UNUSED(no_f[3]), const short UNUSED(no_s[3])) +{ + MappedUserData *mappedData = (MappedUserData *)userData; + + if (BLI_BITMAP_GET(mappedData->vertex_visit, index) == 0) { + /* we need coord from prototype vertex, not from copies, + * assume they stored in the beginning of vertex array stored in DM + * (mirror modifier for eg does this) */ + copy_v3_v3(mappedData->vertexcos[index], co); + BLI_BITMAP_SET(mappedData->vertex_visit, index); + } +} + +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))[3] +{ + Mesh *me = obedit->data; + DerivedMesh *dm; + float (*vertexcos)[3]; + int nverts = me->edit_btmesh->bm->totvert; + BLI_bitmap *vertex_visit; + MappedUserData userData; + + /* 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_btmesh, CD_MASK_BAREMESH, 0); + } + + /* now get the cage */ + dm = editbmesh_get_derived_cage(scene, obedit, me->edit_btmesh, CD_MASK_BAREMESH); + + vertexcos = MEM_callocN(sizeof(*vertexcos) * nverts, "vertexcos map"); + vertex_visit = BLI_BITMAP_NEW(nverts, "vertexcos flags"); + + userData.vertexcos = vertexcos; + userData.vertex_visit = vertex_visit; + dm->foreachMappedVert(dm, make_vertexcos__mapFunc, &userData, DM_FOREACH_NOP); + + dm->release(dm); + + /* set back the flag, no new cage needs to be built, transform does it */ + modifiers_disable_subsurf_temporary(obedit); + + MEM_freeN(vertex_visit); + + return vertexcos; +} + +void crazyspace_set_quats_editmesh(BMEditMesh *em, float (*origcos)[3], float (*mappedcos)[3], float (*quats)[4], + const bool use_select) +{ + BMFace *f; + BMIter iter; + int index; + + { + BMVert *v; + BM_ITER_MESH_INDEX (v, &iter, em->bm, BM_VERTS_OF_MESH, index) { + BM_elem_flag_disable(v, BM_ELEM_TAG); + BM_elem_index_set(v, index); /* set_inline */ + } + em->bm->elem_index_dirty &= ~BM_VERT; + } + + BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) { + BMLoop *l_iter, *l_first; + + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + if (BM_elem_flag_test(l_iter->v, BM_ELEM_HIDDEN) || + BM_elem_flag_test(l_iter->v, BM_ELEM_TAG) || + (use_select && !BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT))) + { + continue; + } + + if (!BM_elem_flag_test(l_iter->v, BM_ELEM_TAG)) { + const float *co_prev, *co_curr, *co_next; /* orig */ + const float *vd_prev, *vd_curr, *vd_next; /* deform */ + + const int i_prev = BM_elem_index_get(l_iter->prev->v); + const int i_curr = BM_elem_index_get(l_iter->v); + const int i_next = BM_elem_index_get(l_iter->next->v); + + /* retrieve mapped coordinates */ + vd_prev = mappedcos[i_prev]; + vd_curr = mappedcos[i_curr]; + vd_next = mappedcos[i_next]; + + if (origcos) { + co_prev = origcos[i_prev]; + co_curr = origcos[i_curr]; + co_next = origcos[i_next]; + } + else { + co_prev = l_iter->prev->v->co; + co_curr = l_iter->v->co; + co_next = l_iter->next->v->co; + } + + set_crazy_vertex_quat(quats[i_curr], + co_curr, co_next, co_prev, + vd_curr, vd_next, vd_prev); + + BM_elem_flag_enable(l_iter->v, BM_ELEM_TAG); + } + } while ((l_iter = l_iter->next) != l_first); + } +} + +void crazyspace_set_quats_mesh(Mesh *me, float (*origcos)[3], float (*mappedcos)[3], float (*quats)[4]) +{ + int i; + MVert *mvert; + MLoop *mloop; + MPoly *mp; + + 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; + mp = me->mpoly; + mloop = me->mloop; + + for (i = 0; i < me->totpoly; i++, mp++) { + MLoop *ml_prev, *ml_curr, *ml_next; + int j; + + ml_next = &mloop[mp->loopstart]; + ml_curr = &ml_next[mp->totloop - 1]; + ml_prev = &ml_next[mp->totloop - 2]; + + for (j = 0; j < mp->totloop; j++) { + if ((mvert[ml_curr->v].flag & ME_VERT_TMP_TAG) == 0) { + const float *co_prev, *co_curr, *co_next; /* orig */ + const float *vd_prev, *vd_curr, *vd_next; /* deform */ + + /* retrieve mapped coordinates */ + vd_prev = mappedcos[ml_prev->v]; + vd_curr = mappedcos[ml_curr->v]; + vd_next = mappedcos[ml_next->v]; + + if (origcos) { + co_prev = origcos[ml_prev->v]; + co_curr = origcos[ml_curr->v]; + co_next = origcos[ml_next->v]; + } + else { + co_prev = mvert[ml_prev->v].co; + co_curr = mvert[ml_curr->v].co; + co_next = mvert[ml_next->v].co; + } + + set_crazy_vertex_quat(quats[ml_curr->v], + co_curr, co_next, co_prev, + vd_curr, vd_next, vd_prev); + + mvert[ml_curr->v].flag |= ME_VERT_TMP_TAG; + } + + ml_prev = ml_curr; + ml_curr = ml_next; + ml_next++; + } + } +} + +int editbmesh_get_first_deform_matrices(Scene *scene, Object *ob, BMEditMesh *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; + VirtualModifierData virtualModifierData; + + modifiers_clearErrors(ob); + + dm = NULL; + md = modifiers_getVirtualModifierList(ob, &virtualModifierData); + + /* 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 (!editbmesh_modifier_is_enabled(scene, md, dm)) + continue; + + if (mti->type == eModifierTypeType_OnlyDeform && mti->deformMatricesEM) { + if (!defmats) { + dm = getEditDerivedBMesh(em, ob, NULL); + deformedVerts = editbmesh_get_vertex_cos(em, &numVerts); + defmats = MEM_mallocN(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 (editbmesh_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); + const bool has_multires = mmd != NULL && mmd->sculptlvl > 0; + int numleft = 0; + VirtualModifierData virtualModifierData; + + if (has_multires) { + *deformmats = NULL; + *deformcos = NULL; + return numleft; + } + + dm = NULL; + md = modifiers_getVirtualModifierList(ob, &virtualModifierData); + + 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, NULL); + deformedVerts = BKE_mesh_vertexCos_get(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 matrices + * calculation. Need additional crazyspace correction */ + + float (*deformedVerts)[3] = *deformcos; + float (*origVerts)[3] = MEM_dupallocN(deformedVerts); + float (*quats)[4]; + int i, deformed = 0; + VirtualModifierData virtualModifierData; + ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); + 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) { + /* skip leading modifiers which have been already + * handled in sculpt_get_first_deform_matrices */ + if (mti->deformMatrices && !deformed) + continue; + + mti->deformVerts(md, ob, NULL, deformedVerts, me->totvert, 0); + deformed = 1; + } + } + + quats = MEM_mallocN(me->totvert * sizeof(*quats), "crazy quats"); + + crazyspace_set_quats_mesh(me, origVerts, deformedVerts, quats); + + for (i = 0; i < me->totvert; i++) { + float qmat[3][3], tmat[3][3]; + + quat_to_mat3(qmat, quats[i]); + mul_m3_m3m3(tmat, qmat, (*deformmats)[i]); + copy_m3_m3((*deformmats)[i], tmat); + } + + MEM_freeN(origVerts); + MEM_freeN(quats); + } + + if (*deformmats == NULL) { + int a, numVerts; + Mesh *me = (Mesh *)ob->data; + + *deformcos = BKE_mesh_vertexCos_get(me, &numVerts); + *deformmats = MEM_callocN(sizeof(*(*deformmats)) * numVerts, "defmats"); + + for (a = 0; a < numVerts; a++) + unit_m3((*deformmats)[a]); + } +} |