Blender V2.61 - r43446

MOD_weightvg_util.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software  Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2011 by Bastien Montagne.
00019  * All rights reserved.
00020  *
00021  * Contributor(s): None yet.
00022  *
00023  * ***** END GPL LICENSE BLOCK *****
00024  *
00025  */
00026 
00031 #include "BLI_math.h"
00032 #include "BLI_rand.h"
00033 #include "BLI_string.h"
00034 #include "BLI_utildefines.h"
00035 
00036 #include "DNA_color_types.h"      /* CurveMapping. */
00037 #include "DNA_mesh_types.h"
00038 #include "DNA_meshdata_types.h"
00039 #include "DNA_modifier_types.h"
00040 #include "DNA_object_types.h"
00041 
00042 #include "BKE_cdderivedmesh.h"
00043 #include "BKE_colortools.h"       /* CurveMapping. */
00044 #include "BKE_deform.h"
00045 #include "BKE_mesh.h"
00046 #include "BKE_modifier.h"
00047 #include "BKE_texture.h"          /* Texture masking. */
00048 
00049 #include "depsgraph_private.h"
00050 #include "MEM_guardedalloc.h"
00051 #include "MOD_util.h"
00052 #include "MOD_weightvg_util.h"
00053 #include "RE_shader_ext.h"        /* Texture masking. */
00054 
00055 /* Maps new_w weights in place, using either one of the predifined functions, or a custom curve.
00056  * Return values are in new_w.
00057  * If indices is not NULL, it must be a table of same length as org_w and new_w, mapping to the real
00058  * vertex index (in case the weight tables do not cover the whole vertices...).
00059  * cmap might be NULL, in which case curve mapping mode will return unmodified data.
00060  */
00061 void weightvg_do_map(int num, float *new_w, short falloff_type, CurveMapping *cmap)
00062 {
00063     int i;
00064 
00065     /* Return immediately, if we have nothing to do! */
00066     /* Also security checks... */
00067     if(((falloff_type == MOD_WVG_MAPPING_CURVE) && (cmap == NULL))
00068             || !ELEM7(falloff_type, MOD_WVG_MAPPING_CURVE, MOD_WVG_MAPPING_SHARP, MOD_WVG_MAPPING_SMOOTH,
00069                       MOD_WVG_MAPPING_ROOT, MOD_WVG_MAPPING_SPHERE, MOD_WVG_MAPPING_RANDOM,
00070                       MOD_WVG_MAPPING_STEP))
00071         return;
00072 
00073     /* Map each weight (vertex) to its new value, accordingly to the chosen mode. */
00074     for(i = 0; i < num; ++i) {
00075         float fac = new_w[i];
00076 
00077         /* Code borrowed from the warp modifier. */
00078         /* Closely matches PROP_SMOOTH and similar. */
00079         switch(falloff_type) {
00080         case MOD_WVG_MAPPING_CURVE:
00081             fac = curvemapping_evaluateF(cmap, 0, fac);
00082             break;
00083         case MOD_WVG_MAPPING_SHARP:
00084             fac = fac*fac;
00085             break;
00086         case MOD_WVG_MAPPING_SMOOTH:
00087             fac = 3.0f*fac*fac - 2.0f*fac*fac*fac;
00088             break;
00089         case MOD_WVG_MAPPING_ROOT:
00090             fac = (float)sqrt(fac);
00091             break;
00092         case MOD_WVG_MAPPING_SPHERE:
00093             fac = (float)sqrt(2*fac - fac * fac);
00094             break;
00095         case MOD_WVG_MAPPING_RANDOM:
00096             BLI_srand(BLI_rand()); /* random seed */
00097             fac = BLI_frand()*fac;
00098             break;
00099         case MOD_WVG_MAPPING_STEP:
00100             fac = (fac >= 0.5f)?1.0f:0.0f;
00101             break;
00102         }
00103 
00104         new_w[i] = fac;
00105     }
00106 }
00107 
00108 /* Applies new_w weights to org_w ones, using either a texture, vgroup or constant value as factor.
00109  * Return values are in org_w.
00110  * If indices is not NULL, it must be a table of same length as org_w and new_w, mapping to the real
00111  * vertex index (in case the weight tables do not cover the whole vertices...).
00112  * XXX The standard “factor” value is assumed in [0.0, 1.0] range. Else, weird results might appear.
00113  */
00114 void weightvg_do_mask(int num, const int *indices, float *org_w, const float *new_w,
00115                       Object *ob, DerivedMesh *dm, float fact, const char defgrp_name[MAX_VGROUP_NAME],
00116                       Tex *texture, int tex_use_channel, int tex_mapping,
00117                       Object *tex_map_object, const char *tex_uvlayer_name)
00118 {
00119     int ref_didx;
00120     int i;
00121 
00122     /* If influence factor is null, nothing to do! */
00123     if (fact == 0.0f) return;
00124 
00125     /* If we want to mask vgroup weights from a texture. */
00126     if (texture) {
00127         /* The texture coordinates. */
00128         float (*tex_co)[3];
00129         /* See mapping note below... */
00130         MappingInfoModifierData t_map;
00131         float (*v_co)[3];
00132 
00133         /* Use new generic get_texture_coords, but do not modify our DNA struct for it...
00134          * XXX Why use a ModifierData stuff here ? Why not a simple, generic struct for parameters ?
00135          *     What e.g. if a modifier wants to use several textures ?
00136          *     Why use only v_co, and not MVert (or both) ?
00137          */
00138         t_map.texture = texture;
00139         t_map.map_object = tex_map_object;
00140         BLI_strncpy(t_map.uvlayer_name, tex_uvlayer_name, sizeof(t_map.uvlayer_name));
00141         t_map.texmapping = tex_mapping;
00142         v_co = MEM_mallocN(sizeof(*v_co) * num, "WeightVG Modifier, TEX mode, v_co");
00143         dm->getVertCos(dm, v_co);
00144         tex_co = MEM_callocN(sizeof(*tex_co) * num, "WeightVG Modifier, TEX mode, tex_co");
00145         get_texture_coords(&t_map, ob, dm, v_co, tex_co, num);
00146         MEM_freeN(v_co);
00147 
00148         /* For each weight (vertex), make the mix between org and new weights. */
00149         for(i = 0; i < num; ++i) {
00150             int idx = indices ? indices[i] : i;
00151             TexResult texres;
00152             float h, s, v; /* For HSV color space. */
00153 
00154             texres.nor = NULL;
00155             get_texture_value(texture, tex_co[idx], &texres);
00156             /* Get the good channel value... */
00157             switch(tex_use_channel) {
00158             case MOD_WVG_MASK_TEX_USE_INT:
00159                 org_w[i] = (new_w[i] * texres.tin * fact) + (org_w[i] * (1.0f - (texres.tin*fact)));
00160                 break;
00161             case MOD_WVG_MASK_TEX_USE_RED:
00162                 org_w[i] = (new_w[i] * texres.tr * fact) + (org_w[i] * (1.0f - (texres.tr*fact)));
00163                 break;
00164             case MOD_WVG_MASK_TEX_USE_GREEN:
00165                 org_w[i] = (new_w[i] * texres.tg * fact) + (org_w[i] * (1.0f - (texres.tg*fact)));
00166                 break;
00167             case MOD_WVG_MASK_TEX_USE_BLUE:
00168                 org_w[i] = (new_w[i] * texres.tb * fact) + (org_w[i] * (1.0f - (texres.tb*fact)));
00169                 break;
00170             case MOD_WVG_MASK_TEX_USE_HUE:
00171                 rgb_to_hsv(texres.tr, texres.tg, texres.tb, &h, &s, &v);
00172                 org_w[i] = (new_w[i] * h * fact) + (org_w[i] * (1.0f - (h*fact)));
00173                 break;
00174             case MOD_WVG_MASK_TEX_USE_SAT:
00175                 rgb_to_hsv(texres.tr, texres.tg, texres.tb, &h, &s, &v);
00176                 org_w[i] = (new_w[i] * s * fact) + (org_w[i] * (1.0f - (s*fact)));
00177                 break;
00178             case MOD_WVG_MASK_TEX_USE_VAL:
00179                 rgb_to_hsv(texres.tr, texres.tg, texres.tb, &h, &s, &v);
00180                 org_w[i] = (new_w[i] * v * fact) + (org_w[i] * (1.0f - (v*fact)));
00181                 break;
00182             case MOD_WVG_MASK_TEX_USE_ALPHA:
00183                 org_w[i] = (new_w[i] * texres.ta * fact) + (org_w[i] * (1.0f - (texres.ta*fact)));
00184                 break;
00185             default:
00186                 org_w[i] = (new_w[i] * texres.tin * fact) + (org_w[i] * (1.0f - (texres.tin*fact)));
00187                 break;
00188             }
00189         }
00190 
00191         MEM_freeN(tex_co);
00192     }
00193     else if ((ref_didx = defgroup_name_index(ob, defgrp_name)) != -1) {
00194         MDeformVert *dvert = NULL;
00195 
00196         /* Check whether we want to set vgroup weights from a constant weight factor or a vertex
00197          * group.
00198          */
00199         /* Get vgroup idx from its name. */
00200 
00201         /* Proceed only if vgroup is valid, else use constant factor. */
00202         /* Get actual dverts (ie vertex group data). */
00203         dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
00204         /* Proceed only if vgroup is valid, else assume factor = O. */
00205         if (dvert == NULL) return;
00206 
00207         /* For each weight (vertex), make the mix between org and new weights. */
00208         for (i = 0; i < num; i++) {
00209             int idx = indices ? indices[i] : i;
00210             const float f = defvert_find_weight(&dvert[idx], ref_didx) * fact;
00211             org_w[i] = (new_w[i] * f) + (org_w[i] * (1.0f-f));
00212             /* If that vertex is not in ref vgroup, assume null factor, and hence do nothing! */
00213         }
00214     }
00215     else {
00216         /* Default "influence" behavior. */
00217         /* For each weight (vertex), make the mix between org and new weights. */
00218         const float ifact = 1.0f - fact;
00219         for (i = 0; i < num; i++) {
00220             org_w[i] = (new_w[i] * fact) + (org_w[i] * ifact);
00221         }
00222     }
00223 }
00224 
00225 
00226 
00227 
00228 /* Applies weights to given vgroup (defgroup), and optionnaly add/remove vertices from the group.
00229  * If dws is not NULL, it must be an array of MDeformWeight pointers of same length as weights (and
00230  * defgrp_idx can then have any value).
00231  * If indices is not NULL, it must be an array of same length as weights, mapping to the real
00232  * vertex index (in case the weight array does not cover the whole vertices...).
00233  */
00234 void weightvg_update_vg(MDeformVert *dvert, int defgrp_idx, MDeformWeight **dws, int num,
00235                         const int *indices, const float *weights, int do_add,
00236                         float add_thresh, int do_rem, float rem_thresh)
00237 {
00238     int i;
00239 
00240     for(i = 0; i < num; i++) {
00241         float w = weights[i];
00242         MDeformVert *dv = &dvert[indices ? indices[i] : i];
00243         MDeformWeight *dw = dws ? dws[i] : defvert_find_index(dv, defgrp_idx);
00244 
00245         /* Never allow weights out of [0.0, 1.0] range. */
00246         CLAMP(w, 0.0f, 1.0f);
00247 
00248         /* If the vertex is in this vgroup, remove it if needed, or just update it. */
00249         if(dw != NULL) {
00250             if(do_rem && w < rem_thresh) {
00251                 defvert_remove_group(dv, dw);
00252             }
00253             else {
00254                 dw->weight = w;
00255             }
00256         }
00257         /* Else, add it if needed! */
00258         else if(do_add && w > add_thresh) {
00259             defvert_add_index_notest(dv, defgrp_idx, w);
00260         }
00261     }
00262 }