Particle ID block controls:
authorJanne Karhu <jhkarh@gmail.com>
Sat, 27 Jun 2009 15:41:47 +0000 (15:41 +0000)
committerJanne Karhu <jhkarh@gmail.com>
Sat, 27 Jun 2009 15:41:47 +0000 (15:41 +0000)
* Adding/removing particle systems to an object.
* Changing of particle settings.
* Currently showing an object's particle systems in a list (like materials).

release/ui/buttons_particle.py
source/blender/blenkernel/BKE_particle.h
source/blender/blenkernel/intern/depsgraph.c
source/blender/blenkernel/intern/modifier.c
source/blender/blenkernel/intern/particle.c
source/blender/editors/space_buttons/buttons_intern.h
source/blender/editors/space_buttons/buttons_ops.c
source/blender/editors/space_buttons/space_buttons.c
source/blender/makesrna/intern/rna_object.c
source/blender/makesrna/intern/rna_particle.c

index 378689e820289bf6c74fee73497d16a4afbd722e..e51df6ef7fd1777d4b992c83ea62e9a8d8b7c931 100644 (file)
@@ -7,6 +7,7 @@ def particle_panel_enabled(psys):
 def particle_panel_poll(context):
        psys = context.particle_system
        if psys==None:  return False
+       if psys.settings==None:  return False
        return psys.settings.type in ('EMITTER', 'REACTOR', 'HAIR')
 
 class ParticleButtonsPanel(bpy.types.Panel):
@@ -29,42 +30,51 @@ class PARTICLE_PT_particles(ParticleButtonsPanel):
                ob = context.object
                psys = context.particle_system
 
-               split = layout.split(percentage=0.65)
+               if ob:
+                       row = layout.row()
 
-               if psys:
-                       split.template_ID(psys, "settings")
+                       row.template_list(ob, "particle_systems", "active_particle_system_index")
+
+                       col = row.column(align=True)
+                       col.itemO("OBJECT_OT_particle_system_slot_add", icon="ICON_ZOOMIN", text="")
+                       col.itemO("OBJECT_OT_particle_system_slot_remove", icon="ICON_ZOOMOUT", text="")
 
                if psys:
+                       split = layout.split(percentage=0.65)
+                       
+                       split.template_ID(psys, "settings", new="PARTICLE_OT_new")
+                       
                        #row = layout.row()
                        #row.itemL(text="Viewport")
                        #row.itemL(text="Render")
                        
                        part = psys.settings
-                       ptype = psys.settings.type
                        
-                       if ptype not in ('EMITTER', 'REACTOR', 'HAIR'):
-                               layout.itemL(text="No settings for fluid particles")
-                               return
+                       if part:
+                               ptype = psys.settings.type
+                               if ptype not in ('EMITTER', 'REACTOR', 'HAIR'):
+                                       layout.itemL(text="No settings for fluid particles")
+                                       return
+                                       
+                               split = layout.split(percentage=0.65)
                                
-                       split = layout.split(percentage=0.65)
-                       
-                       split.enabled = particle_panel_enabled(psys)
-                       split.itemR(part, "type")
-                       split.itemR(psys, "seed")
-                       
-                       split = layout.split(percentage=0.65)
-                       if part.type=='HAIR':
-                               if psys.editable==True:
-                                       split.itemO("PARTICLE_OT_editable_set", text="Free Edit")
-                               else:
-                                       split.itemO("PARTICLE_OT_editable_set", text="Make Editable")
-                               row = split.row()
-                               row.enabled = particle_panel_enabled(psys)
-                               row.itemR(part, "hair_step")
-                       elif part.type=='REACTOR':
                                split.enabled = particle_panel_enabled(psys)
-                               split.itemR(psys, "reactor_target_object")
-                               split.itemR(psys, "reactor_target_particle_system", text="Particle System")
+                               split.itemR(part, "type")
+                               split.itemR(psys, "seed")
+                               
+                               split = layout.split(percentage=0.65)
+                               if part.type=='HAIR':
+                                       if psys.editable==True:
+                                               split.itemO("PARTICLE_OT_editable_set", text="Free Edit")
+                                       else:
+                                               split.itemO("PARTICLE_OT_editable_set", text="Make Editable")
+                                       row = split.row()
+                                       row.enabled = particle_panel_enabled(psys)
+                                       row.itemR(part, "hair_step")
+                               elif part.type=='REACTOR':
+                                       split.enabled = particle_panel_enabled(psys)
+                                       split.itemR(psys, "reactor_target_object")
+                                       split.itemR(psys, "reactor_target_particle_system", text="Particle System")
                
 class PARTICLE_PT_emission(ParticleButtonsPanel):
        __idname__= "PARTICLE_PT_emission"
