Disconnect/connect hair:
- Moves hair from face-space to global space and back. - Allows for editing of emitter mesh after hair combing. - Disconnect hair before doing topology changing changes in mesh edit mode, connect after changes. - Notes: * The closest location on emitter surface to the hair root is used to connect the hair. * Emitter deflection, sticky roots and add brush don't apply for disconnect hair in particle mode. - Todo for future: * Copy disconnected hair from object to another (when 2.5 has proper copy operators again). * Possible automatic disconnect/connect with topology changing operations in mesh edit mode. Other changes/fixes: - Proper subtypes for some particle mode notifiers. - Particle mode selections didn't draw correctly because of using lighting for the paths.
This commit is contained in:
@@ -151,6 +151,11 @@ class PARTICLE_PT_particles(ParticleButtonsPanel):
|
||||
row = split.row()
|
||||
row.enabled = particle_panel_enabled(psys)
|
||||
row.itemR(part, "hair_step")
|
||||
if psys.edited==True:
|
||||
if psys.global_hair:
|
||||
layout.itemO("particle.connect_hair")
|
||||
else:
|
||||
layout.itemO("particle.disconnect_hair")
|
||||
elif part.type=='REACTOR':
|
||||
split.enabled = particle_panel_enabled(psys)
|
||||
split.itemR(psys, "reactor_target_object")
|
||||
|
||||
@@ -192,6 +192,7 @@ typedef struct PTCacheUndo {
|
||||
struct ParticleData *particles;
|
||||
struct KDTree *emitter_field;
|
||||
float *emitter_cosnos;
|
||||
int psys_flag;
|
||||
|
||||
/* cache stuff */
|
||||
struct ListBase mem_cache;
|
||||
|
||||
@@ -418,7 +418,7 @@ void psys_free_path_cache(ParticleSystem *psys, PTCacheEdit *edit)
|
||||
edit->pathcache= NULL;
|
||||
edit->totcached= 0;
|
||||
}
|
||||
else {
|
||||
if(psys) {
|
||||
psys_free_path_cache_buffers(psys->pathcache, &psys->pathcachebufs);
|
||||
psys->pathcache= NULL;
|
||||
psys->totcached= 0;
|
||||
@@ -2676,7 +2676,7 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra
|
||||
baked = psys->pointcache->flag & PTCACHE_BAKED;
|
||||
|
||||
/* clear out old and create new empty path cache */
|
||||
psys_free_path_cache(psys, NULL);
|
||||
psys_free_path_cache(psys, psys->edit);
|
||||
cache= psys->pathcache= psys_alloc_path_cache_buffers(&psys->pathcachebufs, totpart, steps+1);
|
||||
|
||||
if(psys->soft && psys->softflag & OB_SB_ENABLE) {
|
||||
@@ -2891,7 +2891,7 @@ void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cf
|
||||
|
||||
if(!cache || edit->totpoint != edit->totcached) {
|
||||
/* clear out old and create new empty path cache */
|
||||
psys_free_path_cache(NULL, edit);
|
||||
psys_free_path_cache(edit->psys, edit);
|
||||
cache= edit->pathcache= psys_alloc_path_cache_buffers(&edit->pathcachebufs, totpart, steps+1);
|
||||
}
|
||||
|
||||
@@ -2946,7 +2946,7 @@ void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cf
|
||||
do_particle_interpolation(psys, i, pa, t, frs_sec, &pind, &result);
|
||||
|
||||
/* non-hair points are allready in global space */
|
||||
if(psys)
|
||||
if(psys && !(psys->flag & PSYS_GLOBAL_HAIR))
|
||||
Mat4MulVecfl(hairmat, result.co);
|
||||
|
||||
VECCOPY(ca->co, result.co);
|
||||
|
||||
@@ -158,7 +158,7 @@ void psys_reset(ParticleSystem *psys, int mode)
|
||||
psys->totchild= 0;
|
||||
|
||||
/* reset path cache */
|
||||
psys_free_path_cache(psys, NULL);
|
||||
psys_free_path_cache(psys, psys->edit);
|
||||
|
||||
/* reset point cache */
|
||||
psys->pointcache->flag &= ~PTCACHE_SIMULATION_VALID;
|
||||
|
||||
@@ -555,7 +555,7 @@ static void foreach_mouse_hit_key(PEData *data, ForKeyMatFunc func, int selected
|
||||
Mat4One(mat);
|
||||
|
||||
LOOP_VISIBLE_POINTS {
|
||||
if(edit->psys) {
|
||||
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);
|
||||
Mat4Invert(imat,mat);
|
||||
}
|
||||
@@ -812,7 +812,7 @@ static void pe_deflect_emitter(Scene *scene, Object *ob, PTCacheEdit *edit)
|
||||
float *vec, *nor, dvec[3], dot, dist_1st;
|
||||
float hairimat[4][4], hairmat[4][4];
|
||||
|
||||
if(edit==NULL || edit->psys==NULL || (pset->flag & PE_DEFLECT_EMITTER)==0)
|
||||
if(edit==NULL || edit->psys==NULL || (pset->flag & PE_DEFLECT_EMITTER)==0 || (edit->psys->flag & PSYS_GLOBAL_HAIR))
|
||||
return;
|
||||
|
||||
psys = edit->psys;
|
||||
@@ -876,6 +876,9 @@ void PE_apply_lengths(Scene *scene, PTCacheEdit *edit)
|
||||
if(edit==0 || (pset->flag & PE_KEEP_LENGTHS)==0)
|
||||
return;
|
||||
|
||||
if(edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR)
|
||||
return;
|
||||
|
||||
LOOP_EDITED_POINTS {
|
||||
LOOP_KEYS {
|
||||
if(k) {
|
||||
@@ -899,10 +902,10 @@ static void pe_iterate_lengths(Scene *scene, PTCacheEdit *edit)
|
||||
float dv1[3]= {0.0f, 0.0f, 0.0f};
|
||||
float dv2[3]= {0.0f, 0.0f, 0.0f};
|
||||
|
||||
if(edit==0)
|
||||
if(edit==0 || (pset->flag & PE_KEEP_LENGTHS)==0)
|
||||
return;
|
||||
|
||||
if((pset->flag & PE_KEEP_LENGTHS)==0)
|
||||
if(edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR)
|
||||
return;
|
||||
|
||||
LOOP_EDITED_POINTS {
|
||||
@@ -1057,11 +1060,13 @@ static void update_world_cos(Object *ob, PTCacheEdit *edit)
|
||||
return;
|
||||
|
||||
LOOP_POINTS {
|
||||
psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, psys->particles+p, hairmat);
|
||||
if(!(psys->flag & PSYS_GLOBAL_HAIR))
|
||||
psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, psys->particles+p, hairmat);
|
||||
|
||||
LOOP_KEYS {
|
||||
VECCOPY(key->world_co,key->co);
|
||||
Mat4MulVecfl(hairmat, key->world_co);
|
||||
if(!(psys->flag & PSYS_GLOBAL_HAIR))
|
||||
Mat4MulVecfl(hairmat, key->world_co);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1480,7 +1485,7 @@ int PE_lasso_select(bContext *C, short mcords[][2], short moves, short select)
|
||||
Mat4One(mat);
|
||||
|
||||
LOOP_VISIBLE_POINTS {
|
||||
if(edit->psys)
|
||||
if(edit->psys && !(psys->flag & PSYS_GLOBAL_HAIR))
|
||||
psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, psys->particles + p, mat);
|
||||
|
||||
if(pset->selectmode==SCE_SELECT_POINT) {
|
||||
@@ -1777,7 +1782,8 @@ static void rekey_particle(PEData *data, int pa_index)
|
||||
for(k=0, key=pa->hair; k<pa->totkey; k++, key++, ekey++) {
|
||||
ekey->co= key->co;
|
||||
ekey->time= &key->time;
|
||||
ekey->flag |= PEK_USE_WCO;
|
||||
if(!(psys->flag & PSYS_GLOBAL_HAIR))
|
||||
ekey->flag |= PEK_USE_WCO;
|
||||
}
|
||||
|
||||
pa->flag &= ~PARS_REKEY;
|
||||
@@ -2059,7 +2065,9 @@ static void subdivide_particle(PEData *data, int pa_index)
|
||||
|
||||
nekey->co= nkey->co;
|
||||
nekey->time= &nkey->time;
|
||||
nekey->flag |= (PEK_SELECT|PEK_USE_WCO);
|
||||
nekey->flag |= PEK_SELECT;
|
||||
if(!(psys->flag & PSYS_GLOBAL_HAIR))
|
||||
nekey->flag |= PEK_USE_WCO;
|
||||
|
||||
nekey++;
|
||||
nkey++;
|
||||
@@ -2129,6 +2137,9 @@ static int remove_doubles_exec(bContext *C, wmOperator *op)
|
||||
float mat[4][4], co[3], threshold= RNA_float_get(op->ptr, "threshold");
|
||||
int n, totn, removed, flag, totremoved;
|
||||
|
||||
if(psys->flag & PSYS_GLOBAL_HAIR)
|
||||
return OPERATOR_CANCELLED;
|
||||
|
||||
edit= psys->edit;
|
||||
psmd= psys_get_modifier(ob, psys);
|
||||
totremoved= 0;
|
||||
@@ -2400,6 +2411,9 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
|
||||
int *mirrorfaces;
|
||||
int rotation, totpart, newtotpart;
|
||||
|
||||
if(psys->flag & PSYS_GLOBAL_HAIR)
|
||||
return;
|
||||
|
||||
psmd= psys_get_modifier(ob, psys);
|
||||
|
||||
mirrorfaces= mesh_get_x_mirror_faces(ob, NULL);
|
||||
@@ -2750,7 +2764,7 @@ static void brush_puff(PEData *data, int point_index)
|
||||
float mat[4][4], imat[4][4];
|
||||
float lastco[3], rootco[3], co[3], nor[3], kco[3], dco[3], fac, length;
|
||||
|
||||
if(psys) {
|
||||
if(psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
|
||||
psys_mat_hair_to_global(data->ob, data->dm, psys->part->from, psys->particles + point_index, mat);
|
||||
Mat4Invert(imat,mat);
|
||||
}
|
||||
@@ -2849,6 +2863,9 @@ static void brush_add(PEData *data, short number)
|
||||
DerivedMesh *dm=0;
|
||||
Mat4Invert(imat,ob->obmat);
|
||||
|
||||
if(psys->flag & PSYS_GLOBAL_HAIR)
|
||||
return;
|
||||
|
||||
BLI_srandom(psys->seed+data->mval[0]+data->mval[1]);
|
||||
|
||||
/* painting onto the deformed mesh, could be an option? */
|
||||
@@ -3070,6 +3087,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
|
||||
float vec[3], mousef[2];
|
||||
short mval[2], mvalo[2];
|
||||
int flip, mouse[2], dx, dy, removed= 0, selected= 0;
|
||||
int lock_root = pset->flag & PE_LOCK_FIRST;
|
||||
|
||||
if(!PE_start_edit(edit))
|
||||
return;
|
||||
@@ -3093,6 +3111,10 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
|
||||
mvalo[0]= bedit->lastmouse[0];
|
||||
mvalo[1]= bedit->lastmouse[1];
|
||||
|
||||
/* disable locking temporatily for disconnected hair */
|
||||
if(edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR)
|
||||
pset->flag &= ~PE_LOCK_FIRST;
|
||||
|
||||
if(((pset->brushtype == PE_BRUSH_ADD) ?
|
||||
(sqrt(dx * dx + dy * dy) > pset->brush[PE_BRUSH_ADD].step) : (dx != 0 || dy != 0))
|
||||
|| bedit->first) {
|
||||
@@ -3248,6 +3270,8 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
|
||||
bedit->lastmouse[1]= mouse[1];
|
||||
bedit->first= 0;
|
||||
}
|
||||
|
||||
pset->flag |= lock_root;
|
||||
}
|
||||
|
||||
static void brush_edit_exit(bContext *C, wmOperator *op)
|
||||
@@ -3382,6 +3406,8 @@ static void make_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo)
|
||||
|
||||
for(i=0; i<edit->totpoint; i++, pa++)
|
||||
pa->hair= MEM_dupallocN(pa->hair);
|
||||
|
||||
undo->psys_flag = edit->psys->flag;
|
||||
}
|
||||
else {
|
||||
PTCacheMem *pm;
|
||||
@@ -3449,6 +3475,8 @@ static void get_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo)
|
||||
hkey++;
|
||||
}
|
||||
}
|
||||
|
||||
psys->flag = undo->psys_flag;
|
||||
}
|
||||
else {
|
||||
PTCacheMem *pm;
|
||||
@@ -3704,7 +3732,8 @@ static void PE_create_particle_edit(Scene *scene, Object *ob, PointCache *cache,
|
||||
key->co= hkey->co;
|
||||
key->time= &hkey->time;
|
||||
key->flag= hkey->editflag;
|
||||
key->flag |= PEK_USE_WCO;
|
||||
if(!(psys->flag & PSYS_GLOBAL_HAIR))
|
||||
key->flag |= PEK_USE_WCO;
|
||||
hkey++;
|
||||
}
|
||||
pa++;
|
||||
@@ -3828,6 +3857,7 @@ static int clear_edited_exec(bContext *C, wmOperator *op)
|
||||
psys->free_edit = NULL;
|
||||
|
||||
psys->recalc |= PSYS_RECALC_RESET;
|
||||
psys->flag &= ~PSYS_GLOBAL_HAIR;
|
||||
|
||||
psys_reset(psys, PSYS_RESET_DEPSGRAPH);
|
||||
DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
|
||||
|
||||
@@ -85,6 +85,8 @@ void PARTICLE_OT_new_target(struct wmOperatorType *ot);
|
||||
void PARTICLE_OT_remove_target(struct wmOperatorType *ot);
|
||||
void PARTICLE_OT_target_move_up(struct wmOperatorType *ot);
|
||||
void PARTICLE_OT_target_move_down(struct wmOperatorType *ot);
|
||||
void PARTICLE_OT_connect_hair(struct wmOperatorType *ot);
|
||||
void PARTICLE_OT_disconnect_hair(struct wmOperatorType *ot);
|
||||
|
||||
void SCENE_OT_render_layer_add(struct wmOperatorType *ot);
|
||||
void SCENE_OT_render_layer_remove(struct wmOperatorType *ot);
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
#include "DNA_group_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_material_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
#include "DNA_node_types.h"
|
||||
#include "DNA_texture_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
@@ -42,8 +44,11 @@
|
||||
#include "DNA_space_types.h"
|
||||
#include "DNA_world_types.h"
|
||||
|
||||
#include "BKE_bvhutils.h"
|
||||
#include "BKE_cdderivedmesh.h"
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_depsgraph.h"
|
||||
#include "BKE_DerivedMesh.h"
|
||||
#include "BKE_group.h"
|
||||
#include "BKE_font.h"
|
||||
#include "BKE_library.h"
|
||||
@@ -51,11 +56,13 @@
|
||||
#include "BKE_material.h"
|
||||
#include "BKE_node.h"
|
||||
#include "BKE_particle.h"
|
||||
#include "BKE_pointcache.h"
|
||||
#include "BKE_scene.h"
|
||||
#include "BKE_texture.h"
|
||||
#include "BKE_utildefines.h"
|
||||
#include "BKE_world.h"
|
||||
|
||||
#include "BLI_arithb.h"
|
||||
#include "BLI_editVert.h"
|
||||
#include "BLI_listbase.h"
|
||||
|
||||
@@ -838,6 +845,217 @@ void PARTICLE_OT_target_move_down(wmOperatorType *ot)
|
||||
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
/************************ connect/disconnect hair operators *********************/
|
||||
|
||||
static void disconnect_hair(Scene *scene, Object *ob, ParticleSystem *psys)
|
||||
{
|
||||
ParticleSystemModifierData *psmd = psys_get_modifier(ob,psys);
|
||||
ParticleData *pa = psys->particles;
|
||||
PTCacheEdit *edit = psys->edit;
|
||||
PTCacheEditPoint *point = edit ? edit->points : NULL;
|
||||
PTCacheEditKey *ekey = NULL;
|
||||
HairKey *key;
|
||||
int i, k;
|
||||
float hairmat[4][4];
|
||||
|
||||
if(!ob || !psys || psys->flag & PSYS_GLOBAL_HAIR)
|
||||
return;
|
||||
|
||||
if(!psys->part || psys->part->type != PART_HAIR)
|
||||
return;
|
||||
|
||||
for(i=0; i<psys->totpart; i++,pa++) {
|
||||
if(point) {
|
||||
ekey = point->keys;
|
||||
point++;
|
||||
}
|
||||
|
||||
psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat);
|
||||
|
||||
for(k=0,key=pa->hair; k<pa->totkey; k++,key++) {
|
||||
Mat4MulVecfl(hairmat,key->co);
|
||||
|
||||
if(ekey) {
|
||||
ekey->flag &= ~PEK_USE_WCO;
|
||||
ekey++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
psys_free_path_cache(psys, psys->edit);
|
||||
|
||||
psys->flag |= PSYS_GLOBAL_HAIR;
|
||||
|
||||
PE_update_object(scene, ob, 0);
|
||||
}
|
||||
|
||||
static int disconnect_hair_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Scene *scene= CTX_data_scene(C);
|
||||
Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
|
||||
PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
|
||||
ParticleSystem *psys= NULL;
|
||||
int all = RNA_boolean_get(op->ptr, "all");
|
||||
|
||||
if(!ob)
|
||||
return OPERATOR_CANCELLED;
|
||||
|
||||
if(all) {
|
||||
for(psys=ob->particlesystem.first; psys; psys=psys->next) {
|
||||
disconnect_hair(scene, ob, psys);
|
||||
}
|
||||
}
|
||||
else {
|
||||
psys = ptr.data;
|
||||
disconnect_hair(scene, ob, psys);
|
||||
}
|
||||
|
||||
WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void PARTICLE_OT_disconnect_hair(wmOperatorType *ot)
|
||||
{
|
||||
ot->name= "Disconnect Hair";
|
||||
ot->description= "Disconnect hair from the emitter mesh.";
|
||||
ot->idname= "PARTICLE_OT_disconnect_hair";
|
||||
|
||||
ot->exec= disconnect_hair_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
||||
|
||||
RNA_def_boolean(ot->srna, "all", 0, "All hair", "Disconnect all hair systems from the emitter mesh");
|
||||
}
|
||||
|
||||
static void connect_hair(Scene *scene, Object *ob, ParticleSystem *psys)
|
||||
{
|
||||
ParticleSystemModifierData *psmd = psys_get_modifier(ob,psys);
|
||||
ParticleData *pa = psys->particles;
|
||||
PTCacheEdit *edit = psys->edit;
|
||||
PTCacheEditPoint *point = edit ? edit->points : NULL;
|
||||
PTCacheEditKey *ekey;
|
||||
HairKey *key;
|
||||
BVHTreeFromMesh bvhtree;
|
||||
BVHTreeNearest nearest;
|
||||
MFace *mface;
|
||||
DerivedMesh *dm = CDDM_copy(psmd->dm);
|
||||
int numverts = dm->getNumVerts (dm);
|
||||
int i, k;
|
||||
float hairmat[4][4], imat[4][4];
|
||||
float v[4][3], vec[3];
|
||||
|
||||
if(!psys || !psys->part || psys->part->type != PART_HAIR)
|
||||
return;
|
||||
|
||||
memset( &bvhtree, 0, sizeof(bvhtree) );
|
||||
|
||||
/* convert to global coordinates */
|
||||
for (i=0; i<numverts; i++)
|
||||
Mat4MulVecfl (ob->obmat, CDDM_get_vert(dm, i)->co);
|
||||
|
||||
bvhtree_from_mesh_faces(&bvhtree, dm, 0.0, 2, 6);
|
||||
|
||||
for(i=0; i<psys->totpart; i++,pa++) {
|
||||
key = pa->hair;
|
||||
|
||||
nearest.index = -1;
|
||||
nearest.dist = FLT_MAX;
|
||||
|
||||
BLI_bvhtree_find_nearest(bvhtree.tree, key->co, &nearest, bvhtree.nearest_callback, &bvhtree);
|
||||
|
||||
if(nearest.index == -1) {
|
||||
printf("No nearest point found for hair root!");
|
||||
continue;
|
||||
}
|
||||
|
||||
mface = CDDM_get_face(dm,nearest.index);
|
||||
|
||||
VecCopyf(v[0], CDDM_get_vert(dm,mface->v1)->co);
|
||||
VecCopyf(v[1], CDDM_get_vert(dm,mface->v2)->co);
|
||||
VecCopyf(v[2], CDDM_get_vert(dm,mface->v3)->co);
|
||||
if(mface->v4) {
|
||||
VecCopyf(v[3], CDDM_get_vert(dm,mface->v4)->co);
|
||||
MeanValueWeights(v, 4, nearest.co, pa->fuv);
|
||||
}
|
||||
else
|
||||
MeanValueWeights(v, 3, nearest.co, pa->fuv);
|
||||
|
||||
pa->num = nearest.index;
|
||||
pa->num_dmcache = psys_particle_dm_face_lookup(ob,psmd->dm,pa->num,pa->fuv,NULL);
|
||||
|
||||
psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat);
|
||||
Mat4Invert(imat,hairmat);
|
||||
|
||||
VECSUB(vec, nearest.co, key->co);
|
||||
|
||||
if(point) {
|
||||
ekey = point->keys;
|
||||
point++;
|
||||
}
|
||||
|
||||
for(k=0,key=pa->hair; k<pa->totkey; k++,key++) {
|
||||
VECADD(key->co, key->co, vec);
|
||||
Mat4MulVecfl(imat,key->co);
|
||||
|
||||
if(ekey) {
|
||||
ekey->flag |= PEK_USE_WCO;
|
||||
ekey++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free_bvhtree_from_mesh(&bvhtree);
|
||||
dm->release(dm);
|
||||
|
||||
psys_free_path_cache(psys, psys->edit);
|
||||
|
||||
psys->flag &= ~PSYS_GLOBAL_HAIR;
|
||||
|
||||
PE_update_object(scene, ob, 0);
|
||||
}
|
||||
|
||||
static int connect_hair_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Scene *scene= CTX_data_scene(C);
|
||||
Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
|
||||
PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
|
||||
ParticleSystem *psys= NULL;
|
||||
int all = RNA_boolean_get(op->ptr, "all");
|
||||
|
||||
if(!ob)
|
||||
return OPERATOR_CANCELLED;
|
||||
|
||||
if(all) {
|
||||
for(psys=ob->particlesystem.first; psys; psys=psys->next) {
|
||||
connect_hair(scene, ob, psys);
|
||||
}
|
||||
}
|
||||
else {
|
||||
psys = ptr.data;
|
||||
connect_hair(scene, ob, psys);
|
||||
}
|
||||
|
||||
WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void PARTICLE_OT_connect_hair(wmOperatorType *ot)
|
||||
{
|
||||
ot->name= "Connect Hair";
|
||||
ot->description= "Connect hair to the emitter mesh.";
|
||||
ot->idname= "PARTICLE_OT_connect_hair";
|
||||
|
||||
ot->exec= connect_hair_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
||||
|
||||
RNA_def_boolean(ot->srna, "all", 0, "All hair", "Connect all hair systems to the emitter mesh");
|
||||
}
|
||||
|
||||
/********************** render layer operators *********************/
|
||||
|
||||
static int render_layer_add_exec(bContext *C, wmOperator *op)
|
||||
|
||||
@@ -204,6 +204,8 @@ void buttons_operatortypes(void)
|
||||
WM_operatortype_append(PARTICLE_OT_remove_target);
|
||||
WM_operatortype_append(PARTICLE_OT_target_move_up);
|
||||
WM_operatortype_append(PARTICLE_OT_target_move_down);
|
||||
WM_operatortype_append(PARTICLE_OT_connect_hair);
|
||||
WM_operatortype_append(PARTICLE_OT_disconnect_hair);
|
||||
|
||||
WM_operatortype_append(SCENE_OT_render_layer_add);
|
||||
WM_operatortype_append(SCENE_OT_render_layer_remove);
|
||||
|
||||
@@ -3749,7 +3749,6 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, RegionView3D *rv3d, Obj
|
||||
nosel_col[1]=(float)nosel[1]/255.0f;
|
||||
nosel_col[2]=(float)nosel[2]/255.0f;
|
||||
|
||||
|
||||
/* draw paths */
|
||||
if(timed) {
|
||||
glEnable(GL_BLEND);
|
||||
@@ -3758,24 +3757,16 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, RegionView3D *rv3d, Obj
|
||||
}
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
/* solid shaded with lighting */
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
|
||||
glEnable(GL_COLOR_MATERIAL);
|
||||
glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
|
||||
|
||||
/* only draw child paths with lighting */
|
||||
if(dt > OB_WIRE)
|
||||
glEnable(GL_LIGHTING);
|
||||
|
||||
/* draw paths without lighting */
|
||||
cache=edit->pathcache;
|
||||
for(i=0; i<totpoint; i++){
|
||||
path = cache[i];
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co);
|
||||
glNormalPointer(GL_FLOAT, sizeof(ParticleCacheKey), path->vel);
|
||||
|
||||
if(timed) {
|
||||
for(k=0, pcol=pathcol, pkey=path; k<steps; k++, pkey++, pcol+=4){
|
||||
@@ -3796,9 +3787,6 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, RegionView3D *rv3d, Obj
|
||||
|
||||
/* draw edit vertices */
|
||||
if(pset->selectmode!=SCE_SELECT_PATH){
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
glDisable(GL_LIGHTING);
|
||||
glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
|
||||
|
||||
if(pset->selectmode==SCE_SELECT_POINT){
|
||||
@@ -3810,7 +3798,7 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, RegionView3D *rv3d, Obj
|
||||
if(!(point->flag & PEP_HIDE))
|
||||
totkeys += point->totkey;
|
||||
|
||||
if(!edit->psys)
|
||||
if(!(edit->points->keys->flag & PEK_USE_WCO))
|
||||
pd=pdata=MEM_callocN(totkeys*3*sizeof(float), "particle edit point data");
|
||||
cd=cdata=MEM_callocN(totkeys*(timed?4:3)*sizeof(float), "particle edit color data");
|
||||
|
||||
@@ -3843,7 +3831,7 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, RegionView3D *rv3d, Obj
|
||||
if(point->flag & PEP_HIDE)
|
||||
continue;
|
||||
|
||||
if(edit->psys)
|
||||
if(point->keys->flag & PEK_USE_WCO)
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(PTCacheEditKey), point->keys->world_co);
|
||||
else
|
||||
glVertexPointer(3, GL_FLOAT, 3*sizeof(float), pd);
|
||||
|
||||
@@ -1760,17 +1760,17 @@ static void do_view3d_header_buttons(bContext *C, void *arg, int event)
|
||||
|
||||
case B_SEL_PATH:
|
||||
ts->particle.selectmode= SCE_SELECT_PATH;
|
||||
WM_event_add_notifier(C, NC_OBJECT, ob);
|
||||
WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
|
||||
ED_undo_push(C, "Selectmode Set: Path");
|
||||
break;
|
||||
case B_SEL_POINT:
|
||||
ts->particle.selectmode = SCE_SELECT_POINT;
|
||||
WM_event_add_notifier(C, NC_OBJECT, ob);
|
||||
WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
|
||||
ED_undo_push(C, "Selectmode Set: Point");
|
||||
break;
|
||||
case B_SEL_END:
|
||||
ts->particle.selectmode = SCE_SELECT_END;
|
||||
WM_event_add_notifier(C, NC_OBJECT, ob);
|
||||
WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
|
||||
ED_undo_push(C, "Selectmode Set: End point");
|
||||
break;
|
||||
|
||||
|
||||
@@ -1690,11 +1690,11 @@ static void createTransParticleVerts(bContext *C, TransInfo *t)
|
||||
|
||||
if(!(point->flag & PEP_TRANSFORM)) continue;
|
||||
|
||||
if(psys)
|
||||
if(psys && !(psys->flag & PSYS_GLOBAL_HAIR))
|
||||
psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, psys->particles + i, mat);
|
||||
|
||||
for(k=0, key=point->keys; k<point->totkey; k++, key++) {
|
||||
if(psys) {
|
||||
if(key->flag & PEK_USE_WCO) {
|
||||
VECCOPY(key->world_co, key->co);
|
||||
Mat4MulVecfl(mat, key->world_co);
|
||||
td->loc = key->world_co;
|
||||
@@ -1714,7 +1714,7 @@ static void createTransParticleVerts(bContext *C, TransInfo *t)
|
||||
Mat3One(td->smtx);
|
||||
|
||||
/* don't allow moving roots */
|
||||
if(k==0 && pset->flag & PE_LOCK_FIRST)
|
||||
if(k==0 && pset->flag & PE_LOCK_FIRST && (!psys || !(psys->flag & PSYS_GLOBAL_HAIR)))
|
||||
td->protectflag |= OB_LOCK_LOC;
|
||||
|
||||
td->ob = ob;
|
||||
@@ -1764,7 +1764,7 @@ void flushTransParticles(TransInfo *t)
|
||||
for(i=0, point=edit->points; i<edit->totpoint; i++, point++, td++) {
|
||||
if(!(point->flag & PEP_TRANSFORM)) continue;
|
||||
|
||||
if(psys) {
|
||||
if(psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
|
||||
psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, psys->particles + i, mat);
|
||||
Mat4Invert(imat,mat);
|
||||
|
||||
|
||||
@@ -1884,6 +1884,11 @@ static void rna_def_particle_system(BlenderRNA *brna)
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "softflag", OB_SB_ENABLE);
|
||||
RNA_def_property_ui_text(prop, "Use Soft Body", "Enable use of soft body for hair physics simulation.");
|
||||
|
||||
prop= RNA_def_property(srna, "global_hair", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", PSYS_GLOBAL_HAIR);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_ui_text(prop, "Global Hair", "Hair keys are in global coordinate space");
|
||||
|
||||
/* reactor */
|
||||
prop= RNA_def_property(srna, "reactor_target_object", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "target_ob");
|
||||
|
||||
@@ -107,7 +107,7 @@ static void rna_ParticleEdit_redo(bContext *C, PointerRNA *ptr)
|
||||
if(!edit)
|
||||
return;
|
||||
|
||||
psys_free_path_cache(NULL, edit);
|
||||
psys_free_path_cache(edit->psys, edit);
|
||||
}
|
||||
|
||||
static void rna_ParticleEdit_update(bContext *C, PointerRNA *ptr)
|
||||
@@ -410,7 +410,7 @@ static void rna_def_particle_edit(BlenderRNA *brna)
|
||||
prop= RNA_def_property(srna, "fade_time", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", PE_FADE_TIME);
|
||||
RNA_def_property_ui_text(prop, "Fade Time", "Fade paths and keys further away from current frame.");
|
||||
RNA_def_property_update(prop, NC_OBJECT, "rna_ParticleEdit_update");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_DRAW, "rna_ParticleEdit_update");
|
||||
|
||||
prop= RNA_def_property(srna, "auto_velocity", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", PE_AUTO_VELOCITY);
|
||||
@@ -443,18 +443,18 @@ static void rna_def_particle_edit(BlenderRNA *brna)
|
||||
prop= RNA_def_property(srna, "draw_step", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 2, 10);
|
||||
RNA_def_property_ui_text(prop, "Steps", "How many steps to draw the path with.");
|
||||
RNA_def_property_update(prop, NC_OBJECT, "rna_ParticleEdit_redo");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_DRAW, "rna_ParticleEdit_redo");
|
||||
|
||||
prop= RNA_def_property(srna, "fade_frames", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 2, 100);
|
||||
RNA_def_property_ui_text(prop, "Frames", "How many frames to fade.");
|
||||
RNA_def_property_update(prop, NC_OBJECT, "rna_ParticleEdit_update");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_DRAW, "rna_ParticleEdit_update");
|
||||
|
||||
prop= RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "edittype");
|
||||
RNA_def_property_enum_items(prop, edit_type_items);
|
||||
RNA_def_property_ui_text(prop, "Type", "");
|
||||
RNA_def_property_update(prop, NC_OBJECT, "rna_ParticleEdit_redo");
|
||||
RNA_def_property_update(prop, NC_OBJECT|ND_DRAW, "rna_ParticleEdit_redo");
|
||||
|
||||
prop= RNA_def_property(srna, "editable", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_funcs(prop, "rna_ParticleEdit_editable_get", NULL);
|
||||
|
||||
Reference in New Issue
Block a user