Point cache editing:
authorJanne Karhu <jhkarh@gmail.com>
Sat, 29 Aug 2009 15:20:36 +0000 (15:20 +0000)
committerJanne Karhu <jhkarh@gmail.com>
Sat, 29 Aug 2009 15:20:36 +0000 (15:20 +0000)
- Baked point caches for particles, cloth and softbody can now be edited in particle mode.
* This overwrites the old cloth/sb cache editmode editing.
* The type of editable system is chosen from a menu.
* For particles the current particle system and it's current cache are used.
- Currently this only works for caches that are in memory, but some automatic conversion from disk to memory and back can be implemented later.
- All tools from hair editing can't be applied to point caches and are hidden in the tool panel and specials menu. Some functionality like subdividing paths can be later implemented in a slightly different way from how it works for hair.
- Code is not yet optimized for speed, so editing might be slow sometimes.

Known issues:
- Cloth doesn't update properly while in particle mode, due to the way cloth modifier currently works. Daniel can you check on this?
- As "particle mode" is not only for particles any more some other name would be in place?
- Better icons are needed for the path, point, and tip-modes as the current icons from mesh edit mode are quite misleading.
- Direct editing of point velocities is not yet implemented, but will be in the future.

Other changes:
- Hair editing doesn't require a "make editable" button press any more.
- Multiple caches in single particle system disables changing emission properties.
- Unified ui code for all point cache panels.
* Defined in buttons_particle.py and imported for cloth, smoke & softbody.
- Proper disabling of properties in ui after baking point caches. (Daniel could you please make needed disable code for smoke panels as their functionality is not familiar to me.)
- Hair weight brush has been removed. Once hair dynamics is re-implemented I'll code a more useable alternative to the functionality.

Bug fixes:
- Unlinking particle settings crashed.
- Deleting the active object with particles in the scene crashed.
- Softbody didn't write point caches correctly on save.

28 files changed:
release/ui/buttons_particle.py
release/ui/buttons_physics_cloth.py
release/ui/buttons_physics_smoke.py
release/ui/buttons_physics_softbody.py
release/ui/space_view3d_toolbar.py
source/blender/blenkernel/BKE_particle.h
source/blender/blenkernel/BKE_pointcache.h
source/blender/blenkernel/intern/cloth.c
source/blender/blenkernel/intern/particle.c
source/blender/blenkernel/intern/particle_system.c
source/blender/blenkernel/intern/pointcache.c
source/blender/blenkernel/intern/scene.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/editors/include/ED_particle.h
source/blender/editors/mesh/editmesh.c
source/blender/editors/physics/ed_pointcache.c
source/blender/editors/physics/editparticle.c
source/blender/editors/space_outliner/outliner.c
source/blender/editors/space_view3d/drawobject.c
source/blender/editors/space_view3d/view3d_header.c
source/blender/editors/transform/transform_conversions.c
source/blender/editors/transform/transform_manipulator.c
source/blender/makesdna/DNA_object_force.h
source/blender/makesdna/DNA_particle_types.h
source/blender/makesdna/DNA_scene_types.h
source/blender/makesrna/intern/rna_particle.c
source/blender/makesrna/intern/rna_sculpt_paint.c

index 0454f2a402366ba667e0b9ed69d21804ce250450..0b18b7c2072a80916039666272351b678d11f193 100644 (file)
@@ -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"
index 9ddf03e3d4dfd42debc47d41f7670fa824fa0bd8..9399d557a518f1bb0aee314e2ce929dea782295c 100644 (file)
@@ -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()
                
index 3cfba0f9df9837a7524e8d76596dcc81dac0417f..d73136326385a484a3c12b26333a52bef705e8f5 100644 (file)
@@ -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
index 2beba8c95a0c67642751d31c9e2aa62fd467708a..3d3c3c23faf9ca76c82bc09242a3d196629275d5 100644 (file)
@@ -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()
index 0e6dc76d49dece1bc296198d99394a8c00810b4b..517571e1b098bbb83a4b5a9ceb54b5f98e91f761 100644 (file)
@@ -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)
index cf02efc34acd8b23094746532487d967a0626f6f..e24114cd2190d8c7d6594e30feb36813d3fa2963 100644 (file)
@@ -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
index 531487549daae5ec17dd859011c840220ceffc70..9ba3409106406997136fd5fd467106c3d00a9e06 100644 (file)
@@ -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);
index 3acaaecb1e87fc95a3beb287fdd7d2b198f0e35b..eafd9eb01feb1e792c748925fb40404bec6b775f 100644 (file)
@@ -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);
index e1987d34a6cec7e5063ce46c42a6f04ac8cff2a1..18e3512967a22795b4c99ee52e41aafff8c42706 100644 (file)
@@ -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);
 
index bf642a14a49c7bbab090b9a2267b15793e7f85d2..0f72c1c5866b45ee2054be2a7e29f1386a20ad35 100644 (file)
@@ -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;
        }
index 69da8f19d8c634c858912ebea9967b8729ec0dc7..c0223d1690c9ddfe03aa1e6eba7d59c750bcbbef 100644 (file)
@@ -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);
index 63dabf18faa5016063edc3a669d8d12ed562b2dd..10f6a8cf47c1a9c4cac567fb4a3891c875f6f56e 100644 (file)
@@ -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;
index 9d5ae3062a18eca4298be9562ee3514cc2db5819..070c873686c54d18272f03ab588bdfa3efd8af76 100644 (file)
@@ -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;
index 26fd0cf6af636a594af9ef122d3ad25eaffb5912..88c6f205d15a47f69eae6ee999c03dafc544ee95 100644 (file)
@@ -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);
index 43cb5053f48236537d062897d792b2882778cd38..dcac51928a3d95815ef197818cc134e5f25a2c44 100644 (file)
@@ -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 */
index 17838d6042cbe9f22745fbbe9a1919a7cec8ebc3..c3f1637d3aff5779b40ddbeb7009a9bfed20e6ef 100644 (file)
@@ -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;
index 917e2b40d724ec7ad1b2741de40148e3b3d2270f..68e0c28e9c1ca12ac0b2b7753572fa32f35aa805 100644 (file)
@@ -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;
 }
index b92632b45afcf8d9bd0e8b9a1d0e699f76bd4138..dbb11f7289065a369d975bcd714dcbad6405a285 100644 (file)
@@ -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"
 
 #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)
index fca5b0cc59adf703a4c49e2e65f52ea66eea1f48..e6cd9c0e4486e0775a913a2d1dcd086f004a7c11 100644 (file)
@@ -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);
index 6cf229ead31e3bf68d065784697575ccdbade2fe..e49616fc7408933fd1ccc69ab232cbd6f4c9b6bc 100644 (file)
@@ -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 */
        {
index eee85f217986936f98218629f8c751d409762651..305b69560371cdf3105dd7d4b879f63d6745e7ab 100644 (file)
@@ -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);
        }