This commit is contained in:
Campbell Barton 2011-09-08 08:08:31 +00:00
commit 24c9369477
15 changed files with 9019 additions and 6734 deletions

@ -4252,6 +4252,13 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
if(tmd->curfalloff)
direct_link_curvemapping(fd, tmd->curfalloff);
}
else if (md->type==eModifierType_WeightVGEdit) {
WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
wmd->cmap_curve = newdataadr(fd, wmd->cmap_curve);
if(wmd->cmap_curve)
direct_link_curvemapping(fd, wmd->cmap_curve);
}
}
}

@ -1352,6 +1352,12 @@ static void write_modifiers(WriteData *wd, ListBase *modbase)
write_curvemapping(wd, tmd->curfalloff);
}
}
else if (md->type==eModifierType_WeightVGEdit) {
WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
if (wmd->cmap_curve)
write_curvemapping(wd, wmd->cmap_curve);
}
}
}

File diff suppressed because it is too large Load Diff

@ -589,8 +589,8 @@ DEF_ICON(MOD_MULTIRES)
DEF_ICON(MOD_SMOKE)
DEF_ICON(MOD_SOLIDIFY)
DEF_ICON(MOD_SCREW)
DEF_ICON(MOD_WEIGHTVG)
#ifndef DEF_ICON_BLANK_SKIP
DEF_ICON(BLANK160)
DEF_ICON(BLANK161)
DEF_ICON(BLANK162)
DEF_ICON(BLANK163)

@ -71,6 +71,9 @@ typedef enum ModifierType {
eModifierType_Solidify,
eModifierType_Screw,
eModifierType_Warp,
eModifierType_WeightVGEdit,
eModifierType_WeightVGMix,
eModifierType_WeightVGProximity,
eModifierType_NgonInterp,
NUM_MODIFIER_TYPES
} ModifierType;
@ -790,4 +793,173 @@ typedef enum {
/* PROP_RANDOM not used */
} WarpModifierFalloff;
typedef struct WeightVGEditModifierData {
ModifierData modifier;
/* Note: I tried to keep everything logically ordered - provided the
* alignment constraints... */
char defgrp_name[32]; /* Name of vertex group to edit. */
short edit_flags; /* Using MOD_WVG_EDIT_* flags. */
short mapping_mode; /* Using MOD_WVG_MAPPING_* defines. */
float default_weight; /* Weight for vertices not in vgroup. */
/* Mapping stuff. */
struct CurveMapping *cmap_curve; /* The custom mapping curve! */
/* The add/remove vertices weight thresholds. */
float add_threshold, rem_threshold;
/* Masking options. */
float mask_constant; /* The global "influence", if no vgroup nor tex is used as mask. */
/* Name of mask vertex group from which to get weight factors. */
char mask_defgrp_name[32];
/* Texture masking. */
int mask_tex_use_channel; /* Which channel to use as weightf. */
struct Tex *mask_texture; /* The texture. */
struct Object *mask_tex_map_obj; /* Name of the map object. */
/* How to map the texture (using MOD_DISP_MAP_* constants). */
int mask_tex_mapping;
char mask_tex_uvlayer_name[32]; /* Name of the UV layer. */
/* Padding… */
int pad_i1;
} WeightVGEditModifierData;
/* WeightVGEdit flags. */
/* Use parametric mapping. */
//#define MOD_WVG_EDIT_MAP (1 << 0)
/* Use curve mapping. */
//#define MOD_WVG_EDIT_CMAP (1 << 1)
/* Reverse weights (in the [0.0, 1.0] standard range). */
//#define MOD_WVG_EDIT_REVERSE_WEIGHTS (1 << 2)
/* Add vertices with higher weight than threshold to vgroup. */
#define MOD_WVG_EDIT_ADD2VG (1 << 3)
/* Remove vertices with lower weight than threshold from vgroup. */
#define MOD_WVG_EDIT_REMFVG (1 << 4)
/* Clamp weights. */
//#define MOD_WVG_EDIT_CLAMP (1 << 5)
typedef struct WeightVGMixModifierData {
ModifierData modifier;
/* XXX Note: I tried to keep everything logically ordered provided the
* alignment constraints... */
char defgrp_name_a[32]; /* Name of vertex group to modify/weight. */
char defgrp_name_b[32]; /* Name of other vertex group to mix in. */
float default_weight_a; /* Default weight value for first vgroup. */
float default_weight_b; /* Default weight value to mix in. */
char mix_mode; /* How second vgroups weights affect first ones */
char mix_set; /* What vertices to affect. */
char pad_c1[6];
/* Masking options. */
float mask_constant; /* The global "influence", if no vgroup nor tex is used as mask. */
/* Name of mask vertex group from which to get weight factors. */
char mask_defgrp_name[32];
/* Texture masking. */
int mask_tex_use_channel; /* Which channel to use as weightf. */
struct Tex *mask_texture; /* The texture. */
struct Object *mask_tex_map_obj; /* Name of the map object. */
int mask_tex_mapping; /* How to map the texture! */
char mask_tex_uvlayer_name[32]; /* Name of the UV layer. */
/* Padding… */
int pad_i1;
} WeightVGMixModifierData;
/* How second vgroup's weights affect first ones. */
#define MOD_WVG_MIX_SET 1 /* Second weights replace weights. */
#define MOD_WVG_MIX_ADD 2 /* Second weights are added to weights. */
#define MOD_WVG_MIX_SUB 3 /* Second weights are subtracted from weights. */
#define MOD_WVG_MIX_MUL 4 /* Second weights are multiplied with weights. */
#define MOD_WVG_MIX_DIV 5 /* Second weights divide weights. */
#define MOD_WVG_MIX_DIF 6 /* Difference between second weights and weights. */
#define MOD_WVG_MIX_AVG 7 /* Average of both weights. */
/* What vertices to affect. */
#define MOD_WVG_SET_ALL 1 /* Affect all vertices. */
#define MOD_WVG_SET_A 2 /* Affect only vertices in first vgroup. */
#define MOD_WVG_SET_B 3 /* Affect only vertices in second vgroup. */
#define MOD_WVG_SET_OR 4 /* Affect only vertices in one vgroup or the other. */
#define MOD_WVG_SET_AND 5 /* Affect only vertices in both vgroups. */
typedef struct WeightVGProximityModifierData {
ModifierData modifier;
/* Note: I tried to keep everything logically ordered - provided the
* alignment constraints... */
char defgrp_name[32]; /* Name of vertex group to modify/weight. */
/* Proximity modes. */
int proximity_mode;
int proximity_flags;
/* Target object from which to calculate vertices distances. */
struct Object *proximity_ob_target;
/* Masking options. */
float mask_constant; /* The global "influence", if no vgroup nor tex is used as mask. */
/* Name of mask vertex group from which to get weight factors. */
char mask_defgrp_name[32];
/* Texture masking. */
int mask_tex_use_channel; /* Which channel to use as weightf. */
struct Tex *mask_texture; /* The texture. */
struct Object *mask_tex_map_obj; /* Name of the map object. */
int mask_tex_mapping; /* How to map the texture! */
char mask_tex_uvlayer_name[32]; /* Name of the UV layer. */
float min_dist, max_dist; /* Distances mapping to 0.0/1.0 weights. */
/* Put here to avoid breaking existing struct... */
short mapping_mode; /* Using MOD_WVG_MAPPING_* defines. */
/* Padding... */
short pad_s1;
} WeightVGProximityModifierData;
/* Modes of proximity weighting. */
/* Dist from target object to affected object. */
#define MOD_WVG_PROXIMITY_OBJECT 1 /* source vertex to other location */
/* Dist from target object to vertex. */
#define MOD_WVG_PROXIMITY_GEOMETRY 2 /* source vertex to other geometry */
/* Flags options for proximity weighting. */
/* Use nearest vertices of target obj, in MOD_WVG_PROXIMITY_GEOMETRY mode. */
#define MOD_WVG_PROXIMITY_GEOM_VERTS (1 << 0)
/* Use nearest edges of target obj, in MOD_WVG_PROXIMITY_GEOMETRY mode. */
#define MOD_WVG_PROXIMITY_GEOM_EDGES (1 << 1)
/* Use nearest faces of target obj, in MOD_WVG_PROXIMITY_GEOMETRY mode. */
#define MOD_WVG_PROXIMITY_GEOM_FACES (1 << 2)
/* Defines common to all WeightVG modifiers. */
/* Mapping modes. */
#define MOD_WVG_MAPPING_NONE 0
#define MOD_WVG_MAPPING_CURVE 1
#define MOD_WVG_MAPPING_SHARP 2 /* PROP_SHARP */
#define MOD_WVG_MAPPING_SMOOTH 3 /* PROP_SMOOTH */
#define MOD_WVG_MAPPING_ROOT 4 /* PROP_ROOT */
/* PROP_LIN not used (same as NONE, here...). */
/* PROP_CONST not used. */
#define MOD_WVG_MAPPING_SPHERE 7 /* PROP_SPHERE */
#define MOD_WVG_MAPPING_RANDOM 8 /* PROP_RANDOM */
#define MOD_WVG_MAPPING_STEP 9 /* Median Step. */
/* Tex channel to be used as mask. */
#define MOD_WVG_MASK_TEX_USE_INT 1
#define MOD_WVG_MASK_TEX_USE_RED 2
#define MOD_WVG_MASK_TEX_USE_GREEN 3
#define MOD_WVG_MASK_TEX_USE_BLUE 4
#define MOD_WVG_MASK_TEX_USE_HUE 5
#define MOD_WVG_MASK_TEX_USE_SAT 6
#define MOD_WVG_MASK_TEX_USE_VAL 7
#define MOD_WVG_MASK_TEX_USE_ALPHA 8
#endif

@ -566,6 +566,9 @@ extern StructRNA RNA_VoxelData;
extern StructRNA RNA_VoxelDataTexture;
extern StructRNA RNA_WarpModifier;
extern StructRNA RNA_WaveModifier;
extern StructRNA RNA_WeightVGEditModifier;
extern StructRNA RNA_WeightVGMixModifier;
extern StructRNA RNA_WeightVGProximityModifier;
extern StructRNA RNA_Window;
extern StructRNA RNA_WindowManager;
extern StructRNA RNA_WipeSequence;

