Merge branch 'master' into blender2.8
authorBastien Montagne <montagne29@wanadoo.fr>
Mon, 11 Jul 2016 22:01:38 +0000 (00:01 +0200)
committerBastien Montagne <montagne29@wanadoo.fr>
Mon, 11 Jul 2016 22:07:44 +0000 (00:07 +0200)
Conflicts:
intern/cycles/blender/addon/ui.py
source/blender/blenkernel/BKE_particle.h
source/blender/blenkernel/intern/dynamicpaint.c
source/blender/blenkernel/intern/library.c
source/blender/blenkernel/intern/object.c
source/blender/blenkernel/intern/particle.c
source/blender/blenkernel/intern/particle_distribute.c
source/blender/blenkernel/intern/texture.c
source/blender/editors/object/object_add.c
source/blender/editors/object/object_relations.c
source/blender/editors/physics/particle_edit.c
source/blender/editors/physics/particle_object.c
source/blender/editors/transform/transform_snap_object.c

67 files changed:
1  2 
intern/cycles/blender/addon/ui.py
release/scripts/startup/bl_ui/space_dopesheet.py
release/scripts/startup/bl_ui/space_view3d.py
release/scripts/startup/bl_ui/space_view3d_toolbar.py
source/blender/blenkernel/BKE_library.h
source/blender/blenkernel/BKE_object.h
source/blender/blenkernel/BKE_texture.h
source/blender/blenkernel/intern/anim_sys.c
source/blender/blenkernel/intern/bpath.c
source/blender/blenkernel/intern/dynamicpaint.c
source/blender/blenkernel/intern/group.c
source/blender/blenkernel/intern/library.c
source/blender/blenkernel/intern/library_query.c
source/blender/blenkernel/intern/library_remap.c
source/blender/blenkernel/intern/modifier.c
source/blender/blenkernel/intern/object.c
source/blender/blenkernel/intern/object_update.c
source/blender/blenkernel/intern/scene.c
source/blender/blenkernel/intern/softbody.c
source/blender/blenkernel/intern/texture.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/versioning_250.c
source/blender/blenloader/intern/writefile.c
source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
source/blender/depsgraph/intern/builder/deg_builder_relations.cc
source/blender/editors/animation/anim_channels_edit.c
source/blender/editors/animation/anim_filter.c
source/blender/editors/include/ED_anim_api.h
source/blender/editors/interface/interface_icons.c
source/blender/editors/interface/interface_templates.c
source/blender/editors/object/object_add.c
source/blender/editors/object/object_edit.c
source/blender/editors/object/object_modifier.c
source/blender/editors/object/object_ops.c
source/blender/editors/object/object_relations.c
source/blender/editors/render/render_shading.c
source/blender/editors/sculpt_paint/paint_vertex.c
source/blender/editors/space_file/filesel.c
source/blender/editors/space_outliner/outliner_draw.c
source/blender/editors/space_outliner/outliner_intern.h
source/blender/editors/space_outliner/outliner_tree.c
source/blender/editors/space_view3d/drawobject.c
source/blender/editors/space_view3d/view3d_draw.c
source/blender/editors/space_view3d/view3d_edit.c
source/blender/editors/transform/transform.c
source/blender/editors/transform/transform_conversions.c
source/blender/editors/transform/transform_generics.c
source/blender/editors/transform/transform_manipulator.c
source/blender/editors/transform/transform_snap_object.c
source/blender/gpu/GPU_material.h
source/blender/gpu/intern/gpu_material.c
source/blender/makesdna/DNA_ID.h
source/blender/makesdna/DNA_scene_types.h
source/blender/makesdna/DNA_space_types.h
source/blender/makesdna/DNA_userdef_types.h
source/blender/makesrna/intern/rna_ID.c
source/blender/makesrna/intern/rna_action.c
source/blender/makesrna/intern/rna_main_api.c
source/blender/makesrna/intern/rna_modifier.c
source/blender/makesrna/intern/rna_nodetree.c
source/blender/makesrna/intern/rna_object.c
source/blender/makesrna/intern/rna_scene.c
source/blender/makesrna/intern/rna_space.c
source/blender/makesrna/intern/rna_userdef.c
source/blender/modifiers/intern/MOD_solidify.c
source/blender/render/intern/source/convertblender.c
source/blender/render/intern/source/pipeline.c

