Blender  V3.3
MOD_uvwarp.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include <string.h>
8 
9 #include "BLI_utildefines.h"
10 
11 #include "BLI_math.h"
12 #include "BLI_task.h"
13 
14 #include "BLT_translation.h"
15 
16 #include "DNA_defaults.h"
17 #include "DNA_mesh_types.h"
18 #include "DNA_meshdata_types.h"
19 #include "DNA_object_types.h"
20 #include "DNA_screen_types.h"
21 
22 #include "BKE_action.h" /* BKE_pose_channel_find_name */
23 #include "BKE_context.h"
24 #include "BKE_deform.h"
25 #include "BKE_lib_query.h"
26 #include "BKE_modifier.h"
27 #include "BKE_screen.h"
28 
29 #include "UI_interface.h"
30 #include "UI_resources.h"
31 
32 #include "RNA_access.h"
33 #include "RNA_prototypes.h"
34 
35 #include "DEG_depsgraph_query.h"
36 
37 #include "MOD_ui_common.h"
38 #include "MOD_util.h"
39 
40 static void uv_warp_from_mat4_pair(float uv_dst[2],
41  const float uv_src[2],
42  const float warp_mat[4][4])
43 {
44  float tuv[3] = {0.0f};
45 
46  copy_v2_v2(tuv, uv_src);
47  mul_m4_v3(warp_mat, tuv);
48  copy_v2_v2(uv_dst, tuv);
49 }
50 
51 static void initData(ModifierData *md)
52 {
54 
56 
58 }
59 
60 static void requiredDataMask(Object *UNUSED(ob),
61  ModifierData *md,
62  CustomData_MeshMasks *r_cddata_masks)
63 {
65 
66  /* ask for vertexgroups if we need them */
67  if (umd->vgroup_name[0] != '\0') {
68  r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
69  }
70 }
71 
72 static void matrix_from_obj_pchan(float mat[4][4], Object *ob, const char *bonename)
73 {
74  bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, bonename);
75  if (pchan) {
76  mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat);
77  }
78  else {
79  copy_m4_m4(mat, ob->obmat);
80  }
81 }
82 
83 typedef struct UVWarpData {
87 
90 
91  float (*warp_mat)[4];
94 
95 static void uv_warp_compute(void *__restrict userdata,
96  const int i,
97  const TaskParallelTLS *__restrict UNUSED(tls))
98 {
99  const UVWarpData *data = userdata;
100 
101  const MPoly *mp = &data->mpoly[i];
102  const MLoop *ml = &data->mloop[mp->loopstart];
103  MLoopUV *mluv = &data->mloopuv[mp->loopstart];
104 
105  const MDeformVert *dvert = data->dvert;
106  const int defgrp_index = data->defgrp_index;
107 
108  float(*warp_mat)[4] = data->warp_mat;
109 
110  int l;
111 
112  if (dvert) {
113  for (l = 0; l < mp->totloop; l++, ml++, mluv++) {
114  float uv[2];
115  const float weight = data->invert_vgroup ?
116  1.0f - BKE_defvert_find_weight(&dvert[ml->v], defgrp_index) :
117  BKE_defvert_find_weight(&dvert[ml->v], defgrp_index);
118 
119  uv_warp_from_mat4_pair(uv, mluv->uv, warp_mat);
120  interp_v2_v2v2(mluv->uv, mluv->uv, uv, weight);
121  }
122  }
123  else {
124  for (l = 0; l < mp->totloop; l++, ml++, mluv++) {
125  uv_warp_from_mat4_pair(mluv->uv, mluv->uv, warp_mat);
126  }
127  }
128 }
129 
131 {
133  int polys_num, loops_num;
134  MPoly *mpoly;
135  MLoop *mloop;
136  MLoopUV *mloopuv;
137  MDeformVert *dvert;
138  int defgrp_index;
139  char uvname[MAX_CUSTOMDATA_LAYER_NAME];
140  float warp_mat[4][4];
141  const int axis_u = umd->axis_u;
142  const int axis_v = umd->axis_v;
143  const bool invert_vgroup = (umd->flag & MOD_UVWARP_INVERT_VGROUP) != 0;
144 
145  /* make sure there are UV Maps available */
147  return mesh;
148  }
149 
150  if (!ELEM(NULL, umd->object_src, umd->object_dst)) {
151  float mat_src[4][4];
152  float mat_dst[4][4];
153  float imat_dst[4][4];
154  float shuf_mat[4][4];
155 
156  /* make sure anything moving UVs is available */
157  matrix_from_obj_pchan(mat_src, umd->object_src, umd->bone_src);
158  matrix_from_obj_pchan(mat_dst, umd->object_dst, umd->bone_dst);
159 
160  invert_m4_m4(imat_dst, mat_dst);
161  mul_m4_m4m4(warp_mat, imat_dst, mat_src);
162 
163  /* apply warp */
164  if (!is_zero_v2(umd->center)) {
165  float mat_cent[4][4];
166  float imat_cent[4][4];
167 
168  unit_m4(mat_cent);
169  mat_cent[3][axis_u] = umd->center[0];
170  mat_cent[3][axis_v] = umd->center[1];
171 
172  invert_m4_m4(imat_cent, mat_cent);
173 
174  mul_m4_m4m4(warp_mat, warp_mat, imat_cent);
175  mul_m4_m4m4(warp_mat, mat_cent, warp_mat);
176  }
177 
178  const int shuf_indices[4] = {axis_u, axis_v, -1, 3};
179  shuffle_m4(shuf_mat, shuf_indices);
180  mul_m4_m4m4(warp_mat, shuf_mat, warp_mat);
181  transpose_m4(shuf_mat);
182  mul_m4_m4m4(warp_mat, warp_mat, shuf_mat);
183  }
184  else {
185  unit_m4(warp_mat);
186  }
187 
188  /* Apply direct 2d transform. */
189  translate_m4(warp_mat, umd->center[0], umd->center[1], 0.0f);
190  const float scale[3] = {umd->scale[0], umd->scale[1], 1.0f};
191  rescale_m4(warp_mat, scale);
192  rotate_m4(warp_mat, 'Z', umd->rotation);
193  translate_m4(warp_mat, umd->offset[0], umd->offset[1], 0.0f);
194  translate_m4(warp_mat, -umd->center[0], -umd->center[1], 0.0f);
195 
196  /* make sure we're using an existing layer */
198 
199  polys_num = mesh->totpoly;
200  loops_num = mesh->totloop;
201 
202  mpoly = mesh->mpoly;
203  mloop = mesh->mloop;
204  /* make sure we are not modifying the original UV map */
206  &mesh->ldata, CD_MLOOPUV, uvname, loops_num);
207  MOD_get_vgroup(ctx->object, mesh, umd->vgroup_name, &dvert, &defgrp_index);
208 
209  UVWarpData data = {
210  .mpoly = mpoly,
211  .mloop = mloop,
212  .mloopuv = mloopuv,
213  .dvert = dvert,
214  .defgrp_index = defgrp_index,
215  .warp_mat = warp_mat,
216  .invert_vgroup = invert_vgroup,
217  };
218  TaskParallelSettings settings;
220  settings.use_threading = (polys_num > 1000);
221  BLI_task_parallel_range(0, polys_num, &data, uv_warp_compute, &settings);
222 
223  mesh->runtime.is_original = false;
224 
225  return mesh;
226 }
227 
228 static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
229 {
231 
232  walk(userData, ob, (ID **)&umd->object_dst, IDWALK_CB_NOP);
233  walk(userData, ob, (ID **)&umd->object_src, IDWALK_CB_NOP);
234 }
235 
237 {
239 
241  ctx->node, umd->object_src, umd->bone_src, "UVWarp Modifier");
243  ctx->node, umd->object_dst, umd->bone_dst, "UVWarp Modifier");
244 
245  DEG_add_modifier_to_transform_relation(ctx->node, "UVWarp Modifier");
246 }
247 
248 static void panel_draw(const bContext *UNUSED(C), Panel *panel)
249 {
250  uiLayout *col;
251  uiLayout *layout = panel->layout;
252 
253  PointerRNA ob_ptr;
255 
256  PointerRNA warp_obj_ptr;
257  PointerRNA obj_data_ptr = RNA_pointer_get(&ob_ptr, "data");
258 
259  uiLayoutSetPropSep(layout, true);
260 
261  uiItemPointerR(layout, ptr, "uv_layer", &obj_data_ptr, "uv_layers", NULL, ICON_NONE);
262 
263  col = uiLayoutColumn(layout, false);
264  uiItemR(col, ptr, "center", 0, NULL, ICON_NONE);
265 
266  col = uiLayoutColumn(layout, false);
267  uiItemR(col, ptr, "axis_u", 0, IFACE_("Axis U"), ICON_NONE);
268  uiItemR(col, ptr, "axis_v", 0, IFACE_("V"), ICON_NONE);
269 
270  col = uiLayoutColumn(layout, false);
271  uiItemR(col, ptr, "object_from", 0, NULL, ICON_NONE);
272  warp_obj_ptr = RNA_pointer_get(ptr, "object_from");
273  if (!RNA_pointer_is_null(&warp_obj_ptr) && RNA_enum_get(&warp_obj_ptr, "type") == OB_ARMATURE) {
274  PointerRNA warp_obj_data_ptr = RNA_pointer_get(&warp_obj_ptr, "data");
275  uiItemPointerR(col, ptr, "bone_from", &warp_obj_data_ptr, "bones", NULL, ICON_NONE);
276  }
277 
278  uiItemR(col, ptr, "object_to", 0, IFACE_("To"), ICON_NONE);
279  warp_obj_ptr = RNA_pointer_get(ptr, "object_to");
280  if (!RNA_pointer_is_null(&warp_obj_ptr) && RNA_enum_get(&warp_obj_ptr, "type") == OB_ARMATURE) {
281  PointerRNA warp_obj_data_ptr = RNA_pointer_get(&warp_obj_ptr, "data");
282  uiItemPointerR(col, ptr, "bone_to", &warp_obj_data_ptr, "bones", NULL, ICON_NONE);
283  }
284 
285  modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL);
286 
287  modifier_panel_end(layout, ptr);
288 }
289 
290 static void transform_panel_draw(const bContext *UNUSED(C), Panel *panel)
291 {
292  uiLayout *layout = panel->layout;
293 
295 
296  uiLayoutSetPropSep(layout, true);
297 
298  uiItemR(layout, ptr, "offset", 0, NULL, ICON_NONE);
299  uiItemR(layout, ptr, "scale", 0, NULL, ICON_NONE);
300  uiItemR(layout, ptr, "rotation", 0, NULL, ICON_NONE);
301 }
302 
303 static void panelRegister(ARegionType *region_type)
304 {
307  region_type, "offset", "Transform", NULL, transform_panel_draw, panel_type);
308 }
309 
311  /* name */ N_("UVWarp"),
312  /* structName */ "UVWarpModifierData",
313  /* structSize */ sizeof(UVWarpModifierData),
314  /* srna */ &RNA_UVWarpModifier,
318  /* icon */ ICON_MOD_UVPROJECT, /* TODO: Use correct icon. */
319 
320  /* copyData */ BKE_modifier_copydata_generic,
321 
322  /* deformVerts */ NULL,
323  /* deformMatrices */ NULL,
324  /* deformVertsEM */ NULL,
325  /* deformMatricesEM */ NULL,
326  /* modifyMesh */ modifyMesh,
327  /* modifyGeometrySet */ NULL,
328 
329  /* initData */ initData,
330  /* requiredDataMask */ requiredDataMask,
331  /* freeData */ NULL,
332  /* isDisabled */ NULL,
333  /* updateDepsgraph */ updateDepsgraph,
334  /* dependsOnTime */ NULL,
335  /* dependsOnNormals */ NULL,
336  /* foreachIDLink */ foreachIDLink,
337  /* foreachTexLink */ NULL,
338  /* freeRuntimeData */ NULL,
339  /* panelRegister */ panelRegister,
340  /* blendWrite */ NULL,
341  /* blendRead */ NULL,
342 };
typedef float(TangentPoint)[2]
Blender kernel action and pose functionality.
struct bPoseChannel * BKE_pose_channel_find_name(const struct bPose *pose, const char *name)
bool CustomData_has_layer(const struct CustomData *data, int type)
void * CustomData_duplicate_referenced_layer_named(struct CustomData *data, int type, const char *name, int totelem)
Definition: customdata.cc:2995
void CustomData_validate_layer_name(const struct CustomData *data, int type, const char *name, char *outname)
support for deformation groups and hooks.
float BKE_defvert_find_weight(const struct MDeformVert *dvert, int defgroup)
Definition: deform.c:704
@ IDWALK_CB_NOP
Definition: BKE_lib_query.h:33
void(* IDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin, int cb_flag)
Definition: BKE_modifier.h:107
@ eModifierTypeFlag_EnableInEditmode
Definition: BKE_modifier.h:78
@ eModifierTypeFlag_SupportsEditmode
Definition: BKE_modifier.h:69
@ eModifierTypeFlag_AcceptsMesh
Definition: BKE_modifier.h:66
void BKE_modifier_copydata_generic(const struct ModifierData *md, struct ModifierData *md_dst, int flag)
@ eModifierTypeType_NonGeometrical
Definition: BKE_modifier.h:62
#define BLI_assert(a)
Definition: BLI_assert.h:46
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
Definition: math_matrix.c:259
void unit_m4(float m[4][4])
Definition: rct.c:1090
void translate_m4(float mat[4][4], float tx, float ty, float tz)
Definition: math_matrix.c:2318
bool invert_m4_m4(float R[4][4], const float A[4][4])
Definition: math_matrix.c:1287
void rescale_m4(float mat[4][4], const float scale[3])
Definition: math_matrix.c:2362
void mul_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:729
void copy_m4_m4(float m1[4][4], const float m2[4][4])
Definition: math_matrix.c:77
void shuffle_m4(float R[4][4], const int index[4])
Definition: math_matrix.c:247
void rotate_m4(float mat[4][4], char axis, float angle)
Definition: math_matrix.c:2325
void transpose_m4(float R[4][4])
Definition: math_matrix.c:1377
void interp_v2_v2v2(float r[2], const float a[2], const float b[2], float t)
Definition: math_vector.c:14
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE bool is_zero_v2(const float a[2]) ATTR_WARN_UNUSED_RESULT
void BLI_task_parallel_range(int start, int stop, void *userdata, TaskParallelRangeFunc func, const TaskParallelSettings *settings)
Definition: task_range.cc:94
BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings)
Definition: BLI_task.h:293
#define UNUSED(x)
#define ELEM(...)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
#define IFACE_(msgid)
void DEG_add_modifier_to_transform_relation(struct DepsNodeHandle *node_handle, const char *description)
#define MAX_CUSTOMDATA_LAYER_NAME
#define CD_MASK_MDEFORMVERT
@ CD_MLOOPUV
#define DNA_struct_default_get(struct_name)
Definition: DNA_defaults.h:29
@ eModifierType_UVWarp
@ MOD_UVWARP_INVERT_VGROUP
struct UVWarpModifierData UVWarpModifierData
Object is a sort of wrapper for general info.
@ OB_ARMATURE
PointerRNA * modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
void modifier_panel_end(uiLayout *layout, PointerRNA *ptr)
Definition: MOD_ui_common.c:91
PanelType * modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
void modifier_vgroup_ui(uiLayout *layout, PointerRNA *ptr, PointerRNA *ob_ptr, const char *vgroup_prop, const char *invert_vgroup_prop, const char *text)
PanelType * modifier_subpanel_register(ARegionType *region_type, const char *name, const char *label, PanelDrawFn draw_header, PanelDrawFn draw, PanelType *parent)
void MOD_depsgraph_update_object_bone_relation(struct DepsNodeHandle *node, Object *object, const char *bonename, const char *description)
Definition: MOD_util.c:258
void MOD_get_vgroup(Object *ob, struct Mesh *mesh, const char *name, MDeformVert **dvert, int *defgrp_index)
Definition: MOD_util.c:235
static Mesh * modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
Definition: MOD_uvwarp.c:130
static void transform_panel_draw(const bContext *UNUSED(C), Panel *panel)
Definition: MOD_uvwarp.c:290
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
Definition: MOD_uvwarp.c:236
static void matrix_from_obj_pchan(float mat[4][4], Object *ob, const char *bonename)
Definition: MOD_uvwarp.c:72
static void uv_warp_compute(void *__restrict userdata, const int i, const TaskParallelTLS *__restrict UNUSED(tls))
Definition: MOD_uvwarp.c:95
static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
Definition: MOD_uvwarp.c:228
static void uv_warp_from_mat4_pair(float uv_dst[2], const float uv_src[2], const float warp_mat[4][4])
Definition: MOD_uvwarp.c:40
struct UVWarpData UVWarpData
ModifierTypeInfo modifierType_UVWarp
Definition: MOD_uvwarp.c:310
static void panel_draw(const bContext *UNUSED(C), Panel *panel)
Definition: MOD_uvwarp.c:248
static void initData(ModifierData *md)
Definition: MOD_uvwarp.c:51
static void panelRegister(ARegionType *region_type)
Definition: MOD_uvwarp.c:303
static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks)
Definition: MOD_uvwarp.c:60
#define C
Definition: RandGen.cpp:25
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
void uiItemPointerR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, struct PointerRNA *searchptr, const char *searchpropname, const char *name, int icon)
ATTR_WARN_UNUSED_RESULT const BMLoop * l
uint col
PointerRNA RNA_pointer_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5167
bool RNA_pointer_is_null(const PointerRNA *ptr)
Definition: rna_access.c:164
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5004
Definition: DNA_ID.h:368
struct MLoop * mloop
Mesh_Runtime runtime
int totpoly
int totloop
struct MPoly * mpoly
CustomData ldata
struct Object * object
Definition: BKE_modifier.h:141
struct DepsNodeHandle * node
Definition: BKE_modifier.h:134
struct bPose * pose
float obmat[4][4]
struct uiLayout * layout
MLoop * mloop
Definition: MOD_uvwarp.c:85
MPoly * mpoly
Definition: MOD_uvwarp.c:84
MLoopUV * mloopuv
Definition: MOD_uvwarp.c:86
MDeformVert * dvert
Definition: MOD_uvwarp.c:88
bool invert_vgroup
Definition: MOD_uvwarp.c:92
int defgrp_index
Definition: MOD_uvwarp.c:89
float(* warp_mat)[4]
Definition: MOD_uvwarp.c:91
struct Object * object_dst
struct Object * object_src
float pose_mat[4][4]
#define N_(msgid)
PointerRNA * ptr
Definition: wm_files.c:3480