@ -69,6 +69,9 @@ EnumPropertyItem modifier_type_items[] ={
{eModifierType_Solidify, "SOLIDIFY", ICON_MOD_SOLIDIFY, "Solidify", ""},
{eModifierType_Subsurf, "SUBSURF", ICON_MOD_SUBSURF, "Subdivision Surface", ""},
{eModifierType_UVProject, "UV_PROJECT", ICON_MOD_UVPROJECT, "UV Project", ""},
{eModifierType_WeightVGEdit, "WEIGHT_VGEDIT", ICON_MOD_WEIGHTVG, "WeightVG Edit", ""},
{eModifierType_WeightVGMix, "WEIGHT_VGMIX", ICON_MOD_WEIGHTVG, "WeightVG Mix", ""},
{eModifierType_WeightVGProximity, "WEIGHT_VGPROXIMITY", ICON_MOD_WEIGHTVG, "WeightVG Proximity", ""},
{0, "", 0, "Deform", ""},
{eModifierType_Armature, "ARMATURE", ICON_MOD_ARMATURE, "Armature", ""},
{eModifierType_Cast, "CAST", ICON_MOD_CAST, "Cast", ""},
@ -187,6 +190,12 @@ static StructRNA* rna_Modifier_refine(struct PointerRNA *ptr)
return &RNA_ScrewModifier;
case eModifierType_Warp:
return &RNA_WarpModifier;
case eModifierType_WeightVGEdit:
return &RNA_WeightVGEditModifier;
case eModifierType_WeightVGMix:
return &RNA_WeightVGMixModifier;
case eModifierType_WeightVGProximity:
return &RNA_WeightVGProximityModifier;
default:
return &RNA_Modifier;
}
@ -379,6 +388,46 @@ static void rna_SolidifyModifier_vgroup_set(PointerRNA *ptr, const char *value)
rna_object_vgroup_name_set(ptr, value, smd->defgrp_name, sizeof(smd->defgrp_name));
}
static void rna_WeightVGModifier_vgroup_set(PointerRNA *ptr, const char *value)
{
ModifierData *md = (ModifierData*)ptr->data;
if (md->type == eModifierType_WeightVGEdit) {
WeightVGEditModifierData *wmd= (WeightVGEditModifierData*)md;
rna_object_vgroup_name_set(ptr, value, wmd->defgrp_name, sizeof(wmd->defgrp_name));
}
else if (md->type == eModifierType_WeightVGMix) {
WeightVGMixModifierData *wmd= (WeightVGMixModifierData*)md;
rna_object_vgroup_name_set(ptr, value, wmd->defgrp_name_a, sizeof(wmd->defgrp_name_a));
}
else if (md->type == eModifierType_WeightVGProximity) {
WeightVGProximityModifierData *wmd= (WeightVGProximityModifierData*)md;
rna_object_vgroup_name_set(ptr, value, wmd->defgrp_name, sizeof(wmd->defgrp_name));
}
}
static void rna_WeightVGModifier_mask_vgroup_set(PointerRNA *ptr, const char *value)
{
ModifierData *md = (ModifierData*)ptr->data;
if (md->type == eModifierType_WeightVGEdit) {
WeightVGEditModifierData *wmd= (WeightVGEditModifierData*)md;
rna_object_vgroup_name_set(ptr, value, wmd->mask_defgrp_name, sizeof(wmd->mask_defgrp_name));
}
else if (md->type == eModifierType_WeightVGMix) {
WeightVGMixModifierData *wmd= (WeightVGMixModifierData*)md;
rna_object_vgroup_name_set(ptr, value, wmd->mask_defgrp_name, sizeof(wmd->mask_defgrp_name));
}
else if (md->type == eModifierType_WeightVGProximity) {
WeightVGProximityModifierData *wmd= (WeightVGProximityModifierData*)md;
rna_object_vgroup_name_set(ptr, value, wmd->mask_defgrp_name, sizeof(wmd->mask_defgrp_name));
}
}
static void rna_WeightVGMixModifier_vgroup2_set(PointerRNA *ptr, const char *value)
{
WeightVGMixModifierData *wmd= (WeightVGMixModifierData*)ptr->data;
rna_object_vgroup_name_set(ptr, value, wmd->defgrp_name_b, sizeof(wmd->defgrp_name_b));
}
static void rna_MappingInfo_uvlayer_set(PointerRNA *ptr, const char *value)
{
MappingInfoModifierData *mmd= (MappingInfoModifierData *)ptr->data;
@ -403,6 +452,23 @@ static void rna_WaveModifier_uvlayer_set(PointerRNA *ptr, const char *value)
rna_object_uvlayer_name_set(ptr, value, wmd->uvlayer_name, sizeof(wmd->uvlayer_name));
}
static void rna_WeightVGModifier_mask_uvlayer_set(PointerRNA *ptr, const char *value)
{
ModifierData *md = (ModifierData*)ptr->data;
if (md->type == eModifierType_WeightVGEdit) {
WeightVGEditModifierData *wmd = (WeightVGEditModifierData*)md;
rna_object_uvlayer_name_set(ptr, value, wmd->mask_tex_uvlayer_name, sizeof(wmd->mask_tex_uvlayer_name));
}
else if (md->type == eModifierType_WeightVGMix) {
WeightVGMixModifierData *wmd = (WeightVGMixModifierData*)md;
rna_object_uvlayer_name_set(ptr, value, wmd->mask_tex_uvlayer_name, sizeof(wmd->mask_tex_uvlayer_name));
}
else if (md->type == eModifierType_WeightVGProximity) {
WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData*)md;
rna_object_uvlayer_name_set(ptr, value, wmd->mask_tex_uvlayer_name, sizeof(wmd->mask_tex_uvlayer_name));
}
}
static void rna_MultiresModifier_level_range(PointerRNA *ptr, int *min, int *max)
{
MultiresModifierData *mmd = (MultiresModifierData*)ptr->data;
@ -1410,8 +1476,8 @@ static void rna_def_modifier_edgesplit(BlenderRNA *brna)
RNA_def_property_ui_range(prop, 0, DEG2RAD(180), 100, 2);
#else
prop= RNA_def_property(srna, "split_angle", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0, 90);
RNA_def_property_ui_range(prop, 0, 90, 100, 2);
RNA_def_property_range(prop, 0, 180);
RNA_def_property_ui_range(prop, 0, 180, 100, 2);
#endif
RNA_def_property_ui_text(prop, "Split Angle", "Angle above which to split edges");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
@ -2423,6 +2489,298 @@ static void rna_def_modifier_screw(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Modifier_update");*/
}
static void rna_def_modifier_weightvg_mask(BlenderRNA *brna, StructRNA *srna)
{
static EnumPropertyItem weightvg_mask_tex_map_items[] = {
{MOD_DISP_MAP_LOCAL, "LOCAL", 0, "Local", ""},
{MOD_DISP_MAP_GLOBAL, "GLOBAL", 0, "Global", ""},
{MOD_DISP_MAP_OBJECT, "OBJECT", 0, "Object", ""},
{MOD_DISP_MAP_UV, "UV", 0, "UV", ""},
{0, NULL, 0, NULL, NULL}};
static EnumPropertyItem weightvg_mask_tex_used_items[] = {
{MOD_WVG_MASK_TEX_USE_INT, "INT", 0, "Intensity", ""},
{MOD_WVG_MASK_TEX_USE_RED, "RED", 0, "Red", ""},
{MOD_WVG_MASK_TEX_USE_GREEN, "GREEN", 0, "Green", ""},
{MOD_WVG_MASK_TEX_USE_BLUE, "BLUE", 0, "Blue", ""},
{MOD_WVG_MASK_TEX_USE_HUE, "HUE", 0, "Hue", ""},
{MOD_WVG_MASK_TEX_USE_SAT, "SAT", 0, "Saturation", ""},
{MOD_WVG_MASK_TEX_USE_VAL, "VAL", 0, "Value", ""},
{MOD_WVG_MASK_TEX_USE_ALPHA, "ALPHA", 0, "Alpha", ""},
{0, NULL, 0, NULL, NULL}};
PropertyRNA *prop;
prop= RNA_def_property(srna, "mask_constant", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
RNA_def_property_ui_range(prop, -1.0, 1.0, 10, 0);
RNA_def_property_ui_text(prop, "Influence", "Global influence of current modifications on vgroup.");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop= RNA_def_property(srna, "mask_vertex_group", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "mask_defgrp_name");
RNA_def_property_ui_text(prop, "Mask VGroup", "Masking vertex group name.");
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_WeightVGModifier_mask_vgroup_set");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop= RNA_def_property(srna, "mask_texture", PROP_POINTER, PROP_NONE);
RNA_def_property_ui_text(prop, "Masking Tex", "Masking texture.");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop= RNA_def_property(srna, "mask_tex_use_channel", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, weightvg_mask_tex_used_items);
RNA_def_property_ui_text(prop, "Use Channel", "Which texture channel to use for masking.");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop= RNA_def_property(srna, "mask_tex_mapping", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, weightvg_mask_tex_map_items);
RNA_def_property_ui_text(prop, "Texture Coordinates", "Which texture coordinates "
"to use for mapping.");
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop= RNA_def_property(srna, "mask_tex_uv_layer", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "mask_tex_uvlayer_name");
RNA_def_property_ui_text(prop, "UV Layer", "UV layer name");
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_WeightVGModifier_mask_uvlayer_set");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop= RNA_def_property(srna, "mask_tex_map_object", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "mask_tex_map_obj");
RNA_def_property_ui_text(prop, "Texture Coordinate Object", "Which object to take texture "
"coordinates from.");
RNA_def_property_flag(prop, PROP_EDITABLE|PROP_ID_SELF_CHECK);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
}
static void rna_def_modifier_weightvgedit(BlenderRNA *brna)
{
static EnumPropertyItem weightvg_edit_mapping_mode_items[] = {
{MOD_WVG_MAPPING_NONE, "LINEAR", ICON_LINCURVE, "Linear", ""},
{MOD_WVG_MAPPING_CURVE, "CURVE", ICON_RNDCURVE, "Custom Curve", ""},
{MOD_WVG_MAPPING_SHARP, "SHARP", ICON_SHARPCURVE, "Sharp", ""},
{MOD_WVG_MAPPING_SMOOTH, "SMOOTH", ICON_SMOOTHCURVE, "Smooth", ""},
{MOD_WVG_MAPPING_ROOT, "ROOT", ICON_ROOTCURVE, "Root", ""},
{MOD_WVG_MAPPING_SPHERE, "ICON_SPHERECURVE", ICON_SPHERECURVE, "Sphere", ""},
{MOD_WVG_MAPPING_RANDOM, "RANDOM", ICON_RNDCURVE, "Random", ""},
{MOD_WVG_MAPPING_STEP, "STEP", ICON_NOCURVE, "Median Step", ""}, /* Would need a better icon... */
{0, NULL, 0, NULL, NULL}};
StructRNA *srna;
PropertyRNA *prop;
srna= RNA_def_struct(brna, "WeightVGEditModifier", "Modifier");
RNA_def_struct_ui_text(srna, "WeightVG Edit Modifier",
"Edit the weights of vertices in a group.");
RNA_def_struct_sdna(srna, "WeightVGEditModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_WEIGHTVG);
prop= RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "defgrp_name");
RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name.");
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_WeightVGModifier_vgroup_set");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop= RNA_def_property(srna, "mapping_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, weightvg_edit_mapping_mode_items);
RNA_def_property_ui_text(prop, "Mapping Mode", "How weights are mapped to there new values.");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop= RNA_def_property(srna, "use_add", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "edit_flags", MOD_WVG_EDIT_ADD2VG);
RNA_def_property_ui_text(prop, "Group Add", "Add vertices with weight over threshold "
"to vgroup.");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop= RNA_def_property(srna, "use_remove", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "edit_flags", MOD_WVG_EDIT_REMFVG);
RNA_def_property_ui_text(prop, "Group Remove", "Remove vertices with weight below threshold "
"from vgroup.");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop= RNA_def_property(srna, "default_weight", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 1.0f);
RNA_def_property_ui_range(prop, 0.0, 1.0, 10, 0);
RNA_def_property_ui_text(prop, "Default Weight", "Default weight a vertex will have if "
"it is not in the vgroup.");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop= RNA_def_property(srna, "map_curve", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "cmap_curve");
RNA_def_property_ui_text(prop, "Mapping Curve", "Custom mapping curve.");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop= RNA_def_property(srna, "add_threshold", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "add_threshold");
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_ui_range(prop, 0.0, 1.0, 10, 0);
RNA_def_property_ui_text(prop, "Add Threshold", "Lower bound for a vertex's weight "
"to be added to the vgroup.");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop= RNA_def_property(srna, "remove_threshold", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "rem_threshold");
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_ui_range(prop, 0.0, 1.0, 10, 0);
RNA_def_property_ui_text(prop, "Rem Threshold", "Upper bound for a vertex's weight "
"to be removed from the vgroup.");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
/* Common masking properties. */
rna_def_modifier_weightvg_mask(brna, srna);
}
static void rna_def_modifier_weightvgmix(BlenderRNA *brna)
{
static EnumPropertyItem weightvg_mix_modes_items[] = {
{MOD_WVG_MIX_SET, "SET", 0, "Replace weights", ""},
{MOD_WVG_MIX_ADD, "ADD", 0, "Add to weights", ""},
{MOD_WVG_MIX_SUB, "SUB", 0, "Subtract from weights", ""},
{MOD_WVG_MIX_MUL, "MUL", 0, "Multiply weights", ""},
{MOD_WVG_MIX_DIV, "DIV", 0, "Divide weights", ""},
{MOD_WVG_MIX_DIF, "DIF", 0, "Difference", ""},
{MOD_WVG_MIX_AVG, "AVG", 0, "Average", ""},
{0, NULL, 0, NULL, NULL}};
static EnumPropertyItem weightvg_mix_set_items[] = {
{MOD_WVG_SET_ALL, "ALL", 0, "All vertices", ""},
{MOD_WVG_SET_A, "A", 0, "Vertices from group A", ""},
{MOD_WVG_SET_B, "B", 0, "Vertices from group B", ""},
{MOD_WVG_SET_OR, "OR", 0, "Vertices from one group", ""},
{MOD_WVG_SET_AND, "AND", 0, "Vertices from both groups", ""},
{0, NULL, 0, NULL, NULL}};
StructRNA *srna;
PropertyRNA *prop;
srna= RNA_def_struct(brna, "WeightVGMixModifier", "Modifier");
RNA_def_struct_ui_text(srna, "WeightVG Mix Modifier",
"Mix the weights of two vertex groups.");
RNA_def_struct_sdna(srna, "WeightVGMixModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_WEIGHTVG);
prop= RNA_def_property(srna, "vertex_group_a", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "defgrp_name_a");
RNA_def_property_ui_text(prop, "Vertex Group A", "First vertex group name.");
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_WeightVGModifier_vgroup_set");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop= RNA_def_property(srna, "vertex_group_b", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "defgrp_name_b");
RNA_def_property_ui_text(prop, "Vertex Group B", "Second vertex group name.");
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_WeightVGMixModifier_vgroup2_set");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop= RNA_def_property(srna, "default_weight_a", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 1.0f);
RNA_def_property_ui_range(prop, 0.0, 1.0, 10, 0);
RNA_def_property_ui_text(prop, "Default Weight A", "Default weight a vertex will have if "
"it is not in the first vgroup.");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop= RNA_def_property(srna, "default_weight_b", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 1.0f);
RNA_def_property_ui_range(prop, 0.0, 1.0, 10, 0);
RNA_def_property_ui_text(prop, "Default Weight B", "Default weight a vertex will have if "
"it is not in the second vgroup.");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop= RNA_def_property(srna, "mix_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, weightvg_mix_modes_items);
RNA_def_property_ui_text(prop, "Mix Mode", "How weights from vgroup 2 affect weights "
"of vgroup 1.");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop= RNA_def_property(srna, "mix_set", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, weightvg_mix_set_items);
RNA_def_property_ui_text(prop, "Vertex Set", "Which vertices should be affected.");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
/* Common masking properties. */
rna_def_modifier_weightvg_mask(brna, srna);
}
static void rna_def_modifier_weightvgproximity(BlenderRNA *brna)
{
static EnumPropertyItem weightvg_proximity_modes_items[] = {
{MOD_WVG_PROXIMITY_OBJECT, "OBJECT", 0, "Object Distance",
"Use distance between affected and target objects."},
{MOD_WVG_PROXIMITY_GEOMETRY, "GEOMETRY", 0, "Geometry Distance",
"Use distance between affected object's vertices and target object, or target object's geometry."},
{0, NULL, 0, NULL, NULL}};
static EnumPropertyItem proximity_geometry_items[] = {
{MOD_WVG_PROXIMITY_GEOM_VERTS, "VERTEX", ICON_VERTEXSEL, "Vertex", ""},
{MOD_WVG_PROXIMITY_GEOM_EDGES, "EDGE", ICON_EDGESEL, "Edge", ""},
{MOD_WVG_PROXIMITY_GEOM_FACES, "FACE", ICON_FACESEL, "Face", ""},
{0, NULL, 0, NULL, NULL}};
static EnumPropertyItem weightvg_proximity_mapping_mode_items[] = {
{MOD_WVG_MAPPING_NONE, "LINEAR", ICON_LINCURVE, "Linear", ""},
/* No curve mapping here! */
{MOD_WVG_MAPPING_SHARP, "SHARP", ICON_SHARPCURVE, "Sharp", ""},
{MOD_WVG_MAPPING_SMOOTH, "SMOOTH", ICON_SMOOTHCURVE, "Smooth", ""},
{MOD_WVG_MAPPING_ROOT, "ROOT", ICON_ROOTCURVE, "Root", ""},
{MOD_WVG_MAPPING_SPHERE, "ICON_SPHERECURVE", ICON_SPHERECURVE, "Sphere", ""},
{MOD_WVG_MAPPING_RANDOM, "RANDOM", ICON_RNDCURVE, "Random", ""},
{MOD_WVG_MAPPING_STEP, "STEP", ICON_NOCURVE, "Median Step", ""}, /* Would need a better icon... */
{0, NULL, 0, NULL, NULL}};
StructRNA *srna;
PropertyRNA *prop;
srna= RNA_def_struct(brna, "WeightVGProximityModifier", "Modifier");
RNA_def_struct_ui_text(srna, "WeightVG Proximity Modifier",
"Set the weights of vertices in a group from a target object's "
"distance.");
RNA_def_struct_sdna(srna, "WeightVGProximityModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_WEIGHTVG);
prop= RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "defgrp_name");
RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name.");
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_WeightVGModifier_vgroup_set");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop= RNA_def_property(srna, "proximity_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, weightvg_proximity_modes_items);
RNA_def_property_ui_text(prop, "Proximity Mode", "Which distances to target object to use.");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop= RNA_def_property(srna, "proximity_geometry", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "proximity_flags");
RNA_def_property_enum_items(prop, proximity_geometry_items);
RNA_def_property_flag(prop, PROP_ENUM_FLAG); /* important to run before default set */
RNA_def_property_ui_text(prop, "Proximity Geometry", "Use shortest distance to target object's geometry as weight");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop= RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "proximity_ob_target");
RNA_def_property_ui_text(prop, "Target Object", "Object to calculate vertices distances from.");
RNA_def_property_flag(prop, PROP_EDITABLE|PROP_ID_SELF_CHECK);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop= RNA_def_property(srna, "min_dist", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, FLT_MAX);
RNA_def_property_ui_range(prop, 0.0, 1000.0, 10, 0);
RNA_def_property_ui_text(prop, "Lowest Dist", "Distance mapping to weight 0.0.");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop= RNA_def_property(srna, "max_dist", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, FLT_MAX);
RNA_def_property_ui_range(prop, 0.0, 1000.0, 10, 0);
RNA_def_property_ui_text(prop, "Highest Dist", "Distance mapping to weight 1.0.");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop= RNA_def_property(srna, "mapping_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, weightvg_proximity_mapping_mode_items);
RNA_def_property_ui_text(prop, "Mapping Mode", "How weights are mapped to there new values.");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
/* Common masking properties. */
rna_def_modifier_weightvg_mask(brna, srna);
}
static void rna_def_modifier_ngoninterp(BlenderRNA *brna)
@ -2539,6 +2897,9 @@ void RNA_def_modifier(BlenderRNA *brna)
rna_def_modifier_smoke(brna);
rna_def_modifier_solidify(brna);
rna_def_modifier_screw(brna);
rna_def_modifier_weightvgedit(brna);
rna_def_modifier_weightvgmix(brna);
rna_def_modifier_weightvgproximity(brna);
rna_def_modifier_ngoninterp(brna);
}

@ -83,11 +83,16 @@ set(SRC
intern/MOD_uvproject.c
intern/MOD_warp.c
intern/MOD_wave.c
intern/MOD_weightvg_util.c
intern/MOD_weightvgedit.c
intern/MOD_weightvgmix.c
intern/MOD_weightvgproximity.c
MOD_modifiertypes.h
intern/MOD_boolean_util.h
intern/MOD_fluidsim_util.h
intern/MOD_util.h
intern/MOD_weightvg_util.h
)
if(WITH_MOD_BOOLEAN)

@ -72,6 +72,9 @@ extern ModifierTypeInfo modifierType_ShapeKey;
extern ModifierTypeInfo modifierType_Solidify;
extern ModifierTypeInfo modifierType_Screw;
extern ModifierTypeInfo modifierType_Warp;
extern ModifierTypeInfo modifierType_WeightVGEdit;
extern ModifierTypeInfo modifierType_WeightVGMix;
extern ModifierTypeInfo modifierType_WeightVGProximity;
extern ModifierTypeInfo modifierType_NgonInterp;
/* MOD_util.c */

@ -295,6 +295,9 @@ void modifier_type_init(ModifierTypeInfo *types[])
INIT_TYPE(Solidify);
INIT_TYPE(Screw);
INIT_TYPE(Warp);
INIT_TYPE(WeightVGEdit);
INIT_TYPE(WeightVGMix);
INIT_TYPE(WeightVGProximity);
INIT_TYPE(NgonInterp);
#undef INIT_TYPE
}

