Particle settings can now be pinned too:

* Particle system's are comparable to texture slots, which can
  only exist within an id block. Particle settings on the other
  hand are idblocks which should be pinnable just like textures.
* When particle settings are pinned only properties that make
  sense without the actual particle system are shown in the
  particle panel.
This commit is contained in:
Janne Karhu
2011-02-16 10:57:58 +00:00
parent d450e35f21
commit ef920a50da
2 changed files with 137 additions and 70 deletions

View File

@@ -27,6 +27,8 @@ from properties_physics_common import basic_force_field_falloff_ui
def particle_panel_enabled(context, psys):
if psys == None:
return True
phystype = psys.settings.physics_type
if psys.settings.type in ('EMITTER', 'REACTOR') and phystype in ('NO', 'KEYED'):
return True
@@ -37,11 +39,24 @@ def particle_panel_enabled(context, psys):
def particle_panel_poll(cls, context):
psys = context.particle_system
engine = context.scene.render.engine
if psys is None:
settings = 0
if psys:
settings = psys.settings
elif isinstance(context.space_data.pin_id, bpy.types.ParticleSettings):
settings = context.space_data.pin_id
if not settings:
return False
if psys.settings is None:
return False
return psys.settings.is_fluid == False and (engine in cls.COMPAT_ENGINES)
return settings.is_fluid == False and (engine in cls.COMPAT_ENGINES)
def particle_get_settings(context):
if context.particle_system:
return context.particle_system.settings
elif isinstance(context.space_data.pin_id, bpy.types.ParticleSettings):
return context.space_data.pin_id
return None
class ParticleButtonsPanel():
@@ -62,13 +77,14 @@ class PARTICLE_PT_context_particles(ParticleButtonsPanel, bpy.types.Panel):
@classmethod
def poll(cls, context):
engine = context.scene.render.engine
return (context.particle_system or context.object) and (engine in cls.COMPAT_ENGINES)
return (context.particle_system or context.object or context.space_data.pin_id) and (engine in cls.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
ob = context.object
psys = context.particle_system
part = 0
if ob:
row = layout.row()
@@ -79,7 +95,21 @@ class PARTICLE_PT_context_particles(ParticleButtonsPanel, bpy.types.Panel):
col.operator("object.particle_system_add", icon='ZOOMIN', text="")
col.operator("object.particle_system_remove", icon='ZOOMOUT', text="")
if psys and not psys.settings:
if psys == None:
part = particle_get_settings(context)
if part == None:
return
layout.template_ID(context.space_data, "pin_id")
if part.is_fluid:
layout.label(text="Settings used for fluid.")
return
layout.prop(part, "type", text="Type")
elif not psys.settings:
split = layout.split(percentage=0.32)
col = split.column()
@@ -89,7 +119,7 @@ class PARTICLE_PT_context_particles(ParticleButtonsPanel, bpy.types.Panel):
col = split.column()
col.prop(psys, "name", text="")
col.template_ID(psys, "settings", new="particle.new")
elif psys:
else:
part = psys.settings
split = layout.split(percentage=0.32)
@@ -110,39 +140,39 @@ class PARTICLE_PT_context_particles(ParticleButtonsPanel, bpy.types.Panel):
#row.label(text="Viewport")
#row.label(text="Render")
if part:
if part.is_fluid:
layout.label(text=str(part.count) + " fluid particles for this frame.")
return
if part.is_fluid:
layout.label(text=str(part.count) + " fluid particles for this frame.")
return
row = col.row()
row.enabled = particle_panel_enabled(context, psys)
row.prop(part, "type", text="")
row.prop(psys, "seed")
row = col.row()
row.enabled = particle_panel_enabled(context, psys)
row.prop(part, "type", text="")
row.prop(psys, "seed")
split = layout.split(percentage=0.65)
if part.type == 'HAIR':
if psys.is_edited:
split.operator("particle.edited_clear", text="Free Edit")
else:
row = split.row()
row.enabled = particle_panel_enabled(context, psys)
row.prop(part, "regrow_hair")
row.prop(part, "use_advanced_hair")
if part:
split = layout.split(percentage=0.65)
if part.type == 'HAIR':
if psys != None and psys.is_edited:
split.operator("particle.edited_clear", text="Free Edit")
else:
row = split.row()
row.enabled = particle_panel_enabled(context, psys)
row.prop(part, "hair_step")
if psys.is_edited:
if psys.is_global_hair:
layout.operator("particle.connect_hair")
layout.label(text="Hair is disconnected.")
else:
layout.operator("particle.disconnect_hair")
layout.label(text="")
elif part.type == 'REACTOR':
split.enabled = particle_panel_enabled(context, psys)
split.prop(psys, "reactor_target_object")
split.prop(psys, "reactor_target_particle_system", text="Particle System")
row.prop(part, "regrow_hair")
row.prop(part, "use_advanced_hair")
row = split.row()
row.enabled = particle_panel_enabled(context, psys)
row.prop(part, "hair_step")
if psys != None and psys.is_edited:
if psys.is_global_hair:
layout.operator("particle.connect_hair")
layout.label(text="Hair is disconnected.")
else:
layout.operator("particle.disconnect_hair")
layout.label(text="")
elif psys != None and part.type == 'REACTOR':
split.enabled = particle_panel_enabled(context, psys)
split.prop(psys, "reactor_target_object")
split.prop(psys, "reactor_target_particle_system", text="Particle System")
class PARTICLE_PT_emission(ParticleButtonsPanel, bpy.types.Panel):
@@ -152,23 +182,23 @@ class PARTICLE_PT_emission(ParticleButtonsPanel, bpy.types.Panel):
@classmethod
def poll(cls, context):
psys = context.particle_system
if psys is None:
settings = particle_get_settings(context)
if settings is None:
return False
if psys.settings is None:
return False
if psys.settings.is_fluid:
if settings.is_fluid:
return False
if particle_panel_poll(PARTICLE_PT_emission, context):
return not context.particle_system.point_cache.use_external
return psys == None or not context.particle_system.point_cache.use_external
return False
def draw(self, context):
layout = self.layout
psys = context.particle_system
part = psys.settings
part = particle_get_settings(context)
layout.enabled = particle_panel_enabled(context, psys) and not psys.has_multiple_caches
layout.enabled = particle_panel_enabled(context, psys) and (psys == None or not psys.has_multiple_caches)
row = layout.row()
row.active = part.distribution != 'GRID'
@@ -309,9 +339,11 @@ class PARTICLE_PT_velocity(ParticleButtonsPanel, bpy.types.Panel):
def poll(cls, context):
if particle_panel_poll(PARTICLE_PT_velocity, context):
psys = context.particle_system
if psys.settings.type == 'HAIR' and not psys.settings.use_advanced_hair:
settings = particle_get_settings(context)
if settings.type == 'HAIR' and not settings.use_advanced_hair:
return False
return psys.settings.physics_type != 'BOIDS' and not psys.point_cache.use_external
return settings.physics_type != 'BOIDS' and (psys == None or not psys.point_cache.use_external)
else:
return False
@@ -319,7 +351,7 @@ class PARTICLE_PT_velocity(ParticleButtonsPanel, bpy.types.Panel):
layout = self.layout
psys = context.particle_system
part = psys.settings
part = particle_get_settings(context)
layout.enabled = particle_panel_enabled(context, psys)
@@ -359,9 +391,11 @@ class PARTICLE_PT_rotation(ParticleButtonsPanel, bpy.types.Panel):
def poll(cls, context):
if particle_panel_poll(PARTICLE_PT_rotation, context):
psys = context.particle_system
if psys.settings.type == 'HAIR' and not psys.settings.use_advanced_hair:
settings = particle_get_settings(context)
if settings.type == 'HAIR' and not settings.use_advanced_hair:
return False
return psys.settings.physics_type != 'BOIDS' and not psys.point_cache.use_external
return settings.physics_type != 'BOIDS' and (psys == None or not psys.point_cache.use_external)
else:
return False
@@ -369,7 +403,10 @@ class PARTICLE_PT_rotation(ParticleButtonsPanel, bpy.types.Panel):
layout = self.layout
psys = context.particle_system
part = psys.settings
if psys:
part = psys.settings
else:
part = context.space_data.pin_id
layout.enabled = particle_panel_enabled(context, psys)
@@ -404,9 +441,11 @@ class PARTICLE_PT_physics(ParticleButtonsPanel, bpy.types.Panel):
def poll(cls, context):
if particle_panel_poll(PARTICLE_PT_physics, context):
psys = context.particle_system
if psys.settings.type == 'HAIR' and not psys.settings.use_advanced_hair:
settings = particle_get_settings(context)
if settings.type == 'HAIR' and not settings.use_advanced_hair:
return False
return not psys.point_cache.use_external
return psys == None or not psys.point_cache.use_external
else:
return False
@@ -414,7 +453,7 @@ class PARTICLE_PT_physics(ParticleButtonsPanel, bpy.types.Panel):
layout = self.layout
psys = context.particle_system
part = psys.settings
part = particle_get_settings(context)
layout.enabled = particle_panel_enabled(context, psys)
@@ -504,7 +543,8 @@ class PARTICLE_PT_physics(ParticleButtonsPanel, bpy.types.Panel):
col = row.column()
col.active = not psys.use_keyed_timing
col.prop(part, "keyed_loops", text="Loops")
row.prop(psys, "use_keyed_timing", text="Use Timing")
if psys:
row.prop(psys, "use_keyed_timing", text="Use Timing")
layout.label(text="Keys:")
elif part.physics_type == 'BOIDS':
@@ -555,7 +595,7 @@ class PARTICLE_PT_physics(ParticleButtonsPanel, bpy.types.Panel):
col.prop(boids, "pitch", slider=True)
col.prop(boids, "height", slider=True)
if part.physics_type == 'KEYED' or part.physics_type == 'BOIDS' or part.physics_type == 'FLUID':
if psys and part.physics_type in ('KEYED', 'BOIDS', 'FLUID'):
if part.physics_type == 'BOIDS':
layout.label(text="Relations:")
elif part.physics_type == 'FLUID':
@@ -610,19 +650,19 @@ class PARTICLE_PT_boidbrain(ParticleButtonsPanel, bpy.types.Panel):
@classmethod
def poll(cls, context):
psys = context.particle_system
settings = particle_get_settings(context)
engine = context.scene.render.engine
if psys is None:
if settings is None:
return False
if psys.settings is None:
if psys != None and psys.point_cache.use_external:
return False
if psys.point_cache.use_external:
return False
return psys.settings.physics_type == 'BOIDS' and engine in cls.COMPAT_ENGINES
return settings.physics_type == 'BOIDS' and engine in cls.COMPAT_ENGINES
def draw(self, context):
layout = self.layout
boids = context.particle_system.settings.boids
boids = particle_get_settings(context).boids
layout.enabled = particle_panel_enabled(context, context.particle_system)
@@ -890,7 +930,7 @@ class PARTICLE_PT_draw(ParticleButtonsPanel, bpy.types.Panel):
layout = self.layout
psys = context.particle_system
part = psys.settings
part = particle_get_settings(context)
row = layout.row()
row.prop(part, "draw_method", expand=True)
@@ -949,7 +989,7 @@ class PARTICLE_PT_children(ParticleButtonsPanel, bpy.types.Panel):
layout = self.layout
psys = context.particle_system
part = psys.settings
part = particle_get_settings(context)
layout.row().prop(part, "child_type", expand=True)
@@ -964,7 +1004,8 @@ class PARTICLE_PT_children(ParticleButtonsPanel, bpy.types.Panel):
if part.child_type == 'INTERPOLATED':
col = row.column()
col.prop(psys, "child_seed", text="Seed")
if psys:
col.prop(psys, "child_seed", text="Seed")
col.prop(part, "virtual_parents", slider=True)
col.prop(part, "create_long_hair_children")
else:
@@ -989,7 +1030,8 @@ class PARTICLE_PT_children(ParticleButtonsPanel, bpy.types.Panel):
sub = col.column(align=True)
sub.prop(part, "child_radius", text="Radius")
sub.prop(part, "child_roundness", text="Roundness", slider=True)
sub.prop(psys, "child_seed", text="Seed")
if psys:
sub.prop(psys, "child_seed", text="Seed")
elif part.virtual_parents > 0.0:
sub = col.column(align=True)
sub.label(text="Parting not")
@@ -1044,7 +1086,7 @@ class PARTICLE_PT_field_weights(ParticleButtonsPanel, bpy.types.Panel):
return particle_panel_poll(cls, context)
def draw(self, context):
part = context.particle_system.settings
part = particle_get_settings(context)
effector_weights_ui(self, context, part.effector_weights)
if part.type == 'HAIR':
@@ -1063,7 +1105,7 @@ class PARTICLE_PT_force_fields(ParticleButtonsPanel, bpy.types.Panel):
def draw(self, context):
layout = self.layout
part = context.particle_system.settings
part = particle_get_settings(context)
row = layout.row()
row.prop(part, "use_self_effect")
@@ -1096,6 +1138,8 @@ class PARTICLE_PT_vertexgroups(ParticleButtonsPanel, bpy.types.Panel):
@classmethod
def poll(cls, context):
if context.particle_system == None:
return False
return particle_panel_poll(cls, context)
def draw(self, context):

View File

@@ -307,7 +307,12 @@ static int buttons_context_path_particle(ButsContextPath *path)
{
Object *ob;
ParticleSystem *psys;
PointerRNA *ptr= &path->ptr[path->len-1];
/* if we already have (pinned) particle settings, we're done */
if(RNA_struct_is_a(ptr->type, &RNA_ParticleSettings)) {
return 1;
}
/* if we have an object, get the active particle system */
if(buttons_context_path_object(path)) {
ob= path->ptr[path->len-1].data;
@@ -395,15 +400,25 @@ static int buttons_context_path_texture(ButsContextPath *path)
}
/* try particles */
if((path->tex_ctx == SB_TEXC_PARTICLES) && buttons_context_path_particle(path)) {
psys= path->ptr[path->len-1].data;
if(psys && psys->part && GS(psys->part->id.name)==ID_PA) {
tex= give_current_particle_texture(psys->part);
if(path->ptr[path->len-1].type == &RNA_ParticleSettings) {
ParticleSettings *part = path->ptr[path->len-1].data;
tex= give_current_particle_texture(part);
RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
path->len++;
return 1;
}
else {
psys= path->ptr[path->len-1].data;
if(psys && psys->part && GS(psys->part->id.name)==ID_PA) {
tex= give_current_particle_texture(psys->part);
RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
path->len++;
return 1;
}
}
}
/* try material */
if(buttons_context_path_material(path)) {
@@ -930,6 +945,14 @@ ID *buttons_context_id_path(const bContext *C)
for(a=path->len-1; a>=0; a--) {
ptr= &path->ptr[a];
/* pin particle settings instead of system, since only settings are an idblock*/
if(sbuts->mainb == BCONTEXT_PARTICLE && sbuts->flag & SB_PIN_CONTEXT) {
if(ptr->type == &RNA_ParticleSystem && ptr->data) {
ParticleSystem *psys = (ParticleSystem *)ptr->data;
return &psys->part->id;
}
}
if(ptr->id.data) {
return ptr->id.data;
break;