Depsgraph: Add utility function for transform dependency
[blender.git] / source / blender / modifiers / intern / MOD_uvwarp.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software  Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16
17 /** \file \ingroup modifiers
18  */
19
20 #include <string.h>
21
22 #include "DNA_mesh_types.h"
23 #include "DNA_meshdata_types.h"
24 #include "DNA_object_types.h"
25
26 #include "BLI_math.h"
27 #include "BLI_task.h"
28 #include "BLI_utildefines.h"
29
30 #include "BKE_action.h"  /* BKE_pose_channel_find_name */
31 #include "BKE_deform.h"
32 #include "BKE_library_query.h"
33 #include "BKE_modifier.h"
34
35 #include "DEG_depsgraph_query.h"
36
37 #include "MOD_util.h"
38
39
40 static void uv_warp_from_mat4_pair(
41         float uv_dst[2], const float uv_src[2], float warp_mat[4][4],
42         int axis_u, int axis_v)
43 {
44         float tuv[3] = {0.0f};
45
46         tuv[axis_u] = uv_src[0];
47         tuv[axis_v] = uv_src[1];
48
49         mul_m4_v3(warp_mat, tuv);
50
51         uv_dst[0] = tuv[axis_u];
52         uv_dst[1] = tuv[axis_v];
53 }
54
55 static void initData(ModifierData *md)
56 {
57         UVWarpModifierData *umd = (UVWarpModifierData *) md;
58         umd->axis_u = 0;
59         umd->axis_v = 1;
60         copy_v2_fl(umd->center, 0.5f);
61 }
62
63 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
64 {
65         UVWarpModifierData *umd = (UVWarpModifierData *)md;
66         CustomDataMask dataMask = 0;
67
68         /* ask for vertexgroups if we need them */
69         if (umd->vgroup_name[0])
70                 dataMask |= CD_MASK_MDEFORMVERT;
71
72         return dataMask;
73 }
74
75 static void matrix_from_obj_pchan(float mat[4][4], Object *ob, const char *bonename)
76 {
77         bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, bonename);
78         if (pchan) {
79                 mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat);
80         }
81         else {
82                 copy_m4_m4(mat, ob->obmat);
83         }
84 }
85
86 typedef struct UVWarpData {
87         MPoly *mpoly;
88         MLoop *mloop;
89         MLoopUV *mloopuv;
90
91         MDeformVert *dvert;
92         int defgrp_index;
93
94         float (*warp_mat)[4];
95         int axis_u;
96         int axis_v;
97 } UVWarpData;
98
99 static void uv_warp_compute(
100         void *__restrict userdata,
101         const int i,
102         const ParallelRangeTLS *__restrict UNUSED(tls))
103 {
104         const UVWarpData *data = userdata;
105
106         const MPoly *mp = &data->mpoly[i];
107         const MLoop *ml = &data->mloop[mp->loopstart];
108         MLoopUV *mluv = &data->mloopuv[mp->loopstart];
109
110         const MDeformVert *dvert = data->dvert;
111         const int defgrp_index = data->defgrp_index;
112
113         float (*warp_mat)[4] = data->warp_mat;
114         const int axis_u = data->axis_u;
115         const int axis_v = data->axis_v;
116
117         int l;
118
119         if (dvert) {
120                 for (l = 0; l < mp->totloop; l++, ml++, mluv++) {
121                         float uv[2];
122                         const float weight = defvert_find_weight(&dvert[ml->v], defgrp_index);
123
124                         uv_warp_from_mat4_pair(uv, mluv->uv, warp_mat, axis_u, axis_v);
125                         interp_v2_v2v2(mluv->uv, mluv->uv, uv, weight);
126                 }
127         }
128         else {
129                 for (l = 0; l < mp->totloop; l++, ml++, mluv++) {
130                         uv_warp_from_mat4_pair(mluv->uv, mluv->uv, warp_mat, axis_u, axis_v);
131                 }
132         }
133 }
134
135 static Mesh *applyModifier(
136         ModifierData *md, const ModifierEvalContext *ctx,
137         Mesh *mesh)
138 {
139         UVWarpModifierData *umd = (UVWarpModifierData *) md;
140         int numPolys, numLoops;
141         MPoly *mpoly;
142         MLoop *mloop;
143         MLoopUV *mloopuv;
144         MDeformVert *dvert;
145         int defgrp_index;
146         char uvname[MAX_CUSTOMDATA_LAYER_NAME];
147         float mat_src[4][4];
148         float mat_dst[4][4];
149         float imat_dst[4][4];
150         float warp_mat[4][4];
151         const int axis_u = umd->axis_u;
152         const int axis_v = umd->axis_v;
153
154         /* make sure there are UV Maps available */
155         if (!CustomData_has_layer(&mesh->ldata, CD_MLOOPUV)) {
156                 return mesh;
157         }
158         else if (ELEM(NULL, umd->object_src, umd->object_dst)) {
159                 modifier_setError(md, "From/To objects must be set");
160                 return mesh;
161         }
162
163         /* make sure anything moving UVs is available */
164         matrix_from_obj_pchan(mat_src, DEG_get_evaluated_object(ctx->depsgraph, umd->object_src), umd->bone_src);
165         matrix_from_obj_pchan(mat_dst, DEG_get_evaluated_object(ctx->depsgraph, umd->object_dst), umd->bone_dst);
166
167         invert_m4_m4(imat_dst, mat_dst);
168         mul_m4_m4m4(warp_mat, imat_dst, mat_src);
169
170         /* apply warp */
171         if (!is_zero_v2(umd->center)) {
172                 float mat_cent[4][4];
173                 float imat_cent[4][4];
174
175                 unit_m4(mat_cent);
176                 mat_cent[3][axis_u] = umd->center[0];
177                 mat_cent[3][axis_v] = umd->center[1];
178
179                 invert_m4_m4(imat_cent, mat_cent);
180
181                 mul_m4_m4m4(warp_mat, warp_mat, imat_cent);
182                 mul_m4_m4m4(warp_mat, mat_cent, warp_mat);
183         }
184
185         /* make sure we're using an existing layer */
186         CustomData_validate_layer_name(&mesh->ldata, CD_MLOOPUV, umd->uvlayer_name, uvname);
187
188         numPolys = mesh->totpoly;
189         numLoops = mesh->totloop;
190
191         mpoly = mesh->mpoly;
192         mloop = mesh->mloop;
193         /* make sure we are not modifying the original UV map */
194         mloopuv = CustomData_duplicate_referenced_layer_named(&mesh->ldata, CD_MLOOPUV, uvname, numLoops);
195         MOD_get_vgroup(ctx->object, mesh, umd->vgroup_name, &dvert, &defgrp_index);
196
197         UVWarpData data = {
198                 .mpoly = mpoly, .mloop = mloop, .mloopuv = mloopuv,
199                 .dvert = dvert, .defgrp_index = defgrp_index,
200                 .warp_mat = warp_mat, .axis_u = axis_u, .axis_v = axis_v,
201         };
202         ParallelRangeSettings settings;
203         BLI_parallel_range_settings_defaults(&settings);
204         settings.use_threading = (numPolys > 1000);
205         BLI_task_parallel_range(0, numPolys,
206                                 &data,
207                                 uv_warp_compute,
208                                 &settings);
209
210         /* XXX TODO is this still needed? */
211 //      me_eval->dirty |= DM_DIRTY_TESS_CDLAYERS;
212
213         return mesh;
214 }
215
216 static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData)
217 {
218         UVWarpModifierData *umd = (UVWarpModifierData *) md;
219
220         walk(userData, ob, &umd->object_dst, IDWALK_CB_NOP);
221         walk(userData, ob, &umd->object_src, IDWALK_CB_NOP);
222 }
223
224 static void uv_warp_deps_object_bone_new(
225         struct DepsNodeHandle *node,
226         Object *object,
227         const char *bonename)
228 {
229         if (object != NULL) {
230                 if (bonename[0])
231                         DEG_add_object_relation(node, object, DEG_OB_COMP_EVAL_POSE, "UVWarp Modifier");
232                 else
233                         DEG_add_object_relation(node, object, DEG_OB_COMP_TRANSFORM, "UVWarp Modifier");
234         }
235 }
236
237 static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
238 {
239         UVWarpModifierData *umd = (UVWarpModifierData *) md;
240
241         uv_warp_deps_object_bone_new(ctx->node, umd->object_src, umd->bone_src);
242         uv_warp_deps_object_bone_new(ctx->node, umd->object_dst, umd->bone_dst);
243
244         DEG_add_modifier_to_transform_relation(ctx->node, "UVWarp Modifier");
245 }
246
247 ModifierTypeInfo modifierType_UVWarp = {
248         /* name */              "UVWarp",
249         /* structName */        "UVWarpModifierData",
250         /* structSize */        sizeof(UVWarpModifierData),
251         /* type */              eModifierTypeType_NonGeometrical,
252         /* flags */             eModifierTypeFlag_AcceptsMesh |
253                                 eModifierTypeFlag_SupportsEditmode |
254                                 eModifierTypeFlag_EnableInEditmode,
255
256         /* copyData */          modifier_copyData_generic,
257
258         /* deformVerts_DM */    NULL,
259         /* deformMatrices_DM */ NULL,
260         /* deformVertsEM_DM */  NULL,
261         /* deformMatricesEM_DM*/NULL,
262         /* applyModifier_DM */  NULL,
263
264         /* deformVerts */       NULL,
265         /* deformMatrices */    NULL,
266         /* deformVertsEM */     NULL,
267         /* deformMatricesEM */  NULL,
268         /* applyModifier */     applyModifier,
269
270         /* initData */          initData,
271         /* requiredDataMask */  requiredDataMask,
272         /* freeData */          NULL,
273         /* isDisabled */        NULL,
274         /* updateDepsgraph */   updateDepsgraph,
275         /* dependsOnTime */     NULL,
276         /* dependsOnNormals */  NULL,
277         /* foreachObjectLink */ foreachObjectLink,
278         /* foreachIDLink */     NULL,
279         /* foreachTexLink */    NULL,
280 };