@ -0,0 +1,306 @@
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2011 by Bastien Montagne.
* All rights reserved.
*
* Contributor(s): None yet.
*
* ***** END GPL LICENSE BLOCK *****
*
*/
/*
* XXX I'd like to make modified weights visible in WeightPaint mode,
* but couldn't figure a way to do this
* Maybe this will need changes in mesh_calc_modifiers (DerivedMesh.c)?
* Or the WeightPaint mode code itself?
*/
#include "BLI_math.h"
#include "BLI_rand.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "DNA_color_types.h" /* CurveMapping. */
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_colortools.h" /* CurveMapping. */
#include "BKE_deform.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_texture.h" /* Texture masking. */
#include "depsgraph_private.h"
#include "MEM_guardedalloc.h"
#include "MOD_util.h"
#include "MOD_weightvg_util.h"
#include "RE_shader_ext.h" /* Texture masking. */
/* Maps new_w weights in place, using either one of the predifined functions, or a custom curve.
* Return values are in new_w.
* If indices is not NULL, it must be a table of same length as org_w and new_w, mapping to the real
* vertex index (in case the weight tables do not cover the whole vertices...).
* cmap might be NULL, in which case curve mapping mode will return unmodified data.
*/
void weightvg_do_map(int num, float *new_w, short mode, CurveMapping *cmap)
{
int i;
/* Return immediately, if we have nothing to do! */
/* Also security checks... */
if(((mode == MOD_WVG_MAPPING_CURVE) && (cmap == NULL))
|| !ELEM7(mode, MOD_WVG_MAPPING_CURVE, MOD_WVG_MAPPING_SHARP, MOD_WVG_MAPPING_SMOOTH,
MOD_WVG_MAPPING_ROOT, MOD_WVG_MAPPING_SPHERE, MOD_WVG_MAPPING_RANDOM,
MOD_WVG_MAPPING_STEP))
return;
/* Map each weight (vertex) to its new value, accordingly to the chosen mode. */
for(i = 0; i < num; ++i) {
float fac = new_w[i];
/* Code borrowed from the warp modifier. */
/* Closely matches PROP_SMOOTH and similar. */
switch(mode) {
case MOD_WVG_MAPPING_CURVE:
fac = curvemapping_evaluateF(cmap, 0, fac);
break;
case MOD_WVG_MAPPING_SHARP:
fac = fac*fac;
break;
case MOD_WVG_MAPPING_SMOOTH:
fac = 3.0f*fac*fac - 2.0f*fac*fac*fac;
break;
case MOD_WVG_MAPPING_ROOT:
fac = (float)sqrt(fac);
break;
case MOD_WVG_MAPPING_SPHERE:
fac = (float)sqrt(2*fac - fac * fac);
break;
case MOD_WVG_MAPPING_RANDOM:
BLI_srand(BLI_rand()); /* random seed */
fac = BLI_frand()*fac;
break;
case MOD_WVG_MAPPING_STEP:
fac = (fac >= 0.5f)?1.0f:0.0f;
break;
}
new_w[i] = fac;
}
}
/* Applies new_w weights to org_w ones, using either a texture, vgroup or constant value as factor.
* Return values are in org_w.
* If indices is not NULL, it must be a table of same length as org_w and new_w, mapping to the real
* vertex index (in case the weight tables do not cover the whole vertices...).
* XXX The standard factor value is assumed in [0.0, 1.0] range. Else, weird results might appear.
*/
void weightvg_do_mask(int num, const int *indices, float *org_w, const float *new_w,
Object *ob, DerivedMesh *dm, float fact, const char defgrp_name[32],
Tex *texture, int tex_use_channel, int tex_mapping,
Object *tex_map_object, const char *tex_uvlayer_name)
{
int ref_didx;
int i;
/* If influence factor is null, nothing to do! */
if (fact == 0.0f) return;
/* If we want to mask vgroup weights from a texture. */
if (texture) {
/* The texture coordinates. */
float (*tex_co)[3];
/* See mapping note below… */
MappingInfoModifierData t_map;
float (*v_co)[3];
/* Use new generic get_texture_coords, but do not modify our DNA struct for it…
* XXX Why use a ModifierData stuff here ? Why not a simple, generic struct for parameters ?
* What e.g. if a modifier wants to use several textures ?
* Why use only v_co, and not MVert (or both) ?
*/
t_map.texture = texture;
t_map.map_object = tex_map_object;
BLI_strncpy(t_map.uvlayer_name, tex_uvlayer_name, sizeof(t_map.uvlayer_name));
t_map.texmapping = tex_mapping;
v_co = MEM_mallocN(sizeof(*v_co) * num, "WeightVG Modifier, TEX mode, v_co");
dm->getVertCos(dm, v_co);
tex_co = MEM_callocN(sizeof(*tex_co) * num, "WeightVG Modifier, TEX mode, tex_co");
get_texture_coords(&t_map, ob, dm, v_co, tex_co, num);
MEM_freeN(v_co);
/* For each weight (vertex), make the mix between org and new weights. */
for(i = 0; i < num; ++i) {
int idx = indices ? indices[i] : i;
TexResult texres;
float h, s, v; /* For HSV color space. */
texres.nor = NULL;
get_texture_value(texture, tex_co[idx], &texres);
/* Get the good channel value… */
switch(tex_use_channel) {
case MOD_WVG_MASK_TEX_USE_INT:
org_w[i] = (new_w[i] * texres.tin * fact) + (org_w[i] * (1.0f - (texres.tin*fact)));
break;
case MOD_WVG_MASK_TEX_USE_RED:
org_w[i] = (new_w[i] * texres.tr * fact) + (org_w[i] * (1.0f - (texres.tr*fact)));
break;
case MOD_WVG_MASK_TEX_USE_GREEN:
org_w[i] = (new_w[i] * texres.tg * fact) + (org_w[i] * (1.0f - (texres.tg*fact)));
break;
case MOD_WVG_MASK_TEX_USE_BLUE:
org_w[i] = (new_w[i] * texres.tb * fact) + (org_w[i] * (1.0f - (texres.tb*fact)));
break;
case MOD_WVG_MASK_TEX_USE_HUE:
rgb_to_hsv(texres.tr, texres.tg, texres.tb, &h, &s, &v);
org_w[i] = (new_w[i] * h * fact) + (org_w[i] * (1.0f - (h*fact)));
break;
case MOD_WVG_MASK_TEX_USE_SAT:
rgb_to_hsv(texres.tr, texres.tg, texres.tb, &h, &s, &v);
org_w[i] = (new_w[i] * s * fact) + (org_w[i] * (1.0f - (s*fact)));
break;
case MOD_WVG_MASK_TEX_USE_VAL:
rgb_to_hsv(texres.tr, texres.tg, texres.tb, &h, &s, &v);
org_w[i] = (new_w[i] * v * fact) + (org_w[i] * (1.0f - (v*fact)));
break;
case MOD_WVG_MASK_TEX_USE_ALPHA:
org_w[i] = (new_w[i] * texres.ta * fact) + (org_w[i] * (1.0f - (texres.ta*fact)));
break;
default:
org_w[i] = (new_w[i] * texres.tin * fact) + (org_w[i] * (1.0f - (texres.tin*fact)));
break;
}
}
MEM_freeN(tex_co);
}
else if ((ref_didx = defgroup_name_index(ob, defgrp_name)) != -1) {
MDeformVert *dvert = NULL;
/* Check whether we want to set vgroup weights from a constant weight factor or a vertex
* group.
*/
/* Get vgroup idx from its name. */
/* Proceed only if vgroup is valid, else use constant factor. */
/* Get actual dverts (ie vertex group data). */
dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
/* Proceed only if vgroup is valid, else assume factor = O. */
if (dvert == NULL) return;
/* For each weight (vertex), make the mix between org and new weights. */
for (i = 0; i < num; i++) {
int idx = indices ? indices[i] : i;
const float f= defvert_find_weight(&dvert[idx], ref_didx) * fact;
org_w[i] = (new_w[i] * f) + (org_w[i] * (1.0f-f));
/* If that vertex is not in ref vgroup, assume null factor, and hence do nothing! */
}
}
else {
/* Default "influence" behavior. */
/* For each weight (vertex), make the mix between org and new weights. */
const float ifact= 1.0f - fact;
for (i = 0; i < num; i++) {
org_w[i] = (new_w[i] * fact) + (org_w[i] * ifact);
}
}
}
/* Applies weights to given vgroup (defgroup), and optionnaly add/remove vertices from the group.
* If indices is not NULL, it must be a table of same length as weights, mapping to the real
* vertex index (in case the weight table does not cover the whole vertices...).
*/
void weightvg_update_vg(MDeformVert *dvert, int defgrp_idx, int num,
const int *indices, const float *weights, int do_add,
float add_thresh, int do_rem, float rem_thresh)
{
int i;
for (i = 0; i < num; i++) {
int j;
int add2vg = do_add;
float w = weights[i];
MDeformVert *dv = &dvert[indices ? indices[i] : i];
MDeformWeight *newdw;
/* Never allow weights out of [0.0, 1.0] range. */
CLAMP(w, 0.0f, 1.0f);
/* Let's first check to see if this vert is already in the weight group if so
* let's update it, or remove it if needed.
*/
for (j = 0; j < dv->totweight; j++) {
/* If this weight corresponds to the deform group, update the value or,
* if lower than rem_threshold, remove the vertex from the vgroup.
*/
if (dv->dw[j].def_nr == defgrp_idx) {
/* Remove the vertex from this vgroup if needed. */
if (do_rem && w < rem_thresh) {
/* TODO, move this into deform.c to make into a generic function */
dv->totweight--;
/* If there are still other deform weights attached to this vert then remove
* this deform weight, and reshuffle the others.
*/
if(dv->totweight) {
newdw = MEM_mallocN(sizeof(MDeformWeight)*(dv->totweight), "deformWeight");
if(dv->dw){
memcpy(newdw, dv->dw, sizeof(MDeformWeight)*j);
memcpy(newdw+j, dv->dw+j+1, sizeof(MDeformWeight)*(dv->totweight-j));
MEM_freeN(dv->dw);
}
dv->dw = newdw;
}
/* If there are no other deform weights left then just remove this one. */
else {
MEM_freeN(dv->dw);
dv->dw = NULL;
}
}
/* Else, just set the new computed weight. */
else {
dv->dw[j].weight = w;
}
add2vg = FALSE;
break;
}
}
/* If the vert wasn't in the deform group, add it if needed!
*/
if ((add2vg == TRUE) && w > add_thresh) {
/* TODO, mvoe into deform.c and make into a generic function, this assumes the vertex
* groups have already been checked, so this has to remain low level */
newdw = MEM_callocN(sizeof(MDeformWeight)*(dv->totweight+1), "WeightVGEdit Modifier, deformWeight");
if(dv->dw) {
memcpy(newdw, dv->dw, sizeof(MDeformWeight)*dv->totweight);
MEM_freeN(dv->dw);
}
dv->dw = newdw;
dv->dw[dv->totweight].weight = w;
dv->dw[dv->totweight].def_nr = defgrp_idx;
dv->totweight++;
}
}
}

