7e1c402007b844accd457b6cdfd4993f06fb839c
[blender.git] / source / blender / modifiers / intern / MOD_weightvg_util.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) 2011 by Bastien Montagne.
19  * All rights reserved.
20  *
21  * Contributor(s): None yet.
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  *
25  */
26
27 /** \file blender/modifiers/intern/MOD_weightvg_util.c
28  *  \ingroup modifiers
29  */
30
31 #include "BLI_math.h"
32 #include "BLI_rand.h"
33 #include "BLI_string.h"
34 #include "BLI_utildefines.h"
35
36 #include "DNA_color_types.h"      /* CurveMapping. */
37 #include "DNA_meshdata_types.h"
38 #include "DNA_modifier_types.h"
39 #include "DNA_object_types.h"
40 #include "DNA_scene_types.h"
41
42 #include "BKE_cdderivedmesh.h"
43 #include "BKE_colortools.h"       /* CurveMapping. */
44 #include "BKE_deform.h"
45 #include "BKE_modifier.h"
46 #include "BKE_texture.h"          /* Texture masking. */
47
48 #include "MEM_guardedalloc.h"
49 #include "MOD_util.h"
50 #include "MOD_weightvg_util.h"
51 #include "RE_shader_ext.h"        /* Texture masking. */
52
53 /* Maps new_w weights in place, using either one of the predefined functions, or a custom curve.
54  * Return values are in new_w.
55  * If indices is not NULL, it must be a table of same length as org_w and new_w, mapping to the real
56  * vertex index (in case the weight tables do not cover the whole vertices...).
57  * cmap might be NULL, in which case curve mapping mode will return unmodified data.
58  */
59 void weightvg_do_map(int num, float *new_w, short falloff_type, CurveMapping *cmap, RNG *rng)
60 {
61         int i;
62
63         /* Return immediately, if we have nothing to do! */
64         /* Also security checks... */
65         if (((falloff_type == MOD_WVG_MAPPING_CURVE) && (cmap == NULL)) ||
66             !ELEM(falloff_type, MOD_WVG_MAPPING_CURVE, MOD_WVG_MAPPING_SHARP, MOD_WVG_MAPPING_SMOOTH,
67                   MOD_WVG_MAPPING_ROOT, MOD_WVG_MAPPING_SPHERE, MOD_WVG_MAPPING_RANDOM,
68                   MOD_WVG_MAPPING_STEP))
69         {
70                 return;
71         }
72
73         if (cmap && falloff_type == MOD_WVG_MAPPING_CURVE) {
74                 curvemapping_initialize(cmap);
75         }
76
77         /* Map each weight (vertex) to its new value, accordingly to the chosen mode. */
78         for (i = 0; i < num; ++i) {
79                 float fac = new_w[i];
80
81                 /* Code borrowed from the warp modifier. */
82                 /* Closely matches PROP_SMOOTH and similar. */
83                 switch (falloff_type) {
84                         case MOD_WVG_MAPPING_CURVE:
85                                 fac = curvemapping_evaluateF(cmap, 0, fac);
86                                 break;
87                         case MOD_WVG_MAPPING_SHARP:
88                                 fac = fac * fac;
89                                 break;
90                         case MOD_WVG_MAPPING_SMOOTH:
91                                 fac = 3.0f * fac * fac - 2.0f * fac * fac * fac;
92                                 break;
93                         case MOD_WVG_MAPPING_ROOT:
94                                 fac = sqrtf(fac);
95                                 break;
96                         case MOD_WVG_MAPPING_SPHERE:
97                                 fac = sqrtf(2 * fac - fac * fac);
98                                 break;
99                         case MOD_WVG_MAPPING_RANDOM:
100                                 fac = BLI_rng_get_float(rng) * fac;
101                                 break;
102                         case MOD_WVG_MAPPING_STEP:
103                                 fac = (fac >= 0.5f) ? 1.0f : 0.0f;
104                                 break;
105                 }
106
107                 new_w[i] = fac;
108         }
109 }
110
111 /* Applies new_w weights to org_w ones, using either a texture, vgroup or constant value as factor.
112  * Return values are in org_w.
113  * If indices is not NULL, it must be a table of same length as org_w and new_w, mapping to the real
114  * vertex index (in case the weight tables do not cover the whole vertices...).
115  * XXX The standard "factor" value is assumed in [0.0, 1.0] range. Else, weird results might appear.
116  */
117 void weightvg_do_mask(int num, const int *indices, float *org_w, const float *new_w,
118                       Object *ob, DerivedMesh *dm, float fact, const char defgrp_name[MAX_VGROUP_NAME],
119                       Scene *scene, Tex *texture, int tex_use_channel, int tex_mapping,
120                       Object *tex_map_object, const char *tex_uvlayer_name)
121 {
122         int ref_didx;
123         int i;
124
125         /* If influence factor is null, nothing to do! */
126         if (fact == 0.0f) return;
127
128         /* If we want to mask vgroup weights from a texture. */
129         if (texture) {
130                 /* The texture coordinates. */
131                 float (*tex_co)[3];
132                 /* See mapping note below... */
133                 MappingInfoModifierData t_map;
134                 float (*v_co)[3];
135                 int numVerts = dm->getNumVerts(dm);
136
137                 /* Use new generic get_texture_coords, but do not modify our DNA struct for it...
138                  * XXX Why use a ModifierData stuff here ? Why not a simple, generic struct for parameters ?
139                  *     What e.g. if a modifier wants to use several textures ?
140                  *     Why use only v_co, and not MVert (or both) ?
141                  */
142                 t_map.texture = texture;
143                 t_map.map_object = tex_map_object;
144                 BLI_strncpy(t_map.uvlayer_name, tex_uvlayer_name, sizeof(t_map.uvlayer_name));
145                 t_map.texmapping = tex_mapping;
146                 v_co = MEM_mallocN(sizeof(*v_co) * numVerts, "WeightVG Modifier, TEX mode, v_co");
147                 dm->getVertCos(dm, v_co);
148                 tex_co = MEM_callocN(sizeof(*tex_co) * numVerts, "WeightVG Modifier, TEX mode, tex_co");
149                 get_texture_coords(&t_map, ob, dm, v_co, tex_co, num);
150                 MEM_freeN(v_co);
151
152                 modifier_init_texture(scene, texture);
153
154                 /* For each weight (vertex), make the mix between org and new weights. */
155                 for (i = 0; i < num; ++i) {
156                         int idx = indices ? indices[i] : i;
157                         TexResult texres;
158                         float hsv[3]; /* For HSV color space. */
159                         bool do_color_manage;
160
161                         do_color_manage = tex_use_channel != MOD_WVG_MASK_TEX_USE_INT;
162
163                         texres.nor = NULL;
164                         BKE_texture_get_value(scene, texture, tex_co[idx], &texres, do_color_manage);
165                         /* Get the good channel value... */
166                         switch (tex_use_channel) {
167                                 case MOD_WVG_MASK_TEX_USE_INT:
168                                         org_w[i] = (new_w[i] * texres.tin * fact) + (org_w[i] * (1.0f - (texres.tin * fact)));
169                                         break;
170                                 case MOD_WVG_MASK_TEX_USE_RED:
171                                         org_w[i] = (new_w[i] * texres.tr * fact) + (org_w[i] * (1.0f - (texres.tr * fact)));
172                                         break;
173                                 case MOD_WVG_MASK_TEX_USE_GREEN:
174                                         org_w[i] = (new_w[i] * texres.tg * fact) + (org_w[i] * (1.0f - (texres.tg * fact)));
175                                         break;
176                                 case MOD_WVG_MASK_TEX_USE_BLUE:
177                                         org_w[i] = (new_w[i] * texres.tb * fact) + (org_w[i] * (1.0f - (texres.tb * fact)));
178                                         break;
179                                 case MOD_WVG_MASK_TEX_USE_HUE:
180                                         rgb_to_hsv_v(&texres.tr, hsv);
181                                         org_w[i] = (new_w[i] * hsv[0] * fact) + (org_w[i] * (1.0f - (hsv[0] * fact)));
182                                         break;
183                                 case MOD_WVG_MASK_TEX_USE_SAT:
184                                         rgb_to_hsv_v(&texres.tr, hsv);
185                                         org_w[i] = (new_w[i] * hsv[1] * fact) + (org_w[i] * (1.0f - (hsv[1] * fact)));
186                                         break;
187                                 case MOD_WVG_MASK_TEX_USE_VAL:
188                                         rgb_to_hsv_v(&texres.tr, hsv);
189                                         org_w[i] = (new_w[i] * hsv[2] * fact) + (org_w[i] * (1.0f - (hsv[2] * fact)));
190                                         break;
191                                 case MOD_WVG_MASK_TEX_USE_ALPHA:
192                                         org_w[i] = (new_w[i] * texres.ta * fact) + (org_w[i] * (1.0f - (texres.ta * fact)));
193                                         break;
194                                 default:
195                                         org_w[i] = (new_w[i] * texres.tin * fact) + (org_w[i] * (1.0f - (texres.tin * fact)));
196                                         break;
197                         }
198                 }
199
200                 MEM_freeN(tex_co);
201         }
202         else if ((ref_didx = defgroup_name_index(ob, defgrp_name)) != -1) {
203                 MDeformVert *dvert = NULL;
204
205                 /* Check whether we want to set vgroup weights from a constant weight factor or a vertex
206                  * group.
207                  */
208                 /* Get vgroup idx from its name. */
209
210                 /* Proceed only if vgroup is valid, else use constant factor. */
211                 /* Get actual dverts (ie vertex group data). */
212                 dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
213                 /* Proceed only if vgroup is valid, else assume factor = O. */
214                 if (dvert == NULL) return;
215
216                 /* For each weight (vertex), make the mix between org and new weights. */
217                 for (i = 0; i < num; i++) {
218                         int idx = indices ? indices[i] : i;
219                         const float f = defvert_find_weight(&dvert[idx], ref_didx) * fact;
220                         org_w[i] = (new_w[i] * f) + (org_w[i] * (1.0f - f));
221                         /* If that vertex is not in ref vgroup, assume null factor, and hence do nothing! */
222                 }
223         }
224         else {
225                 /* Default "influence" behavior. */
226                 /* For each weight (vertex), make the mix between org and new weights. */
227                 const float ifact = 1.0f - fact;
228                 for (i = 0; i < num; i++) {
229                         org_w[i] = (new_w[i] * fact) + (org_w[i] * ifact);
230                 }
231         }
232 }
233
234
235
236
237 /* Applies weights to given vgroup (defgroup), and optionally add/remove vertices from the group.
238  * If dws is not NULL, it must be an array of MDeformWeight pointers of same length as weights (and
239  * defgrp_idx can then have any value).
240  * If indices is not NULL, it must be an array of same length as weights, mapping to the real
241  * vertex index (in case the weight array does not cover the whole vertices...).
242  */
243 void weightvg_update_vg(MDeformVert *dvert, int defgrp_idx, MDeformWeight **dws, int num,
244                         const int *indices, const float *weights, const bool do_add,
245                         const float add_thresh, const bool do_rem, const float rem_thresh)
246 {
247         int i;
248
249         for (i = 0; i < num; i++) {
250                 float w = weights[i];
251                 MDeformVert *dv = &dvert[indices ? indices[i] : i];
252                 MDeformWeight *dw = dws ? dws[i] : defvert_find_index(dv, defgrp_idx);
253
254                 /* Never allow weights out of [0.0, 1.0] range. */
255                 CLAMP(w, 0.0f, 1.0f);
256
257                 /* If the vertex is in this vgroup, remove it if needed, or just update it. */
258                 if (dw != NULL) {
259                         if (do_rem && w < rem_thresh) {
260                                 defvert_remove_group(dv, dw);
261                         }
262                         else {
263                                 dw->weight = w;
264                         }
265                 }
266                 /* Else, add it if needed! */
267                 else if (do_add && w > add_thresh) {
268                         defvert_add_index_notest(dv, defgrp_idx, w);
269                 }
270         }
271 }