- mask_tex_map_obj --> mask_tex_map_object
[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_utildefines.h"
37 #include "BLI_math.h"
38 #include "BLI_string.h"
39
40 #include "DNA_mesh_types.h"
41 #include "DNA_meshdata_types.h"
42 #include "DNA_modifier_types.h"
43 #include "DNA_object_types.h"
44
45 #include "BKE_cdderivedmesh.h"
46 #include "BKE_deform.h"
47 #include "BKE_mesh.h"
48 #include "BKE_modifier.h"
49 #include "BKE_texture.h"          /* Texture masking. */
50
51 #include "depsgraph_private.h"
52 #include "MEM_guardedalloc.h"
53 #include "MOD_util.h"
54 #include "MOD_weightvg_util.h"
55 #include "RE_shader_ext.h"        /* Texture masking. */
56
57 /* Applies new_w weights to org_w ones, using either a texture, vgroup or constant value as factor.
58  * Return values are in org_w.
59  * If indices is not NULL, it must be a table of same length as org_w and new_w, mapping to the real
60  * vertex index (in case the weight tables do not cover the whole vertices...).
61  * XXX The standard “factor” value is assumed in [0.0, 1.0] range. Else, weird results might appear.
62  */
63 void weightvg_do_mask(int num, int *indices, float *org_w, float *new_w, Object *ob,
64                       DerivedMesh *dm, float fact, const char defgrp_name[32], Tex *texture,
65                       int tex_use_channel, int tex_mapping, Object *tex_map_object,
66                       const char *tex_uvlayer_name)
67 {
68         int ref_didx;
69         MDeformVert *dvert = NULL;
70         int i;
71
72         /* If influence factor is null, nothing to do! */
73         if (fact == 0.0) return;
74
75         /* If we want to mask vgroup weights from a texture. */
76         if (texture) {
77                 /* The texture coordinates. */
78                 float (*tex_co)[3];
79                 /* See mapping note below… */
80                 MappingInfoModifierData t_map;
81                 float (*v_co)[3];
82
83                 /* Use new generic get_texture_coords, but do not modify our DNA struct for it…
84                  * XXX Why use a ModifierData stuff here ? Why not a simple, generic struct for parameters ?
85                  *     What e.g. if a modifier wants to use several textures ?
86                  *     Why use only v_co, and not MVert (or both) ?
87                  */
88                 t_map.texture = texture;
89                 t_map.map_object = tex_map_object;
90                 BLI_strncpy(t_map.uvlayer_name, tex_uvlayer_name, sizeof(t_map.uvlayer_name));
91                 t_map.texmapping = tex_mapping;
92                 v_co = MEM_mallocN(sizeof(*v_co) * num, "WeightVG Modifier, TEX mode, v_co");
93                 dm->getVertCos(dm, v_co);
94                 tex_co = MEM_callocN(sizeof(*tex_co) * num, "WeightVG Modifier, TEX mode, tex_co");
95                 get_texture_coords(&t_map, ob, dm, v_co, tex_co, num);
96                 MEM_freeN(v_co);
97
98                 /* For each weight (vertex), make the mix between org and new weights. */
99                 for(i = 0; i < num; ++i) {
100                         int idx = indices ? indices[i] : i;
101                         TexResult texres;
102                         float h, s, v; /* For HSV color space. */
103
104                         texres.nor = NULL;
105                         get_texture_value(texture, tex_co[idx], &texres);
106                         /* Get the good channel value… */
107                         switch(tex_use_channel) {
108                         case MOD_WVG_MASK_TEX_USE_INT:
109                                 org_w[i] = (new_w[i] * texres.tin * fact) + (org_w[i] * (1.0 - (texres.tin*fact)));
110                                 break;
111                         case MOD_WVG_MASK_TEX_USE_RED:
112                                 org_w[i] = (new_w[i] * texres.tr * fact) + (org_w[i] * (1.0 - (texres.tr*fact)));
113                                 break;
114                         case MOD_WVG_MASK_TEX_USE_GREEN:
115                                 org_w[i] = (new_w[i] * texres.tg * fact) + (org_w[i] * (1.0 - (texres.tg*fact)));
116                                 break;
117                         case MOD_WVG_MASK_TEX_USE_BLUE:
118                                 org_w[i] = (new_w[i] * texres.tb * fact) + (org_w[i] * (1.0 - (texres.tb*fact)));
119                                 break;
120                         case MOD_WVG_MASK_TEX_USE_HUE:
121                                 rgb_to_hsv(texres.tr, texres.tg, texres.tb, &h, &s, &v);
122                                 org_w[i] = (new_w[i] * h * fact) + (org_w[i] * (1.0 - (h*fact)));
123                                 break;
124                         case MOD_WVG_MASK_TEX_USE_SAT:
125                                 rgb_to_hsv(texres.tr, texres.tg, texres.tb, &h, &s, &v);
126                                 org_w[i] = (new_w[i] * s * fact) + (org_w[i] * (1.0 - (s*fact)));
127                                 break;
128                         case MOD_WVG_MASK_TEX_USE_VAL:
129                                 rgb_to_hsv(texres.tr, texres.tg, texres.tb, &h, &s, &v);
130                                 org_w[i] = (new_w[i] * v * fact) + (org_w[i] * (1.0 - (v*fact)));
131                                 break;
132                         case MOD_WVG_MASK_TEX_USE_ALPHA:
133                                 org_w[i] = (new_w[i] * texres.ta * fact) + (org_w[i] * (1.0 - (texres.ta*fact)));
134                                 break;
135                         default:
136                                 org_w[i] = (new_w[i] * texres.tin * fact) + (org_w[i] * (1.0 - (texres.tin*fact)));
137                                 break;
138                         }
139                 }
140
141                 MEM_freeN(tex_co);
142                 return;
143         }
144
145         /* Check whether we want to set vgroup weights from a constant weight factor or a vertex
146          * group.
147          */
148         /* Get vgroup idx from its name. */
149         ref_didx = defgroup_name_index(ob, defgrp_name);
150         /* Proceed only if vgroup is valid, else use constant factor. */
151         if (ref_didx >= 0) {
152                 /* Get actual dverts (ie vertex group data). */
153                 dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
154                 /* Proceed only if vgroup is valid, else assume factor = O. */
155                 if (dvert == NULL) return;
156
157                 /* For each weight (vertex), make the mix between org and new weights. */
158                 for (i = 0; i < num; i++) {
159                         int idx = indices ? indices[i] : i;
160                         int j;
161                         for (j = 0; j < dvert[idx].totweight; j++) {
162                                 if(dvert[idx].dw[j].def_nr == ref_didx) {
163                                         float f = dvert[idx].dw[j].weight * fact;
164                                         org_w[i] = (new_w[i] * f) + (org_w[i] * (1.0-f));
165                                         break;
166                                 }
167                         }
168                         /* If that vertex is not in ref vgroup, assume null factor, and hence do nothing! */
169                 }
170                 return;
171         }
172
173         /* Default "influence" behavior. */
174         /* For each weight (vertex), make the mix between org and new weights. */
175         for (i = 0; i < num; i++) {
176                 org_w[i] = (new_w[i] * fact) + (org_w[i] * (1.0-fact));
177         }
178 }
179
180 /* Applies weights to given vgroup (defgroup), and optionnaly add/remove vertices from the group.
181  * If indices is not NULL, it must be a table of same length as weights, mapping to the real
182  * vertex index (in case the weight table does not cover the whole vertices...).
183  */
184 void weightvg_update_vg(MDeformVert *dvert, int defgrp_idx, int num,
185                         const int *indices, const float *weights, int do_add,
186                         float add_thresh, int do_rem, float rem_thresh)
187 {
188         int i;
189
190         for (i = 0; i < num; i++) {
191                 int j;
192                 char add2vg = do_add;
193                 float w = weights[i];
194                 MDeformVert *dv = &dvert[indices ? indices[i] : i];
195                 MDeformWeight *newdw;
196
197                 /* Never allow weights out of [0.0, 1.0] range. */
198                 CLAMP(w, 0.0, 1.0);
199
200                 /* Let's first check to see if this vert is already in the weight group – if so
201                  * let's update it, or remove it if needed.
202                  */
203                 for (j = 0; j < dv->totweight; j++) {
204                         /* If this weight corresponds to the deform group, update the value or,
205                          * if lower than rem_threshold, remove the vertex from the vgroup.
206                          */
207                         if (dv->dw[j].def_nr == defgrp_idx) {
208                                 /* Remove the vertex from this vgroup if needed. */
209                                 if (do_rem && w < rem_thresh) {
210                                         dv->totweight--;
211                                         /* If there are still other deform weights attached to this vert then remove
212                                          * this deform weight, and reshuffle the others.
213                                          */
214                                         if(dv->totweight) {
215                                                 newdw = MEM_mallocN(sizeof(MDeformWeight)*(dv->totweight), "deformWeight");
216                                                 if(dv->dw){
217                                                         memcpy(newdw, dv->dw, sizeof(MDeformWeight)*j);
218                                                         memcpy(newdw+j, dv->dw+j+1, sizeof(MDeformWeight)*(dv->totweight-j));
219                                                         MEM_freeN(dv->dw);
220                                                 }
221                                                 dv->dw = newdw;
222                                         }
223                                         /* If there are no other deform weights left then just remove this one. */
224                                         else {
225                                                 MEM_freeN(dv->dw);
226                                                 dv->dw = NULL;
227                                         }
228                                 }
229                                 /* Else, just set the new computed weight. */
230                                 else {
231                                         dv->dw[j].weight = w;
232                                 }
233                                 add2vg = 0;
234                                 break;
235                         }
236                 }
237
238                 /* If the vert wasn't in the deform group, add it if needed!
239                  */
240                 if (add2vg && w > add_thresh) {
241                         newdw = MEM_callocN(sizeof(MDeformWeight)*(dv->totweight+1), "WeightVGEdit Modifier, deformWeight");
242                         if(dv->dw) {
243                                 memcpy(newdw, dv->dw, sizeof(MDeformWeight)*dv->totweight);
244                                 MEM_freeN(dv->dw);
245                         }
246                         dv->dw = newdw;
247                         dv->dw[dv->totweight].weight = w;
248                         dv->dw[dv->totweight].def_nr = defgrp_idx;
249                         dv->totweight++;
250                 }
251         }
252 }