Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/physics/particle_edit.c')
-rw-r--r--source/blender/editors/physics/particle_edit.c298
1 files changed, 198 insertions, 100 deletions
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index 101ec225cb2..c2ead76ff3e 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -88,6 +88,7 @@
static void PE_create_particle_edit(Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys);
static void PTCacheUndo_clear(PTCacheEdit *edit);
+static void recalc_emitter_field(Object *ob, ParticleSystem *psys);
#define KEY_K PTCacheEditKey *key; int k
#define POINT_P PTCacheEditPoint *point; int p
@@ -193,7 +194,10 @@ ParticleEditSettings *PE_settings(Scene *scene)
return &scene->toolsettings->particle;
}
-/* always gets atleast the first particlesystem even if PSYS_CURRENT flag is not set */
+/* always gets atleast the first particlesystem even if PSYS_CURRENT flag is not set
+ *
+ * note: this function runs on poll, therefor it can runs many times a second
+ * keep it fast! */
static PTCacheEdit *pe_get_current(Scene *scene, Object *ob, int create)
{
ParticleEditSettings *pset= PE_settings(scene);
@@ -370,7 +374,8 @@ static void PE_set_view3d_data(bContext *C, PEData *data)
PE_set_data(C, data);
view3d_set_viewcontext(C, &data->vc);
- view3d_get_transformation(data->vc.ar, data->vc.rv3d, data->ob, &data->mats);
+ /* note, the object argument means the modelview matrix does not account for the objects matrix, use viewmat rather then (obmat * viewmat) */
+ view3d_get_transformation(data->vc.ar, data->vc.rv3d, NULL, &data->mats);
if((data->vc.v3d->drawtype>OB_WIRE) && (data->vc.v3d->flag & V3D_ZBUF_SELECT))
view3d_validate_backbuf(&data->vc);
@@ -403,7 +408,8 @@ static int key_test_depth(PEData *data, float co[3])
x+= (short)data->vc.ar->winrct.xmin;
y+= (short)data->vc.ar->winrct.ymin;
- view3d_validate_backbuf(&data->vc);
+ /* PE_set_view3d_data calls this. no need to call here */
+ /* view3d_validate_backbuf(&data->vc); */
glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
if((float)uz - 0.0001 > depth)
@@ -588,25 +594,34 @@ static void foreach_mouse_hit_key(PEData *data, ForKeyMatFunc func, int selected
unit_m4(mat);
LOOP_VISIBLE_POINTS {
- if(edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) {
- psys_mat_hair_to_global(data->ob, psmd->dm, psys->part->from, psys->particles + p, mat);
- invert_m4_m4(imat,mat);
- }
-
if(pset->selectmode==SCE_SELECT_END) {
/* only do end keys */
key= point->keys + point->totkey-1;
- if(selected==0 || key->flag & PEK_SELECT)
- if(key_inside_circle(data, data->rad, KEY_WCO, &data->dist))
+ if(selected==0 || key->flag & PEK_SELECT) {
+ if(key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) {
+ if(edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) {
+ psys_mat_hair_to_global(data->ob, psmd->dm, psys->part->from, psys->particles + p, mat);
+ invert_m4_m4(imat,mat);
+ }
+
func(data, mat, imat, p, point->totkey-1, key);
+ }
+ }
}
else {
/* do all keys */
LOOP_VISIBLE_KEYS {
- if(selected==0 || key->flag & PEK_SELECT)
- if(key_inside_circle(data, data->rad, KEY_WCO, &data->dist))
+ if(selected==0 || key->flag & PEK_SELECT) {
+ if(key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) {
+ if(edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) {
+ psys_mat_hair_to_global(data->ob, psmd->dm, psys->part->from, psys->particles + p, mat);
+ invert_m4_m4(imat,mat);
+ }
+
func(data, mat, imat, p, k, key);
+ }
+ }
}
}
}
@@ -2008,7 +2023,6 @@ static void rekey_particle_to_time(Scene *scene, Object *ob, int pa_index, float
static int remove_tagged_particles(Scene *scene, Object *ob, ParticleSystem *psys, int mirror)
{
PTCacheEdit *edit = psys->edit;
- ParticleEditSettings *pset= PE_settings(scene);
ParticleData *pa, *npa=0, *new_pars=0;
POINT_P;
PTCacheEditPoint *npoint=0, *new_points=0;
@@ -2079,7 +2093,6 @@ static int remove_tagged_particles(Scene *scene, Object *ob, ParticleSystem *psy
static void remove_tagged_keys(Scene *scene, Object *ob, ParticleSystem *psys)
{
PTCacheEdit *edit= psys->edit;
- ParticleEditSettings *pset= PE_settings(scene);
ParticleData *pa;
HairKey *hkey, *nhkey, *new_hkeys=0;
POINT_P; KEY_K;
@@ -2270,7 +2283,6 @@ static int remove_doubles_exec(bContext *C, wmOperator *op)
{
Scene *scene= CTX_data_scene(C);
Object *ob= CTX_data_active_object(C);
- ParticleEditSettings *pset=PE_settings(scene);
PTCacheEdit *edit= PE_get_current(scene, ob);
ParticleSystem *psys = edit->psys;
ParticleSystemModifierData *psmd;
@@ -2356,6 +2368,52 @@ void PARTICLE_OT_remove_doubles(wmOperatorType *ot)
RNA_def_float(ot->srna, "threshold", 0.0002f, 0.0f, FLT_MAX, "Threshold", "Threshold distance withing which particles are removed", 0.00001f, 0.1f);
}
+
+static int weight_set_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene= CTX_data_scene(C);
+ ParticleEditSettings *pset= PE_settings(scene);
+ Object *ob= CTX_data_active_object(C);
+ PTCacheEdit *edit= PE_get_current(scene, ob);
+ ParticleSystem *psys = edit->psys;
+ POINT_P;
+ KEY_K;
+ HairKey *hkey;
+ float weight;
+ ParticleBrushData *brush= &pset->brush[pset->brushtype];
+ edit= psys->edit;
+
+ weight= (float)(brush->strength / 100.0f);
+
+ LOOP_SELECTED_POINTS {
+ ParticleData *pa= psys->particles + p;
+
+ LOOP_SELECTED_KEYS {
+ hkey= pa->hair + k;
+ hkey->weight= weight;
+ }
+ }
+
+ DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_DATA, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void PARTICLE_OT_weight_set(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Weight Set";
+ ot->idname= "PARTICLE_OT_weight_set";
+
+ /* api callbacks */
+ ot->exec= weight_set_exec;
+ ot->poll= PE_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
/************************ cursor drawing *******************************/
static void brush_drawcursor(bContext *C, int x, int y, void *customdata)
@@ -2530,7 +2588,7 @@ void PARTICLE_OT_delete(wmOperatorType *ot)
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
/* properties */
- RNA_def_enum(ot->srna, "type", delete_type_items, DEL_PARTICLE, "Type", "Delete a full particle or only keys.");
+ ot->prop= RNA_def_enum(ot->srna, "type", delete_type_items, DEL_PARTICLE, "Type", "Delete a full particle or only keys.");
}
/*************************** mirror operator **************************/
@@ -2689,79 +2747,6 @@ void PARTICLE_OT_mirror(wmOperatorType *ot)
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}
-/*********************** set brush operator **********************/
-
-static EnumPropertyItem brush_type_items[]= {
- {PE_BRUSH_NONE, "NONE", 0, "None", ""},
- {PE_BRUSH_COMB, "COMB", 0, "Comb", ""},
- {PE_BRUSH_SMOOTH, "SMOOTH", 0, "Smooth", ""},
- {PE_BRUSH_ADD, "ADD", 0, "Add", ""},
- {PE_BRUSH_LENGTH, "LENGTH", 0, "Length", ""},
- {PE_BRUSH_PUFF, "PUFF", 0, "Puff", ""},
- {PE_BRUSH_CUT, "CUT", 0, "Cut", ""},
- {0, NULL, 0, NULL, NULL}
-};
-
-static int set_brush_exec(bContext *C, wmOperator *op)
-{
- Scene *scene= CTX_data_scene(C);
- ParticleEditSettings *pset= PE_settings(scene);
-
- pset->brushtype= RNA_enum_get(op->ptr, "type");
-
- return OPERATOR_FINISHED;
-}
-
-void PARTICLE_OT_brush_set(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Set Brush";
- ot->idname= "PARTICLE_OT_brush_set";
-
- /* api callbacks */
- ot->exec= set_brush_exec;
- ot->invoke= WM_menu_invoke;
- ot->poll= PE_poll;
-
- /* properties */
- RNA_def_enum(ot->srna, "type", brush_type_items, PE_BRUSH_NONE, "Type", "Brush type to select for editing.");
-}
-
-
-/*********************** set mode operator **********************/
-
-static EnumPropertyItem edit_type_items[]= {
- {PE_TYPE_PARTICLES, "PARTICLES", 0, "Particles", ""},
- {PE_TYPE_SOFTBODY, "SOFTBODY", 0, "Soft body", ""},
- {PE_TYPE_CLOTH, "CLOTH", 0, "Cloth", ""},
- {0, NULL, 0, NULL, NULL}
-};
-
-static int set_edit_mode_exec(bContext *C, wmOperator *op)
-{
- Scene *scene= CTX_data_scene(C);
- ParticleEditSettings *pset= PE_settings(scene);
-
- pset->edittype= RNA_enum_get(op->ptr, "type");
-
- return OPERATOR_FINISHED;
-}
-
-void PARTICLE_OT_edit_type_set(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Set Edit Type";
- ot->idname= "PARTICLE_OT_edit_type_set";
-
- /* api callbacks */
- ot->exec= set_edit_mode_exec;
- ot->invoke= WM_menu_invoke;
- ot->poll= PE_poll;
-
- /* properties */
- RNA_def_enum(ot->srna, "type", edit_type_items, PE_TYPE_PARTICLES, "Type", "Edit type to select for editing.");
-}
-
/************************* brush edit callbacks ********************/
static void brush_comb(PEData *data, float mat[][4], float imat[][4], int point_index, int key_index, PTCacheEditKey *key)
@@ -2907,7 +2892,16 @@ static void brush_puff(PEData *data, int point_index)
PTCacheEditPoint *point = edit->points + point_index;
KEY_K;
float mat[4][4], imat[4][4];
- float lastco[3], rootco[3] = {0.0f, 0.0f, 0.0f}, co[3], nor[3], kco[3], dco[3], fac=0.0f, length=0.0f;
+
+ float lastco[3], rootco[3] = {0.0f, 0.0f, 0.0f}, co[3], nor[3], kco[3], dco[3], ofs[3] = {0.0f, 0.0f, 0.0f}, fac=0.0f, length=0.0f;
+ int puff_volume = 0;
+ int change= 0;
+
+ {
+ ParticleEditSettings *pset= PE_settings(data->scene);
+ ParticleBrushData *brush= &pset->brush[pset->brushtype];
+ puff_volume = brush->flag & PE_BRUSH_DATA_PUFF_VOLUME;
+ }
if(psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
psys_mat_hair_to_global(data->ob, data->dm, psys->part->from, psys->particles + point_index, mat);
@@ -2923,12 +2917,15 @@ static void brush_puff(PEData *data, int point_index)
/* find root coordinate and normal on emitter */
VECCOPY(co, key->co);
mul_m4_v3(mat, co);
+ mul_v3_m4v3(kco, data->ob->imat, co); /* use 'kco' as the object space version of worldspace 'co', ob->imat is set before calling */
- point_index= BLI_kdtree_find_nearest(edit->emitter_field, co, NULL, NULL);
+ point_index= BLI_kdtree_find_nearest(edit->emitter_field, kco, NULL, NULL);
if(point_index == -1) return;
VECCOPY(rootco, co);
copy_v3_v3(nor, &edit->emitter_cosnos[point_index*6+3]);
+ mul_mat3_m4_v3(data->ob->obmat, nor); /* normal into worldspace */
+
normalize_v3(nor);
length= 0.0f;
@@ -2938,24 +2935,101 @@ static void brush_puff(PEData *data, int point_index)
fac= -fac;
}
else {
- /* compute position as if hair was standing up straight */
+ /* compute position as if hair was standing up straight.
+ * */
VECCOPY(lastco, co);
VECCOPY(co, key->co);
mul_m4_v3(mat, co);
length += len_v3v3(lastco, co);
+ if((key->flag & PEK_SELECT) && !(key->flag & PEK_HIDE)) {
+ VECADDFAC(kco, rootco, nor, length);
- VECADDFAC(kco, rootco, nor, length);
+ /* blend between the current and straight position */
+ VECSUB(dco, kco, co);
+ VECADDFAC(co, co, dco, fac);
- /* blend between the current and straight position */
- VECSUB(dco, kco, co);
- VECADDFAC(co, co, dco, fac);
+ /* re-use dco to compare before and after translation and add to the offset */
+ VECCOPY(dco, key->co);
- VECCOPY(key->co, co);
- mul_m4_v3(imat, key->co);
+ mul_v3_m4v3(key->co, imat, co);
+
+ if(puff_volume) {
+ /* accumulate the total distance moved to apply to unselected
+ * keys that come after */
+ ofs[0] += key->co[0] - dco[0];
+ ofs[1] += key->co[1] - dco[1];
+ ofs[2] += key->co[2] - dco[2];
+ }
+ change = 1;
+ }
+ else {
+
+ if(puff_volume) {
+#if 0
+ /* this is simple but looks bad, adds annoying kinks */
+ add_v3_v3(key->co, ofs);
+#else
+ /* translate (not rotate) the rest of the hair if its not selected */
+ if(ofs[0] || ofs[1] || ofs[2]) {
+#if 0 /* kindof works but looks worse then whats below */
+
+ /* Move the unselected point on a vector based on the
+ * hair direction and the offset */
+ float c1[3], c2[3];
+ VECSUB(dco, lastco, co);
+ mul_mat3_m4_v3(imat, dco); /* into particle space */
+
+ /* move the point allong a vector perpendicular to the
+ * hairs direction, reduces odd kinks, */
+ cross_v3_v3v3(c1, ofs, dco);
+ cross_v3_v3v3(c2, c1, dco);
+ normalize_v3(c2);
+ mul_v3_fl(c2, len_v3(ofs));
+ add_v3_v3(key->co, c2);
+#else
+ /* Move the unselected point on a vector based on the
+ * the normal of the closest geometry */
+ float oco[3], onor[3];
+ VECCOPY(oco, key->co);
+ mul_m4_v3(mat, oco);
+ mul_v3_m4v3(kco, data->ob->imat, oco); /* use 'kco' as the object space version of worldspace 'co', ob->imat is set before calling */
+
+ point_index= BLI_kdtree_find_nearest(edit->emitter_field, kco, NULL, NULL);
+ if(point_index != -1) {
+ copy_v3_v3(onor, &edit->emitter_cosnos[point_index*6+3]);
+ mul_mat3_m4_v3(data->ob->obmat, onor); /* normal into worldspace */
+ mul_mat3_m4_v3(imat, onor); /* worldspace into particle space */
+ normalize_v3(onor);
+
+
+ mul_v3_fl(onor, len_v3(ofs));
+ add_v3_v3(key->co, onor);
+ }
+#endif
+ }
+#endif
+ }
+ }
}
}
- point->flag |= PEP_EDIT_RECALC;
+ if(change)
+ point->flag |= PEP_EDIT_RECALC;
+}
+
+
+static void brush_weight(PEData *data, float mat[][4], float imat[][4], int point_index, int key_index, PTCacheEditKey *key)
+{
+ /* roots have full weight allways */
+ if(key_index) {
+ PTCacheEdit *edit = data->edit;
+ ParticleSystem *psys = edit->psys;
+
+ ParticleData *pa= psys->particles + point_index;
+ pa->hair[key_index].weight = data->weightfac;
+
+ (data->edit->points + point_index)->flag |= PEP_EDIT_RECALC;
+ }
}
static void brush_smooth_get(PEData *data, float mat[][4], float imat[][4], int point_index, int key_index, PTCacheEditKey *key)
@@ -3405,6 +3479,23 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
break;
}
+ case PE_BRUSH_WEIGHT:
+ {
+ PEData data;
+ PE_set_view3d_data(C, &data);
+
+ if(edit->psys) {
+ data.dm= psmd->dm;
+ data.mval= mval;
+ data.rad= (float)brush->size;
+
+ data.weightfac = (float)(brush->strength / 100.0f); /* note that this will never be zero */
+
+ foreach_mouse_hit_key(&data, brush_weight, selected);
+ }
+
+ break;
+ }
}
if((pset->flag & PE_KEEP_LENGTHS)==0)
recalc_lengths(edit);
@@ -3970,8 +4061,15 @@ static int particle_edit_toggle_exec(bContext *C, wmOperator *op)
Object *ob= CTX_data_active_object(C);
if(!(ob->mode & OB_MODE_PARTICLE_EDIT)) {
+ PTCacheEdit *edit;
ob->mode |= OB_MODE_PARTICLE_EDIT;
- PE_create_current(scene, ob);
+ edit= PE_create_current(scene, ob);
+
+ /* mesh may have changed since last entering editmode.
+ * note, this may have run before if the edit data was just created, so could avoid this and speed up a little */
+ if(edit && edit->psys)
+ recalc_emitter_field(ob, edit->psys);
+
toggle_particle_cursor(C, 1);
WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_PARTICLE, NULL);
}