@ -0,0 +1,90 @@
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2011 by Bastien Montagne.
* All rights reserved.
*
* Contributor(s): None yet.
*
* ***** END GPL LICENSE BLOCK *****
*
*/
/** \file blender/modifiers/intern/MOD_util.h
* \ingroup modifiers
*/
#ifndef MOD_WEIGHTVG_UTIL_H
#define MOD_WEIGHTVG_UTIL_H
/* so modifier types match their defines */
#include "MOD_modifiertypes.h"
struct CurveMapping;
struct DerivedMesh;
struct Object;
struct Tex;
/*
* XXX I'd like to make modified weights visible in WeightPaint mode,
* but couldn't figure a way to do this
* Maybe this will need changes in mesh_calc_modifiers (DerivedMesh.c)?
* Or the WeightPaint mode code itself?
*/
/**************************************
* Util functions. *
**************************************/
/* We cannot divide by zero (what a surprise…).
* So if -MOD_WEIGHTVGROUP_DIVMODE_ZEROFLOOR < weightf < MOD_WEIGHTVGROUP_DIVMODE_ZEROFLOOR,
* we clamp weightf to this value (or its negative version).
* Also used to avoid null power factor.
*/
#define MOD_WVG_ZEROFLOOR 1.0e-32f
/* Maps new_w weights in place, using either one of the predifined functions, or a custom curve.
* Return values are in new_w.
* If indices is not NULL, it must be a table of same length as org_w and new_w, mapping to the real
* vertex index (in case the weight tables do not cover the whole vertices...).
* cmap might be NULL, in which case curve mapping mode will return unmodified data.
*/
void weightvg_do_map(int num, float *new_w, short mode, struct CurveMapping *cmap);
/* Applies new_w weights to org_w ones, using either a texture, vgroup or constant value as factor.
* Return values are in org_w.
* If indices is not NULL, it must be a table of same length as org_w and new_w, mapping to the real
* vertex index (in case the weight tables do not cover the whole vertices...).
* XXX The standard factor value is assumed in [0.0, 1.0] range. Else, weird results might appear.
*/
void weightvg_do_mask(int num, const int *indices, float *org_w, const float *new_w, Object *ob,
DerivedMesh *dm, float fact, const char defgrp_name[32], Tex *texture,
int tex_use_channel, int tex_mapping, Object *tex_map_object,
const char *tex_uvlayer_name);
/* Applies weights to given vgroup (defgroup), and optionnaly add/remove vertices from the group.
* If indices is not NULL, it must be a table of same length as weights, mapping to the real
* vertex index (in case the weight table does not cover the whole vertices...).
*/
void weightvg_update_vg(MDeformVert *dvert, int defgrp_idx, int num,
const int *indices, const float *weights, int do_add,
float add_thresh, int do_rem, float rem_thresh);
#endif /* MOD_WEIGHTVG_UTIL_H */

