[SCM] blender/upstream: Imported Upstream version 2.76.a+dfsg0

mfv at users.alioth.debian.org mfv at users.alioth.debian.org
Wed Dec 9 21:43:42 UTC 2015


The following commit has been merged in the upstream branch:
commit 65f721dad143aca88ecdfbafe0a3100d11f81a50
Author: Matteo F. Vescovi <mfv at debian.org>
Date:   Fri Nov 13 21:19:18 2015 +0100

    Imported Upstream version 2.76.a+dfsg0

diff --git a/intern/cycles/blender/blender_camera.cpp b/intern/cycles/blender/blender_camera.cpp
index 0a79bfb..065bd1a 100644
--- a/intern/cycles/blender/blender_camera.cpp
+++ b/intern/cycles/blender/blender_camera.cpp
@@ -487,6 +487,11 @@ void BlenderSync::sync_camera_motion(BL::RenderSettings b_render,
 		BlenderCamera bcam;
 		float aspectratio, sensor_size;
 		blender_camera_init(&bcam, b_render);
+
+		/* TODO(sergey): Consider making it a part of blender_camera_init(). */
+		bcam.pixelaspect.x = b_render.pixel_aspect_x();
+		bcam.pixelaspect.y = b_render.pixel_aspect_y();
+
 		blender_camera_from_object(&bcam, b_engine, b_ob);
 		blender_camera_viewplane(&bcam,
 		                         width, height,
diff --git a/intern/cycles/kernel/geom/geom_triangle_intersect.h b/intern/cycles/kernel/geom/geom_triangle_intersect.h
index ba309a1..9cc31ca 100644
--- a/intern/cycles/kernel/geom/geom_triangle_intersect.h
+++ b/intern/cycles/kernel/geom/geom_triangle_intersect.h
@@ -51,11 +51,7 @@ typedef struct IsectPrecalc {
 
 #if defined(__KERNEL_CUDA__)
 #  if (defined(i386) || defined(_M_IX86))
-#    if __CUDA_ARCH__ > 500
 ccl_device_noinline
-#    else  /* __CUDA_ARCH__ > 500 */
-ccl_device_inline
-#    endif  /* __CUDA_ARCH__ > 500 */
 #  else  /* (defined(i386) || defined(_M_IX86)) */
 #    if defined(__KERNEL_EXPERIMENTAL__) && (__CUDA_ARCH__ >= 500)
 ccl_device_noinline
@@ -142,12 +138,8 @@ ccl_device_inline bool triangle_intersect(KernelGlobals *kg,
 	float U = Cx * By - Cy * Bx;
 	float V = Ax * Cy - Ay * Cx;
 	float W = Bx * Ay - By * Ax;
-	const int sign_mask = (__float_as_int(U) & 0x80000000);
-	/* TODO(sergey): Check if multiplication plus sign check is faster
-	 * or at least same speed (but robust for endian types).
-	 */
-	if(sign_mask != (__float_as_int(V) & 0x80000000) ||
-	   sign_mask != (__float_as_int(W) & 0x80000000))
+	if((U < 0.0f || V < 0.0f || W < 0.0f) &&
+	   (U > 0.0f || V > 0.0f || W > 0.0f))
 	{
 		return false;
 	}
@@ -162,9 +154,10 @@ ccl_device_inline bool triangle_intersect(KernelGlobals *kg,
 	 * the hit distance.
 	 */
 	const float T = (U * A_kz + V * B_kz + W * C_kz) * Sz;
-	const float sign_T = xor_signmask(T, sign_mask);
+	const int sign_det = (__float_as_int(det) & 0x80000000);
+	const float sign_T = xor_signmask(T, sign_det);
 	if((sign_T < 0.0f) ||
-	   (sign_T > isect->t * xor_signmask(det, sign_mask)))
+	   (sign_T > isect->t * xor_signmask(det, sign_det)))
 	{
 		return false;
 	}
@@ -204,7 +197,13 @@ ccl_device_inline bool triangle_intersect(KernelGlobals *kg,
  */
 
 #ifdef __SUBSURFACE__
-ccl_device_inline void triangle_intersect_subsurface(
+
+#if defined(__KERNEL_CUDA__) && (defined(i386) || defined(_M_IX86))
+ccl_device_noinline
+#else
+ccl_device_inline
+#endif
+void triangle_intersect_subsurface(
         KernelGlobals *kg,
         const IsectPrecalc *isect_precalc,
         Intersection *isect_array,
@@ -245,13 +244,12 @@ ccl_device_inline void triangle_intersect_subsurface(
 
 	/* Calculate scaled barycentric coordinates. */
 	float U = Cx * By - Cy * Bx;
-	int sign_mask = (__float_as_int(U) & 0x80000000);
 	float V = Ax * Cy - Ay * Cx;
-	if(sign_mask != (__float_as_int(V) & 0x80000000)) {
-		return;
-	}
 	float W = Bx * Ay - By * Ax;
-	if(sign_mask != (__float_as_int(W) & 0x80000000)) {
+
+	if((U < 0.0f || V < 0.0f || W < 0.0f) &&
+	   (U > 0.0f || V > 0.0f || W > 0.0f))
+	{
 		return;
 	}
 
@@ -264,10 +262,11 @@ ccl_device_inline void triangle_intersect_subsurface(
 	/* Calculate scaled z−coordinates of vertices and use them to calculate
 	 * the hit distance.
 	 */
+	const int sign_det = (__float_as_int(det) & 0x80000000);
 	const float T = (U * A_kz + V * B_kz + W * C_kz) * Sz;
-	const float sign_T = xor_signmask(T, sign_mask);
+	const float sign_T = xor_signmask(T, sign_det);
 	if((sign_T < 0.0f) ||
-	   (sign_T > tmax * xor_signmask(det, sign_mask)))
+	   (sign_T > tmax * xor_signmask(det, sign_det)))
 	{
 		return;
 	}
diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp
index 7bceb8a..7a846e1 100644
--- a/intern/cycles/render/image.cpp
+++ b/intern/cycles/render/image.cpp
@@ -69,6 +69,9 @@ void ImageManager::set_extended_image_limits(const DeviceInfo& info)
 	else if((info.type == DEVICE_CUDA || info.type == DEVICE_MULTI) && info.extended_images) {
 		tex_num_images = TEX_EXTENDED_NUM_IMAGES_GPU;
 	}
+	else if(info.pack_images) {
+		tex_num_images = TEX_PACKED_NUM_IMAGES;
+	}
 }
 
 bool ImageManager::set_animation_frame_update(int frame)
diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h
index bcc58ae..c79c152 100644
--- a/intern/cycles/render/image.h
+++ b/intern/cycles/render/image.h
@@ -40,6 +40,13 @@ CCL_NAMESPACE_BEGIN
 #define TEX_EXTENDED_NUM_IMAGES_CPU		1024
 #define TEX_EXTENDED_IMAGE_BYTE_START	TEX_EXTENDED_NUM_FLOAT_IMAGES
 
+/* Limitations for packed images.
+ *
+ * Technically number of textures is unlimited, but it should in
+ * fact be in sync with CPU limitations.
+ */
+#define TEX_PACKED_NUM_IMAGES			1024
+
 /* color to use when textures are not found */
 #define TEX_IMAGE_MISSING_R 1
 #define TEX_IMAGE_MISSING_G 0
diff --git a/intern/cycles/util/util_optimization.h b/intern/cycles/util/util_optimization.h
index c951c35..42d3ca6 100644
--- a/intern/cycles/util/util_optimization.h
+++ b/intern/cycles/util/util_optimization.h
@@ -101,7 +101,7 @@
 
 #ifdef _MSC_VER
 #include <intrin.h>
-#else
+#elif (defined(__x86_64__) || defined(__i386__))
 #include <x86intrin.h>
 #endif
 
diff --git a/release/scripts/addons/modules/rna_manual_reference.py b/release/scripts/addons/modules/rna_manual_reference.py
index d23d436..b0c67d5 100644
--- a/release/scripts/addons/modules/rna_manual_reference.py
+++ b/release/scripts/addons/modules/rna_manual_reference.py
@@ -98,54 +98,54 @@ url_manual_mapping = (
 
     # *** Modifiers ***
     # --- Intro ---
-    ("bpy.types.Modifier.show_*", "modifiers/the_stack.html"),
-    ("bpy.types.Modifier.*", "modifiers"),  # catchall for various generic options
+    ("bpy.types.Modifier.show_*", "modeling/modifiers/the_stack.html"),
+    ("bpy.types.Modifier.*", "modeling/modifiers"),  # catchall for various generic options
     # --- Modify Modifiers ---
-    ("bpy.types.MeshCacheModifier.*",              "modifiers/modify/mesh_cache.html"),
-    ("bpy.types.UVProjectModifier.*",              "modifiers/modify/uv_project.html"),
-    ("bpy.types.UVWarpModifier.*",                 "modifiers/modify/uv_warp.html"),
-    ("bpy.types.VertexWeightMixModifier.*",        "modifiers/modify/vertex_weight.html"),
-    ("bpy.types.VertexWeightEditModifier.*",       "modifiers/modify/vertex_weight.html"),
-    ("bpy.types.VertexWeightProximityModifier.*",  "modifiers/modify/vertex_weight.html"),
+    ("bpy.types.MeshCacheModifier.*",              "modeling/modifiers/modify/mesh_cache.html"),
+    ("bpy.types.UVProjectModifier.*",              "modeling/modifiers/modify/uv_project.html"),
+    ("bpy.types.UVWarpModifier.*",                 "modeling/modifiers/modify/uv_warp.html"),
+    ("bpy.types.VertexWeightMixModifier.*",        "modeling/modifiers/modify/vertex_weight.html"),
+    ("bpy.types.VertexWeightEditModifier.*",       "modeling/modifiers/modify/vertex_weight.html"),
+    ("bpy.types.VertexWeightProximityModifier.*",  "modeling/modifiers/modify/vertex_weight.html"),
     # --- Generate Modifiers ---
-    ("bpy.types.ArrayModifier.*",      "modifiers/generate/array.html"),
-    ("bpy.types.BevelModifier.*",      "modifiers/generate/bevel.html"),
-    ("bpy.types.BooleanModifier.*",    "modifiers/generate/booleans.html"),
-    ("bpy.types.BuildModifier.*",      "modifiers/generate/build.html"),
-    ("bpy.types.DecimateModifier.*",   "modifiers/generate/decimate.html"),
-    ("bpy.types.EdgeSplitModifier.*",  "modifiers/generate/edge_split.html"),
-    ("bpy.types.MaskModifier.*",       "modifiers/generate/mask.html"),
-    ("bpy.types.MirrorModifier.*",     "modifiers/generate/mirror.html"),
-    ("bpy.types.MultiresModifier.*",   "modifiers/generate/multiresolution.html"),
-    ("bpy.types.RemeshModifier.*",     "modifiers/generate/remesh.html"),
-    ("bpy.types.ScrewModifier.*",      "modifiers/generate/screw.html"),
-    ("bpy.types.SkinModifier.*",       "modifiers/generate/skin.html"),
-    ("bpy.types.SolidifyModifier.*",   "modifiers/generate/solidify.html"),
-    ("bpy.types.SubsurfModifier.*",    "modifiers/generate/subsurf.html"),
-    ("bpy.types.TriangulateModifier.*","modifiers/generate/triangulate.html"),
+    ("bpy.types.ArrayModifier.*",      "modeling/modifiers/generate/array.html"),
+    ("bpy.types.BevelModifier.*",      "modeling/modifiers/generate/bevel.html"),
+    ("bpy.types.BooleanModifier.*",    "modeling/modifiers/generate/booleans.html"),
+    ("bpy.types.BuildModifier.*",      "modeling/modifiers/generate/build.html"),
+    ("bpy.types.DecimateModifier.*",   "modeling/modifiers/generate/decimate.html"),
+    ("bpy.types.EdgeSplitModifier.*",  "modeling/modifiers/generate/edge_split.html"),
+    ("bpy.types.MaskModifier.*",       "modeling/modifiers/generate/mask.html"),
+    ("bpy.types.MirrorModifier.*",     "modeling/modifiers/generate/mirror.html"),
+    ("bpy.types.MultiresModifier.*",   "modeling/modifiers/generate/multiresolution.html"),
+    ("bpy.types.RemeshModifier.*",     "modeling/modifiers/generate/remesh.html"),
+    ("bpy.types.ScrewModifier.*",      "modeling/modifiers/generate/screw.html"),
+    ("bpy.types.SkinModifier.*",       "modeling/modifiers/generate/skin.html"),
+    ("bpy.types.SolidifyModifier.*",   "modeling/modifiers/generate/solidify.html"),
+    ("bpy.types.SubsurfModifier.*",    "modeling/modifiers/generate/subsurf.html"),
+    ("bpy.types.TriangulateModifier.*","modeling/modifiers/generate/triangulate.html"),
     # --- Deform Modifiers ---
-    ("bpy.types.ArmatureModifier.*",      "modifiers/deform/armature.html"),
-    ("bpy.types.CastModifier.*",          "modifiers/deform/cast.html"),
-    ("bpy.types.CurveModifier.*",         "modifiers/deform/curve.html"),
-    ("bpy.types.DisplaceModifier.*",      "modifiers/deform/displace.html"),
-    ("bpy.types.HookModifier.*",          "modifiers/deform/hooks.html"),
-    ("bpy.types.LaplacianSmoothModifier.*", "modifiers/deform/laplacian_smooth.html"),
-    ("bpy.types.LatticeModifier.*",       "modifiers/deform/lattice.html"),
-    ("bpy.types.MeshDeformModifier.*",    "modifiers/deform/mesh_deform.html"),
-    ("bpy.types.ShrinkwrapModifier.*",    "modifiers/deform/shrinkwrap.html"),
-    ("bpy.types.SimpleDeformModifier.*",  "modifiers/deform/simple_deform.html"),
-    ("bpy.types.SmoothModifier.*",        "modifiers/deform/smooth.html"),
+    ("bpy.types.ArmatureModifier.*",      "modeling/modifiers/deform/armature.html"),
+    ("bpy.types.CastModifier.*",          "modeling/modifiers/deform/cast.html"),
+    ("bpy.types.CurveModifier.*",         "modeling/modifiers/deform/curve.html"),
+    ("bpy.types.DisplaceModifier.*",      "modeling/modifiers/deform/displace.html"),
+    ("bpy.types.HookModifier.*",          "modeling/modifiers/deform/hooks.html"),
+    ("bpy.types.LaplacianSmoothModifier.*", "modeling/modifiers/deform/laplacian_smooth.html"),
+    ("bpy.types.LatticeModifier.*",       "modeling/modifiers/deform/lattice.html"),
+    ("bpy.types.MeshDeformModifier.*",    "modeling/modifiers/deform/mesh_deform.html"),
+    ("bpy.types.ShrinkwrapModifier.*",    "modeling/modifiers/deform/shrinkwrap.html"),
+    ("bpy.types.SimpleDeformModifier.*",  "modeling/modifiers/deform/simple_deform.html"),
+    ("bpy.types.SmoothModifier.*",        "modeling/modifiers/deform/smooth.html"),
     # ("bpy.types.SurfaceModifier.*",     "Modifiers/Deform/"),  # USERS NEVER SEE THIS
-    ("bpy.types.WarpModifier.*",          "modifiers/deform/warp.html"),
-    ("bpy.types.WaveModifier.*",          "modifiers/deform/wave.html"),
+    ("bpy.types.WarpModifier.*",          "modeling/modifiers/deform/warp.html"),
+    ("bpy.types.WaveModifier.*",          "modeling/modifiers/deform/wave.html"),
     # --- Simulate Modifiers ---
     ("bpy.types.ClothModifier.*",             "physics/cloth.html"),
     ("bpy.types.CollisionModifier.*",         "physics/collision.html"),
     ("bpy.types.DynamicPaintModifier.*",      "physics/dynamic_paint"),
-    ("bpy.types.ExplodeModifier.*",           "modifiers/simulate/explode.html"),
+    ("bpy.types.ExplodeModifier.*",           "modeling/modifiers/simulate/explode.html"),
     ("bpy.types.FluidSimulationModifier.*",   "physics/fluid"),
-    ("bpy.types.OceanModifier.*",             "modifiers/simulate/ocean.html"),
-    ("bpy.types.ParticleInstanceModifier.*",  "modifiers/simulate/particle_instance.html"),
+    ("bpy.types.OceanModifier.*",             "modeling/modifiers/simulate/ocean.html"),
+    ("bpy.types.ParticleInstanceModifier.*",  "modeling/modifiers/simulate/particle_instance.html"),
     ("bpy.types.ParticleSystemModifier.*",    "physics/particles"),
     ("bpy.types.SmokeModifier.*",             "physics/smoke"),
     ("bpy.types.SoftBodyModifier.*",          "physics/soft_body"),
@@ -185,20 +185,20 @@ url_manual_mapping = (
     ("bpy.types.RigidBodyJointConstraint.*",  "rigging/constraints/relationship/rigid_body_joint.html"),
     ("bpy.types.ShrinkwrapConstraint.*",      "rigging/constraints/relationship/shrinkwrap.html"),
 
-    ("bpy.types.ImageFormatSettings.*",  "render/output.html#file-type"),
-    ("bpy.types.RenderSettings.filepath",  "render/output.html#file-locations"),
-    ("bpy.types.RenderSettings.display_mode",  "render/display.html#displaying-renders"),
+    ("bpy.types.ImageFormatSettings.*",  "data_system/files/image_formats.html"),
+    ("bpy.types.RenderSettings.filepath",  "render/output/output.html#output-panel"),
+    ("bpy.types.RenderSettings.display_mode",  "render/output/display.html#displaying-renders"),
     ("bpy.types.RenderSettings.*",       "render"),  # catchall, todo - refine
 
     # *** ID Subclasses ***
-    ("bpy.types.Action.*", "animation/basics/actions.html"),
+    ("bpy.types.Action.*", "animation/actions.html"),
     #("bpy.types.Brush.*", ""),  # TODO - manual has no place for this! XXX
     ("bpy.types.Curve.*", "modeling/curves"),
     ("bpy.types.GreasePencil.*", "interface/grease_pencil/index.html"),
     ("bpy.types.Group.*", "modeling/objects/groups_and_parenting.html#grouping-objects"),
     ("bpy.types.Image.*", "render/blender_render/textures/types/image.html"),
-    ("bpy.types.ShapeKey.*", "animation/techs/shape/shape_keys.html"), # not an id but include because of key
-    ("bpy.types.Key.*", "animation/techs/shape/shape_keys.html"),
+    ("bpy.types.ShapeKey.*", "animation/shape_keys.html"), # not an id but include because of key
+    ("bpy.types.Key.*", "animation/shape_keys.html"),
     #("bpy.types.Lattice.*", ""), # TODO - manual has no place for this! XXX
     ("bpy.types.Library.*", "data_system/linked_libraries.html"),
     #("bpy.types.Mask.*", ""), # TODO - manual has no place for this! XXX
@@ -227,7 +227,7 @@ url_manual_mapping = (
     #("bpy.types.NodeTree.*", ""),  # dont document
     ("bpy.types.Object.*",  "modeling/objects"),  # catchall, todo - refine
     ("bpy.types.ParticleSettings.*", "physics/particles"),
-    ("bpy.types.Scene.*", "interface/scenes.html"),
+    ("bpy.types.Scene.*", "data_system/scenes.html"),
     ("bpy.types.Screen.*", "interface/screens.html"),
     #("bpy.types.Sound.*", ""), # TODO - manual has no place for this! XXX
     #("bpy.types.Speaker.*", ""), # TODO - manual has no place for this! XXX
@@ -252,7 +252,7 @@ url_manual_mapping = (
 
     # Currently all manual links on all sockets and values (such as Fac, Roughness, Color...) are NodeSocket* type.
     # It'd be much better if the name of the socket could be used for the manual reference
-    ("bpy.types.NodeSocket*", "editors/node_editor/node_controls.html"),  # no generic socket type page exists, but composite types are the same
+    ("bpy.types.NodeSocket*", "editors/node_editor/node_parts.html"),  # no generic socket type page exists, but composite types are the same
 
     # *** Cycles Material Nodes ***
     # Outputs
@@ -440,7 +440,7 @@ url_manual_mapping = (
     ("bpy.types.Lamp.*",       "render/blender_render/lighting"),             # catchall, todo - refine
 
     # --- Animation ---
-    ("bpy.types.Keyframe.*", "animation/basics/actions.html"),
+    ("bpy.types.Keyframe.*", "animation/actions.html"),
     ("bpy.types.FCurve.*", "editors/graph_editor/fcurves.html"),
 
     # --- Rigging ---
@@ -460,7 +460,7 @@ url_manual_mapping = (
     # Catch all only for now!
     # *** Window/Screen ***
 
-    ("bpy.ops.action.*",  "animation/basics/actions.html"),
+    ("bpy.ops.action.*",  "animation/actions.html"),
     ("bpy.ops.anim.*",  "animation"),
     ("bpy.ops.armature.*",  "rigging/armatures.html"),
     ("bpy.ops.boid.*",  "physics/particles/physics/boids.html"),
@@ -492,7 +492,7 @@ url_manual_mapping = (
     ("bpy.ops.lamp.*",  "render/blender_render/lighting"),  # --- todo ... all below ---
     # ("bpy.ops.lattice.*",  ""),  # TODO
     ("bpy.ops.logic.*",  "game_engine/logic"),
-    ("bpy.ops.marker.*",  "animation/basics/markers.html"),
+    ("bpy.ops.marker.*",  "animation/markers.html"),
     # ("bpy.ops.mask.*",  ""),  # TODO
     ("bpy.ops.material.new",  "render/blender_render/materials/assigning_a_material.html#creating-a-new-material"),
     ("bpy.ops.material.*",  "render/blender_render"),
@@ -510,8 +510,8 @@ url_manual_mapping = (
     ("bpy.ops.mesh.*",  "modeling/meshes"),
     ("bpy.ops.nla.*",  "editors/nla.html"),
     # ("bpy.ops.node.*",  ""),  # TODO
-    ("bpy.ops.object.*shape_key*", "animation/techs/shape/shape_keys.html"),
-    ("bpy.ops.object.join_shapes", "animation/techs/shape/shape_keys.html"),
+    ("bpy.ops.object.*shape_key*", "animation/shape_keys.html"),
+    ("bpy.ops.object.join_shapes", "animation/shape_keys.html"),
     ("bpy.ops.object.*",  "modeling/objects"),
     ("bpy.ops.outliner.*",  "editors/outliner.html"),
     # ("bpy.ops.paint.*",  ""),  # TODO
@@ -520,10 +520,10 @@ url_manual_mapping = (
     ("bpy.ops.poselib.*",  "rigging/posing/pose_library.html"),
     # ("bpy.ops.ptcache.*",  ""),  # TODO
 
-    ("bpy.ops.render.play-rendered-anim",  "render/display.html#animation-playback"),
+    ("bpy.ops.render.play-rendered-anim",  "render/output/display.html#animation-playback"),
     ("bpy.ops.render.*",  "render"),  # catchall
 
-    ("bpy.ops.scene.*",  "interface/scenes.html"),
+    ("bpy.ops.scene.*",  "data_system/scenes.html"),
     ("bpy.ops.screen.*",  "interface/window_system"),
     ("bpy.ops.script.*",  "advanced/scripting"),
     ("bpy.ops.sculpt.*",  "modeling/meshes/editing/sculpt_mode.html"),
diff --git a/release/scripts/freestyle/modules/parameter_editor.py b/release/scripts/freestyle/modules/parameter_editor.py
index fe6c6f6..082ce13 100644
--- a/release/scripts/freestyle/modules/parameter_editor.py
+++ b/release/scripts/freestyle/modules/parameter_editor.py
@@ -1406,10 +1406,11 @@ def process(layer_name, lineset_name):
             shaders_list.append(ColorDistanceFromCameraShader(
                 m.blend, m.influence, m.color_ramp,
                 m.range_min, m.range_max))
-        elif m.type == 'DISTANCE_FROM_OBJECT' and m.target is not None:
-            shaders_list.append(ColorDistanceFromObjectShader(
-                m.blend, m.influence, m.color_ramp, m.target,
-                m.range_min, m.range_max))
+        elif m.type == 'DISTANCE_FROM_OBJECT':
+            if m.target is not None:
+                shaders_list.append(ColorDistanceFromObjectShader(
+                    m.blend, m.influence, m.color_ramp, m.target,
+                    m.range_min, m.range_max))
         elif m.type == 'MATERIAL':
             shaders_list.append(ColorMaterialShader(
                 m.blend, m.influence, m.color_ramp, m.material_attribute,
@@ -1439,10 +1440,11 @@ def process(layer_name, lineset_name):
             shaders_list.append(AlphaDistanceFromCameraShader(
                 m.blend, m.influence, m.mapping, m.invert, m.curve,
                 m.range_min, m.range_max))
-        elif m.type == 'DISTANCE_FROM_OBJECT' and m.target is not None:
-            shaders_list.append(AlphaDistanceFromObjectShader(
-                m.blend, m.influence, m.mapping, m.invert, m.curve, m.target,
-                m.range_min, m.range_max))
+        elif m.type == 'DISTANCE_FROM_OBJECT':
+            if m.target is not None:
+                shaders_list.append(AlphaDistanceFromObjectShader(
+                    m.blend, m.influence, m.mapping, m.invert, m.curve, m.target,
+                    m.range_min, m.range_max))
         elif m.type == 'MATERIAL':
             shaders_list.append(AlphaMaterialShader(
                 m.blend, m.influence, m.mapping, m.invert, m.curve,
@@ -1475,11 +1477,12 @@ def process(layer_name, lineset_name):
                 thickness_position, linestyle.thickness_ratio,
                 m.blend, m.influence, m.mapping, m.invert, m.curve,
                 m.range_min, m.range_max, m.value_min, m.value_max))
-        elif m.type == 'DISTANCE_FROM_OBJECT' and m.target is not None:
-            shaders_list.append(ThicknessDistanceFromObjectShader(
-                thickness_position, linestyle.thickness_ratio,
-                m.blend, m.influence, m.mapping, m.invert, m.curve, m.target,
-                m.range_min, m.range_max, m.value_min, m.value_max))
+        elif m.type == 'DISTANCE_FROM_OBJECT':
+            if m.target is not None:
+                shaders_list.append(ThicknessDistanceFromObjectShader(
+                    thickness_position, linestyle.thickness_ratio,
+                    m.blend, m.influence, m.mapping, m.invert, m.curve, m.target,
+                    m.range_min, m.range_max, m.value_min, m.value_max))
         elif m.type == 'MATERIAL':
             shaders_list.append(ThicknessMaterialShader(
                 thickness_position, linestyle.thickness_ratio,
diff --git a/release/scripts/modules/bpy/utils/previews.py b/release/scripts/modules/bpy/utils/previews.py
index 9659711..c67c523 100644
--- a/release/scripts/modules/bpy/utils/previews.py
+++ b/release/scripts/modules/bpy/utils/previews.py
@@ -86,7 +86,7 @@ class ImagePreviewCollection(dict):
 
     def new(self, name):
         if name in self:
-            raise KeyException("key %r already exists")
+            raise KeyError("key %r already exists" % name)
         p = self[name] = _utils_previews.new(
                 self._gen_key(name))
         return p
@@ -94,7 +94,7 @@ class ImagePreviewCollection(dict):
 
     def load(self, name, path, path_type, force_reload=False):
         if name in self:
-            raise KeyException("key %r already exists")
+            raise KeyError("key %r already exists" % name)
         p = self[name] = _utils_previews.load(
                 self._gen_key(name), path, path_type, force_reload)
         return p
diff --git a/release/scripts/modules/progress_report.py b/release/scripts/modules/progress_report.py
index 578eb96..fc77a3e 100644
--- a/release/scripts/modules/progress_report.py
+++ b/release/scripts/modules/progress_report.py
@@ -99,7 +99,7 @@ class ProgressReport:
     def enter_substeps(self, nbr, msg=""):
         if msg:
             self.update(msg)
-        self.steps.append(self.steps[-1] / nbr)
+        self.steps.append(self.steps[-1] / max(nbr, 1))
         self.curr_step.append(0)
         self.start_time.append(time.time())
 
diff --git a/release/scripts/startup/bl_ui/properties_data_bone.py b/release/scripts/startup/bl_ui/properties_data_bone.py
index a14e345..33398b3 100644
--- a/release/scripts/startup/bl_ui/properties_data_bone.py
+++ b/release/scripts/startup/bl_ui/properties_data_bone.py
@@ -220,7 +220,7 @@ class BONE_PT_display(BoneButtonsPanel, Panel):
             col = split.column()
             col.prop(bone, "hide", text="Hide")
             sub = col.column()
-            sub.active = bool(pchan.custom_shape)
+            sub.active = bool(pchan and pchan.custom_shape)
             sub.prop(bone, "show_wire", text="Wireframe")
 
             if pchan:
diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py
index 6b32d2a..34137c8 100644
--- a/release/scripts/startup/bl_ui/space_dopesheet.py
+++ b/release/scripts/startup/bl_ui/space_dopesheet.py
@@ -339,7 +339,7 @@ class DOPESHEET_MT_key(Menu):
         layout.operator_menu_enum("action.interpolation_type", "type", text="Interpolation Mode")
 
         layout.separator()
-        layout.operator("action.clean")
+        layout.operator("action.clean").channels = False
         layout.operator("action.clean", text="Clean Channels").channels = True
         layout.operator("action.sample")
 
@@ -422,7 +422,7 @@ class DOPESHEET_MT_delete(Menu):
 
         layout.separator()
 
-        layout.operator("action.clean")
+        layout.operator("action.clean").channels = False
         layout.operator("action.clean", text="Clean Channels").channels = True
 
 
diff --git a/release/scripts/startup/bl_ui/space_graph.py b/release/scripts/startup/bl_ui/space_graph.py
index 104fd14..82497f1 100644
--- a/release/scripts/startup/bl_ui/space_graph.py
+++ b/release/scripts/startup/bl_ui/space_graph.py
@@ -257,7 +257,7 @@ class GRAPH_MT_key(Menu):
         layout.operator_menu_enum("graph.easing_type", "type", text="Easing Type")
 
         layout.separator()
-        layout.operator("graph.clean")
+        layout.operator("graph.clean").channels = False
         layout.operator("graph.clean", text="Clean Channels").channels = True
         layout.operator("graph.smooth")
         layout.operator("graph.sample")
@@ -293,7 +293,7 @@ class GRAPH_MT_delete(Menu):
 
         layout.separator()
 
-        layout.operator("graph.clean")
+        layout.operator("graph.clean").channels = False
         layout.operator("graph.clean", text="Clean Channels").channels = True
 
 
diff --git a/source/blender/avi/intern/avi.c b/source/blender/avi/intern/avi.c
index 6ea94d3..9601d6e 100644
--- a/source/blender/avi/intern/avi.c
+++ b/source/blender/avi/intern/avi.c
@@ -1063,6 +1063,11 @@ AviError AVI_close_compress(AviMovie *movie)
 {
 	int temp, movi_size, i;
 
+	if (movie->fp == NULL) {
+		/* none of the allocations below were done if the file failed to open */
+		return AVI_ERROR_FOUND;
+	}
+
 	fseek(movie->fp, 0L, SEEK_END);
 	movi_size = (int)ftell(movie->fp);
 
diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h
index 38ebda1..3c705a1 100644
--- a/source/blender/blenkernel/BKE_blender.h
+++ b/source/blender/blenkernel/BKE_blender.h
@@ -49,7 +49,7 @@ extern "C" {
 
 /* used by packaging tools */
 /* can be left blank, otherwise a,b,c... etc with no quotes */
-#define BLENDER_VERSION_CHAR   
+#define BLENDER_VERSION_CHAR   a
 /* alpha/beta/rc/release, docs use this */
 #define BLENDER_VERSION_CYCLE   release
 
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index 3e78475..a7c5c21 100644
--- a/source/blender/blenkernel/BKE_customdata.h
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -472,6 +472,8 @@ typedef struct CustomDataTransferLayerMap {
 	size_t data_offset;  /* Offset of actual data we transfer (in element contained in data_src/dst). */
 	uint64_t data_flag;  /* For bitflag transfer, flag(s) to affect in transfered data. */
 
+	void *interp_data;   /* Opaque pointer, to be used by specific interp callback (e.g. transformspace for normals). */
+
 	cd_datatransfer_interp interp;
 } CustomDataTransferLayerMap;
 
diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h
index 94afc8a..ea63161 100644
--- a/source/blender/blenkernel/BKE_image.h
+++ b/source/blender/blenkernel/BKE_image.h
@@ -212,6 +212,8 @@ void BKE_image_multiview_index(struct Image *ima, struct ImageUser *iuser);
 
 /* for multilayer images as well as for render-viewer */
 bool BKE_image_is_multilayer(struct Image *ima);
+bool BKE_image_is_multiview(struct Image *ima);
+bool BKE_image_is_stereo(struct Image *ima);
 struct RenderResult *BKE_image_acquire_renderresult(struct Scene *scene, struct Image *ima);
 void BKE_image_release_renderresult(struct Scene *scene, struct Image *ima);
 
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index 20dabbd..144f6e3 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -3453,7 +3453,7 @@ void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert,
 
 		if (attribs->mcol[b].array) {
 			const MLoopCol *cp = &attribs->mcol[b].array[loop];
-			copy_v4_v4_char((char *)col, &cp->r);
+			copy_v4_v4_char((char *)col, (char *)&cp->r);
 		}
 		else {
 			col[0] = 0; col[1] = 0; col[2] = 0; col[3] = 0;
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index 7c3287e..c0ebad0 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -1072,7 +1072,7 @@ static void cdDM_drawMappedFacesGLSL(
 						if (matconv[i].attribs.mcol[b].array) {
 							const MLoopCol *mloopcol = matconv[i].attribs.mcol[b].array;
 							for (j = 0; j < mpoly->totloop; j++)
-								copy_v4_v4_char((char *)&varray[offset + j * max_element_size], &mloopcol[mpoly->loopstart + j].r);
+								copy_v4_v4_char((char *)&varray[offset + j * max_element_size], (char *)&mloopcol[mpoly->loopstart + j].r);
 							offset += sizeof(unsigned char) * 4;
 						}
 					}
@@ -1482,7 +1482,7 @@ static void cdDM_buffer_copy_mcol(
 
 	for (i = 0; i < totpoly; i++, mpoly++) {
 		for (j = 0; j < mpoly->totloop; j++) {
-			copy_v3_v3_char((char *)&varray[start], &mloopcol[mpoly->loopstart + j].r);
+			copy_v3_v3_char((char *)&varray[start], (char *)&mloopcol[mpoly->loopstart + j].r);
 			start += 3;
 		}
 	}
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index 2aba4fc..27043b0 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -133,7 +133,20 @@ bConstraintOb *BKE_constraints_make_evalob(Scene *scene, Object *ob, void *subda
 			if (ob) {
 				cob->ob = ob;
 				cob->type = datatype;
-				cob->rotOrder = EULER_ORDER_DEFAULT; // TODO: when objects have rotation order too, use that
+				
+				if (cob->ob->rotmode > 0) {
+					/* Should be some kind of Euler order, so use it */
+					/* NOTE: Versions <= 2.76 assumed that "default" order
+					 *       would always get used, so we may seem some rig
+					 *       breakage as a result. However, this change here
+					 *       is needed to fix T46599
+					 */
+					cob->rotOrder = ob->rotmode;
+				}
+				else {
+					/* Quats/Axis-Angle, so Eulers should just use default order */
+					cob->rotOrder = EULER_ORDER_DEFAULT;
+				}
 				copy_m4_m4(cob->matrix, ob->obmat);
 			}
 			else
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index 815c18b..88ab634 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -61,6 +61,8 @@
 #include "BKE_mesh_remap.h"
 #include "BKE_multires.h"
 
+#include "data_transfer_intern.h"
+
 #include "bmesh.h"
 
 #include <math.h>
@@ -305,13 +307,16 @@ static void layerInterp_normal(
         const void **sources, const float *weights,
         const float *UNUSED(sub_weights), int count, void *dest)
 {
+	/* Note: This is linear interpolation, which is not optimal for vectors.
+	 *       Unfortunately, spherical interpolation of more than two values is hairy, so for now it will do... */
 	float no[3] = {0.0f};
 
 	while (count--) {
 		madd_v3_v3fl(no, (const float *)sources[count], weights[count]);
 	}
 
-	copy_v3_v3((float *)dest, no);
+	/* Weighted sum of normalized vectors will **not** be normalized, even if weights are. */
+	normalize_v3_v3((float *)dest, no);
 }
 
 static void layerCopyValue_normal(const void *source, void *dest, const int mixmode, const float mixfactor)
@@ -926,6 +931,7 @@ static void layerInterp_mloopuv(
 	}
 
 	/* delay writing to the destination incase dest is in sources */
+	((MLoopUV *)dest)->flag = ((MLoopUV *)sources)->flag;
 	copy_v2_v2(((MLoopUV *)dest)->uv, uv);
 }
 
@@ -3912,6 +3918,38 @@ static void customdata_data_transfer_interp_generic(
 	MEM_freeN(tmp_dst);
 }
 
+/* Normals are special, we need to take care of source & destination spaces... */
+void customdata_data_transfer_interp_normal_normals(
+        const CustomDataTransferLayerMap *laymap, void *data_dst,
+        const void **sources, const float *weights, const int count,
+        const float mix_factor)
+{
+	const int data_type = laymap->data_type;
+	const int mix_mode = laymap->mix_mode;
+
+	SpaceTransform *space_transform = laymap->interp_data;
+
+	const LayerTypeInfo *type_info = layerType_getInfo(data_type);
+	cd_interp interp_cd = type_info->interp;
+
+	float tmp_dst[3];
+
+	BLI_assert(data_type == CD_NORMAL);
+
+	if (!sources) {
+		/* Not supported here, abort. */
+		return;
+	}
+
+	interp_cd(sources, weights, NULL, count, tmp_dst);
+	if (space_transform) {
+		/* tmp_dst is in source space so far, bring it back in destination space. */
+		BLI_space_transform_invert_normal(space_transform, tmp_dst);
+	}
+
+	CustomData_data_mix_value(data_type, tmp_dst, data_dst, mix_mode, mix_factor);
+}
+
 void CustomData_data_transfer(const MeshPairRemap *me_remap, const CustomDataTransferLayerMap *laymap)
 {
 	MeshPairRemapItem *mapit = me_remap->items;
diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c
index 53b6f4a..0baf7e3 100644
--- a/source/blender/blenkernel/intern/data_transfer.c
+++ b/source/blender/blenkernel/intern/data_transfer.c
@@ -428,7 +428,7 @@ void data_transfer_layersmapping_add_item(
         ListBase *r_map, const int cddata_type, const int mix_mode, const float mix_factor, const float *mix_weights,
         const void *data_src, void *data_dst, const int data_src_n, const int data_dst_n,
         const size_t elem_size, const size_t data_size, const size_t data_offset, const uint64_t data_flag,
-        cd_datatransfer_interp interp)
+        cd_datatransfer_interp interp, void *interp_data)
 {
 	CustomDataTransferLayerMap *item = MEM_mallocN(sizeof(*item), __func__);
 
@@ -450,17 +450,18 @@ void data_transfer_layersmapping_add_item(
 	item->data_flag = data_flag;
 
 	item->interp = interp;
+	item->interp_data = interp_data;
 
 	BLI_addtail(r_map, item);
 }
 
 static void data_transfer_layersmapping_add_item_cd(
         ListBase *r_map, const int cddata_type, const int mix_mode, const float mix_factor, const float *mix_weights,
-        void *data_src, void *data_dst)
+        void *data_src, void *data_dst, cd_datatransfer_interp interp, void *interp_data)
 {
 	data_transfer_layersmapping_add_item(
 	        r_map, cddata_type, mix_mode, mix_factor, mix_weights, data_src, data_dst,
-	        0, 0, 0, 0, 0, 0, NULL);
+	        0, 0, 0, 0, 0, 0, interp, interp_data);
 }
 
 /* Note: All those layer mapping handlers return false *only* if they were given invalid parameters.
@@ -473,7 +474,8 @@ static bool data_transfer_layersmapping_cdlayers_multisrc_to_dst(
         ListBase *r_map, const int cddata_type, const int mix_mode, const float mix_factor, const float *mix_weights,
         const int num_elem_dst, const bool use_create, const bool use_delete,
         CustomData *cd_src, CustomData *cd_dst, const bool use_dupref_dst,
-        const int tolayers, bool *use_layers_src, const int num_layers_src)
+        const int tolayers, bool *use_layers_src, const int num_layers_src,
+        cd_datatransfer_interp interp, void *interp_data)
 {
 	void *data_src, *data_dst = NULL;
 	int idx_src = num_layers_src;
@@ -527,7 +529,7 @@ static bool data_transfer_layersmapping_cdlayers_multisrc_to_dst(
 						data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_src);
 					}
 					data_transfer_layersmapping_add_item_cd(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
-					                                        data_src, data_dst);
+					                                        data_src, data_dst, interp, interp_data);
 				}
 			}
 			break;
@@ -571,7 +573,7 @@ static bool data_transfer_layersmapping_cdlayers_multisrc_to_dst(
 						data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_dst);
 					}
 					data_transfer_layersmapping_add_item_cd(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
-					                                        data_src, data_dst);
+					                                        data_src, data_dst, interp, interp_data);
 				}
 			}
 
@@ -599,7 +601,8 @@ static bool data_transfer_layersmapping_cdlayers(
         ListBase *r_map, const int cddata_type, const int mix_mode, const float mix_factor, const float *mix_weights,
         const int num_elem_dst, const bool use_create, const bool use_delete,
         CustomData *cd_src, CustomData *cd_dst, const bool use_dupref_dst,
-        const int fromlayers, const int tolayers)
+        const int fromlayers, const int tolayers,
+        cd_datatransfer_interp interp, void *interp_data)
 {
 	int idx_src, idx_dst;
 	void *data_src, *data_dst = NULL;
@@ -626,7 +629,7 @@ static bool data_transfer_layersmapping_cdlayers(
 
 		if (r_map) {
 			data_transfer_layersmapping_add_item_cd(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
-			                                        data_src, data_dst);
+			                                        data_src, data_dst, interp, interp_data);
 		}
 	}
 	else if (fromlayers == DT_LAYERS_ACTIVE_SRC || fromlayers >= 0) {
@@ -719,7 +722,7 @@ static bool data_transfer_layersmapping_cdlayers(
 
 		if (r_map) {
 			data_transfer_layersmapping_add_item_cd(
-			        r_map, cddata_type, mix_mode, mix_factor, mix_weights, data_src, data_dst);
+			        r_map, cddata_type, mix_mode, mix_factor, mix_weights, data_src, data_dst, interp, interp_data);
 		}
 	}
 	else if (fromlayers == DT_LAYERS_ALL_SRC) {
@@ -734,7 +737,8 @@ static bool data_transfer_layersmapping_cdlayers(
 		ret = data_transfer_layersmapping_cdlayers_multisrc_to_dst(
 		        r_map, cddata_type, mix_mode, mix_factor, mix_weights,
 		        num_elem_dst, use_create, use_delete, cd_src, cd_dst, use_dupref_dst,
-		        tolayers, use_layers_src, num_src);
+		        tolayers, use_layers_src, num_src,
+		        interp, interp_data);
 
 		if (use_layers_src) {
 			MEM_freeN(use_layers_src);
@@ -751,10 +755,14 @@ static bool data_transfer_layersmapping_cdlayers(
 static bool data_transfer_layersmapping_generate(
         ListBase *r_map, Object *ob_src, Object *ob_dst, DerivedMesh *dm_src, DerivedMesh *dm_dst, Mesh *me_dst,
         const int elem_type, int cddata_type, int mix_mode, float mix_factor, const float *mix_weights,
-        const int num_elem_dst, const bool use_create, const bool use_delete, const int fromlayers, const int tolayers)
+        const int num_elem_dst, const bool use_create, const bool use_delete, const int fromlayers, const int tolayers,
+        SpaceTransform *space_transform)
 {
 	CustomData *cd_src, *cd_dst;
 
+	cd_datatransfer_interp interp = NULL;
+	void *interp_data = NULL;
+
 	if (elem_type == ME_VERT) {
 		if (!(cddata_type & CD_FAKE)) {
 			cd_src = dm_src->getVertDataLayout(dm_src);
@@ -763,7 +771,8 @@ static bool data_transfer_layersmapping_generate(
 			if (!data_transfer_layersmapping_cdlayers(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
 			                                          num_elem_dst, use_create, use_delete,
 			                                          cd_src, cd_dst, dm_dst != NULL,
-			                                          fromlayers, tolayers))
+			                                          fromlayers, tolayers,
+			                                          interp, interp_data))
 			{
 				/* We handle specific source selection cases here. */
 				return false;
@@ -795,7 +804,7 @@ static bool data_transfer_layersmapping_generate(
 				                                     dm_src->getNumVerts(dm_src),
 				                                     dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert,
 				                                     elem_size, data_size, data_offset, data_flag,
-				                                     data_transfer_interp_char);
+				                                     data_transfer_interp_char, interp_data);
 			}
 			return true;
 		}
@@ -827,7 +836,8 @@ static bool data_transfer_layersmapping_generate(
 			if (!data_transfer_layersmapping_cdlayers(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
 			                                          num_elem_dst, use_create, use_delete,
 			                                          cd_src, cd_dst, dm_dst != NULL,
-			                                          fromlayers, tolayers))
+			                                          fromlayers, tolayers,
+			                                          interp, interp_data))
 			{
 				/* We handle specific source selection cases here. */
 				return false;
@@ -859,7 +869,7 @@ static bool data_transfer_layersmapping_generate(
 				                                     dm_src->getNumEdges(dm_src),
 				                                     dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge,
 				                                     elem_size, data_size, data_offset, data_flag,
-				                                     data_transfer_interp_char);
+				                                     data_transfer_interp_char, interp_data);
 			}
 			return true;
 		}
@@ -888,7 +898,7 @@ static bool data_transfer_layersmapping_generate(
 				                                     dm_src->getNumEdges(dm_src),
 				                                     dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge,
 				                                     elem_size, data_size, data_offset, data_flag,
-				                                     data_transfer_interp_char);
+				                                     data_transfer_interp_char, interp_data);
 			}
 			return true;
 		}
@@ -904,7 +914,7 @@ static bool data_transfer_layersmapping_generate(
 			        dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge,
 			        dm_src->getNumEdges(dm_src),
 			        dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge,
-			        elem_size, data_size, data_offset, data_flag, NULL);
+			        elem_size, data_size, data_offset, data_flag, NULL, interp_data);
 			return true;
 		}
 		else {
@@ -918,6 +928,8 @@ static bool data_transfer_layersmapping_generate(
 		else if (cddata_type == CD_FAKE_LNOR) {
 			/* Preprocess should have generated it, Postprocess will convert it back to CD_CUSTOMLOOPNORMAL. */
 			cddata_type = CD_NORMAL;
+			interp_data = space_transform;
+			interp = customdata_data_transfer_interp_normal_normals;
 		}
 
 		if (!(cddata_type & CD_FAKE)) {
@@ -927,7 +939,8 @@ static bool data_transfer_layersmapping_generate(
 			if (!data_transfer_layersmapping_cdlayers(
 			        r_map, cddata_type, mix_mode, mix_factor, mix_weights,
 			        num_elem_dst, use_create, use_delete, cd_src, cd_dst, dm_dst != NULL,
-			        fromlayers, tolayers))
+			        fromlayers, tolayers,
+			        interp, interp_data))
 			{
 				/* We handle specific source selection cases here. */
 				return false;
@@ -950,7 +963,8 @@ static bool data_transfer_layersmapping_generate(
 			if (!data_transfer_layersmapping_cdlayers(
 			        r_map, cddata_type, mix_mode, mix_factor, mix_weights,
 			        num_elem_dst, use_create, use_delete, cd_src, cd_dst, dm_dst != NULL,
-			        fromlayers, tolayers))
+			        fromlayers, tolayers,
+			        interp, interp_data))
 			{
 				/* We handle specific source selection cases here. */
 				return false;
@@ -969,7 +983,7 @@ static bool data_transfer_layersmapping_generate(
 			        dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly,
 			        dm_src->getNumPolys(dm_src),
 			        dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly,
-			        elem_size, data_size, data_offset, data_flag, NULL);
+			        elem_size, data_size, data_offset, data_flag, NULL, interp_data);
 			return true;
 		}
 		else {
@@ -1035,28 +1049,28 @@ void BKE_object_data_transfer_layout(
 
 			data_transfer_layersmapping_generate(
 			        NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_VERT, cddata_type, 0, 0.0f, NULL,
-			        num_elem_dst, use_create, use_delete, fromlayers, tolayers);
+			        num_elem_dst, use_create, use_delete, fromlayers, tolayers, NULL);
 		}
 		if (DT_DATATYPE_IS_EDGE(dtdata_type)) {
 			const int num_elem_dst = me_dst->totedge;
 
 			data_transfer_layersmapping_generate(
 			        NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_EDGE, cddata_type, 0, 0.0f, NULL,
-			        num_elem_dst, use_create, use_delete, fromlayers, tolayers);
+			        num_elem_dst, use_create, use_delete, fromlayers, tolayers, NULL);
 		}
 		if (DT_DATATYPE_IS_LOOP(dtdata_type)) {
 			const int num_elem_dst = me_dst->totloop;
 
 			data_transfer_layersmapping_generate(
 			        NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_LOOP, cddata_type, 0, 0.0f, NULL,
-			        num_elem_dst, use_create, use_delete, fromlayers, tolayers);
+			        num_elem_dst, use_create, use_delete, fromlayers, tolayers, NULL);
 		}
 		if (DT_DATATYPE_IS_POLY(dtdata_type)) {
 			const int num_elem_dst = me_dst->totpoly;
 
 			data_transfer_layersmapping_generate(
 			        NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_POLY, cddata_type, 0, 0.0f, NULL,
-			        num_elem_dst, use_create, use_delete, fromlayers, tolayers);
+			        num_elem_dst, use_create, use_delete, fromlayers, tolayers, NULL);
 		}
 	}
 }
@@ -1198,7 +1212,7 @@ bool BKE_object_data_transfer_dm(
 			if (data_transfer_layersmapping_generate(
 			        &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_VERT,
 			        cddata_type, mix_mode, mix_factor, weights[VDATA],
-			        num_verts_dst, use_create, use_delete, fromlayers, tolayers))
+			        num_verts_dst, use_create, use_delete, fromlayers, tolayers, space_transform))
 			{
 				CustomDataTransferLayerMap *lay_mapit;
 
@@ -1249,7 +1263,7 @@ bool BKE_object_data_transfer_dm(
 			if (data_transfer_layersmapping_generate(
 			        &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_EDGE,
 			        cddata_type, mix_mode, mix_factor, weights[EDATA],
-			        num_edges_dst, use_create, use_delete, fromlayers, tolayers))
+			        num_edges_dst, use_create, use_delete, fromlayers, tolayers, space_transform))
 			{
 				CustomDataTransferLayerMap *lay_mapit;
 
@@ -1312,7 +1326,7 @@ bool BKE_object_data_transfer_dm(
 			if (data_transfer_layersmapping_generate(
 			        &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_LOOP,
 			        cddata_type, mix_mode, mix_factor, weights[LDATA],
-			        num_loops_dst, use_create, use_delete, fromlayers, tolayers))
+			        num_loops_dst, use_create, use_delete, fromlayers, tolayers, space_transform))
 			{
 				CustomDataTransferLayerMap *lay_mapit;
 
@@ -1367,7 +1381,7 @@ bool BKE_object_data_transfer_dm(
 			if (data_transfer_layersmapping_generate(
 			        &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_POLY,
 			        cddata_type, mix_mode, mix_factor, weights[PDATA],
-			        num_polys_dst, use_create, use_delete, fromlayers, tolayers))
+			        num_polys_dst, use_create, use_delete, fromlayers, tolayers, space_transform))
 			{
 				CustomDataTransferLayerMap *lay_mapit;
 
diff --git a/source/blender/blenkernel/intern/data_transfer_intern.h b/source/blender/blenkernel/intern/data_transfer_intern.h
index 501b749..352eedc 100644
--- a/source/blender/blenkernel/intern/data_transfer_intern.h
+++ b/source/blender/blenkernel/intern/data_transfer_intern.h
@@ -45,7 +45,7 @@ void data_transfer_layersmapping_add_item(
         const float mix_factor, const float *mix_weights,
         const void *data_src, void *data_dst, const int data_src_n, const int data_dst_n,
         const size_t elem_size, const size_t data_size, const size_t data_offset, const uint64_t data_flag,
-        cd_datatransfer_interp interp);
+        cd_datatransfer_interp interp, void *interp_data);
 
 /* Type-specific. */
 
@@ -55,4 +55,10 @@ bool data_transfer_layersmapping_vgroups(
         struct Object *ob_src, struct Object *ob_dst, struct CustomData *cd_src, struct CustomData *cd_dst,
         const bool use_dupref_dst, const int fromlayers, const int tolayers);
 
+/* Defined in customdata.c */
+void customdata_data_transfer_interp_normal_normals(
+        const CustomDataTransferLayerMap *laymap, void *data_dst,
+        const void **sources, const float *weights, const int count,
+        const float mix_factor);
+
 #endif  /* __DATA_TRANSFER_INTERN_H__ */
diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c
index 6670c33..f904369 100644
--- a/source/blender/blenkernel/intern/deform.c
+++ b/source/blender/blenkernel/intern/deform.c
@@ -1163,7 +1163,7 @@ static bool data_transfer_layersmapping_vgroups_multisrc_to_dst(
 					}
 					data_transfer_layersmapping_add_item(r_map, CD_FAKE_MDEFORMVERT, mix_mode, mix_factor, mix_weights,
 					                                     data_src, data_dst, idx_src, idx_src,
-					                                     elem_size, 0, 0, 0, vgroups_datatransfer_interp);
+					                                     elem_size, 0, 0, 0, vgroups_datatransfer_interp, NULL);
 				}
 			}
 			break;
@@ -1211,7 +1211,7 @@ static bool data_transfer_layersmapping_vgroups_multisrc_to_dst(
 						data_transfer_layersmapping_add_item(
 						        r_map, CD_FAKE_MDEFORMVERT, mix_mode, mix_factor, mix_weights,
 						        data_src, data_dst, idx_src, idx_dst,
-						        elem_size, 0, 0, 0, vgroups_datatransfer_interp);
+						        elem_size, 0, 0, 0, vgroups_datatransfer_interp, NULL);
 					}
 				}
 				break;
@@ -1317,7 +1317,7 @@ bool data_transfer_layersmapping_vgroups(
 
 			data_transfer_layersmapping_add_item(r_map, CD_FAKE_MDEFORMVERT, mix_mode, mix_factor, mix_weights,
 			                                     data_src, data_dst, idx_src, idx_dst,
-			                                     elem_size, 0, 0, 0, vgroups_datatransfer_interp);
+			                                     elem_size, 0, 0, 0, vgroups_datatransfer_interp, NULL);
 		}
 	}
 	else {
diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c
index 4373e79..ea8475f 100644
--- a/source/blender/blenkernel/intern/depsgraph.c
+++ b/source/blender/blenkernel/intern/depsgraph.c
@@ -1140,7 +1140,7 @@ void dag_add_relation(DagForest *forest, DagNode *fob1, DagNode *fob2, short rel
 
 	/* TODO(sergey): Find a better place for this. */
 #ifdef WITH_OPENSUBDIV
-	if ((rel & DAG_RL_DATA_DATA) != 0) {
+	if ((rel & (DAG_RL_DATA_DATA | DAG_RL_DATA_OB)) != 0) {
 		if (fob1->type == ID_OB) {
 			if ((fob1->eval_flags & DAG_EVAL_NEED_CPU) == 0) {
 				Object *ob2 = fob2->ob;
diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c
index 840935c..b2bb73b 100644
--- a/source/blender/blenkernel/intern/editderivedmesh.c
+++ b/source/blender/blenkernel/intern/editderivedmesh.c
@@ -1248,7 +1248,7 @@ static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const B
 		GLubyte col[4];
 		if (attribs->mcol[i].em_offset != -1) {
 			const MLoopCol *cp = BM_ELEM_CD_GET_VOID_P(loop, attribs->mcol[i].em_offset);
-			copy_v4_v4_char((char *)col, &cp->r);
+			copy_v4_v4_char((char *)col, (char *)&cp->r);
 		}
 		else {
 			col[0] = 0; col[1] = 0; col[2] = 0; col[3] = 0;
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 36aeb97..5eb8e7d 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -280,14 +280,9 @@ void BKE_image_free_packedfiles(Image *ima)
 	image_free_packedfiles(ima);
 }
 
-static void image_free_views(Image *ima)
-{
-	BLI_freelistN(&ima->views);
-}
-
 void BKE_image_free_views(Image *image)
 {
-	image_free_views(image);
+	BLI_freelistN(&image->views);
 }
 
 static void image_free_anims(Image *ima)
@@ -350,7 +345,7 @@ void BKE_image_free(Image *ima)
 		}
 	}
 
-	image_free_views(ima);
+	BKE_image_free_views(ima);
 	MEM_freeN(ima->stereo3d_format);
 }
 
@@ -873,8 +868,6 @@ Image *BKE_image_add_generated(Main *bmain, unsigned int width, unsigned int hei
 		}
 
 		ima->ok = IMA_OK_LOADED;
-		if (stereo3d)
-			ima->flag |= IMA_IS_STEREO | IMA_IS_MULTIVIEW;
 	}
 
 	return ima;
@@ -964,7 +957,7 @@ void BKE_image_memorypack(Image *ima)
 {
 	ImBuf *ibuf;
 
-	if ((ima->flag & IMA_IS_MULTIVIEW)) {
+	if (BKE_image_is_multiview(ima)) {
 		image_memorypack_multiview(ima);
 		return;
 	}
@@ -1370,6 +1363,7 @@ char BKE_imtype_valid_channels(const char imtype, bool write_file)
 			if (write_file) break;
 			/* fall-through */
 		case R_IMF_IMTYPE_TARGA:
+		case R_IMF_IMTYPE_RAWTGA:
 		case R_IMF_IMTYPE_IRIS:
 		case R_IMF_IMTYPE_PNG:
 		case R_IMF_IMTYPE_RADHDR:
@@ -2474,15 +2468,8 @@ void BKE_image_verify_viewer_views(const RenderData *rd, Image *ima, ImageUser *
 
 	BLI_lock_thread(LOCK_DRAW_IMAGE);
 
-	if (BKE_scene_multiview_is_stereo3d(rd)) {
-		ima->flag |= IMA_IS_STEREO;
-		ima->flag |= IMA_IS_MULTIVIEW;
-	}
-	else {
-		ima->flag &= ~IMA_IS_STEREO;
-		ima->flag &= ~IMA_IS_MULTIVIEW;
+	if (!BKE_scene_multiview_is_stereo3d(rd))
 		iuser->flag &= ~IMA_SHOW_STEREO;
-	}
 
 	/* see if all scene render views are in the image view list */
 	do_reset = (BKE_scene_multiview_num_views_get(rd) != BLI_listbase_count(&ima->views));
@@ -2528,6 +2515,17 @@ void BKE_image_walk_all_users(const Main *mainp, void *customdata,
 		if (tex->type == TEX_IMAGE && tex->ima) {
 			callback(tex->ima, &tex->iuser, customdata);
 		}
+
+		if (tex->nodetree) {
+			bNode *node;
+			for (node = tex->nodetree->nodes.first; node; node = node->next) {
+				if (node->id && node->type == TEX_NODE_IMAGE) {
+					Image *ima = (Image *)node->id;
+					ImageUser *iuser = node->storage;
+					callback(ima, iuser, customdata);
+				}
+			}
+		}
 	}
 
 	/* image window, compo node users */
@@ -2812,7 +2810,7 @@ RenderPass *BKE_image_multilayer_index(RenderResult *rr, ImageUser *iuser)
 void BKE_image_multiview_index(Image *ima, ImageUser *iuser)
 {
 	if (iuser) {
-		bool is_stereo = (ima->flag & IMA_IS_STEREO) && (iuser->flag & IMA_SHOW_STEREO);
+		bool is_stereo = BKE_image_is_stereo(ima) && (iuser->flag & IMA_SHOW_STEREO);
 		if (is_stereo) {
 			iuser->multi_index = iuser->multiview_eye;
 		}
@@ -2845,27 +2843,38 @@ bool BKE_image_is_multilayer(Image *ima)
 	return false;
 }
 
-static void image_init_multilayer_multiview_flag(Image *ima, RenderResult *rr)
+bool BKE_image_is_multiview(Image *ima)
 {
+	return (BLI_listbase_count_ex(&ima->views, 2) > 1);
+}
+
+bool BKE_image_is_stereo(Image *ima)
+{
+	return BKE_image_is_multiview(ima) &&
+	       (BLI_findstring(&ima->views, STEREO_LEFT_NAME, offsetof(ImageView, name)) &&
+            BLI_findstring(&ima->views, STEREO_RIGHT_NAME, offsetof(ImageView, name)));
+}
+
+static void image_view_from_render_view(ImageView *iv_dst, RenderView *rv_src)
+{
+	BLI_strncpy(iv_dst->name, rv_src->name, sizeof(iv_dst->name));
+}
+
+static void image_init_multilayer_multiview(Image *ima, RenderResult *rr)
+{
+	BKE_image_free_views(ima);
 	if (rr) {
-		if (RE_RenderResult_is_stereo(rr)) {
-			ima->flag |= IMA_IS_STEREO;
-			ima->flag |= IMA_IS_MULTIVIEW;
-		}
-		else {
-			ima->flag &= ~IMA_IS_STEREO;
-			if (BLI_listbase_count_ex(&rr->views, 2) > 1)
-				ima->flag |= IMA_IS_MULTIVIEW;
-			else
-				ima->flag &= ~IMA_IS_MULTIVIEW;
+		RenderView *rv_src;
+		for (rv_src = rr->views.first; rv_src; rv_src = rv_src->next) {
+			ImageView *iv_dst;
+			iv_dst = MEM_callocN(sizeof(ImageView), "Viewer Image View");
+			image_view_from_render_view(iv_dst, rv_src);
+			BLI_addhead(&ima->views, iv_dst);
 		}
 	}
-	else {
-		ima->flag &= ~IMA_IS_STEREO;
-		ima->flag &= ~IMA_IS_MULTIVIEW;
-	}
 }
 
+
 RenderResult *BKE_image_acquire_renderresult(Scene *scene, Image *ima)
 {
 	RenderResult *rr = NULL;
@@ -2878,8 +2887,8 @@ RenderResult *BKE_image_acquire_renderresult(Scene *scene, Image *ima)
 		else
 			rr = ima->renders[ima->render_slot];
 
-		/* set proper multiview flag */
-		image_init_multilayer_multiview_flag(ima, rr);
+		/* set proper views */
+		image_init_multilayer_multiview(ima, rr);
 	}
 
 	return rr;
@@ -3037,39 +3046,15 @@ static void image_add_buffer_cb(void *base, const char *str, ImBuf *ibuf, const
 }
 #endif  /* WITH_OPENEXR */
 
-#ifdef WITH_OPENEXR
-static void image_update_multiview_flags(Image *ima)
-{
-	if (BLI_listbase_count_ex(&ima->views, 2) > 1) {
-		ima->flag |= IMA_IS_MULTIVIEW;
-
-		if (BLI_findstring(&ima->views, STEREO_LEFT_NAME, offsetof(ImageView, name)) &&
-		    BLI_findstring(&ima->views, STEREO_RIGHT_NAME, offsetof(ImageView, name)))
-		{
-			ima->flag |= IMA_IS_STEREO;
-		}
-		else {
-			ima->flag &= ~IMA_IS_STEREO;
-		}
-	}
-	else {
-		ima->flag &= ~IMA_IS_STEREO;
-		ima->flag &= ~IMA_IS_MULTIVIEW;
-	}
-}
-#endif  /* WITH_OPENEXR */
-
 /* after imbuf load, openexr type can return with a exrhandle open */
 /* in that case we have to build a render-result */
 #ifdef WITH_OPENEXR
 static void image_create_multiview(Image *ima, ImBuf *ibuf, const int frame)
 {
-	image_free_views(ima);
+	BKE_image_free_views(ima);
 
 	IMB_exr_multiview_convert(ibuf->userdata, ima, image_add_view_cb, image_add_buffer_cb, frame);
 
-	image_update_multiview_flags(ima);
-
 	IMB_exr_close(ibuf->userdata);
 }
 #endif  /* WITH_OPENEXR */
@@ -3082,7 +3067,9 @@ static void image_create_multilayer(Image *ima, ImBuf *ibuf, int framenr)
 	const char *colorspace = ima->colorspace_settings.name;
 	bool predivide = (ima->alpha_mode == IMA_ALPHA_PREMUL);
 
-	ima->rr = RE_MultilayerConvert(ibuf->userdata, colorspace, predivide, ibuf->x, ibuf->y);
+	/* only load rr once for multiview */
+	if (!ima->rr)
+		ima->rr = RE_MultilayerConvert(ibuf->userdata, colorspace, predivide, ibuf->x, ibuf->y);
 
 	IMB_exr_close(ibuf->userdata);
 
@@ -3090,8 +3077,8 @@ static void image_create_multilayer(Image *ima, ImBuf *ibuf, int framenr)
 	if (ima->rr)
 		ima->rr->framenr = framenr;
 
-	/* set proper multiview flag */
-	image_init_multilayer_multiview_flag(ima, ima->rr);
+	/* set proper views */
+	image_init_multilayer_multiview(ima, ima->rr);
 }
 #endif  /* WITH_OPENEXR */
 
@@ -3129,7 +3116,7 @@ static int imbuf_alpha_flags_for_image(Image *ima)
 /* the number of files will vary according to the stereo format */
 static size_t image_num_files(Image *ima)
 {
-	const bool is_multiview = (ima->flag & IMA_IS_MULTIVIEW) != 0;
+	const bool is_multiview = BKE_image_is_multiview(ima);
 
 	if (!is_multiview) {
 		return 1;
@@ -3211,7 +3198,7 @@ static ImBuf *load_sequence_single(Image *ima, ImageUser *iuser, int frame, cons
 static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame)
 {
 	struct ImBuf *ibuf = NULL;
-	const bool is_multiview = (ima->flag & IMA_IS_MULTIVIEW) != 0;
+	const bool is_multiview = BKE_image_is_multiview(ima);
 	const size_t totfiles = image_num_files(ima);
 	bool assign = false;
 
@@ -3231,7 +3218,7 @@ static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame)
 		for (i = 0; i < totfiles; i++)
 			ibuf_arr[i] = load_sequence_single(ima, iuser, frame, i, &assign);
 
-		if ((ima->flag & IMA_IS_STEREO) && ima->views_format == R_IMF_VIEWS_STEREO_3D)
+		if (BKE_image_is_stereo(ima) && ima->views_format == R_IMF_VIEWS_STEREO_3D)
 			IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]);
 
 		/* return the original requested ImBuf */
@@ -3368,7 +3355,7 @@ static ImBuf *load_movie_single(Image *ima, ImageUser *iuser, int frame, const s
 static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame)
 {
 	struct ImBuf *ibuf = NULL;
-	const bool is_multiview = (ima->flag & IMA_IS_MULTIVIEW) != 0;
+	const bool is_multiview = BKE_image_is_multiview(ima);
 	const size_t totfiles = image_num_files(ima);
 	size_t i;
 
@@ -3396,7 +3383,7 @@ static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame)
 			ibuf_arr[i] = load_movie_single(ima, iuser, frame, i);
 		}
 
-		if ((ima->flag & IMA_IS_STEREO) && ima->views_format == R_IMF_VIEWS_STEREO_3D)
+		if (BKE_image_is_stereo(ima) && ima->views_format == R_IMF_VIEWS_STEREO_3D)
 			IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]);
 
 		for (i = 0; i < totviews; i++) {
@@ -3524,7 +3511,7 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra)
 {
 	struct ImBuf *ibuf = NULL;
 	bool assign = false;
-	const bool is_multiview = (ima->flag & IMA_IS_MULTIVIEW) != 0;
+	const bool is_multiview = BKE_image_is_multiview(ima);
 	const size_t totfiles = image_num_files(ima);
 	bool has_packed = BKE_image_has_packedfile(ima);
 
@@ -3557,7 +3544,7 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra)
 			ibuf_arr[i] = load_image_single(ima, iuser, cfra, i, has_packed, &assign);
 
 		/* multi-views/multi-layers OpenEXR files directly populate ima, and return NULL ibuf... */
-		if ((ima->flag & IMA_IS_STEREO) && ima->views_format == R_IMF_VIEWS_STEREO_3D &&
+		if (BKE_image_is_stereo(ima) && ima->views_format == R_IMF_VIEWS_STEREO_3D &&
 		    ibuf_arr[0] && totfiles == 1 && totviews >= 2)
 		{
 			IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]);
@@ -3657,7 +3644,7 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc
 	pass = iuser->pass;
 	actview = iuser->view;
 
-	if ((ima->flag & IMA_IS_STEREO) && (iuser->flag & IMA_SHOW_STEREO))
+	if (BKE_image_is_stereo(ima) && (iuser->flag & IMA_SHOW_STEREO))
 		actview = iuser->multiview_eye;
 
 	if (from_render) {
@@ -3831,12 +3818,12 @@ static size_t image_get_multiview_index(Image *ima, ImageUser *iuser)
 		return iuser ? iuser->multi_index : index;
 	}
 	else if (is_backdrop) {
-		if ((ima->flag & IMA_IS_STEREO)) {
+		if (BKE_image_is_stereo(ima)) {
 			/* backdrop hackaround (since there is no iuser */
 			return ima->eye;
 		}
 	}
-	else if ((ima->flag & IMA_IS_MULTIVIEW)) {
+	else if (BKE_image_is_multiview(ima)) {
 		return iuser ? iuser->multi_index : index;
 	}
 
@@ -4325,9 +4312,12 @@ void BKE_image_update_frame(const Main *bmain, int cfra)
 
 void BKE_image_user_file_path(ImageUser *iuser, Image *ima, char *filepath)
 {
-	if ((ima->flag & IMA_IS_MULTIVIEW) && (ima->rr == NULL)) {
+	if (BKE_image_is_multiview(ima) && (ima->rr == NULL)) {
 		ImageView *iv = BLI_findlink(&ima->views, iuser->view);
-		BLI_strncpy(filepath, iv->filepath, FILE_MAX);
+		if (iv->filepath[0])
+			BLI_strncpy(filepath, iv->filepath, FILE_MAX);
+		else
+			BLI_strncpy(filepath, ima->name, FILE_MAX);
 	}
 	else {
 		BLI_strncpy(filepath, ima->name, FILE_MAX);
@@ -4622,15 +4612,12 @@ static void image_update_views_format(Image *ima, ImageUser *iuser)
 	BKE_image_free_views(ima);
 
 	if (!is_multiview) {
-		goto monoview;
+		/* nothing to do */
 	}
 	else if (ima->views_format == R_IMF_VIEWS_STEREO_3D) {
 		size_t i;
 		const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
 
-		ima->flag |= IMA_IS_MULTIVIEW;
-		ima->flag |= IMA_IS_STEREO;
-
 		for (i = 0; i < 2; i++) {
 			image_add_view(ima, names[i], ima->name);
 		}
@@ -4645,7 +4632,8 @@ static void image_update_views_format(Image *ima, ImageUser *iuser)
 		BKE_scene_multiview_view_prefix_get(scene, name, prefix, &ext);
 
 		if (prefix[0] == '\0') {
-			goto monoview;
+			BKE_image_free_views(ima);
+			return;
 		}
 
 		/* create all the image views */
@@ -4681,15 +4669,7 @@ static void image_update_views_format(Image *ima, ImageUser *iuser)
 		}
 
 		/* all good */
-		if (BLI_listbase_count_ex(&ima->views, 2) > 1) {
-			ima->flag |= IMA_IS_MULTIVIEW;
-			if (BKE_scene_multiview_is_stereo3d(&scene->r))
-				ima->flag |= IMA_IS_STEREO;
-		}
-		else {
-monoview:
-			ima->flag &= ~IMA_IS_STEREO;
-			ima->flag &= ~IMA_IS_MULTIVIEW;
+		if (!BKE_image_is_multiview(ima)) {
 			BKE_image_free_views(ima);
 		}
 	}
diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c
index c3b88b8..b4f55d0 100644
--- a/source/blender/blenkernel/intern/mesh_remap.c
+++ b/source/blender/blenkernel/intern/mesh_remap.c
@@ -455,14 +455,13 @@ void BKE_mesh_remap_calc_verts_from_dm(
 		BVHTreeNearest nearest = {0};
 		BVHTreeRayHit rayhit = {0};
 		float hit_dist;
+		float tmp_co[3], tmp_no[3];
 
 		if (mode == MREMAP_MODE_VERT_NEAREST) {
 			bvhtree_from_mesh_verts(&treedata, dm_src, 0.0f, 2, 6);
 			nearest.index = -1;
 
 			for (i = 0; i < numverts_dst; i++) {
-				float tmp_co[3];
-
 				copy_v3_v3(tmp_co, verts_dst[i].co);
 
 				/* Convert the vertex to tree coordinates, if needed. */
@@ -488,8 +487,6 @@ void BKE_mesh_remap_calc_verts_from_dm(
 			nearest.index = -1;
 
 			for (i = 0; i < numverts_dst; i++) {
-				float tmp_co[3];
-
 				copy_v3_v3(tmp_co, verts_dst[i].co);
 
 				/* Convert the vertex to tree coordinates, if needed. */
@@ -548,8 +545,6 @@ void BKE_mesh_remap_calc_verts_from_dm(
 
 			if (mode == MREMAP_MODE_VERT_POLYINTERP_VNORPROJ) {
 				for (i = 0; i < numverts_dst; i++) {
-					float tmp_co[3], tmp_no[3];
-
 					copy_v3_v3(tmp_co, verts_dst[i].co);
 					normal_short_to_float_v3(tmp_no, verts_dst[i].no);
 
@@ -580,8 +575,6 @@ void BKE_mesh_remap_calc_verts_from_dm(
 				nearest.index = -1;
 
 				for (i = 0; i < numverts_dst; i++) {
-					float tmp_co[3];
-
 					copy_v3_v3(tmp_co, verts_dst[i].co);
 
 					/* Convert the vertex to tree coordinates, if needed. */
@@ -656,6 +649,7 @@ void BKE_mesh_remap_calc_edges_from_dm(
 		BVHTreeNearest nearest = {0};
 		BVHTreeRayHit rayhit = {0};
 		float hit_dist;
+		float tmp_co[3], tmp_no[3];
 
 		if (mode == MREMAP_MODE_EDGE_VERT_NEAREST) {
 			const int num_verts_src = dm_src->getNumVerts(dm_src);
@@ -694,8 +688,6 @@ void BKE_mesh_remap_calc_edges_from_dm(
 
 					/* Compute closest verts only once! */
 					if (v_dst_to_src_map[vidx_dst].hit_dist == -1.0f) {
-						float tmp_co[3];
-
 						copy_v3_v3(tmp_co, verts_dst[vidx_dst].co);
 
 						/* Convert the vertex to tree coordinates, if needed. */
@@ -786,8 +778,6 @@ void BKE_mesh_remap_calc_edges_from_dm(
 			nearest.index = -1;
 
 			for (i = 0; i < numedges_dst; i++) {
-				float tmp_co[3];
-
 				interp_v3_v3v3(tmp_co, verts_dst[edges_dst[i].v1].co, verts_dst[edges_dst[i].v2].co, 0.5f);
 
 				/* Convert the vertex to tree coordinates, if needed. */
@@ -814,8 +804,6 @@ void BKE_mesh_remap_calc_edges_from_dm(
 			bvhtree_from_mesh_looptri(&treedata, dm_src, 0.0f, 2, 6);
 
 			for (i = 0; i < numedges_dst; i++) {
-				float tmp_co[3];
-
 				interp_v3_v3v3(tmp_co, verts_dst[edges_dst[i].v1].co, verts_dst[edges_dst[i].v2].co, 0.5f);
 
 				/* Convert the vertex to tree coordinates, if needed. */
@@ -872,8 +860,8 @@ void BKE_mesh_remap_calc_edges_from_dm(
 				/* For each dst edge, we sample some rays from it (interpolated from its vertices)
 				 * and use their hits to interpolate from source edges. */
 				const MEdge *me = &edges_dst[i];
-				float tmp_co[3], v1_co[3], v2_co[3];
-				float tmp_no[3], v1_no[3], v2_no[3];
+				float v1_co[3], v2_co[3];
+				float v1_no[3], v2_no[3];
 
 				int grid_size;
 				float edge_dst_len;
@@ -1150,6 +1138,7 @@ void BKE_mesh_remap_calc_loops_from_dm(
 		BVHTreeRayHit rayhit = {0};
 		int num_trees = 0;
 		float hit_dist;
+		float tmp_co[3], tmp_no[3];
 
 		const bool use_from_vert = (mode & MREMAP_USE_VERT);
 
@@ -1440,13 +1429,18 @@ void BKE_mesh_remap_calc_loops_from_dm(
 		}
 
 		for (pidx_dst = 0, mp_dst = polys_dst; pidx_dst < numpolys_dst; pidx_dst++, mp_dst++) {
-			float (*pnor_dst)[3] = &poly_nors_dst[pidx_dst];
+			float pnor_dst[3];
 
 			/* Only in use_from_vert case, we may need polys' centers as fallback in case we cannot decide which
 			 * corner to use from normals only. */
 			float pcent_dst[3];
 			bool pcent_dst_valid = false;
 
+			if (mode == MREMAP_MODE_LOOP_NEAREST_POLYNOR) {
+				copy_v3_v3(pnor_dst, poly_nors_dst[pidx_dst]);
+				BLI_space_transform_apply_normal(space_transform, pnor_dst);
+			}
+
 			if ((size_t)mp_dst->totloop > islands_res_buff_size) {
 				islands_res_buff_size = (size_t)mp_dst->totloop + MREMAP_DEFAULT_BUFSIZE;
 				for (tindex = 0; tindex < num_trees; tindex++) {
@@ -1460,7 +1454,6 @@ void BKE_mesh_remap_calc_loops_from_dm(
 				ml_dst = &loops_dst[mp_dst->loopstart];
 				for (plidx_dst = 0; plidx_dst < mp_dst->totloop; plidx_dst++, ml_dst++) {
 					if (use_from_vert) {
-						float tmp_co[3];
 						MeshElemMap *vert_to_refelem_map_src = NULL;
 
 						copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co);
@@ -1479,12 +1472,14 @@ void BKE_mesh_remap_calc_loops_from_dm(
 							int best_index_src = -1;
 
 							if (mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) {
-								nor_dst = &loop_nors_dst[plidx_dst + mp_dst->loopstart];
+								copy_v3_v3(tmp_no, loop_nors_dst[plidx_dst + mp_dst->loopstart]);
+								BLI_space_transform_apply_normal(space_transform, tmp_no);
+								nor_dst = &tmp_no;
 								nors_src = loop_nors_src;
 								vert_to_refelem_map_src = vert_to_loop_map_src;
 							}
 							else {  /* if (mode == MREMAP_MODE_LOOP_NEAREST_POLYNOR) { */
-								nor_dst = pnor_dst;
+								nor_dst = &pnor_dst;
 								nors_src = poly_nors_src;
 								vert_to_refelem_map_src = vert_to_poly_map_src;
 							}
@@ -1556,8 +1551,6 @@ void BKE_mesh_remap_calc_loops_from_dm(
 						}
 					}
 					else if (mode & MREMAP_USE_NORPROJ) {
-						float tmp_co[3], tmp_no[3];
-
 						int n = (ray_radius > 0.0f) ? MREMAP_RAYCAST_APPROXIMATE_NR : 1;
 						float w = 1.0f;
 
@@ -1615,8 +1608,6 @@ void BKE_mesh_remap_calc_loops_from_dm(
 						}
 					}
 					else {  /* Nearest poly either to use all its loops/verts or just closest one. */
-						float tmp_co[3];
-
 						copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co);
 						nearest.index = -1;
 
@@ -1739,7 +1730,6 @@ void BKE_mesh_remap_calc_loops_from_dm(
 										 * Note we could be much more subtle here, again that's for later... */
 										int j;
 										float best_dist_sq = FLT_MAX;
-										float tmp_co[3];
 
 										ml_dst = &loops_dst[lidx_dst];
 										copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co);
@@ -1824,7 +1814,6 @@ void BKE_mesh_remap_calc_loops_from_dm(
 										/* Find a new valid loop in that new poly (nearest point on poly for now).
 										 * Note we could be much more subtle here, again that's for later... */
 										float best_dist_sq = FLT_MAX;
-										float tmp_co[3];
 										int j;
 
 										ml_dst = &loops_dst[lidx_dst];
@@ -1987,6 +1976,7 @@ void BKE_mesh_remap_calc_polys_from_dm(
 	const float full_weight = 1.0f;
 	const float max_dist_sq = max_dist * max_dist;
 	float (*poly_nors_dst)[3] = NULL;
+	float tmp_co[3], tmp_no[3];
 	int i;
 
 	BLI_assert(mode & MREMAP_MODE_POLY);
@@ -2028,7 +2018,6 @@ void BKE_mesh_remap_calc_polys_from_dm(
 
 			for (i = 0; i < numpolys_dst; i++) {
 				MPoly *mp = &polys_dst[i];
-				float tmp_co[3];
 
 				BKE_mesh_calc_poly_center(mp, &loops_dst[mp->loopstart], verts_dst, tmp_co);
 
@@ -2055,7 +2044,6 @@ void BKE_mesh_remap_calc_polys_from_dm(
 
 			for (i = 0; i < numpolys_dst; i++) {
 				MPoly *mp = &polys_dst[i];
-				float tmp_co[3], tmp_no[3];
 
 				BKE_mesh_calc_poly_center(mp, &loops_dst[mp->loopstart], verts_dst, tmp_co);
 				copy_v3_v3(tmp_no, poly_nors_dst[i]);
@@ -2104,7 +2092,6 @@ void BKE_mesh_remap_calc_polys_from_dm(
 				 * and use their hits to interpolate from source polys. */
 				/* Note: dst poly is early-converted into src space! */
 				MPoly *mp = &polys_dst[i];
-				float tmp_co[3], tmp_no[3];
 
 				int tot_rays, done_rays = 0;
 				float poly_area_2d_inv, done_area = 0.0f;
diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c
index 151889b..a1669c7 100644
--- a/source/blender/blenkernel/intern/packedFile.c
+++ b/source/blender/blenkernel/intern/packedFile.c
@@ -582,7 +582,7 @@ int unpackImage(ReportList *reports, Image *ima, int how)
 {
 	int ret_value = RET_ERROR;
 
-	if (ima != NULL && ima->name[0]) {
+	if (ima != NULL) {
 		while (ima->packedfiles.last) {
 			char localname[FILE_MAX], absname[FILE_MAX];
 			char *newname;
@@ -605,7 +605,9 @@ int unpackImage(ReportList *reports, Image *ima, int how)
 				}
 
 				/* keep the new name in the image for non-pack specific reasons */
-				BLI_strncpy(ima->name, newname, sizeof(imapf->filepath));
+				if (how != PF_REMOVE) {
+					BLI_strncpy(ima->name, newname, sizeof(imapf->filepath));
+				}
 				MEM_freeN(newname);
 			}
 			else {
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index dfdab89..ca6dcb4 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -3444,7 +3444,7 @@ static ImBuf *seq_render_strip(const SeqRenderData *context, Sequence *seq, floa
 	float nr = give_stripelem_index(seq, cfra);
 	/* all effects are handled similarly with the exception of speed effect */
 	int type = (seq->type & SEQ_TYPE_EFFECT && seq->type != SEQ_TYPE_SPEED) ? SEQ_TYPE_EFFECT : seq->type;
-	bool is_preprocessed = !ELEM(type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE, SEQ_TYPE_SCENE);
+	bool is_preprocessed = !ELEM(type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE, SEQ_TYPE_SCENE, SEQ_TYPE_MOVIECLIP);
 
 	ibuf = BKE_sequencer_cache_get(context, seq, cfra, SEQ_STRIPELEM_IBUF);
 
diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c
index cec455e..cc39a1b 100644
--- a/source/blender/blenkernel/intern/writeavi.c
+++ b/source/blender/blenkernel/intern/writeavi.c
@@ -213,8 +213,6 @@ static int start_avi(void *context_v, Scene *UNUSED(scene), RenderData *rd, int
 
 	if (AVI_open_compress(name, avi, 1, format) != AVI_ERROR_NONE) {
 		BKE_report(reports, RPT_ERROR, "Cannot open or start AVI movie file");
-		MEM_freeN(avi);
-		avi = NULL;
 		return 0;
 	}
 			
diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c
index bc734a9..a2fa201 100644
--- a/source/blender/blenkernel/intern/writeffmpeg.c
+++ b/source/blender/blenkernel/intern/writeffmpeg.c
@@ -809,7 +809,7 @@ static int start_ffmpeg_impl(FFMpegContext *context, struct RenderData *rd, int
 	AVFormatContext *of;
 	AVOutputFormat *fmt;
 	AVDictionary *opts = NULL;
-	char name[256], error[1024];
+	char name[FILE_MAX], error[1024];
 	const char **exts;
 
 	context->ffmpeg_type = rd->ffcodecdata.type;
@@ -847,7 +847,10 @@ static int start_ffmpeg_impl(FFMpegContext *context, struct RenderData *rd, int
 		BKE_report(reports, RPT_ERROR, "Error opening output file");
 		return 0;
 	}
-	
+
+
+	/* Returns after this must 'goto fail;' */
+
 	of->oformat = fmt;
 	of->packet_size = rd->ffcodecdata.mux_packet_size;
 	if (context->ffmpeg_audio_codec != AV_CODEC_ID_NONE) {
@@ -900,15 +903,15 @@ static int start_ffmpeg_impl(FFMpegContext *context, struct RenderData *rd, int
 	if (fmt->video_codec == AV_CODEC_ID_DVVIDEO) {
 		if (rectx != 720) {
 			BKE_report(reports, RPT_ERROR, "Render width has to be 720 pixels for DV!");
-			return 0;
+			goto fail;
 		}
 		if (rd->frs_sec != 25 && recty != 480) {
 			BKE_report(reports, RPT_ERROR, "Render height has to be 480 pixels for DV-NTSC!");
-			return 0;
+			goto fail;
 		}
 		if (rd->frs_sec == 25 && recty != 576) {
 			BKE_report(reports, RPT_ERROR, "Render height has to be 576 pixels for DV-PAL!");
-			return 0;
+			goto fail;
 		}
 	}
 	
@@ -916,8 +919,7 @@ static int start_ffmpeg_impl(FFMpegContext *context, struct RenderData *rd, int
 		fmt->audio_codec = AV_CODEC_ID_PCM_S16LE;
 		if (context->ffmpeg_audio_codec != AV_CODEC_ID_NONE && rd->ffcodecdata.audio_mixrate != 48000 && rd->ffcodecdata.audio_channels != 2) {
 			BKE_report(reports, RPT_ERROR, "FFMPEG only supports 48khz / stereo audio for DV!");
-			av_dict_free(&opts);
-			return 0;
+			goto fail;
 		}
 	}
 	
@@ -929,9 +931,7 @@ static int start_ffmpeg_impl(FFMpegContext *context, struct RenderData *rd, int
 				BKE_report(reports, RPT_ERROR, error);
 			else
 				BKE_report(reports, RPT_ERROR, "Error initializing video stream");
-
-			av_dict_free(&opts);
-			return 0;
+			goto fail;
 		}
 	}
 
@@ -942,22 +942,18 @@ static int start_ffmpeg_impl(FFMpegContext *context, struct RenderData *rd, int
 				BKE_report(reports, RPT_ERROR, error);
 			else
 				BKE_report(reports, RPT_ERROR, "Error initializing audio stream");
-			av_dict_free(&opts);
-			return 0;
+			goto fail;
 		}
 	}
 	if (!(fmt->flags & AVFMT_NOFILE)) {
 		if (avio_open(&of->pb, name, AVIO_FLAG_WRITE) < 0) {
 			BKE_report(reports, RPT_ERROR, "Could not open file for writing");
-			av_dict_free(&opts);
-			return 0;
+			goto fail;
 		}
 	}
 	if (avformat_write_header(of, NULL) < 0) {
 		BKE_report(reports, RPT_ERROR, "Could not initialize streams, probably unsupported codec combination");
-		av_dict_free(&opts);
-		avio_close(of->pb);
-		return 0;
+		goto fail;
 	}
 
 	context->outfile = of;
@@ -965,6 +961,26 @@ static int start_ffmpeg_impl(FFMpegContext *context, struct RenderData *rd, int
 	av_dict_free(&opts);
 
 	return 1;
+
+
+fail:
+	if (of->pb) {
+		avio_close(of->pb);
+	}
+
+	if (context->video_stream && context->video_stream->codec) {
+		avcodec_close(context->video_stream->codec);
+		context->video_stream = NULL;
+	}
+
+	if (context->audio_stream && context->audio_stream->codec) {
+		avcodec_close(context->audio_stream->codec);
+		context->audio_stream = NULL;
+	}
+
+	av_dict_free(&opts);
+	avformat_free_context(of);
+	return 0;
 }
 
 /**
@@ -1234,6 +1250,11 @@ static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit)
 		context->video_stream = 0;
 	}
 
+	if (context->audio_stream && context->audio_stream->codec) {
+		avcodec_close(context->audio_stream->codec);
+		context->audio_stream = 0;
+	}
+
 	/* free the temp buffer */
 	if (context->current_frame) {
 		delete_picture(context->current_frame);
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index dad2a2f..e005809 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -1384,16 +1384,14 @@ bool isect_ray_tri_watertight_v3(
 	const float cy = c_ky - sy * c_kz;
 
 	/* Calculate scaled barycentric coordinates. */
-	float u = cx * by - cy * bx;
-	int sign_mask = (float_as_int(u) & (int)0x80000000);
-	float v = ax * cy - ay * cx;
-	float w, det;
+	const float u = cx * by - cy * bx;
+	const float v = ax * cy - ay * cx;
+	const float w = bx * ay - by * ax;
+	float det;
 
-	if (sign_mask != (float_as_int(v) & (int)0x80000000)) {
-		return false;
-	}
-	w = bx * ay - by * ax;
-	if (sign_mask != (float_as_int(w) & (int)0x80000000)) {
+	if ((u < 0.0f || v < 0.0f || w < 0.0f) &&
+	    (u > 0.0f || v > 0.0f || w > 0.0f))
+	{
 		return false;
 	}
 
@@ -1406,8 +1404,9 @@ bool isect_ray_tri_watertight_v3(
 		/* Calculate scaled z-coordinates of vertices and use them to calculate
 		 * the hit distance.
 		 */
+		const int sign_det = (float_as_int(det) & (int)0x80000000);
 		const float t = (u * a_kz + v * b_kz + w * c_kz) * sz;
-		const float sign_t = xor_fl(t, sign_mask);
+		const float sign_t = xor_fl(t, sign_det);
 		if ((sign_t < 0.0f)
 		    /* differ from Cycles, don't read r_lambda's original value
 		     * otherwise we won't match any of the other intersect functions here...
diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c
index 4692af0..7c3af302 100644
--- a/source/blender/blenlib/intern/path_util.c
+++ b/source/blender/blenlib/intern/path_util.c
@@ -191,31 +191,6 @@ int BLI_split_name_num(char *left, int *nr, const char *name, const char delim)
 }
 
 /**
- * Looks for a string of digits within name (using BLI_stringdec) and adjusts it by add.
- */
-void BLI_newname(char *name, int add)
-{
-	char head[UNIQUE_NAME_MAX], tail[UNIQUE_NAME_MAX];
-	int pic;
-	unsigned short digits;
-	
-	pic = BLI_stringdec(name, head, tail, &digits);
-	
-	/* are we going from 100 -> 99 or from 10 -> 9 */
-	if (add < 0 && digits < 4 && digits > 0) {
-		int i, exp;
-		exp = 1;
-		for (i = digits; i > 1; i--) exp *= 10;
-		if (pic >= exp && (pic + add) < exp) digits--;
-	}
-	
-	pic += add;
-	
-	if (digits == 4 && pic < 0) pic = 0;
-	BLI_stringenc(name, head, tail, digits, pic);
-}
-
-/**
  * Ensures name is unique (according to criteria specified by caller in unique_check callback),
  * incrementing its numeric suffix as necessary. Returns true if name had to be adjusted.
  *
@@ -453,6 +428,8 @@ void BLI_cleanup_file(const char *relabase, char *path)
  *
  * \note Space case ' ' is a bit of an edge case here - in theory it is allowed, but again can be an issue
  *       in some cases, so we simply replace it by an underscore too (good practice anyway).
+ *       REMOVED based on popular demand (see T45900).
+ *       Percent '%' char is a bit same case - not recommended to use it, but supported by all decent FS/OS around...
  *
  * \note On Windows, it also ensures there is no '.' (dot char) at the end of the file, this can lead to issues...
  *
@@ -461,9 +438,9 @@ void BLI_cleanup_file(const char *relabase, char *path)
  */
 bool BLI_filename_make_safe(char *fname)
 {
-	const char *invalid =     "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+	const char *invalid = "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
 	                      "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
-	                      "/\\?%*:|\"<> ";
+	                      "/\\?*:|\"<>";
 	char *fn;
 	bool changed = false;
 
diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c
index 25074ef..947f945 100644
--- a/source/blender/blenloader/intern/versioning_260.c
+++ b/source/blender/blenloader/intern/versioning_260.c
@@ -343,7 +343,7 @@ static void do_versions_mesh_mloopcol_swap_2_62_1(Mesh *me)
 		if (layer->type == CD_MLOOPCOL) {
 			mloopcol = (MLoopCol *)layer->data;
 			for (i = 0; i < me->totloop; i++, mloopcol++) {
-				SWAP(char, mloopcol->r, mloopcol->b);
+				SWAP(unsigned char, mloopcol->r, mloopcol->b);
 			}
 		}
 	}
diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c
index 17b6d1d..cd3c832 100644
--- a/source/blender/bmesh/intern/bmesh_marking.c
+++ b/source/blender/bmesh/intern/bmesh_marking.c
@@ -102,6 +102,7 @@ static bool bm_vert_is_edge_select_any(const BMVert *v)
 }
 #endif
 
+#if 0
 static bool bm_edge_is_face_select_any_other(BMLoop *l_first)
 {
 	const BMLoop *l_iter = l_first;
@@ -114,6 +115,7 @@ static bool bm_edge_is_face_select_any_other(BMLoop *l_first)
 	}
 	return false;
 }
+#endif
 
 #if 0
 static bool bm_edge_is_face_select_any(const BMEdge *e)
@@ -498,6 +500,20 @@ void BM_face_select_set(BMesh *bm, BMFace *f, const bool select)
 			BM_elem_flag_disable(f, BM_ELEM_SELECT);
 			bm->totfacesel -= 1;
 		}
+		/**
+		 * \note This allows a temporarily invalid state - where for eg
+		 * an edge bay be de-selected, but an adjacent face remains selected.
+		 *
+		 * Rely on #BM_mesh_select_mode_flush to correct these cases.
+		 */
+#if 1
+		l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+		do {
+			BM_vert_select_set(bm, l_iter->v, false);
+			BM_edge_select_set(bm, l_iter->e, false);
+		} while ((l_iter = l_iter->next) != l_first);
+#else
+		/* disabled, see T46494 */
 
 		/* flush down to edges */
 		l_iter = l_first = BM_FACE_FIRST_LOOP(f);
@@ -515,6 +531,7 @@ void BM_face_select_set(BMesh *bm, BMFace *f, const bool select)
 				BM_vert_select_set(bm, l_iter->v, false);
 			}
 		} while ((l_iter = l_iter->next) != l_first);
+#endif
 	}
 }
 
diff --git a/source/blender/collada/ArmatureImporter.cpp b/source/blender/collada/ArmatureImporter.cpp
index 6ddce75..fd08e1e 100644
--- a/source/blender/collada/ArmatureImporter.cpp
+++ b/source/blender/collada/ArmatureImporter.cpp
@@ -255,9 +255,13 @@ void ArmatureImporter::connect_bone_chains(bArmature *armature, Bone *parentbone
 {
 	BoneExtended *dominant_child = NULL;
 	int maxlen = 0;
-	Bone *child = (Bone *)parentbone->childbase.first;
-	if (child && (import_settings->find_chains || child->next==NULL) )
-	{
+	Bone *child;
+
+	if (parentbone == NULL)
+		return;
+
+	child = (Bone *)parentbone->childbase.first;
+	if (child && (import_settings->find_chains || child->next==NULL)) {
 		for (; child; child = child->next) {
 			BoneExtended *be = extended_bones[child->name];
 			if (be != NULL) {
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 7802161..671c590 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -1100,7 +1100,7 @@ static bool ui_but_event_property_operator_string(const bContext *C, uiBut *but,
 			
 			/* check each until one works... */
 			for (i = 0; (i < num_ops) && (ctx_toggle_opnames[i]); i++) {
-				//printf("\t%s\n", ctx_toggle_opnames[i]);
+				printf("\t%s\n", ctx_toggle_opnames[i]);
 				if (WM_key_event_operator_string(C, ctx_toggle_opnames[i], WM_OP_INVOKE_REGION_WIN, prop_path, false,
 				                                 buf_len, buf))
 				{
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 3fd2ba6..1b52140 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -7517,8 +7517,14 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s
 	else if (data->state == BUTTON_STATE_NUM_EDITING) {
 		ui_numedit_end(but, data);
 
-		if (but->flag & UI_BUT_DRIVEN)
-			WM_report(C, RPT_INFO, "Can't edit driven number value, see graph editor for the driver setup.");
+		if (but->flag & UI_BUT_DRIVEN) {
+			/* Only warn when editing stepping/dragging the value.
+			 * No warnings should show for editing driver expressions though!
+			 */
+			if (state != BUTTON_STATE_TEXT_EDITING) {
+				WM_report(C, RPT_INFO, "Can't edit driven number value, see graph editor for the driver setup.");
+			}
+		}
 
 		if (ui_but_is_cursor_warp(but)) {
 
diff --git a/source/blender/editors/mask/mask_edit.c b/source/blender/editors/mask/mask_edit.c
index e1a58d5..9a2635c 100644
--- a/source/blender/editors/mask/mask_edit.c
+++ b/source/blender/editors/mask/mask_edit.c
@@ -403,6 +403,10 @@ bool ED_mask_selected_minmax(const bContext *C, float min[2], float max[2])
 	Mask *mask = CTX_data_edit_mask(C);
 	MaskLayer *mask_layer;
 	bool ok = false;
+
+	if (mask == NULL)
+		return ok;
+
 	INIT_MINMAX2(min, max);
 	for (mask_layer = mask->masklayers.first;
 	     mask_layer != NULL;
diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c
index c718dfa..9235dd4 100644
--- a/source/blender/editors/render/render_opengl.c
+++ b/source/blender/editors/render/render_opengl.c
@@ -228,13 +228,8 @@ static void screen_opengl_views_setup(OGLRender *oglrender)
 	}
 
 	BLI_lock_thread(LOCK_DRAW_IMAGE);
-	if (is_multiview && BKE_scene_multiview_is_stereo3d(rd)) {
-		oglrender->ima->flag |= IMA_IS_STEREO;
-	}
-	else {
-		oglrender->ima->flag &= ~IMA_IS_STEREO;
+	if (!(is_multiview && BKE_scene_multiview_is_stereo3d(rd)))
 		oglrender->iuser.flag &= ~IMA_SHOW_STEREO;
-	}
 	BLI_unlock_thread(LOCK_DRAW_IMAGE);
 
 	/* will only work for non multiview correctly */
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index 569d611..71f6064 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -42,6 +42,7 @@
 
 #include "BKE_context.h"
 #include "BKE_depsgraph.h"
+#include "BKE_image.h"
 #include "BKE_global.h"
 #include "BKE_library.h"
 #include "BKE_main.h"
@@ -2195,7 +2196,7 @@ bool ED_screen_stereo3d_required(bScreen *screen)
 				/* images should always show in stereo, even if
 				 * the file doesn't have views enabled */
 				sima = sa->spacedata.first;
-				if (sima->image && (sima->image->flag & IMA_IS_STEREO) &&
+				if (sima->image && BKE_image_is_stereo(sima->image) &&
 				    (sima->iuser.flag & IMA_SHOW_STEREO))
 				{
 					return true;
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index f1489f2..73a3cce 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -4324,7 +4324,7 @@ static void do_projectpaint_soften(ProjPaintState *ps, ProjPixel *projPixel, flo
 		}
 		else {
 			premul_float_to_straight_uchar(rgba_ub, rgba);
-			blend_color_interpolate_byte(rgba_ub, rgba_ub, projPixel->pixel.ch_pt, mask);
+			blend_color_interpolate_byte(rgba_ub, projPixel->pixel.ch_pt, rgba_ub, mask);
 		}
 		BLI_linklist_prepend_arena(softenPixels, (void *)projPixel, softenArena);
 	}
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index 08b6564..328b09d 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -1973,6 +1973,37 @@ void FILE_OT_bookmark_toggle(struct wmOperatorType *ot)
 }
 
 
+/**
+ * Looks for a string of digits within name (using BLI_stringdec) and adjusts it by add.
+ */
+static void filenum_newname(char *name, size_t name_size, int add)
+{
+	char head[FILE_MAXFILE], tail[FILE_MAXFILE];
+	char name_temp[FILE_MAXFILE];
+	int pic;
+	unsigned short digits;
+
+	pic = BLI_stringdec(name, head, tail, &digits);
+
+	/* are we going from 100 -> 99 or from 10 -> 9 */
+	if (add < 0 && digits > 0) {
+		int i, exp;
+		exp = 1;
+		for (i = digits; i > 1; i--) {
+			exp *= 10;
+		}
+		if (pic >= exp && (pic + add) < exp) {
+			digits--;
+		}
+	}
+
+	pic += add;
+	if (pic < 0)
+		pic = 0;
+	BLI_stringenc(name_temp, head, tail, digits, pic);
+	BLI_strncpy(name, name_temp, name_size);
+}
+
 static int file_filenum_exec(bContext *C, wmOperator *op)
 {
 	SpaceFile *sfile = CTX_wm_space_file(C);
@@ -1980,7 +2011,7 @@ static int file_filenum_exec(bContext *C, wmOperator *op)
 	
 	int inc = RNA_int_get(op->ptr, "increment");
 	if (sfile->params && (inc != 0)) {
-		BLI_newname(sfile->params->file, inc);
+		filenum_newname(sfile->params->file, sizeof(sfile->params->file), inc);
 		ED_area_tag_redraw(sa);
 		file_draw_check(C);
 		// WM_event_add_notifier(C, NC_WINDOW, NULL);
diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c
index 8e5c85d..07c16fa 100644
--- a/source/blender/editors/space_graph/graph_ops.c
+++ b/source/blender/editors/space_graph/graph_ops.c
@@ -166,6 +166,8 @@ static int graphview_cursor_modal(bContext *C, wmOperator *op, const wmEvent *ev
 		case ESCKEY:
 			if (screen)
 				screen->scrubbing = false;
+			
+			WM_event_add_notifier(C, NC_SCENE | ND_FRAME, CTX_data_scene(C));
 			return OPERATOR_FINISHED;
 		
 		case MOUSEMOVE:
@@ -183,6 +185,8 @@ static int graphview_cursor_modal(bContext *C, wmOperator *op, const wmEvent *ev
 			if (event->val == KM_RELEASE) {
 				if (screen)
 					screen->scrubbing = false;
+				
+				WM_event_add_notifier(C, NC_SCENE | ND_FRAME, CTX_data_scene(C));
 				return OPERATOR_FINISHED;
 			}
 			break;
diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c
index 4c7ac53..ea5cd56 100644
--- a/source/blender/editors/space_graph/space_graph.c
+++ b/source/blender/editors/space_graph/space_graph.c
@@ -240,7 +240,7 @@ static void graph_main_area_draw(const bContext *C, ARegion *ar)
 	UI_view2d_view_ortho(v2d);
 	
 	/* grid */
-	unitx = (sipo->flag & SIPO_DRAWTIME) ? V2D_UNIT_SECONDS : V2D_UNIT_FRAMESCALE;
+	unitx = ((sipo->mode == SIPO_MODE_ANIMATION) && (sipo->flag & SIPO_DRAWTIME)) ? V2D_UNIT_SECONDS : V2D_UNIT_FRAMESCALE;
 	grid = UI_view2d_grid_calc(CTX_data_scene(C), v2d, unitx, V2D_GRID_NOCLAMP, unity, V2D_GRID_NOCLAMP, ar->winx, ar->winy);
 	UI_view2d_grid_draw(v2d, grid, V2D_GRIDLINES_ALL);
 	
diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c
index 6b5cc38..2f87d43 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -715,8 +715,8 @@ static void uiblock_layer_pass_buttons(uiLayout *layout, Image *image, RenderRes
 	}
 
 	/* stereo image */
-	else if (((image->flag & IMA_IS_STEREO) && (!show_stereo)) ||
-	         ((image->flag & IMA_IS_MULTIVIEW) && ((image->flag & IMA_IS_STEREO) == 0)))
+	else if ((BKE_image_is_stereo(image) && (!show_stereo)) ||
+	         (BKE_image_is_multiview(image) && !BKE_image_is_stereo(image)))
 	{
 		ImageView *iv;
 		int nr = 0;
diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c
index 3a178ed..792b1e7 100644
--- a/source/blender/editors/space_image/image_draw.c
+++ b/source/blender/editors/space_image/image_draw.c
@@ -813,7 +813,7 @@ void draw_image_main(const bContext *C, ARegion *ar)
 	show_viewer = (ima && ima->source == IMA_SRC_VIEWER) != 0;
 	show_render = (show_viewer && ima->type == IMA_TYPE_R_RESULT) != 0;
 	show_paint = (ima && (sima->mode == SI_MODE_PAINT) && (show_viewer == false) && (show_render == false));
-	show_stereo3d = (ima && (ima->flag & IMA_IS_STEREO) && (sima->iuser.flag & IMA_SHOW_STEREO));
+	show_stereo3d = (ima && BKE_image_is_stereo(ima) && (sima->iuser.flag & IMA_SHOW_STEREO));
 	show_multilayer = ima && BKE_image_is_multilayer(ima);
 
 	if (show_viewer) {
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 3c5aff4..faba61c 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -1153,8 +1153,6 @@ static int image_open_exec(bContext *C, wmOperator *op)
 	}
 	else {
 		ima->flag &= ~IMA_USE_VIEWS;
-		ima->flag &= ~IMA_IS_STEREO;
-		ima->flag &= ~IMA_IS_MULTIVIEW;
 		BKE_image_free_views(ima);
 	}
 
@@ -1703,7 +1701,7 @@ static bool save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI
 		/* we need renderresult for exr and rendered multiview */
 		scene = CTX_data_scene(C);
 		rr = BKE_image_acquire_renderresult(scene, ima);
-		is_mono = rr ? BLI_listbase_count_ex(&rr->views, 2) < 2 : (ima->flag & IMA_IS_MULTIVIEW) == 0;
+		is_mono = rr ? BLI_listbase_count_ex(&rr->views, 2) < 2 : BLI_listbase_count_ex(&ima->views, 2) < 2;
 
 		/* error handling */
 		if (!rr) {
@@ -1714,7 +1712,7 @@ static bool save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI
 		}
 		else {
 			if (imf->views_format == R_IMF_VIEWS_STEREO_3D) {
-				if ((ima->flag & IMA_IS_STEREO) == 0) {
+				if (!BKE_image_is_stereo(ima)) {
 					BKE_reportf(op->reports, RPT_ERROR, "Did not write, the image doesn't have a \"%s\" and \"%s\" views",
 					           STEREO_LEFT_NAME, STEREO_RIGHT_NAME);
 					goto cleanup;
@@ -1959,9 +1957,9 @@ static int image_save_as_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS
 
 	/* show multiview save options only if image has multiviews */
 	prop = RNA_struct_find_property(op->ptr, "show_multiview");
-	RNA_property_boolean_set(op->ptr, prop, (ima->flag & IMA_IS_MULTIVIEW) != 0);
+	RNA_property_boolean_set(op->ptr, prop, BKE_image_is_multiview(ima));
 	prop = RNA_struct_find_property(op->ptr, "use_multiview");
-	RNA_property_boolean_set(op->ptr, prop, (ima->flag & IMA_IS_MULTIVIEW) != 0);
+	RNA_property_boolean_set(op->ptr, prop, BKE_image_is_multiview(ima));
 
 	image_filesel(C, op, simopts.filepath);
 
diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h
index c89a1bb..f10e6be 100644
--- a/source/blender/editors/space_outliner/outliner_intern.h
+++ b/source/blender/editors/space_outliner/outliner_intern.h
@@ -150,8 +150,15 @@ int outliner_item_do_activate(struct bContext *C, int x, int y, bool extend, boo
 
 /* outliner_edit.c ---------------------------------------------- */
 
-void outliner_do_object_operation(struct bContext *C, struct Scene *scene, struct SpaceOops *soops, struct ListBase *lb, 
-                                  void (*operation_cb)(struct bContext *C, struct Scene *scene, struct TreeElement *, struct TreeStoreElem *, TreeStoreElem *));
+void outliner_do_object_operation_ex(
+        struct bContext *C, struct Scene *scene, struct SpaceOops *soops, struct ListBase *lb,
+        void (*operation_cb)(struct bContext *C, struct Scene *scene,
+                             struct TreeElement *, struct TreeStoreElem *, TreeStoreElem *),
+        bool recurse_selected);
+void outliner_do_object_operation(
+        struct bContext *C, struct Scene *scene, struct SpaceOops *soops, struct ListBase *lb,
+        void (*operation_cb)(struct bContext *C, struct Scene *scene,
+                             struct TreeElement *, struct TreeStoreElem *, TreeStoreElem *));
 
 int common_restrict_check(struct bContext *C, struct Object *ob);
 
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index 50171d7..863f09d 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -516,15 +516,20 @@ static void group_instance_cb(bContext *C, Scene *scene, TreeElement *UNUSED(te)
 	id_lib_extern(&group->id);
 }
 
-void outliner_do_object_operation(bContext *C, Scene *scene_act, SpaceOops *soops, ListBase *lb, 
-                                  void (*operation_cb)(bContext *C, Scene *scene, TreeElement *,
-                                                       TreeStoreElem *, TreeStoreElem *))
+/**
+ * \param select_recurse: Set to false for operations which are already recursively operating on their children.
+ */
+void outliner_do_object_operation_ex(
+        bContext *C, Scene *scene_act, SpaceOops *soops, ListBase *lb,
+        void (*operation_cb)(bContext *C, Scene *scene, TreeElement *,
+                             TreeStoreElem *, TreeStoreElem *),
+        bool select_recurse)
 {
 	TreeElement *te;
-	TreeStoreElem *tselem;
 	
 	for (te = lb->first; te; te = te->next) {
-		tselem = TREESTORE(te);
+		TreeStoreElem *tselem = TREESTORE(te);
+		bool select_handled = false;
 		if (tselem->flag & TSE_SELECTED) {
 			if (tselem->type == 0 && te->idcode == ID_OB) {
 				// when objects selected in other scenes... dunno if that should be allowed
@@ -536,14 +541,25 @@ void outliner_do_object_operation(bContext *C, Scene *scene_act, SpaceOops *soop
 				 * only use 'scene_act' when 'scene_owner' is NULL, which can happen when the
 				 * outliner isn't showing scenes: Visible Layer draw mode for eg. */
 				operation_cb(C, scene_owner ? scene_owner : scene_act, te, NULL, tselem);
+				select_handled = true;
 			}
 		}
 		if (TSELEM_OPEN(tselem, soops)) {
-			outliner_do_object_operation(C, scene_act, soops, &te->subtree, operation_cb);
+			if ((select_handled == false) || select_recurse) {
+				outliner_do_object_operation_ex(C, scene_act, soops, &te->subtree, operation_cb, select_recurse);
+			}
 		}
 	}
 }
 
+void outliner_do_object_operation(
+        bContext *C, Scene *scene_act, SpaceOops *soops, ListBase *lb,
+        void (*operation_cb)(bContext *C, Scene *scene, TreeElement *,
+                             TreeStoreElem *, TreeStoreElem *))
+{
+	outliner_do_object_operation_ex(C, scene_act, soops, lb, operation_cb, true);
+}
+
 /* ******************************************** */
 
 static void clear_animdata_cb(int UNUSED(event), TreeElement *UNUSED(te),
@@ -876,7 +892,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
 	}
 	else if (event == OL_OP_SELECT_HIERARCHY) {
 		Scene *sce = scene;  // to be able to delete, scenes are set...
-		outliner_do_object_operation(C, scene, soops, &soops->tree, object_select_hierarchy_cb);
+		outliner_do_object_operation_ex(C, scene, soops, &soops->tree, object_select_hierarchy_cb, false);
 		if (scene != sce) {
 			ED_screen_set_scene(C, CTX_wm_screen(C), sce);
 		}	
@@ -903,7 +919,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
 		WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
 	}
 	else if (event == OL_OP_DELETE_HIERARCHY) {
-		outliner_do_object_operation(C, scene, soops, &soops->tree, object_delete_hierarchy_cb);
+		outliner_do_object_operation_ex(C, scene, soops, &soops->tree, object_delete_hierarchy_cb, false);
 
 		/* XXX: See OL_OP_DELETE comment above. */
 		outliner_cleanup_tree(soops);
diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c
index d806dfa..10c75eb 100644
--- a/source/blender/editors/space_view3d/drawmesh.c
+++ b/source/blender/editors/space_view3d/drawmesh.c
@@ -410,7 +410,8 @@ static void draw_textured_begin(Scene *scene, View3D *v3d, RegionView3D *rv3d, O
 		solidtex = false;
 		Gtexdraw.is_lit = 0;
 	}
-	else if (v3d->drawtype == OB_SOLID || ((ob->mode & OB_MODE_EDIT) && v3d->drawtype != OB_TEXTURE)) {
+	else if (v3d->drawtype == OB_SOLID || ((ob->mode & OB_MODE_EDIT) && v3d->drawtype != OB_TEXTURE) ||
+	        (BKE_scene_use_new_shading_nodes(scene) && (ob->mode & OB_MODE_TEXTURE_PAINT))) {
 		/* draw with default lights in solid draw mode and edit mode */
 		solidtex = true;
 		Gtexdraw.is_lit = -1;
@@ -664,7 +665,7 @@ static void update_tface_color_layer(DerivedMesh *dm, bool use_mcol)
 		else if (ma && (ma->shade_flag & MA_OBCOLOR)) {
 			int loop_index = mp->loopstart;
 			for (j = 0; j < mp->totloop; j++, loop_index++) {
-				copy_v3_v3_char(&finalCol[loop_index].r, (char *)Gtexdraw.obcol);
+				copy_v3_v3_char((char *)&finalCol[loop_index].r, (char *)Gtexdraw.obcol);
 			}
 			copy_mode = COPY_PREV;
 		}
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index d9ad481..95c8cd5 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -1618,7 +1618,7 @@ exit:
 
 static void view3d_stereo_bgpic_setup(Scene *scene, View3D *v3d, Image *ima, ImageUser *iuser)
 {
-	if ((ima->flag & IMA_IS_STEREO)) {
+	if (BKE_image_is_stereo(ima)) {
 		iuser->flag |= IMA_SHOW_STEREO;
 
 		if ((scene->r.scemode & R_MULTIVIEW) == 0) {
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 8e867eb..9ae18c1 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -3085,6 +3085,7 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
 	float value;
 	int i;
 	char str[MAX_INFO_LEN];
+	const bool is_local_center = transdata_check_local_center(t, t->around);
 	
 	copy_m3_m4(persmat, t->viewmat);
 	invert_m3_m3(persinv, persmat);
@@ -3120,8 +3121,10 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
 	
 	mul_m3_m3m3(tmat, smat, persmat);
 	mul_m3_m3m3(totmat, persinv, tmat);
-	
+
 	for (i = 0; i < t->total; i++, td++) {
+		const float *center, *co;
+
 		if (td->flag & TD_NOACTION)
 			break;
 		
@@ -3136,12 +3139,22 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
 		else {
 			copy_m3_m3(tmat, totmat);
 		}
-		sub_v3_v3v3(vec, td->center, t->center);
+
+		if (is_local_center) {
+			center = td->center;
+			co = td->loc;
+		}
+		else {
+			center = t->center;
+			co = td->center;
+		}
+
+		sub_v3_v3v3(vec, co, center);
 		
 		mul_m3_v3(tmat, vec);
 		
-		add_v3_v3(vec, t->center);
-		sub_v3_v3(vec, td->center);
+		add_v3_v3(vec, center);
+		sub_v3_v3(vec, co);
 		
 		mul_v3_fl(vec, td->factor);
 		
diff --git a/source/blender/editors/transform/transform_input.c b/source/blender/editors/transform/transform_input.c
index 61b2dea..3b8d87c 100644
--- a/source/blender/editors/transform/transform_input.c
+++ b/source/blender/editors/transform/transform_input.c
@@ -39,6 +39,11 @@
 
 #include "MEM_guardedalloc.h" 
 
+struct InputTrackBall_Data {
+	float value_accum[2];
+	float value_prev[2];
+};
+
 /* ************************** INPUT FROM MOUSE *************************** */
 
 static void InputVector(TransInfo *t, MouseInput *mi, const int mval[2], float output[3])
@@ -102,18 +107,23 @@ static void InputSpringDelta(TransInfo *t, MouseInput *mi, const int mval[2], fl
 
 static void InputTrackBall(TransInfo *UNUSED(t), MouseInput *mi, const int mval[2], float output[3])
 {
+	struct InputTrackBall_Data *data = mi->data;
+	float dxy[2];
+	float dxy_accum[2];
+
+	dxy[0] = (mi->imval[1] - mval[1]);
+	dxy[1] = (mval[0] - mi->imval[0]);
+
+	sub_v2_v2v2(dxy_accum, dxy, data->value_prev);
+
+	add_v2_v2(data->value_prev, dxy_accum);
 
 	if (mi->precision) {
-		output[0] = (mi->imval[1] - mi->precision_mval[1]) + (mi->precision_mval[1] - mval[1]) * 0.1f;
-		output[1] = (mi->precision_mval[0] - mi->imval[0]) + (mval[0] - mi->precision_mval[0]) * 0.1f;
-	}
-	else {
-		output[0] = (float)(mi->imval[1] - mval[1]);
-		output[1] = (float)(mval[0] - mi->imval[0]);
+		mul_v2_fl(dxy_accum, 1.0f / 30.0f);
 	}
 
-	output[0] *= mi->factor;
-	output[1] *= mi->factor;
+	add_v2_v2(data->value_accum, dxy_accum);
+	mul_v2_v2fl(output, data->value_accum, mi->factor);
 }
 
 static void InputHorizontalRatio(TransInfo *t, MouseInput *mi, const int mval[2], float output[3])
@@ -358,6 +368,7 @@ void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode)
 		case INPUT_TRACKBALL:
 			/* factor has to become setting or so */
 			mi->factor = 0.01f;
+			mi->data = MEM_callocN(sizeof(struct InputTrackBall_Data), "angle accumulator");
 			mi->apply = InputTrackBall;
 			t->helpline = HLP_TRACKBALL;
 			break;
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index 6075261..bdebeb7 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -85,6 +85,8 @@
 
 #define TRANSFORM_DIST_MAX_PX 1000.0f
 #define TRANSFORM_SNAP_MAX_PX 100.0f
+#define TRANSFORM_DIST_INVALID -FLT_MAX
+
 /* use half of flt-max so we can scale up without an exception */
 
 /********************* PROTOTYPES ***********************/
@@ -887,17 +889,20 @@ static float ResizeBetween(TransInfo *t, const float p1[3], const float p2[3])
 
 	sub_v3_v3v3(d1, p1, t->center_global);
 	sub_v3_v3v3(d2, p2, t->center_global);
-	
-	project_v3_v3v3(d1, d1, d2);
 
 	if (t->con.applyRot != NULL && (t->con.mode & CON_APPLY)) {
 		mul_m3_v3(t->con.pmtx, d1);
 		mul_m3_v3(t->con.pmtx, d2);
 	}
+
+	project_v3_v3v3(d1, d1, d2);
 	
 	len_d1 = len_v3(d1);
 
-	return len_d1 != 0.0f ? len_v3(d2) / len_d1 : 1;
+	/* Use 'invalid' dist when `center == p1` (after projecting),
+	 * in this case scale will _never_ move the point in relation to the center,
+	 * so it makes no sense to take it into account when scaling. see: T46503 */
+	return len_d1 != 0.0f ? len_v3(d2) / len_d1 : TRANSFORM_DIST_INVALID;
 }
 
 /********************** CALC **************************/
@@ -1177,8 +1182,10 @@ static void TargetSnapClosest(TransInfo *t)
 						mul_m4_v3(td->ext->obmat, loc);
 						
 						dist = t->tsnap.distance(t, loc, t->tsnap.snapPoint);
-						
-						if (closest == NULL || fabsf(dist) < fabsf(t->tsnap.dist)) {
+
+						if ((dist != TRANSFORM_DIST_INVALID) &&
+						    (closest == NULL || fabsf(dist) < fabsf(t->tsnap.dist)))
+						{
 							copy_v3_v3(t->tsnap.snapTarget, loc);
 							closest = td;
 							t->tsnap.dist = dist; 
@@ -1193,8 +1200,10 @@ static void TargetSnapClosest(TransInfo *t)
 					copy_v3_v3(loc, td->center);
 					
 					dist = t->tsnap.distance(t, loc, t->tsnap.snapPoint);
-					
-					if (closest == NULL || fabsf(dist) < fabsf(t->tsnap.dist)) {
+
+					if ((dist != TRANSFORM_DIST_INVALID) &&
+					    (closest == NULL || fabsf(dist) < fabsf(t->tsnap.dist)))
+					{
 						copy_v3_v3(t->tsnap.snapTarget, loc);
 						closest = td;
 						t->tsnap.dist = dist; 
@@ -1217,7 +1226,9 @@ static void TargetSnapClosest(TransInfo *t)
 				
 				dist = t->tsnap.distance(t, loc, t->tsnap.snapPoint);
 				
-				if (closest == NULL || fabsf(dist) < fabsf(t->tsnap.dist)) {
+				if ((dist != TRANSFORM_DIST_INVALID) &&
+				    (closest == NULL || fabsf(dist) < fabsf(t->tsnap.dist)))
+				{
 					copy_v3_v3(t->tsnap.snapTarget, loc);
 					closest = td;
 					t->tsnap.dist = dist; 
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index 71d557f..3fc0b65 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -4119,7 +4119,13 @@ static int uv_seams_from_islands_exec(bContext *C, wmOperator *op)
 		}
 	}
 
-	me->drawflag |= ME_DRAWSEAMS;
+	if (mark_seams) {
+		me->drawflag |= ME_DRAWSEAMS;
+	}
+	if (mark_sharp) {
+		me->drawflag |= ME_DRAWSHARP;
+	}
+
 
 	BM_uv_vert_map_free(vmap);
 
@@ -4189,6 +4195,10 @@ static int uv_mark_seam_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
 	uiPopupMenu *pup;
 	uiLayout *layout;
 
+	if (RNA_struct_property_is_set(op->ptr, "clear")) {
+		return uv_mark_seam_exec(C, op);
+	}
+
 	pup = UI_popup_menu_begin(C, IFACE_("Edges"), ICON_NONE);
 	layout = UI_popup_menu_layout(pup);
 
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index f915a4b..3ff3e29 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -344,7 +344,8 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, Object *ob, B
 {
 	ParamHandle *handle;
 	/* index pointers */
-	MFace *face;
+	MPoly *mpoly;
+	MLoop *mloop;
 	MEdge *edge;
 	int i;
 
@@ -356,11 +357,12 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, Object *ob, B
 	/* Used to hold subsurfed Mesh */
 	DerivedMesh *derivedMesh, *initialDerived;
 	/* holds original indices for subsurfed mesh */
-	const int *origVertIndices, *origEdgeIndices, *origFaceIndices, *origPolyIndices;
+	const int *origVertIndices, *origEdgeIndices, *origPolyIndices;
 	/* Holds vertices of subsurfed mesh */
 	MVert *subsurfedVerts;
 	MEdge *subsurfedEdges;
-	MFace *subsurfedFaces;
+	MPoly *subsurfedPolys;
+	MLoop *subsurfedLoops;
 	/* number of vertices and faces for subsurfed mesh*/
 	int numOfEdges, numOfFaces;
 
@@ -398,15 +400,15 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, Object *ob, B
 	/* get the derived data */
 	subsurfedVerts = derivedMesh->getVertArray(derivedMesh);
 	subsurfedEdges = derivedMesh->getEdgeArray(derivedMesh);
-	subsurfedFaces = derivedMesh->getTessFaceArray(derivedMesh);
+	subsurfedPolys = derivedMesh->getPolyArray(derivedMesh);
+	subsurfedLoops = derivedMesh->getLoopArray(derivedMesh);
 
 	origVertIndices = derivedMesh->getVertDataArray(derivedMesh, CD_ORIGINDEX);
 	origEdgeIndices = derivedMesh->getEdgeDataArray(derivedMesh, CD_ORIGINDEX);
-	origFaceIndices = derivedMesh->getTessFaceDataArray(derivedMesh, CD_ORIGINDEX);
 	origPolyIndices = derivedMesh->getPolyDataArray(derivedMesh, CD_ORIGINDEX);
 
 	numOfEdges = derivedMesh->getNumEdges(derivedMesh);
-	numOfFaces = derivedMesh->getNumTessFaces(derivedMesh);
+	numOfFaces = derivedMesh->getNumPolys(derivedMesh);
 
 	faceMap = MEM_mallocN(numOfFaces * sizeof(BMFace *), "unwrap_edit_face_map");
 
@@ -415,7 +417,7 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, Object *ob, B
 
 	/* map subsurfed faces to original editFaces */
 	for (i = 0; i < numOfFaces; i++)
-		faceMap[i] = BM_face_at_index(em->bm, DM_origindex_mface_mpoly(origFaceIndices, origPolyIndices, i));
+		faceMap[i] = BM_face_at_index(em->bm, origPolyIndices[i]);
 
 	edgeMap = MEM_mallocN(numOfEdges * sizeof(BMEdge *), "unwrap_edit_edge_map");
 
@@ -427,15 +429,13 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, Object *ob, B
 	}
 
 	/* Prepare and feed faces to the solver */
-	for (i = 0; i < numOfFaces; i++) {
+	for (i = 0, mpoly = subsurfedPolys; i < numOfFaces; i++, mpoly++) {
 		ParamKey key, vkeys[4];
 		ParamBool pin[4], select[4];
 		float *co[4];
 		float *uv[4];
 		BMFace *origFace = faceMap[i];
 
-		face = subsurfedFaces + i;
-
 		if (scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
 			if (BM_elem_flag_test(origFace, BM_ELEM_HIDDEN))
 				continue;
@@ -445,24 +445,27 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, Object *ob, B
 				continue;
 		}
 
+		mloop = &subsurfedLoops[mpoly->loopstart];
+
 		/* We will not check for v4 here. Subsurfed mfaces always have 4 vertices. */
-		key = (ParamKey)face;
-		vkeys[0] = (ParamKey)face->v1;
-		vkeys[1] = (ParamKey)face->v2;
-		vkeys[2] = (ParamKey)face->v3;
-		vkeys[3] = (ParamKey)face->v4;
-
-		co[0] = subsurfedVerts[face->v1].co;
-		co[1] = subsurfedVerts[face->v2].co;
-		co[2] = subsurfedVerts[face->v3].co;
-		co[3] = subsurfedVerts[face->v4].co;
+		BLI_assert(mpoly->totloop == 4);
+		key = (ParamKey)mpoly;
+		vkeys[0] = (ParamKey)mloop[0].v;
+		vkeys[1] = (ParamKey)mloop[1].v;
+		vkeys[2] = (ParamKey)mloop[2].v;
+		vkeys[3] = (ParamKey)mloop[3].v;
+
+		co[0] = subsurfedVerts[mloop[0].v].co;
+		co[1] = subsurfedVerts[mloop[1].v].co;
+		co[2] = subsurfedVerts[mloop[2].v].co;
+		co[3] = subsurfedVerts[mloop[3].v].co;
 		
 		/* This is where all the magic is done. If the vertex exists in the, we pass the original uv pointer to the solver, thus
 		 * flushing the solution to the edit mesh. */
-		texface_from_original_index(origFace, origVertIndices[face->v1], &uv[0], &pin[0], &select[0], scene, cd_loop_uv_offset);
-		texface_from_original_index(origFace, origVertIndices[face->v2], &uv[1], &pin[1], &select[1], scene, cd_loop_uv_offset);
-		texface_from_original_index(origFace, origVertIndices[face->v3], &uv[2], &pin[2], &select[2], scene, cd_loop_uv_offset);
-		texface_from_original_index(origFace, origVertIndices[face->v4], &uv[3], &pin[3], &select[3], scene, cd_loop_uv_offset);
+		texface_from_original_index(origFace, origVertIndices[mloop[0].v], &uv[0], &pin[0], &select[0], scene, cd_loop_uv_offset);
+		texface_from_original_index(origFace, origVertIndices[mloop[1].v], &uv[1], &pin[1], &select[1], scene, cd_loop_uv_offset);
+		texface_from_original_index(origFace, origVertIndices[mloop[2].v], &uv[2], &pin[2], &select[2], scene, cd_loop_uv_offset);
+		texface_from_original_index(origFace, origVertIndices[mloop[3].v], &uv[3], &pin[3], &select[3], scene, cd_loop_uv_offset);
 
 		param_face_add(handle, key, 4, vkeys, co, uv, pin, select, NULL);
 	}
diff --git a/source/blender/freestyle/intern/application/Controller.cpp b/source/blender/freestyle/intern/application/Controller.cpp
index 8983a78..eb6a470 100644
--- a/source/blender/freestyle/intern/application/Controller.cpp
+++ b/source/blender/freestyle/intern/application/Controller.cpp
@@ -106,7 +106,9 @@ Controller::Controller()
 
 	_ProgressBar = new ProgressBar;
 	_SceneNumFaces = 0;
+#if 0
 	_minEdgeSize = DBL_MAX;
+#endif
 	_EPSILON = 1.0e-6;
 	_bboxDiag = 0;
 
@@ -264,9 +266,11 @@ int Controller::LoadMesh(Render *re, SceneRenderLayer *srl)
 	}
 	_SceneNumFaces += loader.numFacesRead();
 
+#if 0
 	if (loader.minEdgeSize() < _minEdgeSize) {
 		_minEdgeSize = loader.minEdgeSize();
 	}
+#endif
 
 #if 0  // DEBUG
 	ScenePrettyPrinter spp;
@@ -406,7 +410,9 @@ void Controller::DeleteWingedEdge()
 	_Grid.clear();
 	_Scene3dBBox.clear();
 	_SceneNumFaces = 0;
+#if 0
 	_minEdgeSize = DBL_MAX;
+#endif
 }
 
 void Controller::DeleteViewMap(bool freeCache)
diff --git a/source/blender/freestyle/intern/application/Controller.h b/source/blender/freestyle/intern/application/Controller.h
index 22eaaf5..6f3cb3b 100644
--- a/source/blender/freestyle/intern/application/Controller.h
+++ b/source/blender/freestyle/intern/application/Controller.h
@@ -209,7 +209,9 @@ private:
 
 	BBox<Vec3r> _Scene3dBBox;
 	unsigned int _SceneNumFaces;
+#if 0
 	real _minEdgeSize;
+#endif
 	real _EPSILON;
 	real _bboxDiag;
 
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
index 2b0d3b1..ea5a557 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
@@ -38,7 +38,9 @@ BlenderFileLoader::BlenderFileLoader(Render *re, SceneRenderLayer *srl)
 	_srl = srl;
 	_Scene = NULL;
 	_numFacesRead = 0;
+#if 0
 	_minEdgeSize = DBL_MAX;
+#endif
 	_smooth = (srl->freestyleConfig.flags & FREESTYLE_FACE_SMOOTHNESS_FLAG) != 0;
 	_pRenderMonitor = NULL;
 }
@@ -262,7 +264,10 @@ void BlenderFileLoader::addTriangle(struct LoaderState *ls, float v1[3], float v
                                     float n1[3], float n2[3], float n3[3],
                                     bool fm, bool em1, bool em2, bool em3)
 {
-	float *fv[3], *fn[3], len;
+	float *fv[3], *fn[3];
+#if 0
+	float len;
+#endif
 	unsigned int i, j;
 	IndexedFaceSet::FaceEdgeMark marks = 0;
 
@@ -289,9 +294,11 @@ void BlenderFileLoader::addTriangle(struct LoaderState *ls, float v1[3], float v
 				ls->maxBBox[j] = ls->pv[j];
 		}
 
+#if 0
 		len = len_v3v3(fv[i], fv[(i + 1) % 3]);
 		if (_minEdgeSize > len)
 			_minEdgeSize = len;
+#endif
 
 		*ls->pvi = ls->currentIndex;
 		*ls->pni = ls->currentIndex;
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h
index d16a311..894f8ee 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h
+++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h
@@ -87,8 +87,10 @@ public:
 	/*! Gets the number of read faces */
 	inline unsigned int numFacesRead() {return _numFacesRead;}
 
+#if 0
 	/*! Gets the smallest edge size read */
 	inline real minEdgeSize() {return _minEdgeSize;}
+#endif
 
 	/*! Modifiers */
 	inline void setRenderMonitor(RenderMonitor *iRenderMonitor) {_pRenderMonitor = iRenderMonitor;}
@@ -115,7 +117,9 @@ protected:
 	SceneRenderLayer *_srl;
 	NodeGroup *_Scene;
 	unsigned _numFacesRead;
+#if 0
 	real _minEdgeSize;
+#endif
 	bool _smooth; /* if true, face smoothness is taken into account */
 	float _viewplane_left;
 	float _viewplane_right;
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
index 64ef49d..7c10591 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
@@ -55,6 +55,8 @@ extern "C" {
 
 #include "BLI_ghash.h"
 #include "BLI_listbase.h"
+#include "BLI_math_color.h"
+#include "BLI_math_vector.h"
 #include "BLI_utildefines.h"
 
 #include "RE_pipeline.h"
@@ -113,7 +115,6 @@ BlenderStrokeRenderer::BlenderStrokeRenderer(Render *re, int render_count) : Str
 	BLI_strncpy(freestyle_scene->r.engine, old_scene->r.engine, sizeof(freestyle_scene->r.engine));
 	freestyle_scene->r.im_format.planes = R_IMF_PLANES_RGBA; 
 	freestyle_scene->r.im_format.imtype = R_IMF_IMTYPE_PNG;
-	BKE_scene_disable_color_management(freestyle_scene);
 
 	if (G.debug & G_DEBUG_FREESTYLE) {
 		printf("%s: %d thread(s)\n", __func__, BKE_render_num_threads(&freestyle_scene->r));
@@ -871,38 +872,24 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex)
 						}
 					}
 
-					// colors and alpha transparency
+					// colors and alpha transparency. vertex colors are in sRGB
+					// space by convention, so convert from linear
+					float rgba[3][4];
+
+					for (int i = 0; i < 3; i++) {
+						copy_v3fl_v3db(rgba[i], &svRep[i]->color()[0]);
+						rgba[i][3] = svRep[i]->alpha();
+					}
+
 					if (is_odd) {
-						colors[0].r = (short)(255.0f * svRep[2]->color()[0]);
-						colors[0].g = (short)(255.0f * svRep[2]->color()[1]);
-						colors[0].b = (short)(255.0f * svRep[2]->color()[2]);
-						colors[0].a = (short)(255.0f * svRep[2]->alpha());
-
-						colors[1].r = (short)(255.0f * svRep[0]->color()[0]);
-						colors[1].g = (short)(255.0f * svRep[0]->color()[1]);
-						colors[1].b = (short)(255.0f * svRep[0]->color()[2]);
-						colors[1].a = (short)(255.0f * svRep[0]->alpha());
-
-						colors[2].r = (short)(255.0f * svRep[1]->color()[0]);
-						colors[2].g = (short)(255.0f * svRep[1]->color()[1]);
-						colors[2].b = (short)(255.0f * svRep[1]->color()[2]);
-						colors[2].a = (short)(255.0f * svRep[1]->alpha());
+						linearrgb_to_srgb_uchar4(&colors[0].r, rgba[2]);
+						linearrgb_to_srgb_uchar4(&colors[1].r, rgba[0]);
+						linearrgb_to_srgb_uchar4(&colors[2].r, rgba[1]);
 					}
 					else {
-						colors[0].r = (short)(255.0f * svRep[2]->color()[0]);
-						colors[0].g = (short)(255.0f * svRep[2]->color()[1]);
-						colors[0].b = (short)(255.0f * svRep[2]->color()[2]);
-						colors[0].a = (short)(255.0f * svRep[2]->alpha());
-
-						colors[1].r = (short)(255.0f * svRep[1]->color()[0]);
-						colors[1].g = (short)(255.0f * svRep[1]->color()[1]);
-						colors[1].b = (short)(255.0f * svRep[1]->color()[2]);
-						colors[1].a = (short)(255.0f * svRep[1]->alpha());
-
-						colors[2].r = (short)(255.0f * svRep[0]->color()[0]);
-						colors[2].g = (short)(255.0f * svRep[0]->color()[1]);
-						colors[2].b = (short)(255.0f * svRep[0]->color()[2]);
-						colors[2].a = (short)(255.0f * svRep[0]->alpha());
+						linearrgb_to_srgb_uchar4(&colors[0].r, rgba[2]);
+						linearrgb_to_srgb_uchar4(&colors[1].r, rgba[1]);
+						linearrgb_to_srgb_uchar4(&colors[2].r, rgba[0]);
 					}
 					transp[0].r = transp[0].g = transp[0].b = colors[0].a;
 					transp[1].r = transp[1].g = transp[1].b = colors[1].a;
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_ChainPredicateIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_ChainPredicateIterator.cpp
index 6e253b7..c07f94c 100644
--- a/source/blender/freestyle/intern/python/Iterator/BPy_ChainPredicateIterator.cpp
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_ChainPredicateIterator.cpp
@@ -54,25 +54,6 @@ PyDoc_STRVAR(ChainPredicateIterator_doc,
 "predicate is kept as the next one.  If none of the potential next\n"
 "ViewEdge respects these two predicates, None is returned.\n"
 "\n"
-".. method:: __init__(restrict_to_selection=True, restrict_to_unvisited=True, begin=None, orientation=True)\n"
-"\n"
-"   Builds a ChainPredicateIterator from a starting ViewEdge and its\n"
-"   orientation.\n"
-"\n"
-"   :arg restrict_to_selection: Indicates whether to force the chaining\n"
-"      to stay within the set of selected ViewEdges or not.\n"
-"   :type restrict_to_selection: bool\n"
-"   :arg restrict_to_unvisited: Indicates whether a ViewEdge that has\n"
-"      already been chained must be ignored ot not.\n"
-"   :type restrict_to_unvisited: bool\n"
-"   :arg begin: The ViewEdge from where to start the iteration.\n"
-"   :type begin: :class:`freestyle.types.ViewEdge` or None\n"
-"   :arg orientation: If true, we'll look for the next ViewEdge among\n"
-"      the ViewEdges that surround the ending ViewVertex of begin.  If\n"
-"      false, we'll search over the ViewEdges surrounding the ending\n"
-"      ViewVertex of begin. \n"
-"   :type orientation: bool\n"
-"\n"
 ".. method:: __init__(upred, bpred, restrict_to_selection=True, restrict_to_unvisited=True, begin=None, "
 "orientation=True)\n"
 "\n"
@@ -118,11 +99,14 @@ static int ChainPredicateIterator_init(BPy_ChainPredicateIterator *self, PyObjec
 	static const char *kwlist_1[] = {"brother", NULL};
 	static const char *kwlist_2[] = {"upred", "bpred", "restrict_to_selection", "restrict_to_unvisited", "begin",
 	                                 "orientation", NULL};
-	static const char *kwlist_3[] = {"restrict_to_selection", "restrict_to_unvisited", "begin", "orientation", NULL};
 	PyObject *obj1 = 0, *obj2 = 0, *obj3 = 0, *obj4 = 0, *obj5 = 0, *obj6 = 0;
 
-	if (PyArg_ParseTupleAndKeywords(args, kwds, "O!", (char **)kwlist_1, &ChainingIterator_Type, &obj1)) {
+	if (PyArg_ParseTupleAndKeywords(args, kwds, "O!", (char **)kwlist_1, &ChainPredicateIterator_Type, &obj1)) {
 		self->cp_it = new ChainPredicateIterator(*(((BPy_ChainPredicateIterator *)obj1)->cp_it));
+		self->upred = ((BPy_ChainPredicateIterator *)obj1)->upred;
+		self->bpred = ((BPy_ChainPredicateIterator *)obj1)->bpred;
+		Py_INCREF(self->upred);
+		Py_INCREF(self->bpred);
 	}
 	else if (PyErr_Clear(), (obj3 = obj4 = obj5 = obj6 = 0),
 	         PyArg_ParseTupleAndKeywords(args, kwds, "O!O!|O!O!O&O!", (char **)kwlist_2,
@@ -143,19 +127,6 @@ static int ChainPredicateIterator_init(BPy_ChainPredicateIterator *self, PyObjec
 		Py_INCREF(self->upred);
 		Py_INCREF(self->bpred);
 	}
-	else if (PyErr_Clear(), (obj1 = obj2 = obj3 = obj4 = 0),
-	         PyArg_ParseTupleAndKeywords(args, kwds, "|O!O!O&O!", (char **)kwlist_3,
-	                                     &PyBool_Type, &obj1, &PyBool_Type, &obj2, check_begin, &obj3,
-	                                     &PyBool_Type, &obj4))
-	{
-		bool restrict_to_selection = (!obj1) ? true : bool_from_PyBool(obj1);
-		bool restrict_to_unvisited = (!obj2) ? true : bool_from_PyBool(obj2);
-		ViewEdge *begin = (!obj3 || obj3 == Py_None) ? NULL : ((BPy_ViewEdge *)obj3)->ve;
-		bool orientation = (!obj4) ? true : bool_from_PyBool(obj4);
-		self->cp_it = new ChainPredicateIterator(restrict_to_selection, restrict_to_unvisited, begin, orientation);
-		self->upred = NULL;
-		self->bpred = NULL;
-	}
 	else {
 		PyErr_SetString(PyExc_TypeError, "invalid argument(s)");
 		return -1;
diff --git a/source/blender/freestyle/intern/stroke/ChainingIterators.cpp b/source/blender/freestyle/intern/stroke/ChainingIterators.cpp
index 84d770a..6cacdfe 100644
--- a/source/blender/freestyle/intern/stroke/ChainingIterators.cpp
+++ b/source/blender/freestyle/intern/stroke/ChainingIterators.cpp
@@ -191,6 +191,8 @@ int ChainSilhouetteIterator::traverse(const AdjacencyIterator& ait)
 
 int ChainPredicateIterator::traverse(const AdjacencyIterator& ait)
 {
+	if (!_unary_predicate || !_binary_predicate)
+		return -1;
 	AdjacencyIterator it(ait);
 	// Iterates over next edges to see if one of them respects the predicate:
 	while (!it.isEnd()) {
diff --git a/source/blender/freestyle/intern/stroke/Operators.cpp b/source/blender/freestyle/intern/stroke/Operators.cpp
index 87ba34e..dfb50d9 100644
--- a/source/blender/freestyle/intern/stroke/Operators.cpp
+++ b/source/blender/freestyle/intern/stroke/Operators.cpp
@@ -996,6 +996,8 @@ public:
 
 	inline bool operator()(Interface1D *i1, Interface1D *i2)
 	{
+		if (i1 == i2)
+			return false;
 		if ((*_pred)(*i1, *i2) < 0)
 			throw std::runtime_error("comparison failed");
 		return _pred->result;
diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h
index 08ce9c0..e9dcf2d 100644
--- a/source/blender/imbuf/IMB_imbuf_types.h
+++ b/source/blender/imbuf/IMB_imbuf_types.h
@@ -67,32 +67,34 @@ typedef struct DDSData {
  */
 
 /* ibuf->ftype flag, main image types */
+/* Warning: Keep explicit value assignements here, this file is included in areas where not all format defines
+ *          are set (e.g. intern/dds only get WITH_DDS, even if TIFF, HDR etc are also defined). See T46524. */
 enum eImbTypes {
-	IMB_FTYPE_PNG = 1,
-	IMB_FTYPE_TGA,
-	IMB_FTYPE_JPG,
-	IMB_FTYPE_BMP,
-	IMB_FTYPE_OPENEXR,
-	IMB_FTYPE_IMAGIC,
+	IMB_FTYPE_PNG       = 1,
+	IMB_FTYPE_TGA       = 2,
+	IMB_FTYPE_JPG       = 3,
+	IMB_FTYPE_BMP       = 4,
+	IMB_FTYPE_OPENEXR   = 5,
+	IMB_FTYPE_IMAGIC    = 6,
 #ifdef WITH_OPENIMAGEIO
-	IMB_FTYPE_PSD,
+	IMB_FTYPE_PSD       = 7,
 #endif
 #ifdef WITH_OPENJPEG
-	IMB_FTYPE_JP2,
+	IMB_FTYPE_JP2       = 8,
 #endif
 #ifdef WITH_HDR
-	IMB_FTYPE_RADHDR,
+	IMB_FTYPE_RADHDR    = 9,
 #endif
 #ifdef WITH_TIFF
-	IMB_FTYPE_TIF,
+	IMB_FTYPE_TIF       = 10,
 #endif
 #ifdef WITH_CINEON
-	IMB_FTYPE_CINEON,
-	IMB_FTYPE_DPX,
+	IMB_FTYPE_CINEON    = 11,
+	IMB_FTYPE_DPX       = 12,
 #endif
 
 #ifdef WITH_DDS
-	IMB_FTYPE_DDS,
+	IMB_FTYPE_DDS       = 13,
 #endif
 };
 
@@ -124,12 +126,6 @@ enum eImbTypes {
 
 #define RAWTGA	        1
 
-#define JPG_STD	        0
-#define JPG_VID	        1
-#define JPG_JST	        2
-#define JPG_MAX	        3
-#define JPG_MSK	        0x03
-
 #ifdef WITH_TIFF
 #define TIF_16BIT		(1 << 8 )
 #endif
diff --git a/source/blender/imbuf/intern/jpeg.c b/source/blender/imbuf/intern/jpeg.c
index ff2a976..35c7b63 100644
--- a/source/blender/imbuf/intern/jpeg.c
+++ b/source/blender/imbuf/intern/jpeg.c
@@ -54,12 +54,6 @@
 #include "IMB_colormanagement.h"
 #include "IMB_colormanagement_intern.h"
 
-// #define IS_jpg(x)       (x->ftype & JPG) // UNUSED
-#define IS_stdjpg(x)    ((x->foptions.flag & JPG_MSK) == JPG_STD)
-// #define IS_vidjpg(x)    ((x->foptions & JPG_MSK) == JPG_VID) // UNUSED
-#define IS_jstjpg(x)    ((x->foptions.flag & JPG_MSK) == JPG_JST)
-#define IS_maxjpg(x)    ((x->foptions.flag & JPG_MSK) == JPG_MAX)
-
 /* the types are from the jpeg lib */
 static void jpeg_error(j_common_ptr cinfo) ATTR_NORETURN;
 static void init_source(j_decompress_ptr cinfo);
@@ -70,22 +64,8 @@ static void memory_source(j_decompress_ptr cinfo, const unsigned char *buffer, s
 static boolean handle_app1(j_decompress_ptr cinfo);
 static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo, int flags);
 
-
-/*
- * In principle there are 4 jpeg formats.
- *
- * 1. jpeg - standard printing, u & v at quarter of resolution
- * 2. jvid - standard video, u & v half resolution, frame not interlaced
- *
- * type 3 is unsupported as of jul 05 2000 Frank.
- *
- * 3. jstr - as 2, but written in 2 separate fields
- *
- * 4. jmax - no scaling in the components
- */
-
-static int jpeg_default_quality;
-static int ibuf_foptions;
+static const uchar jpeg_default_quality = 75;
+static uchar ibuf_quality;
 
 int imb_is_a_jpeg(const unsigned char *mem)
 {
@@ -254,6 +234,13 @@ static void memory_source(j_decompress_ptr cinfo, const unsigned char *buffer, s
 	      bytes_in_buffer--; \
 	      V += GETJOCTET(*next_input_byte++); )
 
+struct NeoGeo_Word {
+	uchar pad1;
+	uchar pad2;
+	uchar pad3;
+	uchar quality;
+} ;
+BLI_STATIC_ASSERT(sizeof(struct NeoGeo_Word) == 4, "Must be 4 bytes");
 
 static boolean handle_app1(j_decompress_ptr cinfo)
 {
@@ -267,13 +254,19 @@ static boolean handle_app1(j_decompress_ptr cinfo)
 	length -= 2;
 	
 	if (length < 16) {
-		for (i = 0; i < length; i++) INPUT_BYTE(cinfo, neogeo[i], return false);
+		for (i = 0; i < length; i++) {
+			INPUT_BYTE(cinfo, neogeo[i], return false);
+		}
 		length = 0;
-		if (STREQLEN(neogeo, "NeoGeo", 6)) memcpy(&ibuf_foptions, neogeo + 6, 4);
-		ibuf_foptions = BIG_LONG(ibuf_foptions);
+		if (STREQLEN(neogeo, "NeoGeo", 6)) {
+			struct NeoGeo_Word *neogeo_word = (struct NeoGeo_Word *)(neogeo + 6);
+			ibuf_quality = neogeo_word->quality;
+		}
 	}
 	INPUT_SYNC(cinfo);  /* do before skip_input_data */
-	if (length > 0) (*cinfo->src->skip_input_data)(cinfo, length);
+	if (length > 0) {
+		(*cinfo->src->skip_input_data)(cinfo, length);
+	}
 	return true;
 }
 
@@ -290,7 +283,7 @@ static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo, int fla
 	char *str, *key, *value;
 
 	/* install own app1 handler */
-	ibuf_foptions = 0;
+	ibuf_quality = jpeg_default_quality;
 	jpeg_set_marker_processor(cinfo, 0xe1, handle_app1);
 	cinfo->dct_method = JDCT_FLOAT;
 	jpeg_save_markers(cinfo, JPEG_COM, 0xffff);
@@ -304,14 +297,6 @@ static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo, int fla
 
 		jpeg_start_decompress(cinfo);
 
-		if (ibuf_foptions == 0) {
-			ibuf_foptions = JPG_STD;
-			if (cinfo->max_v_samp_factor == 1) {
-				if (cinfo->max_h_samp_factor == 1) ibuf_foptions = JPG_MAX;
-				else ibuf_foptions = JPG_VID;
-			}
-		}
-
 		if (flags & IB_test) {
 			jpeg_abort_decompress(cinfo);
 			ibuf = IMB_allocImBuf(x, y, 8 * depth, 0);
@@ -436,7 +421,7 @@ next_stamp_marker:
 		jpeg_destroy((j_common_ptr) cinfo);
 		if (ibuf) {
 			ibuf->ftype = IMB_FTYPE_JPG;
-			ibuf->foptions.flag = ibuf_foptions;
+			ibuf->foptions.quality = MIN2(ibuf_quality, 100);
 		}
 	}
 
@@ -481,16 +466,16 @@ static void write_jpeg(struct jpeg_compress_struct *cinfo, struct ImBuf *ibuf)
 	uchar *rect;
 	int x, y;
 	char neogeo[128];
+	struct NeoGeo_Word *neogeo_word;
 	char *text;
 
 	jpeg_start_compress(cinfo, true);
 
 	strcpy(neogeo, "NeoGeo");
-	ibuf_foptions = BIG_LONG((((int)ibuf->foptions.flag) << 8) | (int)ibuf->foptions.quality);
-	
-	memcpy(neogeo + 6, &ibuf_foptions, 4);
+	neogeo_word = (struct NeoGeo_Word *)(neogeo + 6);
+	memset(neogeo_word, 0, sizeof(*neogeo_word));
+	neogeo_word->quality = ibuf->foptions.quality;
 	jpeg_write_marker(cinfo, 0xe1, (JOCTET *) neogeo, 10);
-
 	if (ibuf->metadata) {
 		IDProperty *prop;
 		/* key + max value + "Blender" */
@@ -613,113 +598,8 @@ static int save_stdjpeg(const char *name, struct ImBuf *ibuf)
 	struct jpeg_compress_struct _cinfo, *cinfo = &_cinfo;
 	struct my_error_mgr jerr;
 
-	if ((outfile = BLI_fopen(name, "wb")) == NULL) return 0;
-	jpeg_default_quality = 75;
-
-	cinfo->err = jpeg_std_error(&jerr.pub);
-	jerr.pub.error_exit = jpeg_error;
-
-	/* Establish the setjmp return context for jpeg_error to use. */
-	if (setjmp(jerr.setjmp_buffer)) {
-		/* If we get here, the JPEG code has signaled an error.
-		 * We need to clean up the JPEG object, close the input file, and return.
-		 */
-		jpeg_destroy_compress(cinfo);
-		fclose(outfile);
-		remove(name);
+	if ((outfile = BLI_fopen(name, "wb")) == NULL)
 		return 0;
-	}
-
-	init_jpeg(outfile, cinfo, ibuf);
-
-	write_jpeg(cinfo, ibuf);
-
-	fclose(outfile);
-	jpeg_destroy_compress(cinfo);
-
-	return 1;
-}
-
-
-static int save_vidjpeg(const char *name, struct ImBuf *ibuf)
-{
-	FILE *outfile;
-	struct jpeg_compress_struct _cinfo, *cinfo = &_cinfo;
-	struct my_error_mgr jerr;
-
-	if ((outfile = BLI_fopen(name, "wb")) == NULL) return 0;
-	jpeg_default_quality = 90;
-
-	cinfo->err = jpeg_std_error(&jerr.pub);
-	jerr.pub.error_exit = jpeg_error;
-
-	/* Establish the setjmp return context for jpeg_error to use. */
-	if (setjmp(jerr.setjmp_buffer)) {
-		/* If we get here, the JPEG code has signaled an error.
-		 * We need to clean up the JPEG object, close the input file, and return.
-		 */
-		jpeg_destroy_compress(cinfo);
-		fclose(outfile);
-		remove(name);
-		return 0;
-	}
-
-	init_jpeg(outfile, cinfo, ibuf);
-
-	/* adjust scaling factors */
-	if (cinfo->in_color_space == JCS_RGB) {
-		cinfo->comp_info[0].h_samp_factor = 2;
-		cinfo->comp_info[0].v_samp_factor = 1;
-	}
-
-	write_jpeg(cinfo, ibuf);
-
-	fclose(outfile);
-	jpeg_destroy_compress(cinfo);
-
-	return 1;
-}
-
-static int save_jstjpeg(const char *name, struct ImBuf *ibuf)
-{
-	char fieldname[1024];
-	struct ImBuf *tbuf;
-	int oldy, returnval;
-
-	tbuf = IMB_allocImBuf(ibuf->x, ibuf->y / 2, 24, IB_rect);
-	tbuf->ftype = ibuf->ftype;
-	tbuf->foptions = ibuf->foptions;
-	tbuf->flags = ibuf->flags;
-	
-	oldy = ibuf->y;
-	ibuf->x *= 2;
-	ibuf->y /= 2;
-
-	IMB_rectcpy(tbuf, ibuf, 0, 0, 0, 0, ibuf->x, ibuf->y);
-	sprintf(fieldname, "%s.jf0", name);
-
-	returnval = save_vidjpeg(fieldname, tbuf);
-	if (returnval == 1) {
-		IMB_rectcpy(tbuf, ibuf, 0, 0, tbuf->x, 0, ibuf->x, ibuf->y);
-		sprintf(fieldname, "%s.jf1", name);
-		returnval = save_vidjpeg(fieldname, tbuf);
-	}
-
-	ibuf->y = oldy;
-	ibuf->x /= 2;
-	IMB_freeImBuf(tbuf);
-
-	return returnval;
-}
-
-static int save_maxjpeg(const char *name, struct ImBuf *ibuf)
-{
-	FILE *outfile;
-	struct jpeg_compress_struct _cinfo, *cinfo = &_cinfo;
-	struct my_error_mgr jerr;
-
-	if ((outfile = BLI_fopen(name, "wb")) == NULL) return 0;
-	jpeg_default_quality = 100;
 
 	cinfo->err = jpeg_std_error(&jerr.pub);
 	jerr.pub.error_exit = jpeg_error;
@@ -737,12 +617,6 @@ static int save_maxjpeg(const char *name, struct ImBuf *ibuf)
 
 	init_jpeg(outfile, cinfo, ibuf);
 
-	/* adjust scaling factors */
-	if (cinfo->in_color_space == JCS_RGB) {
-		cinfo->comp_info[0].h_samp_factor = 1;
-		cinfo->comp_info[0].v_samp_factor = 1;
-	}
-
 	write_jpeg(cinfo, ibuf);
 
 	fclose(outfile);
@@ -755,9 +629,5 @@ int imb_savejpeg(struct ImBuf *ibuf, const char *name, int flags)
 {
 	
 	ibuf->flags = flags;
-	if (IS_stdjpg(ibuf)) return save_stdjpeg(name, ibuf);
-	if (IS_jstjpg(ibuf)) return save_jstjpeg(name, ibuf);
-	if (IS_maxjpg(ibuf)) return save_maxjpeg(name, ibuf);
-	return save_vidjpeg(name, ibuf);
+	return save_stdjpeg(name, ibuf);
 }
-
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index e3c0273..80a4a33 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -32,6 +32,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <stddef.h>
+#include <stdexcept>
 #include <fstream>
 #include <string>
 #include <set>
@@ -427,6 +428,14 @@ static bool imb_save_openexr_half(ImBuf *ibuf, const char *name, const int flags
 			const size_t offset = view_id * width * height;
 			RGBAZ *to = pixels + offset;
 
+			/* TODO (dfelinto)
+			 * In some cases we get NULL ibufs, it needs investigation, meanwhile prevent crash
+			 * Multiview Render + Image Editor + OpenEXR + Multi-View
+			 */
+			if (view_ibuf == NULL) {
+				throw std::runtime_error(std::string("Missing data to write to ") + name);
+			}
+
 			/* indicate used buffers */
 			frameBuffer.insert(insertViewName("R", views, view_id), Slice(HALF,  (char *) &pixels[offset].r, xstride, ystride));
 			frameBuffer.insert(insertViewName("G", views, view_id), Slice(HALF,  (char *) &pixels[offset].g, xstride, ystride));
@@ -541,6 +550,14 @@ static bool imb_save_openexr_float(ImBuf *ibuf, const char *name, const int flag
 			float *rect[4] = {NULL, NULL, NULL, NULL};
 			ImBuf *view_ibuf = is_multiview ? getbuffer(ibuf->userdata, view_id) : ibuf;
 
+			/* TODO (dfelinto)
+			 * In some cases we get NULL ibufs, it needs investigation, meanwhile prevent crash
+			 * Multiview Render + Image Editor + OpenEXR + Multi-View
+			 */
+			if (view_ibuf == NULL) {
+				throw std::runtime_error(std::string("Missing data to write to ") + name);
+			}
+
 			/* last scanline, stride negative */
 			rect[0] = view_ibuf->rect_float + channels * (height - 1) * width;
 			rect[1] = (channels >= 2) ? rect[0] + 1 : rect[0];
@@ -1806,8 +1823,15 @@ static void imb_exr_type_by_channels(ChannelList& channels, StringVector& views,
 	/* will not include empty layer names */
 	channels.layers(layerNames);
 
-	if (views.size() && views[0] != "")
+	if (views.size() && views[0] != "") {
 		*r_multiview = true;
+	}
+	else {
+		*r_singlelayer = false;
+		*r_multilayer = true;
+		*r_multiview = false;
+		return;
+	}
 
 	if (layerNames.size()) {
 		/* if layerNames is not empty, it means at least one layer is non-empty,
@@ -1824,7 +1848,7 @@ static void imb_exr_type_by_channels(ChannelList& channels, StringVector& views,
 					std::string layerName = *i;
 					size_t pos = layerName.rfind ('.');
 
-					if (pos != std::string::npos) {
+					if (pos == std::string::npos) {
 						*r_multilayer = true;
 						*r_singlelayer = false;
 						return;
diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h
index 56a8842..d112790 100644
--- a/source/blender/makesdna/DNA_image_types.h
+++ b/source/blender/makesdna/DNA_image_types.h
@@ -172,8 +172,8 @@ enum {
 	IMA_IGNORE_ALPHA        = (1 << 12),
 	IMA_DEINTERLACE         = (1 << 13),
 	IMA_USE_VIEWS           = (1 << 14),
-	IMA_IS_STEREO           = (1 << 15),
-	IMA_IS_MULTIVIEW        = (1 << 16), /* similar to stereo, but a more general case */
+	// IMA_IS_STEREO        = (1 << 15), /* deprecated */
+	// IMA_IS_MULTIVIEW     = (1 << 16), /* deprecated */
 };
 
 /* Image.tpageflag */
diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h
index 59e6f28..621807d 100644
--- a/source/blender/makesdna/DNA_meshdata_types.h
+++ b/source/blender/makesdna/DNA_meshdata_types.h
@@ -71,7 +71,7 @@ typedef struct MVert {
  * at the moment alpha is abused for vertex painting and not used for transparency, note that red and blue are swapped
  */
 typedef struct MCol {
-	char a, r, g, b;
+	unsigned char a, r, g, b;
 } MCol;
 
 /* new face structure, replaces MFace, which is now only used for storing tessellations.*/
@@ -224,7 +224,7 @@ enum {
  * \note red and blue are _not_ swapped, as they are with #MCol
  */
 typedef struct MLoopCol {
-	char r, g, b, a;
+	unsigned char r, g, b, a;
 } MLoopCol;
 
 #define MESH_MLOOPCOL_FROM_MCOL(_mloopcol, _mcol) \
diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c
index 6dac2e2..860ed5e 100644
--- a/source/blender/makesrna/intern/rna_constraint.c
+++ b/source/blender/makesrna/intern/rna_constraint.c
@@ -412,6 +412,7 @@ static void rna_Constraint_followTrack_camera_set(PointerRNA *ptr, PointerRNA va
 	if (ob) {
 		if (ob->type == OB_CAMERA && ob != (Object *)ptr->id.data) {
 			data->camera = ob;
+			id_lib_extern((ID *)ob);
 		}
 	}
 	else {
@@ -428,6 +429,7 @@ static void rna_Constraint_followTrack_depthObject_set(PointerRNA *ptr, PointerR
 	if (ob) {
 		if (ob->type == OB_MESH && ob != (Object *)ptr->id.data) {
 			data->depth_ob = ob;
+			id_lib_extern((ID *)ob);
 		}
 	}
 	else {
@@ -457,6 +459,7 @@ static void rna_Constraint_objectSolver_camera_set(PointerRNA *ptr, PointerRNA v
 	if (ob) {
 		if (ob->type == OB_CAMERA && ob != (Object *)ptr->id.data) {
 			data->camera = ob;
+			id_lib_extern((ID *)ob);
 		}
 	}
 	else {
diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c
index e1e9fc1..65175e3 100644
--- a/source/blender/makesrna/intern/rna_curve.c
+++ b/source/blender/makesrna/intern/rna_curve.c
@@ -385,6 +385,7 @@ static void rna_Curve_bevelObject_set(PointerRNA *ptr, PointerRNA value)
 		/* set as bevobj, there could be infinity loop in displist calculation */
 		if (ob->type == OB_CURVE && ob->data != cu) {
 			cu->bevobj = ob;
+			id_lib_extern((ID *)ob);
 		}
 	}
 	else {
@@ -427,6 +428,7 @@ static void rna_Curve_taperObject_set(PointerRNA *ptr, PointerRNA value)
 		/* set as bevobj, there could be infinity loop in displist calculation */
 		if (ob->type == OB_CURVE && ob->data != cu) {
 			cu->taperobj = ob;
+			id_lib_extern((ID *)ob);
 		}
 	}
 	else {
diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c
index 561f5c9..2fa2fde 100644
--- a/source/blender/makesrna/intern/rna_image.c
+++ b/source/blender/makesrna/intern/rna_image.c
@@ -78,6 +78,16 @@ static void rna_Image_animated_update(Main *UNUSED(bmain), Scene *UNUSED(scene),
 	}
 }
 
+static int rna_Image_is_stereo_3d_get(PointerRNA *ptr)
+{
+	return BKE_image_is_stereo((Image *)ptr->data);
+}
+
+static int rna_Image_is_multiview_get(PointerRNA *ptr)
+{
+	return BKE_image_is_multiview((Image *)ptr->data);
+}
+
 static int rna_Image_dirty_get(PointerRNA *ptr)
 {
 	return BKE_image_is_dirty((Image *)ptr->data);
@@ -716,12 +726,12 @@ static void rna_def_image(BlenderRNA *brna)
 	RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_views_format_update");
 
 	prop = RNA_def_property(srna, "is_stereo_3d", PROP_BOOLEAN, PROP_NONE);
-	RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_IS_STEREO);
+	RNA_def_property_boolean_funcs(prop, "rna_Image_is_stereo_3d_get", NULL);
 	RNA_def_property_ui_text(prop, "Stereo 3D", "Image has left and right views");
 	RNA_def_property_clear_flag(prop, PROP_EDITABLE);
 
 	prop = RNA_def_property(srna, "is_multiview", PROP_BOOLEAN, PROP_NONE);
-	RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_IS_MULTIVIEW);
+	RNA_def_property_boolean_funcs(prop, "rna_Image_is_multiview_get", NULL);
 	RNA_def_property_ui_text(prop, "Multiple Views", "Image has more than one view");
 	RNA_def_property_clear_flag(prop, PROP_EDITABLE);
 
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index 27c4bf0..9bddb6c 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -549,9 +549,11 @@ RNA_MOD_OBJECT_SET(Shrinkwrap, auxTarget, OB_MESH);
 static void rna_HookModifier_object_set(PointerRNA *ptr, PointerRNA value)
 {
 	HookModifierData *hmd = ptr->data;
+	Object *ob = (Object *)value.data;
 
-	hmd->object = (Object *)value.data;
-	BKE_object_modifier_hook_reset((Object *)ptr->id.data, hmd);
+	hmd->object = ob;
+	id_lib_extern((ID *)ob);
+	BKE_object_modifier_hook_reset(ob, hmd);
 }
 
 static PointerRNA rna_UVProjector_object_get(PointerRNA *ptr)
@@ -562,8 +564,10 @@ static PointerRNA rna_UVProjector_object_get(PointerRNA *ptr)
 
 static void rna_UVProjector_object_set(PointerRNA *ptr, PointerRNA value)
 {
-	Object **ob = (Object **)ptr->data;
-	*ob = value.data;
+	Object **ob_p = (Object **)ptr->data;
+	Object *ob = (Object *)value.data;
+	id_lib_extern((ID *)ob);
+	*ob_p = ob;
 }
 
 #undef RNA_MOD_OBJECT_SET
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 54f1798..01547e7 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -535,11 +535,14 @@ static void rna_Object_dup_group_set(PointerRNA *ptr, PointerRNA value)
 	/* must not let this be set if the object belongs in this group already,
 	 * thus causing a cycle/infinite-recursion leading to crashes on load [#25298]
 	 */
-	if (BKE_group_object_exists(grp, ob) == 0)
+	if (BKE_group_object_exists(grp, ob) == 0) {
 		ob->dup_group = grp;
-	else
+		id_lib_extern((ID *)grp);
+	}
+	else {
 		BKE_report(NULL, RPT_ERROR,
 		           "Cannot set dupli-group as object belongs in group being instanced, thus causing a cycle");
+	}
 }
 
 static void rna_VertexGroup_name_set(PointerRNA *ptr, const char *value)
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 176c218..4578fae 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -554,6 +554,7 @@ static void rna_Scene_set_set(PointerRNA *ptr, PointerRNA value)
 			return;
 	}
 
+	id_lib_extern((ID *)set);
 	scene->set = set;
 }
 
@@ -1950,7 +1951,7 @@ static void rna_Stereo3dFormat_update(Main *UNUSED(bmain), Scene *UNUSED(scene),
 		ImBuf *ibuf;
 		void *lock;
 
-		if ((ima->flag & IMA_IS_STEREO) == 0)
+		if (!BKE_image_is_stereo(ima))
 			return;
 
 		ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c
index e819d33..e2fa053 100644
--- a/source/blender/makesrna/intern/rna_wm_api.c
+++ b/source/blender/makesrna/intern/rna_wm_api.c
@@ -420,7 +420,7 @@ void RNA_api_wm(StructRNA *srna)
 
 	/* Progress bar interface */
 	func = RNA_def_function(srna, "progress_begin", "rna_progress_begin");
-	RNA_def_function_ui_description(func, "Start Progress bar");
+	RNA_def_function_ui_description(func, "Start progress report");
 
 	parm = RNA_def_property(func, "min", PROP_FLOAT, PROP_NONE);
 	RNA_def_property_ui_text(parm, "min", "any value in range [0,9999]");
@@ -436,7 +436,7 @@ void RNA_api_wm(StructRNA *srna)
 	RNA_def_property_ui_text(parm, "value", "any value between min and max as set in progress_begin()");
 
 	func = RNA_def_function(srna, "progress_end", "rna_progress_end");
-	RNA_def_function_ui_description(func, "Terminate Progress bar");
+	RNA_def_function_ui_description(func, "Terminate progress report");
 
 	/* invoke functions, for use with python */
 	func = RNA_def_function(srna, "invoke_props_popup", "rna_Operator_props_popup");
diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c
index cbd7bc9..23ab618 100644
--- a/source/blender/modifiers/intern/MOD_subsurf.c
+++ b/source/blender/modifiers/intern/MOD_subsurf.c
@@ -108,10 +108,8 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
 
 #ifdef WITH_OPENSUBDIV
 	const bool allow_gpu = (flag & MOD_APPLY_ALLOW_GPU) != 0;
-	const bool do_cddm_convert = useRenderParams || (!isFinalCalc && !smd->use_opensubdiv);
-#else
-	const bool do_cddm_convert = useRenderParams || !isFinalCalc;
 #endif
+	bool do_cddm_convert = useRenderParams || !isFinalCalc;
 
 	if (useRenderParams)
 		subsurf_flags |= SUBSURF_USE_RENDER_PARAMS;
@@ -134,6 +132,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
 		}
 		else if ((DAG_get_eval_flags_for_object(md->scene, ob) & DAG_EVAL_NEED_CPU) == 0) {
 			subsurf_flags |= SUBSURF_USE_GPU_BACKEND;
+			do_cddm_convert = false;
 		}
 		else {
 			modifier_setError(md, "OpenSubdiv is disabled due to dependencies");
diff --git a/source/blender/python/mathutils/mathutils_bvhtree.c b/source/blender/python/mathutils/mathutils_bvhtree.c
index bf06b88..9deb57d 100644
--- a/source/blender/python/mathutils/mathutils_bvhtree.c
+++ b/source/blender/python/mathutils/mathutils_bvhtree.c
@@ -352,7 +352,7 @@ static PyObject *py_bvhtree_ray_cast(PyBVHTree *self, PyObject *args)
 
 		if (!PyArg_ParseTuple(
 		        args, (char *)"OO|f:ray_cast",
-		        &py_co, &py_direction, max_dist))
+		        &py_co, &py_direction, &max_dist))
 		{
 			return NULL;
 		}
diff --git a/source/blender/python/mathutils/mathutils_geometry.c b/source/blender/python/mathutils/mathutils_geometry.c
index 0224798..a4ca252 100644
--- a/source/blender/python/mathutils/mathutils_geometry.c
+++ b/source/blender/python/mathutils/mathutils_geometry.c
@@ -415,7 +415,9 @@ static PyObject *M_Geometry_volume_tetrahedron(PyObject *UNUSED(self), PyObject
 PyDoc_STRVAR(M_Geometry_intersect_line_line_2d_doc,
 ".. function:: intersect_line_line_2d(lineA_p1, lineA_p2, lineB_p1, lineB_p2)\n"
 "\n"
-"   Takes 2 lines (as 4 vectors) and returns a vector for their point of intersection or None.\n"
+"   Takes 2 segments (defined by 4 vectors) and returns a vector for their point of intersection or None.\n"
+"\n"
+"   .. warning:: Despite its name, this function works on segments, and not on lines..."
 "\n"
 "   :arg lineA_p1: First point of the first line\n"
 "   :type lineA_p1: :class:`mathutils.Vector`\n"
diff --git a/source/blender/render/intern/source/bake_api.c b/source/blender/render/intern/source/bake_api.c
index 87cdd87..d1dba50 100644
--- a/source/blender/render/intern/source/bake_api.c
+++ b/source/blender/render/intern/source/bake_api.c
@@ -86,6 +86,8 @@
 #include "render_types.h"
 #include "zbuf.h"
 
+/* Remove when Cycles moves from MFace to MLoopTri */
+#define USE_MFACE_WORKAROUND
 
 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
 /* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
@@ -352,6 +354,27 @@ static bool cast_ray_highpoly(
 	return hit_mesh != -1;
 }
 
+#ifdef USE_MFACE_WORKAROUND
+/**
+ * Until cycles moves to #MLoopTri, we need to keep face-rotation in sync with #test_index_face
+ *
+ * We only need to consider quads since #BKE_mesh_recalc_tessellation doesn't execute this on triangles.
+ */
+static void test_index_face_looptri(const MPoly *mp, MLoop *mloop, MLoopTri *lt)
+{
+	if (mp->totloop == 4) {
+		if (UNLIKELY((mloop[mp->loopstart + 2].v == 0) ||
+		             (mloop[mp->loopstart + 3].v == 0)))
+		{
+			/* remap: (2, 3, 0, 1) */
+			unsigned int l = mp->loopstart;
+			ARRAY_SET_ITEMS(lt[0].tri, l + 2, l + 3, l + 0);
+			ARRAY_SET_ITEMS(lt[1].tri, l + 2, l + 0, l + 1);
+		}
+	}
+}
+#endif
+
 /**
  * This function populates an array of verts for the triangles of a mesh
  * Tangent and Normals are also stored
@@ -373,6 +396,10 @@ static TriTessFace *mesh_calc_tri_tessface(
 	unsigned int mpoly_prev = UINT_MAX;
 	float no[3];
 
+#ifdef USE_MFACE_WORKAROUND
+	unsigned int mpoly_prev_testindex = UINT_MAX;
+#endif
+
 	mvert = CustomData_get_layer(&me->vdata, CD_MVERT);
 	looptri = MEM_mallocN(sizeof(*looptri) * tottri, __func__);
 	triangles = MEM_mallocN(sizeof(TriTessFace) * tottri, __func__);
@@ -395,8 +422,15 @@ static TriTessFace *mesh_calc_tri_tessface(
 	            looptri);
 
 	for (i = 0; i < tottri; i++) {
-		MLoopTri *lt = &looptri[i];
-		MPoly *mp = &me->mpoly[lt->poly];
+		const MLoopTri *lt = &looptri[i];
+		const MPoly *mp = &me->mpoly[lt->poly];
+
+#ifdef USE_MFACE_WORKAROUND
+		if (lt->poly != mpoly_prev_testindex) {
+			test_index_face_looptri(mp, me->mloop, &looptri[i]);
+			mpoly_prev_testindex = lt->poly;
+		}
+#endif
 
 		triangles[i].mverts[0] = &mvert[me->mloop[lt->tri[0]].v];
 		triangles[i].mverts[1] = &mvert[me->mloop[lt->tri[1]].v];
@@ -586,6 +620,9 @@ void RE_bake_pixels_populate(
 	const MLoopUV *mloopuv;
 	const int tottri = poly_to_tri_count(me->totpoly, me->totloop);
 	MLoopTri *looptri;
+#ifdef USE_MFACE_WORKAROUND
+	unsigned int mpoly_prev_testindex = UINT_MAX;
+#endif
 
 	/* we can't bake in edit mode */
 	if (me->edit_btmesh)
@@ -633,6 +670,13 @@ void RE_bake_pixels_populate(
 		bd.bk_image = &bake_images->data[image_id];
 		bd.primitive_id = ++p_id;
 
+#ifdef USE_MFACE_WORKAROUND
+		if (lt->poly != mpoly_prev_testindex) {
+			test_index_face_looptri(mp, me->mloop, &looptri[i]);
+			mpoly_prev_testindex = lt->poly;
+		}
+#endif
+
 		for (a = 0; a < 3; a++) {
 			const float *uv = mloopuv[lt->tri[a]].uv;
 
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index 98279da..64e6c14 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -2108,9 +2108,10 @@ static void ntree_render_scenes(Render *re)
 /* bad call... need to think over proper method still */
 static void render_composit_stats(void *UNUSED(arg), const char *str)
 {
-	R.i.infostr = str;
-	R.stats_draw(R.sdh, &R.i);
-	R.i.infostr = NULL;
+	RenderStats i;
+	memcpy(&i, &R.i, sizeof(i));
+	i.infostr = str;
+	R.stats_draw(R.sdh, &i);
 }
 
 #ifdef WITH_FREESTYLE
@@ -3168,11 +3169,17 @@ void RE_RenderFreestyleStrokes(Render *re, Main *bmain, Scene *scene, int render
 void RE_RenderFreestyleExternal(Render *re)
 {
 	if (!re->test_break(re->tbh)) {
-		RE_Database_FromScene(re, re->main, re->scene, re->lay, 1);
-		RE_Database_Preprocess(re);
+		RenderView *rv;
+
 		init_freestyle(re);
-		add_freestyle(re, 1);
-		RE_Database_Free(re);
+
+		for (rv = re->result->views.first; rv; rv = rv->next) {
+			RE_SetActiveRenderView(re, rv->name);
+			RE_Database_FromScene(re, re->main, re->scene, re->lay, 1);
+			RE_Database_Preprocess(re);
+			add_freestyle(re, 1);
+			RE_Database_Free(re);
+		}
 	}
 }
 #endif
@@ -3480,6 +3487,18 @@ static void get_videos_dimensions(Render *re, RenderData *rd, size_t *r_width, s
 	BKE_scene_multiview_videos_dimensions_get(rd, width, height, r_width, r_height);
 }
 
+static void re_movie_free_all(Render *re, bMovieHandle *mh, size_t totvideos)
+{
+	size_t i;
+
+	for (i = 0; i < totvideos; i++) {
+		mh->end_movie(re->movie_ctx_arr[i]);
+		mh->context_free(re->movie_ctx_arr[i]);
+	}
+
+	MEM_SAFE_FREE(re->movie_ctx_arr);
+}
+
 /* saves images to disk */
 void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_override,
                     unsigned int lay_override, int sfra, int efra, int tfra)
@@ -3504,15 +3523,10 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
 		BKE_report(re->reports, RPT_ERROR, "Frame Server only support stereo output for multiview rendering");
 		return;
 	}
-	
-	/* ugly global still... is to prevent renderwin events and signal subsurfs etc to make full resol */
-	/* is also set by caller renderwin.c */
-	G.is_rendering = true;
-
-	re->flag |= R_ANIMATION;
 
 	if (is_movie) {
 		size_t i, width, height;
+		bool is_error = false;
 
 		get_videos_dimensions(re, &rd, &width, &height);
 
@@ -3524,11 +3538,25 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
 
 			re->movie_ctx_arr[i] = mh->context_create();
 
-			if (!mh->start_movie(re->movie_ctx_arr[i], scene, &re->r, width, height, re->reports, false, suffix))
-				G.is_break = true;
+			if (!mh->start_movie(re->movie_ctx_arr[i], scene, &re->r, width, height, re->reports, false, suffix)) {
+				is_error = true;
+				break;
+			}
+		}
+
+		if (is_error) {
+			/* report is handled above */
+			re_movie_free_all(re, mh, i + 1);
+			return;
 		}
 	}
 
+	/* ugly global still... is to prevent renderwin events and signal subsurfs etc to make full resol */
+	/* is also set by caller renderwin.c */
+	G.is_rendering = true;
+
+	re->flag |= R_ANIMATION;
+
 	if (mh && mh->get_next_frame) {
 		/* MULTIVIEW_TODO:
 		 * in case a new video format is added that implements get_next_frame multiview has to be addressed
@@ -3712,15 +3740,7 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
 	
 	/* end movie */
 	if (is_movie) {
-		size_t i;
-		for (i = 0; i < totvideos; i++) {
-			mh->end_movie(re->movie_ctx_arr[i]);
-			mh->context_free(re->movie_ctx_arr[i]);
-		}
-
-		if (re->movie_ctx_arr) {
-			MEM_freeN(re->movie_ctx_arr);
-		}
+		re_movie_free_all(re, mh, totvideos);
 	}
 	
 	if (totskipped && totrendered == 0)
diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c
index 5098df2..9d2ca35 100644
--- a/source/blender/windowmanager/intern/wm_keymap.c
+++ b/source/blender/windowmanager/intern/wm_keymap.c
@@ -1783,7 +1783,7 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
 	}
 	/* UV Editor */
 	else if (STRPREFIX(opname, "UV_OT")) {
-		km = WM_keymap_find_all(C, "UV Editor", sl->spacetype, 0);
+		km = WM_keymap_find_all(C, "UV Editor", 0, 0);
 	}
 	/* Node Editor */
 	else if (STRPREFIX(opname, "NODE_OT")) {
diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c
index bf30fd8..64f77e7 100644
--- a/source/blender/windowmanager/intern/wm_playanim.c
+++ b/source/blender/windowmanager/intern/wm_playanim.c
@@ -383,7 +383,6 @@ static void build_pict_list_ex(PlayState *ps, const char *first, int totframes,
 //	short val;
 	PlayAnimPict *picture = NULL;
 	struct ImBuf *ibuf = NULL;
-	char str[32 + FILE_MAX];
 	struct anim *anim;
 
 	if (IMB_isanim(first)) {
@@ -402,8 +401,7 @@ static void build_pict_list_ex(PlayState *ps, const char *first, int totframes,
 				picture->anim = anim;
 				picture->frame = pic;
 				picture->IB_flags = IB_rect;
-				BLI_snprintf(str, sizeof(str), "%s : %4.d", first, pic + 1);
-				picture->name = strdup(str);
+				picture->name = BLI_sprintfN("%s : %4.d", first, pic + 1);
 				BLI_addtail(&picsbase, picture);
 			}
 		}
@@ -414,7 +412,14 @@ static void build_pict_list_ex(PlayState *ps, const char *first, int totframes,
 	else {
 		int count = 0;
 
+		int fp_framenr;
+		struct {
+			char head[FILE_MAX], tail[FILE_MAX];
+			unsigned short digits;
+		} fp_decoded;
+
 		BLI_strncpy(filepath, first, sizeof(filepath));
+		fp_framenr = BLI_stringdec(filepath, fp_decoded.head, fp_decoded.tail, &fp_decoded.digits);
 
 		pupdate_time();
 		ptottime = 1.0;
@@ -480,8 +485,8 @@ static void build_pict_list_ex(PlayState *ps, const char *first, int totframes,
 			}
 
 			picture->mem = mem;
-			picture->name = strdup(filepath);
-			picture->frame = count; /* not exact but should work for positioning */
+			picture->name = BLI_strdup(filepath);
+			picture->frame = count;
 			close(file);
 			BLI_addtail(&picsbase, picture);
 			count++;
@@ -505,7 +510,9 @@ static void build_pict_list_ex(PlayState *ps, const char *first, int totframes,
 				ptottime = 0.0;
 			}
 
-			BLI_newname(filepath, +fstep);
+			/* create a new filepath each time */
+			fp_framenr += fstep;
+			BLI_stringenc(filepath, fp_decoded.head, fp_decoded.tail, fp_decoded.digits, fp_framenr);
 
 			while ((hasevent = GHOST_ProcessEvents(g_WS.ghost_system, 0))) {
 				if (hasevent) {
@@ -544,17 +551,16 @@ static void update_sound_fps(void)
 static void change_frame(PlayState *ps, int cx)
 {
 	int sizex, sizey;
-	int i;
+	int i, i_last;
 
-	playanim_window_get_size(&sizex, &sizey);
-	ps->picture = picsbase.first;
-	/* TODO - store in ps direct? */
-	i = 0;
-	while (ps->picture) {
-		i++;
-		ps->picture = ps->picture->next;
+	if (BLI_listbase_is_empty(&picsbase)) {
+		return;
 	}
-	i = (i * cx) / sizex;
+
+	playanim_window_get_size(&sizex, &sizey);
+	i_last = ((struct PlayAnimPict *)picsbase.last)->frame;
+	i = (i_last * cx) / sizex;
+	CLAMP(i, 0, i_last);
 
 #ifdef WITH_AUDASPACE
 	if (scrub_handle) {
@@ -588,11 +594,8 @@ static void change_frame(PlayState *ps, int cx)
 	}
 #endif
 
-	ps->picture = picsbase.first;
-	for (; i > 0; i--) {
-		if (ps->picture->next == NULL) break;
-		ps->picture = ps->picture->next;
-	}
+	ps->picture = BLI_findlink(&picsbase, i);
+	BLI_assert(ps->picture != NULL);
 
 	ps->sstep = true;
 	ps->wait2 = false;
@@ -977,6 +980,19 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
 				GHOST_TEventCursorData *cd = GHOST_GetEventData(evt);
 				int cx, cy;
 
+				/* Ignore 'in-between' events, since they can make scrubbing lag.
+				 *
+				 * Ideally we would keep into the event queue and see if this is the last motion event.
+				 * however the API currently doesn't support this. */
+				{
+					int x_test, y_test;
+					GHOST_GetCursorPosition(g_WS.ghost_system, &x_test, &y_test);
+					if (x_test != cd->x || y_test != cd->y) {
+						/* we're not the last event... skipping */
+						break;
+					}
+				}
+
 				GHOST_ScreenToClient(g_WS.ghost_window, cd->x, cd->y, &cx, &cy);
 
 				change_frame(ps, cx);
@@ -1093,7 +1109,6 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
 	GHOST_TUns32 maxwinx, maxwiny;
 	int i;
 	/* This was done to disambiguate the name for use under c++. */
-	struct anim *anim = NULL;
 	int start_x = 0, start_y = 0;
 	int sfra = -1;
 	int efra = -1;
@@ -1200,6 +1215,7 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
 
 	if (IMB_isanim(filepath)) {
 		/* OCIO_TODO: support different input color spaces */
+		struct anim *anim;
 		anim = IMB_open_anim(filepath, IB_rect, 0, NULL);
 		if (anim) {
 			ibuf = IMB_anim_absolute(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE);
@@ -1471,13 +1487,13 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
 			}
 		}
 	}
-	ps.picture = picsbase.first;
-	anim = NULL;
-	while (ps.picture) {
-		if (ps.picture && ps.picture->anim && (anim != ps.picture->anim)) {
-			// to prevent divx crashes
-			anim = ps.picture->anim;
-			IMB_close_anim(anim);
+	while ((ps.picture = BLI_pophead(&picsbase))) {
+		if (ps.picture->anim) {
+			if ((ps.picture->next == NULL) ||
+			    (ps.picture->next->anim != ps.picture->anim))
+			{
+				IMB_close_anim(ps.picture->anim);
+			}
 		}
 
 		if (ps.picture->ibuf) {
@@ -1487,7 +1503,8 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
 			MEM_freeN(ps.picture->mem);
 		}
 
-		ps.picture = ps.picture->next;
+		MEM_freeN((void *)ps.picture->name);
+		MEM_freeN(ps.picture);
 	}
 
 	/* cleanup */
diff --git a/source/gameengine/Converter/KX_ConvertActuators.cpp b/source/gameengine/Converter/KX_ConvertActuators.cpp
index 3b36e09..7b62f07 100644
--- a/source/gameengine/Converter/KX_ConvertActuators.cpp
+++ b/source/gameengine/Converter/KX_ConvertActuators.cpp
@@ -421,7 +421,7 @@ void BL_ConvertActuators(const char* maggiename,
 						soundActuatorType);
 
 					// if we made it mono, we have to free it
-					if(snd_sound != sound->playback_handle && snd_sound != NULL)
+					if(sound && snd_sound && snd_sound != sound->playback_handle)
 						AUD_Sound_free(snd_sound);
 
 					tmpsoundact->SetName(bact->name);
diff --git a/source/gameengine/Ketsji/BL_Action.cpp b/source/gameengine/Ketsji/BL_Action.cpp
index 12a1cae..d22b9f0 100644
--- a/source/gameengine/Ketsji/BL_Action.cpp
+++ b/source/gameengine/Ketsji/BL_Action.cpp
@@ -56,6 +56,15 @@ extern "C" {
 #include "BKE_library.h"
 #include "BKE_global.h"
 
+#include "BLI_threads.h" // for lock
+
+/* Lock to solve animation thread issues.
+ * A spin lock is better than a mutex in case of short wait 
+ * because spin lock stop the thread by a loop contrary to mutex
+ * which switch all memory, process.
+ */ 
+static SpinLock BL_ActionLock;
+
 BL_Action::BL_Action(class KX_GameObject* gameobj)
 :
 	m_action(NULL),
@@ -506,15 +515,23 @@ void BL_Action::Update(float curtime)
 		}
 	}
 
-	// This isn't thread-safe, so we move it into it's own function for now
-	//m_obj->UpdateIPO(m_localtime, m_ipo_flags & ACT_IPOFLAG_CHILD);
+	BLI_spin_lock(&BL_ActionLock);
+	/* This function is not thread safe because of recursive scene graph transform
+	 * updates on children. e.g: If an object and one of its children is animated,
+	 * the both can write transform at the same time. A thread lock avoid problems. */
+	m_obj->UpdateIPO(m_localtime, m_ipo_flags & ACT_IPOFLAG_CHILD);
+	BLI_spin_unlock(&BL_ActionLock);
 
 	if (m_done)
 		ClearControllerList();
 }
 
-void BL_Action::UpdateIPOs()
+void BL_Action::InitLock()
+{
+	BLI_spin_init(&BL_ActionLock);
+}
+
+void BL_Action::EndLock()
 {
-	if (!m_done)
-		m_obj->UpdateIPO(m_localtime, m_ipo_flags & ACT_IPOFLAG_CHILD);
+	BLI_spin_end(&BL_ActionLock);
 }
diff --git a/source/gameengine/Ketsji/BL_Action.h b/source/gameengine/Ketsji/BL_Action.h
index 379dd52..d4f50c1 100644
--- a/source/gameengine/Ketsji/BL_Action.h
+++ b/source/gameengine/Ketsji/BL_Action.h
@@ -105,10 +105,6 @@ public:
 	 * Update the action's frame, etc.
 	 */
 	void Update(float curtime);
-	/**
-	 * Update object IPOs (note: not thread-safe!)
-	 */
-	void UpdateIPOs();
 
 	// Accessors
 	float GetFrame();
@@ -144,6 +140,11 @@ public:
 		ACT_IPOFLAG_CHILD = 8,
 	};
 
+	/// Initialize a lock for animation thread issues.
+	static void InitLock();
+	/// Finalize a lock for animation thread issues.
+	static void EndLock();
+
 #ifdef WITH_CXX_GUARDEDALLOC
 	MEM_CXX_CLASS_ALLOC_FUNCS("GE:BL_Action")
 #endif
diff --git a/source/gameengine/Ketsji/BL_ActionManager.cpp b/source/gameengine/Ketsji/BL_ActionManager.cpp
index 9e46905..3aefb36 100644
--- a/source/gameengine/Ketsji/BL_ActionManager.cpp
+++ b/source/gameengine/Ketsji/BL_ActionManager.cpp
@@ -170,13 +170,3 @@ void BL_ActionManager::Update(float curtime)
 		}
 	}
 }
-
-void BL_ActionManager::UpdateIPOs()
-{
-	BL_ActionMap::iterator it;
-	for (it = m_layers.begin(); it != m_layers.end(); ++it)
-	{
-		if (!it->second->IsDone())
-			it->second->UpdateIPOs();
-	}
-}
diff --git a/source/gameengine/Ketsji/BL_ActionManager.h b/source/gameengine/Ketsji/BL_ActionManager.h
index 97d6d88..599ee28 100644
--- a/source/gameengine/Ketsji/BL_ActionManager.h
+++ b/source/gameengine/Ketsji/BL_ActionManager.h
@@ -129,11 +129,6 @@ public:
 	 */
 	void Update(float);
 
-	/**
-	 * Update object IPOs (note: not thread-safe!)
-	 */
-	void UpdateIPOs();
-
 #ifdef WITH_CXX_GUARDEDALLOC
 	MEM_CXX_CLASS_ALLOC_FUNCS("GE:BL_ActionManager")
 #endif
diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp
index c3da80b..e7ba5ea 100644
--- a/source/gameengine/Ketsji/KX_GameObject.cpp
+++ b/source/gameengine/Ketsji/KX_GameObject.cpp
@@ -484,11 +484,6 @@ void KX_GameObject::UpdateActionManager(float curtime)
 	GetActionManager()->Update(curtime);
 }
 
-void KX_GameObject::UpdateActionIPOs()
-{
-	GetActionManager()->UpdateIPOs();
-}
-
 float KX_GameObject::GetActionFrame(short layer)
 {
 	return GetActionManager()->GetActionFrame(layer);
@@ -952,6 +947,9 @@ void KX_GameObject::InitIPO(bool ipo_as_force,
 void KX_GameObject::UpdateIPO(float curframetime,
 							  bool recurse) 
 {
+	/* This function shouldn't call BL_Action::Update, not even indirectly, 
+	 * as it will cause deadlock due to the lock in BL_Action::Update. */
+
 	// just the 'normal' update procedure.
 	GetSGNode()->SetSimulatedTime(curframetime,recurse);
 	GetSGNode()->UpdateWorldData(curframetime);
diff --git a/source/gameengine/Ketsji/KX_GameObject.h b/source/gameengine/Ketsji/KX_GameObject.h
index c10802a..a5b6d12 100644
--- a/source/gameengine/Ketsji/KX_GameObject.h
+++ b/source/gameengine/Ketsji/KX_GameObject.h
@@ -321,12 +321,6 @@ public:
 	 */
 	void UpdateActionManager(float curtime);
 
-	/**
-	 * Have the action manager update IPOs
-	 * note: not thread-safe!
-	 */
-	void UpdateActionIPOs();
-
 	/*********************************
 	 * End Animation API
 	 *********************************/
diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
index 72c5125..c6e5f73 100644
--- a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
+++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
@@ -75,6 +75,8 @@
 
 #include "KX_NavMeshObject.h"
 
+#include "BL_Action.h" // For managing action lock.
+
 #define DEFAULT_LOGIC_TIC_RATE 60.0
 //#define DEFAULT_PHYSICS_TIC_RATE 60.0
 
@@ -181,6 +183,8 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system)
 #endif
 
 	m_taskscheduler = BLI_task_scheduler_create(TASK_SCHEDULER_AUTO_THREADS);
+
+	BL_Action::InitLock();
 }
 
 
@@ -200,6 +204,8 @@ KX_KetsjiEngine::~KX_KetsjiEngine()
 
 	if (m_taskscheduler)
 		BLI_task_scheduler_free(m_taskscheduler);
+
+	BL_Action::EndLock();
 }
 
 
@@ -1019,6 +1025,10 @@ void KX_KetsjiEngine::GetSceneViewport(KX_Scene *scene, KX_Camera* cam, RAS_Rect
 
 void KX_KetsjiEngine::UpdateAnimations(KX_Scene *scene)
 {
+	if (scene->IsSuspended()) {
+		return;
+	}
+
 	// Handle the animations independently of the logic time step
 	if (GetRestrictAnimationFPS()) {
 		double anim_timestep = 1.0 / KX_GetActiveScene()->GetAnimationFPS();
diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp
index 7237369..56707bf 100644
--- a/source/gameengine/Ketsji/KX_Scene.cpp
+++ b/source/gameengine/Ketsji/KX_Scene.cpp
@@ -1678,10 +1678,6 @@ void KX_Scene::UpdateAnimations(double curtime)
 
 	BLI_task_pool_work_and_wait(pool);
 	BLI_task_pool_free(pool);
-
-	for (int i=0; i<m_animatedlist->GetCount(); ++i) {
-		((KX_GameObject*)m_animatedlist->GetValue(i))->UpdateActionIPOs();
-	}
 }
 
 void KX_Scene::LogicUpdateFrame(double curtime, bool frame)
diff --git a/source/gameengine/Ketsji/KX_SoundActuator.cpp b/source/gameengine/Ketsji/KX_SoundActuator.cpp
index 02b1071..f6f09dd 100644
--- a/source/gameengine/Ketsji/KX_SoundActuator.cpp
+++ b/source/gameengine/Ketsji/KX_SoundActuator.cpp
@@ -65,7 +65,7 @@ KX_SoundActuator::KX_SoundActuator(SCA_IObject* gameobj,
 								   KX_SOUNDACT_TYPE type)//,
 								   : SCA_IActuator(gameobj, KX_ACT_SOUND)
 {
-	m_sound = AUD_Sound_copy(sound);
+	m_sound = sound ? AUD_Sound_copy(sound) : NULL;
 	m_handle = NULL;
 	m_volume = volume;
 	m_pitch = pitch;
diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp
index dbaa925..1076ac5 100644
--- a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp
+++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp
@@ -1858,9 +1858,11 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject *meshobj, DerivedMesh *dm,
 	if (!dm) {
 		free_dm = true;
 		dm = CDDM_from_mesh(meshobj->GetMesh());
-		DM_ensure_tessface(dm);
 	}
 
+	// Some meshes with modifiers returns 0 polys, call DM_ensure_tessface avoid this.
+	DM_ensure_tessface(dm);
+
 	MVert *mvert = dm->getVertArray(dm);
 	MFace *mface = dm->getTessFaceArray(dm);
 	numpolys = dm->getNumTessFaces(dm);

-- 
blender packaging



More information about the pkg-multimedia-commits mailing list