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