@ -0,0 +1,326 @@
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2011 by Bastien Montagne.
* All rights reserved.
*
* Contributor(s): None yet.
*
* ***** END GPL LICENSE BLOCK *****
*
*/
/*
* XXX I'd like to make modified weights visible in WeightPaint mode,
* but couldn't figure a way to do this
* Maybe this will need changes in mesh_calc_modifiers (DerivedMesh.c)?
* Or the WeightPaint mode code itself?
*/
#include "BLI_utildefines.h"
#include "BLI_math.h"
#include "BLI_string.h"
#include "DNA_color_types.h" /* CurveMapping. */
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_colortools.h" /* CurveMapping. */
#include "BKE_deform.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_texture.h" /* Texture masking. */
#include "depsgraph_private.h"
#include "MEM_guardedalloc.h"
#include "MOD_util.h"
#include "MOD_weightvg_util.h"
/**************************************
* Modifiers functions. *
**************************************/
static void initData(ModifierData *md)
{
WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
wmd->edit_flags = 0;
wmd->mapping_mode = MOD_WVG_MAPPING_NONE;
wmd->default_weight = 0.0f;
wmd->cmap_curve = curvemapping_add(1, 0.0, 0.0, 1.0, 1.0);
curvemapping_initialize(wmd->cmap_curve);
wmd->rem_threshold = 0.01f;
wmd->add_threshold = 0.01f;
wmd->mask_constant = 1.0f;
wmd->mask_tex_use_channel = MOD_WVG_MASK_TEX_USE_INT; /* Use intensity by default. */
wmd->mask_tex_mapping = MOD_DISP_MAP_LOCAL;
}
static void freeData(ModifierData *md)
{
WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
curvemapping_free(wmd->cmap_curve);
}
static void copyData(ModifierData *md, ModifierData *target)
{
WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
WeightVGEditModifierData *twmd = (WeightVGEditModifierData*) target;
BLI_strncpy(twmd->defgrp_name, wmd->defgrp_name, sizeof(twmd->defgrp_name));
twmd->edit_flags = wmd->edit_flags;
twmd->mapping_mode = wmd->mapping_mode;
twmd->default_weight = wmd->default_weight;
twmd->cmap_curve = curvemapping_copy(wmd->cmap_curve);
twmd->add_threshold = wmd->add_threshold;
twmd->rem_threshold = wmd->rem_threshold;
twmd->mask_constant = wmd->mask_constant;
BLI_strncpy(twmd->mask_defgrp_name, wmd->mask_defgrp_name, sizeof(twmd->mask_defgrp_name));
twmd->mask_texture = wmd->mask_texture;
twmd->mask_tex_use_channel = wmd->mask_tex_use_channel;
twmd->mask_tex_mapping = wmd->mask_tex_mapping;
twmd->mask_tex_map_obj = wmd->mask_tex_map_obj;
BLI_strncpy(twmd->mask_tex_uvlayer_name, wmd->mask_tex_uvlayer_name, sizeof(twmd->mask_tex_uvlayer_name));
}
static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
{
WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
CustomDataMask dataMask = 0;
/* We need vertex groups! */
dataMask |= CD_MASK_MDEFORMVERT;
/* Ask for UV coordinates if we need them. */
if(wmd->mask_tex_mapping == MOD_DISP_MAP_UV)
dataMask |= CD_MASK_MTFACE;
return dataMask;
}
static int dependsOnTime(ModifierData *md)
{
WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
if(wmd->mask_texture)
return BKE_texture_dependsOnTime(wmd->mask_texture);
return 0;
}
static void foreachObjectLink(ModifierData *md, Object *ob,
void (*walk)(void *userData, Object *ob, Object **obpoin),
void *userData)
{
WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
walk(userData, ob, &wmd->mask_tex_map_obj);
}
static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
{
WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
walk(userData, ob, (ID **)&wmd->mask_texture);
foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
}
static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void *userData)
{
walk(userData, ob, md, "mask_texture");
}
static void updateDepgraph(ModifierData *md, DagForest *forest, struct Scene *UNUSED(scene),
Object *UNUSED(ob), DagNode *obNode)
{
WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
DagNode *curNode;
if(wmd->mask_tex_map_obj && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
curNode = dag_get_node(forest, wmd->mask_tex_map_obj);
dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA|DAG_RL_OB_DATA,
"WeightVGEdit Modifier");
}
if(wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL)
dag_add_relation(forest, obNode, obNode, DAG_RL_DATA_DATA|DAG_RL_OB_DATA,
"WeightVGEdit Modifier");
}
static int isDisabled(ModifierData *md, int UNUSED(useRenderParams))
{
WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
/* If no vertex group, bypass. */
return (wmd->defgrp_name[0] == '\0');
}
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData,
int UNUSED(useRenderParams), int UNUSED(isFinalCalc))
{
WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md;
DerivedMesh *dm = derivedData, *ret = NULL;
#if 0
Mesh *ob_m = NULL;
#endif
MDeformVert *dvert = NULL;
float *org_w; /* Array original weights. */
float *new_w; /* Array new weights. */
int numVerts;
int defgrp_idx;
int i;
char rel_ret = 0; /* Boolean, whether we have to release ret dm or not, when not using it! */
/* Flags. */
int do_add = (wmd->edit_flags & MOD_WVG_EDIT_ADD2VG) != 0;
int do_rem = (wmd->edit_flags & MOD_WVG_EDIT_REMFVG) != 0;
/* Get number of verts. */
numVerts = dm->getNumVerts(dm);
/* Check if we can just return the original mesh.
* Must have verts and therefore verts assigned to vgroups to do anything useful!
*/
if ((numVerts == 0) || (ob->defbase.first == NULL))
return dm;
/* Get vgroup idx from its name. */
defgrp_idx = defgroup_name_index(ob, wmd->defgrp_name);
if (defgrp_idx < 0)
return dm;
/* XXX All this to avoid copying dm when not needed… However, it nearly doubles compute
* time! See scene 5 of the WeighVG test file
*/
#if 0
/* Get actual dverts (ie vertex group data). */
dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
/* If no dverts, return unmodified data… */
if (dvert == NULL)
return dm;
/* Get org mesh, only to test whether affected cdata layer has already been copied
* somewhere up in the modifiers stack.
*/
ob_m = get_mesh(ob);
if (ob_m == NULL)
return dm;
/* Create a copy of our dmesh, only if our affected cdata layer is the same as org mesh. */
if (dvert == CustomData_get_layer(&ob_m->vdata, CD_MDEFORMVERT)) {
/* XXX Seems to create problems with weightpaint mode???
* I'm missing something here, I guess
*/
// DM_set_only_copy(dm, CD_MASK_MDEFORMVERT); /* Only copy defgroup layer. */
ret = CDDM_copy(dm);
dvert = ret->getVertDataArray(ret, CD_MDEFORMVERT);
if (dvert == NULL) {
ret->release(ret);
return dm;
}
rel_ret = 1;
}
else
ret = dm;
#else
ret = CDDM_copy(dm);
rel_ret = 1;
dvert = ret->getVertDataArray(ret, CD_MDEFORMVERT);
if (dvert == NULL) {
if (rel_ret)
ret->release(ret);
return dm;
}
#endif
/* Get org weights, assuming 0.0 for vertices not in given vgroup. */
org_w = MEM_mallocN(sizeof(float) * numVerts, "WeightVGEdit Modifier, org_w");
new_w = MEM_mallocN(sizeof(float) * numVerts, "WeightVGEdit Modifier, org_w");
for (i = 0; i < numVerts; i++) {
MDeformWeight *dw= defvert_find_index(&dvert[i], defgrp_idx);
org_w[i] = new_w[i] = wmd->default_weight;
if(dw) {
org_w[i] = new_w[i] = dw->weight;
}
}
/* Do mapping. */
if (wmd->mapping_mode != MOD_WVG_MAPPING_NONE) {
weightvg_do_map(numVerts, new_w, wmd->mapping_mode, wmd->cmap_curve);
}
/* Do masking. */
weightvg_do_mask(numVerts, NULL, org_w, new_w, ob, ret, wmd->mask_constant,
wmd->mask_defgrp_name, wmd->mask_texture, wmd->mask_tex_use_channel,
wmd->mask_tex_mapping, wmd->mask_tex_map_obj, wmd->mask_tex_uvlayer_name);
/* Update/add/remove from vgroup. */
weightvg_update_vg(dvert, defgrp_idx, numVerts, NULL, org_w, do_add, wmd->add_threshold,
do_rem, wmd->rem_threshold);
/* Freeing stuff. */
MEM_freeN(org_w);
MEM_freeN(new_w);
/* Return the vgroup-modified mesh. */
return ret;
}
static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
struct EditMesh *UNUSED(editData),
DerivedMesh *derivedData)
{
return applyModifier(md, ob, derivedData, 0, 1);
}
ModifierTypeInfo modifierType_WeightVGEdit = {
/* name */ "WeightVGEdit",
/* structName */ "WeightVGEditModifierData",
/* structSize */ sizeof(WeightVGEditModifierData),
/* type */ eModifierTypeType_Nonconstructive,
/* flags */ eModifierTypeFlag_AcceptsMesh
/* |eModifierTypeFlag_SupportsMapping*/
|eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ applyModifier,
/* applyModifierEM */ applyModifierEM,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
/* foreachIDLink */ foreachIDLink,
/* foreachTexLink */ foreachTexLink,
};

