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