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  * The Original Code is Copyright (C) 2005 by the Blender Foundation.
17  * All rights reserved.
18  */
19 
20 /** \file
21  * \ingroup modifiers
22  */
23 
24 #include "BLI_utildefines.h"
25 
26 #include "BLI_math.h"
27 
28 #include "BLT_translation.h"
29 
30 #include "DNA_defaults.h"
31 #include "DNA_mesh_types.h"
32 #include "DNA_meshdata_types.h"
33 #include "DNA_object_types.h"
34 #include "DNA_screen_types.h"
35 
36 #include "BKE_context.h"
37 #include "BKE_deform.h"
38 #include "BKE_editmesh.h"
39 #include "BKE_lib_id.h"
40 #include "BKE_lib_query.h"
41 #include "BKE_mesh.h"
42 #include "BKE_mesh_wrapper.h"
43 #include "BKE_modifier.h"
44 #include "BKE_screen.h"
45 
46 #include "UI_interface.h"
47 #include "UI_resources.h"
48 
49 #include "RNA_access.h"
50 
51 #include "DEG_depsgraph_query.h"
52 
53 #include "MOD_ui_common.h"
54 #include "MOD_util.h"
55 
initData(ModifierData * md)56 static void initData(ModifierData *md)
57 {
58   CastModifierData *cmd = (CastModifierData *)md;
59 
60   BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(cmd, modifier));
61 
62   MEMCPY_STRUCT_AFTER(cmd, DNA_struct_default_get(CastModifierData), modifier);
63 }
64 
isDisabled(const struct Scene * UNUSED (scene),ModifierData * md,bool UNUSED (useRenderParams))65 static bool isDisabled(const struct Scene *UNUSED(scene),
66                        ModifierData *md,
67                        bool UNUSED(useRenderParams))
68 {
69   CastModifierData *cmd = (CastModifierData *)md;
70   short flag;
71 
72   flag = cmd->flag & (MOD_CAST_X | MOD_CAST_Y | MOD_CAST_Z);
73 
74   if ((cmd->fac == 0.0f) || flag == 0) {
75     return true;
76   }
77 
78   return false;
79 }
80 
requiredDataMask(Object * UNUSED (ob),ModifierData * md,CustomData_MeshMasks * r_cddata_masks)81 static void requiredDataMask(Object *UNUSED(ob),
82                              ModifierData *md,
83                              CustomData_MeshMasks *r_cddata_masks)
84 {
85   CastModifierData *cmd = (CastModifierData *)md;
86 
87   /* ask for vertexgroups if we need them */
88   if (cmd->defgrp_name[0] != '\0') {
89     r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
90   }
91 }
92 
foreachIDLink(ModifierData * md,Object * ob,IDWalkFunc walk,void * userData)93 static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
94 {
95   CastModifierData *cmd = (CastModifierData *)md;
96 
97   walk(userData, ob, (ID **)&cmd->object, IDWALK_CB_NOP);
98 }
99 
updateDepsgraph(ModifierData * md,const ModifierUpdateDepsgraphContext * ctx)100 static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
101 {
102   CastModifierData *cmd = (CastModifierData *)md;
103   if (cmd->object != NULL) {
104     DEG_add_object_relation(ctx->node, cmd->object, DEG_OB_COMP_TRANSFORM, "Cast Modifier");
105     DEG_add_modifier_to_transform_relation(ctx->node, "Cast Modifier");
106   }
107 }
108 
sphere_do(CastModifierData * cmd,const ModifierEvalContext * UNUSED (ctx),Object * ob,Mesh * mesh,float (* vertexCos)[3],int numVerts)109 static void sphere_do(CastModifierData *cmd,
110                       const ModifierEvalContext *UNUSED(ctx),
111                       Object *ob,
112                       Mesh *mesh,
113                       float (*vertexCos)[3],
114                       int numVerts)
115 {
116   MDeformVert *dvert = NULL;
117   const bool invert_vgroup = (cmd->flag & MOD_CAST_INVERT_VGROUP) != 0;
118 
119   Object *ctrl_ob = NULL;
120 
121   int i, defgrp_index;
122   bool has_radius = false;
123   short flag, type;
124   float len = 0.0f;
125   float fac = cmd->fac;
126   float facm = 1.0f - fac;
127   const float fac_orig = fac;
128   float vec[3], center[3] = {0.0f, 0.0f, 0.0f};
129   float mat[4][4], imat[4][4];
130 
131   flag = cmd->flag;
132   type = cmd->type; /* projection type: sphere or cylinder */
133 
134   if (type == MOD_CAST_TYPE_CYLINDER) {
135     flag &= ~MOD_CAST_Z;
136   }
137 
138   ctrl_ob = cmd->object;
139 
140   /* spherify's center is {0, 0, 0} (the ob's own center in its local
141    * space), by default, but if the user defined a control object,
142    * we use its location, transformed to ob's local space */
143   if (ctrl_ob) {
144     if (flag & MOD_CAST_USE_OB_TRANSFORM) {
145       invert_m4_m4(imat, ctrl_ob->obmat);
146       mul_m4_m4m4(mat, imat, ob->obmat);
147       invert_m4_m4(imat, mat);
148     }
149 
150     invert_m4_m4(ob->imat, ob->obmat);
151     mul_v3_m4v3(center, ob->imat, ctrl_ob->obmat[3]);
152   }
153 
154   /* now we check which options the user wants */
155 
156   /* 1) (flag was checked in the "if (ctrl_ob)" block above) */
157   /* 2) cmd->radius > 0.0f: only the vertices within this radius from
158    * the center of the effect should be deformed */
159   if (cmd->radius > FLT_EPSILON) {
160     has_radius = 1;
161   }
162 
163   /* 3) if we were given a vertex group name,
164    * only those vertices should be affected */
165   if (cmd->defgrp_name[0] != '\0') {
166     MOD_get_vgroup(ob, mesh, cmd->defgrp_name, &dvert, &defgrp_index);
167   }
168 
169   if (flag & MOD_CAST_SIZE_FROM_RADIUS) {
170     len = cmd->radius;
171   }
172   else {
173     len = cmd->size;
174   }
175 
176   if (len <= 0) {
177     for (i = 0; i < numVerts; i++) {
178       len += len_v3v3(center, vertexCos[i]);
179     }
180     len /= numVerts;
181 
182     if (len == 0.0f) {
183       len = 10.0f;
184     }
185   }
186 
187   for (i = 0; i < numVerts; i++) {
188     float tmp_co[3];
189 
190     copy_v3_v3(tmp_co, vertexCos[i]);
191     if (ctrl_ob) {
192       if (flag & MOD_CAST_USE_OB_TRANSFORM) {
193         mul_m4_v3(mat, tmp_co);
194       }
195       else {
196         sub_v3_v3(tmp_co, center);
197       }
198     }
199 
200     copy_v3_v3(vec, tmp_co);
201 
202     if (type == MOD_CAST_TYPE_CYLINDER) {
203       vec[2] = 0.0f;
204     }
205 
206     if (has_radius) {
207       if (len_v3(vec) > cmd->radius) {
208         continue;
209       }
210     }
211 
212     if (dvert) {
213       const float weight = invert_vgroup ?
214                                1.0f - BKE_defvert_find_weight(&dvert[i], defgrp_index) :
215                                BKE_defvert_find_weight(&dvert[i], defgrp_index);
216 
217       if (weight == 0.0f) {
218         continue;
219       }
220 
221       fac = fac_orig * weight;
222       facm = 1.0f - fac;
223     }
224 
225     normalize_v3(vec);
226 
227     if (flag & MOD_CAST_X) {
228       tmp_co[0] = fac * vec[0] * len + facm * tmp_co[0];
229     }
230     if (flag & MOD_CAST_Y) {
231       tmp_co[1] = fac * vec[1] * len + facm * tmp_co[1];
232     }
233     if (flag & MOD_CAST_Z) {
234       tmp_co[2] = fac * vec[2] * len + facm * tmp_co[2];
235     }
236 
237     if (ctrl_ob) {
238       if (flag & MOD_CAST_USE_OB_TRANSFORM) {
239         mul_m4_v3(imat, tmp_co);
240       }
241       else {
242         add_v3_v3(tmp_co, center);
243       }
244     }
245 
246     copy_v3_v3(vertexCos[i], tmp_co);
247   }
248 }
249 
cuboid_do(CastModifierData * cmd,const ModifierEvalContext * UNUSED (ctx),Object * ob,Mesh * mesh,float (* vertexCos)[3],int numVerts)250 static void cuboid_do(CastModifierData *cmd,
251                       const ModifierEvalContext *UNUSED(ctx),
252                       Object *ob,
253                       Mesh *mesh,
254                       float (*vertexCos)[3],
255                       int numVerts)
256 {
257   MDeformVert *dvert = NULL;
258   int defgrp_index;
259   const bool invert_vgroup = (cmd->flag & MOD_CAST_INVERT_VGROUP) != 0;
260 
261   Object *ctrl_ob = NULL;
262 
263   int i;
264   bool has_radius = false;
265   short flag;
266   float fac = cmd->fac;
267   float facm = 1.0f - fac;
268   const float fac_orig = fac;
269   float min[3], max[3], bb[8][3];
270   float center[3] = {0.0f, 0.0f, 0.0f};
271   float mat[4][4], imat[4][4];
272 
273   flag = cmd->flag;
274 
275   ctrl_ob = cmd->object;
276 
277   /* now we check which options the user wants */
278 
279   /* 1) (flag was checked in the "if (ctrl_ob)" block above) */
280   /* 2) cmd->radius > 0.0f: only the vertices within this radius from
281    * the center of the effect should be deformed */
282   if (cmd->radius > FLT_EPSILON) {
283     has_radius = 1;
284   }
285 
286   /* 3) if we were given a vertex group name,
287    * only those vertices should be affected */
288   if (cmd->defgrp_name[0] != '\0') {
289     MOD_get_vgroup(ob, mesh, cmd->defgrp_name, &dvert, &defgrp_index);
290   }
291 
292   if (ctrl_ob) {
293     if (flag & MOD_CAST_USE_OB_TRANSFORM) {
294       invert_m4_m4(imat, ctrl_ob->obmat);
295       mul_m4_m4m4(mat, imat, ob->obmat);
296       invert_m4_m4(imat, mat);
297     }
298 
299     invert_m4_m4(ob->imat, ob->obmat);
300     mul_v3_m4v3(center, ob->imat, ctrl_ob->obmat[3]);
301   }
302 
303   if ((flag & MOD_CAST_SIZE_FROM_RADIUS) && has_radius) {
304     for (i = 0; i < 3; i++) {
305       min[i] = -cmd->radius;
306       max[i] = cmd->radius;
307     }
308   }
309   else if (!(flag & MOD_CAST_SIZE_FROM_RADIUS) && cmd->size > 0) {
310     for (i = 0; i < 3; i++) {
311       min[i] = -cmd->size;
312       max[i] = cmd->size;
313     }
314   }
315   else {
316     /* get bound box */
317     /* We can't use the object's bound box because other modifiers
318      * may have changed the vertex data. */
319     INIT_MINMAX(min, max);
320 
321     /* Cast's center is the ob's own center in its local space,
322      * by default, but if the user defined a control object, we use
323      * its location, transformed to ob's local space. */
324     if (ctrl_ob) {
325       float vec[3];
326 
327       /* let the center of the ctrl_ob be part of the bound box: */
328       minmax_v3v3_v3(min, max, center);
329 
330       for (i = 0; i < numVerts; i++) {
331         sub_v3_v3v3(vec, vertexCos[i], center);
332         minmax_v3v3_v3(min, max, vec);
333       }
334     }
335     else {
336       for (i = 0; i < numVerts; i++) {
337         minmax_v3v3_v3(min, max, vertexCos[i]);
338       }
339     }
340 
341     /* we want a symmetric bound box around the origin */
342     if (fabsf(min[0]) > fabsf(max[0])) {
343       max[0] = fabsf(min[0]);
344     }
345     if (fabsf(min[1]) > fabsf(max[1])) {
346       max[1] = fabsf(min[1]);
347     }
348     if (fabsf(min[2]) > fabsf(max[2])) {
349       max[2] = fabsf(min[2]);
350     }
351     min[0] = -max[0];
352     min[1] = -max[1];
353     min[2] = -max[2];
354   }
355 
356   /* building our custom bounding box */
357   bb[0][0] = bb[2][0] = bb[4][0] = bb[6][0] = min[0];
358   bb[1][0] = bb[3][0] = bb[5][0] = bb[7][0] = max[0];
359   bb[0][1] = bb[1][1] = bb[4][1] = bb[5][1] = min[1];
360   bb[2][1] = bb[3][1] = bb[6][1] = bb[7][1] = max[1];
361   bb[0][2] = bb[1][2] = bb[2][2] = bb[3][2] = min[2];
362   bb[4][2] = bb[5][2] = bb[6][2] = bb[7][2] = max[2];
363 
364   /* ready to apply the effect, one vertex at a time */
365   for (i = 0; i < numVerts; i++) {
366     int octant, coord;
367     float d[3], dmax, apex[3], fbb;
368     float tmp_co[3];
369 
370     copy_v3_v3(tmp_co, vertexCos[i]);
371     if (ctrl_ob) {
372       if (flag & MOD_CAST_USE_OB_TRANSFORM) {
373         mul_m4_v3(mat, tmp_co);
374       }
375       else {
376         sub_v3_v3(tmp_co, center);
377       }
378     }
379 
380     if (has_radius) {
381       if (fabsf(tmp_co[0]) > cmd->radius || fabsf(tmp_co[1]) > cmd->radius ||
382           fabsf(tmp_co[2]) > cmd->radius) {
383         continue;
384       }
385     }
386 
387     if (dvert) {
388       const float weight = invert_vgroup ?
389                                1.0f - BKE_defvert_find_weight(&dvert[i], defgrp_index) :
390                                BKE_defvert_find_weight(&dvert[i], defgrp_index);
391 
392       if (weight == 0.0f) {
393         continue;
394       }
395 
396       fac = fac_orig * weight;
397       facm = 1.0f - fac;
398     }
399 
400     /* The algo used to project the vertices to their
401      * bounding box (bb) is pretty simple:
402      * for each vertex v:
403      * 1) find in which octant v is in;
404      * 2) find which outer "wall" of that octant is closer to v;
405      * 3) calculate factor (var fbb) to project v to that wall;
406      * 4) project. */
407 
408     /* find in which octant this vertex is in */
409     octant = 0;
410     if (tmp_co[0] > 0.0f) {
411       octant += 1;
412     }
413     if (tmp_co[1] > 0.0f) {
414       octant += 2;
415     }
416     if (tmp_co[2] > 0.0f) {
417       octant += 4;
418     }
419 
420     /* apex is the bb's vertex at the chosen octant */
421     copy_v3_v3(apex, bb[octant]);
422 
423     /* find which bb plane is closest to this vertex ... */
424     d[0] = tmp_co[0] / apex[0];
425     d[1] = tmp_co[1] / apex[1];
426     d[2] = tmp_co[2] / apex[2];
427 
428     /* ... (the closest has the higher (closer to 1) d value) */
429     dmax = d[0];
430     coord = 0;
431     if (d[1] > dmax) {
432       dmax = d[1];
433       coord = 1;
434     }
435     if (d[2] > dmax) {
436       /* dmax = d[2]; */ /* commented, we don't need it */
437       coord = 2;
438     }
439 
440     /* ok, now we know which coordinate of the vertex to use */
441 
442     if (fabsf(tmp_co[coord]) < FLT_EPSILON) { /* avoid division by zero */
443       continue;
444     }
445 
446     /* finally, this is the factor we wanted, to project the vertex
447      * to its bounding box (bb) */
448     fbb = apex[coord] / tmp_co[coord];
449 
450     /* calculate the new vertex position */
451     if (flag & MOD_CAST_X) {
452       tmp_co[0] = facm * tmp_co[0] + fac * tmp_co[0] * fbb;
453     }
454     if (flag & MOD_CAST_Y) {
455       tmp_co[1] = facm * tmp_co[1] + fac * tmp_co[1] * fbb;
456     }
457     if (flag & MOD_CAST_Z) {
458       tmp_co[2] = facm * tmp_co[2] + fac * tmp_co[2] * fbb;
459     }
460 
461     if (ctrl_ob) {
462       if (flag & MOD_CAST_USE_OB_TRANSFORM) {
463         mul_m4_v3(imat, tmp_co);
464       }
465       else {
466         add_v3_v3(tmp_co, center);
467       }
468     }
469 
470     copy_v3_v3(vertexCos[i], tmp_co);
471   }
472 }
473 
deformVerts(ModifierData * md,const ModifierEvalContext * ctx,Mesh * mesh,float (* vertexCos)[3],int numVerts)474 static void deformVerts(ModifierData *md,
475                         const ModifierEvalContext *ctx,
476                         Mesh *mesh,
477                         float (*vertexCos)[3],
478                         int numVerts)
479 {
480   CastModifierData *cmd = (CastModifierData *)md;
481   Mesh *mesh_src = NULL;
482 
483   if (ctx->object->type == OB_MESH && cmd->defgrp_name[0] != '\0') {
484     /* mesh_src is only needed for vgroups. */
485     mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false);
486   }
487 
488   if (cmd->type == MOD_CAST_TYPE_CUBOID) {
489     cuboid_do(cmd, ctx, ctx->object, mesh_src, vertexCos, numVerts);
490   }
491   else { /* MOD_CAST_TYPE_SPHERE or MOD_CAST_TYPE_CYLINDER */
492     sphere_do(cmd, ctx, ctx->object, mesh_src, vertexCos, numVerts);
493   }
494 
495   if (!ELEM(mesh_src, NULL, mesh)) {
496     BKE_id_free(NULL, mesh_src);
497   }
498 }
499 
deformVertsEM(ModifierData * md,const ModifierEvalContext * ctx,struct BMEditMesh * editData,Mesh * mesh,float (* vertexCos)[3],int numVerts)500 static void deformVertsEM(ModifierData *md,
501                           const ModifierEvalContext *ctx,
502                           struct BMEditMesh *editData,
503                           Mesh *mesh,
504                           float (*vertexCos)[3],
505                           int numVerts)
506 {
507   CastModifierData *cmd = (CastModifierData *)md;
508   Mesh *mesh_src = NULL;
509 
510   if (cmd->defgrp_name[0] != '\0') {
511     mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false);
512   }
513 
514   if (mesh && mesh->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA) {
515     BLI_assert(mesh->totvert == numVerts);
516   }
517 
518   /* TODO(Campbell): use edit-mode data only (remove this line). */
519   if (mesh_src != NULL) {
520     BKE_mesh_wrapper_ensure_mdata(mesh_src);
521   }
522 
523   if (cmd->type == MOD_CAST_TYPE_CUBOID) {
524     cuboid_do(cmd, ctx, ctx->object, mesh_src, vertexCos, numVerts);
525   }
526   else { /* MOD_CAST_TYPE_SPHERE or MOD_CAST_TYPE_CYLINDER */
527     sphere_do(cmd, ctx, ctx->object, mesh_src, vertexCos, numVerts);
528   }
529 
530   if (!ELEM(mesh_src, NULL, mesh)) {
531     BKE_id_free(NULL, mesh_src);
532   }
533 }
534 
panel_draw(const bContext * UNUSED (C),Panel * panel)535 static void panel_draw(const bContext *UNUSED(C), Panel *panel)
536 {
537   uiLayout *row;
538   uiLayout *layout = panel->layout;
539   int toggles_flag = UI_ITEM_R_TOGGLE | UI_ITEM_R_FORCE_BLANK_DECORATE;
540 
541   PointerRNA ob_ptr;
542   PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
543 
544   PointerRNA cast_object_ptr = RNA_pointer_get(ptr, "object");
545 
546   uiLayoutSetPropSep(layout, true);
547 
548   uiItemR(layout, ptr, "cast_type", 0, NULL, ICON_NONE);
549 
550   row = uiLayoutRowWithHeading(layout, true, IFACE_("Axis"));
551   uiItemR(row, ptr, "use_x", toggles_flag, NULL, ICON_NONE);
552   uiItemR(row, ptr, "use_y", toggles_flag, NULL, ICON_NONE);
553   uiItemR(row, ptr, "use_z", toggles_flag, NULL, ICON_NONE);
554 
555   uiItemR(layout, ptr, "factor", 0, NULL, ICON_NONE);
556   uiItemR(layout, ptr, "radius", 0, NULL, ICON_NONE);
557   uiItemR(layout, ptr, "size", 0, NULL, ICON_NONE);
558   uiItemR(layout, ptr, "use_radius_as_size", 0, NULL, ICON_NONE);
559 
560   modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL);
561 
562   uiItemR(layout, ptr, "object", 0, NULL, ICON_NONE);
563   if (!RNA_pointer_is_null(&cast_object_ptr)) {
564     uiItemR(layout, ptr, "use_transform", 0, NULL, ICON_NONE);
565   }
566 
567   modifier_panel_end(layout, ptr);
568 }
569 
panelRegister(ARegionType * region_type)570 static void panelRegister(ARegionType *region_type)
571 {
572   modifier_panel_register(region_type, eModifierType_Cast, panel_draw);
573 }
574 
575 ModifierTypeInfo modifierType_Cast = {
576     /* name */ "Cast",
577     /* structName */ "CastModifierData",
578     /* structSize */ sizeof(CastModifierData),
579     /* srna */ &RNA_CastModifier,
580     /* type */ eModifierTypeType_OnlyDeform,
581     /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsVertexCosOnly |
582         eModifierTypeFlag_SupportsEditmode,
583     /* icon */ ICON_MOD_CAST,
584 
585     /* copyData */ BKE_modifier_copydata_generic,
586 
587     /* deformVerts */ deformVerts,
588     /* deformMatrices */ NULL,
589     /* deformVertsEM */ deformVertsEM,
590     /* deformMatricesEM */ NULL,
591     /* modifyMesh */ NULL,
592     /* modifyHair */ NULL,
593     /* modifyPointCloud */ NULL,
594     /* modifyVolume */ NULL,
595 
596     /* initData */ initData,
597     /* requiredDataMask */ requiredDataMask,
598     /* freeData */ NULL,
599     /* isDisabled */ isDisabled,
600     /* updateDepsgraph */ updateDepsgraph,
601     /* dependsOnTime */ NULL,
602     /* dependsOnNormals */ NULL,
603     /* foreachIDLink */ foreachIDLink,
604     /* foreachTexLink */ NULL,
605     /* freeRuntimeData */ NULL,
606     /* panelRegister */ panelRegister,
607     /* blendWrite */ NULL,
608     /* blendRead */ NULL,
609 };
610