@ -0,0 +1,466 @@
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2011 by Bastien Montagne.
* All rights reserved.
*
* Contributor(s): None yet.
*
* ***** END GPL LICENSE BLOCK *****
*
*/
/*
* XXX I'd like to make modified weights visible in WeightPaint mode,
* but couldn't figure a way to do this
* Maybe this will need changes in mesh_calc_modifiers (DerivedMesh.c)?
* Or the WeightPaint mode code itself?
*/
#include "BLI_utildefines.h"
#include "BLI_math.h"
#include "BLI_string.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_deform.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_texture.h" /* Texture masking. */
#include "depsgraph_private.h"
#include "MEM_guardedalloc.h"
#include "MOD_util.h"
#include "MOD_weightvg_util.h"
/**
* This mixes the old weight with the new weight factor.
*/
static float mix_weight(float weight, float weight2, char mix_mode)
{
#if 0
/*
* XXX Don't know why, but the switch version takes many CPU time,
* and produces lag in realtime playback
*/
switch (mix_mode)
{
case MOD_WVG_MIX_ADD:
return (weight + weight2);
case MOD_WVG_MIX_SUB:
return (weight - weight2);
case MOD_WVG_MIX_MUL:
return (weight * weight2);
case MOD_WVG_MIX_DIV:
/* Avoid dividing by zero (or really small values). */
if (0.0 <= weight2 < MOD_WVG_ZEROFLOOR)
weight2 = MOD_WVG_ZEROFLOOR;
else if (-MOD_WVG_ZEROFLOOR < weight2)
weight2 = -MOD_WVG_ZEROFLOOR;
return (weight / weight2);
case MOD_WVG_MIX_DIF:
return (weight < weight2 ? weight2 - weight : weight - weight2);
case MOD_WVG_MIX_AVG:
return (weight + weight2) / 2.0;
case MOD_WVG_MIX_SET:
default:
return weight2;
}
#endif
if (mix_mode == MOD_WVG_MIX_SET)
return weight2;
else if (mix_mode == MOD_WVG_MIX_ADD)
return (weight + weight2);
else if (mix_mode == MOD_WVG_MIX_SUB)
return (weight - weight2);
else if (mix_mode == MOD_WVG_MIX_MUL)
return (weight * weight2);
else if (mix_mode == MOD_WVG_MIX_DIV) {
/* Avoid dividing by zero (or really small values). */
if (weight2 < 0.0f && weight2 > -MOD_WVG_ZEROFLOOR)
weight2 = -MOD_WVG_ZEROFLOOR;
else if (weight2 >= 0.0f && weight2 < MOD_WVG_ZEROFLOOR)
weight2 = MOD_WVG_ZEROFLOOR;
return (weight / weight2);
}
else if (mix_mode == MOD_WVG_MIX_DIF)
return (weight < weight2 ? weight2 - weight : weight - weight2);
else if (mix_mode == MOD_WVG_MIX_AVG)
return (weight + weight2) * 0.5f;
else return weight2;
}
/**************************************
* Modifiers functions. *
**************************************/
static void initData(ModifierData *md)
{
WeightVGMixModifierData *wmd = (WeightVGMixModifierData*) md;
wmd->default_weight_a = 0.0f;
wmd->default_weight_b = 0.0f;
wmd->mix_mode = MOD_WVG_MIX_SET;
wmd->mix_set = MOD_WVG_SET_AND;
wmd->mask_constant = 1.0f;
wmd->mask_tex_use_channel = MOD_WVG_MASK_TEX_USE_INT; /* Use intensity by default. */
wmd->mask_tex_mapping = MOD_DISP_MAP_LOCAL;
}
static void copyData(ModifierData *md, ModifierData *target)
{
WeightVGMixModifierData *wmd = (WeightVGMixModifierData*) md;
WeightVGMixModifierData *twmd = (WeightVGMixModifierData*) target;
BLI_strncpy(twmd->defgrp_name_a, wmd->defgrp_name_a, sizeof(twmd->defgrp_name_a));
BLI_strncpy(twmd->defgrp_name_b, wmd->defgrp_name_b, sizeof(twmd->defgrp_name_b));
twmd->default_weight_a = wmd->default_weight_a;
twmd->default_weight_b = wmd->default_weight_b;
twmd->mix_mode = wmd->mix_mode;
twmd->mix_set = wmd->mix_set;
twmd->mask_constant = wmd->mask_constant;
BLI_strncpy(twmd->mask_defgrp_name, wmd->mask_defgrp_name, sizeof(twmd->mask_defgrp_name));
twmd->mask_texture = wmd->mask_texture;
twmd->mask_tex_use_channel = wmd->mask_tex_use_channel;
twmd->mask_tex_mapping = wmd->mask_tex_mapping;
twmd->mask_tex_map_obj = wmd->mask_tex_map_obj;
BLI_strncpy(twmd->mask_tex_uvlayer_name, wmd->mask_tex_uvlayer_name, sizeof(twmd->mask_tex_uvlayer_name));
}
static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
{
WeightVGMixModifierData *wmd = (WeightVGMixModifierData*) md;
CustomDataMask dataMask = 0;
/* We need vertex groups! */
dataMask |= CD_MASK_MDEFORMVERT;
/* Ask for UV coordinates if we need them. */
if(wmd->mask_tex_mapping == MOD_DISP_MAP_UV)
dataMask |= CD_MASK_MTFACE;
return dataMask;
}
static int dependsOnTime(ModifierData *md)
{
WeightVGMixModifierData *wmd = (WeightVGMixModifierData*) md;
if(wmd->mask_texture)
return BKE_texture_dependsOnTime(wmd->mask_texture);
return 0;
}
static void foreachObjectLink(ModifierData *md, Object *ob,
void (*walk)(void *userData, Object *ob, Object **obpoin),
void *userData)
{
WeightVGMixModifierData *wmd = (WeightVGMixModifierData*) md;
walk(userData, ob, &wmd->mask_tex_map_obj);
}
static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
{
WeightVGMixModifierData *wmd = (WeightVGMixModifierData*) md;
walk(userData, ob, (ID **)&wmd->mask_texture);
foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
}
static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void *userData)
{
walk(userData, ob, md, "mask_texture");
}
static void updateDepgraph(ModifierData *md, DagForest *forest, struct Scene *UNUSED(scene),
Object *UNUSED(ob), DagNode *obNode)
{
WeightVGMixModifierData *wmd = (WeightVGMixModifierData*) md;
DagNode *curNode;
if(wmd->mask_tex_map_obj && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
curNode = dag_get_node(forest, wmd->mask_tex_map_obj);
dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA|DAG_RL_OB_DATA,
"WeightVGMix Modifier");
}
if(wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL)
dag_add_relation(forest, obNode, obNode, DAG_RL_DATA_DATA|DAG_RL_OB_DATA,
"WeightVGMix Modifier");
}
static int isDisabled(ModifierData *md, int UNUSED(useRenderParams))
{
WeightVGMixModifierData *wmd = (WeightVGMixModifierData*) md;
/* If no vertex group, bypass. */
return (wmd->defgrp_name_a[0] == '\0');
}
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData,
int UNUSED(useRenderParams), int UNUSED(isFinalCalc))
{
WeightVGMixModifierData *wmd = (WeightVGMixModifierData*) md;
DerivedMesh *dm = derivedData, *ret = NULL;
#if 0
Mesh *ob_m = NULL;
#endif
MDeformVert *dvert = NULL;
int numVerts;
int defgrp_idx, defgrp_idx2 = -1;
float *org_w;
float *new_w;
int *tidx, *indices = NULL;
int numIdx = 0;
int i, j;
char rel_ret = 0; /* Boolean, whether we have to release ret dm or not, when not using it! */
/* Get number of verts. */
numVerts = dm->getNumVerts(dm);
/* Check if we can just return the original mesh.
* Must have verts and therefore verts assigned to vgroups to do anything useful!
*/
if ((numVerts == 0) || (ob->defbase.first == NULL))
return dm;
/* Get vgroup idx from its name. */
defgrp_idx = defgroup_name_index(ob, wmd->defgrp_name_a);
if (defgrp_idx < 0)
return dm;
/* Get seconf vgroup idx from its name, if given. */
if (wmd->defgrp_name_b[0] != (char)0) {
defgrp_idx2 = defgroup_name_index(ob, wmd->defgrp_name_b);
if (defgrp_idx2 < 0)
return dm;
}
/* XXX All this to avoid copying dm when not needed… However, it nearly doubles compute
* time! See scene 5 of the WeighVG test file
*/
#if 0
/* Get actual dverts (ie vertex group data). */
dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
/* If no dverts, return unmodified data… */
if (dvert == NULL)
return dm;
/* Get org mesh, only to test whether affected cdata layer has already been copied
* somewhere up in the modifiers stack.
*/
ob_m = get_mesh(ob);
if (ob_m == NULL)
return dm;
/* Create a copy of our dmesh, only if our affected cdata layer is the same as org mesh. */
if (dvert == CustomData_get_layer(&ob_m->vdata, CD_MDEFORMVERT)) {
/* XXX Seems to create problems with weightpaint mode???
* I'm missing something here, I guess
*/
// DM_set_only_copy(dm, CD_MASK_MDEFORMVERT); /* Only copy defgroup layer. */
ret = CDDM_copy(dm);
dvert = ret->getVertDataArray(ret, CD_MDEFORMVERT);
if (dvert == NULL) {
ret->release(ret);
return dm;
}
rel_ret = 1;
}
else
ret = dm;
#else
ret = CDDM_copy(dm);
rel_ret = 1;
dvert = ret->getVertDataArray(ret, CD_MDEFORMVERT);
if (dvert == NULL) {
if (rel_ret)
ret->release(ret);
return dm;
}
#endif
/* Find out which vertices to work on. */
tidx = MEM_mallocN(sizeof(int) * numVerts, "WeightVGMix Modifier, tidx");
switch (wmd->mix_set) {
case MOD_WVG_SET_A:
/* All vertices in first vgroup. */
for (i = 0; i < numVerts; i++) {
for (j = 0; j < dvert[i].totweight; j++) {
if(dvert[i].dw[j].def_nr == defgrp_idx) {
tidx[numIdx++] = i;
break;
}
}
}
break;
case MOD_WVG_SET_B:
/* All vertices in second vgroup. */
for (i = 0; i < numVerts; i++) {
for (j = 0; j < dvert[i].totweight; j++) {
if(dvert[i].dw[j].def_nr == defgrp_idx2) {
tidx[numIdx++] = i;
break;
}
}
}
break;
case MOD_WVG_SET_OR:
/* All vertices in one vgroup or the other. */
for (i = 0; i < numVerts; i++) {
for (j = 0; j < dvert[i].totweight; j++) {
if(dvert[i].dw[j].def_nr == defgrp_idx || dvert[i].dw[j].def_nr == defgrp_idx2) {
tidx[numIdx++] = i;
break;
}
}
}
break;
case MOD_WVG_SET_AND:
/* All vertices in both vgroups. */
for (i = 0; i < numVerts; i++) {
int idx1 = FALSE;
int idx2 = FALSE;
for (j = 0; j < dvert[i].totweight; j++) {
if(dvert[i].dw[j].def_nr == defgrp_idx) {
if (idx2 == TRUE) {
tidx[numIdx++] = i;
break;
}
else {
idx1 = TRUE;
}
}
else if(dvert[i].dw[j].def_nr == defgrp_idx2) {
if (idx1 == TRUE) {
tidx[numIdx++] = i;
break;
}
else {
idx2 = TRUE;
}
}
}
}
break;
case MOD_WVG_SET_ALL:
default:
/* Use all vertices, no need to do anything here. */
break;
}
if (numIdx) {
indices = MEM_mallocN(sizeof(int) * numIdx, "WeightVGMix Modifier, indices");
memcpy(indices, tidx, sizeof(int) * numIdx);
}
else
numIdx = numVerts;
MEM_freeN(tidx);
org_w = MEM_mallocN(sizeof(float) * numIdx, "WeightVGMix Modifier, org_w");
new_w = MEM_mallocN(sizeof(float) * numIdx, "WeightVGMix Modifier, new_w");
/* Mix weights. */
for (i = 0; i < numIdx; i++) {
float weight2 = 0.0;
int w1 = FALSE;
int w2 = FALSE;
int idx = indices ? indices[i] : i;
for (j = 0; j < dvert[idx].totweight; j++) {
if(dvert[idx].dw[j].def_nr == defgrp_idx) {
org_w[i] = dvert[idx].dw[j].weight;
w1 = TRUE;
if (w2 == TRUE)
break;
}
else if(dvert[idx].dw[j].def_nr == defgrp_idx2) {
weight2 = dvert[idx].dw[j].weight;
w2 = TRUE;
if (w1 == TRUE)
break;
}
}
if (w1 == FALSE)
org_w[i] = wmd->default_weight_a;
if (w2 == FALSE)
weight2 = wmd->default_weight_b;
new_w[i] = mix_weight(org_w[i], weight2, wmd->mix_mode);
}
/* Do masking. */
weightvg_do_mask(numIdx, indices, org_w, new_w, ob, ret, wmd->mask_constant,
wmd->mask_defgrp_name, wmd->mask_texture, wmd->mask_tex_use_channel,
wmd->mask_tex_mapping, wmd->mask_tex_map_obj, wmd->mask_tex_uvlayer_name);
/* Update (add to) vgroup.
* XXX Depending on the MOD_WVG_SET_xxx option chosen, we might have to add vertices to vgroup.
*/
weightvg_update_vg(dvert, defgrp_idx, numIdx, indices, org_w, TRUE, -FLT_MAX, 0, 0.0f);
/* Freeing stuff. */
MEM_freeN(org_w);
MEM_freeN(new_w);
if (indices)
MEM_freeN(indices);
/* Return the vgroup-modified mesh. */
return ret;
}
static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
struct EditMesh *UNUSED(editData),
DerivedMesh *derivedData)
{
return applyModifier(md, ob, derivedData, 0, 1);
}
ModifierTypeInfo modifierType_WeightVGMix = {
/* name */ "WeightVGMix",
/* structName */ "WeightVGMixModifierData",
/* structSize */ sizeof(WeightVGMixModifierData),
/* type */ eModifierTypeType_Nonconstructive,
/* flags */ eModifierTypeFlag_AcceptsMesh
/* |eModifierTypeFlag_SupportsMapping*/
|eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ applyModifier,
/* applyModifierEM */ applyModifierEM,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
/* foreachIDLink */ foreachIDLink,
/* foreachTexLink */ foreachTexLink,
};

