From 16595b9ea1c5c5b6f3d07a31d3aa6b4713426abc Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 12 Jun 2020 15:12:54 +1000 Subject: Cleanup: split object data deform functions into their own files Move armature/curve functions into their headers, they were previously in BKE_lattice.h --- source/blender/blenkernel/BKE_armature.h | 31 + source/blender/blenkernel/BKE_curve.h | 35 +- source/blender/blenkernel/BKE_lattice.h | 95 +-- source/blender/blenkernel/CMakeLists.txt | 3 + source/blender/blenkernel/intern/armature.c | 562 ----------------- source/blender/blenkernel/intern/armature_deform.c | 608 ++++++++++++++++++ source/blender/blenkernel/intern/curve.c | 3 - source/blender/blenkernel/intern/curve_deform.c | 398 ++++++++++++ source/blender/blenkernel/intern/lattice.c | 693 --------------------- source/blender/blenkernel/intern/lattice_deform.c | 389 ++++++++++++ .../gpencil_modifiers/intern/MOD_gpencilarmature.c | 2 +- source/blender/modifiers/intern/MOD_armature.c | 2 +- source/blender/modifiers/intern/MOD_curve.c | 2 +- 13 files changed, 1491 insertions(+), 1332 deletions(-) create mode 100644 source/blender/blenkernel/intern/armature_deform.c create mode 100644 source/blender/blenkernel/intern/curve_deform.c create mode 100644 source/blender/blenkernel/intern/lattice_deform.c (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index c22e7a24afe..30a1644af39 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -32,11 +32,13 @@ struct Bone; struct Depsgraph; struct ListBase; struct Main; +struct Mesh; struct Object; struct PoseTree; struct Scene; struct bArmature; struct bConstraint; +struct bGPDstroke; struct bPose; struct bPoseChannel; @@ -342,6 +344,35 @@ void BKE_pose_eval_proxy_copy_bone(struct Depsgraph *depsgraph, struct Object *object, int pchan_index); +/* -------------------------------------------------------------------- */ +/** \name Deform 3D Coordinates by Armature (armature_deform.c) + * \{ */ + +/* Note that we could have a 'BKE_armature_deform_coords' that doesn't take object data + * currently there are no callers for this though. */ + +void BKE_armature_deform_coords_with_gpencil_stroke(struct Object *ob_arm, + struct Object *ob_target, + float (*vert_coords)[3], + float (*vert_deform_mats)[3][3], + int vert_coords_len, + int deformflag, + float (*vert_coords_prev)[3], + const char *defgrp_name, + struct bGPDstroke *gps_target); + +void BKE_armature_deform_coords_with_mesh(struct Object *ob_arm, + struct Object *ob_target, + float (*vert_coords)[3], + float (*vert_deform_mats)[3][3], + int vert_coords_len, + int deformflag, + float (*vert_coords_prev)[3], + const char *defgrp_name, + const struct Mesh *me_target); + +/** \} */ + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h index 40f73ccfe84..417dbd49855 100644 --- a/source/blender/blenkernel/BKE_curve.h +++ b/source/blender/blenkernel/BKE_curve.h @@ -34,6 +34,7 @@ struct Curve; struct Depsgraph; struct GHash; struct ListBase; +struct MDeformVert; struct Main; struct Nurb; struct Object; @@ -278,7 +279,15 @@ enum { void BKE_curve_batch_cache_dirty_tag(struct Curve *cu, int mode); void BKE_curve_batch_cache_free(struct Curve *cu); -/* curve_decimate.c */ +extern void (*BKE_curve_batch_cache_dirty_tag_cb)(struct Curve *cu, int mode); +extern void (*BKE_curve_batch_cache_free_cb)(struct Curve *cu); + +/* -------------------------------------------------------------------- */ +/** \name Decimate Curve (curve_decimate.c) + * + * Simplify curve data. + * \{ */ + unsigned int BKE_curve_decimate_bezt_array(struct BezTriple *bezt_array, const unsigned int bezt_array_len, const unsigned int resolu, @@ -293,8 +302,28 @@ void BKE_curve_decimate_nurb(struct Nurb *nu, const float error_sq_max, const unsigned int error_target_len); -extern void (*BKE_curve_batch_cache_dirty_tag_cb)(struct Curve *cu, int mode); -extern void (*BKE_curve_batch_cache_free_cb)(struct Curve *cu); +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Deform 3D Coordinates by Curve (curve_deform.c) + * \{ */ + +void BKE_curve_deform_coords(struct Object *ob_curve, + struct Object *ob_target, + float (*vert_coords)[3], + const int vert_coords_len, + const struct MDeformVert *dvert, + const int defgrp_index, + const short flag, + const short defaxis); +void BKE_curve_deform_co(struct Object *ob_curve, + struct Object *ob_target, + const float orco[3], + float vec[3], + float mat[3][3], + const int no_rot_axis); + +/** \} */ #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h index 19cb4f5c4e1..922f7278034 100644 --- a/source/blender/blenkernel/BKE_lattice.h +++ b/source/blender/blenkernel/BKE_lattice.h @@ -45,77 +45,9 @@ struct Lattice *BKE_lattice_add(struct Main *bmain, const char *name); struct Lattice *BKE_lattice_copy(struct Main *bmain, const struct Lattice *lt); void calc_lat_fudu(int flag, int res, float *r_fu, float *r_du); -struct LatticeDeformData *init_latt_deform(struct Object *oblatt, - struct Object *ob) ATTR_WARN_UNUSED_RESULT; -void calc_latt_deform(struct LatticeDeformData *lattice_deform_data, float co[3], float weight); -void end_latt_deform(struct LatticeDeformData *lattice_deform_data); - bool object_deform_mball(struct Object *ob, struct ListBase *dispbase); void outside_lattice(struct Lattice *lt); -/* -------------------------------------------------------------------- */ -/** \name Deform 3D Coordinates by Object Data - * - * Used by modifiers (odd location for this API, for now keep these related functions together). - * \{ */ - -void BKE_curve_deform_coords(struct Object *ob_curve, - struct Object *ob_target, - float (*vert_coords)[3], - const int vert_coords_len, - const struct MDeformVert *dvert, - const int defgrp_index, - const short flag, - const short defaxis); -void BKE_curve_deform_co(struct Object *ob_curve, - struct Object *ob_target, - const float orco[3], - float vec[3], - float mat[3][3], - const int no_rot_axis); - -void BKE_lattice_deform_coords(struct Object *ob_lattice, - struct Object *ob_target, - float (*vert_coords)[3], - const int vert_coords_len, - const short flag, - const char *defgrp_name, - float influence); - -void BKE_lattice_deform_coords_with_mesh(struct Object *ob_lattice, - struct Object *ob_target, - float (*vert_coords)[3], - const int vert_coords_len, - const short flag, - const char *defgrp_name, - const float influence, - const struct Mesh *me_target); - -/* Note that we could have a 'BKE_armature_deform_coords' that doesn't take object data - * currently there are no callers for this though. */ - -void BKE_armature_deform_coords_with_gpencil_stroke(struct Object *ob_arm, - struct Object *ob_target, - float (*vert_coords)[3], - float (*vert_deform_mats)[3][3], - int vert_coords_len, - int deformflag, - float (*vert_coords_prev)[3], - const char *defgrp_name, - struct bGPDstroke *gps_target); - -void BKE_armature_deform_coords_with_mesh(struct Object *ob_arm, - struct Object *ob_target, - float (*vert_coords)[3], - float (*vert_deform_mats)[3][3], - int vert_coords_len, - int deformflag, - float (*vert_coords_prev)[3], - const char *defgrp_name, - const struct Mesh *me_target); - -/** \} */ - float (*BKE_lattice_vert_coords_alloc(const struct Lattice *lt, int *r_vert_len))[3]; void BKE_lattice_vert_coords_get(const struct Lattice *lt, float (*vert_coords)[3]); void BKE_lattice_vert_coords_apply_with_mat4(struct Lattice *lt, @@ -166,6 +98,33 @@ void BKE_lattice_batch_cache_free(struct Lattice *lt); extern void (*BKE_lattice_batch_cache_dirty_tag_cb)(struct Lattice *lt, int mode); extern void (*BKE_lattice_batch_cache_free_cb)(struct Lattice *lt); +/* -------------------------------------------------------------------- */ +/** \name Deform 3D Coordinates by Lattice (lattice_deform.c) + * \{ */ + +struct LatticeDeformData *init_latt_deform(struct Object *oblatt, + struct Object *ob) ATTR_WARN_UNUSED_RESULT; +void calc_latt_deform(struct LatticeDeformData *lattice_deform_data, float co[3], float weight); +void end_latt_deform(struct LatticeDeformData *lattice_deform_data); + +void BKE_lattice_deform_coords(struct Object *ob_lattice, + struct Object *ob_target, + float (*vert_coords)[3], + const int vert_coords_len, + const short flag, + const char *defgrp_name, + float influence); + +void BKE_lattice_deform_coords_with_mesh(struct Object *ob_lattice, + struct Object *ob_target, + float (*vert_coords)[3], + const int vert_coords_len, + const short flag, + const char *defgrp_name, + const float influence, + const struct Mesh *me_target); +/** \} */ + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index c1a548360af..b9054d29752 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -74,6 +74,7 @@ set(SRC intern/anim_visualization.c intern/appdir.c intern/armature.c + intern/armature_deform.c intern/armature_update.c intern/autoexec.c intern/blender.c @@ -99,6 +100,7 @@ set(SRC intern/crazyspace.c intern/curve.c intern/curve_decimate.c + intern/curve_deform.c intern/curveprofile.c intern/customdata.c intern/customdata_file.c @@ -138,6 +140,7 @@ set(SRC intern/key.c intern/keyconfig.c intern/lattice.c + intern/lattice_deform.c intern/layer.c intern/layer_utils.c intern/lib_id.c diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index d2ba3434f2a..007062abb5b 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -35,18 +35,12 @@ #include "BLI_listbase.h" #include "BLI_math.h" #include "BLI_string.h" -#include "BLI_task.h" #include "BLI_utildefines.h" #include "BLT_translation.h" -#include "DNA_anim_types.h" #include "DNA_armature_types.h" #include "DNA_constraint_types.h" -#include "DNA_gpencil_types.h" -#include "DNA_lattice_types.h" #include "DNA_listBase.h" -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -55,11 +49,8 @@ #include "BKE_armature.h" #include "BKE_constraint.h" #include "BKE_curve.h" -#include "BKE_deform.h" -#include "BKE_displist.h" #include "BKE_idprop.h" #include "BKE_idtype.h" -#include "BKE_lattice.h" #include "BKE_lib_id.h" #include "BKE_lib_query.h" #include "BKE_main.h" @@ -71,8 +62,6 @@ #include "BIK_api.h" -#include "atomic_ops.h" - #include "CLG_log.h" static CLG_LogRef LOG = {"bke.armature"}; @@ -1385,557 +1374,6 @@ void BKE_pchan_bbone_deform_segment_index(const bPoseChannel *pchan, /** \} */ -/* -------------------------------------------------------------------- */ -/** \name Armature Deform Internal Utilities - * \{ */ - -/* Add the effect of one bone or B-Bone segment to the accumulated result. */ -static void pchan_deform_accumulate(const DualQuat *deform_dq, - const float deform_mat[4][4], - const float co_in[3], - float weight, - float co_accum[3], - DualQuat *dq_accum, - float mat_accum[3][3]) -{ - if (weight == 0.0f) { - return; - } - - if (dq_accum) { - BLI_assert(!co_accum); - - add_weighted_dq_dq(dq_accum, deform_dq, weight); - } - else { - float tmp[3]; - mul_v3_m4v3(tmp, deform_mat, co_in); - - sub_v3_v3(tmp, co_in); - madd_v3_v3fl(co_accum, tmp, weight); - - if (mat_accum) { - float tmpmat[3][3]; - copy_m3_m4(tmpmat, deform_mat); - - madd_m3_m3m3fl(mat_accum, mat_accum, tmpmat, weight); - } - } -} - -static void b_bone_deform(const bPoseChannel *pchan, - const float co[3], - float weight, - float vec[3], - DualQuat *dq, - float defmat[3][3]) -{ - const DualQuat *quats = pchan->runtime.bbone_dual_quats; - const Mat4 *mats = pchan->runtime.bbone_deform_mats; - const float(*mat)[4] = mats[0].mat; - float blend, y; - int index; - - /* Transform co to bone space and get its y component. */ - y = mat[0][1] * co[0] + mat[1][1] * co[1] + mat[2][1] * co[2] + mat[3][1]; - - /* Calculate the indices of the 2 affecting b_bone segments. */ - BKE_pchan_bbone_deform_segment_index(pchan, y / pchan->bone->length, &index, &blend); - - pchan_deform_accumulate( - &quats[index], mats[index + 1].mat, co, weight * (1.0f - blend), vec, dq, defmat); - pchan_deform_accumulate( - &quats[index + 1], mats[index + 2].mat, co, weight * blend, vec, dq, defmat); -} - -/* using vec with dist to bone b1 - b2 */ -float distfactor_to_bone( - const float vec[3], const float b1[3], const float b2[3], float rad1, float rad2, float rdist) -{ - float dist_sq; - float bdelta[3]; - float pdelta[3]; - float hsqr, a, l, rad; - - sub_v3_v3v3(bdelta, b2, b1); - l = normalize_v3(bdelta); - - sub_v3_v3v3(pdelta, vec, b1); - - a = dot_v3v3(bdelta, pdelta); - hsqr = len_squared_v3(pdelta); - - if (a < 0.0f) { - /* If we're past the end of the bone, do a spherical field attenuation thing */ - dist_sq = len_squared_v3v3(b1, vec); - rad = rad1; - } - else if (a > l) { - /* If we're past the end of the bone, do a spherical field attenuation thing */ - dist_sq = len_squared_v3v3(b2, vec); - rad = rad2; - } - else { - dist_sq = (hsqr - (a * a)); - - if (l != 0.0f) { - rad = a / l; - rad = rad * rad2 + (1.0f - rad) * rad1; - } - else { - rad = rad1; - } - } - - a = rad * rad; - if (dist_sq < a) { - return 1.0f; - } - else { - l = rad + rdist; - l *= l; - if (rdist == 0.0f || dist_sq >= l) { - return 0.0f; - } - else { - a = sqrtf(dist_sq) - rad; - return 1.0f - (a * a) / (rdist * rdist); - } - } -} - -static float dist_bone_deform( - bPoseChannel *pchan, float vec[3], DualQuat *dq, float mat[3][3], const float co[3]) -{ - Bone *bone = pchan->bone; - float fac, contrib = 0.0; - - if (bone == NULL) { - return 0.0f; - } - - fac = distfactor_to_bone( - co, bone->arm_head, bone->arm_tail, bone->rad_head, bone->rad_tail, bone->dist); - - if (fac > 0.0f) { - fac *= bone->weight; - contrib = fac; - if (contrib > 0.0f) { - if (bone->segments > 1 && pchan->runtime.bbone_segments == bone->segments) { - b_bone_deform(pchan, co, fac, vec, dq, mat); - } - else { - pchan_deform_accumulate( - &pchan->runtime.deform_dual_quat, pchan->chan_mat, co, fac, vec, dq, mat); - } - } - } - - return contrib; -} - -static void pchan_bone_deform(bPoseChannel *pchan, - float weight, - float vec[3], - DualQuat *dq, - float mat[3][3], - const float co[3], - float *contrib) -{ - Bone *bone = pchan->bone; - - if (!weight) { - return; - } - - if (bone->segments > 1 && pchan->runtime.bbone_segments == bone->segments) { - b_bone_deform(pchan, co, weight, vec, dq, mat); - } - else { - pchan_deform_accumulate( - &pchan->runtime.deform_dual_quat, pchan->chan_mat, co, weight, vec, dq, mat); - } - - (*contrib) += weight; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Armature Deform #BKE_armature_deform_coords API - * - * #BKE_armature_deform_coords and related functions. - * \{ */ - -typedef struct ArmatureUserdata { - Object *ob_arm; - Object *ob_target; - const Mesh *me_target; - float (*vert_coords)[3]; - float (*vert_deform_mats)[3][3]; - float (*vert_coords_prev)[3]; - - bool use_envelope; - bool use_quaternion; - bool invert_vgroup; - bool use_dverts; - - int armature_def_nr; - - const MDeformVert *dverts; - int dverts_len; - - bPoseChannel **pchan_from_defbase; - int defbase_len; - - float premat[4][4]; - float postmat[4][4]; -} ArmatureUserdata; - -static void armature_vert_task(void *__restrict userdata, - const int i, - const TaskParallelTLS *__restrict UNUSED(tls)) -{ - const ArmatureUserdata *data = userdata; - float(*const vert_coords)[3] = data->vert_coords; - float(*const vert_deform_mats)[3][3] = data->vert_deform_mats; - float(*const vert_coords_prev)[3] = data->vert_coords_prev; - const bool use_envelope = data->use_envelope; - const bool use_quaternion = data->use_quaternion; - const bool use_dverts = data->use_dverts; - const int armature_def_nr = data->armature_def_nr; - - const MDeformVert *dvert; - DualQuat sumdq, *dq = NULL; - bPoseChannel *pchan; - float *co, dco[3]; - float sumvec[3], summat[3][3]; - float *vec = NULL, (*smat)[3] = NULL; - float contrib = 0.0f; - float armature_weight = 1.0f; /* default to 1 if no overall def group */ - float prevco_weight = 1.0f; /* weight for optional cached vertexcos */ - - if (use_quaternion) { - memset(&sumdq, 0, sizeof(DualQuat)); - dq = &sumdq; - } - else { - zero_v3(sumvec); - vec = sumvec; - - if (vert_deform_mats) { - zero_m3(summat); - smat = summat; - } - } - - if (use_dverts || armature_def_nr != -1) { - if (data->me_target) { - BLI_assert(i < data->me_target->totvert); - if (data->me_target->dvert != NULL) { - dvert = data->me_target->dvert + i; - } - else { - dvert = NULL; - } - } - else if (data->dverts && i < data->dverts_len) { - dvert = data->dverts + i; - } - else { - dvert = NULL; - } - } - else { - dvert = NULL; - } - - if (armature_def_nr != -1 && dvert) { - armature_weight = BKE_defvert_find_weight(dvert, armature_def_nr); - - if (data->invert_vgroup) { - armature_weight = 1.0f - armature_weight; - } - - /* hackish: the blending factor can be used for blending with vert_coords_prev too */ - if (vert_coords_prev) { - prevco_weight = armature_weight; - armature_weight = 1.0f; - } - } - - /* check if there's any point in calculating for this vert */ - if (armature_weight == 0.0f) { - return; - } - - /* get the coord we work on */ - co = vert_coords_prev ? vert_coords_prev[i] : vert_coords[i]; - - /* Apply the object's matrix */ - mul_m4_v3(data->premat, co); - - if (use_dverts && dvert && dvert->totweight) { /* use weight groups ? */ - const MDeformWeight *dw = dvert->dw; - int deformed = 0; - unsigned int j; - for (j = dvert->totweight; j != 0; j--, dw++) { - const uint index = dw->def_nr; - if (index < data->defbase_len && (pchan = data->pchan_from_defbase[index])) { - float weight = dw->weight; - Bone *bone = pchan->bone; - - deformed = 1; - - if (bone && bone->flag & BONE_MULT_VG_ENV) { - weight *= distfactor_to_bone( - co, bone->arm_head, bone->arm_tail, bone->rad_head, bone->rad_tail, bone->dist); - } - - pchan_bone_deform(pchan, weight, vec, dq, smat, co, &contrib); - } - } - /* if there are vertexgroups but not groups with bones - * (like for softbody groups) */ - if (deformed == 0 && use_envelope) { - for (pchan = data->ob_arm->pose->chanbase.first; pchan; pchan = pchan->next) { - if (!(pchan->bone->flag & BONE_NO_DEFORM)) { - contrib += dist_bone_deform(pchan, vec, dq, smat, co); - } - } - } - } - else if (use_envelope) { - for (pchan = data->ob_arm->pose->chanbase.first; pchan; pchan = pchan->next) { - if (!(pchan->bone->flag & BONE_NO_DEFORM)) { - contrib += dist_bone_deform(pchan, vec, dq, smat, co); - } - } - } - - /* actually should be EPSILON? weight values and contrib can be like 10e-39 small */ - if (contrib > 0.0001f) { - if (use_quaternion) { - normalize_dq(dq, contrib); - - if (armature_weight != 1.0f) { - copy_v3_v3(dco, co); - mul_v3m3_dq(dco, (vert_deform_mats) ? summat : NULL, dq); - sub_v3_v3(dco, co); - mul_v3_fl(dco, armature_weight); - add_v3_v3(co, dco); - } - else { - mul_v3m3_dq(co, (vert_deform_mats) ? summat : NULL, dq); - } - - smat = summat; - } - else { - mul_v3_fl(vec, armature_weight / contrib); - add_v3_v3v3(co, vec, co); - } - - if (vert_deform_mats) { - float pre[3][3], post[3][3], tmpmat[3][3]; - - copy_m3_m4(pre, data->premat); - copy_m3_m4(post, data->postmat); - copy_m3_m3(tmpmat, vert_deform_mats[i]); - - if (!use_quaternion) { /* quaternion already is scale corrected */ - mul_m3_fl(smat, armature_weight / contrib); - } - - mul_m3_series(vert_deform_mats[i], post, smat, pre, tmpmat); - } - } - - /* always, check above code */ - mul_m4_v3(data->postmat, co); - - /* interpolate with previous modifier position using weight group */ - if (vert_coords_prev) { - float mw = 1.0f - prevco_weight; - vert_coords[i][0] = prevco_weight * vert_coords[i][0] + mw * co[0]; - vert_coords[i][1] = prevco_weight * vert_coords[i][1] + mw * co[1]; - vert_coords[i][2] = prevco_weight * vert_coords[i][2] + mw * co[2]; - } -} - -static void armature_deform_coords_impl(Object *ob_arm, - Object *ob_target, - float (*vert_coords)[3], - float (*vert_deform_mats)[3][3], - const int vert_coords_len, - const int deformflag, - float (*vert_coords_prev)[3], - const char *defgrp_name, - const Mesh *me_target, - bGPDstroke *gps_target) -{ - bArmature *arm = ob_arm->data; - bPoseChannel **pchan_from_defbase = NULL; - const MDeformVert *dverts = NULL; - bDeformGroup *dg; - const bool use_envelope = (deformflag & ARM_DEF_ENVELOPE) != 0; - const bool use_quaternion = (deformflag & ARM_DEF_QUATERNION) != 0; - const bool invert_vgroup = (deformflag & ARM_DEF_INVERT_VGROUP) != 0; - int defbase_len = 0; /* safety for vertexgroup index overflow */ - int i, dverts_len = 0; /* safety for vertexgroup overflow */ - bool use_dverts = false; - int armature_def_nr; - - /* in editmode, or not an armature */ - if (arm->edbo || (ob_arm->pose == NULL)) { - return; - } - - if ((ob_arm->pose->flag & POSE_RECALC) != 0) { - CLOG_ERROR(&LOG, - "Trying to evaluate influence of armature '%s' which needs Pose recalc!", - ob_arm->id.name); - BLI_assert(0); - } - - /* get the def_nr for the overall armature vertex group if present */ - armature_def_nr = BKE_object_defgroup_name_index(ob_target, defgrp_name); - - if (ELEM(ob_target->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) { - defbase_len = BLI_listbase_count(&ob_target->defbase); - - if (ob_target->type == OB_MESH) { - Mesh *me = ob_target->data; - dverts = me->dvert; - if (dverts) { - dverts_len = me->totvert; - } - } - else if (ob_target->type == OB_LATTICE) { - Lattice *lt = ob_target->data; - dverts = lt->dvert; - if (dverts) { - dverts_len = lt->pntsu * lt->pntsv * lt->pntsw; - } - } - else if (ob_target->type == OB_GPENCIL) { - dverts = gps_target->dvert; - if (dverts) { - dverts_len = gps_target->totpoints; - } - } - } - - /* get a vertex-deform-index to posechannel array */ - if (deformflag & ARM_DEF_VGROUP) { - if (ELEM(ob_target->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) { - /* if we have a Mesh, only use dverts if it has them */ - if (me_target) { - use_dverts = (me_target->dvert != NULL); - } - else if (dverts) { - use_dverts = true; - } - - if (use_dverts) { - pchan_from_defbase = MEM_callocN(sizeof(*pchan_from_defbase) * defbase_len, "defnrToBone"); - /* TODO(sergey): Some considerations here: - * - * - Check whether keeping this consistent across frames gives speedup. - */ - for (i = 0, dg = ob_target->defbase.first; dg; i++, dg = dg->next) { - pchan_from_defbase[i] = BKE_pose_channel_find_name(ob_arm->pose, dg->name); - /* exclude non-deforming bones */ - if (pchan_from_defbase[i]) { - if (pchan_from_defbase[i]->bone->flag & BONE_NO_DEFORM) { - pchan_from_defbase[i] = NULL; - } - } - } - } - } - } - - ArmatureUserdata data = { - .ob_arm = ob_arm, - .ob_target = ob_target, - .me_target = me_target, - .vert_coords = vert_coords, - .vert_deform_mats = vert_deform_mats, - .vert_coords_prev = vert_coords_prev, - .use_envelope = use_envelope, - .use_quaternion = use_quaternion, - .invert_vgroup = invert_vgroup, - .use_dverts = use_dverts, - .armature_def_nr = armature_def_nr, - .dverts = dverts, - .dverts_len = dverts_len, - .pchan_from_defbase = pchan_from_defbase, - .defbase_len = defbase_len, - }; - - float obinv[4][4]; - invert_m4_m4(obinv, ob_target->obmat); - - mul_m4_m4m4(data.postmat, obinv, ob_arm->obmat); - invert_m4_m4(data.premat, data.postmat); - - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.min_iter_per_thread = 32; - BLI_task_parallel_range(0, vert_coords_len, &data, armature_vert_task, &settings); - - if (pchan_from_defbase) { - MEM_freeN(pchan_from_defbase); - } -} - -void BKE_armature_deform_coords_with_gpencil_stroke(Object *ob_arm, - Object *ob_target, - float (*vert_coords)[3], - float (*vert_deform_mats)[3][3], - int vert_coords_len, - int deformflag, - float (*vert_coords_prev)[3], - const char *defgrp_name, - bGPDstroke *gps_target) -{ - armature_deform_coords_impl(ob_arm, - ob_target, - vert_coords, - vert_deform_mats, - vert_coords_len, - deformflag, - vert_coords_prev, - defgrp_name, - NULL, - gps_target); -} - -void BKE_armature_deform_coords_with_mesh(Object *ob_arm, - Object *ob_target, - float (*vert_coords)[3], - float (*vert_deform_mats)[3][3], - int vert_coords_len, - int deformflag, - float (*vert_coords_prev)[3], - const char *defgrp_name, - const Mesh *me_target) -{ - armature_deform_coords_impl(ob_arm, - ob_target, - vert_coords, - vert_deform_mats, - vert_coords_len, - deformflag, - vert_coords_prev, - defgrp_name, - me_target, - NULL); -} - -/** \} */ - /* -------------------------------------------------------------------- */ /** \name Bone Space to Space Conversion API * \{ */ diff --git a/source/blender/blenkernel/intern/armature_deform.c b/source/blender/blenkernel/intern/armature_deform.c new file mode 100644 index 00000000000..cee487e2244 --- /dev/null +++ b/source/blender/blenkernel/intern/armature_deform.c @@ -0,0 +1,608 @@ +/* + * 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 armature object (used by modifier). + */ + +#include +#include +#include +#include +#include +#include + +#include "MEM_guardedalloc.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_task.h" +#include "BLI_utildefines.h" + +#include "DNA_armature_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_lattice_types.h" +#include "DNA_listBase.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" + +#include "BKE_action.h" +#include "BKE_armature.h" +#include "BKE_deform.h" +#include "BKE_lattice.h" + +#include "DEG_depsgraph_build.h" + +#include "CLG_log.h" + +static CLG_LogRef LOG = {"bke.armature_deform"}; + +/* -------------------------------------------------------------------- */ +/** \name Armature Deform Internal Utilities + * \{ */ + +/* Add the effect of one bone or B-Bone segment to the accumulated result. */ +static void pchan_deform_accumulate(const DualQuat *deform_dq, + const float deform_mat[4][4], + const float co_in[3], + float weight, + float co_accum[3], + DualQuat *dq_accum, + float mat_accum[3][3]) +{ + if (weight == 0.0f) { + return; + } + + if (dq_accum) { + BLI_assert(!co_accum); + + add_weighted_dq_dq(dq_accum, deform_dq, weight); + } + else { + float tmp[3]; + mul_v3_m4v3(tmp, deform_mat, co_in); + + sub_v3_v3(tmp, co_in); + madd_v3_v3fl(co_accum, tmp, weight); + + if (mat_accum) { + float tmpmat[3][3]; + copy_m3_m4(tmpmat, deform_mat); + + madd_m3_m3m3fl(mat_accum, mat_accum, tmpmat, weight); + } + } +} + +static void b_bone_deform(const bPoseChannel *pchan, + const float co[3], + float weight, + float vec[3], + DualQuat *dq, + float defmat[3][3]) +{ + const DualQuat *quats = pchan->runtime.bbone_dual_quats; + const Mat4 *mats = pchan->runtime.bbone_deform_mats; + const float(*mat)[4] = mats[0].mat; + float blend, y; + int index; + + /* Transform co to bone space and get its y component. */ + y = mat[0][1] * co[0] + mat[1][1] * co[1] + mat[2][1] * co[2] + mat[3][1]; + + /* Calculate the indices of the 2 affecting b_bone segments. */ + BKE_pchan_bbone_deform_segment_index(pchan, y / pchan->bone->length, &index, &blend); + + pchan_deform_accumulate( + &quats[index], mats[index + 1].mat, co, weight * (1.0f - blend), vec, dq, defmat); + pchan_deform_accumulate( + &quats[index + 1], mats[index + 2].mat, co, weight * blend, vec, dq, defmat); +} + +/* using vec with dist to bone b1 - b2 */ +float distfactor_to_bone( + const float vec[3], const float b1[3], const float b2[3], float rad1, float rad2, float rdist) +{ + float dist_sq; + float bdelta[3]; + float pdelta[3]; + float hsqr, a, l, rad; + + sub_v3_v3v3(bdelta, b2, b1); + l = normalize_v3(bdelta); + + sub_v3_v3v3(pdelta, vec, b1); + + a = dot_v3v3(bdelta, pdelta); + hsqr = len_squared_v3(pdelta); + + if (a < 0.0f) { + /* If we're past the end of the bone, do a spherical field attenuation thing */ + dist_sq = len_squared_v3v3(b1, vec); + rad = rad1; + } + else if (a > l) { + /* If we're past the end of the bone, do a spherical field attenuation thing */ + dist_sq = len_squared_v3v3(b2, vec); + rad = rad2; + } + else { + dist_sq = (hsqr - (a * a)); + + if (l != 0.0f) { + rad = a / l; + rad = rad * rad2 + (1.0f - rad) * rad1; + } + else { + rad = rad1; + } + } + + a = rad * rad; + if (dist_sq < a) { + return 1.0f; + } + else { + l = rad + rdist; + l *= l; + if (rdist == 0.0f || dist_sq >= l) { + return 0.0f; + } + else { + a = sqrtf(dist_sq) - rad; + return 1.0f - (a * a) / (rdist * rdist); + } + } +} + +static float dist_bone_deform( + bPoseChannel *pchan, float vec[3], DualQuat *dq, float mat[3][3], const float co[3]) +{ + Bone *bone = pchan->bone; + float fac, contrib = 0.0; + + if (bone == NULL) { + return 0.0f; + } + + fac = distfactor_to_bone( + co, bone->arm_head, bone->arm_tail, bone->rad_head, bone->rad_tail, bone->dist); + + if (fac > 0.0f) { + fac *= bone->weight; + contrib = fac; + if (contrib > 0.0f) { + if (bone->segments > 1 && pchan->runtime.bbone_segments == bone->segments) { + b_bone_deform(pchan, co, fac, vec, dq, mat); + } + else { + pchan_deform_accumulate( + &pchan->runtime.deform_dual_quat, pchan->chan_mat, co, fac, vec, dq, mat); + } + } + } + + return contrib; +} + +static void pchan_bone_deform(bPoseChannel *pchan, + float weight, + float vec[3], + DualQuat *dq, + float mat[3][3], + const float co[3], + float *contrib) +{ + Bone *bone = pchan->bone; + + if (!weight) { + return; + } + + if (bone->segments > 1 && pchan->runtime.bbone_segments == bone->segments) { + b_bone_deform(pchan, co, weight, vec, dq, mat); + } + else { + pchan_deform_accumulate( + &pchan->runtime.deform_dual_quat, pchan->chan_mat, co, weight, vec, dq, mat); + } + + (*contrib) += weight; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Armature Deform #BKE_armature_deform_coords API + * + * #BKE_armature_deform_coords and related functions. + * \{ */ + +typedef struct ArmatureUserdata { + Object *ob_arm; + Object *ob_target; + const Mesh *me_target; + float (*vert_coords)[3]; + float (*vert_deform_mats)[3][3]; + float (*vert_coords_prev)[3]; + + bool use_envelope; + bool use_quaternion; + bool invert_vgroup; + bool use_dverts; + + int armature_def_nr; + + const MDeformVert *dverts; + int dverts_len; + + bPoseChannel **pchan_from_defbase; + int defbase_len; + + float premat[4][4]; + float postmat[4][4]; +} ArmatureUserdata; + +static void armature_vert_task(void *__restrict userdata, + const int i, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + const ArmatureUserdata *data = userdata; + float(*const vert_coords)[3] = data->vert_coords; + float(*const vert_deform_mats)[3][3] = data->vert_deform_mats; + float(*const vert_coords_prev)[3] = data->vert_coords_prev; + const bool use_envelope = data->use_envelope; + const bool use_quaternion = data->use_quaternion; + const bool use_dverts = data->use_dverts; + const int armature_def_nr = data->armature_def_nr; + + const MDeformVert *dvert; + DualQuat sumdq, *dq = NULL; + bPoseChannel *pchan; + float *co, dco[3]; + float sumvec[3], summat[3][3]; + float *vec = NULL, (*smat)[3] = NULL; + float contrib = 0.0f; + float armature_weight = 1.0f; /* default to 1 if no overall def group */ + float prevco_weight = 1.0f; /* weight for optional cached vertexcos */ + + if (use_quaternion) { + memset(&sumdq, 0, sizeof(DualQuat)); + dq = &sumdq; + } + else { + zero_v3(sumvec); + vec = sumvec; + + if (vert_deform_mats) { + zero_m3(summat); + smat = summat; + } + } + + if (use_dverts || armature_def_nr != -1) { + if (data->me_target) { + BLI_assert(i < data->me_target->totvert); + if (data->me_target->dvert != NULL) { + dvert = data->me_target->dvert + i; + } + else { + dvert = NULL; + } + } + else if (data->dverts && i < data->dverts_len) { + dvert = data->dverts + i; + } + else { + dvert = NULL; + } + } + else { + dvert = NULL; + } + + if (armature_def_nr != -1 && dvert) { + armature_weight = BKE_defvert_find_weight(dvert, armature_def_nr); + + if (data->invert_vgroup) { + armature_weight = 1.0f - armature_weight; + } + + /* hackish: the blending factor can be used for blending with vert_coords_prev too */ + if (vert_coords_prev) { + prevco_weight = armature_weight; + armature_weight = 1.0f; + } + } + + /* check if there's any point in calculating for this vert */ + if (armature_weight == 0.0f) { + return; + } + + /* get the coord we work on */ + co = vert_coords_prev ? vert_coords_prev[i] : vert_coords[i]; + + /* Apply the object's matrix */ + mul_m4_v3(data->premat, co); + + if (use_dverts && dvert && dvert->totweight) { /* use weight groups ? */ + const MDeformWeight *dw = dvert->dw; + int deformed = 0; + unsigned int j; + for (j = dvert->totweight; j != 0; j--, dw++) { + const uint index = dw->def_nr; + if (index < data->defbase_len && (pchan = data->pchan_from_defbase[index])) { + float weight = dw->weight; + Bone *bone = pchan->bone; + + deformed = 1; + + if (bone && bone->flag & BONE_MULT_VG_ENV) { + weight *= distfactor_to_bone( + co, bone->arm_head, bone->arm_tail, bone->rad_head, bone->rad_tail, bone->dist); + } + + pchan_bone_deform(pchan, weight, vec, dq, smat, co, &contrib); + } + } + /* if there are vertexgroups but not groups with bones + * (like for softbody groups) */ + if (deformed == 0 && use_envelope) { + for (pchan = data->ob_arm->pose->chanbase.first; pchan; pchan = pchan->next) { + if (!(pchan->bone->flag & BONE_NO_DEFORM)) { + contrib += dist_bone_deform(pchan, vec, dq, smat, co); + } + } + } + } + else if (use_envelope) { + for (pchan = data->ob_arm->pose->chanbase.first; pchan; pchan = pchan->next) { + if (!(pchan->bone->flag & BONE_NO_DEFORM)) { + contrib += dist_bone_deform(pchan, vec, dq, smat, co); + } + } + } + + /* actually should be EPSILON? weight values and contrib can be like 10e-39 small */ + if (contrib > 0.0001f) { + if (use_quaternion) { + normalize_dq(dq, contrib); + + if (armature_weight != 1.0f) { + copy_v3_v3(dco, co); + mul_v3m3_dq(dco, (vert_deform_mats) ? summat : NULL, dq); + sub_v3_v3(dco, co); + mul_v3_fl(dco, armature_weight); + add_v3_v3(co, dco); + } + else { + mul_v3m3_dq(co, (vert_deform_mats) ? summat : NULL, dq); + } + + smat = summat; + } + else { + mul_v3_fl(vec, armature_weight / contrib); + add_v3_v3v3(co, vec, co); + } + + if (vert_deform_mats) { + float pre[3][3], post[3][3], tmpmat[3][3]; + + copy_m3_m4(pre, data->premat); + copy_m3_m4(post, data->postmat); + copy_m3_m3(tmpmat, vert_deform_mats[i]); + + if (!use_quaternion) { /* quaternion already is scale corrected */ + mul_m3_fl(smat, armature_weight / contrib); + } + + mul_m3_series(vert_deform_mats[i], post, smat, pre, tmpmat); + } + } + + /* always, check above code */ + mul_m4_v3(data->postmat, co); + + /* interpolate with previous modifier position using weight group */ + if (vert_coords_prev) { + float mw = 1.0f - prevco_weight; + vert_coords[i][0] = prevco_weight * vert_coords[i][0] + mw * co[0]; + vert_coords[i][1] = prevco_weight * vert_coords[i][1] + mw * co[1]; + vert_coords[i][2] = prevco_weight * vert_coords[i][2] + mw * co[2]; + } +} + +static void armature_deform_coords_impl(Object *ob_arm, + Object *ob_target, + float (*vert_coords)[3], + float (*vert_deform_mats)[3][3], + const int vert_coords_len, + const int deformflag, + float (*vert_coords_prev)[3], + const char *defgrp_name, + const Mesh *me_target, + bGPDstroke *gps_target) +{ + bArmature *arm = ob_arm->data; + bPoseChannel **pchan_from_defbase = NULL; + const MDeformVert *dverts = NULL; + bDeformGroup *dg; + const bool use_envelope = (deformflag & ARM_DEF_ENVELOPE) != 0; + const bool use_quaternion = (deformflag & ARM_DEF_QUATERNION) != 0; + const bool invert_vgroup = (deformflag & ARM_DEF_INVERT_VGROUP) != 0; + int defbase_len = 0; /* safety for vertexgroup index overflow */ + int i, dverts_len = 0; /* safety for vertexgroup overflow */ + bool use_dverts = false; + int armature_def_nr; + + /* in editmode, or not an armature */ + if (arm->edbo || (ob_arm->pose == NULL)) { + return; + } + + if ((ob_arm->pose->flag & POSE_RECALC) != 0) { + CLOG_ERROR(&LOG, + "Trying to evaluate influence of armature '%s' which needs Pose recalc!", + ob_arm->id.name); + BLI_assert(0); + } + + /* get the def_nr for the overall armature vertex group if present */ + armature_def_nr = BKE_object_defgroup_name_index(ob_target, defgrp_name); + + if (ELEM(ob_target->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) { + defbase_len = BLI_listbase_count(&ob_target->defbase); + + if (ob_target->type == OB_MESH) { + Mesh *me = ob_target->data; + dverts = me->dvert; + if (dverts) { + dverts_len = me->totvert; + } + } + else if (ob_target->type == OB_LATTICE) { + Lattice *lt = ob_target->data; + dverts = lt->dvert; + if (dverts) { + dverts_len = lt->pntsu * lt->pntsv * lt->pntsw; + } + } + else if (ob_target->type == OB_GPENCIL) { + dverts = gps_target->dvert; + if (dverts) { + dverts_len = gps_target->totpoints; + } + } + } + + /* get a vertex-deform-index to posechannel array */ + if (deformflag & ARM_DEF_VGROUP) { + if (ELEM(ob_target->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) { + /* if we have a Mesh, only use dverts if it has them */ + if (me_target) { + use_dverts = (me_target->dvert != NULL); + } + else if (dverts) { + use_dverts = true; + } + + if (use_dverts) { + pchan_from_defbase = MEM_callocN(sizeof(*pchan_from_defbase) * defbase_len, "defnrToBone"); + /* TODO(sergey): Some considerations here: + * + * - Check whether keeping this consistent across frames gives speedup. + */ + for (i = 0, dg = ob_target->defbase.first; dg; i++, dg = dg->next) { + pchan_from_defbase[i] = BKE_pose_channel_find_name(ob_arm->pose, dg->name); + /* exclude non-deforming bones */ + if (pchan_from_defbase[i]) { + if (pchan_from_defbase[i]->bone->flag & BONE_NO_DEFORM) { + pchan_from_defbase[i] = NULL; + } + } + } + } + } + } + + ArmatureUserdata data = { + .ob_arm = ob_arm, + .ob_target = ob_target, + .me_target = me_target, + .vert_coords = vert_coords, + .vert_deform_mats = vert_deform_mats, + .vert_coords_prev = vert_coords_prev, + .use_envelope = use_envelope, + .use_quaternion = use_quaternion, + .invert_vgroup = invert_vgroup, + .use_dverts = use_dverts, + .armature_def_nr = armature_def_nr, + .dverts = dverts, + .dverts_len = dverts_len, + .pchan_from_defbase = pchan_from_defbase, + .defbase_len = defbase_len, + }; + + float obinv[4][4]; + invert_m4_m4(obinv, ob_target->obmat); + + mul_m4_m4m4(data.postmat, obinv, ob_arm->obmat); + invert_m4_m4(data.premat, data.postmat); + + TaskParallelSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.min_iter_per_thread = 32; + BLI_task_parallel_range(0, vert_coords_len, &data, armature_vert_task, &settings); + + if (pchan_from_defbase) { + MEM_freeN(pchan_from_defbase); + } +} + +void BKE_armature_deform_coords_with_gpencil_stroke(Object *ob_arm, + Object *ob_target, + float (*vert_coords)[3], + float (*vert_deform_mats)[3][3], + int vert_coords_len, + int deformflag, + float (*vert_coords_prev)[3], + const char *defgrp_name, + bGPDstroke *gps_target) +{ + armature_deform_coords_impl(ob_arm, + ob_target, + vert_coords, + vert_deform_mats, + vert_coords_len, + deformflag, + vert_coords_prev, + defgrp_name, + NULL, + gps_target); +} + +void BKE_armature_deform_coords_with_mesh(Object *ob_arm, + Object *ob_target, + float (*vert_coords)[3], + float (*vert_deform_mats)[3][3], + int vert_coords_len, + int deformflag, + float (*vert_coords_prev)[3], + const char *defgrp_name, + const Mesh *me_target) +{ + armature_deform_coords_impl(ob_arm, + ob_target, + vert_coords, + vert_deform_mats, + vert_coords_len, + deformflag, + vert_coords_prev, + defgrp_name, + me_target, + NULL); +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index e67cf8573f3..0b65f53708f 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -29,7 +29,6 @@ #include "BLI_blenlib.h" #include "BLI_ghash.h" -#include "BLI_linklist.h" #include "BLI_math.h" #include "BLI_utildefines.h" @@ -43,7 +42,6 @@ /* for dereferencing pointers */ #include "DNA_key_types.h" #include "DNA_object_types.h" -#include "DNA_scene_types.h" #include "DNA_vfont_types.h" #include "BKE_curve.h" @@ -54,7 +52,6 @@ #include "BKE_lib_id.h" #include "BKE_lib_query.h" #include "BKE_main.h" -#include "BKE_material.h" #include "BKE_object.h" #include "DEG_depsgraph.h" diff --git a/source/blender/blenkernel/intern/curve_deform.c b/source/blender/blenkernel/intern/curve_deform.c new file mode 100644 index 00000000000..36632982b5c --- /dev/null +++ b/source/blender/blenkernel/intern/curve_deform.c @@ -0,0 +1,398 @@ +/* + * 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 curve object (used by modifier). + */ + +#include +#include +#include +#include + +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "DNA_curve_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" + +#include "BKE_anim_path.h" +#include "BKE_curve.h" +#include "BKE_lattice.h" +#include "BKE_modifier.h" + +#include "BKE_deform.h" + +/* -------------------------------------------------------------------- */ +/** \name Curve Deform Internal Utilities + * \{ */ + +/* calculations is in local space of deformed object + * so we store in latmat transform from path coord inside object + */ +typedef struct { + float dmin[3], dmax[3]; + float curvespace[4][4], objectspace[4][4], objectspace3[3][3]; + int no_rot_axis; +} CurveDeform; + +static void init_curve_deform(Object *par, Object *ob, CurveDeform *cd) +{ + invert_m4_m4(ob->imat, ob->obmat); + mul_m4_m4m4(cd->objectspace, ob->imat, par->obmat); + invert_m4_m4(cd->curvespace, cd->objectspace); + copy_m3_m4(cd->objectspace3, cd->objectspace); + cd->no_rot_axis = 0; +} + +/* this makes sure we can extend for non-cyclic. + * + * returns OK: 1/0 + */ +static bool where_on_path_deform( + Object *ob, float ctime, float vec[4], float dir[3], float quat[4], float *radius) +{ + BevList *bl; + float ctime1; + int cycl = 0; + + /* test for cyclic */ + bl = ob->runtime.curve_cache->bev.first; + if (!bl->nr) { + return false; + } + if (bl->poly > -1) { + cycl = 1; + } + + if (cycl == 0) { + ctime1 = CLAMPIS(ctime, 0.0f, 1.0f); + } + else { + ctime1 = ctime; + } + + /* vec needs 4 items */ + if (where_on_path(ob, ctime1, vec, dir, quat, radius, NULL)) { + + if (cycl == 0) { + Path *path = ob->runtime.curve_cache->path; + float dvec[3]; + + if (ctime < 0.0f) { + sub_v3_v3v3(dvec, path->data[1].vec, path->data[0].vec); + mul_v3_fl(dvec, ctime * (float)path->len); + add_v3_v3(vec, dvec); + if (quat) { + copy_qt_qt(quat, path->data[0].quat); + } + if (radius) { + *radius = path->data[0].radius; + } + } + else if (ctime > 1.0f) { + sub_v3_v3v3(dvec, path->data[path->len - 1].vec, path->data[path->len - 2].vec); + mul_v3_fl(dvec, (ctime - 1.0f) * (float)path->len); + add_v3_v3(vec, dvec); + if (quat) { + copy_qt_qt(quat, path->data[path->len - 1].quat); + } + if (radius) { + *radius = path->data[path->len - 1].radius; + } + /* weight - not used but could be added */ + } + } + return true; + } + return false; +} + +/* for each point, rotate & translate to curve */ +/* use path, since it has constant distances */ +/* co: local coord, result local too */ +/* returns quaternion for rotation, using cd->no_rot_axis */ +/* axis is using another define!!! */ +static bool calc_curve_deform( + Object *par, float co[3], const short axis, CurveDeform *cd, float r_quat[4]) +{ + Curve *cu = par->data; + float fac, loc[4], dir[3], new_quat[4], radius; + short index; + const bool is_neg_axis = (axis > 2); + + if (par->runtime.curve_cache == NULL) { + /* Happens with a cyclic dependencies. */ + return false; + } + + if (par->runtime.curve_cache->path == NULL) { + return false; /* happens on append, cyclic dependencies and empty curves */ + } + + /* options */ + if (is_neg_axis) { + index = axis - 3; + if (cu->flag & CU_STRETCH) { + fac = -(co[index] - cd->dmax[index]) / (cd->dmax[index] - cd->dmin[index]); + } + else { + fac = -(co[index] - cd->dmax[index]) / (par->runtime.curve_cache->path->totdist); + } + } + else { + index = axis; + if (cu->flag & CU_STRETCH) { + fac = (co[index] - cd->dmin[index]) / (cd->dmax[index] - cd->dmin[index]); + } + else { + if (LIKELY(par->runtime.curve_cache->path->totdist > FLT_EPSILON)) { + fac = +(co[index] - cd->dmin[index]) / (par->runtime.curve_cache->path->totdist); + } + else { + fac = 0.0f; + } + } + } + + if (where_on_path_deform(par, fac, loc, dir, new_quat, &radius)) { /* returns OK */ + float quat[4], cent[3]; + + if (cd->no_rot_axis) { /* set by caller */ + + /* This is not exactly the same as 2.4x, since the axis is having rotation removed rather + * than changing the axis before calculating the tilt but serves much the same purpose. */ + float dir_flat[3] = {0, 0, 0}, q[4]; + copy_v3_v3(dir_flat, dir); + dir_flat[cd->no_rot_axis - 1] = 0.0f; + + normalize_v3(dir); + normalize_v3(dir_flat); + + rotation_between_vecs_to_quat(q, dir, dir_flat); /* Could this be done faster? */ + + mul_qt_qtqt(new_quat, q, new_quat); + } + + /* Logic for 'cent' orientation * + * + * The way 'co' is copied to 'cent' may seem to have no meaning, but it does. + * + * Use a curve modifier to stretch a cube out, color each side RGB, + * positive side light, negative dark. + * view with X up (default), from the angle that you can see 3 faces RGB colors (light), + * anti-clockwise + * Notice X,Y,Z Up all have light colors and each ordered CCW. + * + * Now for Neg Up XYZ, the colors are all dark, and ordered clockwise - Campbell + * + * note: moved functions into quat_apply_track/vec_apply_track + * */ + copy_qt_qt(quat, new_quat); + copy_v3_v3(cent, co); + + /* zero the axis which is not used, + * the big block of text above now applies to these 3 lines */ + quat_apply_track( + quat, + axis, + (axis == 0 || axis == 2) ? 1 : 0); /* up flag is a dummy, set so no rotation is done */ + vec_apply_track(cent, axis); + cent[index] = 0.0f; + + /* scale if enabled */ + if (cu->flag & CU_PATH_RADIUS) { + mul_v3_fl(cent, radius); + } + + /* local rotation */ + normalize_qt(quat); + mul_qt_v3(quat, cent); + + /* translation */ + add_v3_v3v3(co, cent, loc); + + if (r_quat) { + copy_qt_qt(r_quat, quat); + } + + return true; + } + return false; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Curve Deform #BKE_curve_deform_coords API + * + * #BKE_curve_deform and related functions. + * \{ */ + +void BKE_curve_deform_coords(Object *ob_curve, + Object *ob_target, + float (*vert_coords)[3], + const int vert_coords_len, + const MDeformVert *dvert, + const int defgrp_index, + const short flag, + const short defaxis) +{ + Curve *cu; + int a; + CurveDeform cd; + const bool is_neg_axis = (defaxis > 2); + const bool invert_vgroup = (flag & MOD_CURVE_INVERT_VGROUP) != 0; + + if (ob_curve->type != OB_CURVE) { + return; + } + + cu = ob_curve->data; + + init_curve_deform(ob_curve, ob_target, &cd); + + /* dummy bounds, keep if CU_DEFORM_BOUNDS_OFF is set */ + if (is_neg_axis == false) { + cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = 0.0f; + cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 1.0f; + } + else { + /* negative, these bounds give a good rest position */ + cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = -1.0f; + cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 0.0f; + } + + if (dvert) { + const MDeformVert *dvert_iter; + float vec[3]; + + if (cu->flag & CU_DEFORM_BOUNDS_OFF) { + for (a = 0, dvert_iter = dvert; a < vert_coords_len; a++, dvert_iter++) { + const float weight = invert_vgroup ? + 1.0f - BKE_defvert_find_weight(dvert_iter, defgrp_index) : + BKE_defvert_find_weight(dvert_iter, defgrp_index); + + if (weight > 0.0f) { + mul_m4_v3(cd.curvespace, vert_coords[a]); + copy_v3_v3(vec, vert_coords[a]); + calc_curve_deform(ob_curve, vec, defaxis, &cd, NULL); + interp_v3_v3v3(vert_coords[a], vert_coords[a], vec, weight); + mul_m4_v3(cd.objectspace, vert_coords[a]); + } + } + } + else { + /* set mesh min/max bounds */ + INIT_MINMAX(cd.dmin, cd.dmax); + + for (a = 0, dvert_iter = dvert; a < vert_coords_len; a++, dvert_iter++) { + const float weight = invert_vgroup ? + 1.0f - BKE_defvert_find_weight(dvert_iter, defgrp_index) : + BKE_defvert_find_weight(dvert_iter, defgrp_index); + if (weight > 0.0f) { + mul_m4_v3(cd.curvespace, vert_coords[a]); + minmax_v3v3_v3(cd.dmin, cd.dmax, vert_coords[a]); + } + } + + for (a = 0, dvert_iter = dvert; a < vert_coords_len; a++, dvert_iter++) { + const float weight = invert_vgroup ? + 1.0f - BKE_defvert_find_weight(dvert_iter, defgrp_index) : + BKE_defvert_find_weight(dvert_iter, defgrp_index); + + if (weight > 0.0f) { + /* already in 'cd.curvespace', prev for loop */ + copy_v3_v3(vec, vert_coords[a]); + calc_curve_deform(ob_curve, vec, defaxis, &cd, NULL); + interp_v3_v3v3(vert_coords[a], vert_coords[a], vec, weight); + mul_m4_v3(cd.objectspace, vert_coords[a]); + } + } + } + } + else { + if (cu->flag & CU_DEFORM_BOUNDS_OFF) { + for (a = 0; a < vert_coords_len; a++) { + mul_m4_v3(cd.curvespace, vert_coords[a]); + calc_curve_deform(ob_curve, vert_coords[a], defaxis, &cd, NULL); + mul_m4_v3(cd.objectspace, vert_coords[a]); + } + } + else { + /* set mesh min max bounds */ + INIT_MINMAX(cd.dmin, cd.dmax); + + for (a = 0; a < vert_coords_len; a++) { + mul_m4_v3(cd.curvespace, vert_coords[a]); + minmax_v3v3_v3(cd.dmin, cd.dmax, vert_coords[a]); + } + + for (a = 0; a < vert_coords_len; a++) { + /* already in 'cd.curvespace', prev for loop */ + calc_curve_deform(ob_curve, vert_coords[a], defaxis, &cd, NULL); + mul_m4_v3(cd.objectspace, vert_coords[a]); + } + } + } +} + +/* input vec and orco = local coord in armature space */ +/* orco is original not-animated or deformed reference point */ +/* result written in vec and mat */ +void BKE_curve_deform_co(Object *ob_curve, + Object *ob_target, + const float orco[3], + float vec[3], + float mat[3][3], + const int no_rot_axis) +{ + CurveDeform cd; + float quat[4]; + + if (ob_curve->type != OB_CURVE) { + unit_m3(mat); + return; + } + + init_curve_deform(ob_curve, ob_target, &cd); + cd.no_rot_axis = no_rot_axis; /* option to only rotate for XY, for example */ + + copy_v3_v3(cd.dmin, orco); + copy_v3_v3(cd.dmax, orco); + + mul_m4_v3(cd.curvespace, vec); + + if (calc_curve_deform(ob_curve, vec, ob_target->trackflag, &cd, quat)) { + float qmat[3][3]; + + quat_to_mat3(qmat, quat); + mul_m3_m3m3(mat, qmat, cd.objectspace3); + } + else { + unit_m3(mat); + } + + mul_m4_v3(cd.objectspace, vec); +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index 666eb16c75f..c3b2fd9e35d 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -31,7 +31,6 @@ #include "BLI_bitmap.h" #include "BLI_listbase.h" #include "BLI_math.h" -#include "BLI_task.h" #include "BLI_utildefines.h" #include "BLT_translation.h" @@ -40,16 +39,13 @@ #include "DNA_defaults.h" #include "DNA_key_types.h" #include "DNA_lattice_types.h" -#include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" -#include "BKE_anim_path.h" #include "BKE_curve.h" #include "BKE_displist.h" #include "BKE_idtype.h" -#include "BKE_key.h" #include "BKE_lattice.h" #include "BKE_lib_id.h" #include "BKE_lib_query.h" @@ -349,695 +345,6 @@ Lattice *BKE_lattice_copy(Main *bmain, const Lattice *lt) return lt_copy; } -typedef struct LatticeDeformData { - Object *object; - float *latticedata; - float latmat[4][4]; -} LatticeDeformData; - -LatticeDeformData *init_latt_deform(Object *oblatt, 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 calc_latt_deform(LatticeDeformData *lattice_deform_data, float co[3], float weight) -{ - 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; - 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 end_latt_deform(LatticeDeformData *lattice_deform_data) -{ - if (lattice_deform_data->latticedata) { - MEM_freeN(lattice_deform_data->latticedata); - } - - MEM_freeN(lattice_deform_data); -} - -/* -------------------------------------------------------------------- */ -/** \name Curve Deform Internal Utilities - * \{ */ - -/* calculations is in local space of deformed object - * so we store in latmat transform from path coord inside object - */ -typedef struct { - float dmin[3], dmax[3]; - float curvespace[4][4], objectspace[4][4], objectspace3[3][3]; - int no_rot_axis; -} CurveDeform; - -static void init_curve_deform(Object *par, Object *ob, CurveDeform *cd) -{ - invert_m4_m4(ob->imat, ob->obmat); - mul_m4_m4m4(cd->objectspace, ob->imat, par->obmat); - invert_m4_m4(cd->curvespace, cd->objectspace); - copy_m3_m4(cd->objectspace3, cd->objectspace); - cd->no_rot_axis = 0; -} - -/* this makes sure we can extend for non-cyclic. - * - * returns OK: 1/0 - */ -static bool where_on_path_deform( - Object *ob, float ctime, float vec[4], float dir[3], float quat[4], float *radius) -{ - BevList *bl; - float ctime1; - int cycl = 0; - - /* test for cyclic */ - bl = ob->runtime.curve_cache->bev.first; - if (!bl->nr) { - return false; - } - if (bl->poly > -1) { - cycl = 1; - } - - if (cycl == 0) { - ctime1 = CLAMPIS(ctime, 0.0f, 1.0f); - } - else { - ctime1 = ctime; - } - - /* vec needs 4 items */ - if (where_on_path(ob, ctime1, vec, dir, quat, radius, NULL)) { - - if (cycl == 0) { - Path *path = ob->runtime.curve_cache->path; - float dvec[3]; - - if (ctime < 0.0f) { - sub_v3_v3v3(dvec, path->data[1].vec, path->data[0].vec); - mul_v3_fl(dvec, ctime * (float)path->len); - add_v3_v3(vec, dvec); - if (quat) { - copy_qt_qt(quat, path->data[0].quat); - } - if (radius) { - *radius = path->data[0].radius; - } - } - else if (ctime > 1.0f) { - sub_v3_v3v3(dvec, path->data[path->len - 1].vec, path->data[path->len - 2].vec); - mul_v3_fl(dvec, (ctime - 1.0f) * (float)path->len); - add_v3_v3(vec, dvec); - if (quat) { - copy_qt_qt(quat, path->data[path->len - 1].quat); - } - if (radius) { - *radius = path->data[path->len - 1].radius; - } - /* weight - not used but could be added */ - } - } - return true; - } - return false; -} - -/* for each point, rotate & translate to curve */ -/* use path, since it has constant distances */ -/* co: local coord, result local too */ -/* returns quaternion for rotation, using cd->no_rot_axis */ -/* axis is using another define!!! */ -static bool calc_curve_deform( - Object *par, float co[3], const short axis, CurveDeform *cd, float r_quat[4]) -{ - Curve *cu = par->data; - float fac, loc[4], dir[3], new_quat[4], radius; - short index; - const bool is_neg_axis = (axis > 2); - - if (par->runtime.curve_cache == NULL) { - /* Happens with a cyclic dependencies. */ - return false; - } - - if (par->runtime.curve_cache->path == NULL) { - return false; /* happens on append, cyclic dependencies and empty curves */ - } - - /* options */ - if (is_neg_axis) { - index = axis - 3; - if (cu->flag & CU_STRETCH) { - fac = -(co[index] - cd->dmax[index]) / (cd->dmax[index] - cd->dmin[index]); - } - else { - fac = -(co[index] - cd->dmax[index]) / (par->runtime.curve_cache->path->totdist); - } - } - else { - index = axis; - if (cu->flag & CU_STRETCH) { - fac = (co[index] - cd->dmin[index]) / (cd->dmax[index] - cd->dmin[index]); - } - else { - if (LIKELY(par->runtime.curve_cache->path->totdist > FLT_EPSILON)) { - fac = +(co[index] - cd->dmin[index]) / (par->runtime.curve_cache->path->totdist); - } - else { - fac = 0.0f; - } - } - } - - if (where_on_path_deform(par, fac, loc, dir, new_quat, &radius)) { /* returns OK */ - float quat[4], cent[3]; - - if (cd->no_rot_axis) { /* set by caller */ - - /* This is not exactly the same as 2.4x, since the axis is having rotation removed rather - * than changing the axis before calculating the tilt but serves much the same purpose. */ - float dir_flat[3] = {0, 0, 0}, q[4]; - copy_v3_v3(dir_flat, dir); - dir_flat[cd->no_rot_axis - 1] = 0.0f; - - normalize_v3(dir); - normalize_v3(dir_flat); - - rotation_between_vecs_to_quat(q, dir, dir_flat); /* Could this be done faster? */ - - mul_qt_qtqt(new_quat, q, new_quat); - } - - /* Logic for 'cent' orientation * - * - * The way 'co' is copied to 'cent' may seem to have no meaning, but it does. - * - * Use a curve modifier to stretch a cube out, color each side RGB, - * positive side light, negative dark. - * view with X up (default), from the angle that you can see 3 faces RGB colors (light), - * anti-clockwise - * Notice X,Y,Z Up all have light colors and each ordered CCW. - * - * Now for Neg Up XYZ, the colors are all dark, and ordered clockwise - Campbell - * - * note: moved functions into quat_apply_track/vec_apply_track - * */ - copy_qt_qt(quat, new_quat); - copy_v3_v3(cent, co); - - /* zero the axis which is not used, - * the big block of text above now applies to these 3 lines */ - quat_apply_track( - quat, - axis, - (axis == 0 || axis == 2) ? 1 : 0); /* up flag is a dummy, set so no rotation is done */ - vec_apply_track(cent, axis); - cent[index] = 0.0f; - - /* scale if enabled */ - if (cu->flag & CU_PATH_RADIUS) { - mul_v3_fl(cent, radius); - } - - /* local rotation */ - normalize_qt(quat); - mul_qt_v3(quat, cent); - - /* translation */ - add_v3_v3v3(co, cent, loc); - - if (r_quat) { - copy_qt_qt(r_quat, quat); - } - - return true; - } - return false; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Curve Deform #BKE_curve_deform_coords API - * - * #BKE_curve_deform and related functions. - * \{ */ - -void BKE_curve_deform_coords(Object *ob_curve, - Object *ob_target, - float (*vert_coords)[3], - const int vert_coords_len, - const MDeformVert *dvert, - const int defgrp_index, - const short flag, - const short defaxis) -{ - Curve *cu; - int a; - CurveDeform cd; - const bool is_neg_axis = (defaxis > 2); - const bool invert_vgroup = (flag & MOD_CURVE_INVERT_VGROUP) != 0; - - if (ob_curve->type != OB_CURVE) { - return; - } - - cu = ob_curve->data; - - init_curve_deform(ob_curve, ob_target, &cd); - - /* dummy bounds, keep if CU_DEFORM_BOUNDS_OFF is set */ - if (is_neg_axis == false) { - cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = 0.0f; - cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 1.0f; - } - else { - /* negative, these bounds give a good rest position */ - cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = -1.0f; - cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 0.0f; - } - - if (dvert) { - const MDeformVert *dvert_iter; - float vec[3]; - - if (cu->flag & CU_DEFORM_BOUNDS_OFF) { - for (a = 0, dvert_iter = dvert; a < vert_coords_len; a++, dvert_iter++) { - const float weight = invert_vgroup ? - 1.0f - BKE_defvert_find_weight(dvert_iter, defgrp_index) : - BKE_defvert_find_weight(dvert_iter, defgrp_index); - - if (weight > 0.0f) { - mul_m4_v3(cd.curvespace, vert_coords[a]); - copy_v3_v3(vec, vert_coords[a]); - calc_curve_deform(ob_curve, vec, defaxis, &cd, NULL); - interp_v3_v3v3(vert_coords[a], vert_coords[a], vec, weight); - mul_m4_v3(cd.objectspace, vert_coords[a]); - } - } - } - else { - /* set mesh min/max bounds */ - INIT_MINMAX(cd.dmin, cd.dmax); - - for (a = 0, dvert_iter = dvert; a < vert_coords_len; a++, dvert_iter++) { - const float weight = invert_vgroup ? - 1.0f - BKE_defvert_find_weight(dvert_iter, defgrp_index) : - BKE_defvert_find_weight(dvert_iter, defgrp_index); - if (weight > 0.0f) { - mul_m4_v3(cd.curvespace, vert_coords[a]); - minmax_v3v3_v3(cd.dmin, cd.dmax, vert_coords[a]); - } - } - - for (a = 0, dvert_iter = dvert; a < vert_coords_len; a++, dvert_iter++) { - const float weight = invert_vgroup ? - 1.0f - BKE_defvert_find_weight(dvert_iter, defgrp_index) : - BKE_defvert_find_weight(dvert_iter, defgrp_index); - - if (weight > 0.0f) { - /* already in 'cd.curvespace', prev for loop */ - copy_v3_v3(vec, vert_coords[a]); - calc_curve_deform(ob_curve, vec, defaxis, &cd, NULL); - interp_v3_v3v3(vert_coords[a], vert_coords[a], vec, weight); - mul_m4_v3(cd.objectspace, vert_coords[a]); - } - } - } - } - else { - if (cu->flag & CU_DEFORM_BOUNDS_OFF) { - for (a = 0; a < vert_coords_len; a++) { - mul_m4_v3(cd.curvespace, vert_coords[a]); - calc_curve_deform(ob_curve, vert_coords[a], defaxis, &cd, NULL); - mul_m4_v3(cd.objectspace, vert_coords[a]); - } - } - else { - /* set mesh min max bounds */ - INIT_MINMAX(cd.dmin, cd.dmax); - - for (a = 0; a < vert_coords_len; a++) { - mul_m4_v3(cd.curvespace, vert_coords[a]); - minmax_v3v3_v3(cd.dmin, cd.dmax, vert_coords[a]); - } - - for (a = 0; a < vert_coords_len; a++) { - /* already in 'cd.curvespace', prev for loop */ - calc_curve_deform(ob_curve, vert_coords[a], defaxis, &cd, NULL); - mul_m4_v3(cd.objectspace, vert_coords[a]); - } - } - } -} - -/* input vec and orco = local coord in armature space */ -/* orco is original not-animated or deformed reference point */ -/* result written in vec and mat */ -void BKE_curve_deform_co(Object *ob_curve, - Object *ob_target, - const float orco[3], - float vec[3], - float mat[3][3], - const int no_rot_axis) -{ - CurveDeform cd; - float quat[4]; - - if (ob_curve->type != OB_CURVE) { - unit_m3(mat); - return; - } - - init_curve_deform(ob_curve, ob_target, &cd); - cd.no_rot_axis = no_rot_axis; /* option to only rotate for XY, for example */ - - copy_v3_v3(cd.dmin, orco); - copy_v3_v3(cd.dmax, orco); - - mul_m4_v3(cd.curvespace, vec); - - if (calc_curve_deform(ob_curve, vec, ob_target->trackflag, &cd, quat)) { - float qmat[3][3]; - - quat_to_mat3(qmat, quat); - mul_m3_m3m3(mat, qmat, cd.objectspace3); - } - else { - unit_m3(mat); - } - - mul_m4_v3(cd.objectspace, vec); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \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; -} LatticeDeformUserdata; - -static void lattice_deform_vert_task(void *__restrict userdata, - const int index, - const TaskParallelTLS *__restrict UNUSED(tls)) -{ - const LatticeDeformUserdata *data = userdata; - - if (data->dvert != NULL) { - const float weight = data->invert_vgroup ? - 1.0f - - BKE_defvert_find_weight(data->dvert + index, data->defgrp_index) : - BKE_defvert_find_weight(data->dvert + index, data->defgrp_index); - if (weight > 0.0f) { - calc_latt_deform(data->lattice_deform_data, data->vert_coords[index], weight * data->fac); - } - } - else { - calc_latt_deform(data->lattice_deform_data, data->vert_coords[index], data->fac); - } -} - -static void lattice_deform_coords_impl(Object *ob_lattice, - 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) -{ - LatticeDeformData *lattice_deform_data; - const MDeformVert *dvert = NULL; - int defgrp_index = -1; - - if (ob_lattice->type != OB_LATTICE) { - return; - } - - lattice_deform_data = init_latt_deform(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 (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, - }; - - 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); - - end_latt_deform(lattice_deform_data); -} - -void BKE_lattice_deform_coords(Object *ob_lattice, - Object *ob_target, - float (*vert_coords)[3], - int vert_coords_len, - 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); -} - -void BKE_lattice_deform_coords_with_mesh(Object *ob_lattice, - 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); -} - -/** \} */ - bool object_deform_mball(Object *ob, ListBase *dispbase) { if (ob->parent && ob->parent->type == OB_LATTICE && ob->partype == PARSKEL) { diff --git a/source/blender/blenkernel/intern/lattice_deform.c b/source/blender/blenkernel/intern/lattice_deform.c new file mode 100644 index 00000000000..7468ae8b3a4 --- /dev/null +++ b/source/blender/blenkernel/intern/lattice_deform.c @@ -0,0 +1,389 @@ +/* + * 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 +#include +#include +#include + +#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_key.h" +#include "BKE_lattice.h" +#include "BKE_modifier.h" + +#include "BKE_deform.h" + +/* -------------------------------------------------------------------- */ +/** \name Lattice Deform API + * \{ */ + +typedef struct LatticeDeformData { + Object *object; + float *latticedata; + float latmat[4][4]; +} LatticeDeformData; + +LatticeDeformData *init_latt_deform(Object *oblatt, 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 calc_latt_deform(LatticeDeformData *lattice_deform_data, float co[3], float weight) +{ + 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; + 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 end_latt_deform(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; +} LatticeDeformUserdata; + +static void lattice_deform_vert_task(void *__restrict userdata, + const int index, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + const LatticeDeformUserdata *data = userdata; + + if (data->dvert != NULL) { + const float weight = data->invert_vgroup ? + 1.0f - + BKE_defvert_find_weight(data->dvert + index, data->defgrp_index) : + BKE_defvert_find_weight(data->dvert + index, data->defgrp_index); + if (weight > 0.0f) { + calc_latt_deform(data->lattice_deform_data, data->vert_coords[index], weight * data->fac); + } + } + else { + calc_latt_deform(data->lattice_deform_data, data->vert_coords[index], data->fac); + } +} + +static void lattice_deform_coords_impl(Object *ob_lattice, + 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) +{ + LatticeDeformData *lattice_deform_data; + const MDeformVert *dvert = NULL; + int defgrp_index = -1; + + if (ob_lattice->type != OB_LATTICE) { + return; + } + + lattice_deform_data = init_latt_deform(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 (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, + }; + + 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); + + end_latt_deform(lattice_deform_data); +} + +void BKE_lattice_deform_coords(Object *ob_lattice, + Object *ob_target, + float (*vert_coords)[3], + int vert_coords_len, + 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); +} + +void BKE_lattice_deform_coords_with_mesh(Object *ob_lattice, + 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); +} + +/** \} */ diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c index fde5ebcff8d..776e5521179 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c @@ -36,10 +36,10 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "BKE_armature.h" #include "BKE_gpencil.h" #include "BKE_gpencil_geom.h" #include "BKE_gpencil_modifier.h" -#include "BKE_lattice.h" #include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_modifier.h" diff --git a/source/blender/modifiers/intern/MOD_armature.c b/source/blender/modifiers/intern/MOD_armature.c index 800de546a5a..c8697f90b95 100644 --- a/source/blender/modifiers/intern/MOD_armature.c +++ b/source/blender/modifiers/intern/MOD_armature.c @@ -34,9 +34,9 @@ #include "DNA_screen_types.h" #include "BKE_action.h" +#include "BKE_armature.h" #include "BKE_context.h" #include "BKE_editmesh.h" -#include "BKE_lattice.h" #include "BKE_lib_id.h" #include "BKE_lib_query.h" #include "BKE_mesh.h" diff --git a/source/blender/modifiers/intern/MOD_curve.c b/source/blender/modifiers/intern/MOD_curve.c index a081612e063..b55e48f46ce 100644 --- a/source/blender/modifiers/intern/MOD_curve.c +++ b/source/blender/modifiers/intern/MOD_curve.c @@ -33,8 +33,8 @@ #include "DNA_screen_types.h" #include "BKE_context.h" +#include "BKE_curve.h" #include "BKE_editmesh.h" -#include "BKE_lattice.h" #include "BKE_lib_id.h" #include "BKE_lib_query.h" #include "BKE_mesh.h" -- cgit v1.2.3