@@ -120,6 +130,7 @@ class PARTICLE_PT_cache(ParticleButtonsPanel):
        def poll(self, context):
                psys = context.particle_system
                if psys==None:  return False
+               if psys.settings==None:  return False
                return psys.settings.type in ('EMITTER', 'REACTOR')
 
        def draw(self, context):
@@ -287,7 +298,10 @@ class PARTICLE_PT_render(ParticleButtonsPanel):
        __label__ = "Render"
        
        def poll(self, context):
-               return (context.particle_system != None)
+               psys = context.particle_system
+               if psys==None: return False
+               if psys.settings==None: return False
+               return True;
                
        def draw(self, context):
                layout = self.layout
@@ -421,7 +435,10 @@ class PARTICLE_PT_draw(ParticleButtonsPanel):
        __default_closed__ = True
        
        def poll(self, context):
-               return (context.particle_system != None)
+               psys = context.particle_system
+               if psys==None: return False
+               if psys.settings==None: return False
+               return True;
        
        def draw(self, context):
                layout = self.layout
index 08aa111e0e61ffe114121866a65200fe3c18fcc5..4d9916b955767830761239ea6823ab690326f7c7 100644 (file)
@@ -217,6 +217,7 @@ char *psys_menu_string(struct Object *ob, int for_sb);
 
 struct ParticleSystem *psys_get_current(struct Object *ob);
 short psys_get_current_num(struct Object *ob);
+void psys_set_current_num(Object *ob, int index);
 struct Object *psys_find_object(struct Scene *scene, struct ParticleSystem *psys);
 //struct ParticleSystem *psys_get(struct Object *ob, int index);
 struct ParticleData *psys_get_selected_particle(struct ParticleSystem *psys, int *index);