@ -0,0 +1,550 @@
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2011 by Bastien Montagne.
* All rights reserved.
*
* Contributor(s): None yet.
*
* ***** END GPL LICENSE BLOCK *****
*
*/
/*
* XXX I'd like to make modified weights visible in WeightPaint mode,
* but couldn't figure a way to do this
* Maybe this will need changes in mesh_calc_modifiers (DerivedMesh.c)?
* Or the WeightPaint mode code itself?
*/
#include "BLI_editVert.h"
#include "BLI_math.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_deform.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_shrinkwrap.h" /* For SpaceTransform stuff. */
#include "BKE_texture.h" /* Texture masking. */
#include "depsgraph_private.h"
#include "MEM_guardedalloc.h"
#include "MOD_util.h"
#include "MOD_weightvg_util.h"
/**************************************
* Util functions. *
**************************************/
/* Util macro. */
#define OUT_OF_MEMORY() ((void)printf("WeightVGProximity: Out of memory.\n"))
/**
* Returns the squared distance between two given points.
*/
static float squared_dist(const float *a, const float *b)
{
float tmp[3];
VECSUB(tmp, a, b);
return INPR(tmp, tmp);
}
/**
* Find nearest vertex and/or edge and/or face, for each vertex (adapted from shrinkwrap.c).
*/
static void get_vert2geom_distance(int numVerts, float (*v_cos)[3],
float *dist_v, float *dist_e, float *dist_f,
DerivedMesh *target, const SpaceTransform *loc2trgt)
{
int i;
BVHTreeFromMesh treeData_v = NULL_BVHTreeFromMesh;
BVHTreeFromMesh treeData_e = NULL_BVHTreeFromMesh;
BVHTreeFromMesh treeData_f = NULL_BVHTreeFromMesh;
BVHTreeNearest nearest_v = NULL_BVHTreeNearest;
BVHTreeNearest nearest_e = NULL_BVHTreeNearest;
BVHTreeNearest nearest_f = NULL_BVHTreeNearest;
if (dist_v) {
/* Create a bvh-tree of the given target's verts. */
bvhtree_from_mesh_verts(&treeData_v, target, 0.0, 2, 6);
if(treeData_v.tree == NULL) {
OUT_OF_MEMORY();
return;
}
}
if (dist_e) {
/* Create a bvh-tree of the given target's edges. */
bvhtree_from_mesh_edges(&treeData_e, target, 0.0, 2, 6);
if(treeData_e.tree == NULL) {
OUT_OF_MEMORY();
return;
}
}
if (dist_f) {
/* Create a bvh-tree of the given target's faces. */
bvhtree_from_mesh_faces(&treeData_f, target, 0.0, 2, 6);
if(treeData_f.tree == NULL) {
OUT_OF_MEMORY();
return;
}
}
/* Setup nearest. */
nearest_v.index = nearest_e.index = nearest_f.index = -1;
/*nearest_v.dist = nearest_e.dist = nearest_f.dist = FLT_MAX;*/
/* Find the nearest vert/edge/face. */
#ifndef __APPLE__
#pragma omp parallel for default(none) private(i) firstprivate(nearest_v,nearest_e,nearest_f) \
shared(treeData_v,treeData_e,treeData_f,numVerts,v_cos,dist_v,dist_e, \
dist_f,loc2trgt) \
schedule(static)
#endif
for (i = 0; i < numVerts; ++i) {
float tmp_co[3];
/* Convert the vertex to tree coordinates. */
VECCOPY(tmp_co, v_cos[i]);
space_transform_apply(loc2trgt, tmp_co);
/* Use local proximity heuristics (to reduce the nearest search).
*
* If we already had an hit before, we assume this vertex is going to have a close hit to
* that other vertex, so we can initiate the "nearest.dist" with the expected value to that
* last hit.
* This will lead in prunning of the search tree.
*/
if (dist_v) {
nearest_v.dist = nearest_v.index != -1 ? squared_dist(tmp_co, nearest_v.co) : FLT_MAX;
/* Compute and store result. If invalid (-1 idx), keep FLT_MAX dist. */
BLI_bvhtree_find_nearest(treeData_v.tree, tmp_co, &nearest_v, treeData_v.nearest_callback, &treeData_v);
dist_v[i] = sqrtf(nearest_v.dist);
}
if (dist_e) {
nearest_e.dist = nearest_e.index != -1 ? squared_dist(tmp_co, nearest_e.co) : FLT_MAX;
/* Compute and store result. If invalid (-1 idx), keep FLT_MAX dist. */
BLI_bvhtree_find_nearest(treeData_e.tree, tmp_co, &nearest_e, treeData_e.nearest_callback, &treeData_e);
dist_e[i] = sqrtf(nearest_e.dist);
}
if (dist_f) {
nearest_f.dist = nearest_f.index != -1 ? squared_dist(tmp_co, nearest_f.co) : FLT_MAX;
/* Compute and store result. If invalid (-1 idx), keep FLT_MAX dist. */
BLI_bvhtree_find_nearest(treeData_f.tree, tmp_co, &nearest_f, treeData_f.nearest_callback, &treeData_f);
dist_f[i] = sqrtf(nearest_f.dist);
}
}
if (dist_v)
free_bvhtree_from_mesh(&treeData_v);
if (dist_e)
free_bvhtree_from_mesh(&treeData_e);
if (dist_f)
free_bvhtree_from_mesh(&treeData_f);
}
/**
* Returns the real distance between a vertex and another reference object.
* Note that it works in final world space (i.e. with constraints etc. applied).
*/
static void get_vert2ob_distance(int numVerts, float (*v_cos)[3], float *dist,
Object* ob, Object* obr)
{
/* Vertex and ref object coordinates. */
float v_wco[3];
unsigned int i= numVerts;
while(i-- > 0) {
/* Get world-coordinates of the vertex (constraints and anim included). */
mul_v3_m4v3(v_wco, ob->obmat, v_cos[i]);
/* Return distance between both coordinates. */
dist[i] = len_v3v3(v_wco, obr->obmat[3]);
}
}
/**
* Returns the real distance between an object and another reference object.
* Note that it works in final world space (i.e. with constraints etc. applied).
*/
static float get_ob2ob_distance(const Object* ob, const Object* obr)
{
return len_v3v3(ob->obmat[3], obr->obmat[3]);
}
/**
* Maps distances to weights, with an optionnal smoothing mapping.
*/
void do_map(float *weights, const int nidx, const float min_d, const float max_d, short mode)
{
const float range_inv= 1.0f / (max_d - min_d); /* invert since multiplication is faster */
unsigned int i= nidx;
while (i-- > 0) {
if (weights[i] >= max_d) weights[i]= 1.0f; /* most likely case first */
else if(weights[i] <= min_d) weights[i]= 0.0f;
else weights[i]= (weights[i] - min_d) * range_inv;
}
if(!ELEM(mode, MOD_WVG_MAPPING_NONE, MOD_WVG_MAPPING_CURVE)) {
weightvg_do_map(nidx, weights, mode, NULL);
}
}
/**************************************
* Modifiers functions. *
**************************************/
static void initData(ModifierData *md)
{
WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData*) md;
wmd->proximity_mode = MOD_WVG_PROXIMITY_OBJECT;
wmd->proximity_flags = MOD_WVG_PROXIMITY_GEOM_VERTS;
wmd->mapping_mode = MOD_WVG_MAPPING_NONE;
wmd->mask_constant = 1.0f;
wmd->mask_tex_use_channel = MOD_WVG_MASK_TEX_USE_INT; /* Use intensity by default. */
wmd->mask_tex_mapping = MOD_DISP_MAP_LOCAL;
wmd->max_dist = 1.0f; /* vert arbitrary distance, but don't use 0 */
}
static void copyData(ModifierData *md, ModifierData *target)
{
WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData*) md;
WeightVGProximityModifierData *twmd = (WeightVGProximityModifierData*) target;
BLI_strncpy(twmd->defgrp_name, wmd->defgrp_name, sizeof(twmd->defgrp_name));
twmd->proximity_mode = wmd->proximity_mode;
twmd->proximity_flags = wmd->proximity_flags;
twmd->proximity_ob_target = wmd->proximity_ob_target;
twmd->mapping_mode = wmd->mapping_mode;
twmd->mask_constant = wmd->mask_constant;
BLI_strncpy(twmd->mask_defgrp_name, wmd->mask_defgrp_name, sizeof(twmd->mask_defgrp_name));
twmd->mask_texture = wmd->mask_texture;
twmd->mask_tex_use_channel = wmd->mask_tex_use_channel;
twmd->mask_tex_mapping = wmd->mask_tex_mapping;
twmd->mask_tex_map_obj = wmd->mask_tex_map_obj;
BLI_strncpy(twmd->mask_tex_uvlayer_name, wmd->mask_tex_uvlayer_name, sizeof(twmd->mask_tex_uvlayer_name));
twmd->min_dist = wmd->min_dist;
twmd->max_dist = wmd->max_dist;
}
static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
{
WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData*) md;
CustomDataMask dataMask = 0;
/* We need vertex groups! */
dataMask |= CD_MASK_MDEFORMVERT;
/* Ask for UV coordinates if we need them. */
if(wmd->mask_tex_mapping == MOD_DISP_MAP_UV)
dataMask |= CD_MASK_MTFACE;
return dataMask;
}
static int dependsOnTime(ModifierData *md)
{
WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData*) md;
if(wmd->mask_texture)
return BKE_texture_dependsOnTime(wmd->mask_texture);
return 0;
}
static void foreachObjectLink(ModifierData *md, Object *ob,
void (*walk)(void *userData, Object *ob, Object **obpoin),
void *userData)
{
WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData*) md;
walk(userData, ob, &wmd->proximity_ob_target);
walk(userData, ob, &wmd->mask_tex_map_obj);
}
static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
{
WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData*) md;
walk(userData, ob, (ID **)&wmd->mask_texture);
foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
}
static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void *userData)
{
walk(userData, ob, md, "mask_texture");
}
static void updateDepgraph(ModifierData *md, DagForest *forest, struct Scene *UNUSED(scene),
Object *UNUSED(ob), DagNode *obNode)
{
WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData*) md;
DagNode *curNode;
if (wmd->proximity_ob_target) {
curNode = dag_get_node(forest, wmd->proximity_ob_target);
dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA|DAG_RL_OB_DATA,
"WeightVGProximity Modifier");
}
if(wmd->mask_tex_map_obj && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
curNode = dag_get_node(forest, wmd->mask_tex_map_obj);
dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA|DAG_RL_OB_DATA,
"WeightVGProximity Modifier");
}
if(wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL)
dag_add_relation(forest, obNode, obNode, DAG_RL_DATA_DATA|DAG_RL_OB_DATA,
"WeightVGProximity Modifier");
}
static int isDisabled(ModifierData *md, int UNUSED(useRenderParams))
{
WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData*) md;
/* If no vertex group, bypass. */
if (wmd->defgrp_name[0] == '\0') return 1;
/* If no target object, bypass. */
return (wmd->proximity_ob_target == NULL);
}
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData,
int UNUSED(useRenderParams), int UNUSED(isFinalCalc))
{
WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData*) md;
DerivedMesh *dm = derivedData, *ret = NULL;
#if 0
Mesh *ob_m = NULL;
#endif
MDeformVert *dvert = NULL;
int numVerts;
float (*v_cos)[3] = NULL; /* The vertices coordinates. */
Object *obr = NULL; /* Our target object. */
int defgrp_idx;
float *tw = NULL;
float *org_w = NULL;
float *new_w =NULL;
int *tidx, *indices = NULL;
int numIdx = 0;
int i, j;
char rel_ret = 0; /* Boolean, whether we have to release ret dm or not, when not using it! */
/* Get number of verts. */
numVerts = dm->getNumVerts(dm);
/* Check if we can just return the original mesh.
* Must have verts and therefore verts assigned to vgroups to do anything useful!
*/
if ((numVerts == 0) || (ob->defbase.first == NULL))
return dm;
/* Get our target object. */
obr = wmd->proximity_ob_target;
if (obr == NULL)
return dm;
/* Get vgroup idx from its name. */
defgrp_idx = defgroup_name_index(ob, wmd->defgrp_name);
if (defgrp_idx < 0)
return dm;
/* XXX All this to avoid copying dm when not needed… However, it nearly doubles compute
* time! See scene 5 of the WeighVG test file
*/
#if 0
/* Get actual dverts (ie vertex group data). */
dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
/* If no dverts, return unmodified data… */
if (dvert == NULL)
return dm;
/* Get org mesh, only to test whether affected cdata layer has already been copied
* somewhere up in the modifiers stack.
*/
ob_m = get_mesh(ob);
if (ob_m == NULL)
return dm;
/* Create a copy of our dmesh, only if our affected cdata layer is the same as org mesh. */
if (dvert == CustomData_get_layer(&ob_m->vdata, CD_MDEFORMVERT)) {
/* XXX Seems to create problems with weightpaint mode???
* I'm missing something here, I guess
*/
// DM_set_only_copy(dm, CD_MASK_MDEFORMVERT); /* Only copy defgroup layer. */
ret = CDDM_copy(dm);
dvert = ret->getVertDataArray(ret, CD_MDEFORMVERT);
if (dvert == NULL) {
ret->release(ret);
return dm;
}
rel_ret = 1;
}
else
ret = dm;
#else
ret = CDDM_copy(dm);
rel_ret = 1;
dvert = ret->getVertDataArray(ret, CD_MDEFORMVERT);
if (dvert == NULL) {
if (rel_ret)
ret->release(ret);
return dm;
}
#endif
/* Find out which vertices to work on (all vertices in vgroup), and get their relevant weight.
*/
tidx = MEM_mallocN(sizeof(int) * numVerts, "WeightVGProximity Modifier, tidx");
tw = MEM_mallocN(sizeof(float) * numVerts, "WeightVGProximity Modifier, tw");
for (i = 0; i < numVerts; i++) {
for (j = 0; j < dvert[i].totweight; j++) {
if(dvert[i].dw[j].def_nr == defgrp_idx) {
tidx[numIdx] = i;
tw[numIdx++] = dvert[i].dw[j].weight;
break;
}
}
}
indices = MEM_mallocN(sizeof(int) * numIdx, "WeightVGProximity Modifier, indices");
memcpy(indices, tidx, sizeof(int) * numIdx);
org_w = MEM_mallocN(sizeof(float) * numIdx, "WeightVGProximity Modifier, org_w");
new_w = MEM_mallocN(sizeof(float) * numIdx, "WeightVGProximity Modifier, new_w");
memcpy(org_w, tw, sizeof(float) * numIdx);
MEM_freeN(tidx);
MEM_freeN(tw);
/* Get our vertex coordinates. */
v_cos = MEM_mallocN(sizeof(float[3]) * numIdx, "WeightVGProximity Modifier, v_cos");
for (i = 0; i < numIdx; i++)
ret->getVertCo(ret, indices[i], v_cos[i]);
/* Compute wanted distances. */
if (wmd->proximity_mode == MOD_WVG_PROXIMITY_OBJECT) {
float dist = get_ob2ob_distance(ob, obr);
for(i = 0; i < numIdx; i++)
new_w[i] = dist;
}
else if (wmd->proximity_mode == MOD_WVG_PROXIMITY_GEOMETRY) {
const short use_trgt_verts = (wmd->proximity_flags & MOD_WVG_PROXIMITY_GEOM_VERTS);
const short use_trgt_edges = (wmd->proximity_flags & MOD_WVG_PROXIMITY_GEOM_EDGES);
const short use_trgt_faces = (wmd->proximity_flags & MOD_WVG_PROXIMITY_GEOM_FACES);
if (use_trgt_verts || use_trgt_edges || use_trgt_faces) {
DerivedMesh *target_dm = obr->derivedFinal;
if (!target_dm) {
if (ELEM3(obr->type, OB_CURVE, OB_SURF, OB_FONT))
target_dm = CDDM_from_curve(obr);
else if (obr->type == OB_MESH) {
Mesh *me = (Mesh*)obr->data;
if (me->edit_mesh)
target_dm = CDDM_from_editmesh((EditMesh*)me->edit_mesh, me);
else
target_dm = CDDM_from_mesh(me, obr);
}
}
/* We must check that we do have a valid target_dm! */
if (target_dm) {
SpaceTransform loc2trgt;
float *dists_v = use_trgt_verts ? MEM_mallocN(sizeof(float) * numIdx, "WeightVGProximity Modifier, dists_v") : NULL;
float *dists_e = use_trgt_edges ? MEM_mallocN(sizeof(float) * numIdx, "WeightVGProximity Modifier, dists_e") : NULL;
float *dists_f = use_trgt_faces ? MEM_mallocN(sizeof(float) * numIdx, "WeightVGProximity Modifier, dists_f") : NULL;
space_transform_setup(&loc2trgt, ob, obr);
get_vert2geom_distance(numIdx, v_cos, dists_v, dists_e, dists_f,
target_dm, &loc2trgt);
for(i = 0; i < numIdx; i++) {
new_w[i] = dists_v ? dists_v[i] : FLT_MAX;
new_w[i] = dists_e ? minf(dists_e[i], new_w[i]) : new_w[i];
new_w[i] = dists_f ? minf(dists_f[i], new_w[i]) : new_w[i];
}
}
/* Else, fall back to default obj2vert behavior. */
else {
get_vert2ob_distance(numIdx, v_cos, new_w, ob, obr);
}
}
else {
get_vert2ob_distance(numIdx, v_cos, new_w, ob, obr);
}
}
/* Do masking. */
weightvg_do_mask(numIdx, indices, org_w, new_w, ob, ret, wmd->mask_constant,
wmd->mask_defgrp_name, wmd->mask_texture, wmd->mask_tex_use_channel,
wmd->mask_tex_mapping, wmd->mask_tex_map_obj, wmd->mask_tex_uvlayer_name);
/* Map distances to weights. */
do_map(org_w, numIdx, wmd->min_dist, wmd->max_dist, wmd->mapping_mode);
/* Update vgroup. Note we never add nor remove vertices from vgroup here. */
weightvg_update_vg(dvert, defgrp_idx, numIdx, indices, org_w, 0, 0.0f, 0, 0.0f);
/* Freeing stuff. */
MEM_freeN(org_w);
MEM_freeN(new_w);
MEM_freeN(indices);
MEM_freeN(v_cos);
/* Return the vgroup-modified mesh. */
return ret;
}
static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
struct EditMesh *UNUSED(editData),
DerivedMesh *derivedData)
{
return applyModifier(md, ob, derivedData, 0, 1);
}
ModifierTypeInfo modifierType_WeightVGProximity = {
/* name */ "WeightVGProximity",
/* structName */ "WeightVGProximityModifierData",
/* structSize */ sizeof(WeightVGProximityModifierData),
/* type */ eModifierTypeType_Nonconstructive,
/* flags */ eModifierTypeFlag_AcceptsMesh
/* |eModifierTypeFlag_SupportsMapping*/
|eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ applyModifier,
/* applyModifierEM */ applyModifierEM,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
/* foreachIDLink */ foreachIDLink,
/* foreachTexLink */ foreachTexLink,
};