diff options
28 files changed, 2064 insertions, 1945 deletions
diff --git a/release/ui/buttons_particle.py b/release/ui/buttons_particle.py index 0454f2a4023..0b18b7c2072 100644 --- a/release/ui/buttons_particle.py +++ b/release/ui/buttons_particle.py @@ -2,13 +2,79 @@ import bpy def particle_panel_enabled(psys): - return psys.point_cache.baked==False and psys.editable==False + return psys.point_cache.baked==False and psys.edited==False 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') + +def point_cache_ui(self, cache, enabled, particles, smoke): + layout = self.layout + layout.set_context_pointer("PointCache", cache) + + row = layout.row() + row.template_list(cache, "point_cache_list", cache, "active_point_cache_index", rows=2 ) + col = row.column(align=True) + col.itemO("ptcache.add_new", icon='ICON_ZOOMIN', text="") + col.itemO("ptcache.remove", icon='ICON_ZOOMOUT', text="") + + row = layout.row() + row.itemL(text="File Name:") + if particles: + row.itemR(cache, "external") + + if cache.external: + split = layout.split(percentage=0.80) + split.itemR(cache, "name", text="") + split.itemR(cache, "index", text="") + + layout.itemL(text="File Path:") + layout.itemR(cache, "filepath", text="") + + layout.itemL(text=cache.info) + else: + layout.itemR(cache, "name", text="") + + if not particles: + row = layout.row() + row.enabled = enabled + row.itemR(cache, "start_frame") + row.itemR(cache, "end_frame") + + row = layout.row() + + if cache.baked == True: + row.itemO("ptcache.free_bake", text="Free Bake") + else: + row.item_booleanO("ptcache.bake", "bake", True, text="Bake") + + sub = row.row() + sub.enabled = (cache.frames_skipped or cache.outdated) and enabled + sub.itemO("ptcache.bake", "bake", False, text="Calculate to Current Frame") + + row = layout.row() + row.enabled = enabled + row.itemO("ptcache.bake_from_cache", text="Current Cache to Bake") + row.itemR(cache, "step"); + + if not smoke: + row = layout.row() + sub = row.row() + sub.enabled = enabled + sub.itemR(cache, "quick_cache") + row.itemR(cache, "disk_cache") + + layout.itemL(text=cache.info) + + layout.itemS() + + row = layout.row() + row.item_booleanO("ptcache.bake_all", "bake", True, text="Bake All Dynamics") + row.itemO("ptcache.free_bake_all", text="Free All Bakes") + layout.itemO("ptcache.bake_all", "bake", False, text="Update All Dynamics to current frame") + class ParticleButtonsPanel(bpy.types.Panel): __space_type__ = 'PROPERTIES' @@ -38,7 +104,16 @@ class PARTICLE_PT_particles(ParticleButtonsPanel): col.itemO("object.particle_system_add", icon='ICON_ZOOMIN', text="") col.itemO("object.particle_system_remove", icon='ICON_ZOOMOUT', text="") - if psys: + if psys and not psys.settings: + split = layout.split(percentage=0.32) + col = split.column() + col.itemL(text="Name:") + col.itemL(text="Settings:") + + col = split.column() + col.itemR(psys, "name", text="") + col.template_ID(psys, "settings", new="particle.new") + elif psys: part = psys.settings split = layout.split(percentage=0.32) @@ -69,10 +144,10 @@ class PARTICLE_PT_particles(ParticleButtonsPanel): split = layout.split(percentage=0.65) if part.type=='HAIR': - if psys.editable==True: - split.itemO("particle.editable_set", text="Free Edit") + if psys.edited==True: + split.itemO("particle.edited_clear", text="Free Edit") else: - split.itemO("particle.editable_set", text="Make Editable") + split.itemL(text="") row = split.row() row.enabled = particle_panel_enabled(psys) row.itemR(part, "hair_step") @@ -96,7 +171,7 @@ class PARTICLE_PT_emission(ParticleButtonsPanel): psys = context.particle_system part = psys.settings - layout.enabled = particle_panel_enabled(psys) + layout.enabled = particle_panel_enabled(psys) and not psys.multiple_caches row = layout.row() row.itemR(part, "amount") @@ -149,76 +224,8 @@ class PARTICLE_PT_cache(ParticleButtonsPanel): layout = self.layout psys = context.particle_system - part = psys.settings - cache = psys.point_cache - layout.set_context_pointer("PointCache", cache) - - row = layout.row() - row.template_list(cache, "point_cache_list", cache, "active_point_cache_index", rows=2 ) - col = row.column(align=True) - col.itemO("ptcache.add_new", icon='ICON_ZOOMIN', text="") - col.itemO("ptcache.remove", icon='ICON_ZOOMOUT', text="") - - row = layout.row() - row.itemL(text="File Name:") - row.itemR(cache, "external") - - if cache.external: - split = layout.split(percentage=0.80) - split.itemR(cache, "name", text="") - split.itemR(cache, "index", text="") - - layout.itemL(text="File Path:") - layout.itemR(cache, "filepath", text="") - - layout.itemL(text=cache.info) - - #split = layout.split() - - #col = split.column(align=True) - #col.itemR(part, "start") - #col.itemR(part, "end") - - #col = split.column(align=True) - #col.itemR(part, "lifetime") - #col.itemR(part, "random_lifetime", slider=True) - else: - layout.itemR(cache, "name", text="") - - row = layout.row() - - if cache.baked == True: - row.itemO("ptcache.free_bake", text="Free Bake") - else: - row.item_booleanO("ptcache.bake", "bake", True, text="Bake") - - subrow = row.row() - subrow.enabled = (cache.frames_skipped or cache.outdated) and particle_panel_enabled(psys) - subrow.itemO("ptcache.bake", "bake", False, text="Calculate to Current Frame") - - row = layout.row() - row.enabled = particle_panel_enabled(psys) - row.itemO("ptcache.bake_from_cache", text="Current Cache to Bake") - row.itemR(cache, "step"); - - row = layout.row() - subrow = row.row() - subrow.enabled = particle_panel_enabled(psys) - subrow.itemR(cache, "quick_cache") - row.itemR(cache, "disk_cache") - - layout.itemL(text=cache.info) - - layout.itemS() - - row = layout.row() - row.item_booleanO("ptcache.bake_all", "bake", True, text="Bake All Dynamics") - row.itemO("ptcache.free_bake_all", text="Free All Bakes") - layout.itemO("ptcache.bake_all", "bake", False, text="Update All Dynamics to current frame") - # for particles these are figured out automatically - #row.itemR(cache, "start_frame") - #row.itemR(cache, "end_frame") + point_cache_ui(self, psys.point_cache, particle_panel_enabled(psys), 1, 0) class PARTICLE_PT_initial(ParticleButtonsPanel): __label__ = "Velocity" diff --git a/release/ui/buttons_physics_cloth.py b/release/ui/buttons_physics_cloth.py index 9ddf03e3d4d..9399d557a51 100644 --- a/release/ui/buttons_physics_cloth.py +++ b/release/ui/buttons_physics_cloth.py @@ -1,6 +1,11 @@ import bpy +from buttons_particle import point_cache_ui + +def cloth_panel_enabled(md): + return md.point_cache.baked==False + class PhysicButtonsPanel(bpy.types.Panel): __space_type__ = 'PROPERTIES' __region_type__ = 'WINDOW' @@ -41,6 +46,8 @@ class PHYSICS_PT_cloth(PhysicButtonsPanel): split = layout.split() + split.active = cloth_panel_enabled(md) + col = split.column() col.itemL(text="Quality:") col.itemR(cloth, "quality", text="Steps",slider=True) @@ -85,53 +92,8 @@ class PHYSICS_PT_cloth_cache(PhysicButtonsPanel): return (context.cloth != None) def draw(self, context): - layout = self.layout - - cache = context.cloth.point_cache - layout.set_context_pointer("PointCache", cache) - - row = layout.row() - row.template_list(cache, "point_cache_list", cache, "active_point_cache_index", rows=2) - col = row.column(align=True) - col.itemO("ptcache.add_new", icon='ICON_ZOOMIN', text="") - col.itemO("ptcache.remove", icon='ICON_ZOOMOUT', text="") - - row = layout.row() - row.itemR(cache, "name") - - row = layout.row() - row.itemR(cache, "start_frame") - row.itemR(cache, "end_frame") - - row = layout.row() - - if cache.baked == True: - row.itemO("ptcache.free_bake", text="Free Bake") - else: - row.item_booleanO("ptcache.bake", "bake", True, text="Bake") - - subrow = row.row() - subrow.enabled = cache.frames_skipped or cache.outdated - subrow.itemO("ptcache.bake", "bake", False, text="Calculate to Current Frame") - - row = layout.row() - #row.enabled = particle_panel_enabled(psys) - row.itemO("ptcache.bake_from_cache", text="Current Cache to Bake") - row.itemR(cache, "step"); - - row = layout.row() - #row.enabled = particle_panel_enabled(psys) - row.itemR(cache, "quick_cache") - row.itemR(cache, "disk_cache") - - layout.itemL(text=cache.info) - - layout.itemS() - - row = layout.row() - row.itemO("ptcache.bake_all", "bake", True, text="Bake All Dynamics") - row.itemO("ptcache.free_bake_all", text="Free All Bakes") - layout.itemO("ptcache.bake_all", "bake", False, text="Update All Dynamics to current frame") + md = context.cloth + point_cache_ui(self, md.point_cache, cloth_panel_enabled(md), 0, 0) class PHYSICS_PT_cloth_collision(PhysicButtonsPanel): __label__ = "Cloth Collision" @@ -143,7 +105,8 @@ class PHYSICS_PT_cloth_collision(PhysicButtonsPanel): def draw_header(self, context): layout = self.layout cloth = context.cloth.collision_settings - + + layout.active = cloth_panel_enabled(context.cloth) layout.itemR(cloth, "enable_collision", text="") def draw(self, context): @@ -151,7 +114,7 @@ class PHYSICS_PT_cloth_collision(PhysicButtonsPanel): cloth = context.cloth.collision_settings split = layout.split() - layout.active = cloth.enable_collision + layout.active = cloth.enable_collision and cloth_panel_enabled(md) col = split.column() col.itemR(cloth, "collision_quality", slider=True, text="Quality") @@ -176,6 +139,7 @@ class PHYSICS_PT_cloth_stiffness(PhysicButtonsPanel): layout = self.layout cloth = context.cloth.settings + layout.active = cloth_panel_enabled(context.cloth) layout.itemR(cloth, "stiffness_scaling", text="") def draw(self, context): @@ -183,7 +147,7 @@ class PHYSICS_PT_cloth_stiffness(PhysicButtonsPanel): ob = context.object cloth = context.cloth.settings - layout.active = cloth.stiffness_scaling + layout.active = cloth.stiffness_scaling and cloth_panel_enabled(md) split = layout.split() diff --git a/release/ui/buttons_physics_smoke.py b/release/ui/buttons_physics_smoke.py index 3cfba0f9df9..d7313632638 100644 --- a/release/ui/buttons_physics_smoke.py +++ b/release/ui/buttons_physics_smoke.py @@ -1,6 +1,8 @@ import bpy +from buttons_particle import point_cache_ui + def smoke_panel_enabled_low(smd): if smd.smoke_type == 'TYPE_DOMAIN': return smd.domain.point_cache.baked==False @@ -139,48 +141,8 @@ class PHYSICS_PT_smoke_cache(PhysicButtonsPanel): domain = md.domain_settings cache = domain.point_cache - layout.set_context_pointer("PointCache", cache) - - row = layout.row() - row.template_list(cache, "point_cache_list", cache, "active_point_cache_index") - col = row.column(align=True) - col.itemO("ptcache.add_new", icon='ICON_ZOOMIN', text="") - col.itemO("ptcache.remove", icon='ICON_ZOOMOUT', text="") - - row = layout.row() - row.itemR(cache, "name") - - row = layout.row() - row.itemR(cache, "start_frame") - row.itemR(cache, "end_frame") - - row = layout.row() - - if cache.baked == True: - row.itemO("ptcache.free_bake", text="Free Bake") - else: - row.item_booleanO("ptcache.bake", "bake", True, text="Bake") - - subrow = row.row() - subrow.enabled = cache.frames_skipped or cache.outdated - subrow.itemO("ptcache.bake", "bake", False, text="Calculate to Current Frame") - - row = layout.row() - #row.enabled = smoke_panel_enabled(psys) - row.itemO("ptcache.bake_from_cache", text="Current Cache to Bake") - - row = layout.row() - #row.enabled = smoke_panel_enabled(psys) - - layout.itemL(text=cache.info) - - layout.itemS() - - row = layout.row() - row.itemO("ptcache.bake_all", "bake", True, text="Bake All Dynamics") - row.itemO("ptcache.free_bake_all", text="Free All Bakes") - layout.itemO("ptcache.bake_all", "bake", False, text="Update All Dynamics to current frame") - + point_cache_ui(self, cache, cache.baked==False, 0, 1) + class PHYSICS_PT_smoke_highres(PhysicButtonsPanel): __label__ = "Smoke High Resolution" __default_closed__ = True diff --git a/release/ui/buttons_physics_softbody.py b/release/ui/buttons_physics_softbody.py index 2beba8c95a0..3d3c3c23faf 100644 --- a/release/ui/buttons_physics_softbody.py +++ b/release/ui/buttons_physics_softbody.py @@ -1,6 +1,11 @@ import bpy +from buttons_particle import point_cache_ui + +def softbody_panel_enabled(md): + return md.point_cache.baked==False + class PhysicButtonsPanel(bpy.types.Panel): __space_type__ = 'PROPERTIES' __region_type__ = 'WINDOW' @@ -41,6 +46,7 @@ class PHYSICS_PT_softbody(PhysicButtonsPanel): # General split = layout.split() + split.enabled = softbody_panel_enabled(md) col = split.column() col.itemL(text="Object:") @@ -60,52 +66,9 @@ class PHYSICS_PT_softbody_cache(PhysicButtonsPanel): return (context.soft_body) def draw(self, context): - layout = self.layout - - cache = context.soft_body.point_cache - layout.set_context_pointer("PointCache", cache) - - row = layout.row() - row.template_list(cache, "point_cache_list", cache, "active_point_cache_index", rows=2) - col = row.column(align=True) - col.itemO("ptcache.add_new", icon='ICON_ZOOMIN', text="") - col.itemO("ptcache.remove", icon='ICON_ZOOMOUT', text="") - - row = layout.row() - row.itemR(cache, "name") - - row = layout.row() - row.itemR(cache, "start_frame") - row.itemR(cache, "end_frame") - - row = layout.row() - - if cache.baked == True: - row.itemO("ptcache.free_bake", text="Free Bake") - else: - row.item_booleanO("ptcache.bake", "bake", True, text="Bake") - - sub = row.row() - sub.enabled = cache.frames_skipped or cache.outdated - sub.itemO("ptcache.bake", "bake", False, text="Calculate to Current Frame") + md = context.soft_body + point_cache_ui(self, md.point_cache, softbody_panel_enabled(md), 0, 0) - row = layout.row() - row.itemO("ptcache.bake_from_cache", text="Current Cache to Bake") - row.itemR(cache, "step"); - - row = layout.row() - row.itemR(cache, "quick_cache") - row.itemR(cache, "disk_cache") - - layout.itemL(text=cache.info) - - layout.itemS() - - row = layout.row() - row.itemO("ptcache.bake_all", "bake", True, text="Bake All Dynamics") - row.itemO("ptcache.free_bake_all", text="Free All Bakes") - layout.itemO("ptcache.bake_all", "bake", False, text="Update All Dynamics to current frame") - class PHYSICS_PT_softbody_goal(PhysicButtonsPanel): __label__ = "Soft Body Goal" @@ -117,6 +80,7 @@ class PHYSICS_PT_softbody_goal(PhysicButtonsPanel): softbody = context.soft_body.settings + layout.active = softbody_panel_enabled(context.soft_body) layout.itemR(softbody, "use_goal", text="") def draw(self, context): @@ -129,7 +93,7 @@ class PHYSICS_PT_softbody_goal(PhysicButtonsPanel): if md: softbody = md.settings - layout.active = softbody.use_goal + layout.active = softbody.use_goal and softbody_panel_enabled(md) # Goal split = layout.split() @@ -159,6 +123,7 @@ class PHYSICS_PT_softbody_edge(PhysicButtonsPanel): softbody = context.soft_body.settings + layout.active = softbody_panel_enabled(context.soft_body) layout.itemR(softbody, "use_edges", text="") def draw(self, context): @@ -170,7 +135,7 @@ class PHYSICS_PT_softbody_edge(PhysicButtonsPanel): if md: softbody = md.settings - layout.active = softbody.use_edges + layout.active = softbody.use_edges and softbody_panel_enabled(md) split = layout.split() @@ -209,6 +174,7 @@ class PHYSICS_PT_softbody_collision(PhysicButtonsPanel): softbody = context.soft_body.settings + layout.active = softbody_panel_enabled(context.soft_body) layout.itemR(softbody, "self_collision", text="") def draw(self, context): @@ -220,7 +186,7 @@ class PHYSICS_PT_softbody_collision(PhysicButtonsPanel): if md: softbody = md.settings - layout.active = softbody.self_collision + layout.active = softbody.self_collision and softbody_panel_enabled(md) layout.itemL(text="Collision Type:") layout.itemR(softbody, "collision_type", expand=True) @@ -245,6 +211,8 @@ class PHYSICS_PT_softbody_solver(PhysicButtonsPanel): if md: softbody = md.settings + + layout.active = softbody_panel_enabled(md) # Solver split = layout.split() diff --git a/release/ui/space_view3d_toolbar.py b/release/ui/space_view3d_toolbar.py index 0e6dc76d49d..517571e1b09 100644 --- a/release/ui/space_view3d_toolbar.py +++ b/release/ui/space_view3d_toolbar.py @@ -362,8 +362,10 @@ class VIEW3D_PT_tools_brush(PaintPanel): col = layout.column(align=True) col.item_enumR(settings, "tool", 'DRAW') col.item_enumR(settings, "tool", 'SOFTEN') - col.item_enumR(settings, "tool", 'CLONE') - col.item_enumR(settings, "tool", 'SMEAR') + if settings.use_projection: + col.item_enumR(settings, "tool", 'CLONE') + else: + col.item_enumR(settings, "tool", 'SMEAR') col = layout.column() col.itemR(brush, "color", text="") @@ -426,9 +428,9 @@ class VIEW3D_PT_tools_brush_stroke(PaintPanel): if not texture_paint: layout.itemR(brush, "smooth_stroke") col = layout.column() - col.active = brush.smooth_stroke - col.itemR(brush, "smooth_stroke_radius", text="Radius", slider=True) - col.itemR(brush, "smooth_stroke_factor", text="Factor", slider=True) + col.itemR(brush, "airbrush") + col.itemR(brush, "anchored") + col.itemR(brush, "rake") layout.itemR(brush, "space") row = layout.row(align=True) @@ -538,22 +540,12 @@ class VIEW3D_PT_tools_vertexpaint(View3DPanel): # col.itemR(vpaint, "mul", text="") -# ********** options for projection paint **************** +# ********** default tools for texturepaint **************** -class VIEW3D_PT_tools_projectpaint(View3DPanel): +class VIEW3D_PT_tools_texturepaint(View3DPanel): __context__ = "texturepaint" - __label__ = "Project Paint" - - def poll(self, context): - return context.tool_settings.image_paint.tool != 'SMEAR' - - def draw_header(self, context): - layout = self.layout - - ipaint = context.tool_settings.image_paint + __label__ = "Options" - layout.itemR(ipaint, "use_projection", text="") - def draw(self, context): layout = self.layout @@ -562,6 +554,7 @@ class VIEW3D_PT_tools_projectpaint(View3DPanel): use_projection= ipaint.use_projection col = layout.column() + col.itemR(ipaint, "use_projection") sub = col.column() sub.active = use_projection sub.itemR(ipaint, "use_occlude") @@ -606,22 +599,58 @@ class VIEW3D_PT_tools_particlemode(View3DPanel): def draw(self, context): layout = self.layout pe = context.tool_settings.particle_edit + ob = pe.object + row = layout.row() + row.itemL(text="Edit:") + row.itemR(pe, "type", text="") + + if pe.type == 'PARTICLES': + if ob.particle_systems: + if len(ob.particle_systems) > 1: + layout.template_list(ob, "particle_systems", ob, "active_particle_system_index", type='ICONS') + + ptcache = ob.particle_systems[ob.active_particle_system_index].point_cache + else: + for md in ob.modifiers: + if md.type==pe.type: + ptcache = md.point_cache + + if ptcache and len(ptcache.point_cache_list) > 1: + layout.template_list(ptcache, "point_cache_list", ptcache, "active_point_cache_index", type='ICONS') + + + if not pe.editable: + layout.itemL(text="Point cache must be baked") + layout.itemL(text="to enable editing!") + col = layout.column(align=True) - col.itemR(pe, "emitter_deflect", text="Deflect") - sub = col.row() - sub.active = pe.emitter_deflect - sub.itemR(pe, "emitter_distance", text="Distance") + if pe.hair: + col.active = pe.editable + col.itemR(pe, "emitter_deflect", text="Deflect emitter") + sub = col.row() + sub.active = pe.emitter_deflect + sub.itemR(pe, "emitter_distance", text="Distance") col = layout.column(align=True) + col.active = pe.editable col.itemL(text="Keep:") col.itemR(pe, "keep_lengths", text="Lenghts") col.itemR(pe, "keep_root", text="Root") + if not pe.hair: + col.itemL(text="Correct:") + col.itemR(pe, "auto_velocity", text="Velocity") col = layout.column(align=True) - col.itemL(text="Display:") - col.itemR(pe, "show_time", text="Time") - col.itemR(pe, "show_children", text="Children") + col.active = pe.editable + col.itemL(text="Draw:") + col.itemR(pe, "draw_step", text="Path Steps") + if pe.type == 'PARTICLES': + col.itemR(pe, "draw_particles", text="Particles") + col.itemR(pe, "fade_time") + sub = col.row() + sub.active = pe.fade_time + sub.itemR(pe, "fade_frames", slider=True) bpy.types.register(VIEW3D_PT_tools_objectmode) bpy.types.register(VIEW3D_PT_tools_meshedit) @@ -638,5 +667,5 @@ bpy.types.register(VIEW3D_PT_tools_brush_curve) bpy.types.register(VIEW3D_PT_sculpt_options) bpy.types.register(VIEW3D_PT_tools_vertexpaint) bpy.types.register(VIEW3D_PT_tools_weightpaint) -bpy.types.register(VIEW3D_PT_tools_projectpaint) +bpy.types.register(VIEW3D_PT_tools_texturepaint) bpy.types.register(VIEW3D_PT_tools_particlemode) diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index cf02efc34ac..e24114cd219 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -109,46 +109,10 @@ typedef struct ParticleCacheKey{ float vel[3]; float rot[4]; float col[3]; + float time; int steps; } ParticleCacheKey; -typedef struct ParticleEditKey{ - float *co; - float *vel; - float *rot; - float *time; - - float world_co[3]; - float length; - short flag; -} ParticleEditKey; - -typedef struct ParticleUndo { - struct ParticleUndo *next, *prev; - struct ParticleEditKey **keys; - struct KDTree *emitter_field; - struct ParticleData *particles; - float *emitter_cosnos; - int totpart, totkeys; - char name[64]; -} ParticleUndo; - -typedef struct ParticleEdit { - ListBase undo; - struct ParticleUndo *curundo; - - ParticleEditKey **keys; - int totkeys; - - int *mirror_cache; - - struct KDTree *emitter_field; - float *emitter_cosnos; - - char sel_col[3]; - char nosel_col[3]; -} ParticleEdit; - typedef struct ParticleThreadContext { /* shared */ struct Scene *scene; @@ -240,7 +204,7 @@ int psys_check_enabled(struct Object *ob, struct ParticleSystem *psys); void psys_free_boid_rules(struct ListBase *list); void psys_free_settings(struct ParticleSettings *part); void free_child_path_cache(struct ParticleSystem *psys); -void psys_free_path_cache(struct ParticleSystem *psys); +void psys_free_path_cache(struct ParticleSystem *psys, struct PTCacheEdit *edit); void free_hair(struct ParticleSystem *psys, int softbody); void free_keyed_keys(struct ParticleSystem *psys); void psys_free(struct Object * ob, struct ParticleSystem * psys); @@ -271,9 +235,9 @@ void psys_reset(struct ParticleSystem *psys, int mode); void psys_find_parents(struct Object *ob, struct ParticleSystemModifierData *psmd, struct ParticleSystem *psys); -void psys_cache_paths(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys, float cfra, int editupdate); +void psys_cache_paths(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys, float cfra); +void psys_cache_edit_paths(struct Scene *scene, struct Object *ob, struct PTCacheEdit *edit, float cfra); void psys_cache_child_paths(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys, float cfra, int editupdate); -void psys_update_world_cos(struct Object *ob, struct ParticleSystem *psys); int do_guide(struct Scene *scene, struct ParticleKey *state, int pa_num, float time, struct ListBase *lb); float psys_get_size(struct Object *ob, struct Material *ma, struct ParticleSystemModifierData *psmd, struct IpoCurve *icu_size, struct ParticleSystem *psys, struct ParticleSettings *part, struct ParticleData *pa, float *vg_size); float psys_get_timestep(struct ParticleSettings *part); @@ -359,12 +323,6 @@ void reset_particle(struct Scene *scene, struct ParticleData *pa, struct Particl #define PSYS_EC_PARTICLE 4 #define PSYS_EC_REACTOR 8 -/* ParticleEditKey->flag */ -#define PEK_SELECT 1 -#define PEK_TO_SELECT 2 -#define PEK_TAG 4 -#define PEK_HIDE 8 - /* index_dmcache */ #define DMCACHE_NOTFOUND -1 #define DMCACHE_ISCHILD -2 diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h index 531487549da..9ba34091064 100644 --- a/source/blender/blenkernel/BKE_pointcache.h +++ b/source/blender/blenkernel/BKE_pointcache.h @@ -101,6 +101,8 @@ typedef struct PTCacheFile { void *cur[BPHYS_TOT_DATA]; } PTCacheFile; +#define PTCACHE_VEL_PER_SEC 1 + typedef struct PTCacheID { struct PTCacheID *next, *prev; @@ -109,6 +111,7 @@ typedef struct PTCacheID { void *calldata; int type; int stack_index; + int flag; /* flags defined in DNA_object_force.h */ unsigned int data_types, info_types; @@ -151,6 +154,75 @@ typedef struct PTCacheBaker { void *progresscontext; } PTCacheBaker; +/* PTCacheEditKey->flag */ +#define PEK_SELECT 1 +#define PEK_TAG 2 +#define PEK_HIDE 4 +#define PEK_USE_WCO 8 + +typedef struct PTCacheEditKey{ + float *co; + float *vel; + float *rot; + float *time; + + float world_co[3]; + float ftime; + float length; + short flag; +} PTCacheEditKey; + +/* PTCacheEditPoint->flag */ +#define PEP_TAG 1 +#define PEP_EDIT_RECALC 2 +#define PEP_TRANSFORM 4 +#define PEP_HIDE 8 + +typedef struct PTCacheEditPoint { + struct PTCacheEditKey *keys; + int totkey; + short flag; +} PTCacheEditPoint; + +typedef struct PTCacheUndo { + struct PTCacheUndo *next, *prev; + struct PTCacheEditPoint *points; + + /* particles stuff */ + struct ParticleData *particles; + struct KDTree *emitter_field; + float *emitter_cosnos; + + /* cache stuff */ + struct ListBase mem_cache; + + int totpoint; + char name[64]; +} PTCacheUndo; + +typedef struct PTCacheEdit { + ListBase undo; + struct PTCacheUndo *curundo; + PTCacheEditPoint *points; + + struct PTCacheID pid; + + /* particles stuff */ + struct ParticleSystem *psys; + struct ParticleData *particles; + struct KDTree *emitter_field; + float *emitter_cosnos; + int *mirror_cache; + + struct ParticleCacheKey **pathcache; /* path cache (runtime) */ + ListBase pathcachebufs; + + int totpoint, totframes, totcached, edited; + + char sel_col[3]; + char nosel_col[3]; +} PTCacheEdit; + /* Particle functions */ void BKE_ptcache_make_particle_key(struct ParticleKey *key, int index, void **data, float time); @@ -179,6 +251,10 @@ void BKE_ptcache_update_info(PTCacheID *pid); /* Size of cache data type. */ int BKE_ptcache_data_size(int data_type); +/* Memory cache read/write helpers. */ +void BKE_ptcache_mem_init_pointers(struct PTCacheMem *pm); +void BKE_ptcache_mem_incr_pointers(struct PTCacheMem *pm); + /* Copy a specific data type from cache data to point data. */ void BKE_ptcache_data_get(void **data, int type, int index, void *to); @@ -197,7 +273,7 @@ int BKE_ptcache_get_continue_physics(void); /******************* Allocate & free ***************/ struct PointCache *BKE_ptcache_add(struct ListBase *ptcaches); -void BKE_ptache_free_mem(struct PointCache *cache); +void BKE_ptcache_free_mem(struct ListBase *mem_cache); void BKE_ptcache_free(struct PointCache *cache); void BKE_ptcache_free_list(struct ListBase *ptcaches); struct PointCache *BKE_ptcache_copy_list(struct ListBase *ptcaches_new, struct ListBase *ptcaches_old); diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index 3acaaecb1e8..eafd9eb01fe 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -347,7 +347,7 @@ void cloth_clear_cache(Object *ob, ClothModifierData *clmd, float framenr) BKE_ptcache_id_from_cloth(&pid, ob, clmd); // don't do anything as long as we're in editmode! - if(pid.cache->flag & PTCACHE_BAKE_EDIT_ACTIVE) + if(pid.cache->edit && ob->mode & OB_MODE_PARTICLE_EDIT) return; BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_AFTER, framenr); diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index e1987d34a6c..18e3512967a 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -321,7 +321,7 @@ int psys_ob_has_hair(Object *ob) } int psys_in_edit_mode(Scene *scene, ParticleSystem *psys) { - return ((scene->basact->object->mode & OB_MODE_PARTICLE_EDIT) && psys==psys_get_current((scene->basact)->object) && psys->edit); + return (scene->basact && (scene->basact->object->mode & OB_MODE_PARTICLE_EDIT) && psys==psys_get_current((scene->basact)->object) && (psys->edit || psys->pointcache->edit)); } int psys_check_enabled(Object *ob, ParticleSystem *psys) { @@ -406,13 +406,20 @@ void free_child_path_cache(ParticleSystem *psys) psys->childcache = NULL; psys->totchildcache = 0; } -void psys_free_path_cache(ParticleSystem *psys) +void psys_free_path_cache(ParticleSystem *psys, PTCacheEdit *edit) { - psys_free_path_cache_buffers(psys->pathcache, &psys->pathcachebufs); - psys->pathcache= NULL; - psys->totcached= 0; + if(edit) { + psys_free_path_cache_buffers(edit->pathcache, &edit->pathcachebufs); + edit->pathcache= NULL; + edit->totcached= 0; + } + else { + psys_free_path_cache_buffers(psys->pathcache, &psys->pathcachebufs); + psys->pathcache= NULL; + psys->totcached= 0; - free_child_path_cache(psys); + free_child_path_cache(psys); + } } void psys_free_children(ParticleSystem *psys) { @@ -431,14 +438,14 @@ void psys_free(Object *ob, ParticleSystem * psys) int nr = 0; ParticleSystem * tpsys; - psys_free_path_cache(psys); + psys_free_path_cache(psys, NULL); free_hair(psys, 1); free_keyed_keys(psys); if(psys->edit && psys->free_edit) - psys->free_edit(psys); + psys->free_edit(psys->edit); if(psys->particles){ if(psys->particles->boid) @@ -645,7 +652,7 @@ void psys_render_restore(Object *ob, ParticleSystem *psys) psmd->dm->release(psmd->dm); } - psys_free_path_cache(psys); + psys_free_path_cache(psys, NULL); if(psys->child){ MEM_freeN(psys->child); @@ -953,17 +960,25 @@ void psys_interpolate_particle(short type, ParticleKey keys[4], float dt, Partic typedef struct ParticleInterpolationData { - ParticleKey *kkey[2]; HairKey *hkey[2]; - BodyPoint *bp[2]; + + int keyed; + ParticleKey *kkey[2]; + SoftBody *soft; - int keyed, cached; + BodyPoint *bp[2]; + + PointCache *cache; + + PTCacheEditPoint *epoint; + PTCacheEditKey *ekey[2]; + float birthtime, dietime; + int bspline; } ParticleInterpolationData; /* Assumes pointcache->mem_cache exists, so for disk cached particles call psys_make_temp_pointcache() before use */ -static void get_pointcache_keys_for_time(Object *ob, ParticleSystem *psys, int index, float t, ParticleKey *key1, ParticleKey *key2) +static void get_pointcache_keys_for_time(Object *ob, PointCache *cache, int index, float t, ParticleKey *key1, ParticleKey *key2) { - PointCache *cache = psys->pointcache; static PTCacheMem *pm = NULL; /* not thread safe */ if(index < 0) { /* initialize */ @@ -990,22 +1005,27 @@ static void get_pointcache_keys_for_time(Object *ob, ParticleSystem *psys, int i static void init_particle_interpolation(Object *ob, ParticleSystem *psys, ParticleData *pa, ParticleInterpolationData *pind) { - if(pind->keyed) { - pind->kkey[0] = pa->keys; + if(pind->epoint) { + PTCacheEditPoint *point = pind->epoint; - if(pa->totkey > 1) - pind->kkey[1] = pa->keys + 1; - else - pind->kkey[1] = NULL; + pind->ekey[0] = point->keys; + pind->ekey[1] = point->totkey > 1 ? point->keys + 1 : NULL; + + pind->birthtime = *(point->keys->time); + pind->dietime = *((point->keys + point->totkey - 1)->time); + } + else if(pind->keyed) { + pind->kkey[0] = pa->keys; + pind->kkey[1] = pa->totkey > 1 ? pa->keys + 1 : NULL; pind->birthtime = pa->keys->time; pind->dietime = (pa->keys + pa->totkey - 1)->time; } - else if(pind->cached) { - get_pointcache_keys_for_time(ob, psys, -1, 0.0f, NULL, NULL); + else if(pind->cache) { + get_pointcache_keys_for_time(ob, pind->cache, -1, 0.0f, NULL, NULL); - pind->birthtime = pa->time; - pind->dietime = pa->dietime; + pind->birthtime = pa ? pa->time : pind->cache->startframe; + pind->dietime = pa ? pa->dietime : pind->cache->endframe; } else { pind->hkey[0] = pa->hair; @@ -1020,6 +1040,14 @@ static void init_particle_interpolation(Object *ob, ParticleSystem *psys, Partic pind->bp[1] = pind->soft->bpoint + pa->bpi + 1; } } +static void edit_to_particle(ParticleKey *key, PTCacheEditKey *ekey) +{ + VECCOPY(key->co, ekey->co); + if(ekey->vel) { + VECCOPY(key->vel, ekey->vel); + } + key->time = *(ekey->time); +} static void hair_to_particle(ParticleKey *key, HairKey *hkey) { VECCOPY(key->co, hkey->co); @@ -1033,11 +1061,24 @@ static void bp_to_particle(ParticleKey *key, BodyPoint *bp, HairKey *hkey) static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData *pa, float t, float frs_sec, ParticleInterpolationData *pind, ParticleKey *result) { + PTCacheEditPoint *point = pind->epoint; ParticleKey keys[4]; + int point_vel = (point && point->keys->vel); float real_t, dfra, keytime; /* interpret timing and find keys */ - if(pind->keyed) { + if(point) { + if(result->time < 0.0f) + real_t = -result->time; + else + real_t = *(pind->ekey[0]->time) + t * (*(pind->ekey[0][point->totkey-1].time) - *(pind->ekey[0]->time)); + + while(*(pind->ekey[1]->time) < real_t) + pind->ekey[1]++; + + pind->ekey[0] = pind->ekey[1] - 1; + } + else if(pind->keyed) { /* we have only one key, so let's use that */ if(pind->kkey[1]==NULL) { copy_particle_key(result, pind->kkey[0], 1); @@ -1074,7 +1115,7 @@ static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData pind->kkey[0] = pind->kkey[1] - 1; } - else if(pind->cached) { + else if(pind->cache) { if(result->time < 0.0f) /* flag for time in frames */ real_t = -result->time; else @@ -1095,7 +1136,11 @@ static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData } /* set actual interpolation keys */ - if(pind->soft) { + if(point) { + edit_to_particle(keys + 1, pind->ekey[0]); + edit_to_particle(keys + 2, pind->ekey[1]); + } + else if(pind->soft) { pind->bp[0] = pind->bp[1] - 1; bp_to_particle(keys + 1, pind->bp[0], pind->hkey[0]); bp_to_particle(keys + 2, pind->bp[1], pind->hkey[1]); @@ -1104,8 +1149,8 @@ static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData memcpy(keys + 1, pind->kkey[0], sizeof(ParticleKey)); memcpy(keys + 2, pind->kkey[1], sizeof(ParticleKey)); } - else if(pind->cached) { - get_pointcache_keys_for_time(NULL, psys, p, real_t, keys+1, keys+2); + else if(pind->cache) { + get_pointcache_keys_for_time(NULL, pind->cache, p, real_t, keys+1, keys+2); } else { hair_to_particle(keys + 1, pind->hkey[0]); @@ -1113,8 +1158,14 @@ static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData } /* set secondary interpolation keys for hair */ - if(!pind->keyed && !pind->cached) { - if(pind->soft) { + if(!pind->keyed && !pind->cache && !point_vel) { + if(point) { + if(pind->ekey[0] != point->keys) + edit_to_particle(keys, pind->ekey[0] - 1); + else + edit_to_particle(keys, pind->ekey[0]); + } + else if(pind->soft) { if(pind->hkey[0] != pa->hair) bp_to_particle(keys, pind->bp[0] - 1, pind->hkey[0] - 1); else @@ -1127,7 +1178,13 @@ static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData hair_to_particle(keys, pind->hkey[0]); } - if(pind->soft) { + if(point) { + if(pind->ekey[1] != point->keys + point->totkey - 1) + edit_to_particle(keys + 3, pind->ekey[1] + 1); + else + edit_to_particle(keys + 3, pind->ekey[1]); + } + else if(pind->soft) { if(pind->hkey[1] != pa->hair + pa->totkey - 1) bp_to_particle(keys + 3, pind->bp[1] + 1, pind->hkey[1] + 1); else @@ -1145,19 +1202,19 @@ static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData keytime = (real_t - keys[1].time) / dfra; /* convert velocity to timestep size */ - if(pind->keyed || pind->cached){ + if(pind->keyed || pind->cache || point_vel){ VecMulf(keys[1].vel, dfra / frs_sec); VecMulf(keys[2].vel, dfra / frs_sec); QuatInterpol(result->rot,keys[1].rot,keys[2].rot,keytime); } /* now we should have in chronologiacl order k1<=k2<=t<=k3<=k4 with keytime between [0,1]->[k2,k3] (k1 & k4 used for cardinal & bspline interpolation)*/ - psys_interpolate_particle((pind->keyed || pind->cached) ? -1 /* signal for cubic interpolation */ - : ((psys->part->flag & PART_HAIR_BSPLINE) ? KEY_BSPLINE : KEY_CARDINAL) + psys_interpolate_particle((pind->keyed || pind->cache || point_vel) ? -1 /* signal for cubic interpolation */ + : (pind->bspline ? KEY_BSPLINE : KEY_CARDINAL) ,keys, keytime, result, 1); /* the velocity needs to be converted back from cubic interpolation */ - if(pind->keyed || pind->cached) + if(pind->keyed || pind->cache || point_vel) VecMulf(result->vel, frs_sec / dfra); } /************************************************/ @@ -1610,7 +1667,7 @@ ParticleSystemModifierData *psys_get_modifier(Object *ob, ParticleSystem *psys) } } } - return 0; + return NULL; } /************************************************/ /* Particles on a shape */ @@ -2129,7 +2186,7 @@ int psys_threads_init_path(ParticleThread *threads, Scene *scene, float cfra, in /*---start figuring out what is actually wanted---*/ if(psys_in_edit_mode(scene, psys)) - if(psys->renderdata==0 && (psys->edit==NULL || pset->flag & PE_SHOW_CHILD)==0) + if(psys->renderdata==0 && (psys->edit==NULL || pset->flag & PE_DRAW_PART)==0) totchild=0; if(totchild && part->from!=PART_FROM_PARTICLE && part->childtype==PART_CHILD_FACES){ @@ -2245,7 +2302,7 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, needupdate= 0; w= 0; while(w<4 && cpa->pa[w]>=0) { - if(psys->particles[cpa->pa[w]].flag & PARS_EDIT_RECALC) { + if(psys->edit->points[cpa->pa[w]].flag & PEP_EDIT_RECALC) { needupdate= 1; break; } @@ -2288,7 +2345,7 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, } else{ if(ctx->editupdate && !(part->flag & PART_BRANCHING)) { - if(!(psys->particles[cpa->parent].flag & PARS_EDIT_RECALC)) + if(!(psys->edit->points[cpa->parent].flag & PEP_EDIT_RECALC)) return; memset(keys, 0, sizeof(*keys)*(ctx->steps+1)); @@ -2557,24 +2614,20 @@ void psys_cache_child_paths(Scene *scene, Object *ob, ParticleSystem *psys, floa /* -Usefull for making use of opengl vertex arrays for super fast strand drawing. */ /* -Makes child strands possible and creates them too into the cache. */ /* -Cached path data is also used to determine cut position for the editmode tool. */ -void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra, int editupdate) +void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra) { - ParticleCacheKey *ca, **cache=psys->pathcache; + ParticleCacheKey *ca, **cache= psys->pathcache; ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys); - ParticleEditSettings *pset = &scene->toolsettings->particle; ParticleSettings *part = psys->part; + ParticleEditSettings *pset = &scene->toolsettings->particle; - ParticleData *pa; + ParticleData *pa = psys->particles; ParticleKey result; - ParticleEdit *edit = 0; - ParticleEditKey *ekey = 0; - - SoftBody *soft = 0; + SoftBody *soft = NULL; BodyPoint *bp[2] = {NULL, NULL}; Material *ma; - ParticleInterpolationData pind; float birthtime = 0.0, dietime = 0.0; @@ -2583,132 +2636,98 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra float prev_tangent[3], hairmat[4][4]; float rotmat[3][3]; int k,i; - int steps = (int)pow(2.0, (double)psys->part->draw_step); + int steps = (int)pow(2.0, (double)(psys->renderdata ? part->ren_step : part->draw_step)); int totpart = psys->totpart; - float sel_col[3]; - float nosel_col[3]; float length, vec[3]; float *vg_effector= NULL, effector=0.0f; float *vg_length= NULL, pa_length=1.0f; int keyed, baked; /* we don't have anything valid to create paths from so let's quit here */ - if((psys->flag & PSYS_HAIR_DONE)==0 && (psys->flag & PSYS_KEYED)==0 && (psys->pointcache->flag & PTCACHE_BAKED)==0) + if(!(psys->flag & PSYS_HAIR_DONE) && !(psys->flag & PSYS_KEYED) && !(psys->pointcache->flag & PTCACHE_BAKED)) return; + if(psys_in_edit_mode(scene, psys)) + if(psys->renderdata==0 && (psys->edit==NULL || pset->flag & PE_DRAW_PART)==0) + return; + BLI_srandom(psys->seed); keyed = psys->flag & PSYS_KEYED; baked = psys->pointcache->flag & PTCACHE_BAKED; - if(psys->renderdata) { - steps = (int)pow(2.0, (double)psys->part->ren_step); - } - else if(psys_in_edit_mode(scene, psys)) { - edit=psys->edit; - - //timed = edit->draw_timed; - - if(pset->brushtype == PE_BRUSH_WEIGHT) { - sel_col[0] = sel_col[1] = sel_col[2] = 1.0f; - nosel_col[0] = nosel_col[1] = nosel_col[2] = 0.0f; - } - else{ - sel_col[0] = (float)edit->sel_col[0] / 255.0f; - sel_col[1] = (float)edit->sel_col[1] / 255.0f; - sel_col[2] = (float)edit->sel_col[2] / 255.0f; - nosel_col[0] = (float)edit->nosel_col[0] / 255.0f; - nosel_col[1] = (float)edit->nosel_col[1] / 255.0f; - nosel_col[2] = (float)edit->nosel_col[2] / 255.0f; - } - } - - if(editupdate && psys->pathcache && totpart == psys->totcached) { - cache = psys->pathcache; - } - else { - /* clear out old and create new empty path cache */ - psys_free_path_cache(psys); - cache= psys_alloc_path_cache_buffers(&psys->pathcachebufs, totpart, steps+1); - psys->pathcache= cache; - } + /* clear out old and create new empty path cache */ + psys_free_path_cache(psys, NULL); + cache= psys->pathcache= psys_alloc_path_cache_buffers(&psys->pathcachebufs, totpart, steps+1); - if(edit==NULL && psys->soft && psys->softflag & OB_SB_ENABLE) { + if(psys->soft && psys->softflag & OB_SB_ENABLE) { soft = psys->soft; if(!soft->bpoint) soft= NULL; } - + psys->lattice = psys_get_lattice(scene, ob, psys); ma= give_current_material(ob, psys->part->omat); if(ma && (psys->part->draw & PART_DRAW_MAT_COL)) VECCOPY(col, &ma->r) - + if(psys->part->from!=PART_FROM_PARTICLE) { if(!(psys->part->flag & PART_CHILD_EFFECT)) vg_effector = psys_cache_vgroup(psmd->dm, psys, PSYS_VG_EFFECTOR); - if(!edit && !psys->totchild) + if(!psys->totchild) vg_length = psys_cache_vgroup(psmd->dm, psys, PSYS_VG_LENGTH); } /*---first main loop: create all actual particles' paths---*/ - for(i=0,pa=psys->particles; i<totpart; i++, pa++){ - if(psys && edit==NULL && (pa->flag & PARS_NO_DISP || pa->flag & PARS_UNEXIST)) { + for(i=0; i<totpart; i++, pa++){ + if(pa->flag & PARS_NO_DISP || pa->flag & PARS_UNEXIST) { if(soft) bp[0] += pa->totkey; /* TODO use of initialized value? */ continue; } - if(editupdate && !(pa->flag & PARS_EDIT_RECALC)) continue; - else memset(cache[i], 0, sizeof(*cache[i])*(steps+1)); - - if(!edit && !psys->totchild) { + if(!psys->totchild) { pa_length = 1.0f - part->randlength * 0.5 * (1.0f + pa->r_ave[0]); if(vg_length) pa_length *= psys_particle_value_from_verts(psmd->dm,part->from,pa,vg_length); } - cache[i]->steps = steps; + pind.keyed = keyed; + pind.cache = baked ? psys->pointcache : NULL; + pind.soft = soft; + pind.epoint = NULL; + pind.bspline = (psys->part->flag & PART_HAIR_BSPLINE); + + memset(cache[i], 0, sizeof(*cache[i])*(steps+1)); - if(edit) - ekey = edit->keys[i]; + cache[i]->steps = steps; /*--get the first data points--*/ - pind.keyed = keyed; - pind.cached = baked; - pind.soft = soft; init_particle_interpolation(ob, psys, pa, &pind); - /* hairmat is needed for for non-hair particle too so we get proper rotations */ psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat); VECCOPY(rotmat[0], hairmat[2]); VECCOPY(rotmat[1], hairmat[1]); VECCOPY(rotmat[2], hairmat[0]); - if(!edit) { - if(part->draw & PART_ABS_PATH_TIME) { - birthtime = MAX2(pind.birthtime, part->path_start); - dietime = MIN2(pind.dietime, part->path_end); - } - else { - float tb = pind.birthtime; - birthtime = tb + part->path_start * (pind.dietime - tb); - dietime = tb + part->path_end * (pind.dietime - tb); - } - - if(birthtime >= dietime) { - cache[i]->steps = -1; - continue; - } + if(part->draw & PART_ABS_PATH_TIME) { + birthtime = MAX2(pind.birthtime, part->path_start); + dietime = MIN2(pind.dietime, part->path_end); + } + else { + float tb = pind.birthtime; + birthtime = tb + part->path_start * (pind.dietime - tb); + dietime = tb + part->path_end * (pind.dietime - tb); + } - dietime = birthtime + pa_length * (dietime - birthtime); + if(birthtime >= dietime) { + cache[i]->steps = -1; + continue; } - else - /* XXX brecht: don't know if this code from 2.4 is correct - * still, but makes hair appear again in particle mode */ - dietime= pind.hkey[0][pa->totkey-1].time; + + dietime = birthtime + pa_length * (dietime - birthtime); /*--interpolate actual path from data points--*/ for(k=0, ca=cache[i]; k<=steps; k++, ca++){ @@ -2726,40 +2745,8 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra } VECCOPY(ca->co, result.co); - - /* selection coloring in edit mode */ - if(edit){ - if(pset->brushtype==PE_BRUSH_WEIGHT){ - if(k==steps) - VecLerpf(ca->col, nosel_col, sel_col, pind.hkey[0]->weight); - else - VecLerpf(ca->col, nosel_col, sel_col, - (1.0f - keytime) * pind.hkey[0]->weight + keytime * pind.hkey[1]->weight); - } - else{ - if((ekey + (pind.hkey[0] - pa->hair))->flag & PEK_SELECT){ - if((ekey + (pind.hkey[1] - pa->hair))->flag & PEK_SELECT){ - VECCOPY(ca->col, sel_col); - } - else{ - VecLerpf(ca->col, sel_col, nosel_col, keytime); - } - } - else{ - if((ekey + (pind.hkey[1] - pa->hair))->flag & PEK_SELECT){ - VecLerpf(ca->col, nosel_col, sel_col, keytime); - } - else{ - VECCOPY(ca->col, nosel_col); - } - } - } - } - else{ - VECCOPY(ca->col, col); - } + VECCOPY(ca->col, col); } - /*--modify paths and calculate rotation & velocity--*/ @@ -2772,16 +2759,16 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra for(k=0, ca=cache[i]; k<=steps; k++, ca++) { /* apply effectors */ - if(!(psys->part->flag & PART_CHILD_EFFECT) && edit==0 && k) + if(!(psys->part->flag & PART_CHILD_EFFECT) && k) do_path_effectors(scene, ob, psys, i, ca, k, steps, cache[i]->co, effector, dfra, cfra, &length, vec); /* apply guide curves to path data */ - if(edit==0 && psys->effectors.first && (psys->part->flag & PART_CHILD_EFFECT)==0) + if(psys->effectors.first && (psys->part->flag & PART_CHILD_EFFECT)==0) /* ca is safe to cast, since only co and vel are used */ do_guide(scene, (ParticleKey*)ca, i, (float)k/(float)steps, &psys->effectors); /* apply lattice */ - if(psys->lattice && edit==0) + if(psys->lattice) calc_latt_deform(psys->lattice, ca->co, 1.0f); /* figure out rotation */ @@ -2810,8 +2797,8 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra cosangle= Inpf(tangent, prev_tangent); /* note we do the comparison on cosangle instead of - * angle, since floating point accuracy makes it give - * different results across platforms */ + * angle, since floating point accuracy makes it give + * different results across platforms */ if(cosangle > 0.999999f) { QUATCOPY((ca - 1)->rot, (ca - 2)->rot); } @@ -2856,6 +2843,124 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra if(vg_length) MEM_freeN(vg_length); } +void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cfra) +{ + ParticleCacheKey *ca, **cache= edit->pathcache; + ParticleEditSettings *pset = &scene->toolsettings->particle; + + PTCacheEditPoint *point = edit->points; + PTCacheEditKey *ekey = NULL; + + ParticleSystem *psys = edit->psys; + ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys); + ParticleSettings *part = psys ? psys->part : NULL; + ParticleData *pa = psys ? psys->particles : NULL; + + ParticleInterpolationData pind; + ParticleKey result; + + float birthtime = 0.0, dietime = 0.0; + float t, time = 0.0, keytime = 0.0, dfra = 1.0, frs_sec; + float hairmat[4][4]; + int k,i; + int steps = (int)pow(2.0, (double)pset->draw_step); + int totpart = edit->totpoint; + float sel_col[3]; + float nosel_col[3]; + + steps = MAX2(steps, 4); + + if(!cache || edit->totpoint != edit->totcached) { + /* clear out old and create new empty path cache */ + psys_free_path_cache(NULL, edit); + cache= edit->pathcache= psys_alloc_path_cache_buffers(&edit->pathcachebufs, totpart, steps+1); + } + + frs_sec = (psys || edit->pid.flag & PTCACHE_VEL_PER_SEC) ? 25.0f : 1.0f; + + sel_col[0] = (float)edit->sel_col[0] / 255.0f; + sel_col[1] = (float)edit->sel_col[1] / 255.0f; + sel_col[2] = (float)edit->sel_col[2] / 255.0f; + nosel_col[0] = (float)edit->nosel_col[0] / 255.0f; + nosel_col[1] = (float)edit->nosel_col[1] / 255.0f; + nosel_col[2] = (float)edit->nosel_col[2] / 255.0f; + + /*---first main loop: create all actual particles' paths---*/ + for(i=0; i<totpart; i++, pa+=pa?1:0, point++){ + if(edit->totcached && !(point->flag & PEP_EDIT_RECALC)) + continue; + + ekey = point->keys; + + pind.keyed = 0; + pind.cache = NULL; + pind.soft = NULL; + pind.epoint = point; + pind.bspline = psys ? (psys->part->flag & PART_HAIR_BSPLINE) : 0; + + memset(cache[i], 0, sizeof(*cache[i])*(steps+1)); + + cache[i]->steps = steps; + + /*--get the first data points--*/ + init_particle_interpolation(ob, psys, pa, &pind); + + if(psys) + psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat); + + birthtime = pind.birthtime; + dietime = pind.dietime; + + if(birthtime >= dietime) { + cache[i]->steps = -1; + continue; + } + + /*--interpolate actual path from data points--*/ + for(k=0, ca=cache[i]; k<=steps; k++, ca++){ + time = (float)k / (float)steps; + + t = birthtime + time * (dietime - birthtime); + + result.time = -t; + + do_particle_interpolation(psys, i, pa, t, frs_sec, &pind, &result); + + /* non-hair points are allready in global space */ + if(psys) + Mat4MulVecfl(hairmat, result.co); + + VECCOPY(ca->co, result.co); + + ca->vel[0] = ca->vel[1] = 0.0f; + ca->vel[1] = 1.0f; + + /* selection coloring in edit mode */ + if((ekey + (pind.ekey[0] - point->keys))->flag & PEK_SELECT){ + if((ekey + (pind.ekey[1] - point->keys))->flag & PEK_SELECT){ + VECCOPY(ca->col, sel_col); + } + else{ + keytime = (t - (*pind.ekey[0]->time))/((*pind.ekey[1]->time) - (*pind.ekey[0]->time)); + VecLerpf(ca->col, sel_col, nosel_col, keytime); + } + } + else{ + if((ekey + (pind.ekey[1] - point->keys))->flag & PEK_SELECT){ + keytime = (t - (*pind.ekey[0]->time))/((*pind.ekey[1]->time) - (*pind.ekey[0]->time)); + VecLerpf(ca->col, nosel_col, sel_col, keytime); + } + else{ + VECCOPY(ca->col, nosel_col); + } + } + + ca->time = t; + } + } + + edit->totcached = totpart; +} /************************************************/ /* Particle Key handling */ /************************************************/ @@ -3663,8 +3768,9 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i } pind.keyed = keyed; - pind.cached = cached; + pind.cache = cached ? psys->pointcache : NULL; pind.soft = NULL; + pind.epoint = NULL; init_particle_interpolation(ob, psys, pa, &pind); do_particle_interpolation(psys, p, pa, t, frs_sec, &pind, state); diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index bf642a14a49..0f72c1c5866 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -127,7 +127,7 @@ void psys_reset(ParticleSystem *psys, int mode) int i; if(ELEM(mode, PSYS_RESET_ALL, PSYS_RESET_DEPSGRAPH)) { - if(mode == PSYS_RESET_ALL || !(part->type == PART_HAIR && (psys->flag & PSYS_EDITED))) { + if(mode == PSYS_RESET_ALL || !(part->type == PART_HAIR && (psys->edit && psys->edit->edited))) { if(psys->particles) { if(psys->particles->keys) MEM_freeN(psys->particles->keys); @@ -145,6 +145,12 @@ void psys_reset(ParticleSystem *psys, int mode) if(psys->reactevents.first) BLI_freelistN(&psys->reactevents); + + if(psys->edit && psys->free_edit) { + psys->free_edit(psys->edit); + psys->edit = NULL; + psys->free_edit = NULL; + } } } else if(mode == PSYS_RESET_CACHE_MISS) { @@ -165,7 +171,7 @@ void psys_reset(ParticleSystem *psys, int mode) psys->totchild= 0; /* reset path cache */ - psys_free_path_cache(psys); + psys_free_path_cache(psys, NULL); /* reset point cache */ psys->pointcache->flag &= ~PTCACHE_SIMULATION_VALID; @@ -2274,7 +2280,7 @@ void psys_clear_temp_pointcache(ParticleSystem *psys) if((psys->pointcache->flag & PTCACHE_DISK_CACHE)==0) return; - BKE_ptache_free_mem(psys->pointcache); + BKE_ptcache_free_mem(&psys->pointcache->mem_cache); } void psys_get_pointcache_start_end(Scene *scene, ParticleSystem *psys, int *sfra, int *efra) { @@ -3747,41 +3753,17 @@ static void psys_update_path_cache(Scene *scene, Object *ob, ParticleSystemModif if((part->type==PART_HAIR || psys->flag&PSYS_KEYED || psys->pointcache->flag & PTCACHE_BAKED) && ( psys_in_edit_mode(scene, psys) || (part->type==PART_HAIR || (part->ren_as == PART_DRAW_PATH && (part->draw_as == PART_DRAW_REND || psys->renderdata))))){ - psys_cache_paths(scene, ob, psys, cfra, 0); + psys_cache_paths(scene, ob, psys, cfra); /* for render, child particle paths are computed on the fly */ if(part->childtype) { - if(((psys->totchild!=0)) || (psys_in_edit_mode(scene, psys) && (pset->flag&PE_SHOW_CHILD))) + if(((psys->totchild!=0)) || (psys_in_edit_mode(scene, psys) && (pset->flag&PE_DRAW_PART))) if(!(psys->part->type == PART_HAIR) || (psys->flag & PSYS_HAIR_DONE)) psys_cache_child_paths(scene, ob, psys, cfra, 0); } } else if(psys->pathcache) - psys_free_path_cache(psys); -} - -/* calculate and store key locations in world coordinates */ -void psys_update_world_cos(Object *ob, ParticleSystem *psys) -{ - ParticleSystemModifierData *psmd= psys_get_modifier(ob, psys); - ParticleData *pa; - ParticleEditKey *key; - int i, k, totpart; - float hairmat[4][4]; - - if(psys==0 || psys->edit==0) - return; - - totpart= psys->totpart; - - for(i=0, pa=psys->particles; i<totpart; i++, pa++) { - psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat); - - for(k=0, key=psys->edit->keys[i]; k<pa->totkey; k++, key++) { - VECCOPY(key->world_co,key->co); - Mat4MulVecfl(hairmat, key->world_co); - } - } + psys_free_path_cache(psys, NULL); } static void hair_step(Scene *scene, Object *ob, ParticleSystemModifierData *psmd, ParticleSystem *psys, float cfra) @@ -3808,9 +3790,6 @@ static void hair_step(Scene *scene, Object *ob, ParticleSystemModifierData *psmd psys_init_effectors(scene, ob, part->eff_group, psys); if(psys->effectors.first) precalc_effectors(scene, ob,psys,psmd,cfra); - - if(psys_in_edit_mode(scene, psys)) - psys_update_world_cos(ob, psys); psys_update_path_cache(scene, ob,psmd,psys,cfra); } @@ -4339,7 +4318,7 @@ static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, Particle psys_update_path_cache(scene, ob, psmd, psys,(int)cfra); } else if(psys->pathcache) - psys_free_path_cache(psys); + psys_free_path_cache(psys, NULL); /* cleanup */ if(vg_vel) MEM_freeN(vg_vel); @@ -4385,7 +4364,7 @@ static void psys_to_softbody(Scene *scene, Object *ob, ParticleSystem *psys) static int hair_needs_recalc(ParticleSystem *psys) { - if((psys->flag & PSYS_EDITED)==0 && + if((!psys->edit || !psys->edit->edited) && ((psys->flag & PSYS_HAIR_DONE)==0 || psys->recalc & PSYS_RECALC_RESET)) { return 1; } diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index 69da8f19d8c..c0223d1690c 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -434,6 +434,8 @@ void BKE_ptcache_id_from_particles(PTCacheID *pid, Object *ob, ParticleSystem *p pid->cache_ptr= &psys->pointcache; pid->ptcaches= &psys->ptcaches; + pid->flag |= PTCACHE_VEL_PER_SEC; + pid->write_elem= ptcache_write_particle; pid->write_stream = NULL; pid->read_stream = NULL; @@ -800,14 +802,16 @@ void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob) } for(psys=ob->particlesystem.first; psys; psys=psys->next) { - pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID"); - BKE_ptcache_id_from_particles(pid, ob, psys); - BLI_addtail(lb, pid); - - if(psys->soft) { + if(psys->part) { pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID"); - BKE_ptcache_id_from_softbody(pid, ob, psys->soft); + BKE_ptcache_id_from_particles(pid, ob, psys); BLI_addtail(lb, pid); + + if(psys->soft) { + pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID"); + BKE_ptcache_id_from_softbody(pid, ob, psys->soft); + BLI_addtail(lb, pid); + } } } @@ -1087,7 +1091,7 @@ static void ptcache_file_init_pointers(PTCacheFile *pf) pf->cur[BPHYS_DATA_BOIDS] = data_types & (1<<BPHYS_DATA_BOIDS) ? &pf->data.boids : NULL; } -static void ptcache_mem_init_pointers(PTCacheMem *pm) +void BKE_ptcache_mem_init_pointers(PTCacheMem *pm) { int data_types = pm->data_types; int i; @@ -1096,7 +1100,7 @@ static void ptcache_mem_init_pointers(PTCacheMem *pm) pm->cur[i] = data_types & (1<<i) ? pm->data[i] : NULL; } -static void ptcache_mem_incr_pointers(PTCacheMem *pm) +void BKE_ptcache_mem_incr_pointers(PTCacheMem *pm) { int i; @@ -1249,12 +1253,12 @@ int BKE_ptcache_read_cache(PTCacheID *pid, float cfra, float frs_sec) return 0; if(pm) { - ptcache_mem_init_pointers(pm); + BKE_ptcache_mem_init_pointers(pm); totpoint = pm->totpoint; index = pm->data_types & (1<<BPHYS_DATA_INDEX) ? pm->cur[BPHYS_DATA_INDEX] : &i; } if(pm2) { - ptcache_mem_init_pointers(pm2); + BKE_ptcache_mem_init_pointers(pm2); totpoint2 = pm2->totpoint; index2 = pm2->data_types & (1<<BPHYS_DATA_INDEX) ? pm2->cur[BPHYS_DATA_INDEX] : &i; } @@ -1336,7 +1340,7 @@ int BKE_ptcache_read_cache(PTCacheID *pid, float cfra, float frs_sec) } if(pm) { - ptcache_mem_incr_pointers(pm); + BKE_ptcache_mem_incr_pointers(pm); index = pm->data_types & (1<<BPHYS_DATA_INDEX) ? pm->cur[BPHYS_DATA_INDEX] : &i; } } @@ -1387,7 +1391,7 @@ int BKE_ptcache_read_cache(PTCacheID *pid, float cfra, float frs_sec) } if(pm2) { - ptcache_mem_incr_pointers(pm2); + BKE_ptcache_mem_incr_pointers(pm2); index2 = pm2->data_types & (1<<BPHYS_DATA_INDEX) ? pm2->cur[BPHYS_DATA_INDEX] : &i; } } @@ -1559,11 +1563,11 @@ int BKE_ptcache_write_cache(PTCacheID *pid, int cfra) pm->data_types = cfra ? pid->data_types : pid->info_types; ptcache_alloc_data(pm); - ptcache_mem_init_pointers(pm); + BKE_ptcache_mem_init_pointers(pm); for(i=0; i<totpoint; i++) { if(pid->write_elem && pid->write_elem(i, pid->calldata, pm->cur)) - ptcache_mem_incr_pointers(pm); + BKE_ptcache_mem_incr_pointers(pm); } //ptcache_make_index_array(pm, pid->totpoint(pid->calldata)); @@ -1664,6 +1668,8 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, int cfra) PTCacheMem *pm= pid->cache->mem_cache.first; PTCacheMem *link= NULL; + pm= pid->cache->mem_cache.first; + if(mode == PTCACHE_CLEAR_ALL) { pid->cache->last_exact = 0; for(; pm; pm=pm->next) @@ -1863,7 +1869,7 @@ int BKE_ptcache_object_reset(Scene *scene, Object *ob, int mode) else if(psys->recalc & PSYS_RECALC_REDO || psys->recalc & PSYS_RECALC_CHILD) skip = 1; - if(skip == 0) { + if(skip == 0 && psys->part) { BKE_ptcache_id_from_particles(&pid, ob, psys); reset |= BKE_ptcache_id_reset(scene, &pid, mode); } @@ -1968,9 +1974,9 @@ PointCache *BKE_ptcache_add(ListBase *ptcaches) return cache; } -void BKE_ptache_free_mem(PointCache *cache) +void BKE_ptcache_free_mem(ListBase *mem_cache) { - PTCacheMem *pm = cache->mem_cache.first; + PTCacheMem *pm = mem_cache->first; if(pm) { for(; pm; pm=pm->next) { @@ -1979,22 +1985,25 @@ void BKE_ptache_free_mem(PointCache *cache) MEM_freeN(pm->index_array); } - BLI_freelistN(&cache->mem_cache); + BLI_freelistN(mem_cache); } } void BKE_ptcache_free(PointCache *cache) { - BKE_ptache_free_mem(cache); + BKE_ptcache_free_mem(&cache->mem_cache); + if(cache->edit && cache->free_edit) + cache->free_edit(cache->edit); MEM_freeN(cache); } void BKE_ptcache_free_list(ListBase *ptcaches) { PointCache *cache = ptcaches->first; - for(; cache; cache=cache->next) - BKE_ptache_free_mem(cache); - - BLI_freelistN(ptcaches); + while(cache) { + BLI_remlink(ptcaches, cache); + BKE_ptcache_free(cache); + cache = ptcaches->first; + } } static PointCache *ptcache_copy(PointCache *cache) @@ -2258,7 +2267,7 @@ void BKE_ptcache_disk_to_mem(PTCacheID *pid) pm->frame = cfra; ptcache_alloc_data(pm); - ptcache_mem_init_pointers(pm); + BKE_ptcache_mem_init_pointers(pm); ptcache_file_init_pointers(pf); for(i=0; i<pm->totpoint; i++) { @@ -2274,7 +2283,7 @@ void BKE_ptcache_disk_to_mem(PTCacheID *pid) return; } ptcache_copy_data(pf->cur, pm->cur); - ptcache_mem_incr_pointers(pm); + BKE_ptcache_mem_incr_pointers(pm); } //ptcache_make_index_array(pm, pid->totpoint(pid->calldata)); @@ -2305,7 +2314,7 @@ void BKE_ptcache_mem_to_disk(PTCacheID *pid) pf->totpoint = pm->totpoint; pf->type = pid->type; - ptcache_mem_init_pointers(pm); + BKE_ptcache_mem_init_pointers(pm); ptcache_file_init_pointers(pf); if(!ptcache_file_write_header_begin(pf) || !pid->write_header(pf)) { @@ -2325,7 +2334,7 @@ void BKE_ptcache_mem_to_disk(PTCacheID *pid) ptcache_file_close(pf); return; } - ptcache_mem_incr_pointers(pm); + BKE_ptcache_mem_incr_pointers(pm); } ptcache_file_close(pf); diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 63dabf18faa..10f6a8cf47c 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -404,11 +404,13 @@ Scene *add_scene(char *name) sce->unit.scale_length = 1.0f; pset= &sce->toolsettings->particle; - pset->flag= PE_KEEP_LENGTHS|PE_LOCK_FIRST|PE_DEFLECT_EMITTER; + pset->flag= PE_KEEP_LENGTHS|PE_LOCK_FIRST|PE_DEFLECT_EMITTER|PE_AUTO_VELOCITY; pset->emitterdist= 0.25f; pset->totrekey= 5; pset->totaddkey= 5; pset->brushtype= PE_BRUSH_NONE; + pset->draw_step= 2; + pset->fade_frames= 2; for(a=0; a<PE_TOT_BRUSH; a++) { pset->brush[a].strength= 50; pset->brush[a].size= 50; diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 9d5ae3062a1..070c873686c 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -2963,8 +2963,10 @@ static void direct_link_pointcache(FileData *fd, PointCache *cache) else cache->mem_cache.first = cache->mem_cache.last = NULL; - cache->flag &= ~(PTCACHE_SIMULATION_VALID|PTCACHE_BAKE_EDIT_ACTIVE); + cache->flag &= ~PTCACHE_SIMULATION_VALID; cache->simframe= 0; + cache->edit= NULL; + cache->free_edit= NULL; } static void direct_link_pointcache_list(FileData *fd, ListBase *ptcaches, PointCache **ocache) @@ -3137,7 +3139,7 @@ static void direct_link_particlesystems(FileData *fd, ListBase *particles) link_list(fd, &psys->targets); - psys->edit = 0; + psys->edit = NULL; psys->free_edit = NULL; psys->pathcache = 0; psys->childcache = 0; diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 26fd0cf6af6..88c6f205d15 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -1208,7 +1208,7 @@ static void write_objects(WriteData *wd, ListBase *idbase) writestruct(wd, DATA, "PartDeflect", 1, ob->pd); writestruct(wd, DATA, "SoftBody", 1, ob->soft); - if(ob->soft) writestruct(wd, DATA, "PointCache", 1, ob->soft->pointcache); + if(ob->soft) write_pointcaches(wd, &ob->soft->ptcaches); writestruct(wd, DATA, "BulletSoftBody", 1, ob->bsoft); write_particlesystems(wd, &ob->particlesystem); diff --git a/source/blender/editors/include/ED_particle.h b/source/blender/editors/include/ED_particle.h index 43cb5053f48..dcac51928a3 100644 --- a/source/blender/editors/include/ED_particle.h +++ b/source/blender/editors/include/ED_particle.h @@ -39,18 +39,16 @@ struct rcti; struct wmWindowManager; /* particle edit mode */ -void PE_change_act(void *ob_v, void *act_v); -void PE_change_act_psys(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys); -int PE_can_edit(struct ParticleSystem *psys); +void PE_free_ptcache_edit(struct PTCacheEdit *edit); +int PE_start_edit(struct PTCacheEdit *edit); /* access */ -struct ParticleSystem *PE_get_current(struct Scene *scene, struct Object *ob); -short PE_get_current_num(struct Object *ob); +struct PTCacheEdit *PE_get_current(struct Scene *scene, struct Object *ob); int PE_minmax(struct Scene *scene, float *min, float *max); struct ParticleEditSettings *PE_settings(Scene *scene); /* update calls */ -void PE_hide_keys_time(struct Scene *scene, struct ParticleSystem *psys, float cfra); +void PE_hide_keys_time(struct Scene *scene, struct PTCacheEdit *edit, float cfra); void PE_update_object(struct Scene *scene, struct Object *ob, int useflag); /* selection tools */ diff --git a/source/blender/editors/mesh/editmesh.c b/source/blender/editors/mesh/editmesh.c index 17838d6042c..c3f1637d3af 100644 --- a/source/blender/editors/mesh/editmesh.c +++ b/source/blender/editors/mesh/editmesh.c @@ -743,78 +743,6 @@ static void edge_drawflags(Mesh *me, EditMesh *em) } } -static int editmesh_pointcache_edit(Scene *scene, Object *ob, int totvert, PTCacheID *pid_p, float mat[][4], int load) -{ - Cloth *cloth; - SoftBody *sb; - ClothModifierData *clmd; - PTCacheID pid, tmpid; - int cfra= (int)scene->r.cfra, found= 0; - - pid.cache= NULL; - - /* check for cloth */ - if(modifiers_isClothEnabled(ob)) { - clmd= (ClothModifierData*)modifiers_findByType(ob, eModifierType_Cloth); - cloth= clmd->clothObject; - - BKE_ptcache_id_from_cloth(&tmpid, ob, clmd); - - /* verify vertex count and baked status */ - if(cloth && (totvert == cloth->numverts)) { - if((tmpid.cache->flag & PTCACHE_BAKED) && (tmpid.cache->flag & PTCACHE_BAKE_EDIT)) { - pid= tmpid; - - if(load && (pid.cache->flag & PTCACHE_BAKE_EDIT_ACTIVE)) - found= 1; - } - } - } - - /* check for softbody */ - if(!found && ob->soft) { - sb= ob->soft; - - BKE_ptcache_id_from_softbody(&tmpid, ob, sb); - - /* verify vertex count and baked status */ - if(sb->bpoint && (totvert == sb->totpoint)) { - if((tmpid.cache->flag & PTCACHE_BAKED) && (tmpid.cache->flag & PTCACHE_BAKE_EDIT)) { - pid= tmpid; - - if(load && (pid.cache->flag & PTCACHE_BAKE_EDIT_ACTIVE)) - found= 1; - } - } - } - - /* if not making editmesh verify editing was active for this point cache */ - if(load) { - if(found) - pid.cache->flag &= ~PTCACHE_BAKE_EDIT_ACTIVE; - else - return 0; - } - - /* check if we have cache for this frame */ - if(pid.cache && BKE_ptcache_id_exist(&pid, cfra)) { - *pid_p = pid; - - if(load) { - Mat4CpyMat4(mat, ob->obmat); - } - else { - pid.cache->editframe= cfra; - pid.cache->flag |= PTCACHE_BAKE_EDIT_ACTIVE; - Mat4Invert(mat, ob->obmat); /* ob->imat is not up to date */ - } - - return 1; - } - - return 0; -} - /* turns Mesh into editmesh */ void make_editMesh(Scene *scene, Object *ob) { @@ -828,11 +756,8 @@ void make_editMesh(Scene *scene, Object *ob) EditFace *efa; EditEdge *eed; EditSelection *ese; - PTCacheID pid; - Cloth *cloth; - SoftBody *sb; - float cacheco[3], cachemat[4][4], *co; - int tot, a, cacheedit= 0, eekadoodle= 0; + float *co; + int tot, a, eekadoodle= 0; if(me->edit_mesh==NULL) me->edit_mesh= MEM_callocN(sizeof(EditMesh), "editmesh"); @@ -867,26 +792,10 @@ void make_editMesh(Scene *scene, Object *ob) CustomData_copy(&me->vdata, &em->vdata, CD_MASK_EDITMESH, CD_CALLOC, 0); mvert= me->mvert; - cacheedit= editmesh_pointcache_edit(scene, ob, tot, &pid, cachemat, 0); - evlist= (EditVert **)MEM_mallocN(tot*sizeof(void *),"evlist"); for(a=0; a<tot; a++, mvert++) { - if(cacheedit) { - if(pid.type == PTCACHE_TYPE_CLOTH) { - cloth= ((ClothModifierData*)pid.calldata)->clothObject; - VECCOPY(cacheco, cloth->verts[a].x) - } - else if(pid.type == PTCACHE_TYPE_SOFTBODY) { - sb= (SoftBody*)pid.calldata; - VECCOPY(cacheco, sb->bpoint[a].pos) - } - - Mat4MulVecfl(cachemat, cacheco); - co= cacheco; - } - else - co= mvert->co; + co= mvert->co; eve= addvertlist(em, co, NULL); evlist[a]= eve; @@ -1011,11 +920,6 @@ void make_editMesh(Scene *scene, Object *ob) if (EM_get_actFace(em, 0)==NULL) { EM_set_actFace(em, em->faces.first ); /* will use the first face, this is so we alwats have an active face */ } - - /* vertex coordinates change with cache edit, need to recalc */ - if(cacheedit) - recalc_editnormals(em); - } /* makes Mesh out of editmesh */ @@ -1031,12 +935,8 @@ void load_editMesh(Scene *scene, Object *ob) EditFace *efa, *efa_act; EditEdge *eed; EditSelection *ese; - SoftBody *sb; - Cloth *cloth; - ClothModifierData *clmd; - PTCacheID pid; - float *fp, *newkey, *oldkey, nor[3], cacheco[3], cachemat[4][4]; - int i, a, ototvert, cacheedit= 0; + float *fp, *newkey, *oldkey, nor[3]; + int i, a, ototvert; /* this one also tests of edges are not in faces: */ /* eed->f2==0: not in face, f2==1: draw it */ @@ -1090,48 +990,8 @@ void load_editMesh(Scene *scene, Object *ob) eve= em->verts.first; a= 0; - /* check for point cache editing */ - cacheedit= editmesh_pointcache_edit(scene, ob, em->totvert, &pid, cachemat, 1); - while(eve) { - if(cacheedit) { - if(pid.type == PTCACHE_TYPE_CLOTH) { - clmd= (ClothModifierData*)pid.calldata; - cloth= clmd->clothObject; - - /* assign position */ - VECCOPY(cacheco, cloth->verts[a].x) - VECCOPY(cloth->verts[a].x, eve->co); - Mat4MulVecfl(cachemat, cloth->verts[a].x); - - /* find plausible velocity, not physical correct but gives - * nicer results when commented */ - VECSUB(cacheco, cloth->verts[a].x, cacheco); - VecMulf(cacheco, clmd->sim_parms->stepsPerFrame*10.0f); - VECADD(cloth->verts[a].v, cloth->verts[a].v, cacheco); - } - else if(pid.type == PTCACHE_TYPE_SOFTBODY) { - sb= (SoftBody*)pid.calldata; - - /* assign position */ - VECCOPY(cacheco, sb->bpoint[a].pos) - VECCOPY(sb->bpoint[a].pos, eve->co); - Mat4MulVecfl(cachemat, sb->bpoint[a].pos); - - /* changing velocity for softbody doesn't seem to give - * good results? */ -#if 0 - VECSUB(cacheco, sb->bpoint[a].pos, cacheco); - VecMulf(cacheco, sb->minloops*10.0f); - VECADD(sb->bpoint[a].vec, sb->bpoint[a].pos, cacheco); -#endif - } - - if(oldverts) - VECCOPY(mvert->co, oldverts[a].co) - } - else - VECCOPY(mvert->co, eve->co); + VECCOPY(mvert->co, eve->co); mvert->mat_nr= 32767; /* what was this for, halos? */ @@ -1155,10 +1015,6 @@ void load_editMesh(Scene *scene, Object *ob) eve= eve->next; mvert++; } - - /* write changes to cache */ - if(cacheedit) - BKE_ptcache_write_cache(&pid, pid.cache->editframe); /* the edges */ a= 0; diff --git a/source/blender/editors/physics/ed_pointcache.c b/source/blender/editors/physics/ed_pointcache.c index 917e2b40d72..68e0c28e9c1 100644 --- a/source/blender/editors/physics/ed_pointcache.c +++ b/source/blender/editors/physics/ed_pointcache.c @@ -46,6 +46,7 @@ #include "ED_screen.h" #include "ED_physics.h" +#include "ED_particle.h" #include "UI_interface.h" #include "UI_resources.h" @@ -184,8 +185,16 @@ static int ptcache_free_bake_exec(bContext *C, wmOperator *op) { PointerRNA ptr= CTX_data_pointer_get_type(C, "PointCache", &RNA_PointCache); PointCache *cache= ptr.data; - - cache->flag &= ~PTCACHE_BAKED; + + if(cache->edit) { + if(!cache->edit->edited || 1) {// XXX okee("Lose changes done in particle mode?")) { + PE_free_ptcache_edit(cache->edit); + cache->edit = NULL; + cache->flag &= ~PTCACHE_BAKED; + } + } + else + cache->flag &= ~PTCACHE_BAKED; return OPERATOR_FINISHED; } diff --git a/source/blender/editors/physics/editparticle.c b/source/blender/editors/physics/editparticle.c index b92632b45af..dbb11f72890 100644 --- a/source/blender/editors/physics/editparticle.c +++ b/source/blender/editors/physics/editparticle.c @@ -57,7 +57,8 @@ #include "BKE_particle.h" #include "BKE_report.h" #include "BKE_scene.h" -#include "BKE_utildefines.h" +#include "BKE_utildefines.h" +#include "BKE_pointcache.h" #include "BLI_arithb.h" #include "BLI_blenlib.h" @@ -85,11 +86,25 @@ #include "physics_intern.h" -static void PE_create_particle_edit(Scene *scene, Object *ob, ParticleSystem *psys); -static void ParticleUndo_clear(ParticleSystem *psys); +static void PE_create_particle_edit(Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys); +static void PTCacheUndo_clear(PTCacheEdit *edit); -#define LOOP_PARTICLES(i, pa) for(i=0, pa=psys->particles; i<totpart; i++, pa++) -#define LOOP_KEYS(k, key) if(psys->edit)for(k=0, key=psys->edit->keys[i]; k<pa->totkey; k++, key++) +#define KEY_K PTCacheEditKey *key; int k +#define POINT_P PTCacheEditPoint *point; int p +#define LOOP_POINTS for(p=0, point=edit->points; p<edit->totpoint; p++, point++) +#define LOOP_VISIBLE_POINTS for(p=0, point=edit->points; p<edit->totpoint; p++, point++) if(!(point->flag & PEP_HIDE)) +#define LOOP_SELECTED_POINTS for(p=0, point=edit->points; p<edit->totpoint; p++, point++) if(point_is_selected(point)) +#define LOOP_UNSELECTED_POINTS for(p=0, point=edit->points; p<edit->totpoint; p++, point++) if(!point_is_selected(point)) +#define LOOP_EDITED_POINTS for(p=0, point=edit->points; p<edit->totpoint; p++, point++) if(point->flag & PEP_EDIT_RECALC) +#define LOOP_TAGGED_POINTS for(p=0, point=edit->points; p<edit->totpoint; p++, point++) if(point->flag & PEP_TAG) +#define LOOP_KEYS for(k=0, key=point->keys; k<point->totkey; k++, key++) +#define LOOP_VISIBLE_KEYS for(k=0, key=point->keys; k<point->totkey; k++, key++) if(!(key->flag & PEK_HIDE)) +#define LOOP_SELECTED_KEYS for(k=0, key=point->keys; k<point->totkey; k++, key++) if((key->flag & PEK_SELECT) && !(key->flag & PEK_HIDE)) +#define LOOP_TAGGED_KEYS for(k=0, key=point->keys; k<point->totkey; k++, key++) if(key->flag & PEK_TAG) + +#define LOOP_PARTICLES(i, pa) for(i=0, pa=psys->particles; i<psys->totpart; i++, pa++) + +#define KEY_WCO (key->flag & PEK_USE_WCO ? key->world_co : key->co) /**************************** utilities *******************************/ @@ -97,14 +112,14 @@ static int PE_poll(bContext *C) { Scene *scene= CTX_data_scene(C); Object *ob= CTX_data_active_object(C); - ParticleSystem *psys; + PTCacheEdit *edit; if(!scene || !ob) return 0; - psys= PE_get_current(scene, ob); + edit= PE_get_current(scene, ob); - return (psys && psys->edit && (ob && ob->mode & OB_MODE_PARTICLE_EDIT)); + return (edit && (ob->mode & OB_MODE_PARTICLE_EDIT)); } static int PE_poll_3dview(bContext *C) @@ -113,22 +128,21 @@ static int PE_poll_3dview(bContext *C) CTX_wm_region(C)->regiontype == RGN_TYPE_WINDOW; } -static void PE_free_particle_edit(ParticleSystem *psys) +void PE_free_ptcache_edit(PTCacheEdit *edit) { - ParticleEdit *edit= psys->edit; - int i, totpart= psys->totpart; + POINT_P; if(edit==0) return; - ParticleUndo_clear(psys); + PTCacheUndo_clear(edit); - if(edit->keys) { - for(i=0; i<totpart; i++) { - if(edit->keys[i]) - MEM_freeN(edit->keys[i]); + if(edit->points) { + LOOP_POINTS { + if(point->keys) + MEM_freeN(point->keys); } - MEM_freeN(edit->keys); + MEM_freeN(edit->points); } if(edit->mirror_cache) @@ -144,19 +158,23 @@ static void PE_free_particle_edit(ParticleSystem *psys) edit->emitter_field= 0; } - MEM_freeN(edit); + psys_free_path_cache(NULL, edit); - psys->edit= NULL; - psys->free_edit= NULL; + MEM_freeN(edit); } /************************************************/ /* Edit Mode Helpers */ /************************************************/ -int PE_can_edit(ParticleSystem *psys) +int PE_start_edit(PTCacheEdit *edit) { - return (psys && psys->edit); + if(edit) { + edit->edited = 1; + return 1; + } + + return 0; } ParticleEditSettings *PE_settings(Scene *scene) @@ -165,73 +183,99 @@ ParticleEditSettings *PE_settings(Scene *scene) } /* always gets atleast the first particlesystem even if PSYS_CURRENT flag is not set */ -ParticleSystem *PE_get_current(Scene *scene, Object *ob) +PTCacheEdit *PE_get_current(Scene *scene, Object *ob) { - ParticleSystem *psys; + ParticleEditSettings *pset= PE_settings(scene); + PTCacheEdit *edit = NULL; + ListBase pidlist; + PTCacheID *pid; + + pset->scene = scene; + pset->object = ob; if(ob==NULL) return NULL; - psys= ob->particlesystem.first; - while(psys) { - if(psys->flag & PSYS_CURRENT) - break; - psys=psys->next; - } + BKE_ptcache_ids_from_object(&pidlist, ob); - if(psys==NULL && ob->particlesystem.first) { - psys=ob->particlesystem.first; - psys->flag |= PSYS_CURRENT; + /* in the case of only one editable thing, set pset->edittype accordingly */ + if(pidlist.first == pidlist.last) { + pid = pidlist.first; + switch(pid->type) { + case PTCACHE_TYPE_PARTICLES: + pset->edittype = PE_TYPE_PARTICLES; + break; + case PTCACHE_TYPE_SOFTBODY: + pset->edittype = PE_TYPE_SOFTBODY; + break; + case PTCACHE_TYPE_CLOTH: + pset->edittype = PE_TYPE_CLOTH; + break; + } } - /* this happens when Blender is started with particle - * edit mode enabled XXX there's a draw error then? */ - if(psys && psys_check_enabled(ob, psys) && (ob == OBACT) && (ob->mode & OB_MODE_PARTICLE_EDIT)) - if(psys->part->type == PART_HAIR && psys->flag & PSYS_EDITED) - if(psys->edit == NULL) - PE_create_particle_edit(scene, ob, psys); - - return psys; -} + for(pid=pidlist.first; pid; pid=pid->next) { + if(pset->edittype == PE_TYPE_PARTICLES && pid->type == PTCACHE_TYPE_PARTICLES) { + ParticleSystem *psys = pid->calldata; -/* returns -1 if no system has PSYS_CURRENT flag */ -short PE_get_current_num(Object *ob) -{ - short num=0; - ParticleSystem *psys= ob->particlesystem.first; + if(psys->flag & PSYS_CURRENT) { + if(psys->part && psys->part->type == PART_HAIR) { + if(!psys->edit && psys->flag & PSYS_HAIR_DONE) + PE_create_particle_edit(scene, ob, NULL, psys); + edit = psys->edit; + } + else { + if(pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) + PE_create_particle_edit(scene, ob, pid->cache, psys); + edit = pid->cache->edit; + } - while(psys) { - if(psys->flag & PSYS_CURRENT) - return num; - num++; - psys=psys->next; + break; + } + } + else if(pset->edittype == PE_TYPE_SOFTBODY && pid->type == PTCACHE_TYPE_SOFTBODY) { + if(pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) + PE_create_particle_edit(scene, ob, pid->cache, NULL); + edit = pid->cache->edit; + break; + } + else if(pset->edittype == PE_TYPE_CLOTH && pid->type == PTCACHE_TYPE_CLOTH) { + if(pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) + PE_create_particle_edit(scene, ob, pid->cache, NULL); + edit = pid->cache->edit; + break; + } } - return -1; + if(edit) + edit->pid = *pid; + + BLI_freelistN(&pidlist); + + return edit; } -void PE_hide_keys_time(Scene *scene, ParticleSystem *psys, float cfra) +void PE_hide_keys_time(Scene *scene, PTCacheEdit *edit, float cfra) { - ParticleData *pa; - ParticleEditKey *key; ParticleEditSettings *pset=PE_settings(scene); - int i, k, totpart= psys->totpart; + POINT_P; KEY_K; - if(pset->draw_timed && pset->selectmode==SCE_SELECT_POINT) { - LOOP_PARTICLES(i, pa) { - LOOP_KEYS(k, key) { - if(fabs(cfra-*key->time) < pset->draw_timed) + + if(pset->flag & PE_FADE_TIME && pset->selectmode==SCE_SELECT_POINT) { + LOOP_POINTS { + LOOP_KEYS { + if(fabs(cfra-*key->time) < pset->fade_frames) key->flag &= ~PEK_HIDE; else { key->flag |= PEK_HIDE; - key->flag &= ~PEK_SELECT; + //key->flag &= ~PEK_SELECT; } } } } else { - LOOP_PARTICLES(i, pa) { - LOOP_KEYS(k, key) { + LOOP_POINTS { + LOOP_KEYS { key->flag &= ~PEK_HIDE; } } @@ -247,7 +291,7 @@ typedef struct PEData { Scene *scene; Object *ob; DerivedMesh *dm; - ParticleSystem *psys; + PTCacheEdit *edit; short *mval; rcti *rect; @@ -276,7 +320,7 @@ static void PE_set_data(bContext *C, PEData *data) data->scene= CTX_data_scene(C); data->ob= CTX_data_active_object(C); - data->psys= PE_get_current(data->scene, data->ob); + data->edit= PE_get_current(data->scene, data->ob); } static void PE_set_view3d_data(bContext *C, PEData *data) @@ -388,121 +432,103 @@ static int key_inside_test(PEData *data, float co[3]) return key_inside_rect(data, co); } -static int particle_is_selected(ParticleSystem *psys, ParticleData *pa) +static int point_is_selected(PTCacheEditPoint *point) { - ParticleEditKey *key; - int sel, i, k; + KEY_K; + int sel; - if(pa->flag & PARS_HIDE) + if(point->flag & PEP_HIDE) return 0; sel= 0; - i= pa - psys->particles; - LOOP_KEYS(k, key) - if(key->flag & PEK_SELECT) - return 1; + LOOP_SELECTED_KEYS { + return 1; + } return 0; } /*************************** iterators *******************************/ -typedef void (*ForParticleFunc)(PEData *data, int pa_index); -typedef void (*ForKeyFunc)(PEData *data, int pa_index, int key_index); -typedef void (*ForKeyMatFunc)(PEData *data, float mat[][4], float imat[][4], int pa_index, int key_index); +typedef void (*ForPointFunc)(PEData *data, int point_index); +typedef void (*ForKeyFunc)(PEData *data, int point_index, int key_index); +typedef void (*ForKeyMatFunc)(PEData *data, float mat[][4], float imat[][4], int point_index, int key_index, PTCacheEditKey *key); static void for_mouse_hit_keys(PEData *data, ForKeyFunc func, int nearest) { - ParticleSystem *psys= data->psys; - ParticleEdit *edit= psys->edit; - ParticleData *pa; - ParticleEditKey *key; ParticleEditSettings *pset= PE_settings(data->scene); - int i, k, totpart, nearest_pa, nearest_key; + PTCacheEdit *edit= data->edit; + POINT_P; KEY_K; + int nearest_point, nearest_key; float dist= data->rad; /* in path select mode we have no keys */ if(pset->selectmode==SCE_SELECT_PATH) return; - totpart= psys->totpart; - nearest_pa= -1; + nearest_point= -1; nearest_key= -1; - LOOP_PARTICLES(i, pa) { - if(pa->flag & PARS_HIDE) continue; - + LOOP_VISIBLE_POINTS { if(pset->selectmode == SCE_SELECT_END) { /* only do end keys */ - key= edit->keys[i] + pa->totkey-1; + key= point->keys + point->totkey-1; if(nearest) { - if(key_inside_circle(data, dist, key->world_co, &dist)) { - nearest_pa= i; - nearest_key= pa->totkey-1; + if(key_inside_circle(data, dist, KEY_WCO, &dist)) { + nearest_point= p; + nearest_key= point->totkey-1; } } - else if(key_inside_test(data, key->world_co)) - func(data, i, pa->totkey-1); + else if(key_inside_test(data, KEY_WCO)) + func(data, p, point->totkey-1); } else { /* do all keys */ - key= edit->keys[i]; - - LOOP_KEYS(k, key) { - if(key->flag & PEK_HIDE) continue; - + LOOP_VISIBLE_KEYS { if(nearest) { - if(key_inside_circle(data, dist, key->world_co, &dist)) { - nearest_pa= i; + if(key_inside_circle(data, dist, KEY_WCO, &dist)) { + nearest_point= p; nearest_key= k; } } - else if(key_inside_test(data, key->world_co)) - func(data, i, k); + else if(key_inside_test(data, KEY_WCO)) + func(data, p, k); } } } /* do nearest only */ - if(nearest && nearest_pa > -1) - func(data, nearest_pa, nearest_key); + if(nearest && nearest_point > -1) + func(data, nearest_point, nearest_key); } -static void foreach_mouse_hit_particle(PEData *data, ForParticleFunc func, int selected) +static void foreach_mouse_hit_point(PEData *data, ForPointFunc func, int selected) { - ParticleSystem *psys= data->psys; - ParticleData *pa; - ParticleEditKey *key; ParticleEditSettings *pset= PE_settings(data->scene); - int i, k, totpart; - - totpart= psys->totpart; + PTCacheEdit *edit= data->edit; + POINT_P; KEY_K; /* all is selected in path mode */ if(pset->selectmode==SCE_SELECT_PATH) selected=0; - LOOP_PARTICLES(i, pa) { - if(pa->flag & PARS_HIDE) continue; - + LOOP_VISIBLE_POINTS { if(pset->selectmode==SCE_SELECT_END) { /* only do end keys */ - key= psys->edit->keys[i] + pa->totkey-1; + key= point->keys + point->totkey - 1; if(selected==0 || key->flag & PEK_SELECT) - if(key_inside_circle(data, data->rad, key->world_co, &data->dist)) - func(data, i); + if(key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) + func(data, p); } else { /* do all keys */ - LOOP_KEYS(k, key) { - if(key->flag & PEK_HIDE) continue; - + LOOP_VISIBLE_KEYS { if(selected==0 || key->flag & PEK_SELECT) { - if(key_inside_circle(data, data->rad, key->world_co, &data->dist)) { - func(data, i); + if(key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) { + func(data, p); break; } } @@ -513,16 +539,15 @@ static void foreach_mouse_hit_particle(PEData *data, ForParticleFunc func, int s static void foreach_mouse_hit_key(PEData *data, ForKeyMatFunc func, int selected) { - ParticleSystem *psys= data->psys; - ParticleData *pa; - ParticleEditKey *key; - ParticleSystemModifierData *psmd=0; + PTCacheEdit *edit = data->edit; + ParticleSystem *psys = edit->psys; + ParticleSystemModifierData *psmd = NULL; ParticleEditSettings *pset= PE_settings(data->scene); - int i, k, totpart; + POINT_P; KEY_K; float mat[4][4], imat[4][4]; - psmd= psys_get_modifier(data->ob,psys); - totpart= psys->totpart; + if(edit->psys) + psmd= psys_get_modifier(data->ob, edit->psys); /* all is selected in path mode */ if(pset->selectmode==SCE_SELECT_PATH) @@ -531,99 +556,77 @@ static void foreach_mouse_hit_key(PEData *data, ForKeyMatFunc func, int selected Mat4One(imat); Mat4One(mat); - LOOP_PARTICLES(i, pa) { - if(pa->flag & PARS_HIDE) continue; - - psys_mat_hair_to_global(data->ob, psmd->dm, psys->part->from, pa, mat); - Mat4Invert(imat,mat); + LOOP_VISIBLE_POINTS { + if(edit->psys) { + psys_mat_hair_to_global(data->ob, psmd->dm, psys->part->from, psys->particles + p, mat); + Mat4Invert(imat,mat); + } if(pset->selectmode==SCE_SELECT_END) { /* only do end keys */ - key= psys->edit->keys[i] + pa->totkey-1; + key= point->keys + point->totkey-1; if(selected==0 || key->flag & PEK_SELECT) - if(key_inside_circle(data, data->rad, key->world_co, &data->dist)) - func(data, mat, imat, i, pa->totkey-1); + if(key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) + func(data, mat, imat, p, point->totkey-1, key); } else { /* do all keys */ - LOOP_KEYS(k, key) { - if(key->flag&PEK_HIDE) continue; - + LOOP_VISIBLE_KEYS { if(selected==0 || key->flag & PEK_SELECT) - if(key_inside_circle(data, data->rad, key->world_co, &data->dist)) - func(data, mat, imat, i, k); + if(key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) + func(data, mat, imat, p, k, key); } } } } -static void foreach_selected_particle(PEData *data, ForParticleFunc func) +static void foreach_selected_point(PEData *data, ForPointFunc func) { - ParticleSystem *psys= data->psys; - ParticleData *pa; - int i, totpart; - - totpart= psys->totpart; + PTCacheEdit *edit = data->edit; + POINT_P; - LOOP_PARTICLES(i, pa) - if(particle_is_selected(psys, pa)) - func(data, i); + LOOP_SELECTED_POINTS { + func(data, p); + } } static void foreach_selected_key(PEData *data, ForKeyFunc func) { - ParticleSystem *psys= data->psys; - ParticleData *pa; - ParticleEditKey *key; - int i, k, totpart; - - totpart= psys->totpart; - - LOOP_PARTICLES(i, pa) { - if(pa->flag & PARS_HIDE) continue; - - key= psys->edit->keys[i]; + PTCacheEdit *edit = data->edit; + POINT_P; KEY_K; - LOOP_KEYS(k, key) - if(key->flag & PEK_SELECT) - func(data, i, k); + LOOP_VISIBLE_POINTS { + LOOP_SELECTED_KEYS { + func(data, p, k); + } } } -void PE_foreach_particle(PEData *data, ForParticleFunc func) +static void foreach_point(PEData *data, ForPointFunc func) { - ParticleSystem *psys= data->psys; - int i, totpart; + PTCacheEdit *edit = data->edit; + POINT_P; - totpart= psys->totpart; - - for(i=0; i<totpart; i++) - func(data, i); + LOOP_POINTS { + func(data, p); + } } -static int count_selected_keys(Scene *scene, ParticleSystem *psys) +static int count_selected_keys(Scene *scene, PTCacheEdit *edit) { - ParticleData *pa; - ParticleEditKey *key; ParticleEditSettings *pset= PE_settings(scene); - int i, k, totpart, sel= 0; - - totpart= psys->totpart; - - LOOP_PARTICLES(i, pa) { - if(pa->flag & PARS_HIDE) continue; - - key= psys->edit->keys[i]; + POINT_P; KEY_K; + int sel= 0; + LOOP_VISIBLE_POINTS { if(pset->selectmode==SCE_SELECT_POINT) { - for(k=0; k<pa->totkey; k++,key++) - if(key->flag & PEK_SELECT) - sel++; + LOOP_SELECTED_KEYS { + sel++; + } } else if(pset->selectmode==SCE_SELECT_END) { - key += pa->totkey-1; - + key = point->keys + point->totkey - 1; if(key->flag & PEK_SELECT) sel++; } @@ -638,7 +641,7 @@ static int count_selected_keys(Scene *scene, ParticleSystem *psys) static void PE_update_mirror_cache(Object *ob, ParticleSystem *psys) { - ParticleEdit *edit; + PTCacheEdit *edit; ParticleData *pa; ParticleSystemModifierData *psmd; KDTree *tree; @@ -696,8 +699,9 @@ static void PE_update_mirror_cache(Object *ob, ParticleSystem *psys) static void PE_mirror_particle(Object *ob, DerivedMesh *dm, ParticleSystem *psys, ParticleData *pa, ParticleData *mpa) { HairKey *hkey, *mhkey; - ParticleEditKey *key, *mkey; - ParticleEdit *edit; + PTCacheEditPoint *point, *mpoint; + PTCacheEditKey *key, *mkey; + PTCacheEdit *edit; float mat[4][4], mmat[4][4], immat[4][4]; int i, mi, k; @@ -717,17 +721,20 @@ static void PE_mirror_particle(Object *ob, DerivedMesh *dm, ParticleSystem *psys else mi= mpa - psys->particles; + point = edit->points + i; + mpoint = edit->points + mi; + /* make sure they have the same amount of keys */ if(pa->totkey != mpa->totkey) { if(mpa->hair) MEM_freeN(mpa->hair); - if(edit->keys[mi]) MEM_freeN(edit->keys[mi]); + if(mpoint->keys) MEM_freeN(mpoint->keys); mpa->hair= MEM_dupallocN(pa->hair); - edit->keys[mi]= MEM_dupallocN(edit->keys[i]); - mpa->totkey= pa->totkey; + mpoint->keys= MEM_dupallocN(point->keys); + mpoint->totkey= point->totkey; mhkey= mpa->hair; - mkey= edit->keys[mi]; + mkey= mpoint->keys; for(k=0; k<mpa->totkey; k++, mkey++, mhkey++) { mkey->co= mhkey->co; mkey->time= &mhkey->time; @@ -742,8 +749,8 @@ static void PE_mirror_particle(Object *ob, DerivedMesh *dm, ParticleSystem *psys hkey=pa->hair; mhkey=mpa->hair; - key= edit->keys[i]; - mkey= edit->keys[mi]; + key= point->keys; + mkey= mpoint->keys; for(k=0; k<pa->totkey; k++, hkey++, mhkey++, key++, mkey++) { VECCOPY(mhkey->co, hkey->co); Mat4MulVecfl(mat, mhkey->co); @@ -754,199 +761,172 @@ static void PE_mirror_particle(Object *ob, DerivedMesh *dm, ParticleSystem *psys mkey->flag |= PEK_TAG; } - if(pa->flag & PARS_TAG) - mpa->flag |= PARS_TAG; - if(pa->flag & PARS_EDIT_RECALC) - mpa->flag |= PARS_EDIT_RECALC; + if(point->flag & PEP_TAG) + mpoint->flag |= PEP_TAG; + if(point->flag & PEP_EDIT_RECALC) + mpoint->flag |= PEP_EDIT_RECALC; } static void PE_apply_mirror(Object *ob, ParticleSystem *psys) { - ParticleEdit *edit; - ParticleData *pa; + PTCacheEdit *edit; ParticleSystemModifierData *psmd; - int i, totpart; + POINT_P; + + if(!psys) + return; edit= psys->edit; psmd= psys_get_modifier(ob, psys); - totpart= psys->totpart; /* we delay settings the PARS_EDIT_RECALC for mirrored particles * to avoid doing mirror twice */ - LOOP_PARTICLES(i, pa) { - if(pa->flag & PARS_EDIT_RECALC) { - PE_mirror_particle(ob, psmd->dm, psys, pa, NULL); + LOOP_POINTS { + if(point->flag & PEP_EDIT_RECALC) { + PE_mirror_particle(ob, psmd->dm, psys, psys->particles + p, NULL); - if(edit->mirror_cache[i] != -1) - psys->particles[edit->mirror_cache[i]].flag &= ~PARS_EDIT_RECALC; + if(edit->mirror_cache[p] != -1) + edit->points[edit->mirror_cache[p]].flag &= ~PEP_EDIT_RECALC; } } - LOOP_PARTICLES(i, pa) - if(pa->flag & PARS_EDIT_RECALC) - if(edit->mirror_cache[i] != -1) - psys->particles[edit->mirror_cache[i]].flag |= PARS_EDIT_RECALC; - - edit->totkeys= psys_count_keys(psys); + LOOP_POINTS { + if(point->flag & PEP_EDIT_RECALC) + if(edit->mirror_cache[p] != -1) + edit->points[edit->mirror_cache[p]].flag |= PEP_EDIT_RECALC; + } } /************************************************/ /* Edit Calculation */ /************************************************/ /* tries to stop edited particles from going through the emitter's surface */ -static void pe_deflect_emitter(Scene *scene, Object *ob, ParticleSystem *psys) +static void pe_deflect_emitter(Scene *scene, Object *ob, PTCacheEdit *edit) { - ParticleEdit *edit; - ParticleData *pa; - ParticleEditKey *key; ParticleEditSettings *pset= PE_settings(scene); - ParticleSystemModifierData *psmd= psys_get_modifier(ob,psys); - int i, k, totpart,index; + ParticleSystem *psys; + ParticleSystemModifierData *psmd; + POINT_P; KEY_K; + int index; float *vec, *nor, dvec[3], dot, dist_1st; float hairimat[4][4], hairmat[4][4]; - if(psys==0) + if(edit==NULL || edit->psys==NULL || (pset->flag & PE_DEFLECT_EMITTER)==0) return; - if((pset->flag & PE_DEFLECT_EMITTER)==0) - return; + psys = edit->psys; + psmd = psys_get_modifier(ob,psys); - edit= psys->edit; - totpart= psys->totpart; - - LOOP_PARTICLES(i, pa) { - if(!(pa->flag & PARS_EDIT_RECALC)) - continue; - - psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, pa, hairmat); - - LOOP_KEYS(k, key) { + LOOP_EDITED_POINTS { + psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, psys->particles + p, hairmat); + + LOOP_KEYS { Mat4MulVecfl(hairmat, key->co); } - //} - - //LOOP_PARTICLES(i, pa) { - key=psys->edit->keys[i]+1; - - dist_1st=VecLenf((key-1)->co,key->co); - dist_1st*=0.75f*pset->emitterdist; - for(k=1; k<pa->totkey; k++, key++) { - index= BLI_kdtree_find_nearest(edit->emitter_field,key->co,NULL,NULL); - - vec=edit->emitter_cosnos +index*6; - nor=vec+3; + LOOP_KEYS { + if(k==0) { + dist_1st = VecLenf((key+1)->co, key->co); + dist_1st *= 0.75f * pset->emitterdist; + } + else { + index= BLI_kdtree_find_nearest(edit->emitter_field,key->co,NULL,NULL); + + vec=edit->emitter_cosnos +index*6; + nor=vec+3; - VecSubf(dvec, key->co, vec); + VecSubf(dvec, key->co, vec); - dot=Inpf(dvec,nor); - VECCOPY(dvec,nor); + dot=Inpf(dvec,nor); + VECCOPY(dvec,nor); - if(dot>0.0f) { - if(dot<dist_1st) { + if(dot>0.0f) { + if(dot<dist_1st) { + Normalize(dvec); + VecMulf(dvec,dist_1st-dot); + VecAddf(key->co,key->co,dvec); + } + } + else { Normalize(dvec); VecMulf(dvec,dist_1st-dot); VecAddf(key->co,key->co,dvec); } + if(k==1) + dist_1st*=1.3333f; } - else { - Normalize(dvec); - VecMulf(dvec,dist_1st-dot); - VecAddf(key->co,key->co,dvec); - } - if(k==1) - dist_1st*=1.3333f; } - //} - - //LOOP_PARTICLES(i, pa) { Mat4Invert(hairimat,hairmat); - LOOP_KEYS(k, key) { + LOOP_KEYS { Mat4MulVecfl(hairimat, key->co); } } } /* force set distances between neighbouring keys */ -void PE_apply_lengths(Scene *scene, ParticleSystem *psys) +void PE_apply_lengths(Scene *scene, PTCacheEdit *edit) { - ParticleEdit *edit; - ParticleData *pa; - ParticleEditKey *key; + ParticleEditSettings *pset=PE_settings(scene); - int i, k, totpart; + POINT_P; KEY_K; float dv1[3]; - if(psys==0) - return; - - if((pset->flag & PE_KEEP_LENGTHS)==0) + if(edit==0 || (pset->flag & PE_KEEP_LENGTHS)==0) return; - edit= psys->edit; - totpart= psys->totpart; - - LOOP_PARTICLES(i, pa) { - if(!(pa->flag & PARS_EDIT_RECALC)) - continue; - - for(k=1, key=edit->keys[i] + 1; k<pa->totkey; k++, key++) { - VecSubf(dv1, key->co, (key - 1)->co); - Normalize(dv1); - VecMulf(dv1, (key - 1)->length); - VecAddf(key->co, (key - 1)->co, dv1); + LOOP_EDITED_POINTS { + LOOP_KEYS { + if(k) { + VecSubf(dv1, key->co, (key - 1)->co); + Normalize(dv1); + VecMulf(dv1, (key - 1)->length); + VecAddf(key->co, (key - 1)->co, dv1); + } } } } /* try to find a nice solution to keep distances between neighbouring keys */ -static void pe_iterate_lengths(Scene *scene, ParticleSystem *psys) +static void pe_iterate_lengths(Scene *scene, PTCacheEdit *edit) { - ParticleEdit *edit; - ParticleData *pa; - ParticleEditKey *key; ParticleEditSettings *pset=PE_settings(scene); - int i, j, k, totpart; + POINT_P; + PTCacheEditKey *key; + int j, k; float tlen; float dv0[3]= {0.0f, 0.0f, 0.0f}; float dv1[3]= {0.0f, 0.0f, 0.0f}; float dv2[3]= {0.0f, 0.0f, 0.0f}; - if(psys==0) + if(edit==0) return; if((pset->flag & PE_KEEP_LENGTHS)==0) return; - edit= psys->edit; - totpart= psys->totpart; - - LOOP_PARTICLES(i, pa) { - if(!(pa->flag & PARS_EDIT_RECALC)) - continue; - - for(j=1; j<pa->totkey; j++) { - float mul= 1.0f / (float)pa->totkey; + LOOP_EDITED_POINTS { + for(j=1; j<point->totkey; j++) { + float mul= 1.0f / (float)point->totkey; if(pset->flag & PE_LOCK_FIRST) { - key= edit->keys[i] + 1; + key= point->keys + 1; k= 1; dv1[0]= dv1[1]= dv1[2]= 0.0; } else { - key= edit->keys[i]; + key= point->keys; k= 0; dv0[0]= dv0[1]= dv0[2]= 0.0; } - for(; k<pa->totkey; k++, key++) { + for(; k<point->totkey; k++, key++) { if(k) { VecSubf(dv0, (key - 1)->co, key->co); tlen= Normalize(dv0); VecMulf(dv0, (mul * (tlen - (key - 1)->length))); } - if(k < pa->totkey - 1) { + if(k < point->totkey - 1) { VecSubf(dv2, (key + 1)->co, key->co); tlen= Normalize(dv2); VecMulf(dv2, mul * (tlen - key->length)); @@ -962,20 +942,16 @@ static void pe_iterate_lengths(Scene *scene, ParticleSystem *psys) } } /* set current distances to be kept between neighbouting keys */ -static void recalc_lengths(ParticleSystem *psys) +static void recalc_lengths(PTCacheEdit *edit) { - ParticleData *pa; - ParticleEditKey *key; - int i, k, totpart; + POINT_P; KEY_K; - if(psys==0) + if(edit==0) return; - totpart= psys->totpart; - - LOOP_PARTICLES(i, pa) { - key= psys->edit->keys[i]; - for(k=0; k<pa->totkey-1; k++, key++) { + LOOP_EDITED_POINTS { + key= point->keys; + for(k=0; k<point->totkey-1; k++, key++) { key->length= VecLenf(key->co, (key + 1)->co); } } @@ -985,7 +961,7 @@ static void recalc_lengths(ParticleSystem *psys) static void recalc_emitter_field(Object *ob, ParticleSystem *psys) { DerivedMesh *dm=psys_get_modifier(ob,psys)->dm; - ParticleEdit *edit= psys->edit; + PTCacheEdit *edit= psys->edit; MFace *mface; MVert *mvert; float *vec, *nor; @@ -1042,74 +1018,145 @@ static void recalc_emitter_field(Object *ob, ParticleSystem *psys) static void PE_update_selection(Scene *scene, Object *ob, int useflag) { - ParticleSystem *psys= PE_get_current(scene, ob); - ParticleEdit *edit= psys->edit; ParticleEditSettings *pset= PE_settings(scene); - ParticleSettings *part= psys->part; - ParticleData *pa; + PTCacheEdit *edit= PE_get_current(scene, ob); HairKey *hkey; - ParticleEditKey *key; - float cfra= CFRA; - int i, k, totpart; - - totpart= psys->totpart; + POINT_P; KEY_K; /* flag all particles to be updated if not using flag */ if(!useflag) - LOOP_PARTICLES(i, pa) - pa->flag |= PARS_EDIT_RECALC; + LOOP_POINTS + point->flag |= PEP_EDIT_RECALC; /* flush edit key flag to hair key flag to preserve selection * on save */ - LOOP_PARTICLES(i, pa) { - key= edit->keys[i]; - - for(k=0, hkey=pa->hair; k<pa->totkey; k++, hkey++, key++) + if(edit->psys) LOOP_POINTS { + hkey = edit->psys->particles[p].hair; + LOOP_KEYS { hkey->editflag= key->flag; + hkey++; + } } - psys_cache_paths(scene, ob, psys, CFRA, 1); + psys_cache_edit_paths(scene, ob, edit, CFRA); - if(part->childtype && (pset->flag & PE_SHOW_CHILD)) - psys_cache_child_paths(scene, ob, psys, cfra, 1); /* disable update flag */ - LOOP_PARTICLES(i, pa) - pa->flag &= ~PARS_EDIT_RECALC; + LOOP_POINTS + point->flag &= ~PEP_EDIT_RECALC; } +static void update_world_cos(Object *ob, PTCacheEdit *edit) +{ + ParticleSystem *psys = edit->psys; + ParticleSystemModifierData *psmd= psys_get_modifier(ob, psys); + POINT_P; KEY_K; + float hairmat[4][4]; + + if(psys==0 || psys->edit==0) + return; + + LOOP_POINTS { + 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); + } + } +} +static void update_velocities(Object *ob, PTCacheEdit *edit) +{ + /*TODO: get frs_sec properly */ + float vec1[3], vec2[3], frs_sec, dfra; + POINT_P; KEY_K; + + /* hair doesn't use velocities */ + if(edit->psys || !edit->points || !edit->points->keys->vel) + return; + + frs_sec = edit->pid.flag & PTCACHE_VEL_PER_SEC ? 25.0f : 1.0f; + + LOOP_EDITED_POINTS { + LOOP_KEYS { + if(k==0) { + dfra = *(key+1)->time - *key->time; + + if(dfra <= 0.0f) + continue; + + VECSUB(key->vel, (key+1)->co, key->co); + + if(point->totkey>2) { + VECSUB(vec1, (key+1)->co, (key+2)->co); + Projf(vec2, vec1, key->vel); + VECSUB(vec2, vec1, vec2); + VECADDFAC(key->vel, key->vel, vec2, 0.5f); + } + } + else if(k==point->totkey-1) { + dfra = *key->time - *(key-1)->time; + + if(dfra <= 0.0f) + continue; + + VECSUB(key->vel, key->co, (key-1)->co); + + if(point->totkey>2) { + VECSUB(vec1, (key-2)->co, (key-1)->co); + Projf(vec2, vec1, key->vel); + VECSUB(vec2, vec1, vec2); + VECADDFAC(key->vel, key->vel, vec2, 0.5f); + } + } + else { + dfra = *(key+1)->time - *(key-1)->time; + + if(dfra <= 0.0f) + continue; + + VECSUB(key->vel, (key+1)->co, (key-1)->co); + } + VecMulf(key->vel, frs_sec/dfra); + } + } +} void PE_update_object(Scene *scene, Object *ob, int useflag) { - ParticleSystem *psys= PE_get_current(scene, ob); ParticleEditSettings *pset= PE_settings(scene); - ParticleSettings *part= psys->part; - ParticleData *pa; - float cfra= CFRA; - int i, totpart= psys->totpart; + PTCacheEdit *edit = PE_get_current(scene, ob); + POINT_P; + + if(!edit) + return; /* flag all particles to be updated if not using flag */ if(!useflag) - LOOP_PARTICLES(i, pa) - pa->flag |= PARS_EDIT_RECALC; + LOOP_POINTS { + point->flag |= PEP_EDIT_RECALC; + } /* do post process on particle edit keys */ - pe_iterate_lengths(scene, psys); - pe_deflect_emitter(scene, ob, psys); - PE_apply_lengths(scene, psys); + pe_iterate_lengths(scene, edit); + pe_deflect_emitter(scene, ob, edit); + PE_apply_lengths(scene, edit); if(pset->flag & PE_X_MIRROR) - PE_apply_mirror(ob,psys); - psys_update_world_cos(ob,psys); - PE_hide_keys_time(scene, psys, cfra); + PE_apply_mirror(ob,edit->psys); + if(edit->psys) + update_world_cos(ob, edit); + if(pset->flag & PE_AUTO_VELOCITY) + update_velocities(ob, edit); + PE_hide_keys_time(scene, edit, CFRA); /* regenerate path caches */ - psys_cache_paths(scene, ob, psys, cfra, 1); - - if(part->childtype && (pset->flag & PE_SHOW_CHILD)) - psys_cache_child_paths(scene, ob, psys, cfra, 1); + psys_cache_edit_paths(scene, ob, edit, CFRA); /* disable update flag */ - LOOP_PARTICLES(i, pa) - pa->flag &= ~PARS_EDIT_RECALC; + LOOP_POINTS { + point->flag &= ~PEP_EDIT_RECALC; + } + + DAG_object_flush_update(scene, ob, OB_RECALC_DATA); } /************************************************/ @@ -1118,48 +1165,44 @@ void PE_update_object(Scene *scene, Object *ob, int useflag) /*-----selection callbacks-----*/ -static void select_key(PEData *data, int pa_index, int key_index) +static void select_key(PEData *data, int point_index, int key_index) { - ParticleSystem *psys= data->psys; - ParticleData *pa= psys->particles + pa_index; - ParticleEditKey *key= psys->edit->keys[pa_index] + key_index; + PTCacheEdit *edit = data->edit; + PTCacheEditPoint *point = edit->points + point_index; + PTCacheEditKey *key = point->keys + key_index; if(data->select) key->flag |= PEK_SELECT; else key->flag &= ~PEK_SELECT; - pa->flag |= PARS_EDIT_RECALC; + point->flag |= PEP_EDIT_RECALC; } -static void select_keys(PEData *data, int pa_index, int key_index) +static void select_keys(PEData *data, int point_index, int key_index) { - ParticleSystem *psys= data->psys; - ParticleData *pa= psys->particles + pa_index; - ParticleEditKey *key= psys->edit->keys[pa_index]; - int k; + PTCacheEdit *edit = data->edit; + PTCacheEditPoint *point = edit->points + point_index; + KEY_K; - for(k=0; k<pa->totkey; k++,key++) { + LOOP_KEYS { if(data->select) key->flag |= PEK_SELECT; else key->flag &= ~PEK_SELECT; } - pa->flag |= PARS_EDIT_RECALC; + point->flag |= PEP_EDIT_RECALC; } -static void toggle_key_select(PEData *data, int pa_index, int key_index) +static void toggle_key_select(PEData *data, int point_index, int key_index) { - ParticleSystem *psys= data->psys; - ParticleData *pa= psys->particles + pa_index; + PTCacheEdit *edit = data->edit; + PTCacheEditPoint *point = edit->points + point_index; + PTCacheEditKey *key = point->keys + key_index; - if(psys->edit->keys[pa_index][key_index].flag&PEK_SELECT) - psys->edit->keys[pa_index][key_index].flag &= ~PEK_SELECT; - else - psys->edit->keys[pa_index][key_index].flag |= PEK_SELECT; - - pa->flag |= PARS_EDIT_RECALC; + key->flag ^= PEK_SELECT; + point->flag |= PEP_EDIT_RECALC; } /************************ de select all operator ************************/ @@ -1168,33 +1211,24 @@ static int de_select_all_exec(bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); Object *ob= CTX_data_active_object(C); - ParticleSystem *psys= PE_get_current(scene, ob); - ParticleEdit *edit= 0; - ParticleData *pa; - ParticleEditKey *key; - int i, k, totpart, sel= 0; + PTCacheEdit *edit= PE_get_current(scene, ob); + POINT_P; KEY_K; + int sel= 0; - edit= psys->edit; - totpart= psys->totpart; - - LOOP_PARTICLES(i, pa) { - if(pa->flag & PARS_HIDE) continue; - LOOP_KEYS(k, key) { - if(key->flag & PEK_SELECT) { - sel= 1; - key->flag &= ~PEK_SELECT; - pa->flag |= PARS_EDIT_RECALC; - } + LOOP_VISIBLE_POINTS { + LOOP_SELECTED_KEYS { + sel= 1; + key->flag &= ~PEK_SELECT; + point->flag |= PEP_EDIT_RECALC; } } if(sel==0) { - LOOP_PARTICLES(i, pa) { - if(pa->flag & PARS_HIDE) continue; - LOOP_KEYS(k, key) { + LOOP_VISIBLE_POINTS { + LOOP_KEYS { if(!(key->flag & PEK_SELECT)) { key->flag |= PEK_SELECT; - pa->flag |= PARS_EDIT_RECALC; + point->flag |= PEP_EDIT_RECALC; } } } @@ -1227,26 +1261,17 @@ int PE_mouse_particles(bContext *C, short *mval, int extend) PEData data; Scene *scene= CTX_data_scene(C); Object *ob= CTX_data_active_object(C); - ParticleSystem *psys= PE_get_current(scene, ob); - ParticleEdit *edit= 0; - ParticleData *pa; - ParticleEditKey *key; - int i, k, totpart; + PTCacheEdit *edit= PE_get_current(scene, ob); + POINT_P; KEY_K; - if(!PE_can_edit(psys)) + if(!PE_start_edit(edit)) return OPERATOR_CANCELLED; - edit= psys->edit; - totpart= psys->totpart; - if(!extend) { - LOOP_PARTICLES(i, pa) { - if(pa->flag & PARS_HIDE) continue; - LOOP_KEYS(k, key) { - if(key->flag & PEK_SELECT) { - key->flag &= ~PEK_SELECT; - pa->flag |= PARS_EDIT_RECALC; - } + LOOP_VISIBLE_POINTS { + LOOP_SELECTED_KEYS { + key->flag &= ~PEK_SELECT; + point->flag |= PEP_EDIT_RECALC; } } } @@ -1265,11 +1290,9 @@ int PE_mouse_particles(bContext *C, short *mval, int extend) /************************ select first operator ************************/ -static void select_root(PEData *data, int pa_index) +static void select_root(PEData *data, int point_index) { - ParticleSystem *psys= data->psys; - - psys->edit->keys[pa_index]->flag |= PEK_SELECT; + data->edit->points[point_index].keys->flag |= PEK_SELECT; } static int select_first_exec(bContext *C, wmOperator *op) @@ -1277,7 +1300,7 @@ static int select_first_exec(bContext *C, wmOperator *op) PEData data; PE_set_data(C, &data); - PE_foreach_particle(&data, select_root); + foreach_point(&data, select_root); WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, data.ob); return OPERATOR_FINISHED; @@ -1299,13 +1322,10 @@ void PARTICLE_OT_select_first(wmOperatorType *ot) /************************ select last operator ************************/ -static void select_tip(PEData *data, int pa_index) +static void select_tip(PEData *data, int point_index) { - ParticleSystem *psys= data->psys; - ParticleData *pa= psys->particles + pa_index; - ParticleEditKey *key= psys->edit->keys[pa_index] + pa->totkey-1; - - key->flag |= PEK_SELECT; + PTCacheEditPoint *point = data->edit->points + point_index; + point->keys[point->totkey - 1].flag |= PEK_SELECT; } static int select_last_exec(bContext *C, wmOperator *op) @@ -1313,7 +1333,7 @@ static int select_last_exec(bContext *C, wmOperator *op) PEData data; PE_set_data(C, &data); - PE_foreach_particle(&data, select_tip); + foreach_point(&data, select_tip); WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, data.ob); return OPERATOR_FINISHED; @@ -1396,10 +1416,10 @@ int PE_border_select(bContext *C, rcti *rect, int select) { Scene *scene= CTX_data_scene(C); Object *ob= CTX_data_active_object(C); - ParticleSystem *psys= PE_get_current(scene, ob); + PTCacheEdit *edit= PE_get_current(scene, ob); PEData data; - if(!PE_can_edit(psys)) + if(!PE_start_edit(edit)) return OPERATOR_CANCELLED; PE_set_view3d_data(C, &data); @@ -1420,10 +1440,10 @@ int PE_circle_select(bContext *C, int selecting, short *mval, float rad) { Scene *scene= CTX_data_scene(C); Object *ob= CTX_data_active_object(C); - ParticleSystem *psys= PE_get_current(scene, ob); + PTCacheEdit *edit= PE_get_current(scene, ob); PEData data; - if(!PE_can_edit(psys)) + if(!PE_start_edit(edit)) return OPERATOR_FINISHED; PE_set_view3d_data(C, &data); @@ -1446,47 +1466,42 @@ int PE_lasso_select(bContext *C, short mcords[][2], short moves, short select) Scene *scene= CTX_data_scene(C); Object *ob= CTX_data_active_object(C); ARegion *ar= CTX_wm_region(C); - ParticleSystem *psys= PE_get_current(scene, ob); - ParticleSystemModifierData *psmd; - ParticleEdit *edit; - ParticleData *pa; - ParticleEditKey *key; ParticleEditSettings *pset= PE_settings(scene); + PTCacheEdit *edit = PE_get_current(scene, ob); + ParticleSystem *psys = edit->psys; + ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys); + POINT_P; KEY_K; float co[3], mat[4][4]; short vertco[2]; - int i, k, totpart; - if(!PE_can_edit(psys)) + if(!PE_start_edit(edit)) return OPERATOR_CANCELLED; - psmd= psys_get_modifier(ob, psys); - edit= psys->edit; - totpart= psys->totpart; - - LOOP_PARTICLES(i, pa) { - if(pa->flag & PARS_HIDE) continue; + Mat4One(mat); - psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, mat); + LOOP_VISIBLE_POINTS { + if(edit->psys) + psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, psys->particles + p, mat); if(pset->selectmode==SCE_SELECT_POINT) { - LOOP_KEYS(k, key) { + LOOP_KEYS { VECCOPY(co, key->co); Mat4MulVecfl(mat, co); project_short(ar, co, vertco); if((vertco[0] != IS_CLIPPED) && lasso_inside(mcords,moves,vertco[0],vertco[1])) { if(select && !(key->flag & PEK_SELECT)) { key->flag |= PEK_SELECT; - pa->flag |= PARS_EDIT_RECALC; + point->flag |= PEP_EDIT_RECALC; } else if(key->flag & PEK_SELECT) { key->flag &= ~PEK_SELECT; - pa->flag |= PARS_EDIT_RECALC; + point->flag |= PEP_EDIT_RECALC; } } } } else if(pset->selectmode==SCE_SELECT_END) { - key= edit->keys[i] + pa->totkey - 1; + key= point->keys + point->totkey - 1; VECCOPY(co, key->co); Mat4MulVecfl(mat, co); @@ -1494,11 +1509,11 @@ int PE_lasso_select(bContext *C, short mcords[][2], short moves, short select) if((vertco[0] != IS_CLIPPED) && lasso_inside(mcords,moves,vertco[0],vertco[1])) { if(select && !(key->flag & PEK_SELECT)) { key->flag |= PEK_SELECT; - pa->flag |= PARS_EDIT_RECALC; + point->flag |= PEP_EDIT_RECALC; } else if(key->flag & PEK_SELECT) { key->flag &= ~PEK_SELECT; - pa->flag |= PARS_EDIT_RECALC; + point->flag |= PEP_EDIT_RECALC; } } } @@ -1516,35 +1531,25 @@ static int hide_exec(bContext *C, wmOperator *op) { Object *ob= CTX_data_active_object(C); Scene *scene= CTX_data_scene(C); - ParticleSystem *psys= PE_get_current(scene, ob); - ParticleEdit *edit; - ParticleEditKey *key; - ParticleData *pa; - int i, k, totpart; - - edit= psys->edit; - totpart= psys->totpart; + PTCacheEdit *edit= PE_get_current(scene, ob); + POINT_P; KEY_K; if(RNA_enum_get(op->ptr, "unselected")) { - LOOP_PARTICLES(i, pa) { - if(!particle_is_selected(psys, pa)) { - pa->flag |= PARS_HIDE; - pa->flag |= PARS_EDIT_RECALC; + LOOP_UNSELECTED_POINTS { + point->flag |= PEP_HIDE; + point->flag |= PEP_EDIT_RECALC; - LOOP_KEYS(k, key) - key->flag &= ~PEK_SELECT; - } + LOOP_KEYS + key->flag &= ~PEK_SELECT; } } else { - LOOP_PARTICLES(i, pa) { - if(particle_is_selected(psys, pa)) { - pa->flag |= PARS_HIDE; - pa->flag |= PARS_EDIT_RECALC; + LOOP_SELECTED_POINTS { + point->flag |= PEP_HIDE; + point->flag |= PEP_EDIT_RECALC; - LOOP_KEYS(k, key) - key->flag &= ~PEK_SELECT; - } + LOOP_KEYS + key->flag &= ~PEK_SELECT; } } @@ -1577,21 +1582,15 @@ static int reveal_exec(bContext *C, wmOperator *op) { Object *ob= CTX_data_active_object(C); Scene *scene= CTX_data_scene(C); - ParticleSystem *psys= PE_get_current(scene, ob); - ParticleEdit *edit; - ParticleEditKey *key; - ParticleData *pa; - int i, k, totpart; - - edit= psys->edit; - totpart= psys->totpart; + PTCacheEdit *edit= PE_get_current(scene, ob); + POINT_P; KEY_K; - LOOP_PARTICLES(i, pa) { - if(pa->flag & PARS_HIDE) { - pa->flag &= ~PARS_HIDE; - pa->flag |= PARS_EDIT_RECALC; + LOOP_POINTS { + if(point->flag & PEP_HIDE) { + point->flag &= ~PEP_HIDE; + point->flag |= PEP_EDIT_RECALC; - LOOP_KEYS(k, key) + LOOP_KEYS key->flag |= PEK_SELECT; } } @@ -1618,34 +1617,30 @@ void PARTICLE_OT_reveal(wmOperatorType *ot) /************************ select less operator ************************/ -static void select_less_keys(PEData *data, int pa_index) +static void select_less_keys(PEData *data, int point_index) { - ParticleSystem *psys= data->psys; - ParticleEdit *edit= psys->edit; - ParticleData *pa= &psys->particles[pa_index]; - ParticleEditKey *key; - int k; - - for(k=0,key=edit->keys[pa_index]; k<pa->totkey; k++,key++) { - if((key->flag & PEK_SELECT)==0) continue; + PTCacheEdit *edit= data->edit; + PTCacheEditPoint *point = edit->points + point_index; + KEY_K; + LOOP_SELECTED_KEYS { if(k==0) { if(((key+1)->flag&PEK_SELECT)==0) - key->flag |= PEK_TO_SELECT; + key->flag |= PEK_TAG; } - else if(k==pa->totkey-1) { + else if(k==point->totkey-1) { if(((key-1)->flag&PEK_SELECT)==0) - key->flag |= PEK_TO_SELECT; + key->flag |= PEK_TAG; } else { if((((key-1)->flag & (key+1)->flag) & PEK_SELECT)==0) - key->flag |= PEK_TO_SELECT; + key->flag |= PEK_TAG; } } - for(k=0,key=edit->keys[pa_index]; k<pa->totkey; k++,key++) { - if(key->flag&PEK_TO_SELECT) - key->flag &= ~(PEK_TO_SELECT|PEK_SELECT); + LOOP_KEYS { + if(key->flag&PEK_TAG) + key->flag &= ~(PEK_TAG|PEK_SELECT); } } @@ -1654,7 +1649,7 @@ static int select_less_exec(bContext *C, wmOperator *op) PEData data; PE_set_data(C, &data); - PE_foreach_particle(&data, select_less_keys); + foreach_point(&data, select_less_keys); WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, data.ob); return OPERATOR_FINISHED; @@ -1676,34 +1671,32 @@ void PARTICLE_OT_select_less(wmOperatorType *ot) /************************ select more operator ************************/ -static void select_more_keys(PEData *data, int pa_index) +static void select_more_keys(PEData *data, int point_index) { - ParticleSystem *psys= data->psys; - ParticleEdit *edit= psys->edit; - ParticleData *pa= &psys->particles[pa_index]; - ParticleEditKey *key; - int k; + PTCacheEdit *edit= data->edit; + PTCacheEditPoint *point = edit->points + point_index; + KEY_K; - for(k=0,key=edit->keys[pa_index]; k<pa->totkey; k++,key++) { + LOOP_KEYS { if(key->flag & PEK_SELECT) continue; if(k==0) { if((key+1)->flag&PEK_SELECT) - key->flag |= PEK_TO_SELECT; + key->flag |= PEK_TAG; } - else if(k==pa->totkey-1) { + else if(k==point->totkey-1) { if((key-1)->flag&PEK_SELECT) - key->flag |= PEK_TO_SELECT; + key->flag |= PEK_TAG; } else { if(((key-1)->flag | (key+1)->flag) & PEK_SELECT) - key->flag |= PEK_TO_SELECT; + key->flag |= PEK_TAG; } } - for(k=0,key=edit->keys[pa_index]; k<pa->totkey; k++,key++) { - if(key->flag&PEK_TO_SELECT) { - key->flag &= ~PEK_TO_SELECT; + LOOP_KEYS { + if(key->flag&PEK_TAG) { + key->flag &= ~PEK_TAG; key->flag |= PEK_SELECT; } } @@ -1714,7 +1707,7 @@ static int select_more_exec(bContext *C, wmOperator *op) PEData data; PE_set_data(C, &data); - PE_foreach_particle(&data, select_more_keys); + foreach_point(&data, select_more_keys); WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, data.ob); return OPERATOR_FINISHED; @@ -1738,12 +1731,13 @@ void PARTICLE_OT_select_more(wmOperatorType *ot) static void rekey_particle(PEData *data, int pa_index) { - ParticleSystem *psys= data->psys; - ParticleData *pa= &psys->particles[pa_index]; - ParticleEdit *edit= psys->edit; + PTCacheEdit *edit= data->edit; + ParticleSystem *psys= edit->psys; + ParticleData *pa= psys->particles + pa_index; + PTCacheEditPoint *point = edit->points + pa_index; ParticleKey state; HairKey *key, *new_keys; - ParticleEditKey *ekey; + PTCacheEditKey *ekey; float dval, sta, end; int k; @@ -1772,19 +1766,21 @@ static void rekey_particle(PEData *data, int pa_index) MEM_freeN(pa->hair); pa->hair= new_keys; - pa->totkey=data->totrekey; + point->totkey=pa->totkey=data->totrekey; - if(edit->keys[pa_index]) - MEM_freeN(edit->keys[pa_index]); - ekey= edit->keys[pa_index]= MEM_callocN(pa->totkey * sizeof(ParticleEditKey),"Hair re-key edit keys"); + + if(point->keys) + MEM_freeN(point->keys); + ekey= point->keys= MEM_callocN(pa->totkey * sizeof(PTCacheEditKey),"Hair re-key edit keys"); 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; } pa->flag &= ~PARS_REKEY; - pa->flag |= PARS_EDIT_RECALC; + point->flag |= PEP_EDIT_RECALC; } static int rekey_exec(bContext *C, wmOperator *op) @@ -1796,11 +1792,9 @@ static int rekey_exec(bContext *C, wmOperator *op) data.dval= 1.0f / (float)(data.totrekey-1); data.totrekey= RNA_int_get(op->ptr, "keys"); - foreach_selected_particle(&data, rekey_particle); - - data.psys->edit->totkeys= psys_count_keys(data.psys); - recalc_lengths(data.psys); + foreach_selected_point(&data, rekey_particle); + recalc_lengths(data.edit); PE_update_object(data.scene, data.ob, 1); WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, data.ob); @@ -1827,19 +1821,19 @@ void PARTICLE_OT_rekey(wmOperatorType *ot) static void rekey_particle_to_time(Scene *scene, Object *ob, int pa_index, float path_time) { - ParticleSystem *psys= PE_get_current(scene, ob); - ParticleEdit *edit=0; + PTCacheEdit *edit= PE_get_current(scene, ob); + ParticleSystem *psys; ParticleData *pa; ParticleKey state; HairKey *new_keys, *key; - ParticleEditKey *ekey; + PTCacheEditKey *ekey; int k; - if(psys==0) return; + if(!edit || !edit->psys) return; - edit= psys->edit; + psys = edit->psys; - pa= &psys->particles[pa_index]; + pa= psys->particles + pa_index; pa->flag |= PARS_REKEY; @@ -1858,7 +1852,7 @@ static void rekey_particle_to_time(Scene *scene, Object *ob, int pa_index, float pa->hair= new_keys; /* update edit pointers */ - for(k=0, key=pa->hair, ekey=edit->keys[pa_index]; k<pa->totkey; k++, key++, ekey++) { + for(k=0, key=pa->hair, ekey=edit->points[pa_index].keys; k<pa->totkey; k++, key++, ekey++) { ekey->co= key->co; ekey->time= &key->time; } @@ -1870,10 +1864,11 @@ 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) { - ParticleEdit *edit= psys->edit; + PTCacheEdit *edit = psys->edit; ParticleEditSettings *pset= PE_settings(scene); ParticleData *pa, *npa=0, *new_pars=0; - ParticleEditKey **key, **nkey=0, **new_keys=0; + POINT_P; + PTCacheEditPoint *npoint=0, *new_points=0; ParticleSystemModifierData *psmd; int i, totpart, new_totpart= psys->totpart, removed= 0; @@ -1882,55 +1877,51 @@ static int remove_tagged_particles(Scene *scene, Object *ob, ParticleSystem *psy psmd= psys_get_modifier(ob, psys); totpart= psys->totpart; - LOOP_PARTICLES(i, pa) - if(pa->flag & PARS_TAG) - PE_mirror_particle(ob, psmd->dm, psys, pa, NULL); + LOOP_TAGGED_POINTS { + PE_mirror_particle(ob, psmd->dm, psys, psys->particles + p, NULL); + } } - for(i=0, pa=psys->particles; i<psys->totpart; i++, pa++) { - if(pa->flag & PARS_TAG) { - new_totpart--; - removed++; - } + LOOP_TAGGED_POINTS { + new_totpart--; + removed++; } if(new_totpart != psys->totpart) { if(new_totpart) { npa= new_pars= MEM_callocN(new_totpart * sizeof(ParticleData), "ParticleData array"); - nkey= new_keys= MEM_callocN(new_totpart * sizeof(ParticleEditKey *), "ParticleEditKey array"); + npoint= new_points= MEM_callocN(new_totpart * sizeof(PTCacheEditPoint), "PTCacheEditKey array"); } pa= psys->particles; - key= edit->keys; - for(i=0; i<psys->totpart; i++, pa++, key++) { - if(pa->flag & PARS_TAG) { - if(*key) - MEM_freeN(*key); + point= edit->points; + for(i=0; i<psys->totpart; i++, pa++, point++) { + if(point->flag & PEP_TAG) { + if(point->keys) + MEM_freeN(point->keys); if(pa->hair) MEM_freeN(pa->hair); } else { memcpy(npa, pa, sizeof(ParticleData)); - memcpy(nkey, key, sizeof(ParticleEditKey*)); + memcpy(npoint, point, sizeof(PTCacheEditPoint)); npa++; - nkey++; + npoint++; } } if(psys->particles) MEM_freeN(psys->particles); psys->particles= new_pars; - if(edit->keys) MEM_freeN(edit->keys); - edit->keys= new_keys; + if(edit->points) MEM_freeN(edit->points); + edit->points= new_points; if(edit->mirror_cache) { MEM_freeN(edit->mirror_cache); edit->mirror_cache= NULL; } - psys->totpart= new_totpart; - - edit->totkeys= psys_count_keys(psys); + edit->totpoint= psys->totpart= new_totpart; } return removed; @@ -1938,84 +1929,82 @@ static int remove_tagged_particles(Scene *scene, Object *ob, ParticleSystem *psy static void remove_tagged_keys(Scene *scene, Object *ob, ParticleSystem *psys) { - ParticleEdit *edit= psys->edit; + PTCacheEdit *edit= psys->edit; ParticleEditSettings *pset= PE_settings(scene); ParticleData *pa; - HairKey *key, *nkey, *new_keys=0; - ParticleEditKey *ekey; + HairKey *hkey, *nhkey, *new_hkeys=0; + POINT_P; KEY_K; ParticleSystemModifierData *psmd; - int i, k, totpart= psys->totpart; short new_totkey; if(pset->flag & PE_X_MIRROR) { /* mirror key tags */ psmd= psys_get_modifier(ob, psys); - LOOP_PARTICLES(i, pa) { - LOOP_KEYS(k,ekey) { - if(ekey->flag & PEK_TAG) { - PE_mirror_particle(ob, psmd->dm, psys, pa, NULL); - break; - } + LOOP_POINTS { + LOOP_TAGGED_KEYS { + PE_mirror_particle(ob, psmd->dm, psys, psys->particles + p, NULL); + break; } } } - LOOP_PARTICLES(i, pa) { - new_totkey= pa->totkey; - LOOP_KEYS(k,ekey) { - if(ekey->flag & PEK_TAG) - new_totkey--; + LOOP_POINTS { + new_totkey= point->totkey; + LOOP_TAGGED_KEYS { + new_totkey--; } /* we can't have elements with less than two keys*/ if(new_totkey < 2) - pa->flag |= PARS_TAG; + point->flag |= PEP_TAG; } remove_tagged_particles(scene, ob, psys); - totpart= psys->totpart; - - LOOP_PARTICLES(i, pa) { + LOOP_POINTS { + pa = psys->particles + p; new_totkey= pa->totkey; - LOOP_KEYS(k,ekey) { - if(ekey->flag & PEK_TAG) - new_totkey--; + + LOOP_TAGGED_KEYS { + new_totkey--; } + if(new_totkey != pa->totkey) { - key= pa->hair; - nkey= new_keys= MEM_callocN(new_totkey*sizeof(HairKey), "HairKeys"); + hkey= pa->hair; + nhkey= new_hkeys= MEM_callocN(new_totkey*sizeof(HairKey), "HairKeys"); - for(k=0, ekey=edit->keys[i]; k<new_totkey; k++, key++, nkey++, ekey++) { - while(ekey->flag & PEK_TAG && key < pa->hair + pa->totkey) { + LOOP_KEYS { + while(key->flag & PEK_TAG && hkey < pa->hair + pa->totkey) { key++; - ekey++; + hkey++; } - if(key < pa->hair + pa->totkey) { - VECCOPY(nkey->co, key->co); - nkey->time= key->time; - nkey->weight= key->weight; + if(hkey < pa->hair + pa->totkey) { + VECCOPY(nhkey->co, hkey->co); + nhkey->time= hkey->time; + nhkey->weight= hkey->weight; } + hkey++; + nhkey++; } if(pa->hair) MEM_freeN(pa->hair); - pa->hair= new_keys; + pa->hair= new_hkeys; - pa->totkey=new_totkey; + point->totkey= pa->totkey= new_totkey; - if(edit->keys[i]) - MEM_freeN(edit->keys[i]); - ekey= edit->keys[i]= MEM_callocN(new_totkey*sizeof(ParticleEditKey), "particle edit keys"); + if(point->keys) + MEM_freeN(point->keys); + key= point->keys= MEM_callocN(new_totkey*sizeof(PTCacheEditKey), "particle edit keys"); - for(k=0, key=pa->hair; k<pa->totkey; k++, key++, ekey++) { - ekey->co= key->co; - ekey->time= &key->time; + hkey = pa->hair; + LOOP_KEYS { + key->co= hkey->co; + key->time= &hkey->time; + hkey++; } } } - - edit->totkeys= psys_count_keys(psys); } /************************ subdivide opertor *********************/ @@ -2023,19 +2012,19 @@ static void remove_tagged_keys(Scene *scene, Object *ob, ParticleSystem *psys) /* works like normal edit mode subdivide, inserts keys between neighbouring selected keys */ static void subdivide_particle(PEData *data, int pa_index) { - ParticleSystem *psys= data->psys; - ParticleEdit *edit= psys->edit; - ParticleData *pa= &psys->particles[pa_index]; - + PTCacheEdit *edit= data->edit; + ParticleSystem *psys= edit->psys; + ParticleData *pa= psys->particles + pa_index; + PTCacheEditPoint *point = edit->points + pa_index; ParticleKey state; HairKey *key, *nkey, *new_keys; - ParticleEditKey *ekey, *nekey, *new_ekeys; + PTCacheEditKey *ekey, *nekey, *new_ekeys; int k; short totnewkey=0; float endtime; - for(k=0, ekey=edit->keys[pa_index]; k<pa->totkey-1; k++,ekey++) { + for(k=0, ekey=point->keys; k<pa->totkey-1; k++,ekey++) { if(ekey->flag&PEK_SELECT && (ekey+1)->flag&PEK_SELECT) totnewkey++; } @@ -2045,13 +2034,13 @@ static void subdivide_particle(PEData *data, int pa_index) pa->flag |= PARS_REKEY; nkey= new_keys= MEM_callocN((pa->totkey+totnewkey)*(sizeof(HairKey)),"Hair subdivide keys"); - nekey= new_ekeys= MEM_callocN((pa->totkey+totnewkey)*(sizeof(ParticleEditKey)),"Hair subdivide edit keys"); + nekey= new_ekeys= MEM_callocN((pa->totkey+totnewkey)*(sizeof(PTCacheEditKey)),"Hair subdivide edit keys"); endtime= pa->hair[pa->totkey-1].time; - for(k=0, key=pa->hair, ekey=edit->keys[pa_index]; k<pa->totkey-1; k++, key++, ekey++) { + for(k=0, key=pa->hair, ekey=point->keys; k<pa->totkey-1; k++, key++, ekey++) { memcpy(nkey,key,sizeof(HairKey)); - memcpy(nekey,ekey,sizeof(ParticleEditKey)); + memcpy(nekey,ekey,sizeof(PTCacheEditKey)); nekey->co= nkey->co; nekey->time= &nkey->time; @@ -2067,7 +2056,7 @@ static void subdivide_particle(PEData *data, int pa_index) nekey->co= nkey->co; nekey->time= &nkey->time; - nekey->flag |= PEK_SELECT; + nekey->flag |= (PEK_SELECT|PEK_USE_WCO); nekey++; nkey++; @@ -2075,7 +2064,7 @@ static void subdivide_particle(PEData *data, int pa_index) } /*tip still not copied*/ memcpy(nkey,key,sizeof(HairKey)); - memcpy(nekey,ekey,sizeof(ParticleEditKey)); + memcpy(nekey,ekey,sizeof(PTCacheEditKey)); nekey->co= nkey->co; nekey->time= &nkey->time; @@ -2084,13 +2073,12 @@ static void subdivide_particle(PEData *data, int pa_index) MEM_freeN(pa->hair); pa->hair= new_keys; - if(edit->keys[pa_index]) - MEM_freeN(edit->keys[pa_index]); + if(point->keys) + MEM_freeN(point->keys); + point->keys= new_ekeys; - edit->keys[pa_index]= new_ekeys; - - pa->totkey += totnewkey; - pa->flag |= PARS_EDIT_RECALC; + point->totkey = pa->totkey = pa->totkey + totnewkey; + point->flag |= PEP_EDIT_RECALC; pa->flag &= ~PARS_REKEY; } @@ -2099,13 +2087,9 @@ static int subdivide_exec(bContext *C, wmOperator *op) PEData data; PE_set_data(C, &data); - PE_foreach_particle(&data, subdivide_particle); - - data.psys->edit->totkeys= psys_count_keys(data.psys); + foreach_point(&data, subdivide_particle); - recalc_lengths(data.psys); - psys_update_world_cos(data.ob, data.psys); - + recalc_lengths(data.edit); PE_update_object(data.scene, data.ob, 1); WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, data.ob); @@ -2132,15 +2116,15 @@ static int remove_doubles_exec(bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); Object *ob= CTX_data_active_object(C); - ParticleSystem *psys= PE_get_current(scene, ob); ParticleEditSettings *pset=PE_settings(scene); - ParticleData *pa; - ParticleEdit *edit; + PTCacheEdit *edit= PE_get_current(scene, ob); + ParticleSystem *psys = edit->psys; ParticleSystemModifierData *psmd; KDTree *tree; KDTreeNearest nearest[10]; + POINT_P; float mat[4][4], co[3], threshold= RNA_float_get(op->ptr, "threshold"); - int i, n, totn, removed, totpart, flag, totremoved; + int n, totn, removed, flag, totremoved; edit= psys->edit; psmd= psys_get_modifier(ob, psys); @@ -2149,37 +2133,32 @@ static int remove_doubles_exec(bContext *C, wmOperator *op) do { removed= 0; - totpart= psys->totpart; - tree=BLI_kdtree_new(totpart); + tree=BLI_kdtree_new(psys->totpart); /* insert particles into kd tree */ - LOOP_PARTICLES(i, pa) { - if(particle_is_selected(psys, pa)) { - psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, pa, mat); - VECCOPY(co, pa->hair[0].co); - Mat4MulVecfl(mat, co); - BLI_kdtree_insert(tree, i, co, NULL); - } + LOOP_SELECTED_POINTS { + psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, psys->particles+p, mat); + VECCOPY(co, point->keys->co); + Mat4MulVecfl(mat, co); + BLI_kdtree_insert(tree, p, co, NULL); } BLI_kdtree_balance(tree); /* tag particles to be removed */ - LOOP_PARTICLES(i, pa) { - if(particle_is_selected(psys, pa)) { - psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, pa, mat); - VECCOPY(co, pa->hair[0].co); - Mat4MulVecfl(mat, co); + LOOP_SELECTED_POINTS { + psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, psys->particles+p, mat); + VECCOPY(co, point->keys->co); + Mat4MulVecfl(mat, co); - totn= BLI_kdtree_find_n_nearest(tree,10,co,NULL,nearest); + totn= BLI_kdtree_find_n_nearest(tree,10,co,NULL,nearest); - for(n=0; n<totn; n++) { - /* this needs a custom threshold still */ - if(nearest[n].index > i && nearest[n].dist < threshold) { - if(!(pa->flag & PARS_TAG)) { - pa->flag |= PARS_TAG; - removed++; - } + for(n=0; n<totn; n++) { + /* this needs a custom threshold still */ + if(nearest[n].index > p && nearest[n].dist < threshold) { + if(!(point->flag & PEP_TAG)) { + point->flag |= PEP_TAG; + removed++; } } } @@ -2200,7 +2179,7 @@ static int remove_doubles_exec(bContext *C, wmOperator *op) BKE_reportf(op->reports, RPT_INFO, "Remove %d double particles.", totremoved); - psys_update_world_cos(ob, psys); + PE_update_object(scene, ob, 0); DAG_object_flush_update(scene, ob, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, ob); @@ -2347,16 +2326,16 @@ static EnumPropertyItem delete_type_items[]= { static void set_delete_particle(PEData *data, int pa_index) { - ParticleSystem *psys= data->psys; + PTCacheEdit *edit= data->edit; - psys->particles[pa_index].flag |= PARS_TAG; + edit->points[pa_index].flag |= PEP_TAG; } static void set_delete_particle_key(PEData *data, int pa_index, int key_index) { - ParticleSystem *psys= data->psys; + PTCacheEdit *edit= data->edit; - psys->edit->keys[pa_index][key_index].flag |= PEK_TAG; + edit->points[pa_index].keys[key_index].flag |= PEK_TAG; } static int delete_exec(bContext *C, wmOperator *op) @@ -2368,15 +2347,17 @@ static int delete_exec(bContext *C, wmOperator *op) if(type == DEL_KEY) { foreach_selected_key(&data, set_delete_particle_key); - remove_tagged_keys(data.scene, data.ob, data.psys); - recalc_lengths(data.psys); + remove_tagged_keys(data.scene, data.ob, data.edit->psys); + recalc_lengths(data.edit); } else if(type == DEL_PARTICLE) { - foreach_selected_particle(&data, set_delete_particle); - remove_tagged_particles(data.scene, data.ob, data.psys); - recalc_lengths(data.psys); + foreach_selected_point(&data, set_delete_particle); + remove_tagged_particles(data.scene, data.ob, data.edit->psys); + recalc_lengths(data.edit); } + PE_update_object(data.scene, data.ob, 0); + DAG_object_flush_update(data.scene, data.ob, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, data.ob); @@ -2407,15 +2388,15 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged) { Mesh *me= (Mesh*)(ob->data); ParticleSystemModifierData *psmd; - ParticleSystem *psys= PE_get_current(scene, ob); - ParticleEdit *edit; + PTCacheEdit *edit= PE_get_current(scene, ob); + ParticleSystem *psys = edit->psys; ParticleData *pa, *newpa, *new_pars; - ParticleEditKey *ekey, **newkey, **key, **new_keys; + PTCacheEditPoint *newpoint, *new_points; + POINT_P; KEY_K; HairKey *hkey; int *mirrorfaces; - int i, k, rotation, totpart, newtotpart; + int rotation, totpart, newtotpart; - edit= psys->edit; psmd= psys_get_modifier(ob, psys); mirrorfaces= mesh_get_x_mirror_faces(ob, NULL); @@ -2425,29 +2406,28 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged) totpart= psys->totpart; newtotpart= psys->totpart; - LOOP_PARTICLES(i, pa) { - if(pa->flag & PARS_HIDE) continue; - + LOOP_VISIBLE_POINTS { + pa = psys->particles + p; if(!tagged) { - if(particle_is_selected(psys, pa)) { - if(edit->mirror_cache[i] != -1) { + if(point_is_selected(point)) { + if(edit->mirror_cache[p] != -1) { /* already has a mirror, don't need to duplicate */ PE_mirror_particle(ob, psmd->dm, psys, pa, NULL); continue; } else - pa->flag |= PARS_TAG; + point->flag |= PEP_TAG; } } - if((pa->flag & PARS_TAG) && mirrorfaces[pa->num*2] != -1) + if((point->flag & PEP_TAG) && mirrorfaces[pa->num*2] != -1) newtotpart++; } if(newtotpart != psys->totpart) { /* allocate new arrays and copy existing */ new_pars= MEM_callocN(newtotpart*sizeof(ParticleData), "ParticleData new"); - new_keys= MEM_callocN(newtotpart*sizeof(ParticleEditKey*), "ParticleEditKey new"); + new_points= MEM_callocN(newtotpart*sizeof(PTCacheEditPoint), "PTCacheEditPoint new"); if(psys->particles) { memcpy(new_pars, psys->particles, totpart*sizeof(ParticleData)); @@ -2455,36 +2435,35 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged) } psys->particles= new_pars; - if(edit->keys) { - memcpy(new_keys, edit->keys, totpart*sizeof(ParticleEditKey*)); - MEM_freeN(edit->keys); + if(edit->points) { + memcpy(new_points, edit->points, totpart*sizeof(PTCacheEditPoint)); + MEM_freeN(edit->points); } - edit->keys= new_keys; + edit->points= new_points; if(edit->mirror_cache) { MEM_freeN(edit->mirror_cache); edit->mirror_cache= NULL; } - psys->totpart= newtotpart; + edit->totpoint= psys->totpart= newtotpart; /* create new elements */ - pa= psys->particles; newpa= psys->particles + totpart; - key= edit->keys; - newkey= edit->keys + totpart; + newpoint= edit->points + totpart; - for(i=0; i<totpart; i++, pa++, key++) { - if(pa->flag & PARS_HIDE) continue; + LOOP_VISIBLE_POINTS { + pa = psys->particles + p; - if(!(pa->flag & PARS_TAG) || mirrorfaces[pa->num*2] == -1) + if(!(point->flag & PEP_TAG) || mirrorfaces[pa->num*2] == -1) continue; /* duplicate */ *newpa= *pa; + *newpoint= *point; if(pa->hair) newpa->hair= MEM_dupallocN(pa->hair); if(pa->keys) newpa->keys= MEM_dupallocN(pa->keys); - if(*key) *newkey= MEM_dupallocN(*key); + if(point->keys) newpoint->keys= MEM_dupallocN(point->keys); /* rotate weights according to vertex index rotation */ rotation= mirrorfaces[pa->num*2+1]; @@ -2503,24 +2482,23 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged) newpa->num_dmcache= psys_particle_dm_face_lookup(ob,psmd->dm,newpa->num,newpa->fuv, NULL); /* update edit key pointers */ - ekey= *newkey; - for(k=0, hkey=newpa->hair; k<newpa->totkey; k++, hkey++, ekey++) { - ekey->co= hkey->co; - ekey->time= &hkey->time; + key= newpoint->keys; + for(k=0, hkey=newpa->hair; k<newpa->totkey; k++, hkey++, key++) { + key->co= hkey->co; + key->time= &hkey->time; } /* map key positions as mirror over x axis */ PE_mirror_particle(ob, psmd->dm, psys, pa, newpa); newpa++; - newkey++; + newpoint++; } - - edit->totkeys= psys_count_keys(psys); } - for(pa=psys->particles, i=0; i<psys->totpart; i++, pa++) - pa->flag &= ~PARS_TAG; + LOOP_POINTS { + point->flag &= ~PEP_TAG; + } MEM_freeN(mirrorfaces); } @@ -2529,11 +2507,11 @@ static int mirror_exec(bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); Object *ob= CTX_data_active_object(C); - ParticleSystem *psys= PE_get_current(scene, ob); + PTCacheEdit *edit= PE_get_current(scene, ob); PE_mirror_x(scene, ob, 0); - psys_update_world_cos(ob, psys); + update_world_cos(ob, edit); WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, ob); DAG_object_flush_update(scene, ob, OB_RECALC_DATA); @@ -2560,7 +2538,6 @@ 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_WEIGHT, "WEIGHT", 0, "Weight", ""}, {PE_BRUSH_ADD, "ADD", 0, "Add", ""}, {PE_BRUSH_LENGTH, "LENGTH", 0, "Length", ""}, {PE_BRUSH_PUFF, "PUFF", 0, "Puff", ""}, @@ -2593,14 +2570,46 @@ void PARTICLE_OT_brush_set(wmOperatorType *ot) 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 Brush"; + ot->idname= "PARTICLE_OT_edit_type_set"; + + /* api callbacks */ + ot->exec= set_brush_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 pa_index, int key_index) +static void brush_comb(PEData *data, float mat[][4], float imat[][4], int point_index, int key_index, PTCacheEditKey *key) { - ParticleSystem *psys= data->psys; - ParticleData *pa= &psys->particles[pa_index]; ParticleEditSettings *pset= PE_settings(data->scene); - HairKey *key= pa->hair + key_index; float cvec[3], fac; if(pset->flag & PE_LOCK_FIRST && key_index == 0) return; @@ -2612,19 +2621,21 @@ static void brush_comb(PEData *data, float mat[][4], float imat[][4], int pa_ind VecMulf(cvec, fac); VECADD(key->co, key->co, cvec); - pa->flag |= PARS_EDIT_RECALC; + (data->edit->points + point_index)->flag |= PEP_EDIT_RECALC; } static void brush_cut(PEData *data, int pa_index) { - ParticleSystem *psys= data->psys; + PTCacheEdit *edit = data->edit; + ParticleSystem *psys= edit->psys; ARegion *ar= data->vc.ar; Object *ob= data->ob; + ParticleEditSettings *pset= PE_settings(data->scene); ParticleData *pa= &psys->particles[pa_index]; - ParticleCacheKey *key= psys->pathcache[pa_index]; + ParticleCacheKey *key= edit->pathcache[pa_index]; float rad2, cut_time= 1.0; float x0, x1, v0, v1, o0, o1, xo0, xo1, d, dv; - int k, cut, keys= (int)pow(2.0, (double)psys->part->draw_step); + int k, cut, keys= (int)pow(2.0, (double)pset->draw_step); short vertco[2]; /* blunt scissors */ @@ -2699,93 +2710,97 @@ static void brush_cut(PEData *data, int pa_index) if(cut) { if(cut_time < 0.0f) { - pa->flag |= PARS_TAG; + edit->points[pa_index].flag |= PEP_TAG; } else { rekey_particle_to_time(data->scene, ob, pa_index, cut_time); - pa->flag |= PARS_EDIT_RECALC; + edit->points[pa_index].flag |= PEP_EDIT_RECALC; } } } -static void brush_length(PEData *data, int pa_index) +static void brush_length(PEData *data, int point_index) { - ParticleSystem *psys= data->psys; - ParticleData *pa= &psys->particles[pa_index]; - HairKey *key; + PTCacheEdit *edit= data->edit; + PTCacheEditPoint *point = edit->points + point_index; + KEY_K; float dvec[3],pvec[3]; - int k; - key= pa->hair; - VECCOPY(pvec,key->co); - - for(k=1, key++; k<pa->totkey; k++,key++) { - VECSUB(dvec,key->co,pvec); - VECCOPY(pvec,key->co); - VecMulf(dvec,data->growfac); - VECADD(key->co,(key-1)->co,dvec); + LOOP_KEYS { + if(k==0) { + VECCOPY(pvec,key->co); + } + else { + VECSUB(dvec,key->co,pvec); + VECCOPY(pvec,key->co); + VecMulf(dvec,data->growfac); + VECADD(key->co,(key-1)->co,dvec); + } } - pa->flag |= PARS_EDIT_RECALC; + point->flag |= PEP_EDIT_RECALC; } -static void brush_puff(PEData *data, int pa_index) +static void brush_puff(PEData *data, int point_index) { - ParticleSystem *psys= data->psys; - ParticleData *pa= &psys->particles[pa_index]; - ParticleEdit *edit= psys->edit; - HairKey *key; + PTCacheEdit *edit = data->edit; + ParticleSystem *psys = edit->psys; + PTCacheEditPoint *point = edit->points + point_index; + KEY_K; float mat[4][4], imat[4][4]; float lastco[3], rootco[3], co[3], nor[3], kco[3], dco[3], fac, length; - int k; - - psys_mat_hair_to_global(data->ob, data->dm, psys->part->from, pa, mat); - Mat4Invert(imat,mat); - /* find root coordinate and normal on emitter */ - key= pa->hair; - VECCOPY(co, key->co); - Mat4MulVecfl(mat, co); + if(psys) { + psys_mat_hair_to_global(data->ob, data->dm, psys->part->from, psys->particles + point_index, mat); + Mat4Invert(imat,mat); + } + else { + Mat4One(mat); + Mat4One(imat); + } - pa_index= BLI_kdtree_find_nearest(edit->emitter_field, co, NULL, NULL); - if(pa_index == -1) return; + LOOP_KEYS { + if(k==0) { + /* find root coordinate and normal on emitter */ + VECCOPY(co, key->co); + Mat4MulVecfl(mat, co); - VECCOPY(rootco, co); - VecCopyf(nor, &psys->edit->emitter_cosnos[pa_index*6+3]); - Normalize(nor); - length= 0.0f; + point_index= BLI_kdtree_find_nearest(edit->emitter_field, co, NULL, NULL); + if(point_index == -1) return; - fac= (float)pow((double)(1.0f - data->dist / data->rad), (double)data->pufffac); - fac *= 0.025f; - if(data->invert) - fac= -fac; + VECCOPY(rootco, co); + VecCopyf(nor, &edit->emitter_cosnos[point_index*6+3]); + Normalize(nor); + length= 0.0f; - for(k=1, key++; k<pa->totkey; k++, key++) { - /* compute position as if hair was standing up straight */ - VECCOPY(lastco, co); - VECCOPY(co, key->co); - Mat4MulVecfl(mat, co); - length += VecLenf(lastco, co); + fac= (float)pow((double)(1.0f - data->dist / data->rad), (double)data->pufffac); + fac *= 0.025f; + if(data->invert) + fac= -fac; + } + else { + /* compute position as if hair was standing up straight */ + VECCOPY(lastco, co); + VECCOPY(co, key->co); + Mat4MulVecfl(mat, co); + length += VecLenf(lastco, co); - 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); - VECCOPY(key->co, co); - Mat4MulVecfl(imat, key->co); + VECCOPY(key->co, co); + Mat4MulVecfl(imat, key->co); + } } - pa->flag |= PARS_EDIT_RECALC; + point->flag |= PEP_EDIT_RECALC; } -static void brush_smooth_get(PEData *data, float mat[][4], float imat[][4], int pa_index, int key_index) -{ - ParticleSystem *psys= data->psys; - ParticleData *pa= &psys->particles[pa_index]; - HairKey *key= pa->hair + key_index; - +static void brush_smooth_get(PEData *data, float mat[][4], float imat[][4], int point_index, int key_index, PTCacheEditKey *key) +{ if(key_index) { float dvec[3]; @@ -2796,11 +2811,8 @@ static void brush_smooth_get(PEData *data, float mat[][4], float imat[][4], int } } -static void brush_smooth_do(PEData *data, float mat[][4], float imat[][4], int pa_index, int key_index) +static void brush_smooth_do(PEData *data, float mat[][4], float imat[][4], int point_index, int key_index, PTCacheEditKey *key) { - ParticleSystem *psys= data->psys; - ParticleData *pa= &psys->particles[pa_index]; - HairKey *key= pa->hair + key_index; float vec[3], dvec[3]; if(key_index) { @@ -2815,18 +2827,18 @@ static void brush_smooth_do(PEData *data, float mat[][4], float imat[][4], int p VECADD(key->co,key->co,dvec); } - pa->flag |= PARS_EDIT_RECALC; + (data->edit->points + point_index)->flag |= PEP_EDIT_RECALC; } static void brush_add(PEData *data, short number) { Scene *scene= data->scene; Object *ob= data->ob; - ParticleSystem *psys= data->psys; + PTCacheEdit *edit = data->edit; + ParticleSystem *psys= edit->psys; ParticleData *add_pars= MEM_callocN(number*sizeof(ParticleData),"ParticleData add"); ParticleSystemModifierData *psmd= psys_get_modifier(ob,psys); ParticleEditSettings *pset= PE_settings(scene); - ParticleEdit *edit= psys->edit; int i, k, n= 0, totpart= psys->totpart; short mco[2]; short dmx= 0, dmy= 0; @@ -2873,19 +2885,20 @@ static void brush_add(PEData *data, short number) float hairmat[4][4], cur_co[3]; KDTree *tree=0; ParticleData *pa, *new_pars= MEM_callocN(newtotpart*sizeof(ParticleData),"ParticleData new"); - ParticleEditKey *ekey, **key, **new_keys= MEM_callocN(newtotpart*sizeof(ParticleEditKey *),"ParticleEditKey array new"); + PTCacheEditPoint *point, *new_points= MEM_callocN(newtotpart*sizeof(PTCacheEditPoint),"PTCacheEditPoint array new"); + PTCacheEditKey *key; HairKey *hkey; /* save existing elements */ memcpy(new_pars, psys->particles, totpart * sizeof(ParticleData)); - memcpy(new_keys, edit->keys, totpart * sizeof(ParticleEditKey*)); + memcpy(new_points, edit->points, totpart * sizeof(PTCacheEditPoint)); /* change old arrays to new ones */ if(psys->particles) MEM_freeN(psys->particles); psys->particles= new_pars; - if(edit->keys) MEM_freeN(edit->keys); - edit->keys= new_keys; + if(edit->points) MEM_freeN(edit->points); + edit->points= new_points; if(edit->mirror_cache) { MEM_freeN(edit->mirror_cache); @@ -2904,29 +2917,29 @@ static void brush_add(PEData *data, short number) BLI_kdtree_balance(tree); } - psys->totpart= newtotpart; + edit->totpoint= psys->totpart= newtotpart; /* create new elements */ pa= psys->particles + totpart; - key= edit->keys + totpart; + point= edit->points + totpart; - for(i=totpart; i<newtotpart; i++, pa++, key++) { + for(i=totpart; i<newtotpart; i++, pa++, point++) { memcpy(pa, add_pars + i - totpart, sizeof(ParticleData)); pa->hair= MEM_callocN(pset->totaddkey * sizeof(HairKey), "BakeKey key add"); - ekey= *key= MEM_callocN(pset->totaddkey * sizeof(ParticleEditKey), "ParticleEditKey add"); - pa->totkey= pset->totaddkey; + key= point->keys= MEM_callocN(pset->totaddkey * sizeof(PTCacheEditKey), "PTCacheEditKey add"); + point->totkey= pa->totkey= pset->totaddkey; - for(k=0, hkey=pa->hair; k<pa->totkey; k++, hkey++, ekey++) { - ekey->co= hkey->co; - ekey->time= &hkey->time; + for(k=0, hkey=pa->hair; k<pa->totkey; k++, hkey++, key++) { + key->co= hkey->co; + key->time= &hkey->time; } pa->size= 1.0f; initialize_particle(pa,i,ob,psys,psmd); reset_particle(scene, pa,psys,psmd,ob,0.0,1.0,0,0,0); - pa->flag |= PARS_EDIT_RECALC; + point->flag |= PEP_EDIT_RECALC; if(pset->flag & PE_X_MIRROR) - pa->flag |= PARS_TAG; /* signal for duplicate */ + point->flag |= PEP_TAG; /* signal for duplicate */ framestep= pa->lifetime/(float)(pset->totaddkey-1); @@ -2997,7 +3010,6 @@ static void brush_add(PEData *data, short number) Mat4MulVecfl(imat, hkey->co); } } - edit->totkeys= psys_count_keys(psys); if(tree) BLI_kdtree_free(tree); @@ -3009,25 +3021,12 @@ static void brush_add(PEData *data, short number) dm->release(dm); } -static void brush_weight(PEData *data, float mat[][4], float imat[][4], int pa_index, int key_index) -{ - ParticleSystem *psys= data->psys; - ParticleData *pa; - - /* roots have full weight allways */ - if(key_index) { - pa= &psys->particles[pa_index]; - pa->hair[key_index].weight= data->weightfac; - pa->flag |= PARS_EDIT_RECALC; - } -} - /************************* brush edit operator ********************/ typedef struct BrushEdit { Scene *scene; Object *ob; - ParticleSystem *psys; + PTCacheEdit *edit; int first; int lastmouse[2]; @@ -3037,8 +3036,8 @@ static int brush_edit_init(bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); Object *ob= CTX_data_active_object(C); - ParticleSystem *psys= PE_get_current(scene, ob); ParticleEditSettings *pset= PE_settings(scene); + PTCacheEdit *edit= PE_get_current(scene, ob); ARegion *ar= CTX_wm_region(C); BrushEdit *bedit; @@ -3053,7 +3052,7 @@ static int brush_edit_init(bContext *C, wmOperator *op) bedit->scene= scene; bedit->ob= ob; - bedit->psys= psys; + bedit->edit= edit; return 1; } @@ -3063,15 +3062,18 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) BrushEdit *bedit= op->customdata; Scene *scene= bedit->scene; Object *ob= bedit->ob; - ParticleSystem *psys= bedit->psys; + PTCacheEdit *edit= bedit->edit; ParticleEditSettings *pset= PE_settings(scene); - ParticleSystemModifierData *psmd= psys_get_modifier(ob, psys); + ParticleSystemModifierData *psmd= edit->psys ? psys_get_modifier(ob, edit->psys) : NULL; ParticleBrushData *brush= &pset->brush[pset->brushtype]; ARegion *ar= CTX_wm_region(C); - float vec1[3], vec2[3], mousef[2]; + float vec[3], mousef[2]; short mval[2], mvalo[2]; int flip, mouse[2], dx, dy, removed= 0, selected= 0; + if(!PE_start_edit(edit)) + return; + RNA_float_get_array(itemptr, "mouse", mousef); mouse[0] = mousef[0]; mouse[1] = mousef[1]; @@ -3096,7 +3098,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) || bedit->first) { view3d_operator_needs_opengl(C); - selected= (short)count_selected_keys(scene, psys); + selected= (short)count_selected_keys(scene, edit); switch(pset->brushtype) { case PE_BRUSH_COMB: @@ -3115,10 +3117,8 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) Mat4Invert(ob->imat, ob->obmat); - window_to_3d(ar, vec1, mvalo[0], mvalo[1]); - window_to_3d(ar, vec2, mval[0], mval[1]); - VECSUB(vec1, vec2, vec1); - data.dvec= vec1; + window_to_3d_delta(ar, vec, dx, dy); + data.dvec= vec; foreach_mouse_hit_key(&data, brush_comb, selected); break; @@ -3126,20 +3126,22 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) case PE_BRUSH_CUT: { PEData data; + + if(edit->psys && edit->pathcache) { + PE_set_view3d_data(C, &data); + data.mval= mval; + data.rad= (float)brush->size; + data.cutfac= (float)(brush->strength / 100.0f); - PE_set_view3d_data(C, &data); - data.mval= mval; - data.rad= (float)brush->size; - data.cutfac= (float)(brush->strength / 100.0f); - - if(selected) - foreach_selected_particle(&data, brush_cut); - else - PE_foreach_particle(&data, brush_cut); + if(selected) + foreach_selected_point(&data, brush_cut); + else + foreach_point(&data, brush_cut); - removed= remove_tagged_particles(scene, ob, psys); - if(pset->flag & PE_KEEP_LENGTHS) - recalc_lengths(psys); + removed= remove_tagged_particles(scene, ob, edit->psys); + if(pset->flag & PE_KEEP_LENGTHS) + recalc_lengths(edit); + } break; } case PE_BRUSH_LENGTH: @@ -3157,61 +3159,50 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) else data.growfac= 1.0f + data.growfac; - foreach_mouse_hit_particle(&data, brush_length, selected); + foreach_mouse_hit_point(&data, brush_length, selected); if(pset->flag & PE_KEEP_LENGTHS) - recalc_lengths(psys); + recalc_lengths(edit); break; } case PE_BRUSH_PUFF: { PEData data; - PE_set_view3d_data(C, &data); - data.dm= psmd->dm; - data.mval= mval; - data.rad= (float)brush->size; + if(edit->psys) { + PE_set_view3d_data(C, &data); + data.dm= psmd->dm; + data.mval= mval; + data.rad= (float)brush->size; - data.pufffac= (float)(brush->strength - 50) / 50.0f; - if(data.pufffac < 0.0f) - data.pufffac= 1.0f - 9.0f * data.pufffac; - else - data.pufffac= 1.0f - data.pufffac; + data.pufffac= (float)(brush->strength - 50) / 50.0f; + if(data.pufffac < 0.0f) + data.pufffac= 1.0f - 9.0f * data.pufffac; + else + data.pufffac= 1.0f - data.pufffac; - data.invert= (brush->invert ^ flip); - Mat4Invert(ob->imat, ob->obmat); + data.invert= (brush->invert ^ flip); + Mat4Invert(ob->imat, ob->obmat); - foreach_mouse_hit_particle(&data, brush_puff, selected); + foreach_mouse_hit_point(&data, brush_puff, selected); + } break; } case PE_BRUSH_ADD: { PEData data; - if(psys->part->from==PART_FROM_FACE) { + if(edit->psys && edit->psys->part->from==PART_FROM_FACE) { PE_set_view3d_data(C, &data); data.mval= mval; brush_add(&data, brush->strength); if(pset->flag & PE_KEEP_LENGTHS) - recalc_lengths(psys); + recalc_lengths(edit); } break; } - case PE_BRUSH_WEIGHT: - { - PEData data; - - PE_set_view3d_data(C, &data); - data.mval= mval; - data.rad= (float)brush->size; - - data.weightfac= (float)(brush->strength / 100.0f); - - foreach_mouse_hit_key(&data, brush_weight, selected); - break; - } case PE_BRUSH_SMOOTH: { PEData data; @@ -3238,14 +3229,14 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) } } if((pset->flag & PE_KEEP_LENGTHS)==0) - recalc_lengths(psys); + recalc_lengths(edit); if(pset->brushtype == PE_BRUSH_ADD || removed) { if(pset->brushtype == PE_BRUSH_ADD && (pset->flag & PE_X_MIRROR)) PE_mirror_x(scene, ob, 1); - psys_update_world_cos(ob,psys); - psys_free_path_cache(psys); + update_world_cos(ob,edit); + psys_free_path_cache(NULL, edit); DAG_object_flush_update(scene, ob, OB_RECALC_DATA); } else @@ -3357,104 +3348,157 @@ void PARTICLE_OT_brush_edit(wmOperatorType *ot) /*********************** undo ***************************/ -static void free_ParticleUndo(ParticleUndo *undo) +static void free_PTCacheUndo(PTCacheUndo *undo) { - ParticleData *pa; + PTCacheEditPoint *point; int i; - for(i=0, pa=undo->particles; i<undo->totpart; i++, pa++) { - if(pa->hair) - MEM_freeN(pa->hair); - if(undo->keys[i]) - MEM_freeN(undo->keys[i]); + for(i=0, point=undo->points; i<undo->totpoint; i++, point++) { + if(undo->particles && (undo->particles + i)->hair) + MEM_freeN((undo->particles + i)->hair); + if(point->keys) + MEM_freeN(point->keys); } - if(undo->keys) - MEM_freeN(undo->keys); + if(undo->points) + MEM_freeN(undo->points); if(undo->particles) MEM_freeN(undo->particles); - //if(undo->emitter_cosnos) - // MEM_freeN(undo->emitter_cosnos); + BKE_ptcache_free_mem(&undo->mem_cache); } -static void make_ParticleUndo(ParticleSystem *psys, ParticleUndo *undo) +static void make_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo) { - ParticleData *pa,*upa; + PTCacheEditPoint *point; int i; - undo->totpart= psys->totpart; - undo->totkeys= psys->edit->totkeys; + undo->totpoint= edit->totpoint; - upa= undo->particles= MEM_dupallocN(psys->particles); - undo->keys= MEM_dupallocN(psys->edit->keys); - - for(i=0, pa=psys->particles; i<undo->totpart; i++, pa++, upa++) { - upa->hair= MEM_dupallocN(pa->hair); - undo->keys[i]= MEM_dupallocN(psys->edit->keys[i]); + if(edit->psys) { + ParticleData *pa; + + pa= undo->particles= MEM_dupallocN(edit->psys->particles); + + for(i=0; i<edit->totpoint; i++, pa++) + pa->hair= MEM_dupallocN(pa->hair); + } + else { + PTCacheMem *pm; + + BLI_duplicatelist(&undo->mem_cache, &edit->pid.cache->mem_cache); + pm = undo->mem_cache.first; + + for(; pm; pm=pm->next) { + for(i=0; i<BPHYS_TOT_DATA; i++) + pm->data[i] = MEM_dupallocN(pm->data[i]); + } + } + + point= undo->points = MEM_dupallocN(edit->points); + undo->totpoint = edit->totpoint; + + for(i=0; i<edit->totpoint; i++, point++) { + point->keys= MEM_dupallocN(point->keys); /* no need to update edit key->co & key->time pointers here */ } } -static void get_ParticleUndo(ParticleSystem *psys, ParticleUndo *undo) +static void get_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo) { - ParticleData *pa, *upa; - ParticleEditKey *key; + ParticleSystem *psys = edit->psys; + ParticleData *pa; HairKey *hkey; - int i, k, totpart= psys->totpart; + POINT_P; KEY_K; - LOOP_PARTICLES(i, pa) { - if(pa->hair) - MEM_freeN(pa->hair); + LOOP_POINTS { + if(psys && psys->particles[p].hair) + MEM_freeN(psys->particles[p].hair); - if(psys->edit->keys[i]) - MEM_freeN(psys->edit->keys[i]); + if(point->keys) + MEM_freeN(point->keys); } - if(psys->particles) + if(psys && psys->particles) MEM_freeN(psys->particles); - if(psys->edit->keys) - MEM_freeN(psys->edit->keys); - if(psys->edit->mirror_cache) { - MEM_freeN(psys->edit->mirror_cache); - psys->edit->mirror_cache= NULL; + if(edit->points) + MEM_freeN(edit->points); + if(edit->mirror_cache) { + MEM_freeN(edit->mirror_cache); + edit->mirror_cache= NULL; } - pa= psys->particles= MEM_dupallocN(undo->particles); - psys->edit->keys= MEM_dupallocN(undo->keys); + edit->points= MEM_dupallocN(undo->points); + edit->totpoint = undo->totpoint; - for(i=0,upa=undo->particles; i<undo->totpart; i++, upa++, pa++) { - hkey= pa->hair= MEM_dupallocN(upa->hair); - key= psys->edit->keys[i]= MEM_dupallocN(undo->keys[i]); - for(k=0; k<pa->totkey; k++, hkey++, key++) { - key->co= hkey->co; - key->time= &hkey->time; + LOOP_POINTS { + point->keys= MEM_dupallocN(point->keys); + } + + if(psys) { + psys->particles= MEM_dupallocN(undo->particles); + + psys->totpart= undo->totpoint; + + LOOP_POINTS { + pa = psys->particles + p; + hkey= pa->hair = MEM_dupallocN(pa->hair); + + LOOP_KEYS { + key->co= hkey->co; + key->time= &hkey->time; + hkey++; + } } } + else { + PTCacheMem *pm; + int i; + + BKE_ptcache_free_mem(&edit->pid.cache->mem_cache); + + BLI_duplicatelist(&edit->pid.cache->mem_cache, &undo->mem_cache); + + pm = edit->pid.cache->mem_cache.first; - psys->totpart= undo->totpart; - psys->edit->totkeys= undo->totkeys; + for(; pm; pm=pm->next) { + for(i=0; i<BPHYS_TOT_DATA; i++) + pm->data[i] = MEM_dupallocN(pm->data[i]); + + BKE_ptcache_mem_init_pointers(pm); + + LOOP_POINTS { + LOOP_KEYS { + if((int)key->ftime == pm->frame) { + key->co = pm->cur[BPHYS_DATA_LOCATION]; + key->vel = pm->cur[BPHYS_DATA_VELOCITY]; + key->rot = pm->cur[BPHYS_DATA_ROTATION]; + key->time = &key->ftime; + } + } + BKE_ptcache_mem_incr_pointers(pm); + } + } + } } void PE_undo_push(Scene *scene, char *str) { - ParticleSystem *psys= PE_get_current(scene, OBACT); - ParticleEdit *edit= 0; - ParticleUndo *undo; + PTCacheEdit *edit= PE_get_current(scene, OBACT); + PTCacheUndo *undo; int nr; - if(!PE_can_edit(psys)) return; - edit= psys->edit; + if(!edit) return; /* remove all undos after (also when curundo==NULL) */ while(edit->undo.last != edit->curundo) { undo= edit->undo.last; BLI_remlink(&edit->undo, undo); - free_ParticleUndo(undo); + free_PTCacheUndo(undo); MEM_freeN(undo); } /* make new */ - edit->curundo= undo= MEM_callocN(sizeof(ParticleUndo), "particle undo file"); + edit->curundo= undo= MEM_callocN(sizeof(PTCacheUndo), "particle undo file"); strncpy(undo->name, str, 64-1); BLI_addtail(&edit->undo, undo); @@ -3468,27 +3512,25 @@ void PE_undo_push(Scene *scene, char *str) } if(undo) { while(edit->undo.first!=undo) { - ParticleUndo *first= edit->undo.first; + PTCacheUndo *first= edit->undo.first; BLI_remlink(&edit->undo, first); - free_ParticleUndo(first); + free_PTCacheUndo(first); MEM_freeN(first); } } /* copy */ - make_ParticleUndo(psys,edit->curundo); + make_PTCacheUndo(edit,edit->curundo); } void PE_undo_step(Scene *scene, int step) { - ParticleSystem *psys= PE_get_current(scene, OBACT); - ParticleEdit *edit= 0; + PTCacheEdit *edit= PE_get_current(scene, OBACT); - if(!PE_can_edit(psys)) return; - edit= psys->edit; + if(!edit) return; if(step==0) { - get_ParticleUndo(psys,edit->curundo); + get_PTCacheUndo(edit,edit->curundo); } else if(step==1) { @@ -3496,7 +3538,7 @@ void PE_undo_step(Scene *scene, int step) else { if(G.f & G_DEBUG) printf("undo %s\n", edit->curundo->name); edit->curundo= edit->curundo->prev; - get_ParticleUndo(psys, edit->curundo); + get_PTCacheUndo(edit, edit->curundo); } } else { @@ -3504,18 +3546,19 @@ void PE_undo_step(Scene *scene, int step) if(edit->curundo==NULL || edit->curundo->next==NULL); else { - get_ParticleUndo(psys, edit->curundo->next); + get_PTCacheUndo(edit, edit->curundo->next); edit->curundo= edit->curundo->next; if(G.f & G_DEBUG) printf("redo %s\n", edit->curundo->name); } } + PE_update_object(scene, OBACT, 0); DAG_object_flush_update(scene, OBACT, OB_RECALC_DATA); } -static void ParticleUndo_number(Scene *scene, ParticleEdit *edit, int nr) +static void PTCacheUndo_number(Scene *scene, PTCacheEdit *edit, int nr) { - ParticleUndo *undo; + PTCacheUndo *undo; int a=1; for(undo= edit->undo.first; undo; undo= undo->next, a++) { @@ -3525,20 +3568,15 @@ static void ParticleUndo_number(Scene *scene, ParticleEdit *edit, int nr) PE_undo_step(scene, 0); } -static void ParticleUndo_clear(ParticleSystem *psys) +static void PTCacheUndo_clear(PTCacheEdit *edit) { - ParticleUndo *undo; - ParticleEdit *edit; - - if(psys==0) return; - - edit= psys->edit; + PTCacheUndo *undo; if(edit==0) return; undo= edit->undo.first; while(undo) { - free_ParticleUndo(undo); + free_PTCacheUndo(undo); undo= undo->next; } BLI_freelistN(&edit->undo); @@ -3557,15 +3595,13 @@ void PE_redo(Scene *scene) void PE_undo_menu(Scene *scene, Object *ob) { - ParticleSystem *psys= PE_get_current(scene, ob); - ParticleEdit *edit= 0; - ParticleUndo *undo; + PTCacheEdit *edit= PE_get_current(scene, ob); + PTCacheUndo *undo; DynStr *ds; short event=0; char *menu; - if(!PE_can_edit(psys)) return; - edit= psys->edit; + if(!edit) return; ds= BLI_dynstr_new(); @@ -3582,7 +3618,7 @@ void PE_undo_menu(Scene *scene, Object *ob) // XXX event= pupmenu_col(menu, 20); MEM_freeN(menu); - if(event>0) ParticleUndo_number(scene, edit,event); + if(event>0) PTCacheUndo_number(scene, edit, event); } /************************ utilities ******************************/ @@ -3590,30 +3626,29 @@ void PE_undo_menu(Scene *scene, Object *ob) int PE_minmax(Scene *scene, float *min, float *max) { Object *ob= OBACT; - ParticleSystem *psys= PE_get_current(scene, ob); - ParticleSystemModifierData *psmd; - ParticleData *pa; - ParticleEditKey *key; + PTCacheEdit *edit= PE_get_current(scene, ob); + ParticleSystem *psys = edit->psys; + ParticleSystemModifierData *psmd = NULL; + POINT_P; KEY_K; float co[3], mat[4][4]; - int i, k, totpart, ok= 0; + int ok= 0; - if(!PE_can_edit(psys)) return ok; + if(!edit) return ok; - psmd= psys_get_modifier(ob, psys); - totpart= psys->totpart; - - LOOP_PARTICLES(i, pa) { - if(pa->flag & PARS_HIDE) continue; + if(psys) + psmd= psys_get_modifier(ob, psys); + else + Mat4One(mat); - psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, mat); + LOOP_VISIBLE_POINTS { + if(psys) + psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, psys->particles+p, mat); - LOOP_KEYS(k, key) { - if(key->flag & PEK_SELECT) { - VECCOPY(co, key->co); - Mat4MulVecfl(mat, co); - DO_MINMAX(co, min, max); - ok= 1; - } + LOOP_SELECTED_KEYS { + VECCOPY(co, key->co); + Mat4MulVecfl(mat, co); + DO_MINMAX(co, min, max); + ok= 1; } } @@ -3628,56 +3663,106 @@ int PE_minmax(Scene *scene, float *min, float *max) /************************ particle edit toggle operator ************************/ /* initialize needed data for bake edit */ -static void PE_create_particle_edit(Scene *scene, Object *ob, ParticleSystem *psys) +static void PE_create_particle_edit(Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys) { - ParticleEdit *edit= psys->edit; - ParticleData *pa; - ParticleEditKey *key; + PTCacheEdit *edit= psys ? psys->edit : cache->edit; + POINT_P; KEY_K; + ParticleData *pa = NULL; HairKey *hkey; - int i, k, totpart= psys->totpart, alloc=1; + int totpoint; - if((psys->flag & PSYS_EDITED)==0) + if(!psys && !cache) return; - if(edit) { - int newtotkeys= psys_count_keys(psys); + if(cache && cache->flag & PTCACHE_DISK_CACHE) + return; - if(newtotkeys == edit->totkeys) - alloc=0; - } + if(!edit) { + totpoint = psys ? psys->totpart : ((PTCacheMem*)cache->mem_cache.first)->totpoint; - if(alloc) { - if(edit) { - printf("ParticleEdit exists already! Poke jahka!"); - PE_free_particle_edit(psys); - } + edit= MEM_callocN(sizeof(PTCacheEdit), "PE_create_particle_edit"); + edit->points=MEM_callocN(totpoint*sizeof(PTCacheEditPoint),"PTCacheEditPoints"); + edit->totpoint = totpoint; - edit= psys->edit=MEM_callocN(sizeof(ParticleEdit), "PE_create_particle_edit"); - psys->free_edit= PE_free_particle_edit; + if(psys && !cache) { + psys->edit= edit; + edit->psys = psys; - edit->keys=MEM_callocN(totpart*sizeof(ParticleEditKey*),"ParticleEditKey array"); + psys->free_edit= PE_free_ptcache_edit; - LOOP_PARTICLES(i, pa) { - key= edit->keys[i]= MEM_callocN(pa->totkey*sizeof(ParticleEditKey),"ParticleEditKeys"); - for(k=0, hkey=pa->hair; k<pa->totkey; k++, hkey++, key++) { - key->co= hkey->co; - key->time= &hkey->time; - key->flag= hkey->editflag; + edit->pathcache = NULL; + edit->pathcachebufs.first = edit->pathcachebufs.last = NULL; + + pa = psys->particles; + LOOP_POINTS { + point->totkey = pa->totkey; + point->keys= MEM_callocN(point->totkey*sizeof(PTCacheEditKey),"ParticleEditKeys"); + point->flag |= PEP_EDIT_RECALC; + + hkey = pa->hair; + LOOP_KEYS { + key->co= hkey->co; + key->time= &hkey->time; + key->flag= hkey->editflag; + key->flag |= PEK_USE_WCO; + hkey++; + } + pa++; } } + else { + PTCacheMem *pm; + int totframe=0; + + cache->edit= edit; + cache->free_edit= PE_free_ptcache_edit; + edit->psys = NULL; + + for(pm=cache->mem_cache.first; pm; pm=pm->next) + totframe++; + + for(pm=cache->mem_cache.first; pm; pm=pm->next) { + BKE_ptcache_mem_init_pointers(pm); + + LOOP_POINTS { + if(psys) { + pa = psys->particles + p; + if((pm->next && pm->next->frame < pa->time) + || (pm->prev && pm->prev->frame >= pa->dietime)) { + BKE_ptcache_mem_incr_pointers(pm); + continue; + } + } + + if(!point->totkey) { + key = point->keys = MEM_callocN(totframe*sizeof(PTCacheEditKey),"ParticleEditKeys"); + point->flag |= PEP_EDIT_RECALC; + } + else + key = point->keys + point->totkey; - edit->totkeys= psys_count_keys(psys); + key->co = pm->cur[BPHYS_DATA_LOCATION]; + key->vel = pm->cur[BPHYS_DATA_VELOCITY]; + key->rot = pm->cur[BPHYS_DATA_ROTATION]; + key->ftime = (float)pm->frame; + key->time = &key->ftime; + BKE_ptcache_mem_incr_pointers(pm); + + point->totkey++; + } + } + psys = NULL; + } UI_GetThemeColor3ubv(TH_EDGE_SELECT, edit->sel_col); UI_GetThemeColor3ubv(TH_WIRE, edit->nosel_col); - } - recalc_lengths(psys); - recalc_emitter_field(ob, psys); - psys_update_world_cos(ob, psys); + recalc_lengths(edit); + if(psys && !cache) + recalc_emitter_field(ob, psys); + PE_update_object(scene, ob, 1); - if(alloc) { - ParticleUndo_clear(psys); + PTCacheUndo_clear(edit); PE_undo_push(scene, "Original"); } } @@ -3690,30 +3775,16 @@ static int particle_edit_toggle_poll(bContext *C) if(!scene || !ob || ob->id.lib) return 0; - return (ob->particlesystem.first != NULL); + return (ob->particlesystem.first || modifiers_findByType(ob, eModifierType_Cloth) || modifiers_findByType(ob, eModifierType_Softbody)); } static int particle_edit_toggle_exec(bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); Object *ob= CTX_data_active_object(C); - ParticleSystem *psys= PE_get_current(scene, ob); - - if(psys==NULL) { - psys= ob->particlesystem.first; - psys->flag |= PSYS_CURRENT; - } + PTCacheEdit *edit= PE_get_current(scene, ob, PE_settings(scene)->edittype); if(!(ob->mode & OB_MODE_PARTICLE_EDIT)) { - if(psys && psys->part->type == PART_HAIR && psys->flag & PSYS_EDITED) { - if(psys_check_enabled(ob, psys)) { - if(psys->edit==NULL) - PE_create_particle_edit(scene, ob, psys); - - psys_update_world_cos(ob, psys); - } - } - ob->mode |= OB_MODE_PARTICLE_EDIT; toggle_particle_cursor(C, 1); WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_PARTICLE, NULL); @@ -3746,112 +3817,65 @@ void PARTICLE_OT_particle_edit_toggle(wmOperatorType *ot) /************************ set editable operator ************************/ -static int set_editable_exec(bContext *C, wmOperator *op) +static int clear_edited_exec(bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); Object *ob= CTX_data_active_object(C); - ParticleSystem *psys= PE_get_current(scene, ob); + ParticleSystem *psys = psys_get_current(ob); - if(psys->flag & PSYS_EDITED) { - if(1) { // XXX okee("Lose changes done in particle mode?")) { - if(psys->edit) - PE_free_particle_edit(psys); + if(psys->edit) { + if(psys->edit->edited || 1) { // XXX okee("Lose changes done in particle mode?")) + PE_free_ptcache_edit(psys->edit); + + psys->edit = NULL; + psys->free_edit = NULL; - psys->flag &= ~PSYS_EDITED; psys->recalc |= PSYS_RECALC_RESET; + psys_reset(psys, PSYS_RESET_DEPSGRAPH); DAG_object_flush_update(scene, ob, OB_RECALC_DATA); } } - else { - if(psys_check_enabled(ob, psys)) { - psys->flag |= PSYS_EDITED; - - if(ob->mode & OB_MODE_PARTICLE_EDIT) - PE_create_particle_edit(scene, ob, psys); - } - else - BKE_report(op->reports, RPT_ERROR, "Particle system not enabled, skipping set editable"); - } return OPERATOR_FINISHED; } -void PARTICLE_OT_editable_set(wmOperatorType *ot) +void PARTICLE_OT_edited_clear(wmOperatorType *ot) { /* identifiers */ - ot->name= "Set Editable"; - ot->idname= "PARTICLE_OT_editable_set"; + ot->name= "Clear Edited"; + ot->idname= "PARTICLE_OT_edited_clear"; /* api callbacks */ - ot->exec= set_editable_exec; + ot->exec= clear_edited_exec; ot->poll= particle_edit_toggle_poll; /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; } -/*********************** change active **************************/ - -void PE_change_act(void *ob_v, void *act_v) -{ - Scene *scene= NULL; // XXX - Object *ob= ob_v; - ParticleSystem *psys; - short act= *((short*)act_v) - 1; - - if((psys=psys_get_current(ob))) - psys->flag &= ~PSYS_CURRENT; - - if(act>=0) { - if((psys=BLI_findlink(&ob->particlesystem,act))) { - psys->flag |= PSYS_CURRENT; - - if(psys_check_enabled(ob, psys)) { - if(ob->mode & OB_MODE_PARTICLE_EDIT && !psys->edit) - PE_create_particle_edit(scene, ob, psys); - psys_update_world_cos(ob, psys); - } - } - } -} - -void PE_change_act_psys(Scene *scene, Object *ob, ParticleSystem *psys) -{ - ParticleSystem *p; - - if((p=psys_get_current(ob))) - p->flag &= ~PSYS_CURRENT; - - psys->flag |= PSYS_CURRENT; - - if(psys_check_enabled(ob, psys)) { - if(ob->mode & OB_MODE_PARTICLE_EDIT && !psys->edit) - PE_create_particle_edit(scene, ob, psys); - - psys_update_world_cos(ob, psys); - } -} - /*********************** specials menu **************************/ static int specials_menu_invoke(bContext *C, wmOperator *op, wmEvent *event) { Scene *scene= CTX_data_scene(C); ParticleEditSettings *pset=PE_settings(scene); + PTCacheEdit *edit = PE_get_current(scene, CTX_data_active_object(C)); uiPopupMenu *pup; uiLayout *layout; pup= uiPupMenuBegin(C, "Specials", 0); layout= uiPupMenuLayout(pup); - uiItemO(layout, NULL, 0, "PARTICLE_OT_rekey"); - if(pset->selectmode & SCE_SELECT_POINT) { - uiItemO(layout, NULL, 0, "PARTICLE_OT_subdivide"); - uiItemO(layout, NULL, 0, "PARTICLE_OT_select_first"); - uiItemO(layout, NULL, 0, "PARTICLE_OT_select_last"); + if(edit->psys) { + uiItemO(layout, NULL, 0, "PARTICLE_OT_rekey"); + if(pset->selectmode & SCE_SELECT_POINT) { + uiItemO(layout, NULL, 0, "PARTICLE_OT_subdivide"); + uiItemO(layout, NULL, 0, "PARTICLE_OT_select_first"); + uiItemO(layout, NULL, 0, "PARTICLE_OT_select_last"); + } + uiItemO(layout, NULL, 0, "PARTICLE_OT_remove_doubles"); } - uiItemO(layout, NULL, 0, "PARTICLE_OT_remove_doubles"); uiPupMenuEnd(C, pup); @@ -3896,7 +3920,7 @@ void ED_operatortypes_particle(void) WM_operatortype_append(PARTICLE_OT_specials_menu); WM_operatortype_append(PARTICLE_OT_particle_edit_toggle); - WM_operatortype_append(PARTICLE_OT_editable_set); + WM_operatortype_append(PARTICLE_OT_edited_clear); } void ED_keymap_particle(wmWindowManager *wm) diff --git a/source/blender/editors/space_outliner/outliner.c b/source/blender/editors/space_outliner/outliner.c index fca5b0cc59a..e6cd9c0e448 100644 --- a/source/blender/editors/space_outliner/outliner.c +++ b/source/blender/editors/space_outliner/outliner.c @@ -2120,9 +2120,7 @@ static int tree_element_active_psys(bContext *C, Scene *scene, TreeElement *te, { if(set) { Object *ob= (Object *)tselem->id; - ParticleSystem *psys= te->directdata; - PE_change_act_psys(scene, ob, psys); WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, ob); // XXX extern_set_butspace(F7KEY, 0); diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 6cf229ead31..e49616fc740 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -89,6 +89,7 @@ #include "BKE_object.h" #include "BKE_paint.h" #include "BKE_particle.h" +#include "BKE_pointcache.h" #include "BKE_property.h" #include "BKE_smoke.h" #include "BKE_unit.h" @@ -3138,6 +3139,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv { Object *ob=base->object; ParticleSystemModifierData *psmd; + ParticleEditSettings *pset = PE_settings(scene); ParticleSettings *part; ParticleData *pars, *pa; ParticleKey state, *states=0; @@ -3166,9 +3168,8 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv if(pars==0) return; - // XXX what logic is this? - if(!scene->obedit && psys_in_edit_mode(scene, psys) - && psys->flag & PSYS_HAIR_DONE && part->draw_as==PART_DRAW_PATH) + /* don't draw normal paths in edit mode */ + if(psys_in_edit_mode(scene, psys) && (pset->flag & PE_DRAW_PART)==0) return; if(part->draw_as==PART_DRAW_NOT) return; @@ -3709,33 +3710,27 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv wmLoadMatrix(rv3d->viewmat); } -static void draw_particle_edit(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, ParticleSystem *psys, int dt) +static void draw_ptcache_edit(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, PTCacheEdit *edit, int dt) { - ParticleEdit *edit = psys->edit; - ParticleData *pa; - ParticleCacheKey **path; - ParticleEditKey *key; + ParticleCacheKey **cache, *path, *pkey; + PTCacheEditPoint *point; + PTCacheEditKey *key; ParticleEditSettings *pset = PE_settings(scene); - int i, k, totpart = psys->totpart, totchild=0, timed = pset->draw_timed; + int i, k, totpoint = edit->totpoint, timed = pset->flag & PE_FADE_TIME ? pset->fade_frames : 0; + int steps; char nosel[4], sel[4]; float sel_col[3]; float nosel_col[3]; - char val[32]; + float *pathcol = NULL, *pcol; /* create path and child path cache if it doesn't exist already */ - if(psys->pathcache==0){ - PE_hide_keys_time(scene, psys,CFRA); - psys_cache_paths(scene, ob, psys, CFRA,0); - } - if(psys->pathcache==0) + if(edit->pathcache==0) + psys_cache_edit_paths(scene, ob, edit, CFRA); + + if(edit->pathcache==0) return; - if(pset->flag & PE_SHOW_CHILD && psys->part->draw_as == PART_DRAW_PATH) { - if(psys->childcache==0) - psys_cache_child_paths(scene, ob, psys, CFRA, 0); - } - else if(!(pset->flag & PE_SHOW_CHILD) && psys->childcache) - free_child_path_cache(psys); + PE_hide_keys_time(scene, edit, CFRA); /* opengl setup */ if((v3d->flag & V3D_ZBUF_SELECT)==0) @@ -3751,65 +3746,50 @@ static void draw_particle_edit(Scene *scene, View3D *v3d, RegionView3D *rv3d, Ob nosel_col[1]=(float)nosel[1]/255.0f; nosel_col[2]=(float)nosel[2]/255.0f; - if(psys->childcache) - totchild = psys->totchildcache; /* draw paths */ - if(timed) + if(timed) { glEnable(GL_BLEND); + steps = (*edit->pathcache)->steps + 1; + pathcol = MEM_callocN(steps*4*sizeof(float), "particle path color data"); + } glEnableClientState(GL_VERTEX_ARRAY); - if(dt > OB_WIRE) { - /* solid shaded with lighting */ - glEnableClientState(GL_NORMAL_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); + /* solid shaded with lighting */ + glEnableClientState(GL_NORMAL_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); - glEnable(GL_COLOR_MATERIAL); - glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); - } - else { - /* flat wire color */ - glDisableClientState(GL_NORMAL_ARRAY); - glDisable(GL_LIGHTING); - UI_ThemeColor(TH_WIRE); - } + glEnable(GL_COLOR_MATERIAL); + glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); /* only draw child paths with lighting */ if(dt > OB_WIRE) glEnable(GL_LIGHTING); - if(psys->part->draw_as == PART_DRAW_PATH) { - for(i=0, path=psys->childcache; i<totchild; i++,path++){ - glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), (*path)->co); - if(dt > OB_WIRE) { - glNormalPointer(GL_FLOAT, sizeof(ParticleCacheKey), (*path)->vel); - glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), (*path)->col); + /* 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){ + VECCOPY(pcol, pkey->col); + pcol[3] = 1.0f - fabs((float)CFRA - pkey->time)/(float)pset->fade_frames; } - glDrawArrays(GL_LINE_STRIP, 0, (int)(*path)->steps + 1); + glColorPointer(4, GL_FLOAT, 4*sizeof(float), pathcol); } - } - - if(dt > OB_WIRE) - glDisable(GL_LIGHTING); + else + glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col); - if(pset->brushtype == PE_BRUSH_WEIGHT) { - glLineWidth(2.0f); - glEnableClientState(GL_COLOR_ARRAY); - glDisable(GL_LIGHTING); + glDrawArrays(GL_LINE_STRIP, 0, path->steps + 1); } - /* draw parents last without lighting */ - for(i=0, pa=psys->particles, path = psys->pathcache; i<totpart; i++, pa++, path++){ - glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), (*path)->co); - if(dt > OB_WIRE) - glNormalPointer(GL_FLOAT, sizeof(ParticleCacheKey), (*path)->vel); - if(dt > OB_WIRE || pset->brushtype == PE_BRUSH_WEIGHT) - glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), (*path)->col); + if(pathcol) { MEM_freeN(pathcol); pathcol = pcol = NULL; } - glDrawArrays(GL_LINE_STRIP, 0, (int)(*path)->steps + 1); - } /* draw edit vertices */ if(pset->selectmode!=SCE_SELECT_PATH){ @@ -3819,61 +3799,74 @@ static void draw_particle_edit(Scene *scene, View3D *v3d, RegionView3D *rv3d, Ob glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE)); if(pset->selectmode==SCE_SELECT_POINT){ + float *pd=0,*pdata=0; float *cd=0,*cdata=0; - cd=cdata=MEM_callocN(edit->totkeys*(timed?4:3)*sizeof(float), "particle edit color data"); + int totkeys = 0; + + for (i=0, point=edit->points; i<totpoint; i++, point++) + if(!(point->flag & PEP_HIDE)) + totkeys += point->totkey; + + if(!edit->psys) + 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"); + + for(i=0, point=edit->points; i<totpoint; i++, point++){ + if(point->flag & PEP_HIDE) + continue; + + for(k=0, key=point->keys; k<point->totkey; k++, key++){ + if(pd) { + VECCOPY(pd, key->co); + pd += 3; + } - for(i=0, pa=psys->particles; i<totpart; i++, pa++){ - for(k=0, key=edit->keys[i]; k<pa->totkey; k++, key++){ if(key->flag&PEK_SELECT){ VECCOPY(cd,sel_col); } else{ VECCOPY(cd,nosel_col); } + if(timed) - *(cd+3) = (key->flag&PEK_HIDE)?0.0f:1.0f; + *(cd+3) = 1.0f - fabs((float)CFRA - *key->time)/(float)pset->fade_frames; + cd += (timed?4:3); } } cd=cdata; - for(i=0, pa=psys->particles; i<totpart; i++, pa++){ - if((pa->flag & PARS_HIDE)==0){ - glVertexPointer(3, GL_FLOAT, sizeof(ParticleEditKey), edit->keys[i]->world_co); - glColorPointer((timed?4:3), GL_FLOAT, (timed?4:3)*sizeof(float), cd); - glDrawArrays(GL_POINTS, 0, pa->totkey); - } - cd += (timed?4:3) * pa->totkey; + pd=pdata; + for(i=0, point=edit->points; i<totpoint; i++, point++){ + if(point->flag & PEP_HIDE) + continue; - if((pset->flag&PE_SHOW_TIME) && (pa->flag&PARS_HIDE)==0 && !(G.f & G_RENDER_SHADOW)){ - for(k=0, key=edit->keys[i]+k; k<pa->totkey; k++, key++){ - if(key->flag & PEK_HIDE) continue; + if(edit->psys) + glVertexPointer(3, GL_FLOAT, sizeof(PTCacheEditKey), point->keys->world_co); + else + glVertexPointer(3, GL_FLOAT, 3*sizeof(float), pd); - sprintf(val," %.1f",*key->time); - view3d_particle_text_draw_add(key->world_co[0], key->world_co[1], key->world_co[2], val, 0); - } - } + glColorPointer((timed?4:3), GL_FLOAT, (timed?4:3)*sizeof(float), cd); + + glDrawArrays(GL_POINTS, 0, point->totkey); + + pd += pd ? 3 * point->totkey : 0; + cd += (timed?4:3) * point->totkey; } - if(cdata) - MEM_freeN(cdata); - cd=cdata=0; + if(pdata) { MEM_freeN(pdata); pd=pdata=0; } + if(cdata) { MEM_freeN(cdata); cd=cdata=0; } } else if(pset->selectmode == SCE_SELECT_END){ - for(i=0, pa=psys->particles; i<totpart; i++, pa++){ - if((pa->flag & PARS_HIDE)==0){ - key = edit->keys[i] + pa->totkey - 1; + for(i=0, point=edit->points; i<totpoint; i++, point++){ + if((point->flag & PEP_HIDE)==0){ + key = point->keys + point->totkey - 1; if(key->flag & PEK_SELECT) glColor3fv(sel_col); else glColor3fv(nosel_col); /* has to be like this.. otherwise selection won't work, have try glArrayElement later..*/ glBegin(GL_POINTS); - glVertex3fv(key->world_co); + glVertex3fv(key->flag & PEK_USE_WCO ? key->world_co : key->co); glEnd(); - - if((pset->flag & PE_SHOW_TIME) && !(G.f & G_RENDER_SHADOW)){ - sprintf(val," %.1f",*key->time); - view3d_particle_text_draw_add(key->world_co[0], key->world_co[1], key->world_co[2], val, 0); - } } } } @@ -5298,11 +5291,6 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag) for(psys=ob->particlesystem.first; psys; psys=psys->next) draw_new_particle_system(scene, v3d, rv3d, base, psys, dt); - if(ob->mode & OB_MODE_PARTICLE_EDIT && ob==OBACT) { - psys= PE_get_current(scene, ob); - if(psys && !scene->obedit && psys_in_edit_mode(scene, psys)) - draw_particle_edit(scene, v3d, rv3d, ob, psys, dt); - } view3d_particle_text_draw(v3d, ar); wmMultMatrix(ob->obmat); @@ -5310,6 +5298,21 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag) //glDepthMask(GL_TRUE); if(col) cpack(col); } + + if( (warning_recursive==0) && + (flag & DRAW_PICKING)==0 && + (!scene->obedit) + ) { + + if(ob->mode & OB_MODE_PARTICLE_EDIT && ob==OBACT) { + PTCacheEdit *edit = PE_get_current(scene, ob); + if(edit) { + wmLoadMatrix(rv3d->viewmat); + draw_ptcache_edit(scene, v3d, rv3d, ob, edit, dt); + wmMultMatrix(ob->obmat); + } + } + } /* draw code for smoke */ { diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c index eee85f21798..305b6956037 100644 --- a/source/blender/editors/space_view3d/view3d_header.c +++ b/source/blender/editors/space_view3d/view3d_header.c @@ -1571,7 +1571,7 @@ static char *view3d_modeselect_pup(Scene *scene) str += sprintf(str, formatstr, "Pose Mode", OB_MODE_POSE, ICON_POSE_HLT); } - if (ob->particlesystem.first) { + if (ob->particlesystem.first || modifiers_findByType(ob, eModifierType_Cloth) || modifiers_findByType(ob, eModifierType_Softbody)) { str += sprintf(str, formatstr, "Particle Mode", OB_MODE_PARTICLE_EDIT, ICON_PARTICLEMODE); } @@ -1661,6 +1661,7 @@ static void do_view3d_header_buttons(bContext *C, void *arg, int event) ScrArea *sa= CTX_wm_area(C); View3D *v3d= sa->spacedata.first; Object *obedit = CTX_data_edit_object(C); + Object *ob = CTX_data_active_object(C); EditMesh *em= NULL; int bit, ctrl= win->eventstate->ctrl, shift= win->eventstate->shift; PointerRNA props_ptr; @@ -1759,14 +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); 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); 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); ED_undo_push(C, "Selectmode Set: End point"); break; diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 5c5b7281f20..aaede541b76 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -1617,31 +1617,32 @@ static void createTransParticleVerts(bContext *C, TransInfo *t) TransDataExtension *tx; Base *base = CTX_data_active_base(C); Object *ob = CTX_data_active_object(C); - ParticleSystem *psys = PE_get_current(t->scene, ob); - ParticleSystemModifierData *psmd = NULL; ParticleEditSettings *pset = PE_settings(t->scene); - ParticleData *pa = NULL; - ParticleEdit *edit; - ParticleEditKey *key; + PTCacheEdit *edit = PE_get_current(t->scene, ob); + ParticleSystem *psys = NULL; + ParticleSystemModifierData *psmd = NULL; + PTCacheEditPoint *point; + PTCacheEditKey *key; float mat[4][4]; - int i,k, totpart, transformparticle; + int i,k, transformparticle; int count = 0, hasselected = 0; int propmode = t->flag & T_PROP_EDIT; - if(psys==NULL || t->settings->particle.selectmode==SCE_SELECT_PATH) return; + if(edit==NULL || t->settings->particle.selectmode==SCE_SELECT_PATH) return; - psmd = psys_get_modifier(ob,psys); + psys = edit->psys; + + if(psys) + psmd = psys_get_modifier(ob,psys); - edit = psys->edit; - totpart = psys->totpart; base->flag |= BA_HAS_RECALC_DATA; - for(i=0, pa=psys->particles; i<totpart; i++, pa++) { - pa->flag &= ~PARS_TRANSFORM; + for(i=0, point=edit->points; i<edit->totpoint; i++, point++) { + point->flag &= ~PEP_TRANSFORM; transformparticle= 0; - if((pa->flag & PARS_HIDE)==0) { - for(k=0, key=edit->keys[i]; k<pa->totkey; k++, key++) { + if((point->flag & PEP_HIDE)==0) { + for(k=0, key=point->keys; k<point->totkey; k++, key++) { if((key->flag&PEK_HIDE)==0) { if(key->flag&PEK_SELECT) { hasselected= 1; @@ -1654,8 +1655,8 @@ static void createTransParticleVerts(bContext *C, TransInfo *t) } if(transformparticle) { - count += pa->totkey; - pa->flag |= PARS_TRANSFORM; + count += point->totkey; + point->flag |= PEP_TRANSFORM; } } @@ -1674,18 +1675,23 @@ static void createTransParticleVerts(bContext *C, TransInfo *t) Mat4Invert(ob->imat,ob->obmat); - for(i=0, pa=psys->particles; i<totpart; i++, pa++) { + for(i=0, point=edit->points; i<edit->totpoint; i++, point++) { TransData *head, *tail; head = tail = td; - if(!(pa->flag & PARS_TRANSFORM)) continue; + if(!(point->flag & PEP_TRANSFORM)) continue; - psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, mat); + if(psys) + psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, psys->particles + i, mat); - for(k=0, key=edit->keys[i]; k<pa->totkey; k++, key++) { - VECCOPY(key->world_co, key->co); - Mat4MulVecfl(mat, key->world_co); - td->loc = key->world_co; + for(k=0, key=point->keys; k<point->totkey; k++, key++) { + if(psys) { + VECCOPY(key->world_co, key->co); + Mat4MulVecfl(mat, key->world_co); + td->loc = key->world_co; + } + else + td->loc = key->co; VECCOPY(td->iloc, td->loc); VECCOPY(td->center, td->loc); @@ -1713,7 +1719,7 @@ static void createTransParticleVerts(bContext *C, TransInfo *t) if(k==0) tx->size = 0; else tx->size = (key - 1)->time; - if(k == pa->totkey - 1) tx->quat = 0; + if(k == point->totkey - 1) tx->quat = 0; else tx->quat = (key + 1)->time; } @@ -1731,35 +1737,42 @@ void flushTransParticles(TransInfo *t) { Scene *scene = t->scene; Object *ob = OBACT; - ParticleSystem *psys = PE_get_current(scene, ob); + PTCacheEdit *edit = PE_get_current(scene, ob); + ParticleSystem *psys = edit->psys; ParticleSystemModifierData *psmd; - ParticleData *pa; - ParticleEditKey *key; + PTCacheEditPoint *point; + PTCacheEditKey *key; TransData *td; float mat[4][4], imat[4][4], co[3]; int i, k, propmode = t->flag & T_PROP_EDIT; - psmd = psys_get_modifier(ob, psys); + if(psys) + psmd = psys_get_modifier(ob, psys); /* we do transform in world space, so flush world space position - * back to particle local space */ + * back to particle local space (only for hair particles) */ td= t->data; - for(i=0, pa=psys->particles; i<psys->totpart; i++, pa++, td++) { - if(!(pa->flag & PARS_TRANSFORM)) continue; + for(i=0, point=edit->points; i<edit->totpoint; i++, point++, td++) { + if(!(point->flag & PEP_TRANSFORM)) continue; + + if(psys) { + psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, psys->particles + i, mat); + Mat4Invert(imat,mat); - psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, mat); - Mat4Invert(imat,mat); + for(k=0, key=point->keys; k<point->totkey; k++, key++) { + VECCOPY(co, key->world_co); + Mat4MulVecfl(imat, co); - for(k=0, key=psys->edit->keys[i]; k<pa->totkey; k++, key++) { - VECCOPY(co, key->world_co); - Mat4MulVecfl(imat, co); - /* optimization for proportional edit */ - if(!propmode || !FloatCompare(key->co, co, 0.0001f)) { - VECCOPY(key->co, co); - pa->flag |= PARS_EDIT_RECALC; + /* optimization for proportional edit */ + if(!propmode || !FloatCompare(key->co, co, 0.0001f)) { + VECCOPY(key->co, co); + point->flag |= PEP_EDIT_RECALC; + } } } + else + point->flag |= PEP_EDIT_RECALC; } PE_update_object(scene, OBACT, 1); @@ -5256,7 +5269,8 @@ void createTransData(bContext *C, TransInfo *t) } CTX_DATA_END; } - else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT) && PE_can_edit(PE_get_current(scene, ob))) { + else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT) + && PE_start_edit(PE_get_current(scene, ob))) { createTransParticleVerts(C, t); if(t->data && t->flag & T_PROP_EDIT) { diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c index 37fd79e38e1..e4ec43a8f38 100644 --- a/source/blender/editors/transform/transform_manipulator.c +++ b/source/blender/editors/transform/transform_manipulator.c @@ -62,6 +62,7 @@ #include "BKE_mesh.h" #include "BKE_object.h" #include "BKE_particle.h" +#include "BKE_pointcache.h" #include "BKE_utildefines.h" #include "BLI_arithb.h" @@ -362,18 +363,19 @@ int calc_manipulator_stats(const bContext *C) ; } else if(ob && ob->mode & OB_MODE_PARTICLE_EDIT) { - ParticleSystem *psys= PE_get_current(scene, ob); - ParticleData *pa = psys->particles; - ParticleEditKey *ek; + PTCacheEdit *edit= PE_get_current(scene, ob); + PTCacheEditPoint *point; + PTCacheEditKey *ek; int k; - if(psys->edit) { - for(a=0; a<psys->totpart; a++,pa++) { - if(pa->flag & PARS_HIDE) continue; + if(edit) { + point = edit->points; + for(a=0; a<edit->totpoint; a++,point++) { + if(point->flag & PEP_HIDE) continue; - for(k=0, ek=psys->edit->keys[a]; k<pa->totkey; k++, ek++) { + for(k=0, ek=point->keys; k<point->totkey; k++, ek++) { if(ek->flag & PEK_SELECT) { - calc_tw_center(scene, ek->world_co); + calc_tw_center(scene, ek->flag & PEK_USE_WCO ? ek->world_co : ek->co); totsel++; } } diff --git a/source/blender/makesdna/DNA_object_force.h b/source/blender/makesdna/DNA_object_force.h index 625864c4888..5696f82ab0d 100644 --- a/source/blender/makesdna/DNA_object_force.h +++ b/source/blender/makesdna/DNA_object_force.h @@ -95,7 +95,7 @@ typedef struct PartDeflect { typedef struct PTCacheMem { struct PTCacheMem *next, *prev; int frame, totpoint; - unsigned int data_types, rt; + unsigned int data_types, flag; int *index_array; /* quick access to stored points with index */ void *data[8]; /* BPHYS_TOT_DATA */ @@ -121,6 +121,9 @@ typedef struct PointCache { char info[64]; char path[240]; /* file path */ struct ListBase mem_cache; + + struct PTCacheEdit *edit; + void (*free_edit)(struct PTCacheEdit *edit); /* free callback */ } PointCache; typedef struct SBVertex { @@ -300,8 +303,8 @@ typedef struct SoftBody { #define PTCACHE_OUTDATED 2 #define PTCACHE_SIMULATION_VALID 4 #define PTCACHE_BAKING 8 -#define PTCACHE_BAKE_EDIT 16 -#define PTCACHE_BAKE_EDIT_ACTIVE 32 +//#define PTCACHE_BAKE_EDIT 16 +//#define PTCACHE_BAKE_EDIT_ACTIVE 32 #define PTCACHE_DISK_CACHE 64 #define PTCACHE_QUICK_CACHE 128 #define PTCACHE_FRAMES_SKIPPED 256 diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h index 925fd31328d..12c253a7cb8 100644 --- a/source/blender/makesdna/DNA_particle_types.h +++ b/source/blender/makesdna/DNA_particle_types.h @@ -194,8 +194,8 @@ typedef struct ParticleSystem{ /* note, make sure all (runtime) are NULL's in ParticleData *particles; /* (parent) particles */ ChildParticle *child; /* child particles */ - struct ParticleEdit *edit; /* particle editmode (runtime) */ - void (*free_edit)(struct ParticleSystem *sys); /* free callback */ + struct PTCacheEdit *edit; /* particle editmode (runtime) */ + void (*free_edit)(struct PTCacheEdit *edit); /* free callback */ struct ParticleCacheKey **pathcache; /* path cache (runtime) */ struct ParticleCacheKey **childcache; /* child cache (runtime) */ @@ -419,7 +419,7 @@ typedef struct ParticleSystem{ /* note, make sure all (runtime) are NULL's in #define PSYS_DELETE 256 /* remove particlesystem as soon as possible */ #define PSYS_HAIR_DONE 512 #define PSYS_KEYED 1024 -#define PSYS_EDITED 2048 +//#define PSYS_EDITED 2048 //#define PSYS_PROTECT_CACHE 4096 #define PSYS_DISABLED 8192 @@ -427,11 +427,7 @@ typedef struct ParticleSystem{ /* note, make sure all (runtime) are NULL's in #define PARS_UNEXIST 1 #define PARS_NO_DISP 2 #define PARS_STICKY 4 -#define PARS_TRANSFORM 8 -#define PARS_HIDE 16 -#define PARS_TAG 32 -#define PARS_REKEY 64 -#define PARS_EDIT_RECALC 128 +#define PARS_REKEY 8 /* pars->alive */ #define PARS_KILLED 0 diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 20429120812..73afc3d1a53 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -488,10 +488,15 @@ typedef struct ParticleEditSettings { ParticleBrushData brush[7]; /* 7 = PE_TOT_BRUSH */ void *paintcursor; /* runtime */ - float emitterdist; - int draw_timed; + float emitterdist, rt; - int selectmode, pad; + int selectmode; + int edittype; + + int draw_step, fade_frames; + + struct Scene *scene; + struct Object *object; } ParticleEditSettings; typedef struct TransformOrientation { @@ -1042,9 +1047,10 @@ typedef enum SculptFlags { #define PE_LOCK_FIRST 2 #define PE_DEFLECT_EMITTER 4 #define PE_INTERPOLATE_ADDED 8 -#define PE_SHOW_CHILD 16 -#define PE_SHOW_TIME 32 +#define PE_DRAW_PART 16 #define PE_X_MIRROR 64 +#define PE_FADE_TIME 128 +#define PE_AUTO_VELOCITY 256 /* toolsetting->particle brushtype */ #define PE_BRUSH_NONE -1 @@ -1053,11 +1059,15 @@ typedef enum SculptFlags { #define PE_BRUSH_LENGTH 2 #define PE_BRUSH_PUFF 3 #define PE_BRUSH_ADD 4 -#define PE_BRUSH_WEIGHT 5 -#define PE_BRUSH_SMOOTH 6 +#define PE_BRUSH_SMOOTH 5 /* this must equal ParticleEditSettings.brush array size */ -#define PE_TOT_BRUSH 7 +#define PE_TOT_BRUSH 6 + +/* tooksettings->particle edittype */ +#define PE_TYPE_PARTICLES 0 +#define PE_TYPE_SOFTBODY 1 +#define PE_TYPE_CLOTH 2 /* toolsettings->retopo_mode */ #define RETOPO 1 diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index e0dbc232e06..a1f35eca3c2 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -98,6 +98,7 @@ EnumPropertyItem part_hair_ren_as_items[] = { #include "BKE_context.h" #include "BKE_depsgraph.h" #include "BKE_particle.h" +#include "BKE_pointcache.h" #include "BLI_arithb.h" @@ -436,7 +437,30 @@ static void rna_ParticleTarget_name_get(PointerRNA *ptr, char *str) else strcpy(str, "Invalid target!"); } +static int rna_ParticleSystem_multiple_caches_get(PointerRNA *ptr) +{ + ParticleSystem *psys= (ParticleSystem*)ptr->data; + + return (psys->ptcaches.first != psys->ptcaches.last); +} +static int rna_ParticleSystem_editable_get(PointerRNA *ptr) +{ + ParticleSystem *psys= (ParticleSystem*)ptr->data; + + if(psys->part && psys->part->type==PART_HAIR) + return (psys->flag & PSYS_HAIR_DONE); + else + return (psys->pointcache->flag & PTCACHE_BAKED); +} +static int rna_ParticleSystem_edited_get(PointerRNA *ptr) +{ + ParticleSystem *psys= (ParticleSystem*)ptr->data; + if(psys->part && psys->part->type==PART_HAIR) + return (psys->edit && psys->edit->edited); + else + return (psys->pointcache->edit && psys->pointcache->edit->edited); +} EnumPropertyItem from_items[] = { {PART_FROM_VERT, "VERT", 0, "Vertexes", ""}, {PART_FROM_FACE, "FACE", 0, "Faces", ""}, @@ -725,27 +749,10 @@ static void rna_def_particle(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", PARS_STICKY); RNA_def_property_ui_text(prop, "sticky", ""); - prop= RNA_def_property(srna, "transform", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", PARS_TRANSFORM); - RNA_def_property_ui_text(prop, "transform", ""); - - prop= RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", PARS_HIDE); - RNA_def_property_ui_text(prop, "hide", ""); - - prop= RNA_def_property(srna, "tag", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", PARS_TAG); - RNA_def_property_ui_text(prop, "tag", ""); - prop= RNA_def_property(srna, "rekey", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", PARS_REKEY); RNA_def_property_ui_text(prop, "rekey", ""); - prop= RNA_def_property(srna, "edit_recalc", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", PARS_EDIT_RECALC); - RNA_def_property_ui_text(prop, "edit_recalc", ""); - - prop= RNA_def_property(srna, "alive_state", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "alive"); RNA_def_property_enum_items(prop, alive_items); @@ -1907,11 +1914,6 @@ 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, "editable", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", PSYS_EDITED); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* various checks needed */ - RNA_def_property_ui_text(prop, "Editable", "For hair particle systems, finalize the hair to enable editing."); - /* reactor */ prop= RNA_def_property(srna, "reactor_target_object", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "target_ob"); @@ -2089,12 +2091,28 @@ static void rna_def_particle_system(BlenderRNA *brna) RNA_def_property_struct_type(prop, "PointCache"); RNA_def_property_ui_text(prop, "Point Cache", ""); + prop= RNA_def_property(srna, "multiple_caches", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs(prop, "rna_ParticleSystem_multiple_caches_get", NULL); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Multiple Caches", "Particle system has multiple point caches"); + /* offset ob */ prop= RNA_def_property(srna, "parent", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "parent"); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Parent", "Use this object's coordinate system instead of global coordinate system."); RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo"); + + /* hair or cache editing */ + prop= RNA_def_property(srna, "editable", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs(prop, "rna_ParticleSystem_editable_get", NULL); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Editable", "Particle system can be edited in particle mode"); + + prop= RNA_def_property(srna, "edited", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs(prop, "rna_ParticleSystem_edited_get", NULL); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Edited", "Particle system has been edited in particle mode"); } void RNA_def_particle(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c index c2c906e38f2..fabe0b647ea 100644 --- a/source/blender/makesrna/intern/rna_sculpt_paint.c +++ b/source/blender/makesrna/intern/rna_sculpt_paint.c @@ -33,8 +33,34 @@ #include "BKE_paint.h" +#include "WM_types.h" + +static EnumPropertyItem particle_edit_hair_brush_items[] = { + {PE_BRUSH_NONE, "NONE", 0, "None", "Don't use any brush."}, + {PE_BRUSH_COMB, "COMB", 0, "Comb", "Comb hairs."}, + {PE_BRUSH_SMOOTH, "SMOOTH", 0, "Smooth", "Smooth hairs."}, + {PE_BRUSH_ADD, "ADD", 0, "Add", "Add hairs."}, + {PE_BRUSH_LENGTH, "LENGTH", 0, "Length", "Make hairs longer or shorter."}, + {PE_BRUSH_PUFF, "PUFF", 0, "Puff", "Make hairs stand up."}, + {PE_BRUSH_CUT, "CUT", 0, "Cut", "Cut hairs."}, + {0, NULL, 0, NULL, NULL}}; + +static EnumPropertyItem particle_edit_cache_brush_items[] = { + {PE_BRUSH_NONE, "NONE", 0, "None", "Don't use any brush."}, + {PE_BRUSH_COMB, "COMB", 0, "Comb", "Comb paths."}, + {PE_BRUSH_SMOOTH, "SMOOTH", 0, "Smooth", "Smooth paths."}, + {PE_BRUSH_LENGTH, "LENGTH", 0, "Length", "Make paths longer or shorter."}, + {0, NULL, 0, NULL, NULL}}; + #ifdef RNA_RUNTIME +#include "BKE_context.h" +#include "BKE_pointcache.h" +#include "BKE_particle.h" +#include "BKE_depsgraph.h" + +#include "ED_particle.h" + static PointerRNA rna_ParticleEdit_brush_get(PointerRNA *ptr) { ParticleEditSettings *pset= (ParticleEditSettings*)ptr->data; @@ -46,6 +72,7 @@ static PointerRNA rna_ParticleEdit_brush_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_ParticleBrush, brush); } + static PointerRNA rna_ParticleBrush_curve_get(PointerRNA *ptr) { return rna_pointer_inherit_refine(ptr, &RNA_CurveMapping, NULL); @@ -74,6 +101,65 @@ static void rna_Paint_active_brush_set(PointerRNA *ptr, PointerRNA value) paint_brush_set(ptr->data, value.data); } +static void rna_ParticleEdit_redo(bContext *C, PointerRNA *ptr) +{ + PTCacheEdit *edit = PE_get_current(CTX_data_scene(C), CTX_data_active_object(C)); + + if(!edit) + return; + + psys_free_path_cache(NULL, edit); +} + +static void rna_ParticleEdit_update(bContext *C, PointerRNA *ptr) +{ + Scene *scene = CTX_data_scene(C); + Object *ob = CTX_data_active_object(C); + + if(ob) + DAG_object_flush_update(scene, ob, OB_RECALC_DATA); +} + +static EnumPropertyItem *rna_ParticleEdit_tool_itemf(bContext *C, PointerRNA *ptr, int *free) +{ + Scene *scene= CTX_data_scene(C); + PTCacheEdit *edit; + + if(C==NULL) { + EnumPropertyItem *item= NULL; + int totitem= 0; + + /* needed for doc generation */ + RNA_enum_items_add(&item, &totitem, particle_edit_hair_brush_items); + RNA_enum_item_end(&item, &totitem); + + *free= 1; + + return item; + } + + edit = PE_get_current(scene, CTX_data_active_object(C)); + + if(edit && edit->psys) + return particle_edit_hair_brush_items; + + return particle_edit_cache_brush_items; +} + +static int rna_ParticleEdit_editable_get(PointerRNA *ptr) +{ + ParticleEditSettings *pset= (ParticleEditSettings*)ptr->data; + + return (pset->object && PE_get_current(pset->scene, pset->object)); +} +static int rna_ParticleEdit_hair_get(PointerRNA *ptr) +{ + ParticleEditSettings *pset= (ParticleEditSettings*)ptr->data; + + PTCacheEdit *edit = PE_get_current(pset->scene, pset->object); + + return (edit && edit->psys); +} #else static void rna_def_paint(BlenderRNA *brna) @@ -266,17 +352,6 @@ static void rna_def_particle_edit(BlenderRNA *brna) StructRNA *srna; PropertyRNA *prop; - static EnumPropertyItem tool_items[] = { - {PE_BRUSH_NONE, "NONE", 0, "None", "Don't use any brush."}, - {PE_BRUSH_COMB, "COMB", 0, "Comb", "Comb hairs."}, - {PE_BRUSH_SMOOTH, "SMOOTH", 0, "Smooth", "Smooth hairs."}, - {PE_BRUSH_WEIGHT, "WEIGHT", 0, "Weight", "Assign weight to hairs."}, - {PE_BRUSH_ADD, "ADD", 0, "Add", "Add hairs."}, - {PE_BRUSH_LENGTH, "LENGTH", 0, "Length", "Make hairs longer or shorter."}, - {PE_BRUSH_PUFF, "PUFF", 0, "Puff", "Make hairs stand up."}, - {PE_BRUSH_CUT, "CUT", 0, "Cut", "Cut hairs."}, - {0, NULL, 0, NULL, NULL}}; - static EnumPropertyItem select_mode_items[] = { {SCE_SELECT_PATH, "PATH", ICON_EDGESEL, "Path", ""}, // XXX icon {SCE_SELECT_POINT, "POINT", ICON_VERTEXSEL, "Point", ""}, // XXX icon @@ -293,6 +368,14 @@ static void rna_def_particle_edit(BlenderRNA *brna) {1, "SHRINK", 0, "Shrink", "Make hairs shorter."}, {0, NULL, 0, NULL, NULL}}; + static EnumPropertyItem edit_type_items[]= { + {PE_TYPE_PARTICLES, "PARTICLES", 0, "Particles", ""}, + {PE_TYPE_SOFTBODY, "SOFT_BODY", 0, "Soft body", ""}, + {PE_TYPE_CLOTH, "CLOTH", 0, "Cloth", ""}, + {0, NULL, 0, NULL, NULL} + }; + + /* edit */ srna= RNA_def_struct(brna, "ParticleEdit", NULL); @@ -301,13 +384,15 @@ static void rna_def_particle_edit(BlenderRNA *brna) prop= RNA_def_property(srna, "tool", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "brushtype"); - RNA_def_property_enum_items(prop, tool_items); + RNA_def_property_enum_items(prop, particle_edit_hair_brush_items); + RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_ParticleEdit_tool_itemf"); RNA_def_property_ui_text(prop, "Tool", ""); prop= RNA_def_property(srna, "selection_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "selectmode"); RNA_def_property_enum_items(prop, select_mode_items); RNA_def_property_ui_text(prop, "Selection Mode", "Particle select and display mode."); + RNA_def_property_update(prop, NC_OBJECT, "rna_ParticleEdit_update"); prop= RNA_def_property(srna, "keep_lengths", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", PE_KEEP_LENGTHS); @@ -326,13 +411,19 @@ static void rna_def_particle_edit(BlenderRNA *brna) RNA_def_property_ui_range(prop, 0.0f, 10.0f, 10, 3); RNA_def_property_ui_text(prop, "Emitter Distance", "Distance to keep particles away from the emitter."); - prop= RNA_def_property(srna, "show_time", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", PE_SHOW_TIME); - RNA_def_property_ui_text(prop, "Show Time", "Show time values of the baked keys."); + 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"); - prop= RNA_def_property(srna, "show_children", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", PE_SHOW_CHILD); - RNA_def_property_ui_text(prop, "Show Children", "Show child particles."); + prop= RNA_def_property(srna, "auto_velocity", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", PE_AUTO_VELOCITY); + RNA_def_property_ui_text(prop, "Auto Velocity", "Calculate point velocities automatically."); + + prop= RNA_def_property(srna, "draw_particles", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", PE_DRAW_PART); + RNA_def_property_ui_text(prop, "Draw Particles", "Draw actual particles."); + RNA_def_property_update(prop, NC_OBJECT, NULL); prop= RNA_def_property(srna, "mirror_x", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", PE_X_MIRROR); @@ -353,6 +444,37 @@ static void rna_def_particle_edit(BlenderRNA *brna) RNA_def_property_pointer_funcs(prop, "rna_ParticleEdit_brush_get", NULL, NULL); RNA_def_property_ui_text(prop, "Brush", ""); + 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"); + + 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"); + + 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"); + + prop= RNA_def_property(srna, "editable", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs(prop, "rna_ParticleEdit_editable_get", NULL); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Editable", "A valid edit mode exists"); + + prop= RNA_def_property(srna, "hair", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs(prop, "rna_ParticleEdit_hair_get", NULL); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Hair", "Editing hair"); + + prop= RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Object", "The edited object"); + + /* brush */ srna= RNA_def_struct(brna, "ParticleBrush", NULL); |