code cleanup: make bmesh operator names more consistant since python has access to...
[blender.git] / source / blender / modifiers / intern / MOD_cast.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  * The Original Code is Copyright (C) 2005 by the Blender Foundation.
19  * All rights reserved.
20  *
21  * Contributor(s): Daniel Dunbar
22  *                 Ton Roosendaal,
23  *                 Ben Batt,
24  *                 Brecht Van Lommel,
25  *                 Campbell Barton
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  *
29  */
30
31 /** \file blender/modifiers/intern/MOD_cast.c
32  *  \ingroup modifiers
33  */
34
35
36 #include "DNA_meshdata_types.h"
37 #include "DNA_object_types.h"
38
39 #include "BLI_math.h"
40 #include "BLI_utildefines.h"
41 #include "BLI_string.h"
42
43
44 #include "BKE_deform.h"
45 #include "BKE_DerivedMesh.h"
46 #include "BKE_modifier.h"
47
48
49 #include "depsgraph_private.h"
50
51 #include "MOD_util.h"
52
53 static void initData(ModifierData *md)
54 {
55         CastModifierData *cmd = (CastModifierData *) md;
56
57         cmd->fac = 0.5f;
58         cmd->radius = 0.0f;
59         cmd->size = 0.0f;
60         cmd->flag = MOD_CAST_X | MOD_CAST_Y | MOD_CAST_Z | MOD_CAST_SIZE_FROM_RADIUS;
61         cmd->type = MOD_CAST_TYPE_SPHERE;
62         cmd->defgrp_name[0] = '\0';
63         cmd->object = NULL;
64 }
65
66
67 static void copyData(ModifierData *md, ModifierData *target)
68 {
69         CastModifierData *cmd = (CastModifierData *) md;
70         CastModifierData *tcmd = (CastModifierData *) target;
71
72         tcmd->fac = cmd->fac;
73         tcmd->radius = cmd->radius;
74         tcmd->size = cmd->size;
75         tcmd->flag = cmd->flag;
76         tcmd->type = cmd->type;
77         tcmd->object = cmd->object;
78         BLI_strncpy(tcmd->defgrp_name, cmd->defgrp_name, sizeof(tcmd->defgrp_name));
79 }
80
81 static int isDisabled(ModifierData *md, int UNUSED(useRenderParams))
82 {
83         CastModifierData *cmd = (CastModifierData *) md;
84         short flag;
85         
86         flag = cmd->flag & (MOD_CAST_X | MOD_CAST_Y | MOD_CAST_Z);
87
88         if ((cmd->fac == 0.0f) || flag == 0) return 1;
89
90         return 0;
91 }
92
93 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
94 {
95         CastModifierData *cmd = (CastModifierData *)md;
96         CustomDataMask dataMask = 0;
97
98         /* ask for vertexgroups if we need them */
99         if (cmd->defgrp_name[0]) dataMask |= CD_MASK_MDEFORMVERT;
100
101         return dataMask;
102 }
103
104 static void foreachObjectLink(
105         ModifierData *md, Object *ob,
106         void (*walk)(void *userData, Object *ob, Object **obpoin),
107         void *userData)
108 {
109         CastModifierData *cmd = (CastModifierData *) md;
110
111         walk(userData, ob, &cmd->object);
112 }
113
114 static void updateDepgraph(ModifierData *md, DagForest *forest,
115                            struct Scene *UNUSED(scene),
116                            Object *UNUSED(ob),
117                            DagNode *obNode)
118 {
119         CastModifierData *cmd = (CastModifierData *) md;
120
121         if (cmd->object) {
122                 DagNode *curNode = dag_get_node(forest, cmd->object);
123
124                 dag_add_relation(forest, curNode, obNode, DAG_RL_OB_DATA,
125                                  "Cast Modifier");
126         }
127 }
128
129 static void sphere_do(
130         CastModifierData *cmd, Object *ob, DerivedMesh *dm,
131         float (*vertexCos)[3], int numVerts)
132 {
133         MDeformVert *dvert = NULL;
134
135         Object *ctrl_ob = NULL;
136
137         int i, defgrp_index;
138         int has_radius = 0;
139         short flag, type;
140         float fac, facm, len = 0.0f;
141         float vec[3], center[3] = {0.0f, 0.0f, 0.0f};
142         float mat[4][4], imat[4][4];
143
144         fac = cmd->fac;
145         facm = 1.0f - fac;
146
147         flag = cmd->flag;
148         type = cmd->type; /* projection type: sphere or cylinder */
149
150         if (type == MOD_CAST_TYPE_CYLINDER) 
151                 flag &= ~MOD_CAST_Z;
152
153         ctrl_ob = cmd->object;
154
155         /* spherify's center is {0, 0, 0} (the ob's own center in its local
156          * space), by default, but if the user defined a control object,
157          * we use its location, transformed to ob's local space */
158         if (ctrl_ob) {
159                 if (flag & MOD_CAST_USE_OB_TRANSFORM) {
160                         invert_m4_m4(ctrl_ob->imat, ctrl_ob->obmat);
161                         mult_m4_m4m4(mat, ctrl_ob->imat, ob->obmat);
162                         invert_m4_m4(imat, mat);
163                 }
164
165                 invert_m4_m4(ob->imat, ob->obmat);
166                 mul_v3_m4v3(center, ob->imat, ctrl_ob->obmat[3]);
167         }
168
169         /* now we check which options the user wants */
170
171         /* 1) (flag was checked in the "if (ctrl_ob)" block above) */
172         /* 2) cmd->radius > 0.0f: only the vertices within this radius from
173          * the center of the effect should be deformed */
174         if (cmd->radius > FLT_EPSILON) has_radius = 1;
175
176         /* 3) if we were given a vertex group name,
177          * only those vertices should be affected */
178         modifier_get_vgroup(ob, dm, cmd->defgrp_name, &dvert, &defgrp_index);
179
180         if (flag & MOD_CAST_SIZE_FROM_RADIUS) {
181                 len = cmd->radius;
182         }
183         else {
184                 len = cmd->size;
185         }
186
187         if (len <= 0) {
188                 for (i = 0; i < numVerts; i++) {
189                         len += len_v3v3(center, vertexCos[i]);
190                 }
191                 len /= numVerts;
192
193                 if (len == 0.0f) len = 10.0f;
194         }
195
196         /* ready to apply the effect, one vertex at a time;
197          * tiny optimization: the code is separated (with parts repeated)
198          * in two possible cases:
199          * with or w/o a vgroup. With lots of if's in the code below,
200          * further optimization's are possible, if needed */
201         if (dvert) { /* with a vgroup */
202                 MDeformVert *dv = dvert;
203                 float fac_orig = fac;
204                 for (i = 0; i < numVerts; i++, dv++) {
205                         float tmp_co[3];
206                         float weight;
207
208                         copy_v3_v3(tmp_co, vertexCos[i]);
209                         if (ctrl_ob) {
210                                 if (flag & MOD_CAST_USE_OB_TRANSFORM) {
211                                         mul_m4_v3(mat, tmp_co);
212                                 }
213                                 else {
214                                         sub_v3_v3(tmp_co, center);
215                                 }
216                         }
217
218                         copy_v3_v3(vec, tmp_co);
219
220                         if (type == MOD_CAST_TYPE_CYLINDER)
221                                 vec[2] = 0.0f;
222
223                         if (has_radius) {
224                                 if (len_v3(vec) > cmd->radius) continue;
225                         }
226
227                         weight = defvert_find_weight(dv, defgrp_index);
228                         if (weight <= 0.0f) continue;
229
230                         fac = fac_orig * weight;
231                         facm = 1.0f - fac;
232
233                         normalize_v3(vec);
234
235                         if (flag & MOD_CAST_X)
236                                 tmp_co[0] = fac * vec[0] * len + facm * tmp_co[0];
237                         if (flag & MOD_CAST_Y)
238                                 tmp_co[1] = fac * vec[1] * len + facm * tmp_co[1];
239                         if (flag & MOD_CAST_Z)
240                                 tmp_co[2] = fac * vec[2] * len + facm * tmp_co[2];
241
242                         if (ctrl_ob) {
243                                 if (flag & MOD_CAST_USE_OB_TRANSFORM) {
244                                         mul_m4_v3(imat, tmp_co);
245                                 }
246                                 else {
247                                         add_v3_v3(tmp_co, center);
248                                 }
249                         }
250
251                         copy_v3_v3(vertexCos[i], tmp_co);
252                 }
253                 return;
254         }
255
256         /* no vgroup */
257         for (i = 0; i < numVerts; i++) {
258                 float tmp_co[3];
259
260                 copy_v3_v3(tmp_co, vertexCos[i]);
261                 if (ctrl_ob) {
262                         if (flag & MOD_CAST_USE_OB_TRANSFORM) {
263                                 mul_m4_v3(mat, tmp_co);
264                         }
265                         else {
266                                 sub_v3_v3(tmp_co, center);
267                         }
268                 }
269
270                 copy_v3_v3(vec, tmp_co);
271
272                 if (type == MOD_CAST_TYPE_CYLINDER)
273                         vec[2] = 0.0f;
274
275                 if (has_radius) {
276                         if (len_v3(vec) > cmd->radius) continue;
277                 }
278
279                 normalize_v3(vec);
280
281                 if (flag & MOD_CAST_X)
282                         tmp_co[0] = fac * vec[0] * len + facm * tmp_co[0];
283                 if (flag & MOD_CAST_Y)
284                         tmp_co[1] = fac * vec[1] * len + facm * tmp_co[1];
285                 if (flag & MOD_CAST_Z)
286                         tmp_co[2] = fac * vec[2] * len + facm * tmp_co[2];
287
288                 if (ctrl_ob) {
289                         if (flag & MOD_CAST_USE_OB_TRANSFORM) {
290                                 mul_m4_v3(imat, tmp_co);
291                         }
292                         else {
293                                 add_v3_v3(tmp_co, center);
294                         }
295                 }
296
297                 copy_v3_v3(vertexCos[i], tmp_co);
298         }
299 }
300
301 static void cuboid_do(
302         CastModifierData *cmd, Object *ob, DerivedMesh *dm,
303         float (*vertexCos)[3], int numVerts)
304 {
305         MDeformVert *dvert = NULL;
306         Object *ctrl_ob = NULL;
307
308         int i, defgrp_index;
309         int has_radius = 0;
310         short flag;
311         float fac, facm;
312         float min[3], max[3], bb[8][3];
313         float center[3] = {0.0f, 0.0f, 0.0f};
314         float mat[4][4], imat[4][4];
315
316         fac = cmd->fac;
317         facm = 1.0f - fac;
318
319         flag = cmd->flag;
320
321         ctrl_ob = cmd->object;
322
323         /* now we check which options the user wants */
324
325         /* 1) (flag was checked in the "if (ctrl_ob)" block above) */
326         /* 2) cmd->radius > 0.0f: only the vertices within this radius from
327          * the center of the effect should be deformed */
328         if (cmd->radius > FLT_EPSILON) has_radius = 1;
329
330         /* 3) if we were given a vertex group name,
331          * only those vertices should be affected */
332         modifier_get_vgroup(ob, dm, cmd->defgrp_name, &dvert, &defgrp_index);
333
334         if (ctrl_ob) {
335                 if (flag & MOD_CAST_USE_OB_TRANSFORM) {
336                         invert_m4_m4(ctrl_ob->imat, ctrl_ob->obmat);
337                         mult_m4_m4m4(mat, ctrl_ob->imat, ob->obmat);
338                         invert_m4_m4(imat, mat);
339                 }
340
341                 invert_m4_m4(ob->imat, ob->obmat);
342                 mul_v3_m4v3(center, ob->imat, ctrl_ob->obmat[3]);
343         }
344
345         if ((flag & MOD_CAST_SIZE_FROM_RADIUS) && has_radius) {
346                 for (i = 0; i < 3; i++) {
347                         min[i] = -cmd->radius;
348                         max[i] = cmd->radius;
349                 }
350         }
351         else if (!(flag & MOD_CAST_SIZE_FROM_RADIUS) && cmd->size > 0) {
352                 for (i = 0; i < 3; i++) {
353                         min[i] = -cmd->size;
354                         max[i] = cmd->size;
355                 }
356         }
357         else {
358                 /* get bound box */
359                 /* We can't use the object's bound box because other modifiers
360                  * may have changed the vertex data. */
361                 INIT_MINMAX(min, max);
362
363                 /* Cast's center is the ob's own center in its local space,
364                  * by default, but if the user defined a control object, we use
365                  * its location, transformed to ob's local space. */
366                 if (ctrl_ob) {
367                         float vec[3];
368
369                         /* let the center of the ctrl_ob be part of the bound box: */
370                         minmax_v3v3_v3(min, max, center);
371
372                         for (i = 0; i < numVerts; i++) {
373                                 sub_v3_v3v3(vec, vertexCos[i], center);
374                                 minmax_v3v3_v3(min, max, vec);
375                         }
376                 }
377                 else {
378                         for (i = 0; i < numVerts; i++) {
379                                 minmax_v3v3_v3(min, max, vertexCos[i]);
380                         }
381                 }
382
383                 /* we want a symmetric bound box around the origin */
384                 if (fabsf(min[0]) > fabsf(max[0])) max[0] = fabsf(min[0]);
385                 if (fabsf(min[1]) > fabsf(max[1])) max[1] = fabsf(min[1]);
386                 if (fabsf(min[2]) > fabsf(max[2])) max[2] = fabsf(min[2]);
387                 min[0] = -max[0];
388                 min[1] = -max[1];
389                 min[2] = -max[2];
390         }
391
392         /* building our custom bounding box */
393         bb[0][0] = bb[2][0] = bb[4][0] = bb[6][0] = min[0];
394         bb[1][0] = bb[3][0] = bb[5][0] = bb[7][0] = max[0];
395         bb[0][1] = bb[1][1] = bb[4][1] = bb[5][1] = min[1];
396         bb[2][1] = bb[3][1] = bb[6][1] = bb[7][1] = max[1];
397         bb[0][2] = bb[1][2] = bb[2][2] = bb[3][2] = min[2];
398         bb[4][2] = bb[5][2] = bb[6][2] = bb[7][2] = max[2];
399
400         /* ready to apply the effect, one vertex at a time;
401          * tiny optimization: the code is separated (with parts repeated)
402          * in two possible cases:
403          * with or w/o a vgroup. With lots of if's in the code below,
404          * further optimization's are possible, if needed */
405         if (dvert) { /* with a vgroup */
406                 float fac_orig = fac;
407                 for (i = 0; i < numVerts; i++) {
408                         MDeformWeight *dw = NULL;
409                         int j, octant, coord;
410                         float d[3], dmax, apex[3], fbb;
411                         float tmp_co[3];
412
413                         copy_v3_v3(tmp_co, vertexCos[i]);
414                         if (ctrl_ob) {
415                                 if (flag & MOD_CAST_USE_OB_TRANSFORM) {
416                                         mul_m4_v3(mat, tmp_co);
417                                 }
418                                 else {
419                                         sub_v3_v3(tmp_co, center);
420                                 }
421                         }
422
423                         if (has_radius) {
424                                 if (fabsf(tmp_co[0]) > cmd->radius ||
425                                     fabsf(tmp_co[1]) > cmd->radius ||
426                                     fabsf(tmp_co[2]) > cmd->radius)
427                                 {
428                                         continue;
429                                 }
430                         }
431
432                         for (j = 0; j < dvert[i].totweight; ++j) {
433                                 if (dvert[i].dw[j].def_nr == defgrp_index) {
434                                         dw = &dvert[i].dw[j];
435                                         break;
436                                 }
437                         }
438                         if (!dw) continue;
439
440                         fac = fac_orig * dw->weight;
441                         facm = 1.0f - fac;
442
443                         /* The algo used to project the vertices to their
444                          * bounding box (bb) is pretty simple:
445                          * for each vertex v:
446                          * 1) find in which octant v is in;
447                          * 2) find which outer "wall" of that octant is closer to v;
448                          * 3) calculate factor (var fbb) to project v to that wall;
449                          * 4) project. */
450
451                         /* find in which octant this vertex is in */
452                         octant = 0;
453                         if (tmp_co[0] > 0.0f) octant += 1;
454                         if (tmp_co[1] > 0.0f) octant += 2;
455                         if (tmp_co[2] > 0.0f) octant += 4;
456
457                         /* apex is the bb's vertex at the chosen octant */
458                         copy_v3_v3(apex, bb[octant]);
459
460                         /* find which bb plane is closest to this vertex ... */
461                         d[0] = tmp_co[0] / apex[0];
462                         d[1] = tmp_co[1] / apex[1];
463                         d[2] = tmp_co[2] / apex[2];
464
465                         /* ... (the closest has the higher (closer to 1) d value) */
466                         dmax = d[0];
467                         coord = 0;
468                         if (d[1] > dmax) {
469                                 dmax = d[1];
470                                 coord = 1;
471                         }
472                         if (d[2] > dmax) {
473                                 /* dmax = d[2]; */ /* commented, we don't need it */
474                                 coord = 2;
475                         }
476
477                         /* ok, now we know which coordinate of the vertex to use */
478
479                         if (fabsf(tmp_co[coord]) < FLT_EPSILON) /* avoid division by zero */
480                                 continue;
481
482                         /* finally, this is the factor we wanted, to project the vertex
483                          * to its bounding box (bb) */
484                         fbb = apex[coord] / tmp_co[coord];
485
486                         /* calculate the new vertex position */
487                         if (flag & MOD_CAST_X)
488                                 tmp_co[0] = facm * tmp_co[0] + fac * tmp_co[0] * fbb;
489                         if (flag & MOD_CAST_Y)
490                                 tmp_co[1] = facm * tmp_co[1] + fac * tmp_co[1] * fbb;
491                         if (flag & MOD_CAST_Z)
492                                 tmp_co[2] = facm * tmp_co[2] + fac * tmp_co[2] * fbb;
493
494                         if (ctrl_ob) {
495                                 if (flag & MOD_CAST_USE_OB_TRANSFORM) {
496                                         mul_m4_v3(imat, tmp_co);
497                                 }
498                                 else {
499                                         add_v3_v3(tmp_co, center);
500                                 }
501                         }
502
503                         copy_v3_v3(vertexCos[i], tmp_co);
504                 }
505                 return;
506         }
507
508         /* no vgroup (check previous case for comments about the code) */
509         for (i = 0; i < numVerts; i++) {
510                 int octant, coord;
511                 float d[3], dmax, fbb, apex[3];
512                 float tmp_co[3];
513
514                 copy_v3_v3(tmp_co, vertexCos[i]);
515                 if (ctrl_ob) {
516                         if (flag & MOD_CAST_USE_OB_TRANSFORM) {
517                                 mul_m4_v3(mat, tmp_co);
518                         }
519                         else {
520                                 sub_v3_v3(tmp_co, center);
521                         }
522                 }
523
524                 if (has_radius) {
525                         if (fabsf(tmp_co[0]) > cmd->radius ||
526                             fabsf(tmp_co[1]) > cmd->radius ||
527                             fabsf(tmp_co[2]) > cmd->radius)
528                         {
529                                 continue;
530                         }
531                 }
532
533                 octant = 0;
534                 if (tmp_co[0] > 0.0f) octant += 1;
535                 if (tmp_co[1] > 0.0f) octant += 2;
536                 if (tmp_co[2] > 0.0f) octant += 4;
537
538                 copy_v3_v3(apex, bb[octant]);
539
540                 d[0] = tmp_co[0] / apex[0];
541                 d[1] = tmp_co[1] / apex[1];
542                 d[2] = tmp_co[2] / apex[2];
543
544                 dmax = d[0];
545                 coord = 0;
546                 if (d[1] > dmax) {
547                         dmax = d[1];
548                         coord = 1;
549                 }
550                 if (d[2] > dmax) {
551                         /* dmax = d[2]; */ /* commented, we don't need it */
552                         coord = 2;
553                 }
554
555                 if (fabsf(tmp_co[coord]) < FLT_EPSILON)
556                         continue;
557
558                 fbb = apex[coord] / tmp_co[coord];
559
560                 if (flag & MOD_CAST_X)
561                         tmp_co[0] = facm * tmp_co[0] + fac * tmp_co[0] * fbb;
562                 if (flag & MOD_CAST_Y)
563                         tmp_co[1] = facm * tmp_co[1] + fac * tmp_co[1] * fbb;
564                 if (flag & MOD_CAST_Z)
565                         tmp_co[2] = facm * tmp_co[2] + fac * tmp_co[2] * fbb;
566
567                 if (ctrl_ob) {
568                         if (flag & MOD_CAST_USE_OB_TRANSFORM) {
569                                 mul_m4_v3(imat, tmp_co);
570                         }
571                         else {
572                                 add_v3_v3(tmp_co, center);
573                         }
574                 }
575
576                 copy_v3_v3(vertexCos[i], tmp_co);
577         }
578 }
579
580 static void deformVerts(ModifierData *md, Object *ob,
581                         DerivedMesh *derivedData,
582                         float (*vertexCos)[3],
583                         int numVerts,
584                         ModifierApplyFlag UNUSED(flag))
585 {
586         DerivedMesh *dm = NULL;
587         CastModifierData *cmd = (CastModifierData *)md;
588
589         dm = get_dm(ob, NULL, derivedData, NULL, 0);
590
591         if (cmd->type == MOD_CAST_TYPE_CUBOID) {
592                 cuboid_do(cmd, ob, dm, vertexCos, numVerts);
593         }
594         else { /* MOD_CAST_TYPE_SPHERE or MOD_CAST_TYPE_CYLINDER */
595                 sphere_do(cmd, ob, dm, vertexCos, numVerts);
596         }
597
598         if (dm != derivedData)
599                 dm->release(dm);
600 }
601
602 static void deformVertsEM(
603         ModifierData *md, Object *ob, struct BMEditMesh *editData,
604         DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
605 {
606         DerivedMesh *dm = get_dm(ob, editData, derivedData, NULL, 0);
607         CastModifierData *cmd = (CastModifierData *)md;
608
609         if (cmd->type == MOD_CAST_TYPE_CUBOID) {
610                 cuboid_do(cmd, ob, dm, vertexCos, numVerts);
611         }
612         else { /* MOD_CAST_TYPE_SPHERE or MOD_CAST_TYPE_CYLINDER */
613                 sphere_do(cmd, ob, dm, vertexCos, numVerts);
614         }
615
616         if (dm != derivedData)
617                 dm->release(dm);
618 }
619
620
621 ModifierTypeInfo modifierType_Cast = {
622         /* name */              "Cast",
623         /* structName */        "CastModifierData",
624         /* structSize */        sizeof(CastModifierData),
625         /* type */              eModifierTypeType_OnlyDeform,
626         /* flags */             eModifierTypeFlag_AcceptsCVs |
627                                 eModifierTypeFlag_SupportsEditmode,
628
629         /* copyData */          copyData,
630         /* deformVerts */       deformVerts,
631         /* deformMatrices */    NULL,
632         /* deformVertsEM */     deformVertsEM,
633         /* deformMatricesEM */  NULL,
634         /* applyModifier */     NULL,
635         /* applyModifierEM */   NULL,
636         /* initData */          initData,
637         /* requiredDataMask */  requiredDataMask,
638         /* freeData */          NULL,
639         /* isDisabled */        isDisabled,
640         /* updateDepgraph */    updateDepgraph,
641         /* dependsOnTime */     NULL,
642         /* dependsOnNormals */  NULL,
643         /* foreachObjectLink */ foreachObjectLink,
644         /* foreachIDLink */     NULL,
645         /* foreachTexLink */    NULL,
646 };