remove mesh and object arguments from bmesh operators, these are stored within the...
[blender.git] / source / blender / modifiers / intern / MOD_weightvg_util.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software  Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2011 by Bastien Montagne.
21  * All rights reserved.
22  *
23  * Contributor(s): None yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  *
27  */
28
29 /*
30  * XXX I'd like to make modified weights visible in WeightPaint mode,
31  *     but couldn't figure a way to do this...
32  *     Maybe this will need changes in mesh_calc_modifiers (DerivedMesh.c)?
33  *     Or the WeightPaint mode code itself?
34  */
35
36 #include "BLI_math.h"
37 #include "BLI_rand.h"
38 #include "BLI_string.h"
39 #include "BLI_utildefines.h"
40
41 #include "DNA_color_types.h"      /* CurveMapping. */
42 #include "DNA_mesh_types.h"
43 #include "DNA_meshdata_types.h"
44 #include "DNA_modifier_types.h"
45 #include "DNA_object_types.h"
46
47 #include "BKE_cdderivedmesh.h"
48 #include "BKE_colortools.h"       /* CurveMapping. */
49 #include "BKE_deform.h"
50 #include "BKE_mesh.h"
51 #include "BKE_modifier.h"
52 #include "BKE_texture.h"          /* Texture masking. */
53
54 #include "depsgraph_private.h"
55 #include "MEM_guardedalloc.h"
56 #include "MOD_util.h"
57 #include "MOD_weightvg_util.h"
58 #include "RE_shader_ext.h"        /* Texture masking. */
59
60 /* Maps new_w weights in place, using either one of the predifined functions, or a custom curve.
61  * Return values are in new_w.
62  * If indices is not NULL, it must be a table of same length as org_w and new_w, mapping to the real
63  * vertex index (in case the weight tables do not cover the whole vertices...).
64  * cmap might be NULL, in which case curve mapping mode will return unmodified data.
65  */
66 void weightvg_do_map(int num, float *new_w, short falloff_type, CurveMapping *cmap)
67 {
68         int i;
69
70         /* Return immediately, if we have nothing to do! */
71         /* Also security checks... */
72         if(((falloff_type == MOD_WVG_MAPPING_CURVE) && (cmap == NULL))
73                 || !ELEM7(falloff_type, MOD_WVG_MAPPING_CURVE, MOD_WVG_MAPPING_SHARP, MOD_WVG_MAPPING_SMOOTH,
74                           MOD_WVG_MAPPING_ROOT, MOD_WVG_MAPPING_SPHERE, MOD_WVG_MAPPING_RANDOM,
75                           MOD_WVG_MAPPING_STEP))
76                 return;
77
78         /* Map each weight (vertex) to its new value, accordingly to the chosen mode. */
79         for(i = 0; i < num; ++i) {
80                 float fac = new_w[i];
81
82                 /* Code borrowed from the warp modifier. */
83                 /* Closely matches PROP_SMOOTH and similar. */
84                 switch(falloff_type) {
85                 case MOD_WVG_MAPPING_CURVE:
86                         fac = curvemapping_evaluateF(cmap, 0, fac);
87                         break;
88                 case MOD_WVG_MAPPING_SHARP:
89                         fac = fac*fac;
90                         break;
91                 case MOD_WVG_MAPPING_SMOOTH:
92                         fac = 3.0f*fac*fac - 2.0f*fac*fac*fac;
93                         break;
94                 case MOD_WVG_MAPPING_ROOT:
95                         fac = (float)sqrt(fac);
96                         break;
97                 case MOD_WVG_MAPPING_SPHERE:
98                         fac = (float)sqrt(2*fac - fac * fac);
99                         break;
100                 case MOD_WVG_MAPPING_RANDOM:
101                         BLI_srand(BLI_rand()); /* random seed */
102                         fac = BLI_frand()*fac;
103                         break;
104                 case MOD_WVG_MAPPING_STEP:
105                         fac = (fac >= 0.5f)?1.0f:0.0f;
106                         break;
107                 }
108
109                 new_w[i] = fac;
110         }
111 }
112
113 /* Applies new_w weights to org_w ones, using either a texture, vgroup or constant value as factor.
114  * Return values are in org_w.
115  * If indices is not NULL, it must be a table of same length as org_w and new_w, mapping to the real
116  * vertex index (in case the weight tables do not cover the whole vertices...).
117  * XXX The standard “factor” value is assumed in [0.0, 1.0] range. Else, weird results might appear.
118  */
119 void weightvg_do_mask(int num, const int *indices, float *org_w, const float *new_w,
120                       Object *ob, DerivedMesh *dm, float fact, const char defgrp_name[32],
121                       Tex *texture, int tex_use_channel, int tex_mapping,
122                       Object *tex_map_object, const char *tex_uvlayer_name)
123 {
124         int ref_didx;
125         int i;
126
127         /* If influence factor is null, nothing to do! */
128         if (fact == 0.0f) return;
129
130         /* If we want to mask vgroup weights from a texture. */
131         if (texture) {
132                 /* The texture coordinates. */
133                 float (*tex_co)[3];
134                 /* See mapping note below... */
135                 MappingInfoModifierData t_map;
136                 float (*v_co)[3];
137
138                 /* Use new generic get_texture_coords, but do not modify our DNA struct for it…
139                  * XXX Why use a ModifierData stuff here ? Why not a simple, generic struct for parameters ?
140                  *     What e.g. if a modifier wants to use several textures ?
141                  *     Why use only v_co, and not MVert (or both) ?
142                  */
143                 t_map.texture = texture;
144                 t_map.map_object = tex_map_object;
145                 BLI_strncpy(t_map.uvlayer_name, tex_uvlayer_name, sizeof(t_map.uvlayer_name));
146                 t_map.texmapping = tex_mapping;
147                 v_co = MEM_mallocN(sizeof(*v_co) * num, "WeightVG Modifier, TEX mode, v_co");
148                 dm->getVertCos(dm, v_co);
149                 tex_co = MEM_callocN(sizeof(*tex_co) * num, "WeightVG Modifier, TEX mode, tex_co");
150                 get_texture_coords(&t_map, ob, dm, v_co, tex_co, num);
151                 MEM_freeN(v_co);
152
153                 /* For each weight (vertex), make the mix between org and new weights. */
154                 for(i = 0; i < num; ++i) {
155                         int idx = indices ? indices[i] : i;
156                         TexResult texres;
157                         float h, s, v; /* For HSV color space. */
158
159                         texres.nor = NULL;
160                         get_texture_value(texture, tex_co[idx], &texres);
161                         /* Get the good channel value... */
162                         switch(tex_use_channel) {
163                         case MOD_WVG_MASK_TEX_USE_INT:
164                                 org_w[i] = (new_w[i] * texres.tin * fact) + (org_w[i] * (1.0f - (texres.tin*fact)));
165                                 break;
166                         case MOD_WVG_MASK_TEX_USE_RED:
167                                 org_w[i] = (new_w[i] * texres.tr * fact) + (org_w[i] * (1.0f - (texres.tr*fact)));
168                                 break;
169                         case MOD_WVG_MASK_TEX_USE_GREEN:
170                                 org_w[i] = (new_w[i] * texres.tg * fact) + (org_w[i] * (1.0f - (texres.tg*fact)));
171                                 break;
172                         case MOD_WVG_MASK_TEX_USE_BLUE:
173                                 org_w[i] = (new_w[i] * texres.tb * fact) + (org_w[i] * (1.0f - (texres.tb*fact)));
174                                 break;
175                         case MOD_WVG_MASK_TEX_USE_HUE:
176                                 rgb_to_hsv(texres.tr, texres.tg, texres.tb, &h, &s, &v);
177                                 org_w[i] = (new_w[i] * h * fact) + (org_w[i] * (1.0f - (h*fact)));
178                                 break;
179                         case MOD_WVG_MASK_TEX_USE_SAT:
180                                 rgb_to_hsv(texres.tr, texres.tg, texres.tb, &h, &s, &v);
181                                 org_w[i] = (new_w[i] * s * fact) + (org_w[i] * (1.0f - (s*fact)));
182                                 break;
183                         case MOD_WVG_MASK_TEX_USE_VAL:
184                                 rgb_to_hsv(texres.tr, texres.tg, texres.tb, &h, &s, &v);
185                                 org_w[i] = (new_w[i] * v * fact) + (org_w[i] * (1.0f - (v*fact)));
186                                 break;
187                         case MOD_WVG_MASK_TEX_USE_ALPHA:
188                                 org_w[i] = (new_w[i] * texres.ta * fact) + (org_w[i] * (1.0f - (texres.ta*fact)));
189                                 break;
190                         default:
191                                 org_w[i] = (new_w[i] * texres.tin * fact) + (org_w[i] * (1.0f - (texres.tin*fact)));
192                                 break;
193                         }
194                 }
195
196                 MEM_freeN(tex_co);
197         }
198         else if ((ref_didx = defgroup_name_index(ob, defgrp_name)) != -1) {
199                 MDeformVert *dvert = NULL;
200
201                 /* Check whether we want to set vgroup weights from a constant weight factor or a vertex
202                  * group.
203                  */
204                 /* Get vgroup idx from its name. */
205
206                 /* Proceed only if vgroup is valid, else use constant factor. */
207                 /* Get actual dverts (ie vertex group data). */
208                 dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
209                 /* Proceed only if vgroup is valid, else assume factor = O. */
210                 if (dvert == NULL) return;
211
212                 /* For each weight (vertex), make the mix between org and new weights. */
213                 for (i = 0; i < num; i++) {
214                         int idx = indices ? indices[i] : i;
215                         const float f= defvert_find_weight(&dvert[idx], ref_didx) * fact;
216                         org_w[i] = (new_w[i] * f) + (org_w[i] * (1.0f-f));
217                         /* If that vertex is not in ref vgroup, assume null factor, and hence do nothing! */
218                 }
219         }
220         else {
221                 /* Default "influence" behavior. */
222                 /* For each weight (vertex), make the mix between org and new weights. */
223                 const float ifact= 1.0f - fact;
224                 for (i = 0; i < num; i++) {
225                         org_w[i] = (new_w[i] * fact) + (org_w[i] * ifact);
226                 }
227         }
228 }
229
230 /* Applies weights to given vgroup (defgroup), and optionnaly add/remove vertices from the group.
231  * If indices is not NULL, it must be a table of same length as weights, mapping to the real
232  * vertex index (in case the weight table does not cover the whole vertices...).
233  */
234 void weightvg_update_vg(MDeformVert *dvert, int defgrp_idx, int num,
235                         const int *indices, const float *weights, int do_add,
236                         float add_thresh, int do_rem, float rem_thresh)
237 {
238         int i;
239
240         for (i = 0; i < num; i++) {
241                 int j;
242                 int add2vg = do_add;
243                 float w = weights[i];
244                 MDeformVert *dv = &dvert[indices ? indices[i] : i];
245                 MDeformWeight *newdw;
246
247                 /* Never allow weights out of [0.0, 1.0] range. */
248                 CLAMP(w, 0.0f, 1.0f);
249
250                 /* Let's first check to see if this vert is already in the weight group – if so
251                  * let's update it, or remove it if needed.
252                  */
253                 for (j = 0; j < dv->totweight; j++) {
254                         /* If this weight corresponds to the deform group, update the value or,
255                          * if lower than rem_threshold, remove the vertex from the vgroup.
256                          */
257                         if (dv->dw[j].def_nr == defgrp_idx) {
258                                 /* Remove the vertex from this vgroup if needed. */
259                                 if (do_rem && w < rem_thresh) {
260                                         /* TODO, move this into deform.c to make into a generic function */
261
262                                         dv->totweight--;
263                                         /* If there are still other deform weights attached to this vert then remove
264                                          * this deform weight, and reshuffle the others.
265                                          */
266                                         if(dv->totweight) {
267                                                 newdw = MEM_mallocN(sizeof(MDeformWeight)*(dv->totweight), "deformWeight");
268                                                 if(dv->dw){
269                                                         memcpy(newdw, dv->dw, sizeof(MDeformWeight)*j);
270                                                         memcpy(newdw+j, dv->dw+j+1, sizeof(MDeformWeight)*(dv->totweight-j));
271                                                         MEM_freeN(dv->dw);
272                                                 }
273                                                 dv->dw = newdw;
274                                         }
275                                         /* If there are no other deform weights left then just remove this one. */
276                                         else {
277                                                 MEM_freeN(dv->dw);
278                                                 dv->dw = NULL;
279                                         }
280                                 }
281                                 /* Else, just set the new computed weight. */
282                                 else {
283                                         dv->dw[j].weight = w;
284                                 }
285                                 add2vg = FALSE;
286                                 break;
287                         }
288                 }
289
290                 /* If the vert wasn't in the deform group, add it if needed!
291                  */
292                 if ((add2vg == TRUE) && w > add_thresh) {
293                         /* TODO, mvoe into deform.c and make into a generic function, this assumes the vertex
294                          * groups have already been checked, so this has to remain low level */
295                         newdw = MEM_callocN(sizeof(MDeformWeight)*(dv->totweight+1), "WeightVGEdit Modifier, deformWeight");
296                         if(dv->dw) {
297                                 memcpy(newdw, dv->dw, sizeof(MDeformWeight)*dv->totweight);
298                                 MEM_freeN(dv->dw);
299                         }
300                         dv->dw = newdw;
301                         dv->dw[dv->totweight].weight = w;
302                         dv->dw[dv->totweight].def_nr = defgrp_idx;
303                         dv->totweight++;
304                 }
305         }
306 }