index 94ed3dd43112f869f824188761a98ea55ab7a2bf,120199479fefed0211f1166337a3b80b976f583e..3c9c83fec4264c31aa63784706cb5286c685a15f
@@@ -383,7 -383,6 +383,6 @@@ class CyclesRender_PT_performance(Cycle
          sub.prop(cscene, "use_progressive_refine")
  
          subsub = sub.column(align=True)
-         subsub.enabled = not rd.use_border
          subsub.prop(rd, "use_save_buffers")
  
          col = split.column(align=True)
@@@ -1384,6 -1383,37 +1383,6 @@@ class CyclesTexture_PT_colors(CyclesBut
              layout.template_color_ramp(mapping, "color_ramp", expand=True)
  
  
 -class CyclesParticle_PT_textures(CyclesButtonsPanel, Panel):
 -    bl_label = "Textures"
 -    bl_context = "particle"
 -    bl_options = {'DEFAULT_CLOSED'}
 -
 -    @classmethod
 -    def poll(cls, context):
 -        psys = context.particle_system
 -        return psys and CyclesButtonsPanel.poll(context)
 -
 -    def draw(self, context):
 -        layout = self.layout
 -
 -        psys = context.particle_system
 -        part = psys.settings
 -
 -        row = layout.row()
 -        row.template_list("TEXTURE_UL_texslots", "", part, "texture_slots", part, "active_texture_index", rows=2)
 -
 -        col = row.column(align=True)
 -        col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP'
 -        col.operator("texture.slot_move", text="", icon='TRIA_DOWN').type = 'DOWN'
 -        col.menu("TEXTURE_MT_specials", icon='DOWNARROW_HLT', text="")
 -
 -        if not part.active_texture:
 -            layout.template_ID(part, "active_texture", new="texture.new")
 -        else:
 -            slot = part.texture_slots[part.active_texture_index]
 -            layout.template_ID(slot, "texture", new="texture.new")
 -
 -
  class CyclesRender_PT_CurveRendering(CyclesButtonsPanel, Panel):
      bl_label = "Cycles Hair Rendering"
      bl_context = "particle"
@@@ -1532,6 -1562,37 +1531,6 @@@ class CyclesRender_PT_debug(CyclesButto
          col.prop(cscene, "debug_use_opencl_debug", text="Debug")
  
  
 -class CyclesParticle_PT_CurveSettings(CyclesButtonsPanel, Panel):
 -    bl_label = "Cycles Hair Settings"
 -    bl_context = "particle"
 -
 -    @classmethod
 -    def poll(cls, context):
 -        scene = context.scene
 -        ccscene = scene.cycles_curves
 -        psys = context.particle_system
 -        use_curves = ccscene.use_curves and psys
 -        return CyclesButtonsPanel.poll(context) and use_curves and psys.settings.type == 'HAIR'
 -
 -    def draw(self, context):
 -        layout = self.layout
 -
 -        psys = context.particle_settings
 -        cpsys = psys.cycles
 -
 -        row = layout.row()
 -        row.prop(cpsys, "shape", text="Shape")
 -
 -        layout.label(text="Thickness:")
 -        row = layout.row()
 -        row.prop(cpsys, "root_width", text="Root")
 -        row.prop(cpsys, "tip_width", text="Tip")
 -
 -        row = layout.row()
 -        row.prop(cpsys, "radius_scale", text="Scaling")
 -        row.prop(cpsys, "use_closetip", text="Close tip")
 -
 -
  class CyclesScene_PT_simplify(CyclesButtonsPanel, Panel):
      bl_label = "Simplify"
      bl_context = "scene"
          col = split.column()
          col.label(text="Viewport:")
          col.prop(rd, "simplify_subdivision", text="Subdivision")
 -        col.prop(rd, "simplify_child_particles", text="Child Particles")
  
          col = split.column()
          col.label(text="Render:")
          col.prop(rd, "simplify_subdivision_render", text="Subdivision")
 -        col.prop(rd, "simplify_child_particles_render", text="Child Particles")
  
          col = layout.column()
          col.prop(cscene, "use_camera_cull")
@@@ -1599,89 -1662,62 +1598,62 @@@ def draw_pause(self, context)
  
  
  def get_panels():
-     types = bpy.types
-     panels = [
-         "RENDER_PT_render",
-         "RENDER_PT_output",
-         "RENDER_PT_encoding",
-         "RENDER_PT_dimensions",
-         "RENDER_PT_stamp",
-         "RENDER_PT_freestyle",
-         "RENDERLAYER_PT_layers",
-         "RENDERLAYER_PT_freestyle",
-         "RENDERLAYER_PT_freestyle_lineset",
-         "RENDERLAYER_PT_freestyle_linestyle",
-         "SCENE_PT_scene",
-         "SCENE_PT_color_management",
-         "SCENE_PT_custom_props",
-         "SCENE_PT_audio",
-         "SCENE_PT_unit",
-         "SCENE_PT_keying_sets",
-         "SCENE_PT_keying_set_paths",
-         "SCENE_PT_physics",
-         "WORLD_PT_context_world",
-         "WORLD_PT_custom_props",
-         "DATA_PT_context_mesh",
-         "DATA_PT_context_camera",
-         "DATA_PT_context_lamp",
-         "DATA_PT_context_speaker",
-         "DATA_PT_normals",
-         "DATA_PT_texture_space",
-         "DATA_PT_curve_texture_space",
-         "DATA_PT_mball_texture_space",
-         "DATA_PT_vertex_groups",
-         "DATA_PT_shape_keys",
-         "DATA_PT_uv_texture",
-         "DATA_PT_vertex_colors",
-         "DATA_PT_camera",
-         "DATA_PT_camera_display",
-         "DATA_PT_camera_stereoscopy",
-         "DATA_PT_camera_safe_areas",
-         "DATA_PT_lens",
-         "DATA_PT_speaker",
-         "DATA_PT_distance",
-         "DATA_PT_cone",
-         "DATA_PT_customdata",
-         "DATA_PT_custom_props_mesh",
-         "DATA_PT_custom_props_camera",
-         "DATA_PT_custom_props_lamp",
-         "DATA_PT_custom_props_speaker",
-         "DATA_PT_custom_props_arm",
-         "DATA_PT_custom_props_curve",
-         "DATA_PT_custom_props_lattice",
-         "DATA_PT_custom_props_metaball",
-         "TEXTURE_PT_preview",
-         "TEXTURE_PT_custom_props",
-         "TEXTURE_PT_clouds",
-         "TEXTURE_PT_wood",
-         "TEXTURE_PT_marble",
-         "TEXTURE_PT_magic",
-         "TEXTURE_PT_blend",
-         "TEXTURE_PT_stucci",
-         "TEXTURE_PT_image",
-         "TEXTURE_PT_image_sampling",
-         "TEXTURE_PT_image_mapping",
-         "TEXTURE_PT_musgrave",
-         "TEXTURE_PT_voronoi",
-         "TEXTURE_PT_distortednoise",
-         "TEXTURE_PT_voxeldata",
-         "TEXTURE_PT_pointdensity",
-         "TEXTURE_PT_pointdensity_turbulence",
-         "TEXTURE_PT_mapping",
-         "TEXTURE_PT_ocean",
-         "TEXTURE_PT_influence",
-         "TEXTURE_PT_colors",
-         "SCENE_PT_rigid_body_world",
-         "SCENE_PT_rigid_body_cache",
-         "SCENE_PT_rigid_body_field_weights",
-         "MATERIAL_PT_custom_props",
-         "MATERIAL_PT_freestyle_line",
-         "BONE_PT_custom_props",
-         "OBJECT_PT_custom_props",
-         ]
-     return [getattr(types, p) for p in panels if hasattr(types, p)]
+     exclude_panels = {
+         'DATA_PT_area',
+         'DATA_PT_camera_dof',
+         'DATA_PT_falloff_curve',
+         'DATA_PT_lamp',
+         'DATA_PT_preview',
+         'DATA_PT_shadow',
+         'DATA_PT_spot',
+         'DATA_PT_sunsky',
+         'MATERIAL_PT_context_material',
+         'MATERIAL_PT_diffuse',
+         'MATERIAL_PT_flare',
+         'MATERIAL_PT_halo',
+         'MATERIAL_PT_mirror',
+         'MATERIAL_PT_options',
+         'MATERIAL_PT_pipeline',
+         'MATERIAL_PT_preview',
+         'MATERIAL_PT_shading',
+         'MATERIAL_PT_shadow',
+         'MATERIAL_PT_specular',
+         'MATERIAL_PT_sss',
+         'MATERIAL_PT_strand',
+         'MATERIAL_PT_transp',
+         'MATERIAL_PT_volume_density',
+         'MATERIAL_PT_volume_integration',
+         'MATERIAL_PT_volume_lighting',
+         'MATERIAL_PT_volume_options',
+         'MATERIAL_PT_volume_shading',
+         'MATERIAL_PT_volume_transp',
+         'RENDERLAYER_PT_layer_options',
+         'RENDERLAYER_PT_layer_passes',
+         'RENDERLAYER_PT_views',
+         'RENDER_PT_antialiasing',
+         'RENDER_PT_bake',
+         'RENDER_PT_motion_blur',
+         'RENDER_PT_performance',
+         'RENDER_PT_post_processing',
+         'RENDER_PT_shading',
+         'SCENE_PT_simplify',
+         'TEXTURE_PT_context_texture',
+         'WORLD_PT_ambient_occlusion',
+         'WORLD_PT_environment_lighting',
+         'WORLD_PT_gather',
+         'WORLD_PT_indirect_lighting',
+         'WORLD_PT_mist',
+         'WORLD_PT_preview',
+         'WORLD_PT_world'
+         }
+     panels = []
+     for panel in bpy.types.Panel.__subclasses__():
+         if hasattr(panel, 'COMPAT_ENGINES') and 'BLENDER_RENDER' in panel.COMPAT_ENGINES:
+             if panel.__name__ not in exclude_panels:
+                 panels.append(panel)
+     return panels
  
  def register():
      bpy.types.RENDER_PT_render.append(draw_device)
      for panel in get_panels():
          panel.COMPAT_ENGINES.add('CYCLES')
  
  def unregister():
      bpy.types.RENDER_PT_render.remove(draw_device)
      bpy.types.VIEW3D_HT_header.remove(draw_pause)
  
      for panel in get_panels():
-         panel.COMPAT_ENGINES.remove('CYCLES')
+         if 'CYCLES' in panel.COMPAT_ENGINES:
+             panel.COMPAT_ENGINES.remove('CYCLES')
index e6f81656e45bf01dd9c5a3c0b021cb63e20db6f1,d6d9198020151b53bdaf91a80f729ebee0ca545a..6878d4dbb12e5ddf1e3336462b6e0609457b6cab
@@@ -92,6 -92,8 +92,6 @@@ def dopesheet_filter(layout, context, g
                  row.prop(dopesheet, "show_lattices", text="")
              if bpy.data.armatures:
                  row.prop(dopesheet, "show_armatures", text="")
 -            if bpy.data.particles:
 -                row.prop(dopesheet, "show_particles", text="")
              if bpy.data.speakers:
                  row.prop(dopesheet, "show_speakers", text="")
              if bpy.data.linestyles:
              if bpy.data.grease_pencil:
                  row.prop(dopesheet, "show_gpencil", text="")
  
+             layout.prop(dopesheet, "use_datablock_sort", text="")
  
  #######################################
  # DopeSheet Editor - General/Standard UI
index 247c3e099a0f894ea067f07054db0253c8d39ee6,09e3bf38333e823f0a2a5f11f863d286c10a1676..882c3e820015d98f51096ea400cdc5c4948114c1
@@@ -47,9 -47,12 +47,9 @@@ class VIEW3D_HT_header(Header)
  
          if obj:
              mode = obj.mode
 -            # Particle edit
 -            if mode == 'PARTICLE_EDIT':
 -                row.prop(toolsettings.particle_edit, "select_mode", text="", expand=True)
  
              # Occlude geometry
 -            if ((view.viewport_shade not in {'BOUNDBOX', 'WIREFRAME'} and (mode == 'PARTICLE_EDIT' or (mode == 'EDIT' and obj.type == 'MESH'))) or
 +            if ((view.viewport_shade not in {'BOUNDBOX', 'WIREFRAME'} and (mode == 'EDIT' and obj.type == 'MESH')) or
                      (mode == 'WEIGHT_PAINT')):
                  row.prop(view, "use_occlude_geometry", text="")
  
@@@ -59,7 -62,7 +59,7 @@@
                  row.prop(toolsettings, "proportional_edit", icon_only=True)
                  if toolsettings.proportional_edit != 'DISABLED':
                      row.prop(toolsettings, "proportional_edit_falloff", icon_only=True)
 -            elif mode in {'EDIT', 'PARTICLE_EDIT'}:
 +            elif mode == 'EDIT':
                  row = layout.row(align=True)
                  row.prop(toolsettings, "proportional_edit", icon_only=True)
                  if toolsettings.proportional_edit != 'DISABLED':
@@@ -293,10 -296,6 +293,6 @@@ class VIEW3D_MT_transform_object(VIEW3D
          layout.operator("object.randomize_transform")
          layout.operator("object.align")
  
-         layout.separator()
-         layout.operator("object.anim_transforms_to_deltas")
  
  # Armature EditMode extensions to Transform menu
  class VIEW3D_MT_transform_armature(VIEW3D_MT_transform_base):
@@@ -686,6 -685,35 +682,6 @@@ class VIEW3D_MT_select_pose(Menu)
          layout.operator("object.select_pattern", text="Select Pattern...")
  
  
 -class VIEW3D_MT_select_particle(Menu):
 -    bl_label = "Select"
 -
 -    def draw(self, context):
 -        layout = self.layout
 -
 -        layout.operator("view3d.select_border")
 -
 -        layout.separator()
 -
 -        layout.operator("particle.select_all").action = 'TOGGLE'
 -        layout.operator("particle.select_linked")
 -        layout.operator("particle.select_all", text="Inverse").action = 'INVERT'
 -
 -        layout.separator()
 -
 -        layout.operator("particle.select_more")
 -        layout.operator("particle.select_less")
 -
 -        layout.separator()
 -
 -        layout.operator("particle.select_random")
 -
 -        layout.separator()
 -
 -        layout.operator("particle.select_roots", text="Roots")
 -        layout.operator("particle.select_tips", text="Tips")
 -
 -
  class VIEW3D_MT_edit_mesh_select_similar(Menu):
      bl_label = "Select Similar"
  
@@@ -1475,6 -1503,15 +1471,15 @@@ class VIEW3D_MT_object_apply(Menu)
          props = layout.operator("object.transform_apply", text="Rotation & Scale", text_ctxt=i18n_contexts.default)
          props.location, props.rotation, props.scale = False, True, True
  
+         layout.separator()
+         
+         layout.operator("object.transforms_to_deltas", text="Location to Deltas", text_ctxt=i18n_contexts.default).mode = 'LOC'
+         layout.operator("object.transforms_to_deltas", text="Rotation to Deltas", text_ctxt=i18n_contexts.default).mode = 'ROT'
+         layout.operator("object.transforms_to_deltas", text="Scale to Deltas", text_ctxt=i18n_contexts.default).mode = 'SCALE'
+         
+         layout.operator("object.transforms_to_deltas", text="All Transforms to Deltas", text_ctxt=i18n_contexts.default).mode = 'ALL'
+         layout.operator("object.anim_transforms_to_deltas")
+         
          layout.separator()
  
          layout.operator("object.visual_transform_apply", text="Visual Transform", text_ctxt=i18n_contexts.default)
@@@ -1868,8 -1905,87 +1873,8 @@@ class VIEW3D_MT_hide_mask(Menu)
          props = layout.operator("paint.mask_lasso_gesture", text="Lasso Mask")
  
  
 -# ********** Particle menu **********
 -
 -
 -class VIEW3D_MT_particle(Menu):
 -    bl_label = "Particle"
 -
 -    def draw(self, context):
 -        layout = self.layout
 -
 -        particle_edit = context.tool_settings.particle_edit
 -
 -        layout.operator("ed.undo")
 -        layout.operator("ed.redo")
 -        layout.operator("ed.undo_history")
 -
 -        layout.separator()
 -
 -        layout.operator("particle.mirror")
 -
 -        layout.separator()
 -
 -        layout.operator("particle.remove_doubles")
 -        layout.operator("particle.delete")
 -
 -        if particle_edit.select_mode == 'POINT':
 -            layout.operator("particle.subdivide")
 -
          layout.operator("particle.unify_length")
 -        layout.operator("particle.rekey")
 -        layout.operator("particle.weight_set")
 -
 -        layout.separator()
 -
 -        layout.menu("VIEW3D_MT_particle_showhide")
 -
 -
 -class VIEW3D_MT_particle_specials(Menu):
 -    bl_label = "Specials"
 -
 -    def draw(self, context):
 -        layout = self.layout
 -
 -        particle_edit = context.tool_settings.particle_edit
 -
 -        layout.operator("particle.rekey")
 -        layout.operator("particle.delete")
 -        layout.operator("particle.remove_doubles")
          layout.operator("particle.unify_length")
 -
 -        if particle_edit.select_mode == 'POINT':
 -            layout.operator("particle.subdivide")
 -
 -        layout.operator("particle.weight_set")
 -        layout.separator()
 -
 -        layout.operator("particle.mirror")
 -
 -        if particle_edit.select_mode == 'POINT':
 -            layout.separator()
 -            layout.operator("particle.select_roots")
 -            layout.operator("particle.select_tips")
 -
 -            layout.separator()
 -
 -            layout.operator("particle.select_random")
 -
 -            layout.separator()
 -
 -            layout.operator("particle.select_more")
 -            layout.operator("particle.select_less")
 -
 -            layout.separator()
 -
 -            layout.operator("particle.select_all").action = 'TOGGLE'
 -            layout.operator("particle.select_linked")
 -            layout.operator("particle.select_all", text="Inverse").action = 'INVERT'
 -
 -
 -class VIEW3D_MT_particle_showhide(ShowHideMenu, Menu):
 -    _operator_name = "particle"
 -
  # ********** Pose Menu **********
  
  
@@@ -2476,6 -2592,7 +2481,7 @@@ class VIEW3D_MT_edit_mesh_clean(Menu)
  
          layout.separator()
  
+         layout.operator("mesh.decimate")
          layout.operator("mesh.dissolve_degenerate")
          layout.operator("mesh.dissolve_limited")
          layout.operator("mesh.face_make_planar")
index ce605fcdbbe6a3ec956b1cd92ce2da1bcd8f305d,ca1ab4c37ddc316bbe959d6b92db56e3b8a36e39..b2b4d4fa1480d162e1f0ba6fbcad3f6187b3efdd
@@@ -938,12 -938,37 +938,12 @@@ class VIEW3D_PT_tools_brush(Panel, View
          settings = self.paint_settings(context)
          brush = settings.brush
  
 -        if not context.particle_edit_object:
 -            col = layout.split().column()
 -            col.template_ID_preview(settings, "brush", new="brush.add", rows=3, cols=8)
 -
 -        # Particle Mode #
 -        if context.particle_edit_object:
 -            tool = settings.tool
 -
 -            layout.column().prop(settings, "tool", expand=True)
 -
 -            if tool != 'NONE':
 -                col = layout.column()
 -                col.prop(brush, "size", slider=True)
 -                if tool != 'ADD':
 -                    col.prop(brush, "strength", slider=True)
 -
 -            if tool == 'ADD':
 -                col.prop(brush, "count")
 -                col = layout.column()
 -                col.prop(settings, "use_default_interpolate")
 -                col.prop(brush, "steps", slider=True)
 -                col.prop(settings, "default_key_count", slider=True)
 -            elif tool == 'LENGTH':
 -                layout.prop(brush, "length_mode", expand=True)
 -            elif tool == 'PUFF':
 -                layout.prop(brush, "puff_mode", expand=True)
 -                layout.prop(brush, "use_puff_volume")
 +        col = layout.split().column()
 +        col.template_ID_preview(settings, "brush", new="brush.add", rows=3, cols=8)
  
          # Sculpt Mode #
  
 -        elif context.sculpt_object and brush:
 +        if context.sculpt_object and brush:
              capabilities = brush.sculpt_capabilities
  
              col = layout.column()
@@@ -1507,6 -1532,15 +1507,15 @@@ class VIEW3D_PT_sculpt_dyntopo(Panel, V
      def poll(cls, context):
          return (context.sculpt_object and context.tool_settings.sculpt)
  
+     def draw_header(self, context):
+         layout = self.layout
+         layout.operator(
+                 "sculpt.dynamic_topology_toggle",
+                 icon='CHECKBOX_HLT' if context.sculpt_object.use_dynamic_topology_sculpting else 'CHECKBOX_DEHLT',
+                 text="",
+                 emboss=False,
+                 )
      def draw(self, context):
          layout = self.layout
  
          settings = self.paint_settings(context)
          brush = settings.brush
  
-         if context.sculpt_object.use_dynamic_topology_sculpting:
-             layout.operator("sculpt.dynamic_topology_toggle", icon='X', text="Disable Dyntopo")
-         else:
-             layout.operator("sculpt.dynamic_topology_toggle", icon='SCULPT_DYNTOPO', text="Enable Dyntopo")
          col = layout.column()
          col.active = context.sculpt_object.use_dynamic_topology_sculpting
          sub = col.column(align=True)
@@@ -1624,7 -1653,7 +1628,7 @@@ class VIEW3D_PT_tools_brush_appearance(
      @classmethod
      def poll(cls, context):
          settings = cls.paint_settings(context)
 -        return (settings is not None) and (not isinstance(settings, bpy.types.ParticleEdit))
 +        return (settings is not None)
  
      def draw(self, context):
          layout = self.layout
@@@ -1847,6 -1876,78 +1851,6 @@@ class VIEW3D_MT_tools_projectpaint_sten
              props.value = i
  
  
 -class VIEW3D_PT_tools_particlemode(View3DPanel, Panel):
 -    """Default tools for particle mode"""
 -    bl_context = "particlemode"
 -    bl_label = "Options"
 -    bl_category = "Tools"
 -
 -    def draw(self, context):
 -        layout = self.layout
 -
 -        pe = context.tool_settings.particle_edit
 -        ob = pe.object
 -
 -        layout.prop(pe, "type", text="")
 -
 -        ptcache = None
 -
 -        if pe.type == 'PARTICLES':
 -            if ob.particle_systems:
 -                if len(ob.particle_systems) > 1:
 -                    layout.template_list("UI_UL_list", "particle_systems", ob, "particle_systems",
 -                                         ob.particle_systems, "active_index", rows=2, maxrows=3)
 -
 -                ptcache = ob.particle_systems.active.point_cache
 -        else:
 -            for md in ob.modifiers:
 -                if md.type == pe.type:
 -                    ptcache = md.point_cache
 -
 -        if ptcache and len(ptcache.point_caches) > 1:
 -            layout.template_list("UI_UL_list", "particles_point_caches", ptcache, "point_caches",
 -                                 ptcache.point_caches, "active_index", rows=2, maxrows=3)
 -
 -        if not pe.is_editable:
 -            layout.label(text="Point cache must be baked")
 -            layout.label(text="in memory to enable editing!")
 -
 -        col = layout.column(align=True)
 -        if pe.is_hair:
 -            col.active = pe.is_editable
 -            col.prop(pe, "use_emitter_deflect", text="Deflect emitter")
 -            sub = col.row(align=True)
 -            sub.active = pe.use_emitter_deflect
 -            sub.prop(pe, "emitter_distance", text="Distance")
 -
 -        col = layout.column(align=True)
 -        col.active = pe.is_editable
 -        col.label(text="Keep:")
 -        col.prop(pe, "use_preserve_length", text="Lengths")
 -        col.prop(pe, "use_preserve_root", text="Root")
 -        if not pe.is_hair:
 -            col.label(text="Correct:")
 -            col.prop(pe, "use_auto_velocity", text="Velocity")
 -        col.prop(ob.data, "use_mirror_x")
 -
 -        col.prop(pe, "shape_object")
 -        col.operator("particle.shape_cut")
 -
 -        col = layout.column(align=True)
 -        col.active = pe.is_editable
 -        col.label(text="Draw:")
 -        col.prop(pe, "draw_step", text="Path Steps")
 -        if pe.is_hair:
 -            col.prop(pe, "show_particles", text="Children")
 -        else:
 -            if pe.type == 'PARTICLES':
 -                col.prop(pe, "show_particles", text="Particles")
 -            col.prop(pe, "use_fade_time")
 -            sub = col.row(align=True)
 -            sub.active = pe.use_fade_time
 -            sub.prop(pe, "fade_frames", slider=True)
 -
 -
  # Grease Pencil drawing tools
  class VIEW3D_PT_tools_grease_pencil_draw(GreasePencilDrawingToolsPanel, Panel):
      bl_space_type = 'VIEW_3D'
index 2e225775af0c66e15d2e3f80197c5f33839e1583,d419d25747181bcc32478fdaed7f29d9d8101a78..cb39b2e53eeb298dc4fce8e250b1a45550271ed5
@@@ -52,9 -52,8 +52,8 @@@ struct PropertyRNA
  void *BKE_libblock_alloc_notest(short type);
  void *BKE_libblock_alloc(struct Main *bmain, short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
  void  BKE_libblock_init_empty(struct ID *id);
- void *BKE_libblock_copy_ex(struct Main *bmain, struct ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+ void *BKE_libblock_copy(struct Main *bmain, struct ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
  void *BKE_libblock_copy_nolib(struct ID *id, const bool do_action) ATTR_NONNULL();
- void *BKE_libblock_copy(struct ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
  void  BKE_libblock_copy_data(struct ID *id, const struct ID *id_from, const bool do_action);
  void  BKE_libblock_relink(struct ID *id);
  void  BKE_libblock_rename(struct Main *bmain, struct ID *id, const char *name) ATTR_NONNULL();
@@@ -81,10 -80,11 +80,11 @@@ void id_us_min(struct ID *id)
  void id_fake_user_set(struct ID *id);
  void id_fake_user_clear(struct ID *id);
  
- bool id_make_local(struct ID *id, bool test);
+ bool id_make_local(struct Main *bmain, struct ID *id, bool test);
  bool id_single_user(struct bContext *C, struct ID *id, struct PointerRNA *ptr, struct PropertyRNA *prop);
- bool id_copy(struct ID *id, struct ID **newid, bool test);
+ bool id_copy(struct Main *bmain, struct ID *id, struct ID **newid, bool test);
  void id_sort_by_name(struct ListBase *lb, struct ID *id);
+ void BKE_id_expand_local(struct ID *id);
  
  bool new_id(struct ListBase *lb, struct ID *id, const char *name);
  void id_clear_lib_data(struct Main *bmain, struct ID *id);
@@@ -92,7 -92,7 +92,7 @@@ void id_clear_lib_data_ex(struct Main *
  
  struct ListBase *which_libbase(struct Main *mainlib, short type);
  
 -#define MAX_LIBARRAY    34
 +#define MAX_LIBARRAY    33
  int set_listbasepointers(struct Main *main, struct ListBase *lb[MAX_LIBARRAY]);
  
  /* Main API */
index 612c758139abfe3e10914cc8c601b4a8fce1a9ea,1f0dc5f181414852235da2a06cf885b6b5365f9d..2c4df9620c2a3eb7ab080b260ba8fd36197fb9d0
@@@ -55,7 -55,10 +55,7 @@@ void BKE_object_workob_calc_parent(stru
  void BKE_object_transform_copy(struct Object *ob_tar, const struct Object *ob_src);
  struct SoftBody *copy_softbody(const struct SoftBody *sb, bool copy_caches);
  struct BulletSoftBody *copy_bulletsoftbody(struct BulletSoftBody *sb);
 -struct ParticleSystem *BKE_object_copy_particlesystem(struct ParticleSystem *psys);
 -void BKE_object_copy_particlesystems(struct Object *ob_dst, const struct Object *ob_src);
  void BKE_object_copy_softbody(struct Object *ob_dst, const struct Object *ob_src);
 -void BKE_object_free_particlesystems(struct Object *ob);
  void BKE_object_free_softbody(struct Object *ob);
  void BKE_object_free_bulletsoftbody(struct Object *ob);
  void BKE_object_free_curve_cache(struct Object *ob);
@@@ -103,8 -106,8 +103,8 @@@ struct Object *BKE_object_lod_meshob_ge
  struct Object *BKE_object_lod_matob_get(struct Object *ob, struct Scene *scene);
  
  struct Object *BKE_object_copy_ex(struct Main *bmain, struct Object *ob, bool copy_caches);
- struct Object *BKE_object_copy(struct Object *ob);
- void BKE_object_make_local(struct Object *ob);
+ struct Object *BKE_object_copy(struct Main *bmain, struct Object *ob);
+ void BKE_object_make_local(struct Main *bmain, struct Object *ob);
  bool BKE_object_is_libdata(struct Object *ob);
  bool BKE_object_obdata_is_libdata(struct Object *ob);
  
index 433785514495ee9dba20afde3fc479e603fcdedd,56f056c681ab93a18645447bab351d6fdd8b2e4e..52b1906a78bc6033588e6bbc048d4dfa86f72153
@@@ -47,6 -47,7 +47,6 @@@ struct Main
  struct Material;
  struct MTex;
  struct OceanTex;
 -struct ParticleSettings;
  struct PointDensity;
  struct Tex;
  struct TexMapping;
@@@ -68,10 -69,10 +68,10 @@@ void colorband_update_sort(struct Color
  
  void         BKE_texture_free(struct Tex *tex);
  void         BKE_texture_default(struct Tex *tex);
- struct Tex  *BKE_texture_copy(struct Tex *tex);
+ struct Tex  *BKE_texture_copy(struct Main *bmain, struct Tex *tex);
  struct Tex  *BKE_texture_add(struct Main *bmain, const char *name);
  struct Tex  *BKE_texture_localize(struct Tex *tex);
- void         BKE_texture_make_local(struct Tex *tex);
+ void         BKE_texture_make_local(struct Main *bmain, struct Tex *tex);
  void         BKE_texture_type_set(struct Tex *tex, int type);
  
  void         BKE_texture_mtex_default(struct MTex *mtex);
@@@ -86,6 -87,7 +86,6 @@@ struct Tex *give_current_lamp_texture(s
  struct Tex *give_current_linestyle_texture(struct FreestyleLineStyle *linestyle);
  struct Tex *give_current_world_texture(struct World *world);
  struct Tex *give_current_brush_texture(struct Brush *br);
 -struct Tex *give_current_particle_texture(struct ParticleSettings *part);
  
  struct bNode *give_current_material_texture_node(struct Material *ma);
  
@@@ -97,6 -99,7 +97,6 @@@ void set_current_world_texture(struct W
  void set_current_material_texture(struct Material *ma, struct Tex *tex);
  void set_current_lamp_texture(struct Lamp *la, struct Tex *tex);
  void set_current_linestyle_texture(struct FreestyleLineStyle *linestyle, struct Tex *tex);
 -void set_current_particle_texture(struct ParticleSettings *part, struct Tex *tex);
  
  bool has_current_material_texture(struct Material *ma);
  
index b7e8bc62470b7b00ebc378b4fbf1aeee61b335d6,d6f93528262ea99dde9b82d93bc5282bfc61208c..7f10f6833db184e0d33d50d3abea8265bee6395c
  /* Getter/Setter -------------------------------------------- */
  
  /* Check if ID can have AnimData */
- bool id_type_can_have_animdata(ID *id)
+ bool id_type_can_have_animdata(const short id_type)
  {
-       /* sanity check */
-       if (id == NULL)
-               return false;
        /* Only some ID-blocks have this info for now */
        /* TODO: finish adding this for the other blocktypes */
-       switch (GS(id->name)) {
+       switch (id_type) {
                /* has AnimData */
                case ID_OB:
                case ID_ME: case ID_MB: case ID_CU: case ID_AR: case ID_LT:
                case ID_KE:
 -              case ID_PA:
                case ID_MA: case ID_TE: case ID_NT:
                case ID_LA: case ID_CA: case ID_WO:
                case ID_LS:
                case ID_MC:
                case ID_MSK:
                case ID_GD:
-               {
                        return true;
-               }
                
                /* no AnimData */
                default:
        }
  }
  
+ bool id_can_have_animdata(const ID *id)
+ {
+       /* sanity check */
+       if (id == NULL)
+               return false;
+       return id_type_can_have_animdata(GS(id->name));
+ }
  
  /* Get AnimData from the given ID-block. In order for this to work, we assume that 
   * the AnimData pointer is stored immediately after the given ID-block in the struct,
@@@ -121,7 -124,7 +123,7 @@@ AnimData *BKE_animdata_from_id(ID *id
         * types that do to be of type IdAdtTemplate, and extract the
         * AnimData that way
         */
-       if (id_type_can_have_animdata(id)) {
+       if (id_can_have_animdata(id)) {
                IdAdtTemplate *iat = (IdAdtTemplate *)id;
                return iat->adt;
        }
@@@ -139,7 -142,7 +141,7 @@@ AnimData *BKE_animdata_add_id(ID *id
         * types that do to be of type IdAdtTemplate, and add the AnimData
         * to it using the template
         */
-       if (id_type_can_have_animdata(id)) {
+       if (id_can_have_animdata(id)) {
                IdAdtTemplate *iat = (IdAdtTemplate *)id;
                
                /* check if there's already AnimData, in which case, don't add */
@@@ -220,7 -223,7 +222,7 @@@ void BKE_animdata_free(ID *id, const bo
        /* Only some ID-blocks have this info for now, so we cast the 
         * types that do to be of type IdAdtTemplate
         */
-       if (id_type_can_have_animdata(id)) {
+       if (id_can_have_animdata(id)) {
                IdAdtTemplate *iat = (IdAdtTemplate *)id;
                AnimData *adt = iat->adt;
                
@@@ -265,8 -268,8 +267,8 @@@ AnimData *BKE_animdata_copy(AnimData *a
        
        /* make a copy of action - at worst, user has to delete copies... */
        if (do_action) {
-               dadt->action = BKE_action_copy(adt->action);
-               dadt->tmpact = BKE_action_copy(adt->tmpact);
+               dadt->action = BKE_action_copy(G.main, adt->action);
+               dadt->tmpact = BKE_action_copy(G.main, adt->tmpact);
        }
        else {
                id_us_plus((ID *)dadt->action);
@@@ -310,11 -313,11 +312,11 @@@ void BKE_animdata_copy_id_action(ID *id
        if (adt) {
                if (adt->action) {
                        id_us_min((ID *)adt->action);
-                       adt->action = BKE_action_copy(adt->action);
+                       adt->action = BKE_action_copy(G.main, adt->action);
                }
                if (adt->tmpact) {
                        id_us_min((ID *)adt->tmpact);
-                       adt->tmpact = BKE_action_copy(adt->tmpact);
+                       adt->tmpact = BKE_action_copy(G.main, adt->tmpact);
                }
        }
  }
@@@ -338,8 -341,8 +340,8 @@@ void BKE_animdata_merge_copy(ID *dst_id
        /* handle actions... */
        if (action_mode == ADT_MERGECOPY_SRC_COPY) {
                /* make a copy of the actions */
-               dst->action = BKE_action_copy(src->action);
-               dst->tmpact = BKE_action_copy(src->tmpact);
+               dst->action = BKE_action_copy(G.main, src->action);
+               dst->tmpact = BKE_action_copy(G.main, src->tmpact);
        }
        else if (action_mode == ADT_MERGECOPY_SRC_REF) {
                /* make a reference to it */
@@@ -397,8 -400,8 +399,8 @@@ static void make_local_strips(ListBase 
        NlaStrip *strip;
  
        for (strip = strips->first; strip; strip = strip->next) {
-               if (strip->act) BKE_action_make_local(strip->act);
-               if (strip->remap && strip->remap->target) BKE_action_make_local(strip->remap->target);
+               if (strip->act) BKE_action_make_local(G.main, strip->act);
+               if (strip->remap && strip->remap->target) BKE_action_make_local(G.main, strip->remap->target);
                
                make_local_strips(&strip->strips);
        }
@@@ -410,10 -413,10 +412,10 @@@ void BKE_animdata_make_local(AnimData *
        NlaTrack *nlt;
        
        /* Actions - Active and Temp */
-       if (adt->action) BKE_action_make_local(adt->action);
-       if (adt->tmpact) BKE_action_make_local(adt->tmpact);
+       if (adt->action) BKE_action_make_local(G.main, adt->action);
+       if (adt->tmpact) BKE_action_make_local(G.main, adt->tmpact);
        /* Remaps */
-       if (adt->remap && adt->remap->target) BKE_action_make_local(adt->remap->target);
+       if (adt->remap && adt->remap->target) BKE_action_make_local(G.main, adt->remap->target);
        
        /* Drivers */
        /* TODO: need to remap the ID-targets too? */
@@@ -1048,7 -1051,7 +1050,7 @@@ void BKE_animdata_fix_paths_remove(ID *
         */
        NlaTrack *nlt;
  
-       if (id_type_can_have_animdata(id)) {
+       if (id_can_have_animdata(id)) {
                IdAdtTemplate *iat = (IdAdtTemplate *)id;
                AnimData *adt = iat->adt;
  
@@@ -1131,6 -1134,9 +1133,6 @@@ void BKE_animdata_main_cb(Main *mainptr
        /* meshes */
        ANIMDATA_IDS_CB(mainptr->mesh.first);
        
 -      /* particles */
 -      ANIMDATA_IDS_CB(mainptr->particle.first);
 -
        /* speakers */
        ANIMDATA_IDS_CB(mainptr->speaker.first);
  
@@@ -1221,6 -1227,9 +1223,6 @@@ void BKE_animdata_fix_paths_rename_all(
        /* meshes */
        RENAMEFIX_ANIM_IDS(mainptr->mesh.first);
        
 -      /* particles */
 -      RENAMEFIX_ANIM_IDS(mainptr->particle.first);
 -
        /* speakers */
        RENAMEFIX_ANIM_IDS(mainptr->speaker.first);
  
@@@ -2804,6 -2813,9 +2806,6 @@@ void BKE_animsys_evaluate_all_animation
        /* meshes */
        EVAL_ANIM_IDS(main->mesh.first, ADT_RECALC_ANIM);
        
 -      /* particles */
 -      EVAL_ANIM_IDS(main->particle.first, ADT_RECALC_ANIM);
 -      
        /* speakers */
        EVAL_ANIM_IDS(main->speaker.first, ADT_RECALC_ANIM);
  
index e338974eca6a56c605a93f7bc67011badb4a8aab,a708c59fa971820be3e3119f7277553852a233e2..f3ff0f253e53dfbe55335c38a07385ba839d416d
@@@ -55,6 -55,7 +55,6 @@@
  #include "DNA_object_fluidsim.h"
  #include "DNA_object_force.h"
  #include "DNA_object_types.h"
 -#include "DNA_particle_types.h"
  #include "DNA_sequence_types.h"
  #include "DNA_sound_types.h"
  #include "DNA_text_types.h"
@@@ -423,7 -424,7 +423,7 @@@ void BKE_bpath_traverse_id(Main *bmain
  {
        const char *absbase = (flag & BKE_BPATH_TRAVERSE_ABS) ? ID_BLEND_PATH(bmain, id) : NULL;
  
-       if ((flag & BKE_BPATH_TRAVERSE_SKIP_LIBRARY) && id->lib) {
+       if ((flag & BKE_BPATH_TRAVERSE_SKIP_LIBRARY) && ID_IS_LINKED_DATABLOCK(id)) {
                return;
        }
  
                {
                        Object *ob = (Object *)id;
                        ModifierData *md;
 -                      ParticleSystem *psys;
 -
 -#define BPATH_TRAVERSE_POINTCACHE(ptcaches)                                    \
 -      {                                                                          \
 -              PointCache *cache;                                                     \
 -              for (cache = (ptcaches).first; cache; cache = cache->next) {           \
 -                      if (cache->flag & PTCACHE_DISK_CACHE) {                            \
 -                              rewrite_path_fixed(cache->path,                                \
 -                                                 visit_cb,                                   \
 -                                                 absbase,                                    \
 -                                                 bpath_user_data);                           \
 -                      }                                                                  \
 -              }                                                                      \
 -      } (void)0
  
                        /* do via modifiers instead */
  #if 0
                                                rewrite_path_fixed(fluidmd->fss->surfdataPath, visit_cb, absbase, bpath_user_data);
                                        }
                                }
 -                              else if (md->type == eModifierType_Smoke) {
 -                                      SmokeModifierData *smd = (SmokeModifierData *)md;
 -                                      if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
 -                                              BPATH_TRAVERSE_POINTCACHE(smd->domain->ptcaches[0]);
 -                                      }
 -                              }
 -                              else if (md->type == eModifierType_Cloth) {
 -                                      ClothModifierData *clmd = (ClothModifierData *) md;
 -                                      BPATH_TRAVERSE_POINTCACHE(clmd->ptcaches);
 -                              }
                                else if (md->type == eModifierType_Ocean) {
                                        OceanModifierData *omd = (OceanModifierData *) md;
                                        rewrite_path_fixed(omd->cachepath, visit_cb, absbase, bpath_user_data);
                                }
                        }
  
 -                      if (ob->soft) {
 -                              BPATH_TRAVERSE_POINTCACHE(ob->soft->ptcaches);
 -                      }
 -
 -                      for (psys = ob->particlesystem.first; psys; psys = psys->next) {
 -                              BPATH_TRAVERSE_POINTCACHE(psys->ptcaches);
 -                      }
 -
 -#undef BPATH_TRAVERSE_POINTCACHE
 -
                        break;
                }
                case ID_SO:
index d02041d6da8f4d7baa74bce5367288046240c622,2b097f31c59ecd819dd890cadcc599442349da05..82ea710b5b6f73123c98bca6eb8f52c4e48a03b5
@@@ -48,7 -48,6 +48,7 @@@
  #include "DNA_meshdata_types.h"
  #include "DNA_modifier_types.h"
  #include "DNA_object_types.h"
 +#include "DNA_object_force.h"
  #include "DNA_scene_types.h"
  #include "DNA_texture_types.h"
  
@@@ -69,6 -68,8 +69,6 @@@
  #include "BKE_mesh_mapping.h"
  #include "BKE_modifier.h"
  #include "BKE_object.h"
 -#include "BKE_particle.h"
 -#include "BKE_pointcache.h"
  #include "BKE_scene.h"
  #include "BKE_texture.h"
  
@@@ -558,7 -559,7 +558,7 @@@ static bool boundsIntersectDist(Bounds3
  }
  
  /* check whether bounds intersects a point with given radius */
 -static bool boundIntersectPoint(Bounds3D *b, float point[3], const float radius)
 +static bool UNUSED_FUNCTION(boundIntersectPoint)(Bounds3D *b, float point[3], const float radius)
  {
        if (!b->valid)
                return false;
@@@ -857,7 -858,7 +857,7 @@@ static void surface_freeUnusedData(Dyna
                return;
  
        /* free bakedata if not active or surface is baked */
 -      if (!(surface->flags & MOD_DPAINT_ACTIVE) || (surface->pointcache && surface->pointcache->flag & PTCACHE_BAKED)) {
 +      if (!(surface->flags & MOD_DPAINT_ACTIVE)) {
                free_bakeData(surface->data);
        }
  }
@@@ -892,6 -893,10 +892,6 @@@ void dynamicPaint_freeSurfaceData(Dynam
  
  void dynamicPaint_freeSurface(DynamicPaintSurface *surface)
  {
 -      /* point cache */
 -      BKE_ptcache_free_list(&(surface->ptcaches));
 -      surface->pointcache = NULL;
 -
        if (surface->effector_weights)
                MEM_freeN(surface->effector_weights);
        surface->effector_weights = NULL;
@@@ -952,6 -957,11 +952,6 @@@ DynamicPaintSurface *dynamicPaint_creat
        surface->format = MOD_DPAINT_SURFACE_F_VERTEX;
        surface->type = MOD_DPAINT_SURFACE_T_PAINT;
  
 -      /* cache */
 -      surface->pointcache = BKE_ptcache_add(&(surface->ptcaches));
 -      surface->pointcache->flag |= PTCACHE_DISK_CACHE;
 -      surface->pointcache->step = 1;
 -
        /* Set initial values */
        surface->flags = MOD_DPAINT_ANTIALIAS | MOD_DPAINT_MULALPHA | MOD_DPAINT_DRY_LOG | MOD_DPAINT_DISSOLVE_LOG |
                         MOD_DPAINT_ACTIVE | MOD_DPAINT_PREVIEW | MOD_DPAINT_OUT1 | MOD_DPAINT_USE_DRYING;
@@@ -1042,6 -1052,8 +1042,6 @@@ bool dynamicPaint_createType(struct Dyn
                                return false;
                        brush->pmd = pmd;
  
 -                      brush->psys = NULL;
 -
                        brush->flags = MOD_DPAINT_ABS_ALPHA | MOD_DPAINT_RAMP_ALPHA;
                        brush->collision = MOD_DPAINT_COL_VOLUME;
  
@@@ -1195,6 -1207,7 +1195,6 @@@ void dynamicPaint_Modifier_copy(struct 
                t_brush->particle_radius = brush->particle_radius;
                t_brush->particle_smooth = brush->particle_smooth;
                t_brush->paint_distance = brush->paint_distance;
 -              t_brush->psys = brush->psys;
  
                if (brush->paint_ramp)
                        memcpy(t_brush->paint_ramp, brush->paint_ramp, sizeof(ColorBand));
@@@ -1927,6 -1940,15 +1927,6 @@@ static DerivedMesh *dynamicPaint_Modifi
        return result;
  }
  
 -/* update cache frame range */
 -void dynamicPaint_cacheUpdateFrames(DynamicPaintSurface *surface)
 -{
 -      if (surface->pointcache) {
 -              surface->pointcache->startframe = surface->start_frame;
 -              surface->pointcache->endframe = surface->end_frame;
 -      }
 -}
 -
  static void canvas_copyDerivedMesh(DynamicPaintCanvasSettings *canvas, DerivedMesh *dm)
  {
        if (canvas->dm) {
@@@ -1975,10 -1997,29 +1975,10 @@@ static void dynamicPaint_frameUpdate(Dy
                        if (no_surface_data || current_frame != surface->current_frame ||
                            (int)scene->r.cfra == surface->start_frame)
                        {
 -                              PointCache *cache = surface->pointcache;
 -                              PTCacheID pid;
                                surface->current_frame = current_frame;
  
 -                              /* read point cache */
 -                              BKE_ptcache_id_from_dynamicpaint(&pid, ob, surface);
 -                              pid.cache->startframe = surface->start_frame;
 -                              pid.cache->endframe = surface->end_frame;
 -                              BKE_ptcache_id_time(&pid, scene, (float)scene->r.cfra, NULL, NULL, NULL);
 -
 -                              /* reset non-baked cache at first frame */
 -                              if ((int)scene->r.cfra == surface->start_frame && !(cache->flag & PTCACHE_BAKED)) {
 -                                      cache->flag |= PTCACHE_REDO_NEEDED;
 -                                      BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
 -                                      cache->flag &= ~PTCACHE_REDO_NEEDED;
 -                              }
 -
 -                              /* try to read from cache */
 -                              if (BKE_ptcache_read(&pid, (float)scene->r.cfra)) {
 -                                      BKE_ptcache_validate(cache, (int)scene->r.cfra);
 -                              }
 -                              /* if read failed and we're on surface range do recalculate */
 -                              else if ((int)scene->r.cfra == current_frame && !(cache->flag & PTCACHE_BAKED)) {
 +                              /* if we're on surface range do recalculate */
 +                              if ((int)scene->r.cfra == current_frame) {
                                        /* calculate surface frame */
                                        canvas->flags |= MOD_DPAINT_BAKING;
                                        dynamicPaint_calculateFrame(surface, scene, ob, current_frame);
                                        {
                                                canvas_copyDerivedMesh(canvas, dm);
                                        }
 -
 -                                      BKE_ptcache_validate(cache, surface->current_frame);
 -                                      BKE_ptcache_write(&pid, surface->current_frame);
                                }
                        }
                }
@@@ -2205,7 -2249,7 +2205,7 @@@ static void dynamic_paint_create_uv_sur
                                                        /* tri index */
                                                        /* There is a low possibility of actually having a neighbor point which tri is
                                                         * already set from another neighbor in a separate thread here.
-                                                        * Cheking for both tri_index and neighbour_pixel above reduces that probability
+                                                        * Checking for both tri_index and neighbour_pixel above reduces that probability
                                                         * but it remains possible.
                                                         * That atomic op (and its memory fence) ensures tPoint->neighbour_pixel is set
                                                         * to non--1 *before* its tri_index is set (i.e. that it cannot be used a neighbour).
@@@ -3416,6 -3460,7 +3416,6 @@@ typedef struct DynamicPaintPaintData 
        const float *avg_brushNor;
        const Vec3f *brushVelocity;
  
 -      const ParticleSystem *psys;
        const float solidradius;
  
        void *treeData;
@@@ -3785,7 -3830,7 +3785,7 @@@ static int dynamicPaint_paintMesh(Dynam
                const float brush_radius = brush->paint_distance * surface->radius_scale;
                int numOfVerts;
                int ii;
-               Bounds3D mesh_bb = {0};
+               Bounds3D mesh_bb = {{0}};
                VolumeGrid *grid = bData->grid;
  
                dm = CDDM_copy(brush->dm);
        return 1;
  }
  
 -/*
 - *    Paint a particle system to the surface
 - */
 -static void dynamic_paint_paint_particle_cell_point_cb_ex(
 -        void *userdata, void *UNUSED(userdata_chunk), const int id, const int UNUSED(threadid))
 -{
 -      const DynamicPaintPaintData *data = userdata;
 -
 -      const DynamicPaintSurface *surface = data->surface;
 -      const PaintSurfaceData *sData = surface->data;
 -      const PaintBakeData *bData = sData->bData;
 -      VolumeGrid *grid = bData->grid;
 -
 -      const DynamicPaintBrushSettings *brush = data->brush;
 -
 -      const ParticleSystem *psys = data->psys;
 -
 -      const float timescale = data->timescale;
 -      const int c_index = data->c_index;
 -
 -      KDTree *tree = data->treeData;
 -
 -      const float solidradius = data->solidradius;
 -      const float smooth = brush->particle_smooth * surface->radius_scale;
 -      const float range = solidradius + smooth;
 -      const float particle_timestep = 0.04f * psys->part->timetweak;
 -
 -      const int index = grid->t_index[grid->s_pos[c_index] + id];
 -      float disp_intersect = 0.0f;
 -      float radius = 0.0f;
 -      float strength = 0.0f;
 -      int part_index = -1;
 -
 -      /*
 -       *      With predefined radius, there is no variation between particles.
 -       *      It's enough to just find the nearest one.
 -       */
 -      {
 -              KDTreeNearest nearest;
 -              float smooth_range, part_solidradius;
 -
 -              /* Find nearest particle and get distance to it */
 -              BLI_kdtree_find_nearest(tree, bData->realCoord[bData->s_pos[index]].v, &nearest);
 -              /* if outside maximum range, no other particle can influence either */
 -              if (nearest.dist > range)
 -                      return;
 -
 -              if (brush->flags & MOD_DPAINT_PART_RAD) {
 -                      /* use particles individual size */
 -                      ParticleData *pa = psys->particles + nearest.index;
 -                      part_solidradius = pa->size;
 -              }
 -              else {
 -                      part_solidradius = solidradius;
 -              }
 -              radius = part_solidradius + smooth;
 -              if (nearest.dist < radius) {
 -                      /* distances inside solid radius has maximum influence -> dist = 0      */
 -                      smooth_range = max_ff(0.0f, (nearest.dist - part_solidradius));
 -                      /* do smoothness if enabled     */
 -                      if (smooth)
 -                              smooth_range /= smooth;
 -
 -                      strength = 1.0f - smooth_range;
 -                      disp_intersect = radius - nearest.dist;
 -                      part_index = nearest.index;
 -              }
 -      }
 -      /* If using random per particle radius and closest particle didn't give max influence   */
 -      if (brush->flags & MOD_DPAINT_PART_RAD && strength < 1.0f && psys->part->randsize > 0.0f) {
 -              /*
 -               *      If we use per particle radius, we have to sample all particles
 -               *      within max radius range
 -               */
 -              KDTreeNearest *nearest;
 -
 -              float smooth_range = smooth * (1.0f - strength), dist;
 -              /* calculate max range that can have particles with higher influence than the nearest one */
 -              const float max_range = smooth - strength * smooth + solidradius;
 -              /* Make gcc happy! */
 -              dist = max_range;
 -
 -              const int particles = BLI_kdtree_range_search(
 -                                        tree, bData->realCoord[bData->s_pos[index]].v, &nearest, max_range);
 -
 -              /* Find particle that produces highest influence */
 -              for (int n = 0; n < particles; n++) {
 -                      ParticleData *pa = &psys->particles[nearest[n].index];
 -
 -                      /* skip if out of range */
 -                      if (nearest[n].dist > (pa->size + smooth))
 -                              continue;
 -
 -                      /* update hit data */
 -                      const float s_range = nearest[n].dist - pa->size;
 -                      /* skip if higher influence is already found */
 -                      if (smooth_range < s_range)
 -                              continue;
 -
 -                      /* update hit data */
 -                      smooth_range = s_range;
 -                      dist = nearest[n].dist;
 -                      part_index = nearest[n].index;
 -
 -                      /* If inside solid range and no disp depth required, no need to seek further */
 -                      if ((s_range < 0.0f) && !ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
 -                              break;
 -                      }
 -              }
 -
 -              if (nearest)
 -                      MEM_freeN(nearest);
 -
 -              /* now calculate influence for this particle */
 -              const float rad = radius + smooth;
 -              if ((rad - dist) > disp_intersect) {
 -                      disp_intersect = radius - dist;
 -                      radius = rad;
 -              }
 -
 -              /* do smoothness if enabled     */
 -              CLAMP_MIN(smooth_range, 0.0f);
 -              if (smooth)
 -                      smooth_range /= smooth;
 -
 -              const float str = 1.0f - smooth_range;
 -              /* if influence is greater, use this one        */
 -              if (str > strength)
 -                      strength = str;
 -      }
 -
 -      if (strength > 0.001f) {
 -              float paintColor[4] = {0.0f};
 -              float depth = 0.0f;
 -              float velocity_val = 0.0f;
 -
 -              /* apply velocity */
 -              if ((brush->flags & MOD_DPAINT_USES_VELOCITY) && (part_index != -1)) {
 -                      float velocity[3];
 -                      ParticleData *pa = psys->particles + part_index;
 -                      mul_v3_v3fl(velocity, pa->state.vel, particle_timestep);
 -
 -                      /* substract canvas point velocity */
 -                      if (bData->velocity) {
 -                              sub_v3_v3(velocity, bData->velocity[index].v);
 -                      }
 -                      velocity_val = normalize_v3(velocity);
 -
 -                      /* store brush velocity for smudge */
 -                      if ((surface->type == MOD_DPAINT_SURFACE_T_PAINT) &&
 -                          (brush->flags & MOD_DPAINT_DO_SMUDGE && bData->brush_velocity))
 -                      {
 -                              copy_v3_v3(&bData->brush_velocity[index * 4], velocity);
 -                              bData->brush_velocity[index * 4 + 3] = velocity_val;
 -                      }
 -              }
 -
 -              if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
 -                      copy_v3_v3(paintColor, &brush->r);
 -              }
 -              else if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
 -                      /* get displace depth   */
 -                      disp_intersect = (1.0f - sqrtf(disp_intersect / radius)) * radius;
 -                      depth = max_ff(0.0f, (radius - disp_intersect) / bData->bNormal[index].normal_scale);
 -              }
 -
 -              dynamicPaint_updatePointData(surface, index, brush, paintColor, strength, depth, velocity_val, timescale);
 -      }
 -}
 -
 -static int dynamicPaint_paintParticles(DynamicPaintSurface *surface,
 -                                       ParticleSystem *psys,
 -                                       DynamicPaintBrushSettings *brush,
 -                                       float timescale)
 -{
 -      ParticleSettings *part = psys->part;
 -      PaintSurfaceData *sData = surface->data;
 -      PaintBakeData *bData = sData->bData;
 -      VolumeGrid *grid = bData->grid;
 -
 -      KDTree *tree;
 -      int particlesAdded = 0;
 -      int invalidParticles = 0;
 -      int p = 0;
 -
 -      const float solidradius = surface->radius_scale *
 -                                ((brush->flags & MOD_DPAINT_PART_RAD) ? part->size : brush->particle_radius);
 -      const float smooth = brush->particle_smooth * surface->radius_scale;
 -
 -      const float range = solidradius + smooth;
 -
 -      Bounds3D part_bb = {{0}};
 -
 -      if (psys->totpart < 1)
 -              return 1;
 -
 -      /*
 -       *      Build a kd-tree to optimize distance search
 -       */
 -      tree = BLI_kdtree_new(psys->totpart);
 -
 -      /* loop through particles and insert valid ones to the tree     */
 -      p = 0;
 -      for (ParticleData *pa = psys->particles; p < psys->totpart; p++, pa++) {
 -              /* Proceed only if particle is active   */
 -              if ((pa->alive == PARS_UNBORN && (part->flag & PART_UNBORN) == 0) ||
 -                  (pa->alive == PARS_DEAD && (part->flag & PART_DIED) == 0) ||
 -                  (pa->flag & PARS_UNEXIST))
 -              {
 -                      continue;
 -              }
 -
 -              /*      for debug purposes check if any NAN particle proceeds
 -               *      For some reason they get past activity check, this should rule most of them out */
 -              if (isnan(pa->state.co[0]) || isnan(pa->state.co[1]) || isnan(pa->state.co[2])) {
 -                      invalidParticles++;
 -                      continue;
 -              }
 -
 -              /* make sure particle is close enough to canvas */
 -              if (!boundIntersectPoint(&grid->grid_bounds, pa->state.co, range))
 -                      continue;
 -
 -              BLI_kdtree_insert(tree, p, pa->state.co);
 -
 -              /* calc particle system bounds */
 -              boundInsert(&part_bb, pa->state.co);
 -
 -              particlesAdded++;
 -      }
 -      if (invalidParticles)
 -              printf("Warning: Invalid particle(s) found!\n");
 -
 -      /* If no suitable particles were found, exit    */
 -      if (particlesAdded < 1) {
 -              BLI_kdtree_free(tree);
 -              return 1;
 -      }
 -
 -      /* begin thread safe malloc */
 -      BLI_begin_threaded_malloc();
 -
 -      /* only continue if particle bb is close enough to canvas bb */
 -      if (boundsIntersectDist(&grid->grid_bounds, &part_bb, range)) {
 -              int c_index;
 -              int total_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
 -
 -              /* balance tree */
 -              BLI_kdtree_balance(tree);
 -
 -              /* loop through space partitioning grid */
 -              for (c_index = 0; c_index < total_cells; c_index++) {
 -                      /* check cell bounding box */
 -                      if (!grid->s_num[c_index] ||
 -                          !boundsIntersectDist(&grid->bounds[c_index], &part_bb, range))
 -                      {
 -                              continue;
 -                      }
 -
 -                      /* loop through cell points */
 -                      DynamicPaintPaintData data = {
 -                          .surface = surface,
 -                          .brush = brush, .psys = psys,
 -                          .solidradius = solidradius, .timescale = timescale, .c_index = c_index,
 -                          .treeData = tree,
 -                      };
 -                      BLI_task_parallel_range_ex(0, grid->s_num[c_index], &data, NULL, 0,
 -                                                 dynamic_paint_paint_particle_cell_point_cb_ex,
 -                                                 grid->s_num[c_index] > 250, true);
 -              }
 -      }
 -      BLI_end_threaded_malloc();
 -      BLI_kdtree_free(tree);
 -
 -      return 1;
 -}
 -
  /* paint a single point of defined proximity radius to the surface */
  static void dynamic_paint_paint_single_point_cb_ex(
          void *userdata, void *UNUSED(userdata_chunk), const int index, const int UNUSED(threadid))
@@@ -4297,7 -4619,7 +4297,7 @@@ static int dynamicPaint_prepareEffectSt
  
        /* Init force data if required */
        if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) {
 -              ListBase *effectors = pdInitEffectors(scene, ob, NULL, surface->effector_weights, true);
 +              ListBase *effectors = pdInitEffectors(scene, ob, surface->effector_weights, true);
  
                /* allocate memory for force data (dir vector + strength) */
                *force = MEM_mallocN(sData->total_points * 4 * sizeof(float), "PaintEffectForces");
@@@ -4475,7 -4797,7 +4475,7 @@@ static void dynamic_paint_effect_drip_c
  
                        /* Sort of spinlock, but only for given ePoint.
                         * Since the odds a same ePoint is modified at the same time by several threads is very low, this is
-                        * much more eficient than a global spin lock. */
+                        * much more efficient than a global spin lock. */
                        const unsigned int pointlock_idx = n_trgt / 8;
                        const uint8_t pointlock_bitmask = 1 << (n_trgt & 7);  /* 7 == 0b111 */
                        while (atomic_fetch_and_or_uint8(&point_locks[pointlock_idx], pointlock_bitmask) & pointlock_bitmask);
@@@ -5177,8 -5499,20 +5177,8 @@@ static int dynamicPaint_doStep(Scene *s
                                                dynamicPaint_updateBrushMaterials(brushObj, brush->mat, scene, &bMats);
  
                                        /* Apply brush on the surface depending on it's collision type */
 -                                      /* Particle brush: */
 -                                      if (brush->collision == MOD_DPAINT_COL_PSYS) {
 -                                              if (brush->psys && brush->psys->part &&
 -                                                  ELEM(brush->psys->part->type, PART_EMITTER, PART_FLUID) &&
 -                                                  psys_check_enabled(brushObj, brush->psys, G.is_rendering))
 -                                              {
 -                                                      /* Paint a particle system */
 -                                                      BKE_animsys_evaluate_animdata(scene, &brush->psys->part->id, brush->psys->part->adt,
 -                                                                                    BKE_scene_frame_get(scene), ADT_RECALC_ANIM);
 -                                                      dynamicPaint_paintParticles(surface, brush->psys, brush, timescale);
 -                                              }
 -                                      }
                                        /* Object center distance: */
 -                                      else if (brush->collision == MOD_DPAINT_COL_POINT && brushObj != ob) {
 +                                      if (brush->collision == MOD_DPAINT_COL_POINT && brushObj != ob) {
                                                dynamicPaint_paintSinglePoint(surface, brushObj->loc, brush, brushObj, &bMats, scene, timescale);
                                        }
                                        /* Mesh volume/proximity: */
index 95c7730431afde1554b83f6fd32de9c9d1d5254d,11bbd91e9c9e9e16269024668a75496739407311..5a51d4797bbfbb4fda71a460f8ae4d4098329edf
@@@ -40,6 -40,7 +40,6 @@@
  #include "DNA_material_types.h"
  #include "DNA_object_types.h"
  #include "DNA_scene_types.h"
 -#include "DNA_particle_types.h"
  
  #include "BLI_blenlib.h"
  #include "BLI_utildefines.h"
@@@ -86,18 -87,19 +86,19 @@@ Group *BKE_group_add(Main *bmain, cons
        return group;
  }
  
- Group *BKE_group_copy(Group *group)
+ Group *BKE_group_copy(Main *bmain, Group *group)
  {
        Group *groupn;
  
-       groupn = BKE_libblock_copy(&group->id);
+       groupn = BKE_libblock_copy(bmain, &group->id);
        BLI_duplicatelist(&groupn->gobject, &group->gobject);
  
        /* Do not copy group's preview (same behavior as for objects). */
        groupn->preview = NULL;
  
-       if (group->id.lib) {
-               BKE_id_lib_local_paths(G.main, group->id.lib, &groupn->id);
+       if (ID_IS_LINKED_DATABLOCK(group)) {
+               BKE_id_expand_local(&groupn->id);
+               BKE_id_lib_local_paths(bmain, group->id.lib, &groupn->id);
        }
  
        return groupn;
index 5f7bded4262554bc584ebc09cda72f7e543d1696,869e02448eac326cc8743dd73e7275974b67488f..978f1acefbaf5c730987da3f7afc5f54ef323519
  #include "BKE_mask.h"
  #include "BKE_node.h"
  #include "BKE_object.h"
 -#include "BKE_particle.h"
  #include "BKE_packedFile.h"
  #include "BKE_speaker.h"
  #include "BKE_scene.h"
@@@ -141,7 -142,7 +141,7 @@@ void BKE_id_lib_local_paths(Main *bmain
  
  void id_lib_extern(ID *id)
  {
-       if (id) {
+       if (id && ID_IS_LINKED_DATABLOCK(id)) {
                BLI_assert(BKE_idcode_is_linkable(GS(id->name)));
                if (id->tag & LIB_TAG_INDIRECT) {
                        id->tag -= LIB_TAG_INDIRECT;
@@@ -250,9 -251,27 +250,27 @@@ void id_fake_user_clear(ID *id
        }
  }
  
+ static int id_expand_local_callback(
+         void *UNUSED(user_data), struct ID *UNUSED(id_self), struct ID **id_pointer, int UNUSED(cd_flag))
+ {
+       if (*id_pointer) {
+               id_lib_extern(*id_pointer);
+       }
+       return IDWALK_RET_NOP;
+ }
+ /**
+  * Expand ID usages of given id as 'extern' (and no more indirect) linked data. Used by ID copy/make_local functions.
+  */
+ void BKE_id_expand_local(ID *id)
+ {
+       BKE_library_foreach_ID_link(id, id_expand_local_callback, NULL, 0);
+ }
  /* calls the appropriate make_local method for the block, unless test. Returns true
   * if the block can be made local. */
- bool id_make_local(ID *id, bool test)
+ bool id_make_local(Main *bmain, ID *id, bool test)
  {
        if (id->tag & LIB_TAG_INDIRECT)
                return false;
                case ID_LI:
                        return false; /* can't be linked */
                case ID_OB:
-                       if (!test) BKE_object_make_local((Object *)id);
+                       if (!test) BKE_object_make_local(bmain, (Object *)id);
                        return true;
                case ID_ME:
-                       if (!test) {
-                               BKE_mesh_make_local((Mesh *)id);
-                               BKE_key_make_local(((Mesh *)id)->key);
-                       }
+                       if (!test) BKE_mesh_make_local(bmain, (Mesh *)id);
                        return true;
                case ID_CU:
-                       if (!test) {
-                               BKE_curve_make_local((Curve *)id);
-                               BKE_key_make_local(((Curve *)id)->key);
-                       }
+                       if (!test) BKE_curve_make_local(bmain, (Curve *)id);
                        return true;
                case ID_MB:
-                       if (!test) BKE_mball_make_local((MetaBall *)id);
+                       if (!test) BKE_mball_make_local(bmain, (MetaBall *)id);
                        return true;
                case ID_MA:
-                       if (!test) BKE_material_make_local((Material *)id);
+                       if (!test) BKE_material_make_local(bmain, (Material *)id);
                        return true;
                case ID_TE:
-                       if (!test) BKE_texture_make_local((Tex *)id);
+                       if (!test) BKE_texture_make_local(bmain, (Tex *)id);
                        return true;
                case ID_IM:
-                       if (!test) BKE_image_make_local((Image *)id);
+                       if (!test) BKE_image_make_local(bmain, (Image *)id);
                        return true;
                case ID_LT:
-                       if (!test) {
-                               BKE_lattice_make_local((Lattice *)id);
-                               BKE_key_make_local(((Lattice *)id)->key);
-                       }
+                       if (!test) BKE_lattice_make_local(bmain, (Lattice *)id);
                        return true;
                case ID_LA:
-                       if (!test) BKE_lamp_make_local((Lamp *)id);
+                       if (!test) BKE_lamp_make_local(bmain, (Lamp *)id);
                        return true;
                case ID_CA:
-                       if (!test) BKE_camera_make_local((Camera *)id);
+                       if (!test) BKE_camera_make_local(bmain, (Camera *)id);
                        return true;
                case ID_SPK:
-                       if (!test) BKE_speaker_make_local((Speaker *)id);
+                       if (!test) BKE_speaker_make_local(bmain, (Speaker *)id);
                        return true;
                case ID_IP:
                        return false; /* deprecated */
                case ID_KE:
-                       if (!test) BKE_key_make_local((Key *)id);
+                       if (!test) BKE_key_make_local(bmain, (Key *)id);
                        return true;
                case ID_WO:
-                       if (!test) BKE_world_make_local((World *)id);
+                       if (!test) BKE_world_make_local(bmain, (World *)id);
                        return true;
                case ID_SCR:
                        return false; /* can't be linked */
                case ID_GR:
                        return false; /* not implemented */
                case ID_AR:
-                       if (!test) BKE_armature_make_local((bArmature *)id);
+                       if (!test) BKE_armature_make_local(bmain, (bArmature *)id);
                        return true;
                case ID_AC:
-                       if (!test) BKE_action_make_local((bAction *)id);
+                       if (!test) BKE_action_make_local(bmain, (bAction *)id);
                        return true;
                case ID_NT:
-                       if (!test) ntreeMakeLocal((bNodeTree *)id, true);
+                       if (!test) ntreeMakeLocal(bmain, (bNodeTree *)id, true);
                        return true;
                case ID_BR:
-                       if (!test) BKE_brush_make_local((Brush *)id);
+                       if (!test) BKE_brush_make_local(bmain, (Brush *)id);
                        return true;
 -              case ID_PA:
 -                      if (!test) BKE_particlesettings_make_local(bmain, (ParticleSettings *)id);
 -                      return true;
                case ID_WM:
                        return false; /* can't be linked */
                case ID_GD:
   * Invokes the appropriate copy method for the block and returns the result in
   * newid, unless test. Returns true if the block can be copied.
   */
- bool id_copy(ID *id, ID **newid, bool test)
+ bool id_copy(Main *bmain, ID *id, ID **newid, bool test)
  {
-       if (!test) *newid = NULL;
+       if (!test) {
+               *newid = NULL;
+       }
  
        /* conventions:
         * - make shallow copy, only this ID block
                case ID_LI:
                        return false;  /* can't be copied from here */
                case ID_OB:
-                       if (!test) *newid = (ID *)BKE_object_copy((Object *)id);
+                       if (!test) *newid = (ID *)BKE_object_copy(bmain, (Object *)id);
                        return true;
                case ID_ME:
-                       if (!test) *newid = (ID *)BKE_mesh_copy((Mesh *)id);
+                       if (!test) *newid = (ID *)BKE_mesh_copy(bmain, (Mesh *)id);
                        return true;
                case ID_CU:
-                       if (!test) *newid = (ID *)BKE_curve_copy((Curve *)id);
+                       if (!test) *newid = (ID *)BKE_curve_copy(bmain, (Curve *)id);
                        return true;
                case ID_MB:
-                       if (!test) *newid = (ID *)BKE_mball_copy((MetaBall *)id);
+                       if (!test) *newid = (ID *)BKE_mball_copy(bmain, (MetaBall *)id);
                        return true;
                case ID_MA:
-                       if (!test) *newid = (ID *)BKE_material_copy((Material *)id);
+                       if (!test) *newid = (ID *)BKE_material_copy(bmain, (Material *)id);
                        return true;
                case ID_TE:
-                       if (!test) *newid = (ID *)BKE_texture_copy((Tex *)id);
+                       if (!test) *newid = (ID *)BKE_texture_copy(bmain, (Tex *)id);
                        return true;
                case ID_IM:
-                       if (!test) *newid = (ID *)BKE_image_copy(G.main, (Image *)id);
+                       if (!test) *newid = (ID *)BKE_image_copy(bmain, (Image *)id);
                        return true;
                case ID_LT:
-                       if (!test) *newid = (ID *)BKE_lattice_copy((Lattice *)id);
+                       if (!test) *newid = (ID *)BKE_lattice_copy(bmain, (Lattice *)id);
                        return true;
                case ID_LA:
-                       if (!test) *newid = (ID *)BKE_lamp_copy((Lamp *)id);
+                       if (!test) *newid = (ID *)BKE_lamp_copy(bmain, (Lamp *)id);
                        return true;
                case ID_SPK:
-                       if (!test) *newid = (ID *)BKE_speaker_copy((Speaker *)id);
+                       if (!test) *newid = (ID *)BKE_speaker_copy(bmain, (Speaker *)id);
                        return true;
                case ID_CA:
-                       if (!test) *newid = (ID *)BKE_camera_copy((Camera *)id);
+                       if (!test) *newid = (ID *)BKE_camera_copy(bmain, (Camera *)id);
                        return true;
                case ID_IP:
                        return false;  /* deprecated */
                case ID_KE:
-                       if (!test) *newid = (ID *)BKE_key_copy((Key *)id);
+                       if (!test) *newid = (ID *)BKE_key_copy(bmain, (Key *)id);
                        return true;
                case ID_WO:
-                       if (!test) *newid = (ID *)BKE_world_copy((World *)id);
+                       if (!test) *newid = (ID *)BKE_world_copy(bmain, (World *)id);
                        return true;
                case ID_SCR:
                        return false;  /* can't be copied from here */
                case ID_VF:
                        return false;  /* not implemented */
                case ID_TXT:
-                       if (!test) *newid = (ID *)BKE_text_copy(G.main, (Text *)id);
+                       if (!test) *newid = (ID *)BKE_text_copy(bmain, (Text *)id);
                        return true;
                case ID_SO:
                        return false;  /* not implemented */
                case ID_GR:
-                       if (!test) *newid = (ID *)BKE_group_copy((Group *)id);
+                       if (!test) *newid = (ID *)BKE_group_copy(bmain, (Group *)id);
                        return true;
                case ID_AR:
-                       if (!test) *newid = (ID *)BKE_armature_copy((bArmature *)id);
+                       if (!test) *newid = (ID *)BKE_armature_copy(bmain, (bArmature *)id);
                        return true;
                case ID_AC:
-                       if (!test) *newid = (ID *)BKE_action_copy((bAction *)id);
+                       if (!test) *newid = (ID *)BKE_action_copy(bmain, (bAction *)id);
                        return true;
                case ID_NT:
-                       if (!test) *newid = (ID *)ntreeCopyTree((bNodeTree *)id);
+                       if (!test) *newid = (ID *)ntreeCopyTree(bmain, (bNodeTree *)id);
                        return true;
                case ID_BR:
-                       if (!test) *newid = (ID *)BKE_brush_copy((Brush *)id);
+                       if (!test) *newid = (ID *)BKE_brush_copy(bmain, (Brush *)id);
                        return true;
 -              case ID_PA:
 -                      if (!test) *newid = (ID *)BKE_particlesettings_copy(bmain, (ParticleSettings *)id);
 -                      return true;
                case ID_WM:
                        return false;  /* can't be copied from here */
                case ID_GD:
-                       if (!test) *newid = (ID *)gpencil_data_duplicate((bGPdata *)id, false);
+                       if (!test) *newid = (ID *)gpencil_data_duplicate(bmain, (bGPdata *)id, false);
                        return true;
                case ID_MSK:
-                       if (!test) *newid = (ID *)BKE_mask_copy((Mask *)id);
+                       if (!test) *newid = (ID *)BKE_mask_copy(bmain, (Mask *)id);
                        return true;
                case ID_LS:
-                       if (!test) *newid = (ID *)BKE_linestyle_copy(G.main, (FreestyleLineStyle *)id);
+                       if (!test) *newid = (ID *)BKE_linestyle_copy(bmain, (FreestyleLineStyle *)id);
                        return true;
        }
        
@@@ -450,7 -468,7 +461,7 @@@ bool id_single_user(bContext *C, ID *id
        if (id) {
                /* if property isn't editable, we're going to have an extra block hanging around until we save */
                if (RNA_property_editable(ptr, prop)) {
-                       if (id_copy(id, &newid, false) && newid) {
+                       if (id_copy(CTX_data_main(C), id, &newid, false) && newid) {
                                /* copy animation actions too */
                                BKE_animdata_copy_id_action(id);
                                /* us is 1 by convention, but RNA_property_pointer_set
@@@ -523,6 -541,8 +534,6 @@@ ListBase *which_libbase(Main *mainlib, 
                        return &(mainlib->nodetree);
                case ID_BR:
                        return &(mainlib->brush);
 -              case ID_PA:
 -                      return &(mainlib->particle);
                case ID_WM:
                        return &(mainlib->wm);
                case ID_GD:
@@@ -621,7 -641,7 +632,7 @@@ void BKE_main_lib_objects_recalc_all(Ma
  
        /* flag for full recalc */
        for (ob = bmain->object.first; ob; ob = ob->id.next) {
-               if (ob->id.lib) {
+               if (ID_IS_LINKED_DATABLOCK(ob)) {
                        DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
                }
        }
@@@ -674,6 -694,7 +685,6 @@@ int set_listbasepointers(Main *main, Li
        lb[a++] = &(main->palettes);
        lb[a++] = &(main->paintcurves);
        lb[a++] = &(main->brush);
 -      lb[a++] = &(main->particle);
        lb[a++] = &(main->speaker);
  
        lb[a++] = &(main->world);
@@@ -786,6 -807,9 +797,6 @@@ void *BKE_libblock_alloc_notest(short t
                case ID_BR:
                        id = MEM_callocN(sizeof(Brush), "brush");
                        break;
 -              case ID_PA:
 -                      id = MEM_callocN(sizeof(ParticleSettings), "ParticleSettings");
 -                      break;
                case ID_WM:
                        id = MEM_callocN(sizeof(wmWindowManager), "Window manager");
                        break;
@@@ -927,6 -951,9 +938,6 @@@ void BKE_libblock_init_empty(ID *id
                case ID_BR:
                        BKE_brush_init((Brush *)id);
                        break;
 -              case ID_PA:
 -                      /* Nothing to do. */
 -                      break;
                case ID_PC:
                        /* Nothing to do. */
                        break;
@@@ -969,7 -996,7 +980,7 @@@ void BKE_libblock_copy_data(ID *id, con
  }
  
  /* used everywhere in blenkernel */
- void *BKE_libblock_copy_ex(Main *bmain, ID *id)
+ void *BKE_libblock_copy(Main *bmain, ID *id)
  {
        ID *idn;
        size_t idn_len;
@@@ -1021,11 -1048,6 +1032,6 @@@ void *BKE_libblock_copy_nolib(ID *id, c
        return idn;
  }
  
- void *BKE_libblock_copy(ID *id)
- {
-       return BKE_libblock_copy_ex(G.main, id);
- }
  static int id_relink_looper(void *UNUSED(user_data), ID *UNUSED(self_id), ID **id_pointer, const int cd_flag)
  {
        ID *id = *id_pointer;
  
  void BKE_libblock_relink(ID *id)
  {
-       if (id->lib)
+       if (ID_IS_LINKED_DATABLOCK(id))
                return;
  
        BKE_library_foreach_ID_link(id, id_relink_looper, NULL, 0);
@@@ -1259,7 -1281,7 +1265,7 @@@ static ID *is_dupid(ListBase *lb, ID *i
        
        for (idtest = lb->first; idtest; idtest = idtest->next) {
                /* if idtest is not a lib */ 
-               if (id != idtest && idtest->lib == NULL) {
+               if (id != idtest && !ID_IS_LINKED_DATABLOCK(idtest)) {
                        /* do not test alphabetic! */
                        /* optimized */
                        if (idtest->name[2] == name[0]) {
@@@ -1319,7 -1341,7 +1325,7 @@@ static bool check_for_dupid(ListBase *l
                for (idtest = lb->first; idtest; idtest = idtest->next) {
                        int nrtest;
                        if ( (id != idtest) &&
-                            (idtest->lib == NULL) &&
+                            !ID_IS_LINKED_DATABLOCK(idtest) &&
                             (*name == *(idtest->name + 2)) &&
                             STREQLEN(name, idtest->name + 2, left_len) &&
                             (BLI_split_name_num(leftest, &nrtest, idtest->name + 2, '.') == left_len)
@@@ -1401,7 -1423,7 +1407,7 @@@ bool new_id(ListBase *lb, ID *id, cons
        char name[MAX_ID_NAME - 2];
  
        /* if library, don't rename */
-       if (id->lib)
+       if (ID_IS_LINKED_DATABLOCK(id))
                return false;
  
        /* if no libdata given, look up based on ID */
@@@ -1465,7 -1487,7 +1471,7 @@@ void id_clear_lib_data_ex(Main *bmain, 
        ntree = ntreeFromID(id);
  
        if (ntree) {
-               ntreeMakeLocal(ntree, false);
+               ntreeMakeLocal(bmain, ntree, false);
        }
  
        if (GS(id->name) == ID_OB) {
@@@ -1506,7 -1528,7 +1512,7 @@@ static void lib_indirect_test_id(ID *id
  #define LIBTAG(a) \
        if (a && a->id.lib) { a->id.tag &= ~LIB_TAG_INDIRECT; a->id.tag |= LIB_TAG_EXTERN; } (void)0
        
-       if (id->lib) {
+       if (ID_IS_LINKED_DATABLOCK(id)) {
                /* datablocks that were indirectly related are now direct links
                 * without this, appending data that has a link to other data will fail to write */
                if (lib && id->lib->parent == lib) {
index 7cb5bfd136077e8f007b5db076a78fdcc46a747f,f86f5fa01ec4f845be85c42992a44fe0ffa46298..b623cecb0ffdd44e07aa9d8e9ba657c476a09d14
  #include "DNA_linestyle_types.h"
  #include "DNA_material_types.h"
  #include "DNA_mesh_types.h"
+ #include "DNA_meshdata_types.h"
  #include "DNA_meta_types.h"
  #include "DNA_movieclip_types.h"
  #include "DNA_mask_types.h"
  #include "DNA_node_types.h"
  #include "DNA_object_force.h"
 +#include "DNA_object_types.h"
  #include "DNA_rigidbody_types.h"
  #include "DNA_scene_types.h"
  #include "DNA_sensor_types.h"
@@@ -63,6 -63,7 +64,6 @@@
  #include "DNA_world_types.h"
  
  #include "BLI_utildefines.h"
 -#include "BLI_listbase.h"
  #include "BLI_ghash.h"
  #include "BLI_linklist_stack.h"
  
@@@ -71,7 -72,9 +72,8 @@@
  #include "BKE_fcurve.h"
  #include "BKE_library.h"
  #include "BKE_library_query.h"
+ #include "BKE_main.h"
  #include "BKE_modifier.h"
 -#include "BKE_particle.h"
  #include "BKE_rigidbody.h"
  #include "BKE_sca.h"
  #include "BKE_sequencer.h"
@@@ -85,7 -88,7 +87,7 @@@
        if (!((_data)->status & IDWALK_STOP)) { \
                const int _flag = (_data)->flag; \
                ID *old_id = *(id_pp); \
-               const int callback_return = (_data)->callback((_data)->user_data, (_data)->self_id, id_pp, cb_flag); \
+               const int callback_return = (_data)->callback((_data)->user_data, (_data)->self_id, id_pp, cb_flag | (_data)->cd_flag); \
                if (_flag & IDWALK_READONLY) { \
                        BLI_assert(*(id_pp) == old_id); \
                } \
@@@ -126,6 -129,7 +128,7 @@@ enum 
  typedef struct LibraryForeachIDData {
        ID *self_id;
        int flag;
+       int cd_flag;
        LibraryIDLinkCallback callback;
        void *user_data;
        int status;
@@@ -163,6 -167,15 +166,6 @@@ static void library_foreach_constraintO
        FOREACH_FINALIZE_VOID;
  }
  
 -static void library_foreach_particlesystemsObjectLooper(
 -        ParticleSystem *UNUSED(psys), ID **id_pointer, void *user_data, int cd_flag)
 -{
 -      LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
 -      FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
 -
 -      FOREACH_FINALIZE_VOID;
 -}
 -
  static void library_foreach_sensorsObjectLooper(
          bSensor *UNUSED(sensor), ID **id_pointer, void *user_data, int cd_flag)
  {
@@@ -285,6 -298,7 +288,7 @@@ void BKE_library_foreach_ID_link(ID *id
  
        do {
                data.self_id = id;
+               data.cd_flag = ID_IS_LINKED_DATABLOCK(id) ? IDWALK_INDIRECT_USAGE : 0;
  
                AnimData *adt = BKE_animdata_from_id(id);
                if (adt) {
                                if (toolsett) {
                                        CALLBACK_INVOKE(toolsett->skgen_template, IDWALK_NOP);
  
 -                                      CALLBACK_INVOKE(toolsett->particle.scene, IDWALK_NOP);
 -                                      CALLBACK_INVOKE(toolsett->particle.object, IDWALK_NOP);
 -                                      CALLBACK_INVOKE(toolsett->particle.shape_object, IDWALK_NOP);
 -
                                        library_foreach_paint(&data, &toolsett->imapaint.paint);
                                        CALLBACK_INVOKE(toolsett->imapaint.stencil, IDWALK_USER);
                                        CALLBACK_INVOKE(toolsett->imapaint.clone, IDWALK_USER);
                        case ID_OB:
                        {
                                Object *object = (Object *) id;
 -                              ParticleSystem *psys;
  
+                               /* Object is special, proxies make things hard... */
+                               const int data_cd_flag = data.cd_flag;
+                               const int proxy_cd_flag = (object->proxy || object->proxy_group) ? IDWALK_INDIRECT_USAGE : 0;
                                /* object data special case */
+                               data.cd_flag |= proxy_cd_flag;
                                if (object->type == OB_EMPTY) {
                                        /* empty can have NULL or Image */
                                        CALLBACK_INVOKE_ID(object->data, IDWALK_USER);
                                                CALLBACK_INVOKE_ID(object->data, IDWALK_USER | IDWALK_NEVER_NULL);
                                        }
                                }
+                               data.cd_flag = data_cd_flag;
  
                                CALLBACK_INVOKE(object->parent, IDWALK_NOP);
                                CALLBACK_INVOKE(object->track, IDWALK_NOP);
                                CALLBACK_INVOKE(object->proxy_group, IDWALK_NOP);
                                CALLBACK_INVOKE(object->proxy_from, IDWALK_NOP);
                                CALLBACK_INVOKE(object->poselib, IDWALK_USER);
+                               data.cd_flag |= proxy_cd_flag;
                                for (i = 0; i < object->totcol; i++) {
                                        CALLBACK_INVOKE(object->mat[i], IDWALK_USER);
                                }
+                               data.cd_flag = data_cd_flag;
                                CALLBACK_INVOKE(object->gpd, IDWALK_USER);
                                CALLBACK_INVOKE(object->dup_group, IDWALK_USER);
  
  
                                if (object->pose) {
                                        bPoseChannel *pchan;
+                                       data.cd_flag |= proxy_cd_flag;
                                        for (pchan = object->pose->chanbase.first; pchan; pchan = pchan->next) {
                                                CALLBACK_INVOKE(pchan->custom, IDWALK_USER);
                                                BKE_constraints_id_loop(&pchan->constraints, library_foreach_constraintObjectLooper, &data);
                                        }
+                                       data.cd_flag = data_cd_flag;
                                }
  
                                if (object->rigidbody_constraint) {
                                modifiers_foreachIDLink(object, library_foreach_modifiersForeachIDLink, &data);
                                BKE_constraints_id_loop(&object->constraints, library_foreach_constraintObjectLooper, &data);
  
 -                              for (psys = object->particlesystem.first; psys; psys = psys->next) {
 -                                      BKE_particlesystem_id_loop(psys, library_foreach_particlesystemsObjectLooper, &data);
 -                              }
 -
 -                              if (object->soft && object->soft->effector_weights) {
 -                                      CALLBACK_INVOKE(object->soft->effector_weights->group, IDWALK_NOP);
 -                              }
 -
                                BKE_sca_sensors_id_loop(&object->sensors, library_foreach_sensorsObjectLooper, &data);
                                BKE_sca_controllers_id_loop(&object->controllers, library_foreach_controllersObjectLooper, &data);
                                BKE_sca_actuators_id_loop(&object->actuators, library_foreach_actuatorsObjectLooper, &data);
                                for (i = 0; i < mesh->totcol; i++) {
                                        CALLBACK_INVOKE(mesh->mat[i], IDWALK_USER);
                                }
+                               /* XXX Really not happy with this - probably texface should rather use some kind of
+                                * 'texture slots' and just set indices in each poly/face item - would also save some memory.
+                                * Maybe a nice TODO for blender2.8? */
+                               if (mesh->mtface || mesh->mtpoly) {
+                                       for (i = 0; i < mesh->pdata.totlayer; i++) {
+                                               if (mesh->pdata.layers[i].type == CD_MTEXPOLY) {
+                                                       MTexPoly *txface = (MTexPoly *)mesh->pdata.layers[i].data;
+                                                       for (int j = 0; j < mesh->totpoly; j++, txface++) {
+                                                               CALLBACK_INVOKE(txface->tpage, IDWALK_USER_ONE);
+                                                       }
+                                               }
+                                       }
+                                       for (i = 0; i < mesh->fdata.totlayer; i++) {
+                                               if (mesh->fdata.layers[i].type == CD_MTFACE) {
+                                                       MTFace *tface = (MTFace *)mesh->fdata.layers[i].data;
+                                                       for (int j = 0; j < mesh->totface; j++, tface++) {
+                                                               CALLBACK_INVOKE(tface->tpage, IDWALK_USER_ONE);
+                                                       }
+                                               }
+                                       }
+                               }
                                break;
                        }
  
                                break;
                        }
  
 -                      case ID_PA:
 -                      {
 -                              ParticleSettings *psett = (ParticleSettings *) id;
 -                              CALLBACK_INVOKE(psett->dup_group, IDWALK_NOP);
 -                              CALLBACK_INVOKE(psett->dup_ob, IDWALK_NOP);
 -                              CALLBACK_INVOKE(psett->bb_ob, IDWALK_NOP);
 -
 -                              for (i = 0; i < MAX_MTEX; i++) {
 -                                      if (psett->mtex[i]) {
 -                                              library_foreach_mtex(&data, psett->mtex[i]);
 -                                      }
 -                              }
 -
 -                              if (psett->effector_weights) {
 -                                      CALLBACK_INVOKE(psett->effector_weights->group, IDWALK_NOP);
 -                              }
 -
 -                              if (psett->pd) {
 -                                      CALLBACK_INVOKE(psett->pd->tex, IDWALK_USER);
 -                                      CALLBACK_INVOKE(psett->pd->f_source, IDWALK_NOP);
 -                              }
 -                              if (psett->pd2) {
 -                                      CALLBACK_INVOKE(psett->pd2->tex, IDWALK_USER);
 -                                      CALLBACK_INVOKE(psett->pd2->f_source, IDWALK_NOP);
 -                              }
 -
 -                              if (psett->boids) {
 -                                      BoidState *state;
 -                                      BoidRule *rule;
 -
 -                                      for (state = psett->boids->states.first; state; state = state->next) {
 -                                              for (rule = state->rules.first; rule; rule = rule->next) {
 -                                                      if (rule->type == eBoidRuleType_Avoid) {
 -                                                              BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid *)rule;
 -                                                              CALLBACK_INVOKE(gabr->ob, IDWALK_NOP);
 -                                                      }
 -                                                      else if (rule->type == eBoidRuleType_FollowLeader) {
 -                                                              BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader *)rule;
 -                                                              CALLBACK_INVOKE(flbr->ob, IDWALK_NOP);
 -                                                      }
 -                                              }
 -                                      }
 -                              }
 -                              break;
 -                      }
 -
                        case ID_MC:
                        {
                                MovieClip *clip = (MovieClip *) id;
@@@ -743,6 -854,82 +785,80 @@@ void BKE_library_update_ID_link_user(I
        }
  }
  
 -                                                ID_OB, ID_MA, ID_GD, ID_GR, ID_TE, ID_PA, ID_TXT, ID_SO, ID_MC, ID_IM, ID_AC
+ /**
+  * Say whether given \a id_type_owner can use (in any way) a datablock of \a id_type_used.
+  */
+ /* This is a 'simplified' abstract version of BKE_library_foreach_ID_link() above, quite useful to reduce
+  * useless ietrations in some cases. */
+ bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id_type_used)
+ {
+       if (id_type_used == ID_AC) {
+               return id_type_can_have_animdata(id_type_owner);
+       }
+       switch (id_type_owner) {
+               case ID_LI:
+                       return ELEM(id_type_used, ID_LI);
+               case ID_SCE:
+                       return (ELEM(id_type_used, ID_OB, ID_WO, ID_SCE, ID_MC, ID_MA, ID_GR, ID_TXT,
+                                                  ID_LS, ID_MSK, ID_SO, ID_GD, ID_BR, ID_PAL, ID_IM, ID_NT) ||
+                               BKE_library_idtype_can_use_idtype(ID_NT, id_type_used));
+               case ID_OB:
+                       /* Could be the following, but simpler to just always say 'yes' here. */
+ #if 0
+                       return ELEM(id_type_used, ID_ME, ID_CU, ID_MB, ID_LT, ID_SPK, ID_AR, ID_LA, ID_CA,  /* obdata */
 -              case ID_PA:
 -                      return ELEM(id_type_used, ID_OB, ID_GR, ID_TE);
++                                                ID_OB, ID_MA, ID_GD, ID_GR, ID_TE, ID_TXT, ID_SO, ID_MC, ID_IM, ID_AC
+                                                 /* + constraints, modifiers and game logic ID types... */);
+ #else
+                       return true;
+ #endif
+               case ID_ME:
+                       return ELEM(id_type_used, ID_ME, ID_KE, ID_MA);
+               case ID_CU:
+                       return ELEM(id_type_used, ID_OB, ID_KE, ID_MA, ID_VF);
+               case ID_MB:
+                       return ELEM(id_type_used, ID_MA);
+               case ID_MA:
+                       return (ELEM(id_type_used, ID_TE, ID_GR) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used));
+               case ID_TE:
+                       return (ELEM(id_type_used, ID_IM, ID_OB) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used));
+               case ID_LT:
+                       return ELEM(id_type_used, ID_KE);
+               case ID_LA:
+                       return (ELEM(id_type_used, ID_TE) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used));
+               case ID_CA:
+                       return ELEM(id_type_used, ID_OB);
+               case ID_KE:
+                       return ELEM(id_type_used, ID_ME, ID_CU, ID_LT);  /* Warning! key->from, could be more types in future? */
+               case ID_SCR:
+                       return ELEM(id_type_used, ID_SCE);
+               case ID_WO:
+                       return (ELEM(id_type_used, ID_TE) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used));
+               case ID_SPK:
+                       return ELEM(id_type_used, ID_SO);
+               case ID_GR:
+                       return ELEM(id_type_used, ID_OB);
+               case ID_NT:
+                       /* Could be the following, but node.id has no type restriction... */
+ #if 0
+                       return ELEM(id_type_used, ID_GD /* + node.id types... */);
+ #else
+                       return true;
+ #endif
+               case ID_BR:
+                       return ELEM(id_type_used, ID_BR, ID_IM, ID_PC, ID_TE);
+               case ID_MC:
+                       return ELEM(id_type_used, ID_GD, ID_IM);
+               case ID_MSK:
+                       return ELEM(id_type_used, ID_MC);  /* WARNING! mask->parent.id, not typed. */
+               case ID_LS:
+                       return (ELEM(id_type_used, ID_TE, ID_OB) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used));
+               default:
+                       return false;
+       }
+ }
  /* ***** ID users iterator. ***** */
  typedef struct IDUsersIter {
        ID *id;
        int lb_idx;
  
        ID *curr_id;
-       int count;  /* Set by callback. */
+       int count_direct, count_indirect;  /* Set by callback. */
  } IDUsersIter;
  
  static int foreach_libblock_id_users_callback(void *user_data, ID *UNUSED(self_id), ID **id_p, int cb_flag)
  
        if (*id_p && (*id_p == iter->id)) {
  #if 0
-               printf("%s uses %s (refcounted: %d, userone: %d, used_one: %d, used_one_active: %d)\n",
+               printf("%s uses %s (refcounted: %d, userone: %d, used_one: %d, used_one_active: %d, indirect_usage: %d)\n",
                       iter->curr_id->name, iter->id->name, (cb_flag & IDWALK_USER) ? 1 : 0, (cb_flag & IDWALK_USER_ONE) ? 1 : 0,
-                      (iter->id->tag & LIB_TAG_EXTRAUSER) ? 1 : 0, (iter->id->tag & LIB_TAG_EXTRAUSER_SET) ? 1 : 0);
- #else
-               UNUSED_VARS(cb_flag);
+                      (iter->id->tag & LIB_TAG_EXTRAUSER) ? 1 : 0, (iter->id->tag & LIB_TAG_EXTRAUSER_SET) ? 1 : 0,
+                      (cb_flag & IDWALK_INDIRECT_USAGE) ? 1 : 0);
  #endif
-               iter->count++;
+               if (cb_flag & IDWALK_INDIRECT_USAGE) {
+                       iter->count_indirect++;
+               }
+               else {
+                       iter->count_direct++;
+               }
        }
  
        return IDWALK_RET_NOP;
@@@ -789,9 -980,86 +909,86 @@@ int BKE_library_ID_use_ID(ID *id_user, 
        /* We do not care about iter.lb_array/lb_idx here... */
        iter.id = id_used;
        iter.curr_id = id_user;
-       iter.count = 0;
+       iter.count_direct = iter.count_indirect = 0;
  
        BKE_library_foreach_ID_link(iter.curr_id, foreach_libblock_id_users_callback, (void *)&iter, IDWALK_NOP);
  
-       return iter.count;
+       return iter.count_direct + iter.count_indirect;
+ }
+ static bool library_ID_is_used(Main *bmain, void *idv, const bool check_linked)
+ {
+       IDUsersIter iter;
+       ListBase *lb_array[MAX_LIBARRAY];
+       ID *id = idv;
+       int i = set_listbasepointers(bmain, lb_array);
+       bool is_defined = false;
+       iter.id = id;
+       iter.count_direct = iter.count_indirect = 0;
+       while (i-- && !is_defined) {
+               ID *id_curr = lb_array[i]->first;
+               if (!id_curr || !BKE_library_idtype_can_use_idtype(GS(id_curr->name), GS(id->name))) {
+                       continue;
+               }
+               for (; id_curr && !is_defined; id_curr = id_curr->next) {
+                       iter.curr_id = id_curr;
+                       BKE_library_foreach_ID_link(
+                                   id_curr, foreach_libblock_id_users_callback, &iter, IDWALK_NOP);
+                       is_defined = ((check_linked ? iter.count_indirect : iter.count_direct) != 0);
+               }
+       }
+       return is_defined;
+ }
+ /**
+  * Check whether given ID is used locally (i.e. by another non-linked ID).
+  */
+ bool BKE_library_ID_is_locally_used(Main *bmain, void *idv)
+ {
+       return library_ID_is_used(bmain, idv, false);
+ }
+ /**
+  * Check whether given ID is used indirectly (i.e. by another linked ID).
+  */
+ bool BKE_library_ID_is_indirectly_used(Main *bmain, void *idv)
+ {
+       return library_ID_is_used(bmain, idv, true);
+ }
+ /**
+  * Combine \a BKE_library_ID_is_locally_used() and \a BKE_library_ID_is_indirectly_used() in a single call.
+  */
+ void BKE_library_ID_test_usages(Main *bmain, void *idv, bool *is_used_local, bool *is_used_linked)
+ {
+       IDUsersIter iter;
+       ListBase *lb_array[MAX_LIBARRAY];
+       ID *id = idv;
+       int i = set_listbasepointers(bmain, lb_array);
+       bool is_defined = false;
+       iter.id = id;
+       iter.count_direct = iter.count_indirect = 0;
+       while (i-- && !is_defined) {
+               ID *id_curr = lb_array[i]->first;
+               if (!id_curr || !BKE_library_idtype_can_use_idtype(GS(id_curr->name), GS(id->name))) {
+                       continue;
+               }
+               for (; id_curr && !is_defined; id_curr = id_curr->next) {
+                       iter.curr_id = id_curr;
+                       BKE_library_foreach_ID_link(id_curr, foreach_libblock_id_users_callback, &iter, IDWALK_NOP);
+                       is_defined = (iter.count_direct != 0 && iter.count_indirect != 0);
+               }
+       }
+       *is_used_local = (iter.count_direct != 0);
+       *is_used_linked = (iter.count_indirect != 0);
  }
index e9598bee0df19c3efbb8795f147cefc680871cf5,b158b3f968b0b7ff105fcacca7cb57fe8c10e509..62a6541529a4a7ee2991a5249bb69d307b86abd9
  #include "BKE_mesh.h"
  #include "BKE_material.h"
  #include "BKE_main.h"
+ #include "BKE_mask.h"
  #include "BKE_mball.h"
+ #include "BKE_modifier.h"
  #include "BKE_movieclip.h"
- #include "BKE_mask.h"
+ #include "BKE_multires.h"
  #include "BKE_node.h"
  #include "BKE_object.h"
  #include "BKE_paint.h"
 -#include "BKE_particle.h"
  #include "BKE_speaker.h"
  #include "BKE_sound.h"
  #include "BKE_screen.h"
@@@ -162,18 -165,22 +164,22 @@@ static int foreach_libblock_remap_callb
        }
  
        if (*id_p && (*id_p == old_id)) {
-               const bool is_indirect = (id->lib != NULL);
+               const bool is_indirect = (cb_flag & IDWALK_INDIRECT_USAGE) != 0;
                const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0;
                /* Note: proxy usage implies LIB_TAG_EXTERN, so on this aspect it is direct,
                 *       on the other hand since they get reset to lib data on file open/reload it is indirect too...
                 *       Edit Mode is also a 'skip direct' case. */
                const bool is_obj = (GS(id->name) == ID_OB);
-               const bool is_proxy = (is_obj && (((Object *)id)->proxy || ((Object *)id)->proxy_group));
                const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id));
                const bool is_never_null = ((cb_flag & IDWALK_NEVER_NULL) && (new_id == NULL) &&
                                            (id_remap_data->flag & ID_REMAP_FORCE_NEVER_NULL_USAGE) == 0);
                const bool skip_never_null = (id_remap_data->flag & ID_REMAP_SKIP_NEVER_NULL_USAGE) != 0;
  
+ #ifdef DEBUG_PRINT
+               printf("In %s: Remapping %s (%p) to %s (%p) (skip_indirect: %d)\n",
+                      id->name, old_id->name, old_id, new_id ? new_id->name : "<NONE>", new_id, skip_indirect);
+ #endif
                if ((id_remap_data->flag & ID_REMAP_FLAG_NEVER_NULL_USAGE) && (cb_flag & IDWALK_NEVER_NULL)) {
                        id->tag |= LIB_TAG_DOIT;
                }
                /* Special hack in case it's Object->data and we are in edit mode (skipped_direct too). */
                if ((is_never_null && skip_never_null) ||
                    (is_obj_editmode && (((Object *)id)->data == *id_p)) ||
-                   (skip_indirect && (is_proxy || is_indirect)))
+                   (skip_indirect && is_indirect))
                {
-                       if (!is_indirect && (is_never_null || is_proxy || is_obj_editmode)) {
+                       if (is_indirect) {
+                               id_remap_data->skipped_indirect++;
+                       }
+                       else if (is_never_null || is_obj_editmode) {
                                id_remap_data->skipped_direct++;
                        }
                        else {
-                               id_remap_data->skipped_indirect++;
+                               BLI_assert(0);
                        }
                        if (cb_flag & IDWALK_USER) {
                                id_remap_data->skipped_refcounted++;
        return IDWALK_RET_NOP;
  }
  
+ /* Some reamapping unfortunately require extra and/or specific handling, tackle those here. */
+ static void libblock_remap_data_preprocess_scene_base_unlink(
+         IDRemap *r_id_remap_data, Scene *sce, Base *base, const bool skip_indirect, const bool is_indirect)
+ {
+       if (skip_indirect && is_indirect) {
+               r_id_remap_data->skipped_indirect++;
+               r_id_remap_data->skipped_refcounted++;
+       }
+       else {
+               id_us_min((ID *)base->object);
+               BKE_scene_base_unlink(sce, base);
+               MEM_freeN(base);
+               if (!is_indirect) {
+                       r_id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT;
+               }
+       }
+ }
+ static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data)
+ {
+       switch (GS(r_id_remap_data->id->name)) {
+               case ID_SCE:
+               {
+                       Scene *sce = (Scene *)r_id_remap_data->id;
+                       if (!r_id_remap_data->new_id) {
+                               const bool is_indirect = (sce->id.lib != NULL);
+                               const bool skip_indirect = (r_id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0;
+                               /* In case we are unlinking... */
+                               if (!r_id_remap_data->old_id) {
+                                       /* ... everything from scene. */
+                                       Base *base, *base_next;
+                                       for (base = sce->base.first; base; base = base_next) {
+                                               base_next = base->next;
+                                               libblock_remap_data_preprocess_scene_base_unlink(
+                                                           r_id_remap_data, sce, base, skip_indirect, is_indirect);
+                                       }
+                               }
+                               else if (GS(r_id_remap_data->old_id->name) == ID_OB) {
+                                       /* ... a specific object from scene. */
+                                       Object *old_ob = (Object *)r_id_remap_data->old_id;
+                                       Base *base = BKE_scene_base_find(sce, old_ob);
+                                       if (base) {
+                                               libblock_remap_data_preprocess_scene_base_unlink(
+                                                           r_id_remap_data, sce, base, skip_indirect, is_indirect);
+                                       }
+                               }
+                       }
+                       break;
+               }
+               case ID_OB:
+               {
+                       ID *old_id = r_id_remap_data->old_id;
+                       if (!old_id || GS(old_id->name) == ID_AR) {
+                               Object *ob = (Object *)r_id_remap_data->id;
+                               /* Object's pose holds reference to armature bones... sic */
+                               /* Note that in theory, we should have to bother about linked/non-linked/never-null/etc. flags/states.
+                                * Fortunately, this is just a tag, so we can accept to 'over-tag' a bit for pose recalc, and avoid
+                                * another complex and risky condition nightmare like the one we have in
+                                * foreach_libblock_remap_callback()... */
+                               if (ob->pose && (!old_id || ob->data == old_id)) {
+                                       BLI_assert(ob->type == OB_ARMATURE);
+                                       ob->pose->flag |= POSE_RECALC;
+                               }
+                       }
+                       break;
+               }
+               default:
+                       break;
+       }
+ }
+ static void libblock_remap_data_postprocess_object_fromgroup_update(Main *bmain, Object *old_ob, Object *new_ob)
+ {
+       if (old_ob->flag & OB_FROMGROUP) {
+               /* Note that for Scene's BaseObject->flag, either we:
+                *     - unlinked old_ob (i.e. new_ob is NULL), in which case scenes' bases have been removed already.
+                *     - remapped old_ob by new_ob, in which case scenes' bases are still valid as is.
+                * So in any case, no need to update them here. */
+               if (BKE_group_object_find(NULL, old_ob) == NULL) {
+                       old_ob->flag &= ~OB_FROMGROUP;
+               }
+               if (new_ob == NULL) {  /* We need to remove NULL-ified groupobjects... */
+                       for (Group *group = bmain->group.first; group; group = group->id.next) {
+                               BKE_group_object_unlink(group, NULL, NULL, NULL);
+                       }
+               }
+               else {
+                       new_ob->flag |= OB_FROMGROUP;
+               }
+       }
+ }
+ static void libblock_remap_data_postprocess_group_scene_unlink(Main *UNUSED(bmain), Scene *sce, ID *old_id)
+ {
+       /* Note that here we assume no object has no base (i.e. all objects are assumed instanced
+        * in one scene...). */
+       for (Base *base = sce->base.first; base; base = base->next) {
+               if (base->flag & OB_FROMGROUP) {
+                       Object *ob = base->object;
+                       if (ob->flag & OB_FROMGROUP) {
+                               Group *grp = BKE_group_object_find(NULL, ob);
+                               /* Unlinked group (old_id) is still in bmain... */
+                               if (grp && (&grp->id == old_id || grp->id.us == 0)) {
+                                       grp = BKE_group_object_find(grp, ob);
+                               }
+                               if (!grp) {
+                                       ob->flag &= ~OB_FROMGROUP;
+                               }
+                       }
+                       if (!(ob->flag & OB_FROMGROUP)) {
+                               base->flag &= ~OB_FROMGROUP;
+                       }
+               }
+       }
+ }
+ static void libblock_remap_data_postprocess_obdata_relink(Main *UNUSED(bmain), Object *ob, ID *new_id)
+ {
+       if (ob->data == new_id) {
+               switch (GS(new_id->name)) {
+                       case ID_ME:
+                               multires_force_update(ob);
+                               break;
+                       case ID_CU:
+                               BKE_curve_type_test(ob);
+                               break;
+                       default:
+                               break;
+               }
+               test_object_modifiers(ob);
+               test_object_materials(ob, new_id);
+       }
+ }
  /**
   * Execute the 'data' part of the remapping (that is, all ID pointers from other ID datablocks).
   *
@@@ -263,6 -412,7 +411,7 @@@ static void libblock_remap_data
                printf("\tchecking id %s (%p, %p)\n", id->name, id, id->lib);
  #endif
                r_id_remap_data->id = id;
+               libblock_remap_data_preprocess(r_id_remap_data);
                BKE_library_foreach_ID_link(id, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP);
        }
        else {
                while (i--) {
                        ID *id_curr = lb_array[i]->first;
  
+                       if (!id_curr || !BKE_library_idtype_can_use_idtype(GS(id_curr->name), GS(old_id->name))) {
+                               continue;
+                       }
                        for (; id_curr; id_curr = id_curr->next) {
                                /* Note that we cannot skip indirect usages of old_id here (if requested), we still need to check it for
                                 * the user count handling...
                                 * XXX No more true (except for debug usage of those skipping counters). */
                                r_id_remap_data->id = id_curr;
+                               libblock_remap_data_preprocess(r_id_remap_data);
                                BKE_library_foreach_ID_link(
                                            id_curr, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP);
                        }
@@@ -323,29 -478,6 +477,6 @@@ void BKE_libblock_remap_locked
        BLI_assert((new_id == NULL) || GS(old_id->name) == GS(new_id->name));
        BLI_assert(old_id != new_id);
  
-       /* Some pre-process updates.
-        * This is a bit ugly, but cannot see a way to avoid it. Maybe we should do a per-ID callback for this instead?
-        */
-       if (GS(old_id->name) == ID_OB) {
-               Object *old_ob = (Object *)old_id;
-               Object *new_ob = (Object *)new_id;
-               if (new_ob == NULL) {
-                       Scene *sce;
-                       Base *base;
-                       for (sce = bmain->scene.first; sce; sce = sce->id.next) {
-                               base = BKE_scene_base_find(sce, old_ob);
-                               if (base) {
-                                       id_us_min((ID *)base->object);
-                                       BKE_scene_base_unlink(sce, base);
-                                       MEM_freeN(base);
-                               }
-                       }
-               }
-       }
        libblock_remap_data(bmain, NULL, old_id, new_id, remap_flags, &id_remap_data);
  
        if (free_notifier_reference_cb) {
         */
        switch (GS(old_id->name)) {
                case ID_OB:
-               {
-                       Object *old_ob = (Object *)old_id;
-                       Object *new_ob = (Object *)new_id;
-                       if (old_ob->flag & OB_FROMGROUP) {
-                               /* Note that for Scene's BaseObject->flag, either we:
-                                *     - unlinked old_ob (i.e. new_ob is NULL), in which case scenes' bases have been removed already.
-                                *     - remapped old_ob by new_ob, in which case scenes' bases are still valid as is.
-                                * So in any case, no need to update them here. */
-                               if (BKE_group_object_find(NULL, old_ob) == NULL) {
-                                       old_ob->flag &= ~OB_FROMGROUP;
-                               }
-                               if (new_ob == NULL) {  /* We need to remove NULL-ified groupobjects... */
-                                       Group *group;
-                                       for (group = bmain->group.first; group; group = group->id.next) {
-                                               BKE_group_object_unlink(group, NULL, NULL, NULL);
-                                       }
-                               }
-                               else {
-                                       new_ob->flag |= OB_FROMGROUP;
-                               }
-                       }
+                       libblock_remap_data_postprocess_object_fromgroup_update(bmain, (Object *)old_id, (Object *)new_id);
                        break;
-               }
                case ID_GR:
-                       if (new_id == NULL) {  /* Only affects us in case group was unlinked. */
+                       if (!new_id) {  /* Only affects us in case group was unlinked. */
                                for (Scene *sce = bmain->scene.first; sce; sce = sce->id.next) {
-                                       /* Note that here we assume no object has no base (i.e. all objects are assumed instanced
-                                        * in one scene...). */
-                                       for (Base *base = sce->base.first; base; base = base->next) {
-                                               if (base->flag & OB_FROMGROUP) {
-                                                       Object *ob = base->object;
-                                                       if (ob->flag & OB_FROMGROUP) {
-                                                               Group *grp = BKE_group_object_find(NULL, ob);
-                                                               /* Unlinked group (old_id) is still in bmain... */
-                                                               if (grp && (&grp->id == old_id)) {
-                                                                       grp = BKE_group_object_find(grp, ob);
-                                                               }
-                                                               if (!grp) {
-                                                                       ob->flag &= ~OB_FROMGROUP;
-                                                               }
-                                                       }
-                                                       if (!(ob->flag & OB_FROMGROUP)) {
-                                                               base->flag &= ~OB_FROMGROUP;
-                                                       }
-                                               }
-                                       }
+                                       libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, old_id);
+                               }
+                       }
+                       break;
+               case ID_ME:
+               case ID_CU:
+               case ID_MB:
+                       if (new_id) {  /* Only affects us in case obdata was relinked (changed). */
+                               for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
+                                       libblock_remap_data_postprocess_obdata_relink(bmain, ob, new_id);
                                }
                        }
                        break;
@@@ -460,9 -558,10 +557,10 @@@ void BKE_libblock_remap(Main *bmain, vo
   * \param do_flag_never_null: If true, all IDs using \a idv in a 'non-NULL' way are flagged by \a LIB_TAG_DOIT flag
   * (quite obviously, 'non-NULL' usages can never be unlinked by this function...).
   */
- void BKE_libblock_unlink(Main *bmain, void *idv, const bool do_flag_never_null)
+ void BKE_libblock_unlink(Main *bmain, void *idv, const bool do_flag_never_null, const bool do_skip_indirect)
  {
-       const short remap_flags = ID_REMAP_SKIP_INDIRECT_USAGE | (do_flag_never_null ? ID_REMAP_FLAG_NEVER_NULL_USAGE : 0);
+       const short remap_flags = (do_skip_indirect ? ID_REMAP_SKIP_INDIRECT_USAGE : 0) |
+                                 (do_flag_never_null ? ID_REMAP_FLAG_NEVER_NULL_USAGE : 0);
  
        BKE_main_lock(bmain);
  
   *     ... sigh
   */
  void BKE_libblock_relink_ex(
-         void *idv, void *old_idv, void *new_idv, const bool us_min_never_null)
+         Main *bmain, void *idv, void *old_idv, void *new_idv, const bool us_min_never_null)
  {
        ID *id = idv;
        ID *old_id = old_idv;
        ID *new_id = new_idv;
        int remap_flags = us_min_never_null ? 0 : ID_REMAP_SKIP_NEVER_NULL_USAGE;
  
-       /* No need to lock here, we are only affecting given ID. */
+       /* No need to lock here, we are only affecting given ID, not bmain database. */
  
        BLI_assert(id);
        if (old_id) {
        }
  
        libblock_remap_data(NULL, id, old_id, new_id, remap_flags, NULL);
+       /* Some after-process updates.
+        * This is a bit ugly, but cannot see a way to avoid it. Maybe we should do a per-ID callback for this instead?
+        */
+       switch (GS(id->name)) {
+               case ID_SCE:
+               {
+                       Scene *sce = (Scene *)id;
+                       if (old_id) {
+                               switch (GS(old_id->name)) {
+                                       case ID_OB:
+                                       {
+                                               libblock_remap_data_postprocess_object_fromgroup_update(
+                                                           bmain, (Object *)old_id, (Object *)new_id);
+                                               break;
+                                       }
+                                       case ID_GR:
+                                               if (!new_id) {  /* Only affects us in case group was unlinked. */
+                                                       libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, old_id);
+                                               }
+                                               break;
+                                       default:
+                                               break;
+                               }
+                       }
+                       else {
+                               /* No choice but to check whole objects/groups. */
+                               for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
+                                       libblock_remap_data_postprocess_object_fromgroup_update(bmain, ob, NULL);
+                               }
+                               for (Group *grp = bmain->group.first; grp; grp = grp->id.next) {
+                                       libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, NULL);
+                               }
+                       }
+               }
+               case ID_OB:
+                       if (new_id) {  /* Only affects us in case obdata was relinked (changed). */
+                               libblock_remap_data_postprocess_obdata_relink(bmain, (Object *)id, new_id);
+                       }
+                       break;
+               default:
+                       break;
+       }
  }
  
  static void animdata_dtar_clear_cb(ID *UNUSED(id), AnimData *adt, void *userdata)
@@@ -561,7 -704,7 +703,7 @@@ void BKE_libblock_free_ex(Main *bmain, 
  #endif
  
        if (do_id_user) {
-               BKE_libblock_relink_ex(id, NULL, NULL, true);
+               BKE_libblock_relink_ex(bmain, id, NULL, NULL, true);
        }
  
        switch (type) {
                case ID_BR:
                        BKE_brush_free((Brush *)id);
                        break;
 -              case ID_PA:
 -                      BKE_particlesettings_free((ParticleSettings *)id);
 -                      break;
                case ID_WM:
                        if (free_windowmanager_cb)
                                free_windowmanager_cb(NULL, (wmWindowManager *)id);
@@@ -705,7 -851,7 +847,7 @@@ void BKE_libblock_free_us(Main *bmain, 
        }
  
        if (id->us == 0) {
-               BKE_libblock_unlink(bmain, id, false);
+               BKE_libblock_unlink(bmain, id, false, false);
                
                BKE_libblock_free(bmain, id);
        }
index 59eeb5dd96ac6bfdec1befc39350fa33639e9ee6,41e4c21d8141615832b04040513934b53d2e1294..936b014cca333d1f05455643b0815cb80648cf22
@@@ -401,6 -401,13 +401,6 @@@ bool modifiers_isModifierEnabled(Objec
        return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render));
  }
  
 -bool modifiers_isParticleEnabled(Object *ob)
 -{
 -      ModifierData *md = modifiers_findByType(ob, eModifierType_ParticleSystem);
 -
 -      return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render));
 -}
 -
  bool modifier_isEnabled(struct Scene *scene, ModifierData *md, int required_mode)
  {
        const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
@@@ -700,7 -707,7 +700,7 @@@ void test_object_modifiers(Object *ob
   */
  const char *modifier_path_relbase(Object *ob)
  {
-       if (G.relbase_valid || ob->id.lib) {
+       if (G.relbase_valid || ID_IS_LINKED_DATABLOCK(ob)) {
                return ID_BLEND_PATH(G.main, &ob->id);
        }
        else {
index 357f01e096139533c0571d04a4099436ddcf8be7,30a193506a61aed1d4c596c90e2ba2d01252eeae..00c25bed1f70ac3a823ac43d5535a4067c04f2bf
@@@ -50,8 -50,6 +50,8 @@@
  #include "DNA_mesh_types.h"
  #include "DNA_meshdata_types.h"
  #include "DNA_movieclip_types.h"
 +#include "DNA_object_force.h"
 +#include "DNA_object_types.h"
  #include "DNA_scene_types.h"
  #include "DNA_screen_types.h"
  #include "DNA_sequence_types.h"
@@@ -95,6 -93,8 +95,8 @@@
  #include "BKE_lamp.h"
  #include "BKE_lattice.h"
  #include "BKE_library.h"
+ #include "BKE_library_query.h"
+ #include "BKE_library_remap.h"
  #include "BKE_linestyle.h"
  #include "BKE_mesh.h"
  #include "BKE_editmesh.h"
  #include "BKE_node.h"
  #include "BKE_object.h"
  #include "BKE_paint.h"
 -#include "BKE_particle.h"
 -#include "BKE_pointcache.h"
  #include "BKE_property.h"
  #include "BKE_rigidbody.h"
  #include "BKE_sca.h"
@@@ -159,6 -161,15 +161,6 @@@ void BKE_object_update_base_layer(struc
        }
  }
  
 -void BKE_object_free_particlesystems(Object *ob)
 -{
 -      ParticleSystem *psys;
 -
 -      while ((psys = BLI_pophead(&ob->particlesystem))) {
 -              psys_free(ob, psys);
 -      }
 -}
 -
  void BKE_object_free_softbody(Object *ob)
  {
        if (ob->soft) {
@@@ -197,6 -208,9 +199,6 @@@ void BKE_object_free_modifiers(Object *
                modifier_free(md);
        }
  
 -      /* particle modifiers were freed, so free the particlesystems as well */
 -      BKE_object_free_particlesystems(ob);
 -
        /* same for softbody */
        BKE_object_free_softbody(ob);
  
@@@ -293,6 -307,8 +295,6 @@@ void BKE_object_link_modifiers(struct O
                modifier_unique_name(&ob_dst->modifiers, nmd);
        }
  
 -      BKE_object_copy_particlesystems(ob_dst, ob_src);
 -
        /* TODO: smoke?, cloth? */
  }
  
@@@ -336,8 -352,40 +338,8 @@@ void BKE_object_free_derived_caches(Obj
  
  void BKE_object_free_caches(Object *object)
  {
 -      ModifierData *md;
        short update_flag = 0;
  
 -      /* Free particle system caches holding paths. */
 -      if (object->particlesystem.first) {
 -              ParticleSystem *psys;
 -              for (psys = object->particlesystem.first;
 -                   psys != NULL;
 -                   psys = psys->next)
 -              {
 -                      psys_free_path_cache(psys, psys->edit);
 -                      update_flag |= PSYS_RECALC_REDO;
 -              }
 -      }
 -
 -      /* Free memory used by cached derived meshes in the particle system modifiers. */
 -      for (md = object->modifiers.first; md != NULL; md = md->next) {
 -              if (md->type == eModifierType_ParticleSystem) {
 -                      ParticleSystemModifierData *psmd = (ParticleSystemModifierData *) md;
 -                      if (psmd->dm_final != NULL) {
 -                              psmd->dm_final->needsFree = 1;
 -                              psmd->dm_final->release(psmd->dm_final);
 -                              psmd->dm_final = NULL;
 -                              if (psmd->dm_deformed != NULL) {
 -                                      psmd->dm_deformed->needsFree = 1;
 -                                      psmd->dm_deformed->release(psmd->dm_deformed);
 -                                      psmd->dm_deformed = NULL;
 -                              }
 -                              psmd->flag |= eParticleSystemFlag_file_loaded;
 -                              update_flag |= OB_RECALC_DATA;
 -                      }
 -              }
 -      }
 -
        /* Tag object for update, so once memory critical operation is over and
         * scene update routines are back to it's business the object will be
         * guaranteed to be in a known state.
@@@ -816,6 -864,8 +818,6 @@@ SoftBody *copy_softbody(const SoftBody 
        
        sbn->scratch = NULL;
  
 -      sbn->pointcache = BKE_ptcache_copy_list(&sbn->ptcaches, &sb->ptcaches, copy_caches);
 -
        if (sb->effector_weights)
                sbn->effector_weights = MEM_dupallocN(sb->effector_weights);
  
@@@ -833,6 -883,119 +835,6 @@@ BulletSoftBody *copy_bulletsoftbody(Bul
        return bsbn;
  }
  
 -ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys)
 -{
 -      ParticleSystem *psysn;
 -      ParticleData *pa;
 -      int p;
 -
 -      psysn = MEM_dupallocN(psys);
 -      psysn->particles = MEM_dupallocN(psys->particles);
 -      psysn->child = MEM_dupallocN(psys->child);
 -
 -      if (psys->part->type == PART_HAIR) {
 -              for (p = 0, pa = psysn->particles; p < psysn->totpart; p++, pa++)
 -                      pa->hair = MEM_dupallocN(pa->hair);
 -      }
 -
 -      if (psysn->particles && (psysn->particles->keys || psysn->particles->boid)) {
 -              ParticleKey *key = psysn->particles->keys;
 -              BoidParticle *boid = psysn->particles->boid;
 -
 -              if (key)
 -                      key = MEM_dupallocN(key);
 -              
 -              if (boid)
 -                      boid = MEM_dupallocN(boid);
 -              
 -              for (p = 0, pa = psysn->particles; p < psysn->totpart; p++, pa++) {
 -                      if (boid)
 -                              pa->boid = boid++;
 -                      if (key) {
 -                              pa->keys = key;
 -                              key += pa->totkey;
 -                      }
 -              }
 -      }
 -
 -      if (psys->clmd) {
 -              psysn->clmd = (ClothModifierData *)modifier_new(eModifierType_Cloth);
 -              modifier_copyData((ModifierData *)psys->clmd, (ModifierData *)psysn->clmd);
 -              psys->hair_in_dm = psys->hair_out_dm = NULL;
 -      }
 -
 -      BLI_duplicatelist(&psysn->targets, &psys->targets);
 -
 -      psysn->pathcache = NULL;
 -      psysn->childcache = NULL;
 -      psysn->edit = NULL;
 -      psysn->pdd = NULL;
 -      psysn->effectors = NULL;
 -      psysn->tree = NULL;
 -      psysn->bvhtree = NULL;
 -      
 -      BLI_listbase_clear(&psysn->pathcachebufs);
 -      BLI_listbase_clear(&psysn->childcachebufs);
 -      psysn->renderdata = NULL;
 -      
 -      psysn->pointcache = BKE_ptcache_copy_list(&psysn->ptcaches, &psys->ptcaches, false);
 -
 -      /* XXX - from reading existing code this seems correct but intended usage of
 -       * pointcache should /w cloth should be added in 'ParticleSystem' - campbell */
 -      if (psysn->clmd) {
 -              psysn->clmd->point_cache = psysn->pointcache;
 -      }
 -
 -      id_us_plus((ID *)psysn->part);
 -
 -      return psysn;
 -}
 -
 -void BKE_object_copy_particlesystems(Object *ob_dst, const Object *ob_src)
 -{
 -      ParticleSystem *psys, *npsys;
 -      ModifierData *md;
 -
 -      if (ob_dst->type != OB_MESH) {
 -              /* currently only mesh objects can have soft body */
 -              return;
 -      }
 -
 -      BLI_listbase_clear(&ob_dst->particlesystem);
 -      for (psys = ob_src->particlesystem.first; psys; psys = psys->next) {
 -              npsys = BKE_object_copy_particlesystem(psys);
 -
 -              BLI_addtail(&ob_dst->particlesystem, npsys);
 -
 -              /* need to update particle modifiers too */
 -              for (md = ob_dst->modifiers.first; md; md = md->next) {
 -                      if (md->type == eModifierType_ParticleSystem) {
 -                              ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md;
 -                              if (psmd->psys == psys)
 -                                      psmd->psys = npsys;
 -                      }
 -                      else if (md->type == eModifierType_DynamicPaint) {
 -                              DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
 -                              if (pmd->brush) {
 -                                      if (pmd->brush->psys == psys) {
 -                                              pmd->brush->psys = npsys;
 -                                      }
 -                              }
 -                      }
 -                      else if (md->type == eModifierType_Smoke) {
 -                              SmokeModifierData *smd = (SmokeModifierData *) md;
 -                              
 -                              if (smd->type == MOD_SMOKE_TYPE_FLOW) {
 -                                      if (smd->flow) {
 -                                              if (smd->flow->psys == psys)
 -                                                      smd->flow->psys = npsys;
 -                                      }
 -                              }
 -                      }
 -              }
 -      }
 -}
 -
  void BKE_object_copy_softbody(Object *ob_dst, const Object *ob_src)
  {
        if (ob_src->soft) {
@@@ -931,7 -1094,7 +933,7 @@@ Object *BKE_object_copy_ex(Main *bmain
        ModifierData *md;
        int a;
  
-       obn = BKE_libblock_copy_ex(bmain, &ob->id);
+       obn = BKE_libblock_copy(bmain, &ob->id);
        
        if (ob->totcol) {
                obn->mat = MEM_dupallocN(ob->mat);
        obn->rigidbody_object = BKE_rigidbody_copy_object(ob);
        obn->rigidbody_constraint = BKE_rigidbody_copy_constraint(ob);
  
 -      BKE_object_copy_particlesystems(obn, ob);
 -      
        obn->derivedDeform = NULL;
        obn->derivedFinal = NULL;
  
  
        copy_object_lod(obn, ob);
        
        /* Copy runtime surve data. */
        obn->curve_cache = NULL;
  
-       if (ob->id.lib) {
+       if (ID_IS_LINKED_DATABLOCK(ob)) {
+               BKE_id_expand_local(&obn->id);
                BKE_id_lib_local_paths(bmain, ob->id.lib, &obn->id);
        }
  
  }
  
  /* copy objects, will re-initialize cached simulation data */
- Object *BKE_object_copy(Object *ob)
+ Object *BKE_object_copy(Main *bmain, Object *ob)
  {
-       return BKE_object_copy_ex(G.main, ob, false);
+       return BKE_object_copy_ex(bmain, ob, false);
  }
  
- static void extern_local_object__modifiersForeachIDLink(
-         void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int UNUSED(cd_flag))
+ void BKE_object_make_local(Main *bmain, Object *ob)
  {
-       if (*idpoin) {
-               /* intentionally omit ID_OB */
-               if (ELEM(GS((*idpoin)->name), ID_IM, ID_TE)) {
-                       id_lib_extern(*idpoin);
-               }
-       }
- }
- static void extern_local_object(Object *ob)
- {
-       id_lib_extern((ID *)ob->data);
-       id_lib_extern((ID *)ob->dup_group);
-       id_lib_extern((ID *)ob->poselib);
-       id_lib_extern((ID *)ob->gpd);
-       extern_local_matarar(ob->mat, ob->totcol);
-       modifiers_foreachIDLink(ob, extern_local_object__modifiersForeachIDLink, NULL);
-       ob->preview = NULL;
- }
- void BKE_object_make_local(Object *ob)
- {
-       Main *bmain = G.main;
-       Scene *sce;
-       Base *base;
        bool is_local = false, is_lib = false;
  
        /* - only lib users: do nothing
         * - mixed: make copy
         */
  
-       if (ob->id.lib == NULL) return;
-       
-       ob->proxy = ob->proxy_from  = ob->proxy_group = NULL;
-       
-       if (ob->id.us == 1) {
-               id_clear_lib_data(bmain, &ob->id);
-               extern_local_object(ob);
+       if (!ID_IS_LINKED_DATABLOCK(ob)) {
+               return;
        }
-       else {
-               for (sce = bmain->scene.first; sce && ELEM(0, is_lib, is_local); sce = sce->id.next) {
-                       if (BKE_scene_base_find(sce, ob)) {
-                               if (sce->id.lib) is_lib = true;
-                               else is_local = true;
-                       }
-               }
  
-               if (is_local && is_lib == false) {
+       BKE_library_ID_test_usages(bmain, ob, &is_local, &is_lib);
+       if (is_local) {
+               if (!is_lib) {
                        id_clear_lib_data(bmain, &ob->id);
-                       extern_local_object(ob);
+                       BKE_id_expand_local(&ob->id);
                }
-               else if (is_local && is_lib) {
-                       Object *ob_new = BKE_object_copy(ob);
+               else {
+                       Object *ob_new = BKE_object_copy(bmain, ob);
  
                        ob_new->id.us = 0;
-                       
-                       /* Remap paths of new ID using old library as base. */
-                       BKE_id_lib_local_paths(bmain, ob->id.lib, &ob_new->id);
-                       sce = bmain->scene.first;
-                       while (sce) {
-                               if (sce->id.lib == NULL) {
-                                       base = sce->base.first;
-                                       while (base) {
-                                               if (base->object == ob) {
-                                                       base->object = ob_new;
-                                                       id_us_plus(&ob_new->id);
-                                                       id_us_min(&ob->id);
-                                               }
-                                               base = base->next;
-                                       }
-                               }
-                               sce = sce->id.next;
-                       }
+                       ob_new->proxy = ob_new->proxy_from = ob_new->proxy_group = NULL;
+                       BKE_libblock_remap(bmain, ob, ob_new, ID_REMAP_SKIP_INDIRECT_USAGE);
                }
        }
  }
  
- /*
-  * Returns true if the Object is a from an external blend file (libdata)
-  */
+ /* Returns true if the Object is from an external blend file (libdata) */
  bool BKE_object_is_libdata(Object *ob)
  {
-       if (!ob) return false;
-       if (ob->proxy) return false;
-       if (ob->id.lib) return true;
-       return false;
+       return (ob && ID_IS_LINKED_DATABLOCK(ob));
  }
  
- /* Returns true if the Object data is from an external blend file (libdata) */
+ /* Returns true if the Object data is from an external blend file (libdata) */
  bool BKE_object_obdata_is_libdata(Object *ob)
  {
-       if (!ob) return false;
-       if (ob->proxy && (ob->data == NULL || ((ID *)ob->data)->lib == NULL)) return false;
-       if (ob->id.lib) return true;
-       if (ob->data == NULL) return false;
-       if (((ID *)ob->data)->lib) return true;
-       return false;
+       /* Linked objects with local obdata are forbidden! */
+       BLI_assert(!ob || !ob->data || (ID_IS_LINKED_DATABLOCK(ob) ? ID_IS_LINKED_DATABLOCK(ob->data) : true));
+       return (ob && ob->data && ID_IS_LINKED_DATABLOCK(ob->data));
  }
  
  /* *************** PROXY **************** */
@@@ -1172,7 -1275,7 +1112,7 @@@ void BKE_object_copy_proxy_drivers(Obje
                                                        /* only on local objects because this causes indirect links
                                                         * 'a -> b -> c', blend to point directly to a.blend
                                                         * when a.blend has a proxy thats linked into c.blend  */
-                                                       if (ob->id.lib == NULL)
+                                                       if (!ID_IS_LINKED_DATABLOCK(ob))
                                                                id_lib_extern((ID *)dtar->id);
                                                }
                                        }
  void BKE_object_make_proxy(Object *ob, Object *target, Object *gob)
  {
        /* paranoia checks */
-       if (ob->id.lib || target->id.lib == NULL) {
+       if (ID_IS_LINKED_DATABLOCK(ob) || !ID_IS_LINKED_DATABLOCK(target)) {
                printf("cannot make proxy\n");
                return;
        }
@@@ -2567,7 -2670,7 +2507,7 @@@ void BKE_object_handle_update_ex(Evalua
                                printf("recalcob %s\n", ob->id.name + 2);
                        
                        /* handle proxy copy for target */
-                       if (ob->id.lib && ob->proxy_from) {
+                       if (ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from) {
                                // printf("ob proxy copy, lib ob %s proxy %s\n", ob->id.name, ob->proxy_from->id.name);
                                if (ob->proxy_from->proxy_group) { /* transform proxy into group space */
                                        Object *obg = ob->proxy_from->proxy_group;
@@@ -3551,6 -3654,25 +3491,6 @@@ bool BKE_object_modifier_use_time(Objec
        return false;
  }
  
 -/* set "ignore cache" flag for all caches on this object */
 -static void object_cacheIgnoreClear(Object *ob, int state)
 -{
 -      ListBase pidlist;
 -      PTCacheID *pid;
 -      BKE_ptcache_ids_from_object(&pidlist, ob, NULL, 0);
 -
 -      for (pid = pidlist.first; pid; pid = pid->next) {
 -              if (pid->cache) {
 -                      if (state)
 -                              pid->cache->flag |= PTCACHE_IGNORE_CLEAR;
 -                      else
 -                              pid->cache->flag &= ~PTCACHE_IGNORE_CLEAR;
 -              }
 -      }
 -
 -      BLI_freelistN(&pidlist);
 -}
 -
  /* Note: this function should eventually be replaced by depsgraph functionality.
   * Avoid calling this in new code unless there is a very good reason for it!
   */
@@@ -3610,7 -3732,11 +3550,7 @@@ bool BKE_object_modifier_update_subfram
        ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME;
        BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, frame, ADT_RECALC_ANIM);
        if (update_mesh) {
 -              /* ignore cache clear during subframe updates
 -               *  to not mess up cache validity */
 -              object_cacheIgnoreClear(ob, 1);
                BKE_object_handle_update(G.main->eval_ctx, scene, ob);
 -              object_cacheIgnoreClear(ob, 0);
        }
        else
                BKE_object_where_is_calc_time(scene, ob, frame);
index 8df501bd106f504e8e27dd9b99d9b2c31672e0c7,457263f854b5647acff82ec608af49245fe7e699..b5cb59da7d27d11e9676219f642f7ff06c7d6339
@@@ -32,7 -32,6 +32,7 @@@
  #include "DNA_group_types.h"
  #include "DNA_key_types.h"
  #include "DNA_material_types.h"
 +#include "DNA_object_types.h"
  #include "DNA_scene_types.h"
  
  #include "BLI_blenlib.h"
@@@ -54,6 -53,7 +54,6 @@@
  #include "BKE_lattice.h"
  #include "BKE_editmesh.h"
  #include "BKE_object.h"
 -#include "BKE_particle.h"
  #include "BKE_scene.h"
  #include "BKE_material.h"
  #include "BKE_image.h"
@@@ -203,7 -203,7 +203,7 @@@ void BKE_object_handle_data_update(Eval
                        break;
                }
                case OB_ARMATURE:
-                       if (ob->id.lib && ob->proxy_from) {
+                       if (ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from) {
                                if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) {
                                        printf("Proxy copy error, lib Object: %s proxy Object: %s\n",
                                               ob->id.name + 2, ob->proxy_from->id.name + 2);
        else if (ob->type == OB_LAMP)
                lamp_drivers_update(scene, ob->data, ctime);
  
 -      /* particles */
 -      if (ob != scene->obedit && ob->particlesystem.first) {
 -              ParticleSystem *tpsys, *psys;
 -              DerivedMesh *dm;
 -              ob->transflag &= ~OB_DUPLIPARTS;
 -              psys = ob->particlesystem.first;
 -              while (psys) {
 -                      /* ensure this update always happens even if psys is disabled */
 -                      if (psys->recalc & PSYS_RECALC_TYPE) {
 -                              psys_changed_type(ob, psys);
 -                      }
 -
 -                      if (psys_check_enabled(ob, psys, eval_ctx->mode == DAG_EVAL_RENDER)) {
 -                              /* check use of dupli objects here */
 -                              if (psys->part && (psys->part->draw_as == PART_DRAW_REND || eval_ctx->mode == DAG_EVAL_RENDER) &&
 -                                  ((psys->part->ren_as == PART_DRAW_OB && psys->part->dup_ob) ||
 -                                   (psys->part->ren_as == PART_DRAW_GR && psys->part->dup_group)))
 -                              {
 -                                      ob->transflag |= OB_DUPLIPARTS;
 -                              }
 -
 -                              particle_system_update(scene, ob, psys, (eval_ctx->mode == DAG_EVAL_RENDER));
 -                              psys = psys->next;
 -                      }
 -                      else if (psys->flag & PSYS_DELETE) {
 -                              tpsys = psys->next;
 -                              BLI_remlink(&ob->particlesystem, psys);
 -                              psys_free(ob, psys);
 -                              psys = tpsys;
 -                      }
 -                      else
 -                              psys = psys->next;
 -              }
 -
 -              if (eval_ctx->mode == DAG_EVAL_RENDER && ob->transflag & OB_DUPLIPARTS) {
 -                      /* this is to make sure we get render level duplis in groups:
 -                       * the derivedmesh must be created before init_render_mesh,
 -                       * since object_duplilist does dupliparticles before that */
 -                      CustomDataMask data_mask = CD_MASK_BAREMESH | CD_MASK_MFACE | CD_MASK_MTFACE | CD_MASK_MCOL;
 -                      dm = mesh_create_derived_render(scene, ob, data_mask);
 -                      dm->release(dm);
 -
 -                      for (psys = ob->particlesystem.first; psys; psys = psys->next)
 -                              psys_get_modifier(ob, psys)->flag &= ~eParticleSystemFlag_psys_updated;
 -              }
 -      }
 -
        /* quick cache removed */
  }
  
@@@ -268,7 -315,7 +268,7 @@@ void BKE_object_eval_uber_transform(Eva
        // XXX: it's almost redundant now...
  
        /* Handle proxy copy for target, */
-       if (ob->id.lib && ob->proxy_from) {
+       if (ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from) {
                if (ob->proxy_from->proxy_group) {
                        /* Transform proxy into group space. */
                        Object *obg = ob->proxy_from->proxy_group;
index 4a649c2ea6d396d4ee23c1e3ec7a9323048e1401,858b6bd927b22953b0a91f17f8b1685ccd914691..572d23b39c76848726c76b8d33176ef779c41839
@@@ -150,7 -150,7 +150,7 @@@ static void remove_sequencer_fcurves(Sc
        }
  }
  
- Scene *BKE_scene_copy(Scene *sce, int type)
+ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
  {
        Scene *scen;
        SceneRenderLayer *srl, *new_srl;
        if (type == SCE_COPY_EMPTY) {
                ListBase rl, rv;
                /* XXX. main should become an arg */
-               scen = BKE_scene_add(G.main, sce->id.name + 2);
+               scen = BKE_scene_add(bmain, sce->id.name + 2);
                
                rl = scen->r.layers;
                rv = scen->r.views;
                BKE_sound_destroy_scene(scen);
        }
        else {
-               scen = BKE_libblock_copy(&sce->id);
+               scen = BKE_libblock_copy(bmain, &sce->id);
                BLI_duplicatelist(&(scen->base), &(sce->base));
                
-               BKE_main_id_clear_newpoins(G.main);
+               BKE_main_id_clear_newpoins(bmain);
                
                id_us_plus((ID *)scen->world);
                id_us_plus((ID *)scen->set);
  
                if (sce->nodetree) {
                        /* ID's are managed on both copy and switch */
-                       scen->nodetree = ntreeCopyTree(sce->nodetree);
+                       scen->nodetree = ntreeCopyTree(bmain, sce->nodetree);
                        ntreeSwitchID(scen->nodetree, &sce->id, &scen->id);
                }
  
                                for (lineset = new_srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) {
                                        if (lineset->linestyle) {
                                                id_us_plus((ID *)lineset->linestyle);
-                                               lineset->linestyle = BKE_linestyle_copy(G.main, lineset->linestyle);
+                                               lineset->linestyle = BKE_linestyle_copy(bmain, lineset->linestyle);
                                        }
                                }
                        }
                BKE_paint_copy(&ts->imapaint.paint, &ts->imapaint.paint);
                ts->imapaint.paintcursor = NULL;
                id_us_plus((ID *)ts->imapaint.stencil);
 -              ts->particle.paintcursor = NULL;
        }
        
        /* make a private copy of the avicodecdata */
        if (type == SCE_COPY_FULL) {
                if (scen->world) {
                        id_us_plus((ID *)scen->world);
-                       scen->world = BKE_world_copy(scen->world);
+                       scen->world = BKE_world_copy(bmain, scen->world);
                        BKE_animdata_copy_id_action((ID *)scen->world);
                }
  
        /* grease pencil */
        if (scen->gpd) {
                if (type == SCE_COPY_FULL) {
-                       scen->gpd = gpencil_data_duplicate(scen->gpd, false);
+                       scen->gpd = gpencil_data_duplicate(bmain, scen->gpd, false);
                }
                else if (type == SCE_COPY_EMPTY) {
                        scen->gpd = NULL;
                }
        }
  
-       if (sce->preview) {
-               scen->preview = BKE_previewimg_copy(sce->preview);
-       }
+       scen->preview = BKE_previewimg_copy(sce->preview);
  
        return scen;
  }
@@@ -449,6 -448,8 +447,6 @@@ void BKE_scene_free(Scene *sce
  
  void BKE_scene_init(Scene *sce)
  {
 -      ParticleEditSettings *pset;
 -      int a;
        const char *colorspace_name;
        SceneRenderView *srv;
        CurveMapping *mblur_shutter_curve;
  
        sce->unit.scale_length = 1.0f;
  
 -      pset = &sce->toolsettings->particle;
 -      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;
 -      pset->selectmode = SCE_SELECT_PATH;
 -      for (a = 0; a < PE_TOT_BRUSH; a++) {
 -              pset->brush[a].strength = 0.5f;
 -              pset->brush[a].size = 50;
 -              pset->brush[a].step = 10;
 -              pset->brush[a].count = 10;
 -      }
 -      pset->brush[PE_BRUSH_CUT].strength = 1.0f;
 -
        sce->r.ffcodecdata.audio_mixrate = 48000;
        sce->r.ffcodecdata.audio_volume = 1.0f;
        sce->r.ffcodecdata.audio_bitrate = 192;
index 25b32cc40aa44338a341a454a7a44fad60b145bb,8fec817d6948bea6d03201d6d096967506cb35fe..fc3daa132c67f6f498e4a006dd330f0f529fa068
@@@ -63,7 -63,6 +63,7 @@@ variables on the UI for no
  #include "DNA_curve_types.h"
  #include "DNA_mesh_types.h"
  #include "DNA_meshdata_types.h"
 +#include "DNA_object_force.h"
  
  #include "BLI_math.h"
  #include "BLI_utildefines.h"
@@@ -76,6 -75,7 +76,6 @@@
  #include "BKE_global.h"
  #include "BKE_modifier.h"
  #include "BKE_softbody.h"
 -#include "BKE_pointcache.h"
  #include "BKE_deform.h"
  #include "BKE_mesh.h"
  #include "BKE_scene.h"
@@@ -1499,7 -1499,7 +1499,7 @@@ static void scan_for_ext_spring_forces(
        SoftBody *sb = ob->soft;
        ListBase *do_effector = NULL;
  
 -      do_effector = pdInitEffectors(scene, ob, NULL, sb->effector_weights, true);
 +      do_effector = pdInitEffectors(scene, ob, sb->effector_weights, true);
        _scan_for_ext_spring_forces(scene, ob, timenow, 0, sb->totspring, do_effector);
        pdEndEffectors(&do_effector);
  }
@@@ -1519,7 -1519,7 +1519,7 @@@ static void sb_sfesf_threads_run(Scene 
        int i, totthread, left, dec;
        int lowsprings =100; /* wild guess .. may increase with better thread management 'above' or even be UI option sb->spawn_cf_threads_nopts */
  
 -      do_effector= pdInitEffectors(scene, ob, NULL, ob->soft->effector_weights, true);
 +      do_effector= pdInitEffectors(scene, ob, ob->soft->effector_weights, true);
  
        /* figure the number of threads while preventing pretty pointless threading overhead */
        totthread= BKE_scene_num_threads(scene);
@@@ -2209,7 -2209,7 +2209,7 @@@ static void softbody_calc_forcesEx(Scen
                sb_sfesf_threads_run(scene, ob, timenow, sb->totspring, NULL);
  
        /* after spring scan because it uses Effoctors too */
 -      do_effector= pdInitEffectors(scene, ob, NULL, sb->effector_weights, true);
 +      do_effector= pdInitEffectors(scene, ob, sb->effector_weights, true);
  
        if (do_deflector) {
                float defforce[3];
@@@ -2243,7 -2243,7 +2243,7 @@@ static void softbody_calc_forces(Scene 
                .. keeping G.debug_value==17 0x11 option for old files 'needing' the bug*/
  
                /* rule we never alter free variables :bp->vec bp->pos in here !
-               * this will ruin adaptive stepsize AKA heun! (BM)
+                * this will ruin adaptive stepsize AKA heun! (BM)
                */
                SoftBody *sb= ob->soft; /* is supposed to be there */
                BodyPoint  *bp;
  
                if (do_springcollision || do_aero)  scan_for_ext_spring_forces(scene, ob, timenow);
                /* after spring scan because it uses Effoctors too */
 -              do_effector= pdInitEffectors(scene, ob, NULL, ob->soft->effector_weights, true);
 +              do_effector= pdInitEffectors(scene, ob, ob->soft->effector_weights, true);
  
                if (do_deflector) {
                        float defforce[3];
@@@ -3273,6 -3273,8 +3273,6 @@@ SoftBody *sbNew(Scene *scene
        sb->shearstiff = 1.0f;
        sb->solverflags |= SBSO_OLDERR;
  
 -      sb->pointcache = BKE_ptcache_add(&sb->ptcaches);
 -
        if (!sb->effector_weights)
                sb->effector_weights = BKE_add_effector_weights(NULL);
  
  void sbFree(SoftBody *sb)
  {
        free_softbody_intern(sb);
 -      BKE_ptcache_free_list(&sb->ptcaches);
 -      sb->pointcache = NULL;
        if (sb->effector_weights)
                MEM_freeN(sb->effector_weights);
        MEM_freeN(sb);
@@@ -3591,19 -3595,30 +3591,19 @@@ static void softbody_step(Scene *scene
  void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], int numVerts)
  {
        SoftBody *sb= ob->soft;
 -      PointCache *cache;
 -      PTCacheID pid;
 -      float dtime, timescale;
 -      int framedelta, framenr, startframe, endframe;
 -      int cache_result;
 -
 -      cache= sb->pointcache;
 -
 -      framenr= (int)cfra;
 -      framedelta= framenr - cache->simframe;
 +      float dtime, timescale = 1.0f;
 +      int framedelta, framenr = (int)cfra, startframe = scene->r.sfra, endframe = scene->r.efra;
  
 -      BKE_ptcache_id_from_softbody(&pid, ob, sb);
 -      BKE_ptcache_id_time(&pid, scene, framenr, &startframe, &endframe, &timescale);
 +      framedelta = 1;
  
        /* check for changes in mesh, should only happen in case the mesh
         * structure changes during an animation */
        if (sb->bpoint && numVerts != sb->totpoint) {
 -              BKE_ptcache_invalidate(cache);
                return;
        }
  
        /* clamp frame ranges */
        if (framenr < startframe) {
 -              BKE_ptcache_invalidate(cache);
                return;
        }
        else if (framenr > endframe) {
                return;
        }
        if (framenr == startframe) {
 -              BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
 -
                /* first frame, no simulation to do, just set the positions */
                softbody_update_positions(ob, sb, vertexCos, numVerts);
  
 -              BKE_ptcache_validate(cache, framenr);
 -              cache->flag &= ~PTCACHE_REDO_NEEDED;
 -
                sb->last_frame = framenr;
  
                return;
        }
  
 -      /* try to read from cache */
 -      cache_result = BKE_ptcache_read(&pid, (float)framenr+scene->r.subframe);
 -
 -      if (cache_result == PTCACHE_READ_EXACT || cache_result == PTCACHE_READ_INTERPOLATED) {
 -              softbody_to_object(ob, vertexCos, numVerts, sb->local);
 -
 -              BKE_ptcache_validate(cache, framenr);
 -
 -              if (cache_result == PTCACHE_READ_INTERPOLATED && cache->flag & PTCACHE_REDO_NEEDED)
 -                      BKE_ptcache_write(&pid, framenr);
 -
 -              sb->last_frame = framenr;
 -
 -              return;
 -      }
 -      else if (cache_result==PTCACHE_READ_OLD) {
 -              ; /* do nothing */
 -      }
 -      else if (/*ob->id.lib || */(cache->flag & PTCACHE_BAKED)) { /* "library linking & pointcaches" has to be solved properly at some point */
 -              /* if baked and nothing in cache, do nothing */
 -              BKE_ptcache_invalidate(cache);
 -              return;
 -      }
 -
        if (framenr!=sb->last_frame+1)
                return;
  
 -      /* if on second frame, write cache for first frame */
 -      if (cache->simframe == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact==0))
 -              BKE_ptcache_write(&pid, startframe);
 -
        softbody_update_positions(ob, sb, vertexCos, numVerts);
  
        /* checking time: */
  
        softbody_to_object(ob, vertexCos, numVerts, 0);
  
 -      BKE_ptcache_validate(cache, framenr);
 -      BKE_ptcache_write(&pid, framenr);
 -
        sb->last_frame = framenr;
  }
  
index 3e4f13a2c8f3a906f845fd04fc6b633b900f4401,e34d632f2caa2c7a00f4665ce0e96c7df3d8abb7..dcd60aaa7029414a3d0d6f81ffd201206281d21f
@@@ -50,6 -50,7 +50,6 @@@
  #include "DNA_brush_types.h"
  #include "DNA_node_types.h"
  #include "DNA_color_types.h"
 -#include "DNA_particle_types.h"
  #include "DNA_linestyle_types.h"
  
  #include "IMB_imbuf.h"
@@@ -58,6 -59,8 +58,8 @@@
  #include "BKE_main.h"
  
  #include "BKE_library.h"
+ #include "BKE_library_query.h"
+ #include "BKE_library_remap.h"
  #include "BKE_image.h"
  #include "BKE_material.h"
  #include "BKE_texture.h"
@@@ -843,11 -846,11 +845,11 @@@ MTex *BKE_texture_mtex_add_id(ID *id, i
  
  /* ------------------------------------------------------------------------- */
  
- Tex *BKE_texture_copy(Tex *tex)
+ Tex *BKE_texture_copy(Main *bmain, Tex *tex)
  {
        Tex *texn;
        
-       texn = BKE_libblock_copy(&tex->id);
+       texn = BKE_libblock_copy(bmain, &tex->id);
        if (BKE_texture_is_image_user(tex)) {
                id_us_plus((ID *)texn->ima);
        }
                if (tex->nodetree->execdata) {
                        ntreeTexEndExecTree(tex->nodetree->execdata);
                }
-               texn->nodetree = ntreeCopyTree(tex->nodetree);
+               texn->nodetree = ntreeCopyTree(bmain, tex->nodetree);
        }
        
-       if (tex->id.lib) {
-               BKE_id_lib_local_paths(G.main, tex->id.lib, &texn->id);
+       texn->preview = BKE_previewimg_copy(tex->preview);
+       if (ID_IS_LINKED_DATABLOCK(tex)) {
+               BKE_id_expand_local(&texn->id);
+               BKE_id_lib_local_paths(bmain, tex->id.lib, &texn->id);
        }
  
        return texn;
@@@ -912,169 -918,32 +917,32 @@@ Tex *BKE_texture_localize(Tex *tex
  
  /* ------------------------------------------------------------------------- */
  
- static void extern_local_texture(Tex *tex)
- {
-       id_lib_extern((ID *)tex->ima);
- }
- void BKE_texture_make_local(Tex *tex)
+ void BKE_texture_make_local(Main *bmain, Tex *tex)
  {
-       Main *bmain = G.main;
-       Material *ma;
-       World *wrld;
-       Lamp *la;
-       Brush *br;
-       FreestyleLineStyle *ls;
-       int a;
        bool is_local = false, is_lib = false;
  
        /* - only lib users: do nothing
         * - only local users: set flag
         * - mixed: make copy
         */
-       
-       if (tex->id.lib == NULL) return;
  
-       if (tex->id.us == 1) {
-               id_clear_lib_data(bmain, &tex->id);
-               extern_local_texture(tex);
+       if (!ID_IS_LINKED_DATABLOCK(tex)) {
                return;
        }
-       
-       ma = bmain->mat.first;
-       while (ma) {
-               for (a = 0; a < MAX_MTEX; a++) {
-                       if (ma->mtex[a] && ma->mtex[a]->tex == tex) {
-                               if (ma->id.lib) is_lib = true;
-                               else is_local = true;
-                       }
-               }
-               ma = ma->id.next;
-       }
-       la = bmain->lamp.first;
-       while (la) {
-               for (a = 0; a < MAX_MTEX; a++) {
-                       if (la->mtex[a] && la->mtex[a]->tex == tex) {
-                               if (la->id.lib) is_lib = true;
-                               else is_local = true;
-                       }
-               }
-               la = la->id.next;
-       }
-       wrld = bmain->world.first;
-       while (wrld) {
-               for (a = 0; a < MAX_MTEX; a++) {
-                       if (wrld->mtex[a] && wrld->mtex[a]->tex == tex) {
-                               if (wrld->id.lib) is_lib = true;
-                               else is_local = true;
-                       }
-               }
-               wrld = wrld->id.next;
-       }
-       br = bmain->brush.first;
-       while (br) {
-               if (br->mtex.tex == tex) {
-                       if (br->id.lib) is_lib = true;
-                       else is_local = true;
-               }
-               if (br->mask_mtex.tex == tex) {
-                       if (br->id.lib) is_lib = true;
-                       else is_local = true;
-               }
-               br = br->id.next;
-       }
-       ls = bmain->linestyle.first;
-       while (ls) {
-               for (a = 0; a < MAX_MTEX; a++) {
-                       if (ls->mtex[a] && ls->mtex[a]->tex == tex) {
-                               if (ls->id.lib) is_lib = true;
-                               else is_local = true;
-                       }
-               }
-               ls = ls->id.next;
-       }
-       
-       if (is_local && is_lib == false) {
-               id_clear_lib_data(bmain, &tex->id);
-               extern_local_texture(tex);
-       }
-       else if (is_local && is_lib) {
-               Tex *tex_new = BKE_texture_copy(tex);
  
-               tex_new->id.us = 0;
+       BKE_library_ID_test_usages(bmain, tex, &is_local, &is_lib);
  
-               /* Remap paths of new ID using old library as base. */
-               BKE_id_lib_local_paths(bmain, tex->id.lib, &tex_new->id);
-               
-               ma = bmain->mat.first;
-               while (ma) {
-                       for (a = 0; a < MAX_MTEX; a++) {
-                               if (ma->mtex[a] && ma->mtex[a]->tex == tex) {
-                                       if (ma->id.lib == NULL) {
-                                               ma->mtex[a]->tex = tex_new;
-                                               id_us_plus(&tex_new->id);
-                                               id_us_min(&tex->id);
-                                       }
-                               }
-                       }
-                       ma = ma->id.next;
-               }
-               la = bmain->lamp.first;
-               while (la) {
-                       for (a = 0; a < MAX_MTEX; a++) {
-                               if (la->mtex[a] && la->mtex[a]->tex == tex) {
-                                       if (la->id.lib == NULL) {
-                                               la->mtex[a]->tex = tex_new;
-                                               id_us_plus(&tex_new->id);
-                                               id_us_min(&tex->id);
-                                       }
-                               }
-                       }
-                       la = la->id.next;
-               }
-               wrld = bmain->world.first;
-               while (wrld) {
-                       for (a = 0; a < MAX_MTEX; a++) {
-                               if (wrld->mtex[a] && wrld->mtex[a]->tex == tex) {
-                                       if (wrld->id.lib == NULL) {
-                                               wrld->mtex[a]->tex = tex_new;
-                                               id_us_plus(&tex_new->id);
-                                               id_us_min(&tex->id);
-                                       }
-                               }
-                       }
-                       wrld = wrld->id.next;
+       if (is_local) {
+               if (!is_lib) {
+                       id_clear_lib_data(bmain, &tex->id);
+                       BKE_id_expand_local(&tex->id);
                }
-               br = bmain->brush.first;
-               while (br) {
-                       if (br->mtex.tex == tex) {
-                               if (br->id.lib == NULL) {
-                                       br->mtex.tex = tex_new;
-                                       id_us_plus(&tex_new->id);
-                                       id_us_min(&tex->id);
-                               }
-                       }
-                       if (br->mask_mtex.tex == tex) {
-                               if (br->id.lib == NULL) {
-                                       br->mask_mtex.tex = tex_new;
-                                       id_us_plus(&tex_new->id);
-                                       id_us_min(&tex->id);
-                               }
-                       }
-                       br = br->id.next;
-               }
-               ls = bmain->linestyle.first;
-               while (ls) {
-                       for (a = 0; a < MAX_MTEX; a++) {
-                               if (ls->mtex[a] && ls->mtex[a]->tex == tex) {
-                                       if (ls->id.lib == NULL) {
-                                               ls->mtex[a]->tex = tex_new;
-                                               id_us_plus(&tex_new->id);
-                                               id_us_min(&tex->id);
-                                       }
-                               }
-                       }
-                       ls = ls->id.next;
+               else {
+                       Tex *tex_new = BKE_texture_copy(bmain, tex);
+                       tex_new->id.us = 0;
+                       BKE_libblock_remap(bmain, tex, tex_new, ID_REMAP_SKIP_INDIRECT_USAGE);
                }
        }
  }
@@@ -1225,6 -1094,10 +1093,6 @@@ bool give_active_mtex(ID *id, MTex ***m
                        *mtex_ar =       ((FreestyleLineStyle *)id)->mtex;
                        if (act) *act =  (((FreestyleLineStyle *)id)->texact);
                        break;
 -              case ID_PA:
 -                      *mtex_ar =       ((ParticleSettings *)id)->mtex;
 -                      if (act) *act =  (((ParticleSettings *)id)->texact);
 -                      break;
                default:
                        *mtex_ar = NULL;
                        if (act) *act =  0;
@@@ -1252,6 -1125,9 +1120,6 @@@ void set_active_mtex(ID *id, short act
                case ID_LS:
                        ((FreestyleLineStyle *)id)->texact = act;
                        break;
 -              case ID_PA:
 -                      ((ParticleSettings *)id)->texact = act;
 -                      break;
        }
  }
  
@@@ -1361,6 -1237,42 +1229,6 @@@ void set_current_brush_texture(Brush *b
        }
  }
  
 -Tex *give_current_particle_texture(ParticleSettings *part)
 -{
 -      MTex *mtex = NULL;
 -      Tex *tex = NULL;
 -      
 -      if (!part) return NULL;
 -      
 -      mtex = part->mtex[(int)(part->texact)];
 -      if (mtex) tex = mtex->tex;
 -      
 -      return tex;
 -}
 -
 -void set_current_particle_texture(ParticleSettings *part, Tex *newtex)
 -{
 -      int act = part->texact;
 -
 -      if (part->mtex[act] && part->mtex[act]->tex)
 -              id_us_min(&part->mtex[act]->tex->id);
 -
 -      if (newtex) {
 -              if (!part->mtex[act]) {
 -                      part->mtex[act] = BKE_texture_mtex_add();
 -                      part->mtex[act]->texco = TEXCO_ORCO;
 -                      part->mtex[act]->blendtype = MTEX_MUL;
 -              }
 -              
 -              part->mtex[act]->tex = newtex;
 -              id_us_plus(&newtex->id);
 -      }
 -      else if (part->mtex[act]) {
 -              MEM_freeN(part->mtex[act]);
 -              part->mtex[act] = NULL;
 -      }
 -}
 -
  /* ------------------------------------------------------------------------- */
  
  EnvMap *BKE_texture_envmap_add(void)
index 82a92d3f654c6bddb11d7a92d71f87d2b53dde6d,68cc060b0104df5867606ff0bebec1486a59b9e4..5d0de6526b697cc334ec66c6570a5a3378fc80a5
@@@ -80,9 -80,9 +80,9 @@@
  #include "DNA_nla_types.h"
  #include "DNA_node_types.h"
  #include "DNA_object_fluidsim.h" // NT
 +#include "DNA_object_force.h"
  #include "DNA_object_types.h"
  #include "DNA_packedFile_types.h"
 -#include "DNA_particle_types.h"
  #include "DNA_property_types.h"
  #include "DNA_rigidbody_types.h"
  #include "DNA_text_types.h"
  
  #include "BKE_action.h"
  #include "BKE_armature.h"
- #include "BKE_blender_version.h"
  #include "BKE_brush.h"
  #include "BKE_cloth.h"
  #include "BKE_constraint.h"
  #include "BKE_node.h" // for tree type defines
  #include "BKE_object.h"
  #include "BKE_paint.h"
 -#include "BKE_particle.h"
 -#include "BKE_pointcache.h"
  #include "BKE_report.h"
  #include "BKE_sca.h" // for init_actuator
  #include "BKE_scene.h"
@@@ -916,7 -917,7 +915,7 @@@ static int read_file_dna(FileData *fd
                if (bhead->code == DNA1) {
                        const bool do_endian_swap = (fd->flags & FD_FLAGS_SWITCH_ENDIAN) != 0;
                        
-                       fd->filesdna = DNA_sdna_from_data(&bhead[1], bhead->len, do_endian_swap);
+                       fd->filesdna = DNA_sdna_from_data(&bhead[1], bhead->len, do_endian_swap, true);
                        if (fd->filesdna) {
                                fd->compflags = DNA_struct_get_compareflags(fd->filesdna, fd->memsdna);
                                /* used to retrieve ID names from (bhead+1) */
@@@ -1076,7 -1077,7 +1075,7 @@@ static FileData *filedata_new(void
         * but it keeps us re-entrant,  remove once we have
         * a lib that provides a nice lock. - zr
         */
-       fd->memsdna = DNA_sdna_from_data(DNAstr, DNAlen, false);
+       fd->memsdna = DNA_sdna_from_data(DNAstr, DNAlen, false, false);
        
        fd->datamap = oldnewmap_new();
        fd->globmap = oldnewmap_new();
@@@ -3947,6 -3948,83 +3946,6 @@@ static void direct_link_material(FileDa
  }
  
  /* ************ READ PARTICLE SETTINGS ***************** */
 -/* update this also to writefile.c */
 -static const char *ptcache_data_struct[] = {
 -      "", // BPHYS_DATA_INDEX
 -      "", // BPHYS_DATA_LOCATION
 -      "", // BPHYS_DATA_VELOCITY
 -      "", // BPHYS_DATA_ROTATION
 -      "", // BPHYS_DATA_AVELOCITY / BPHYS_DATA_XCONST */
 -      "", // BPHYS_DATA_SIZE:
 -      "", // BPHYS_DATA_TIMES:
 -      "BoidData" // case BPHYS_DATA_BOIDS:
 -};
 -
 -static void direct_link_pointcache_cb(FileData *fd, void *data)
 -{
 -      PTCacheMem *pm = data;
 -      PTCacheExtra *extra;
 -      int i;
 -      for (i = 0; i < BPHYS_TOT_DATA; i++) {
 -              pm->data[i] = newdataadr(fd, pm->data[i]);
 -
 -              /* the cache saves non-struct data without DNA */
 -              if (pm->data[i] && ptcache_data_struct[i][0]=='\0' && (fd->flags & FD_FLAGS_SWITCH_ENDIAN)) {
 -                      int tot = (BKE_ptcache_data_size(i) * pm->totpoint) / sizeof(int);  /* data_size returns bytes */
 -                      int *poin = pm->data[i];
 -
 -                      BLI_endian_switch_int32_array(poin, tot);
 -              }
 -      }
 -
 -      link_list(fd, &pm->extradata);
 -
 -      for (extra=pm->extradata.first; extra; extra=extra->next)
 -              extra->data = newdataadr(fd, extra->data);
 -}
 -
 -static void direct_link_pointcache(FileData *fd, PointCache *cache)
 -{
 -      if ((cache->flag & PTCACHE_DISK_CACHE)==0) {
 -              link_list_ex(fd, &cache->mem_cache, direct_link_pointcache_cb);
 -      }
 -      else
 -              BLI_listbase_clear(&cache->mem_cache);
 -      
 -      cache->flag &= ~PTCACHE_SIMULATION_VALID;
 -      cache->simframe = 0;
 -      cache->edit = NULL;
 -      cache->free_edit = NULL;
 -      cache->cached_frames = NULL;
 -}
 -
 -static void direct_link_pointcache_list(FileData *fd, ListBase *ptcaches, PointCache **ocache, int force_disk)
 -{
 -      if (ptcaches->first) {
 -              PointCache *cache= NULL;
 -              link_list(fd, ptcaches);
 -              for (cache=ptcaches->first; cache; cache=cache->next) {
 -                      direct_link_pointcache(fd, cache);
 -                      if (force_disk) {
 -                              cache->flag |= PTCACHE_DISK_CACHE;
 -                              cache->step = 1;
 -                      }
 -              }
 -              
 -              *ocache = newdataadr(fd, *ocache);
 -      }
 -      else if (*ocache) {
 -              /* old "single" caches need to be linked too */
 -              *ocache = newdataadr(fd, *ocache);
 -              direct_link_pointcache(fd, *ocache);
 -              if (force_disk) {
 -                      (*ocache)->flag |= PTCACHE_DISK_CACHE;
 -                      (*ocache)->step = 1;
 -              }
 -              
 -              ptcaches->first = ptcaches->last = *ocache;
 -      }
 -}
  
  static void lib_link_partdeflect(FileData *fd, ID *id, PartDeflect *pd)
  {
                pd->f_source = newlibadr(fd, id->lib, pd->f_source);
  }
  
 -static void lib_link_particlesettings(FileData *fd, Main *main)
 -{
 -      ParticleSettings *part;
 -      ParticleDupliWeight *dw;
 -      MTex *mtex;
 -      int a;
 -      
 -      for (part = main->particle.first; part; part = part->id.next) {
 -              if (part->id.tag & LIB_TAG_NEED_LINK) {
 -                      lib_link_animdata(fd, &part->id, part->adt);
 -                      part->ipo = newlibadr_us(fd, part->id.lib, part->ipo); // XXX deprecated - old animation system
 -                      
 -                      part->dup_ob = newlibadr(fd, part->id.lib, part->dup_ob);
 -                      part->dup_group = newlibadr(fd, part->id.lib, part->dup_group);
 -                      part->eff_group = newlibadr(fd, part->id.lib, part->eff_group);
 -                      part->bb_ob = newlibadr(fd, part->id.lib, part->bb_ob);
 -                      
 -                      lib_link_partdeflect(fd, &part->id, part->pd);
 -                      lib_link_partdeflect(fd, &part->id, part->pd2);
 -                      
 -                      if (part->effector_weights) {
 -                              part->effector_weights->group = newlibadr(fd, part->id.lib, part->effector_weights->group);
 -                      }
 -                      else {
 -                              part->effector_weights = BKE_add_effector_weights(part->eff_group);
 -                      }
 -
 -                      if (part->dupliweights.first && part->dup_group) {
 -                              int index_ok = 0;
 -                              /* check for old files without indices (all indexes 0) */
 -                              if (BLI_listbase_is_single(&part->dupliweights)) {
 -                                      /* special case for only one object in the group */
 -                                      index_ok = 1;
 -                              }
 -                              else {
 -                                      for (dw = part->dupliweights.first; dw; dw = dw->next) {
 -                                              if (dw->index > 0) {
 -                                                      index_ok = 1;
 -                                                      break;
 -                                              }
 -                                      }
 -                              }
 -
 -                              if (index_ok) {
 -                                      /* if we have indexes, let's use them */
 -                                      for (dw = part->dupliweights.first; dw; dw = dw->next) {
 -                                              GroupObject *go = (GroupObject *)BLI_findlink(&part->dup_group->gobject, dw->index);
 -                                              dw->ob = go ? go->ob : NULL;
 -                                      }
 -                              }
 -                              else {
 -                                      /* otherwise try to get objects from own library (won't work on library linked groups) */
 -                                      for (dw = part->dupliweights.first; dw; dw = dw->next) {
 -                                              dw->ob = newlibadr(fd, part->id.lib, dw->ob);
 -                                      }
 -                              }
 -                      }
 -                      else {
 -                              BLI_listbase_clear(&part->dupliweights);
 -                      }
 -                      
 -                      if (part->boids) {
 -                              BoidState *state = part->boids->states.first;
 -                              BoidRule *rule;
 -                              for (; state; state=state->next) {
 -                                      rule = state->rules.first;
 -                                      for (; rule; rule=rule->next) {
 -                                              switch (rule->type) {
 -                                                      case eBoidRuleType_Goal:
 -                                                      case eBoidRuleType_Avoid:
 -                                                      {
 -                                                              BoidRuleGoalAvoid *brga = (BoidRuleGoalAvoid*)rule;
 -                                                              brga->ob = newlibadr(fd, part->id.lib, brga->ob);
 -                                                              break;
 -                                                      }
 -                                                      case eBoidRuleType_FollowLeader:
 -                                                      {
 -                                                              BoidRuleFollowLeader *brfl = (BoidRuleFollowLeader*)rule;
 -                                                              brfl->ob = newlibadr(fd, part->id.lib, brfl->ob);
 -                                                              break;
 -                                                      }
 -                                              }
 -                                      }
 -                              }
 -                      }
 -
 -                      for (a = 0; a < MAX_MTEX; a++) {
 -                              mtex= part->mtex[a];
 -                              if (mtex) {
 -                                      mtex->tex = newlibadr_us(fd, part->id.lib, mtex->tex);
 -                                      mtex->object = newlibadr(fd, part->id.lib, mtex->object);
 -                              }
 -                      }
 -                      
 -                      part->id.tag &= ~LIB_TAG_NEED_LINK;
 -              }
 -      }
 -}
 -
  static void direct_link_partdeflect(PartDeflect *pd)
  {
        if (pd) pd->rng = NULL;
  }
  
 -static void direct_link_particlesettings(FileData *fd, ParticleSettings *part)
 -{
 -      int a;
 -      
 -      part->adt = newdataadr(fd, part->adt);
 -      part->pd = newdataadr(fd, part->pd);
 -      part->pd2 = newdataadr(fd, part->pd2);
 -
 -      direct_link_animdata(fd, part->adt);
 -      direct_link_partdeflect(part->pd);
 -      direct_link_partdeflect(part->pd2);
 -
 -      part->clumpcurve = newdataadr(fd, part->clumpcurve);
 -      if (part->clumpcurve)
 -              direct_link_curvemapping(fd, part->clumpcurve);
 -      part->roughcurve = newdataadr(fd, part->roughcurve);
 -      if (part->roughcurve)
 -              direct_link_curvemapping(fd, part->roughcurve);
 -
 -      part->effector_weights = newdataadr(fd, part->effector_weights);
 -      if (!part->effector_weights)
 -              part->effector_weights = BKE_add_effector_weights(part->eff_group);
 -
 -      link_list(fd, &part->dupliweights);
 -
 -      part->boids = newdataadr(fd, part->boids);
 -      part->fluid = newdataadr(fd, part->fluid);
 -
 -      if (part->boids) {
 -              BoidState *state;
 -              link_list(fd, &part->boids->states);
 -              
 -              for (state=part->boids->states.first; state; state=state->next) {
 -                      link_list(fd, &state->rules);
 -                      link_list(fd, &state->conditions);
 -                      link_list(fd, &state->actions);
 -              }
 -      }
 -      for (a = 0; a < MAX_MTEX; a++) {
 -              part->mtex[a] = newdataadr(fd, part->mtex[a]);
 -      }
 -}
 -
 -static void lib_link_particlesystems(FileData *fd, Object *ob, ID *id, ListBase *particles)
 -{
 -      ParticleSystem *psys, *psysnext;
 -
 -      for (psys=particles->first; psys; psys=psysnext) {
 -              psysnext = psys->next;
 -              
 -              psys->part = newlibadr_us(fd, id->lib, psys->part);
 -              if (psys->part) {
 -                      ParticleTarget *pt = psys->targets.first;
 -                      
 -                      for (; pt; pt=pt->next)
 -                              pt->ob=newlibadr(fd, id->lib, pt->ob);
 -                      
 -                      psys->parent = newlibadr(fd, id->lib, psys->parent);
 -                      psys->target_ob = newlibadr(fd, id->lib, psys->target_ob);
 -                      
 -                      if (psys->clmd) {
 -                              /* XXX - from reading existing code this seems correct but intended usage of
 -                               * pointcache /w cloth should be added in 'ParticleSystem' - campbell */
 -                              psys->clmd->point_cache = psys->pointcache;
 -                              psys->clmd->ptcaches.first = psys->clmd->ptcaches.last= NULL;
 -                              psys->clmd->coll_parms->group = newlibadr(fd, id->lib, psys->clmd->coll_parms->group);
 -                              psys->clmd->modifier.error = NULL;
 -                      }
 -              }
 -              else {
 -                      /* particle modifier must be removed before particle system */
 -                      ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
 -                      BLI_remlink(&ob->modifiers, psmd);
 -                      modifier_free((ModifierData *)psmd);
 -                      
 -                      BLI_remlink(particles, psys);
 -                      MEM_freeN(psys);
 -              }
 -      }
 -}
 -static void direct_link_particlesystems(FileData *fd, ListBase *particles)
 -{
 -      ParticleSystem *psys;
 -      ParticleData *pa;
 -      int a;
 -      
 -      for (psys=particles->first; psys; psys=psys->next) {
 -              psys->particles=newdataadr(fd, psys->particles);
 -              
 -              if (psys->particles && psys->particles->hair) {
 -                      for (a=0, pa=psys->particles; a<psys->totpart; a++, pa++)
 -                              pa->hair=newdataadr(fd, pa->hair);
 -              }
 -              
 -              if (psys->particles && psys->particles->keys) {
 -                      for (a=0, pa=psys->particles; a<psys->totpart; a++, pa++) {
 -                              pa->keys= NULL;
 -                              pa->totkey= 0;
 -                      }
 -                      
 -                      psys->flag &= ~PSYS_KEYED;
 -              }
 -              
 -              if (psys->particles && psys->particles->boid) {
 -                      pa = psys->particles;
 -                      pa->boid = newdataadr(fd, pa->boid);
 -                      for (a=1, pa++; a<psys->totpart; a++, pa++)
 -                              pa->boid = (pa-1)->boid + 1;
 -              }
 -              else if (psys->particles) {
 -                      for (a=0, pa=psys->particles; a<psys->totpart; a++, pa++)
 -                              pa->boid = NULL;
 -              }
 -              
 -              psys->fluid_springs = newdataadr(fd, psys->fluid_springs);
 -              
 -              psys->child = newdataadr(fd, psys->child);
 -              psys->effectors = NULL;
 -              
 -              link_list(fd, &psys->targets);
 -              
 -              psys->edit = NULL;
 -              psys->free_edit = NULL;
 -              psys->pathcache = NULL;
 -              psys->childcache = NULL;
 -              BLI_listbase_clear(&psys->pathcachebufs);
 -              BLI_listbase_clear(&psys->childcachebufs);
 -              psys->pdd = NULL;
 -              psys->renderdata = NULL;
 -              
 -              if (psys->clmd) {
 -                      psys->clmd = newdataadr(fd, psys->clmd);
 -                      psys->clmd->clothObject = NULL;
 -                      psys->clmd->hairdata = NULL;
 -                      
 -                      psys->clmd->sim_parms= newdataadr(fd, psys->clmd->sim_parms);
 -                      psys->clmd->coll_parms= newdataadr(fd, psys->clmd->coll_parms);
 -                      
 -                      if (psys->clmd->sim_parms) {
 -                              psys->clmd->sim_parms->effector_weights = NULL;
 -                              if (psys->clmd->sim_parms->presets > 10)
 -                                      psys->clmd->sim_parms->presets = 0;
 -                      }
 -                      
 -                      psys->hair_in_dm = psys->hair_out_dm = NULL;
 -                      psys->clmd->solver_result = NULL;
 -              }
 -
 -              direct_link_pointcache_list(fd, &psys->ptcaches, &psys->pointcache, 0);
 -              if (psys->clmd) {
 -                      psys->clmd->point_cache = psys->pointcache;
 -              }
 -
 -              psys->tree = NULL;
 -              psys->bvhtree = NULL;
 -      }
 -      return;
 -}
 -
  /* ************ READ MESH ***************** */
  
  static void lib_link_mtface(FileData *fd, Mesh *me, MTFace *mtface, int totface)
@@@ -4568,6 -4904,7 +4567,6 @@@ static void lib_link_object(FileData *f
                        if (ob->soft)
                                ob->soft->effector_weights->group = newlibadr(fd, ob->id.lib, ob->soft->effector_weights->group);
                        
 -                      lib_link_particlesystems(fd, ob, &ob->id, &ob->particlesystem);
                        lib_link_modifiers(fd, ob);
  
                        if (ob->rigidbody_constraint) {
@@@ -4668,6 -5005,8 +4667,6 @@@ static void direct_link_modifiers(FileD
                        clmd->sim_parms= newdataadr(fd, clmd->sim_parms);
                        clmd->coll_parms= newdataadr(fd, clmd->coll_parms);
                        
 -                      direct_link_pointcache_list(fd, &clmd->ptcaches, &clmd->point_cache, 0);
 -                      
                        if (clmd->sim_parms) {
                                if (clmd->sim_parms->presets > 10)
                                        clmd->sim_parms->presets = 0;
                                smd->domain->effector_weights = newdataadr(fd, smd->domain->effector_weights);
                                if (!smd->domain->effector_weights)
                                        smd->domain->effector_weights = BKE_add_effector_weights(NULL);
 -                              
 -                              direct_link_pointcache_list(fd, &(smd->domain->ptcaches[0]), &(smd->domain->point_cache[0]), 1);
 -                              
 -                              /* Smoke uses only one cache from now on, so store pointer convert */
 -                              if (smd->domain->ptcaches[1].first || smd->domain->point_cache[1]) {
 -                                      if (smd->domain->point_cache[1]) {
 -                                              PointCache *cache = newdataadr(fd, smd->domain->point_cache[1]);
 -                                              if (cache->flag & PTCACHE_FAKE_SMOKE) {
 -                                                      /* Smoke was already saved in "new format" and this cache is a fake one. */
 -                                              }
 -                                              else {
 -                                                      printf("High resolution smoke cache not available due to pointcache update. Please reset the simulation.\n");
 -                                              }
 -                                              BKE_ptcache_free(cache);
 -                                      }
 -                                      BLI_listbase_clear(&smd->domain->ptcaches[1]);
 -                                      smd->domain->point_cache[1] = NULL;
 -                              }
                        }
                        else if (smd->type == MOD_SMOKE_TYPE_FLOW) {
                                smd->domain = NULL;
                                smd->flow->dm = NULL;
                                smd->flow->verts_old = NULL;
                                smd->flow->numverts = 0;
 -                              smd->flow->psys = newdataadr(fd, smd->flow->psys);
                        }
                        else if (smd->type == MOD_SMOKE_TYPE_COLL) {
                                smd->flow = NULL;
                                        for (surface=pmd->canvas->surfaces.first; surface; surface=surface->next) {
                                                surface->canvas = pmd->canvas;
                                                surface->data = NULL;
 -                                              direct_link_pointcache_list(fd, &(surface->ptcaches), &(surface->pointcache), 1);
                                                
                                                if (!(surface->effector_weights = newdataadr(fd, surface->effector_weights)))
                                                        surface->effector_weights = BKE_add_effector_weights(NULL);
                        if (pmd->brush) {
                                pmd->brush = newdataadr(fd, pmd->brush);
                                pmd->brush->pmd = pmd;
 -                              pmd->brush->psys = newdataadr(fd, pmd->brush->psys);
                                pmd->brush->paint_ramp = newdataadr(fd, pmd->brush->paint_ramp);
                                pmd->brush->vel_ramp = newdataadr(fd, pmd->brush->vel_ramp);
                                pmd->brush->dm = NULL;
                                direct_link_curvemapping(fd, hmd->curfalloff);
                        }
                }
 -              else if (md->type == eModifierType_ParticleSystem) {
 -                      ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md;
 -                      
 -                      psmd->dm_final = NULL;
 -                      psmd->dm_deformed = NULL;
 -                      psmd->psys= newdataadr(fd, psmd->psys);
 -                      psmd->flag &= ~eParticleSystemFlag_psys_updated;
 -                      psmd->flag |= eParticleSystemFlag_file_loaded;
 -              }
                else if (md->type == eModifierType_Explode) {
                        ExplodeModifierData *psmd = (ExplodeModifierData *)md;
                        
@@@ -4913,7 -5282,7 +4912,7 @@@ static void direct_link_object(FileDat
         * See [#34776, #42780] for more information.
         */
        if (fd->memfile || (ob->id.tag & (LIB_TAG_EXTERN | LIB_TAG_INDIRECT))) {
 -              ob->mode &= ~(OB_MODE_EDIT | OB_MODE_PARTICLE_EDIT);
 +              ob->mode &= ~OB_MODE_EDIT;
                if (!fd->memfile) {
                        ob->mode &= ~OB_MODE_POSE;
                }
                sb->effector_weights = newdataadr(fd, sb->effector_weights);
                if (!sb->effector_weights)
                        sb->effector_weights = BKE_add_effector_weights(NULL);
 -              
 -              direct_link_pointcache_list(fd, &sb->ptcaches, &sb->pointcache, 0);
        }
        ob->bsoft = newdataadr(fd, ob->bsoft);
        ob->fluidsimSettings= newdataadr(fd, ob->fluidsimSettings); /* NT */
        ob->rigidbody_constraint = newdataadr(fd, ob->rigidbody_constraint);
        if (ob->rigidbody_constraint)
                ob->rigidbody_constraint->physics_constraint = NULL;
 -
 -      link_list(fd, &ob->particlesystem);
 -      direct_link_particlesystems(fd, &ob->particlesystem);
        
        link_list(fd, &ob->prop);
        for (prop = ob->prop.first; prop; prop = prop->next) {
@@@ -5244,6 -5618,8 +5243,6 @@@ static void lib_link_scene(FileData *fd
                        
                        sce->toolsettings->skgen_template = newlibadr(fd, sce->id.lib, sce->toolsettings->skgen_template);
                        
 -                      sce->toolsettings->particle.shape_object = newlibadr(fd, sce->id.lib, sce->toolsettings->particle.shape_object);
 -                      
                        for (base = sce->base.first; base; base = next) {
                                next = base->next;
                                
@@@ -5488,6 -5864,9 +5487,6 @@@ static void direct_link_scene(FileData 
                direct_link_paint(fd, &sce->toolsettings->imapaint.paint);
  
                sce->toolsettings->imapaint.paintcursor = NULL;
 -              sce->toolsettings->particle.paintcursor = NULL;
 -              sce->toolsettings->particle.scene = NULL;
 -              sce->toolsettings->particle.object = NULL;
                sce->toolsettings->gp_sculpt.paintcursor = NULL;
  
                /* in rare cases this is needed, see [#33806] */
                rbw->effector_weights = newdataadr(fd, rbw->effector_weights);
                if (!rbw->effector_weights)
                        rbw->effector_weights = BKE_add_effector_weights(NULL);
 -
 -              /* link cache */
 -              direct_link_pointcache_list(fd, &rbw->ptcaches, &rbw->pointcache, false);
 -              /* make sure simulation starts from the beginning after loading file */
 -              if (rbw->pointcache) {
 -                      rbw->ltime = (float)rbw->pointcache->startframe;
 -              }
        }
  
        sce->preview = direct_link_preview_image(fd, sce->preview);
@@@ -7502,6 -7888,7 +7501,6 @@@ static const char *dataname(short id_co
                case ID_SO: return "Data from SO";
                case ID_NT: return "Data from NT";
                case ID_BR: return "Data from BR";
 -              case ID_PA: return "Data from PA";
                case ID_PAL: return "Data from PAL";
                case ID_PC: return "Data from PCRV";
                case ID_GD: return "Data from GD";
@@@ -7739,6 -8126,9 +7738,6 @@@ static BHead *read_libblock(FileData *f
                case ID_BR:
                        direct_link_brush(fd, (Brush*)id);
                        break;
 -              case ID_PA:
 -                      direct_link_particlesettings(fd, (ParticleSettings*)id);
 -                      break;
                case ID_GD:
                        direct_link_gpencil(fd, (bGPdata *)id);
                        break;
@@@ -7896,9 -8286,6 +7895,6 @@@ static void do_versions(FileData *fd, L
        blo_do_versions_260(fd, lib, main);
        blo_do_versions_270(fd, lib, main);
  
-       main->versionfile = BLENDER_VERSION;
-       main->subversionfile = BLENDER_SUBVERSION;
        /* WATCH IT!!!: pointers from libdata have not been converted yet here! */
        /* WATCH IT 2!: Userdef struct init see do_versions_userdef() above! */
  
@@@ -7948,6 -8335,7 +7944,6 @@@ static void lib_link_all(FileData *fd, 
        lib_link_brush(fd, main);
        lib_link_palette(fd, main);
        lib_link_paint_curve(fd, main);
 -      lib_link_particlesettings(fd, main);
        lib_link_movieclip(fd, main);
        lib_link_mask(fd, main);
        lib_link_linestyle(fd, main);
@@@ -8455,6 -8843,26 +8451,6 @@@ static void expand_animdata(FileData *f
                expand_animdata_nlastrips(fd, mainvar, &nlt->strips);
  }     
  
 -static void expand_particlesettings(FileData *fd, Main *mainvar, ParticleSettings *part)
 -{
 -      int a;
 -      
 -      expand_doit(fd, mainvar, part->dup_ob);
 -      expand_doit(fd, mainvar, part->dup_group);
 -      expand_doit(fd, mainvar, part->eff_group);
 -      expand_doit(fd, mainvar, part->bb_ob);
 -      
 -      if (part->adt)
 -              expand_animdata(fd, mainvar, part->adt);
 -      
 -      for (a = 0; a < MAX_MTEX; a++) {
 -              if (part->mtex[a]) {
 -                      expand_doit(fd, mainvar, part->mtex[a]->tex);
 -                      expand_doit(fd, mainvar, part->mtex[a]->object);
 -              }
 -      }
 -}
 -
  static void expand_group(FileData *fd, Main *mainvar, Group *group)
  {
        GroupObject *go;
@@@ -8757,6 -9165,7 +8753,6 @@@ static void expand_object_expandModifie
  
  static void expand_object(FileData *fd, Main *mainvar, Object *ob)
  {
 -      ParticleSystem *psys;
        bSensor *sens;
        bController *cont;
        bActuator *act;
        if (ob->proxy_group)
                expand_doit(fd, mainvar, ob->proxy_group);
        
 -      for (psys = ob->particlesystem.first; psys; psys = psys->next)
 -              expand_doit(fd, mainvar, psys->part);
 -      
        for (sens = ob->sensors.first; sens; sens = sens->next) {
                if (sens->type == SENS_MESSAGE) {
                        bMessageSensor *ms = sens->data;
@@@ -9172,6 -9584,9 +9168,6 @@@ void BLO_expand_main(void *fdhandle, Ma
                                        case ID_IP:
                                                expand_ipo(fd, mainvar, (Ipo *)id); // XXX deprecated - old animation system
                                                break;
 -                                      case ID_PA:
 -                                              expand_particlesettings(fd, mainvar, (ParticleSettings *)id);
 -                                              break;
                                        case ID_MC:
                                                expand_movieclip(fd, mainvar, (MovieClip *)id);
                                                break;
index 119754fe56791f37a203d50ebdac6ac9f424ce85,1956a17d57bb21d5c369accd1653a539c345ccb8..631aec545c2263b2bd9434883a65849575bde955
@@@ -53,7 -53,6 +53,7 @@@
  #include "DNA_meshdata_types.h"
  #include "DNA_node_types.h"
  #include "DNA_object_fluidsim.h" // NT
 +#include "DNA_object_force.h"
  #include "DNA_object_types.h"
  #include "DNA_view3d_types.h"
  #include "DNA_screen_types.h"
@@@ -79,6 -78,8 +79,6 @@@
  #include "BKE_mesh.h" // for ME_ defines (patching)
  #include "BKE_modifier.h"
  #include "BKE_multires.h"
 -#include "BKE_particle.h"
 -#include "BKE_pointcache.h"
  #include "BKE_screen.h"
  #include "BKE_sequencer.h"
  #include "BKE_texture.h"
@@@ -742,6 -743,7 +742,6 @@@ void blo_do_versions_250(FileData *fd, 
                Curve *cu;
                Scene *sce;
                Tex *tx;
 -              ParticleSettings *part;
                Object *ob;
                //PTCacheID *pid;
                //ListBase pidlist;
                        me->drawflag = ME_DRAWEDGES|ME_DRAWFACES|ME_DRAWCREASES;
                }
  
 -              /* particle draw and render types */
 -              for (part = main->particle.first; part; part = part->id.next) {
 -                      if (part->draw_as) {
 -                              if (part->draw_as == PART_DRAW_DOT) {
 -                                      part->ren_as = PART_DRAW_HALO;
 -                                      part->draw_as = PART_DRAW_REND;
 -                              }
 -                              else if (part->draw_as <= PART_DRAW_AXIS) {
 -                                      part->ren_as = PART_DRAW_HALO;
 -                              }
 -                              else {
 -                                      part->ren_as = part->draw_as;
 -                                      part->draw_as = PART_DRAW_REND;
 -                              }
 -                      }
 -                      part->path_end = 1.0f;
 -                      part->clength = 1.0f;
 -              }
 -
                /* set old pointcaches to have disk cache flag */
                for (ob = main->object.first; ob; ob = ob->id.next) {
  
                                sce->gm.flag |= GAME_GLSL_NO_NODES;
                        if (fd->fileflags & G_FILE_GLSL_NO_EXTRA_TEX)
                                sce->gm.flag |= GAME_GLSL_NO_EXTRA_TEX;
+                       if (fd->fileflags & G_FILE_GLSL_NO_ENV_LIGHTING)
+                               sce->gm.flag |= GAME_GLSL_NO_ENV_LIGHTING;
                        if (fd->fileflags & G_FILE_IGNORE_DEPRECATION_WARNINGS)
                                sce->gm.flag |= GAME_IGNORE_DEPRECATION_WARNINGS;
  
                Lamp *la;
                World *wo;
                Tex *tex;
 -              ParticleSettings *part;
                bool do_gravity = false;
  
                for (sce = main->scene.first; sce; sce = sce->id.next)
                        }
                }
  
 -              /* Assign proper global gravity weights for dynamics (only z-coordinate is taken into account) */
 -              if (do_gravity) {
 -                      for (part = main->particle.first; part; part = part->id.next)
 -                              part->effector_weights->global_gravity = part->acc[2]/-9.81f;
 -              }
 -
                for (ob = main->object.first; ob; ob = ob->id.next) {
                        ModifierData *md;
  
        }
  
        if (main->versionfile < 250 || (main->versionfile == 250 && main->subversionfile < 9)) {
 -              Scene *sce;
                Mesh *me;
                Object *ob;
  
 -              for (sce = main->scene.first; sce; sce = sce->id.next)
 -                      if (!sce->toolsettings->particle.selectmode)
 -                              sce->toolsettings->particle.selectmode = SCE_SELECT_PATH;
 -
                if (main->versionfile == 250 && main->subversionfile > 1) {
                        for (me = main->mesh.first; me; me = me->id.next)
                                multires_load_old_250(me);
                        SEQ_END
                }
  
 -              /* particle brush strength factor was changed from int to float */
 -              for (sce = main->scene.first; sce; sce = sce->id.next) {
 -                      ParticleEditSettings *pset = &sce->toolsettings->particle;
 -                      int a;
 -
 -                      for (a = 0; a < PE_TOT_BRUSH; a++)
 -                              pset->brush[a].strength /= 100.0f;
 -              }
 -
                for (ma = main->mat.first; ma; ma = ma->id.next)
                        if (ma->mode & MA_TRACEBLE)
                                ma->shade_flag |= MA_APPROX_OCCLUSION;
  
        if (main->versionfile < 255 || (main->versionfile == 255 && main->subversionfile < 1)) {
                Brush *br;
 -              ParticleSettings *part;
                bScreen *sc;
                Object *ob;
  
                                br->ob_mode = OB_MODE_ALL_PAINT;
                }
  
 -              for (part = main->particle.first; part; part = part->id.next) {
 -                      if (part->boids)
 -                              part->boids->pitch = 1.0f;
 -
 -                      part->flag &= ~PART_HAIR_REGROW; /* this was a deprecated flag before */
 -                      part->kink_amp_clump = 1.f; /* keep old files looking similar */
 -              }
 -
                for (sc = main->screen.first; sc; sc = sc->id.next) {
                        ScrArea *sa;
                        for (sa = sc->areabase.first; sa; sa = sa->next) {
                bScreen *sc;
                Brush *brush;
                Object *ob;
 -              ParticleSettings *part;
                Material *mat;
                int tex_nr, transp_tex;
  
                                }
                        }
                }
 -
 -              /* particle draw color from material */
 -              for (part = main->particle.first; part; part = part->id.next) {
 -                      if (part->draw & PART_DRAW_MAT_COL)
 -                              part->draw_col = PART_DRAW_COL_MAT;
 -              }
        }
  
        if (main->versionfile < 256 || (main->versionfile == 256 && main->subversionfile < 6)) {
                                }
                        }
                }
 -
 -              {
 -                      ParticleSettings *part;
 -                      for (part = main->particle.first; part; part = part->id.next) {
 -                              /* Initialize particle billboard scale */
 -                              part->bb_size[0] = part->bb_size[1] = 1.0f;
 -                      }
 -              }
        }
  
        if (main->versionfile < 259 || (main->versionfile == 259 && main->subversionfile < 1)) {
        }
  
        if (main->versionfile < 259 || (main->versionfile == 259 && main->subversionfile < 4)) {
 -              {
 -                      /* Adaptive time step for particle systems */
 -                      ParticleSettings *part;
 -                      for (part = main->particle.first; part; part = part->id.next) {
 -                              part->courant_target = 0.2f;
 -                              part->time_flag &= ~PART_TIME_AUTOSF;
 -                      }
 -              }
 -
                {
                        /* set defaults for obstacle avoidance, recast data */
                        Scene *sce;
index 87fe6db96d0b2ed55ce817ea3139c0061f9c6cf6,bd19f2aeb748364103e5954e70274ffee33a0334..9c7aa87f3ccef7e43f83a76779b32fb1d4c699e3
  #include "DNA_object_types.h"
  #include "DNA_object_force.h"
  #include "DNA_packedFile_types.h"
 -#include "DNA_particle_types.h"
  #include "DNA_property_types.h"
  #include "DNA_rigidbody_types.h"
  #include "DNA_scene_types.h"
  #include "BKE_subsurf.h"
  #include "BKE_modifier.h"
  #include "BKE_fcurve.h"
 -#include "BKE_pointcache.h"
  #include "BKE_mesh.h"
  
  #ifdef USE_NODE_COMPAT_CUSTOMNODES
  
  /* ********* my write, buffered writing with minimum size chunks ************ */
  
- #define MYWRITE_BUFFER_SIZE   100000
- #define MYWRITE_MAX_CHUNK     32768
+ /* Use optimal allocation since blocks of this size are kept in memory for undo. */
+ #define MYWRITE_BUFFER_SIZE (MEM_SIZE_OPTIMAL(1 << 17))  /* 128kb */
+ #define MYWRITE_MAX_CHUNK   (MEM_SIZE_OPTIMAL(1 << 15))  /* ~32kb */
  
  
  /** \name Small API to handle compression.
@@@ -323,7 -325,7 +323,7 @@@ static WriteData *writedata_new(WriteWr
  {
        WriteData *wd = MEM_callocN(sizeof(*wd), "writedata");
  
-       wd->sdna = DNA_sdna_from_data(DNAstr, DNAlen, false);
+       wd->sdna = DNA_sdna_from_data(DNAstr, DNAlen, false, false);
  
        wd->ww = ww;
  
@@@ -363,27 -365,32 +363,32 @@@ static void writedata_free(WriteData *w
  
  /***/
  
+ /**
+  * Flush helps the de-duplicating memory for undo-save by logically segmenting data,
+  * so differences in one part of memory won't cause unrelated data to be duplicated.
+  */
+ static void mywrite_flush(WriteData *wd)
+ {
+       if (wd->count) {
+               writedata_do_write(wd, wd->buf, wd->count);
+               wd->count = 0;
+       }
+ }
  /**
   * Low level WRITE(2) wrapper that buffers data
   * \param adr Pointer to new chunk of data
   * \param len Length of new chunk of data
   * \warning Talks to other functions with global parameters
   */
- #define MYWRITE_FLUSH         NULL
  static void mywrite(WriteData *wd, const void *adr, int len)
  {
        if (UNLIKELY(wd->error)) {
                return;
        }
  
-       /* flush helps compression for undo-save */
-       if (adr == MYWRITE_FLUSH) {
-               if (wd->count) {
-                       writedata_do_write(wd, wd->buf, wd->count);
-                       wd->count = 0;
-               }
+       if (adr == NULL) {
+               BLI_assert(0);
                return;
        }
  
@@@ -814,8 -821,7 +819,7 @@@ static void write_actions(WriteData *wd
                }
        }
  
-       /* flush helps the compression for undo-save */
-       mywrite(wd, MYWRITE_FLUSH, 0);
+       mywrite_flush(wd);
  }
  
  static void write_keyingsets(WriteData *wd, ListBase *list)
@@@ -1181,6 -1187,212 +1185,6 @@@ static void write_userdef(WriteData *wd
        }
  }
  
 -static void write_boid_state(WriteData *wd, BoidState *state)
 -{
 -      BoidRule *rule = state->rules.first;
 -
 -      writestruct(wd, DATA, BoidState, 1, state);
 -
 -      for (; rule; rule = rule->next) {
 -              switch (rule->type) {
 -                      case eBoidRuleType_Goal:
 -                      case eBoidRuleType_Avoid:
 -                              writestruct(wd, DATA, BoidRuleGoalAvoid, 1, rule);
 -                              break;
 -                      case eBoidRuleType_AvoidCollision:
 -                              writestruct(wd, DATA, BoidRuleAvoidCollision, 1, rule);
 -                              break;
 -                      case eBoidRuleType_FollowLeader:
 -                              writestruct(wd, DATA, BoidRuleFollowLeader, 1, rule);
 -                              break;
 -                      case eBoidRuleType_AverageSpeed:
 -                              writestruct(wd, DATA, BoidRuleAverageSpeed, 1, rule);
 -                              break;
 -                      case eBoidRuleType_Fight:
 -                              writestruct(wd, DATA, BoidRuleFight, 1, rule);
 -                              break;
 -                      default:
 -                              writestruct(wd, DATA, BoidRule, 1, rule);
 -                              break;
 -              }
 -      }
 -#if 0
 -      BoidCondition *cond = state->conditions.first;
 -      for (; cond; cond = cond->next) {
 -              writestruct(wd, DATA, BoidCondition, 1, cond);
 -      }
 -#endif
 -}
 -
 -/* update this also to readfile.c */
 -static const char *ptcache_data_struct[] = {
 -      "", // BPHYS_DATA_INDEX
 -      "", // BPHYS_DATA_LOCATION
 -      "", // BPHYS_DATA_VELOCITY
 -      "", // BPHYS_DATA_ROTATION
 -      "", // BPHYS_DATA_AVELOCITY / BPHYS_DATA_XCONST */
 -      "", // BPHYS_DATA_SIZE:
 -      "", // BPHYS_DATA_TIMES:
 -      "BoidData" // case BPHYS_DATA_BOIDS:
 -};
 -static const char *ptcache_extra_struct[] = {
 -      "",
 -      "ParticleSpring"
 -};
 -static void write_pointcaches(WriteData *wd, ListBase *ptcaches)
 -{
 -      PointCache *cache = ptcaches->first;
 -      int i;
 -
 -      for (; cache; cache = cache->next) {
 -              writestruct(wd, DATA, PointCache, 1, cache);
 -
 -              if ((cache->flag & PTCACHE_DISK_CACHE) == 0) {
 -                      PTCacheMem *pm = cache->mem_cache.first;
 -
 -                      for (; pm; pm = pm->next) {
 -                              PTCacheExtra *extra = pm->extradata.first;
 -
 -                              writestruct(wd, DATA, PTCacheMem, 1, pm);
 -
 -                              for (i = 0; i < BPHYS_TOT_DATA; i++) {
 -                                      if (pm->data[i] && pm->data_types & (1 << i)) {
 -                                              if (ptcache_data_struct[i][0] == '\0') {
 -                                                      writedata(wd, DATA, MEM_allocN_len(pm->data[i]), pm->data[i]);
 -                                              }
 -                                              else {
 -                                                      writestruct_id(wd, DATA, ptcache_data_struct[i], pm->totpoint, pm->data[i]);
 -                                              }
 -                                      }
 -                              }
 -
 -                              for (; extra; extra = extra->next) {
 -                                      if (ptcache_extra_struct[extra->type][0] == '\0') {
 -                                              continue;
 -                                      }
 -                                      writestruct(wd, DATA, PTCacheExtra, 1, extra);
 -                                      writestruct_id(wd, DATA, ptcache_extra_struct[extra->type], extra->totdata, extra->data);
 -                              }
 -                      }
 -              }
 -      }
 -}
 -static void write_particlesettings(WriteData *wd, ListBase *idbase)
 -{
 -      ParticleSettings *part;
 -      ParticleDupliWeight *dw;
 -      GroupObject *go;
 -      int a;
 -
 -      part = idbase->first;
 -      while (part) {
 -              if (part->id.us > 0 || wd->current) {
 -                      /* write LibData */
 -                      writestruct(wd, ID_PA, ParticleSettings, 1, part);
 -                      write_iddata(wd, &part->id);
 -
 -                      if (part->adt) {
 -                              write_animdata(wd, part->adt);
 -                      }
 -                      writestruct(wd, DATA, PartDeflect, 1, part->pd);
 -                      writestruct(wd, DATA, PartDeflect, 1, part->pd2);
 -                      writestruct(wd, DATA, EffectorWeights, 1, part->effector_weights);
 -
 -                      if (part->clumpcurve) {
 -                              write_curvemapping(wd, part->clumpcurve);
 -                      }
 -                      if (part->roughcurve) {
 -                              write_curvemapping(wd, part->roughcurve);
 -                      }
 -
 -                      dw = part->dupliweights.first;
 -                      for (; dw; dw = dw->next) {
 -                              /* update indices */
 -                              dw->index = 0;
 -                              if (part->dup_group) { /* can be NULL if lining fails or set to None */
 -                                      go = part->dup_group->gobject.first;
 -                                      while (go && go->ob != dw->ob) {
 -                                              go = go->next;
 -                                              dw->index++;
 -                                      }
 -                              }
 -                              writestruct(wd, DATA, ParticleDupliWeight, 1, dw);
 -                      }
 -
 -                      if (part->boids && part->phystype == PART_PHYS_BOIDS) {
 -                              BoidState *state = part->boids->states.first;
 -
 -                              writestruct(wd, DATA, BoidSettings, 1, part->boids);
 -
 -                              for (; state; state = state->next) {
 -                                      write_boid_state(wd, state);
 -                              }
 -                      }
 -                      if (part->fluid && part->phystype == PART_PHYS_FLUID) {
 -                              writestruct(wd, DATA, SPHFluidSettings, 1, part->fluid);
 -                      }
 -
 -                      for (a = 0; a < MAX_MTEX; a++) {
 -                              if (part->mtex[a]) {
 -                                      writestruct(wd, DATA, MTex, 1, part->mtex[a]);
 -                              }
 -                      }
 -              }
 -              part = part->id.next;
 -      }
 -}
 -static void write_particlesystems(WriteData *wd, ListBase *particles)
 -{
 -      ParticleSystem *psys = particles->first;
 -      ParticleTarget *pt;
 -      int a;
 -
 -      for (; psys; psys = psys->next) {
 -              writestruct(wd, DATA, ParticleSystem, 1, psys);
 -
 -              if (psys->particles) {
 -                      writestruct(wd, DATA, ParticleData, psys->totpart, psys->particles);
 -
 -                      if (psys->particles->hair) {
 -                              ParticleData *pa = psys->particles;
 -
 -                              for (a = 0; a < psys->totpart; a++, pa++) {
 -                                      writestruct(wd, DATA, HairKey, pa->totkey, pa->hair);
 -                              }
 -                      }
 -
 -                      if (psys->particles->boid &&
 -                          (psys->part->phystype == PART_PHYS_BOIDS))
 -                      {
 -                              writestruct(wd, DATA, BoidParticle, psys->totpart, psys->particles->boid);
 -                      }
 -
 -                      if (psys->part->fluid &&
 -                          (psys->part->phystype == PART_PHYS_FLUID) &&
 -      &nbs