@@ -250,6 +251,8 @@ void copy_particle_key(struct ParticleKey *to, struct ParticleKey *from, int tim
 void psys_particle_on_emitter(struct ParticleSystemModifierData *psmd, int distr, int index, int index_dmcache, float *fuv, float foffset, float *vec, float *nor, float *utan, float *vtan, float *orco, float *ornor);
 struct ParticleSystemModifierData *psys_get_modifier(struct Object *ob, struct ParticleSystem *psys);
 
+void object_add_particle_system_slot(struct Scene *scene, struct Object *ob);
+void object_remove_particle_system_slot(struct Scene *scene, struct Object *ob);
 struct ParticleSettings *psys_new_settings(char *name, struct Main *main);
 struct ParticleSettings *psys_copy_settings(struct ParticleSettings *part);
 void psys_flush_particle_settings(struct Scene *scene, struct ParticleSettings *part, int recalc);
index b57b8b7a6da1878d0d371007dd8898f790e94d9b..a36b825293e2793398940139394a324cb22d74fa 100644 (file)
@@ -559,7 +559,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O
 
                        dag_add_relation(dag, node, node, DAG_RL_OB_DATA, "Particle-Object Relation");
 
-                       if(psys->flag & PSYS_DISABLED || psys->flag & PSYS_DELETE)
+                       if(!psys_check_enabled(ob, psys))
                                continue;
 
                        if(part->phystype==PART_PHYS_KEYED && psys->keyed_ob &&
index 1a6f57e75c421f457e953fe2aad38c1b0de1a2aa..80a9f173d6ac119b23c9d0918fc9e670f5d41e90 100644 (file)
@@ -6295,6 +6295,9 @@ CustomDataMask particleSystemModifier_requiredDataMask(Object *ob, ModifierData
        MTex *mtex;
        int i;
 
+       if(!psmd->psys->part)
+               return 0;
+
        ma= give_current_material(ob, psmd->psys->part->omat);
        if(ma) {
                for(i=0; i<MAX_MTEX; i++) {
index 04215b1ddd1453fc2972429bb867b0c0bd126e31..2474053298d81a1148b2715dbf6af847842b923d 100644 (file)
@@ -222,6 +222,20 @@ short psys_get_current_num(Object *ob)
        
        return i;
 }
+void psys_set_current_num(Object *ob, int index)
+{
+       ParticleSystem *psys;
+       short i;
+
+       if(ob==0) return;
+
+       for(psys=ob->particlesystem.first, i=0; psys; psys=psys->next, i++) {
+               if(i == index - 1)
+                       psys->flag |= PSYS_CURRENT;
+               else
+                       psys->flag &= ~PSYS_CURRENT;
+       }
+}
 Object *psys_find_object(Scene *scene, ParticleSystem *psys)
 {
        Base *base = scene->base.first;
@@ -307,7 +321,7 @@ int psys_check_enabled(Object *ob, ParticleSystem *psys)
        ParticleSystemModifierData *psmd;
        Mesh *me;
 
-       if(psys->flag & PSYS_DISABLED || psys->flag & PSYS_DELETE)
+       if(psys->flag & PSYS_DISABLED || psys->flag & PSYS_DELETE || !psys->part)
                return 0;
 
        if(ob->type == OB_MESH) {
@@ -2915,6 +2929,61 @@ void psys_mat_hair_to_global(Object *ob, DerivedMesh *dm, short from, ParticleDa
 /************************************************/
 /*                     ParticleSettings handling                       */
 /************************************************/
+void object_add_particle_system_slot(Scene *scene, Object *ob)
+{
+       ParticleSystem *psys;
+       ModifierData *md;
+       ParticleSystemModifierData *psmd;
+
+       if(!ob || ob->type != OB_MESH)
+               return;
+
+       psys = ob->particlesystem.first;
+       for(; psys; psys=psys->next)
+               psys->flag &= ~PSYS_CURRENT;
+
+       psys = MEM_callocN(sizeof(ParticleSystem), "particle_system");
+       psys->pointcache = BKE_ptcache_add();
+       BLI_addtail(&ob->particlesystem, psys);
+
+       psys->part = psys_new_settings("PSys", NULL);
+
+       md= modifier_new(eModifierType_ParticleSystem);
+       sprintf(md->name, "ParticleSystem %i", BLI_countlist(&ob->particlesystem));
+       psmd= (ParticleSystemModifierData*) md;
+       psmd->psys=psys;
+       BLI_addtail(&ob->modifiers, md);
+
+       psys->totpart=0;
+       psys->flag = PSYS_ENABLED|PSYS_CURRENT;
+       psys->cfra=bsystem_time(scene,ob,scene->r.cfra+1,0.0);
+
+       DAG_scene_sort(scene);
+       DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
+}
+void object_remove_particle_system_slot(Scene *scene, Object *ob)
+{
+       ParticleSystem *psys = psys_get_current(ob);
+       ParticleSystemModifierData *psmd;
+
+       if(!psys)
+               return;
+
+       /* clear modifier */
+       psmd= psys_get_modifier(ob, psys);
+       BLI_remlink(&ob->modifiers, psmd);
+       modifier_free((ModifierData *)psmd);
+
+       /* clear particle system */
+       BLI_remlink(&ob->particlesystem, psys);
+       psys_free(ob,psys);
+
+       if(ob->particlesystem.first)
+               ((ParticleSystem *) ob->particlesystem.first)->flag |= PSYS_CURRENT;
+
+       DAG_scene_sort(scene);
+       DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
+}
 static void default_particle_settings(ParticleSettings *part)
 {
        int i;
@@ -3001,6 +3070,9 @@ ParticleSettings *psys_new_settings(char *name, Main *main)
 {
        ParticleSettings *part;
 
+       if(main==NULL)
+               main = G.main;
+
        part= alloc_libblock(&main->particle, ID_PA, name);
        
        default_particle_settings(part);
index b213e4288be407dd67245f205f469412ab7e0f2c..13ea778fb007ff59fad8a5a3fda68859e45f7044 100644 (file)
@@ -71,5 +71,10 @@ void MATERIAL_OT_new(struct wmOperatorType *ot);
 void TEXTURE_OT_new(struct wmOperatorType *ot);
 void WORLD_OT_new(struct wmOperatorType *ot);
 
+void OBJECT_OT_particle_system_slot_add(struct wmOperatorType *ot);
+void OBJECT_OT_particle_system_slot_remove(struct wmOperatorType *ot);
+
+void PARTICLE_OT_new(struct wmOperatorType *ot);
+
 #endif /* ED_BUTTONS_INTERN_H */
 
index 6755a2be1b7fea4b419984917ec2972eec68380b..6ca92674c6edaef3ee191f5c441ceeae60fdff45 100644 (file)
@@ -42,6 +42,7 @@
 #include "BKE_font.h"
 #include "BKE_library.h"
 #include "BKE_material.h"
+#include "BKE_particle.h"
 #include "BKE_texture.h"
 #include "BKE_utildefines.h"
 #include "BKE_world.h"
@@ -407,3 +408,109 @@ void WORLD_OT_new(wmOperatorType *ot)
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 }
 
+
+
+/********************** particle system slot operators *********************/
+
+static int particle_system_slot_add_exec(bContext *C, wmOperator *op)
+{
+       Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
+       Scene *scene = CTX_data_scene(C);
+
+       if(!scene || !ob)
+               return OPERATOR_CANCELLED;
+
+       object_add_particle_system_slot(scene, ob);
+       WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
+       
+       return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_particle_system_slot_add(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Add Particle System Slot";
+       ot->idname= "OBJECT_OT_particle_system_slot_add";
+       
+       /* api callbacks */
+       ot->exec= particle_system_slot_add_exec;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+static int particle_system_slot_remove_exec(bContext *C, wmOperator *op)
+{
+       Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
+       Scene *scene = CTX_data_scene(C);
+
+       if(!scene || !ob)
+               return OPERATOR_CANCELLED;
+
+       object_remove_particle_system_slot(scene, ob);
+       WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
+       
+       return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_particle_system_slot_remove(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Remove Particle System Slot";
+       ot->idname= "OBJECT_OT_particle_system_slot_remove";
+       
+       /* api callbacks */
+       ot->exec= particle_system_slot_remove_exec;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+/********************** new particle settings operator *********************/
+
+static int new_particle_settings_exec(bContext *C, wmOperator *op)
+{
+       Scene *scene = CTX_data_scene(C);
+       ParticleSettings *part= CTX_data_pointer_get_type(C, "particle_settings", &RNA_ParticleSettings).data;
+       Object *ob;
+       PointerRNA ptr;
+
+       /* add or copy particle setting */
+       if(part)
+               part= psys_copy_settings(part);
+       else
+               part= psys_new_settings("PSys", NULL);
+
+       /* attempt to assign to material slot */
+       ptr= CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
+
+       if(ptr.data) {
+               ParticleSystem *psys = (ParticleSystem*)ptr.data;
+               ob= ptr.id.data;
+
+               if(psys->part)
+                       psys->part->id.us--;
+
+               psys->part = part;
+
+               DAG_scene_sort(scene);
+               DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
+
+               WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
+       }
+       
+       return OPERATOR_FINISHED;
+}
+
+void PARTICLE_OT_new(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "New Particle Settings";
+       ot->idname= "PARTICLE_OT_new";
+       
+       /* api callbacks */
+       ot->exec= new_particle_settings_exec;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
index 483a1dc61002c60f7fb1385865513847a4041b12..7954d5254cc0a37c6d248e921bd64058b2824df7 100644 (file)
@@ -219,6 +219,11 @@ void buttons_operatortypes(void)
        WM_operatortype_append(MATERIAL_OT_new);
        WM_operatortype_append(TEXTURE_OT_new);
        WM_operatortype_append(WORLD_OT_new);
+
+       WM_operatortype_append(OBJECT_OT_particle_system_slot_add);
+       WM_operatortype_append(OBJECT_OT_particle_system_slot_remove);
+
+       WM_operatortype_append(PARTICLE_OT_new);
 }
 
 void buttons_keymap(struct wmWindowManager *wm)
index 5b553469bc80d06a891ebb66d749da43b6226f4c..9b3100c733bde43fa68514fcd5d7de3f681c71a0 100644 (file)
@@ -241,6 +241,25 @@ static PointerRNA rna_Object_active_material_get(PointerRNA *ptr)
        return rna_pointer_inherit_refine(ptr, &RNA_MaterialSlot, ob->mat+ob->actcol);
 }
 
+static void rna_Object_active_particle_system_index_range(PointerRNA *ptr, int *min, int *max)
+{
+       Object *ob= (Object*)ptr->id.data;
+       *min= 1;
+       *max= BLI_countlist(&ob->particlesystem);
+}
+
+static int rna_Object_active_particle_system_index_get(PointerRNA *ptr)
+{
+       Object *ob= (Object*)ptr->id.data;
+       return psys_get_current_num(ob) + 1;
+}
+
+static void rna_Object_active_particle_system_index_set(struct PointerRNA *ptr, int value)
+{
+       Object *ob= (Object*)ptr->id.data;
+       psys_set_current_num(ob, value);
+}
+
 #if 0
 static void rna_Object_active_material_set(PointerRNA *ptr, PointerRNA value)
 {
@@ -929,6 +948,10 @@ static void rna_def_object(BlenderRNA *brna)
        RNA_def_property_pointer_funcs(prop, "rna_Object_active_particle_system_get", NULL, NULL);
        RNA_def_property_ui_text(prop, "Active Particle System", "Active particle system being displayed");
 
+       prop= RNA_def_property(srna, "active_particle_system_index", PROP_INT, PROP_UNSIGNED);
+       RNA_def_property_int_funcs(prop, "rna_Object_active_particle_system_index_get", "rna_Object_active_particle_system_index_set", "rna_Object_active_particle_system_index_range");
+       RNA_def_property_ui_text(prop, "Active Particle System Index", "Index of active particle system slot.");
+
        /* restrict */
 
        prop= RNA_def_property(srna, "restrict_view", PROP_BOOLEAN, PROP_NONE);
index ae53c815ed9c84a6758f4439528953ff7c4dc618..d60a215b4985126b41f442b52240aecc37b25655 100644 (file)
@@ -81,13 +81,11 @@ static void rna_Particle_reset(bContext *C, PointerRNA *ptr)
 
                if(ob) {
                        DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
-                       //WM_event_add_notifier(C, NC_SCENE|ND_CACHE_PHYSICS, scene);
                }
        }
        else {
                part = ptr->id.data;
                psys_flush_particle_settings(scene, part, PSYS_RECALC_RESET);
-               //WM_event_add_notifier(C, NC_SCENE|ND_CACHE_PHYSICS, scene);
        }
 }
 
@@ -104,13 +102,11 @@ static void rna_Particle_change_type(bContext *C, PointerRNA *ptr)
 
                if(ob) {
                        DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
-                       //WM_event_add_notifier(C, NC_SCENE|ND_CACHE_PHYSICS, scene);
                }
        }
        else {
                part = ptr->id.data;
                psys_flush_particle_settings(scene, part, PSYS_RECALC_RESET|PSYS_RECALC_TYPE);
-               //WM_event_add_notifier(C, NC_SCENE|ND_CACHE_PHYSICS, scene);
        }
 }
 
@@ -134,6 +130,27 @@ static void rna_Particle_redo_child(bContext *C, PointerRNA *ptr)
                psys_flush_particle_settings(scene, part, PSYS_RECALC_CHILD);
        }
 }
+static PointerRNA rna_particle_settings_get(PointerRNA *ptr)
+{
+       Object *ob= (Object*)ptr->id.data;
+       ParticleSettings *part = psys_get_current(ob)->part;
+
+       return rna_pointer_inherit_refine(ptr, &RNA_ParticleSettings, part);
+}
+
+static void rna_particle_settings_set(PointerRNA *ptr, PointerRNA value)
+{
+       Object *ob= (Object*)ptr->id.data;
+       ParticleSystem *psys = psys_get_current(ob);
+
+       if(psys->part)
+               psys->part->id.us--;
+
+       psys->part = (ParticleSettings *)value.data;
+
+       if(psys->part)
+               psys->part->id.us++;
+}
 static void rna_PartSettings_start_set(struct PointerRNA *ptr, float value)
 {
        ParticleSettings *settings = (ParticleSettings*)ptr->data;
@@ -1493,9 +1510,15 @@ static void rna_def_particle_system(BlenderRNA *brna)
        RNA_def_property_clear_flag(prop, PROP_EDITABLE);
        RNA_def_struct_name_property(srna, prop);
 
+       /* access to particle settings is redirected through functions */
+       /* to allow proper id-buttons functionality */
        prop= RNA_def_property(srna, "settings", PROP_POINTER, PROP_NEVER_NULL);
-       RNA_def_property_pointer_sdna(prop, NULL, "part");
+       //RNA_def_property_pointer_sdna(prop, NULL, "part");
+       RNA_def_property_struct_type(prop, "ParticleSettings");
+       RNA_def_property_flag(prop, PROP_EDITABLE);
+       RNA_def_property_pointer_funcs(prop, "rna_particle_settings_get", "rna_particle_settings_set", NULL);
        RNA_def_property_ui_text(prop, "Settings", "Particle system settings.");
+       RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
 
        prop= RNA_def_property(srna, "particles", PROP_COLLECTION, PROP_NONE);
        RNA_def_property_collection_sdna(prop, NULL, "particles", "totpart");