Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r--source/blender/blenkernel/BKE_crazyspace.h54
-rw-r--r--source/blender/blenkernel/BKE_paint.h11
-rw-r--r--source/blender/blenkernel/CMakeLists.txt4
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c3
-rw-r--r--source/blender/blenkernel/intern/crazyspace.c448
-rw-r--r--source/blender/blenkernel/intern/paint.c241
6 files changed, 759 insertions, 2 deletions
diff --git a/source/blender/blenkernel/BKE_crazyspace.h b/source/blender/blenkernel/BKE_crazyspace.h
new file mode 100644
index 00000000000..89cbd9ec119
--- /dev/null
+++ b/source/blender/blenkernel/BKE_crazyspace.h
@@ -0,0 +1,54 @@
+/*
+ * ***** 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) 2008 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file BKE_crazyspace.h
+ * \ingroup bke
+ */
+
+#ifndef __BKE_CRAZYSPACE_H__
+#define __BKE_CRAZYSPACE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct Scene;
+struct Object;
+struct BMEditMesh;
+struct Mesh;
+
+/* crazyspace.c */
+float (*crazyspace_get_mapped_editverts(struct Scene *scene, struct Object *obedit))[3];
+void crazyspace_set_quats_editmesh(struct BMEditMesh *em, float (*origcos)[3], float (*mappedcos)[3], float (*quats)[4],
+ const bool use_select);
+void crazyspace_set_quats_mesh(struct Mesh *me, float (*origcos)[3], float (*mappedcos)[3], float (*quats)[4]);
+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]);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index df72cb988b1..cb521382bd3 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -47,6 +47,7 @@ struct Object;
struct Paint;
struct PBVH;
struct Scene;
+struct Sculpt;
struct StrokeCache;
struct Tex;
struct ImagePool;
@@ -176,4 +177,14 @@ void free_sculptsession(struct Object *ob);
void free_sculptsession_deformMats(struct SculptSession *ss);
void sculptsession_bm_to_me(struct Object *ob, bool reorder);
void sculptsession_bm_to_me_for_render(struct Object *object);
+void sculpt_update_mesh_elements(struct Scene *scene, struct Sculpt *sd, struct Object *ob,
+ bool need_pmap, bool need_mask);
+struct MultiresModifierData *sculpt_multires_active(struct Scene *scene, struct Object *ob);
+int ED_sculpt_mask_layers_ensure(struct Object *ob,
+ struct MultiresModifierData *mmd);
+
+enum {
+ ED_SCULPT_MASK_LAYER_CALC_VERT = (1 << 0),
+ ED_SCULPT_MASK_LAYER_CALC_LOOP = (1 << 1)
+};
#endif
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 749a5eb408d..0caf7d11c55 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -78,7 +78,8 @@ set(SRC
intern/colortools.c
intern/constraint.c
intern/context.c
- intern/curve.c
+ intern/crazyspace.c
+ intern/curve.c
intern/customdata.c
intern/customdata_file.c
intern/deform.c
@@ -191,6 +192,7 @@ set(SRC
BKE_colortools.h
BKE_constraint.h
BKE_context.h
+ BKE_crazyspace.h
BKE_curve.h
BKE_customdata.h
BKE_customdata_file.h
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index 26cc70e1089..228f4ce7730 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -2251,7 +2251,8 @@ static void mesh_build_data(Scene *scene, Object *ob, CustomDataMask dataMask,
if ((ob->mode & OB_MODE_SCULPT) && ob->sculpt) {
/* create PBVH immediately (would be created on the fly too,
* but this avoids waiting on first stroke) */
- ob->sculpt->pbvh = ob->derivedFinal->getPBVH(ob, ob->derivedFinal);
+
+ sculpt_update_mesh_elements(scene, scene->toolsettings->sculpt, ob, false, false);
}
BLI_assert(!(ob->derivedFinal->dirty & DM_DIRTY_NORMALS));
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]);
+ }
+}
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 1189b5715bb..d5059566dab 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -37,6 +37,7 @@
#include "DNA_object_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
#include "DNA_scene_types.h"
#include "DNA_brush_types.h"
#include "DNA_space_types.h"
@@ -47,10 +48,14 @@
#include "BKE_brush.h"
#include "BKE_context.h"
+#include "BKE_crazyspace.h"
#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_image.h"
+#include "BKE_key.h"
#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_pbvh.h"
@@ -499,3 +504,239 @@ void free_sculptsession(Object *ob)
ob->sculpt = NULL;
}
}
+
+/* Sculpt mode handles multires differently from regular meshes, but only if
+ * it's the last modifier on the stack and it is not on the first level */
+MultiresModifierData *sculpt_multires_active(Scene *scene, Object *ob)
+{
+ Mesh *me = (Mesh *)ob->data;
+ ModifierData *md;
+ VirtualModifierData virtualModifierData;
+
+ if (ob->sculpt && ob->sculpt->bm) {
+ /* can't combine multires and dynamic topology */
+ return NULL;
+ }
+
+ if (!CustomData_get_layer(&me->ldata, CD_MDISPS)) {
+ /* multires can't work without displacement layer */
+ return NULL;
+ }
+
+ for (md = modifiers_getVirtualModifierList(ob, &virtualModifierData); md; md = md->next) {
+ if (md->type == eModifierType_Multires) {
+ MultiresModifierData *mmd = (MultiresModifierData *)md;
+
+ if (!modifier_isEnabled(scene, md, eModifierMode_Realtime))
+ continue;
+
+ if (mmd->sculptlvl > 0) return mmd;
+ else return NULL;
+ }
+ }
+
+ return NULL;
+}
+
+
+/* Checks if there are any supported deformation modifiers active */
+static bool sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob)
+{
+ ModifierData *md;
+ Mesh *me = (Mesh *)ob->data;
+ MultiresModifierData *mmd = sculpt_multires_active(scene, ob);
+ VirtualModifierData virtualModifierData;
+
+ if (mmd || ob->sculpt->bm)
+ return 0;
+
+ /* non-locked shape keys could be handled in the same way as deformed mesh */
+ if ((ob->shapeflag & OB_SHAPE_LOCK) == 0 && me->key && ob->shapenr)
+ return 1;
+
+ md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+
+ /* exception for shape keys because we can edit those */
+ for (; md; md = md->next) {
+ ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue;
+ if (md->type == eModifierType_ShapeKey) continue;
+
+ if (mti->type == eModifierTypeType_OnlyDeform) return 1;
+ else if ((sd->flags & SCULPT_ONLY_DEFORM) == 0) return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * \param need_mask So the DerivedMesh thats returned has mask data
+ */
+void sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob,
+ bool need_pmap, bool need_mask)
+{
+ DerivedMesh *dm;
+ SculptSession *ss = ob->sculpt;
+ Mesh *me = ob->data;
+ MultiresModifierData *mmd = sculpt_multires_active(scene, ob);
+
+ ss->modifiers_active = sculpt_modifiers_active(scene, sd, ob);
+ ss->show_diffuse_color = (sd->flags & SCULPT_SHOW_DIFFUSE) != 0;
+
+ if (need_mask) {
+ if (mmd == NULL) {
+ if (!CustomData_has_layer(&me->vdata, CD_PAINT_MASK)) {
+ ED_sculpt_mask_layers_ensure(ob, NULL);
+ }
+ }
+ else {
+ if (!CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK)) {
+#if 1
+ ED_sculpt_mask_layers_ensure(ob, mmd);
+#else /* if we wanted to support adding mask data while multi-res painting, we would need to do this */
+ if ((ED_sculpt_mask_layers_ensure(ob, mmd) & ED_SCULPT_MASK_LAYER_CALC_LOOP)) {
+ /* remake the derived mesh */
+ ob->recalc |= OB_RECALC_DATA;
+ BKE_object_handle_update(scene, ob);
+ }
+#endif
+ }
+ }
+ }
+
+ /* BMESH ONLY --- at some point we should move sculpt code to use polygons only - but for now it needs tessfaces */
+ BKE_mesh_tessface_ensure(me);
+
+ if (!mmd) ss->kb = BKE_keyblock_from_object(ob);
+ else ss->kb = NULL;
+
+ /* needs to be called after we ensure tessface */
+ dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
+
+ if (mmd) {
+ ss->multires = mmd;
+ ss->totvert = dm->getNumVerts(dm);
+ ss->totpoly = dm->getNumPolys(dm);
+ ss->mvert = NULL;
+ ss->mpoly = NULL;
+ ss->mloop = NULL;
+ ss->face_normals = NULL;
+ }
+ else {
+ ss->totvert = me->totvert;
+ ss->totpoly = me->totpoly;
+ ss->mvert = me->mvert;
+ ss->mpoly = me->mpoly;
+ ss->mloop = me->mloop;
+ ss->face_normals = NULL;
+ ss->multires = NULL;
+ ss->vmask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK);
+ }
+
+ ss->pbvh = dm->getPBVH(ob, dm);
+ ss->pmap = (need_pmap && dm->getPolyMap) ? dm->getPolyMap(ob, dm) : NULL;
+
+ pbvh_show_diffuse_color_set(ss->pbvh, ss->show_diffuse_color);
+
+ if (ss->modifiers_active) {
+ if (!ss->orig_cos) {
+ int a;
+
+ free_sculptsession_deformMats(ss);
+
+ ss->orig_cos = (ss->kb) ? BKE_key_convert_to_vertcos(ob, ss->kb) : BKE_mesh_vertexCos_get(me, NULL);
+
+ crazyspace_build_sculpt(scene, ob, &ss->deform_imats, &ss->deform_cos);
+ BKE_pbvh_apply_vertCos(ss->pbvh, ss->deform_cos);
+
+ for (a = 0; a < me->totvert; ++a) {
+ invert_m3(ss->deform_imats[a]);
+ }
+ }
+ }
+ else {
+ free_sculptsession_deformMats(ss);
+ }
+
+ /* if pbvh is deformed, key block is already applied to it */
+ if (ss->kb && !BKE_pbvh_isDeformed(ss->pbvh)) {
+ float (*vertCos)[3] = BKE_key_convert_to_vertcos(ob, ss->kb);
+
+ if (vertCos) {
+ /* apply shape keys coordinates to PBVH */
+ BKE_pbvh_apply_vertCos(ss->pbvh, vertCos);
+ MEM_freeN(vertCos);
+ }
+ }
+}
+
+int ED_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd)
+{
+ const float *paint_mask;
+ Mesh *me = ob->data;
+ int ret = 0;
+
+ paint_mask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK);
+
+ /* if multires is active, create a grid paint mask layer if there
+ * isn't one already */
+ if (mmd && !CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK)) {
+ GridPaintMask *gmask;
+ int level = max_ii(1, mmd->sculptlvl);
+ int gridsize = BKE_ccg_gridsize(level);
+ int gridarea = gridsize * gridsize;
+ int i, j;
+
+ gmask = CustomData_add_layer(&me->ldata, CD_GRID_PAINT_MASK,
+ CD_CALLOC, NULL, me->totloop);
+
+ for (i = 0; i < me->totloop; i++) {
+ GridPaintMask *gpm = &gmask[i];
+
+ gpm->level = level;
+ gpm->data = MEM_callocN(sizeof(float) * gridarea,
+ "GridPaintMask.data");
+ }
+
+ /* if vertices already have mask, copy into multires data */
+ if (paint_mask) {
+ for (i = 0; i < me->totpoly; i++) {
+ const MPoly *p = &me->mpoly[i];
+ float avg = 0;
+
+ /* mask center */
+ for (j = 0; j < p->totloop; j++) {
+ const MLoop *l = &me->mloop[p->loopstart + j];
+ avg += paint_mask[l->v];
+ }
+ avg /= (float)p->totloop;
+
+ /* fill in multires mask corner */
+ for (j = 0; j < p->totloop; j++) {
+ GridPaintMask *gpm = &gmask[p->loopstart + j];
+ const MLoop *l = &me->mloop[p->loopstart + j];
+ const MLoop *prev = ME_POLY_LOOP_PREV(me->mloop, p, j);
+ const MLoop *next = ME_POLY_LOOP_NEXT(me->mloop, p, j);
+
+ gpm->data[0] = avg;
+ gpm->data[1] = (paint_mask[l->v] +
+ paint_mask[next->v]) * 0.5f;
+ gpm->data[2] = (paint_mask[l->v] +
+ paint_mask[prev->v]) * 0.5f;
+ gpm->data[3] = paint_mask[l->v];
+ }
+ }
+ }
+
+ ret |= ED_SCULPT_MASK_LAYER_CALC_LOOP;
+ }
+
+ /* create vertex paint mask layer if there isn't one already */
+ if (!paint_mask) {
+ CustomData_add_layer(&me->vdata, CD_PAINT_MASK,
+ CD_CALLOC, NULL, me->totvert);
+ ret |= ED_SCULPT_MASK_LAYER_CALC_VERT;
+ }
+
+ return ret;
+}