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/intern/lattice_deform.c')
-rw-r--r--source/blender/blenkernel/intern/lattice_deform.c470
1 files changed, 470 insertions, 0 deletions
diff --git a/source/blender/blenkernel/intern/lattice_deform.c b/source/blender/blenkernel/intern/lattice_deform.c
new file mode 100644
index 00000000000..674ee9ed2c5
--- /dev/null
+++ b/source/blender/blenkernel/intern/lattice_deform.c
@@ -0,0 +1,470 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ *
+ * Deform coordinates by a lattice object (used by modifier).
+ */
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_task.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_curve_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_curve.h"
+#include "BKE_displist.h"
+#include "BKE_editmesh.h"
+#include "BKE_key.h"
+#include "BKE_lattice.h"
+#include "BKE_modifier.h"
+
+#include "BKE_deform.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Lattice Deform API
+ * \{ */
+
+typedef struct LatticeDeformData {
+ const Object *object;
+ float *latticedata;
+ float latmat[4][4];
+} LatticeDeformData;
+
+LatticeDeformData *BKE_lattice_deform_data_create(const Object *oblatt, const Object *ob)
+{
+ /* we make an array with all differences */
+ Lattice *lt = oblatt->data;
+ BPoint *bp;
+ DispList *dl = oblatt->runtime.curve_cache ?
+ BKE_displist_find(&oblatt->runtime.curve_cache->disp, DL_VERTS) :
+ NULL;
+ const float *co = dl ? dl->verts : NULL;
+ float *fp, imat[4][4];
+ float fu, fv, fw;
+ int u, v, w;
+ float *latticedata;
+ float latmat[4][4];
+ LatticeDeformData *lattice_deform_data;
+
+ if (lt->editlatt) {
+ lt = lt->editlatt->latt;
+ }
+ bp = lt->def;
+
+ fp = latticedata = MEM_mallocN(sizeof(float) * 3 * lt->pntsu * lt->pntsv * lt->pntsw,
+ "latticedata");
+
+ /* for example with a particle system: (ob == NULL) */
+ if (ob == NULL) {
+ /* in deformspace, calc matrix */
+ invert_m4_m4(latmat, oblatt->obmat);
+
+ /* back: put in deform array */
+ invert_m4_m4(imat, latmat);
+ }
+ else {
+ /* in deformspace, calc matrix */
+ invert_m4_m4(imat, oblatt->obmat);
+ mul_m4_m4m4(latmat, imat, ob->obmat);
+
+ /* back: put in deform array */
+ invert_m4_m4(imat, latmat);
+ }
+
+ for (w = 0, fw = lt->fw; w < lt->pntsw; w++, fw += lt->dw) {
+ for (v = 0, fv = lt->fv; v < lt->pntsv; v++, fv += lt->dv) {
+ for (u = 0, fu = lt->fu; u < lt->pntsu; u++, bp++, co += 3, fp += 3, fu += lt->du) {
+ if (dl) {
+ fp[0] = co[0] - fu;
+ fp[1] = co[1] - fv;
+ fp[2] = co[2] - fw;
+ }
+ else {
+ fp[0] = bp->vec[0] - fu;
+ fp[1] = bp->vec[1] - fv;
+ fp[2] = bp->vec[2] - fw;
+ }
+
+ mul_mat3_m4_v3(imat, fp);
+ }
+ }
+ }
+
+ lattice_deform_data = MEM_mallocN(sizeof(LatticeDeformData), "Lattice Deform Data");
+ lattice_deform_data->latticedata = latticedata;
+ lattice_deform_data->object = oblatt;
+ copy_m4_m4(lattice_deform_data->latmat, latmat);
+
+ return lattice_deform_data;
+}
+
+void BKE_lattice_deform_data_eval_co(LatticeDeformData *lattice_deform_data,
+ float co[3],
+ float weight)
+{
+ const Object *ob = lattice_deform_data->object;
+ Lattice *lt = ob->data;
+ float u, v, w, tu[4], tv[4], tw[4];
+ float vec[3];
+ int idx_w, idx_v, idx_u;
+ int ui, vi, wi, uu, vv, ww;
+
+ /* vgroup influence */
+ int defgrp_index = -1;
+ float co_prev[3], weight_blend = 0.0f;
+ const MDeformVert *dvert = BKE_lattice_deform_verts_get(ob);
+ float *__restrict latticedata = lattice_deform_data->latticedata;
+
+ if (lt->editlatt) {
+ lt = lt->editlatt->latt;
+ }
+ if (latticedata == NULL) {
+ return;
+ }
+
+ if (lt->vgroup[0] && dvert) {
+ defgrp_index = BKE_object_defgroup_name_index(ob, lt->vgroup);
+ copy_v3_v3(co_prev, co);
+ }
+
+ /* co is in local coords, treat with latmat */
+ mul_v3_m4v3(vec, lattice_deform_data->latmat, co);
+
+ /* u v w coords */
+
+ if (lt->pntsu > 1) {
+ u = (vec[0] - lt->fu) / lt->du;
+ ui = (int)floor(u);
+ u -= ui;
+ key_curve_position_weights(u, tu, lt->typeu);
+ }
+ else {
+ tu[0] = tu[2] = tu[3] = 0.0;
+ tu[1] = 1.0;
+ ui = 0;
+ }
+
+ if (lt->pntsv > 1) {
+ v = (vec[1] - lt->fv) / lt->dv;
+ vi = (int)floor(v);
+ v -= vi;
+ key_curve_position_weights(v, tv, lt->typev);
+ }
+ else {
+ tv[0] = tv[2] = tv[3] = 0.0;
+ tv[1] = 1.0;
+ vi = 0;
+ }
+
+ if (lt->pntsw > 1) {
+ w = (vec[2] - lt->fw) / lt->dw;
+ wi = (int)floor(w);
+ w -= wi;
+ key_curve_position_weights(w, tw, lt->typew);
+ }
+ else {
+ tw[0] = tw[2] = tw[3] = 0.0;
+ tw[1] = 1.0;
+ wi = 0;
+ }
+
+ for (ww = wi - 1; ww <= wi + 2; ww++) {
+ w = tw[ww - wi + 1];
+
+ if (w != 0.0f) {
+ if (ww > 0) {
+ if (ww < lt->pntsw) {
+ idx_w = ww * lt->pntsu * lt->pntsv;
+ }
+ else {
+ idx_w = (lt->pntsw - 1) * lt->pntsu * lt->pntsv;
+ }
+ }
+ else {
+ idx_w = 0;
+ }
+
+ for (vv = vi - 1; vv <= vi + 2; vv++) {
+ v = w * tv[vv - vi + 1];
+
+ if (v != 0.0f) {
+ if (vv > 0) {
+ if (vv < lt->pntsv) {
+ idx_v = idx_w + vv * lt->pntsu;
+ }
+ else {
+ idx_v = idx_w + (lt->pntsv - 1) * lt->pntsu;
+ }
+ }
+ else {
+ idx_v = idx_w;
+ }
+
+ for (uu = ui - 1; uu <= ui + 2; uu++) {
+ u = weight * v * tu[uu - ui + 1];
+
+ if (u != 0.0f) {
+ if (uu > 0) {
+ if (uu < lt->pntsu) {
+ idx_u = idx_v + uu;
+ }
+ else {
+ idx_u = idx_v + (lt->pntsu - 1);
+ }
+ }
+ else {
+ idx_u = idx_v;
+ }
+
+ madd_v3_v3fl(co, &latticedata[idx_u * 3], u);
+
+ if (defgrp_index != -1) {
+ weight_blend += (u * BKE_defvert_find_weight(dvert + idx_u, defgrp_index));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (defgrp_index != -1) {
+ interp_v3_v3v3(co, co_prev, co, weight_blend);
+ }
+}
+
+void BKE_lattice_deform_data_destroy(LatticeDeformData *lattice_deform_data)
+{
+ if (lattice_deform_data->latticedata) {
+ MEM_freeN(lattice_deform_data->latticedata);
+ }
+
+ MEM_freeN(lattice_deform_data);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Lattice Deform #BKE_lattice_deform_coords API
+ *
+ * #BKE_lattice_deform_coords and related functions.
+ * \{ */
+
+typedef struct LatticeDeformUserdata {
+ LatticeDeformData *lattice_deform_data;
+ float (*vert_coords)[3];
+ const MDeformVert *dvert;
+ int defgrp_index;
+ float fac;
+ bool invert_vgroup;
+
+ /** Specific data types. */
+ struct {
+ int cd_dvert_offset;
+ } bmesh;
+} LatticeDeformUserdata;
+
+static void lattice_deform_vert_with_dvert(const LatticeDeformUserdata *data,
+ const int index,
+ const MDeformVert *dvert)
+{
+ if (dvert != NULL) {
+ const float weight = data->invert_vgroup ?
+ 1.0f - BKE_defvert_find_weight(dvert, data->defgrp_index) :
+ BKE_defvert_find_weight(dvert, data->defgrp_index);
+ if (weight > 0.0f) {
+ BKE_lattice_deform_data_eval_co(
+ data->lattice_deform_data, data->vert_coords[index], weight * data->fac);
+ }
+ }
+ else {
+ BKE_lattice_deform_data_eval_co(
+ data->lattice_deform_data, data->vert_coords[index], data->fac);
+ }
+}
+
+static void lattice_deform_vert_task(void *__restrict userdata,
+ const int index,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ const LatticeDeformUserdata *data = userdata;
+ lattice_deform_vert_with_dvert(data, index, data->dvert ? &data->dvert[index] : NULL);
+}
+
+static void lattice_vert_task_editmesh(void *__restrict userdata, MempoolIterData *iter)
+{
+ const LatticeDeformUserdata *data = userdata;
+ BMVert *v = (BMVert *)iter;
+ MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(v, data->bmesh.cd_dvert_offset);
+ lattice_deform_vert_with_dvert(data, BM_elem_index_get(v), dvert);
+}
+
+static void lattice_vert_task_editmesh_no_dvert(void *__restrict userdata, MempoolIterData *iter)
+{
+ const LatticeDeformUserdata *data = userdata;
+ BMVert *v = (BMVert *)iter;
+ lattice_deform_vert_with_dvert(data, BM_elem_index_get(v), NULL);
+}
+
+static void lattice_deform_coords_impl(const Object *ob_lattice,
+ const Object *ob_target,
+ float (*vert_coords)[3],
+ const int vert_coords_len,
+ const short flag,
+ const char *defgrp_name,
+ const float fac,
+ const Mesh *me_target,
+ BMEditMesh *em_target)
+{
+ LatticeDeformData *lattice_deform_data;
+ const MDeformVert *dvert = NULL;
+ int defgrp_index = -1;
+ int cd_dvert_offset = -1;
+
+ if (ob_lattice->type != OB_LATTICE) {
+ return;
+ }
+
+ lattice_deform_data = BKE_lattice_deform_data_create(ob_lattice, ob_target);
+
+ /* Check whether to use vertex groups (only possible if ob_target is a Mesh or Lattice).
+ * We want either a Mesh/Lattice with no derived data, or derived data with deformverts.
+ */
+ if (defgrp_name && defgrp_name[0] && ob_target && ELEM(ob_target->type, OB_MESH, OB_LATTICE)) {
+ defgrp_index = BKE_object_defgroup_name_index(ob_target, defgrp_name);
+
+ if (defgrp_index != -1) {
+ /* if there's derived data without deformverts, don't use vgroups */
+ if (em_target) {
+ cd_dvert_offset = CustomData_get_offset(&em_target->bm->vdata, CD_MDEFORMVERT);
+ }
+ else if (me_target) {
+ dvert = CustomData_get_layer(&me_target->vdata, CD_MDEFORMVERT);
+ }
+ else if (ob_target->type == OB_LATTICE) {
+ dvert = ((Lattice *)ob_target->data)->dvert;
+ }
+ else {
+ dvert = ((Mesh *)ob_target->data)->dvert;
+ }
+ }
+ }
+
+ LatticeDeformUserdata data = {
+ .lattice_deform_data = lattice_deform_data,
+ .vert_coords = vert_coords,
+ .dvert = dvert,
+ .defgrp_index = defgrp_index,
+ .fac = fac,
+ .invert_vgroup = (flag & MOD_LATTICE_INVERT_VGROUP) != 0,
+ .bmesh =
+ {
+ .cd_dvert_offset = cd_dvert_offset,
+ },
+ };
+
+ if (em_target != NULL) {
+ /* While this could cause an extra loop over mesh data, in most cases this will
+ * have already been properly set. */
+ BM_mesh_elem_index_ensure(em_target->bm, BM_VERT);
+
+ if (cd_dvert_offset != -1) {
+ BLI_task_parallel_mempool(em_target->bm->vpool, &data, lattice_vert_task_editmesh, true);
+ }
+ else {
+ BLI_task_parallel_mempool(
+ em_target->bm->vpool, &data, lattice_vert_task_editmesh_no_dvert, true);
+ }
+ }
+ else {
+ TaskParallelSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.min_iter_per_thread = 32;
+ BLI_task_parallel_range(0, vert_coords_len, &data, lattice_deform_vert_task, &settings);
+ }
+
+ BKE_lattice_deform_data_destroy(lattice_deform_data);
+}
+
+void BKE_lattice_deform_coords(const Object *ob_lattice,
+ const Object *ob_target,
+ float (*vert_coords)[3],
+ const int vert_coords_len,
+ const short flag,
+ const char *defgrp_name,
+ float fac)
+{
+ lattice_deform_coords_impl(
+ ob_lattice, ob_target, vert_coords, vert_coords_len, flag, defgrp_name, fac, NULL, NULL);
+}
+
+void BKE_lattice_deform_coords_with_mesh(const Object *ob_lattice,
+ const Object *ob_target,
+ float (*vert_coords)[3],
+ const int vert_coords_len,
+ const short flag,
+ const char *defgrp_name,
+ const float fac,
+ const Mesh *me_target)
+{
+ lattice_deform_coords_impl(ob_lattice,
+ ob_target,
+ vert_coords,
+ vert_coords_len,
+ flag,
+ defgrp_name,
+ fac,
+ me_target,
+ NULL);
+}
+
+void BKE_lattice_deform_coords_with_editmesh(const struct Object *ob_lattice,
+ const struct Object *ob_target,
+ float (*vert_coords)[3],
+ const int vert_coords_len,
+ const short flag,
+ const char *defgrp_name,
+ const float influence,
+ struct BMEditMesh *em_target)
+{
+ lattice_deform_coords_impl(ob_lattice,
+ ob_target,
+ vert_coords,
+ vert_coords_len,
+ flag,
+ defgrp_name,
+ influence,
+ NULL,
+ em_target);
+}
+
+/** \} */