diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7a920016f45d3cbb77dd5f567d388c3714aca672..dd24ea7cb601e788b2cb8397f535c50228b7ef9e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1515,6 +1515,7 @@ elseif(CMAKE_C_COMPILER_ID MATCHES "MSVC")
 		"/wd4267"  # conversion from 'size_t' to 'type', possible loss of data
 		"/wd4305"  # truncation from 'type1' to 'type2'
 		"/wd4800"  # forcing value to bool 'true' or 'false'
+		"/wd4828"  # The file contains a character that is illegal 
 		# errors:
 		"/we4013"  # 'function' undefined; assuming extern returning int
 		"/we4133"  # incompatible pointer types
diff --git a/build_files/build_environment/cmake/boost.cmake b/build_files/build_environment/cmake/boost.cmake
index 2c6bf195e07894217f76da7bac7116e47ea5dab2..46840b7ead457a414d18054f258683e7e4552e6f 100644
--- a/build_files/build_environment/cmake/boost.cmake
+++ b/build_files/build_environment/cmake/boost.cmake
@@ -53,17 +53,20 @@ if(WIN32)
 	if(BUILD_MODE STREQUAL Release)
 		set(BOOST_HARVEST_CMD ${BOOST_HARVEST_CMD} && ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/boost/include/boost-1_60/ ${HARVEST_TARGET}/boost/include/)
 	endif()
+	set(BOOST_PATCH_COMMAND ${PATCH_CMD} --verbose -p 1 -N -d ${BUILD_DIR}/boost/src/external_boost < ${PATCH_DIR}/boost.diff)
 
 elseif(APPLE)
 	set(BOOST_CONFIGURE_COMMAND ./bootstrap.sh)
 	set(BOOST_BUILD_COMMAND ./bjam)
 	set(BOOST_BUILD_OPTIONS toolset=clang cxxflags=${PLATFORM_CXXFLAGS} linkflags=${PLATFORM_LDFLAGS} --disable-icu boost.locale.icu=off)
 	set(BOOST_HARVEST_CMD echo .)
+	set(BOOST_PATCH_COMMAND echo .)
 else()
 	set(BOOST_HARVEST_CMD echo .)
 	set(BOOST_CONFIGURE_COMMAND ./bootstrap.sh)
 	set(BOOST_BUILD_COMMAND ./bjam)
 	set(BOOST_BUILD_OPTIONS cxxflags=${PLATFORM_CXXFLAGS} --disable-icu boost.locale.icu=off)
+	set(BOOST_PATCH_COMMAND echo .)
 endif()
 
 set(BOOST_OPTIONS
@@ -96,6 +99,7 @@ ExternalProject_Add(external_boost
 	URL_HASH MD5=${BOOST_MD5}
 	PREFIX ${BUILD_DIR}/boost
 	UPDATE_COMMAND	""
+	PATCH_COMMAND ${BOOST_PATCH_COMMAND}
 	CONFIGURE_COMMAND ${BOOST_CONFIGURE_COMMAND}
 	BUILD_COMMAND ${BOOST_BUILD_COMMAND} ${BOOST_BUILD_OPTIONS} -j${MAKE_THREADS} architecture=x86 address-model=${BOOST_ADDRESS_MODEL} variant=${BOOST_BUILD_TYPE} link=static threading=multi ${BOOST_OPTIONS}	--prefix=${LIBDIR}/boost install
 	BUILD_IN_SOURCE 1
diff --git a/build_files/build_environment/patches/boost.diff b/build_files/build_environment/patches/boost.diff
new file mode 100644
index 0000000000000000000000000000000000000000..ea3ec035518d79a620fbd3629b1b93fb67914baa
--- /dev/null
+++ b/build_files/build_environment/patches/boost.diff
@@ -0,0 +1,15 @@
+--- a/boost/config/compiler/visualc.hpp       2015-12-08 11:55:19 -0700
++++ b/boost/config/compiler/visualc.hpp    2018-03-17 10:29:52 -0600
+@@ -287,12 +287,3 @@
+ #  define BOOST_COMPILER "Microsoft Visual C++ version " BOOST_STRINGIZE(BOOST_COMPILER_VERSION)
+ #endif
+
+-//
+-// last known and checked version is 19.00.23026 (VC++ 2015 RTM):
+-#if (_MSC_VER > 1900)
+-#  if defined(BOOST_ASSERT_CONFIG)
+-#     error "Unknown compiler version - please run the configure tests and report the results"
+-#  else
+-#     pragma message("Unknown compiler version - please run the configure tests and report the results")
+-#  endif
+-#endif
diff --git a/build_files/cmake/config/blender_lite.cmake b/build_files/cmake/config/blender_lite.cmake
index 7db26c3f7c0d6c99b8d1051606c24a087980279f..1a5e6a3158ada50f8c71be94f5b5e8a3cc95da8f 100644
--- a/build_files/cmake/config/blender_lite.cmake
+++ b/build_files/cmake/config/blender_lite.cmake
@@ -9,6 +9,7 @@ set(WITH_INSTALL_PORTABLE    ON  CACHE BOOL "" FORCE)
 set(WITH_SYSTEM_GLEW         ON  CACHE BOOL "" FORCE)
 
 set(WITH_ALEMBIC             OFF CACHE BOOL "" FORCE)
+set(WITH_BOOST               OFF CACHE BOOL "" FORCE)
 set(WITH_BUILDINFO           OFF CACHE BOOL "" FORCE)
 set(WITH_BULLET              OFF CACHE BOOL "" FORCE)
 set(WITH_CODEC_AVI           OFF CACHE BOOL "" FORCE)
@@ -54,4 +55,3 @@ set(WITH_RAYOPTIMIZATION     OFF CACHE BOOL "" FORCE)
 set(WITH_SDL                 OFF CACHE BOOL "" FORCE)
 set(WITH_X11_XINPUT          OFF CACHE BOOL "" FORCE)
 set(WITH_X11_XF86VMODE       OFF CACHE BOOL "" FORCE)
-
diff --git a/doc/python_api/examples/bpy.props.1.py b/doc/python_api/examples/bpy.props.1.py
index 5153462893002245435adb2cd50539facc85f6b4..dd3a3ebc4325bcc09bf0ee594ef995696d8dc7ba 100644
--- a/doc/python_api/examples/bpy.props.1.py
+++ b/doc/python_api/examples/bpy.props.1.py
@@ -2,30 +2,56 @@
 Operator Example
 ++++++++++++++++
 
-A common use of custom properties is for python based :class:`Operator` classes.
+A common use of custom properties is for python based :class:`Operator`
+classes. Test this code by running it in the text editor, or by clicking the
+button in the 3D Viewport's Tools panel. The latter will show the properties
+in the Redo panel and allow you to change them.
 """
-
 import bpy
 
 
-class DialogOperator(bpy.types.Operator):
-    bl_idname = "object.dialog_operator"
+class OBJECT_OT_property_example(bpy.types.Operator):
+    bl_idname = "object.property_example"
     bl_label = "Property Example"
+    bl_options = {'REGISTER', 'UNDO'}
 
     my_float = bpy.props.FloatProperty(name="Some Floating Point")
     my_bool = bpy.props.BoolProperty(name="Toggle Option")
     my_string = bpy.props.StringProperty(name="String Value")
 
     def execute(self, context):
-        print("Dialog Runs")
+        self.report({'INFO'}, 'F: %.2f  B: %s  S: %r' %
+                    (self.my_float, self.my_bool, self.my_string))
+        print('My float:', self.my_float)
+        print('My bool:', self.my_bool)
+        print('My string:', self.my_string)
         return {'FINISHED'}
 
-    def invoke(self, context, event):
-        wm = context.window_manager
-        return wm.invoke_props_dialog(self)
-
 
-bpy.utils.register_class(DialogOperator)
-
-# test call
-bpy.ops.object.dialog_operator('INVOKE_DEFAULT')
+class OBJECT_PT_property_example(bpy.types.Panel):
+    bl_idname = "object_PT_property_example"
+    bl_label = "Property Example"
+    bl_space_type = 'VIEW_3D'
+    bl_region_type = 'TOOLS'
+    bl_category = "Tools"
+
+    def draw(self, context):
+        # You can set the property values that should be used when the user
+        # presses the button in the UI.
+        props = self.layout.operator('object.property_example')
+        props.my_bool = True
+        props.my_string = "Shouldn't that be 47?"
+
+        # You can set properties dynamically:
+        if context.object:
+            props.my_float = context.object.location.x
+        else:
+            props.my_float = 327
+
+
+bpy.utils.register_class(OBJECT_OT_property_example)
+bpy.utils.register_class(OBJECT_PT_property_example)
+
+# Demo call. Be sure to also test in the 3D Viewport.
+bpy.ops.object.property_example(my_float=47, my_bool=True,
+                                my_string="Shouldn't that be 327?")
diff --git a/doc/python_api/examples/bpy.props.5.py b/doc/python_api/examples/bpy.props.5.py
index 87741cbab8ab3a0b887798c7d9e2bed644013985..a9e79fa0272459692f4550c3c07fa79e8eea1033 100644
--- a/doc/python_api/examples/bpy.props.5.py
+++ b/doc/python_api/examples/bpy.props.5.py
@@ -1,13 +1,12 @@
 """
-Get/Set Example
-+++++++++++++++
+Getter/Setter Example
++++++++++++++++++++++
 
-Get/Set functions can be used for boolean, int, float, string and enum properties.
+Getter/setter functions can be used for boolean, int, float, string and enum properties.
 If these callbacks are defined the property will not be stored in the ID properties
-automatically, instead the get/set functions will be called when the property is
-read or written from the API.
+automatically. Instead, the `get` and `set` functions will be called when the property
+is respectively read or written from the API.
 """
-
 import bpy
 
 
@@ -65,25 +64,24 @@ def set_enum(self, value):
 bpy.types.Scene.test_enum = bpy.props.EnumProperty(items=test_items, get=get_enum, set=set_enum)
 
 
-# Testing
-
+# Testing the properties:
 scene = bpy.context.scene
 
 scene.test_float = 12.34
-print(scene.test_float)
+print('test_float:', scene.test_float)
 
 scene.test_array = (True, False)
-print([x for x in scene.test_array])
+print('test_array:', tuple(scene.test_array))
 
 # scene.test_date = "blah"   # this would fail, property is read-only
-print(scene.test_date)
+print('test_date:', scene.test_date)
 
 scene.test_enum = 'BLUE'
-print(scene.test_enum)
-
-
-# >>> 12.34000015258789
-# >>> [True, False]
-# >>> 2013-01-05 16:33:52.135340
-# >>> setting value 3
-# >>> GREEN
+print('test_enum:', scene.test_enum)
+
+# The above outputs:
+# test_float: 12.34000015258789
+# test_array: (True, False)
+# test_date: 2018-03-14 11:36:53.158653
+# setting value 3
+# test_enum: GREEN
diff --git a/doc/python_api/rst/info_api_reference.rst b/doc/python_api/rst/info_api_reference.rst
index 5ef5866c44a0808cf724a4f24995883b147da4f6..ab690a8ee062c96d510985297b4c57d35755659b 100644
--- a/doc/python_api/rst/info_api_reference.rst
+++ b/doc/python_api/rst/info_api_reference.rst
@@ -53,7 +53,7 @@ Here are some characteristics ID Data-Blocks share.
 Simple Data Access
 ------------------
 
-Lets start with a simple case, say you wan't a python script to adjust the objects location.
+Lets start with a simple case, say you want a python script to adjust the objects location.
 
 Start by finding this setting in the interface ``Properties Window -> Object -> Transform -> Location``
 
diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py
index 08c3e729ed9bd8d95bac8c5cbe1a83a511bfe172..50b07cabff4f726b2ca3a0c78cd996cf17a37fa5 100644
--- a/doc/python_api/sphinx_doc_gen.py
+++ b/doc/python_api/sphinx_doc_gen.py
@@ -417,19 +417,28 @@ MODULE_GROUPING = {
 # -------------------------------BLENDER----------------------------------------
 
 blender_version_strings = [str(v) for v in bpy.app.version]
+is_release = bpy.app.version_cycle in {"rc", "release"}
 
 # converting bytes to strings, due to T30154
 BLENDER_REVISION = str(bpy.app.build_hash, 'utf_8')
 BLENDER_DATE = str(bpy.app.build_date, 'utf_8')
 
-BLENDER_VERSION_DOTS = ".".join(blender_version_strings)    # '2.62.1'
+if is_release:
+    # '2.62a'
+    BLENDER_VERSION_DOTS = ".".join(blender_version_strings[:2]) + bpy.app.version_char
+else:
+    # '2.62.1'
+    BLENDER_VERSION_DOTS = ".".join(blender_version_strings)
 if BLENDER_REVISION != "Unknown":
-    BLENDER_VERSION_DOTS += " " + BLENDER_REVISION          # '2.62.1 SHA1'
+    # '2.62a SHA1' (release) or '2.62.1 SHA1' (non-release)
+    BLENDER_VERSION_DOTS += " " + BLENDER_REVISION          
 
-BLENDER_VERSION_PATH = "_".join(blender_version_strings)    # '2_62_1'
-if bpy.app.version_cycle in {"rc", "release"}:
+if is_release:
     # '2_62a_release'
     BLENDER_VERSION_PATH = "%s%s_release" % ("_".join(blender_version_strings[:2]), bpy.app.version_char)
+else:
+    # '2_62_1'
+    BLENDER_VERSION_PATH = "_".join(blender_version_strings)
 
 # --------------------------DOWNLOADABLE FILES----------------------------------
 
diff --git a/extern/curve_fit_nd/intern/generic_heap.c b/extern/curve_fit_nd/intern/generic_heap.c
index f41025318c49999310f1753cd63b1c44030bf71c..09ed84bea438b7d7d306384989f0fbb8c311d44f 100644
--- a/extern/curve_fit_nd/intern/generic_heap.c
+++ b/extern/curve_fit_nd/intern/generic_heap.c
@@ -305,3 +305,5 @@ void *HEAP_node_ptr(HeapNode *node)
 {
 	return node->ptr;
 }
+
+/** \} */
diff --git a/intern/cycles/app/cycles_standalone.cpp b/intern/cycles/app/cycles_standalone.cpp
index 2d4b0d35e548a87bd45982a7fd55b3bb6fac988e..c682744f5fafb8ca1d92a9ab53d8e749fd99cfde 100644
--- a/intern/cycles/app/cycles_standalone.cpp
+++ b/intern/cycles/app/cycles_standalone.cpp
@@ -51,6 +51,7 @@ struct Options {
 	SessionParams session_params;
 	bool quiet;
 	bool show_help, interactive, pause;
+	string output_path;
 } options;
 
 static void session_print(const string& str)
@@ -86,6 +87,34 @@ static void session_print_status()
 	session_print(status);
 }
 
+static bool write_render(const uchar *pixels, int w, int h, int channels)
+{
+	string msg = string_printf("Writing image %s", options.output_path.c_str());
+	session_print(msg);
+
+	ImageOutput *out = ImageOutput::create(options.output_path);
+	if(!out) {
+		return false;
+	}
+
+	ImageSpec spec(w, h, channels, TypeDesc::UINT8);
+	if(!out->open(options.output_path, spec)) {
+		return false;
+	}
+
+	/* conversion for different top/bottom convention */
+	out->write_image(TypeDesc::UINT8,
+		pixels + (h - 1) * w * channels,
+		AutoStride,
+		-w * channels,
+		AutoStride);
+
+	out->close();
+	delete out;
+
+	return true;
+}
+
 static BufferParams& session_buffer_params()
 {
 	static BufferParams buffer_params;
@@ -120,6 +149,7 @@ static void scene_init()
 
 static void session_init()
 {
+	options.session_params.write_render_cb = write_render;
 	options.session = new Session(options.session_params);
 
 	if(options.session_params.background && !options.quiet)
@@ -364,7 +394,7 @@ static void options_parse(int argc, const char **argv)
 		"--background", &options.session_params.background, "Render in background, without user interface",
 		"--quiet", &options.quiet, "In background mode, don't print progress messages",
 		"--samples %d", &options.session_params.samples, "Number of samples to render",
-		"--output %s", &options.session_params.output_path, "File path to write output image",
+		"--output %s", &options.output_path, "File path to write output image",
 		"--threads %d", &options.session_params.threads, "CPU Rendering Threads",
 		"--width  %d", &options.width, "Window width in pixel",
 		"--height %d", &options.height, "Window height in pixel",
diff --git a/intern/cycles/app/cycles_xml.cpp b/intern/cycles/app/cycles_xml.cpp
index 21ae07e23b846a4ca23be18a969ff178c969c6e1..a46955322e383f79854d8d9b5ecb5bbcb93be90b 100644
--- a/intern/cycles/app/cycles_xml.cpp
+++ b/intern/cycles/app/cycles_xml.cpp
@@ -40,6 +40,7 @@
 
 #include "util/util_foreach.h"
 #include "util/util_path.h"
+#include "util/util_projection.h"
 #include "util/util_transform.h"
 #include "util/util_xml.h"
 
@@ -546,8 +547,10 @@ static void xml_read_transform(xml_node node, Transform& tfm)
 {
 	if(node.attribute("matrix")) {
 		vector<float> matrix;
-		if(xml_read_float_array(matrix, node, "matrix") && matrix.size() == 16)
-			tfm = tfm * transform_transpose((*(Transform*)&matrix[0]));
+		if(xml_read_float_array(matrix, node, "matrix") && matrix.size() == 16) {
+			ProjectionTransform projection = *(ProjectionTransform*)&matrix[0];
+			tfm = tfm * projection_to_transform(projection_transpose(projection));
+		}
 	}
 
 	if(node.attribute("translate")) {
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index 5190c37b052f209de97f54bbb50bb6d4924c7213..585b159235e43ab48c39eb921683913e60ace1b7 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -546,6 +546,11 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
                 default=0,
                 min=0, max=16,
                 )
+        cls.use_bvh_embree = BoolProperty(
+                name="Use Embree",
+                description="Use Embree as ray accelerator",
+                default=True,
+                )
         cls.tile_order = EnumProperty(
                 name="Tile Order",
                 description="Tile order for rendering",
@@ -572,6 +577,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
                 ('SHADOW', "Shadow", ""),
                 ('NORMAL', "Normal", ""),
                 ('UV', "UV", ""),
+                ('ROUGHNESS', "Roughness", ""),
                 ('EMIT', "Emit", ""),
                 ('ENVIRONMENT', "Environment", ""),
                 ('DIFFUSE', "Diffuse", ""),
@@ -1089,7 +1095,7 @@ class CyclesObjectSettings(bpy.types.PropertyGroup):
 
         cls.motion_steps = IntProperty(
                 name="Motion Steps",
-                description="Control accuracy of deformation motion blur, more steps gives more memory usage (actual number of steps is 2^(steps - 1))",
+                description="Control accuracy of motion blur, more steps gives more memory usage (actual number of steps is 2^(steps - 1))",
                 min=1, soft_max=8,
                 default=1,
                 )
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index e3076a8ec2ce4b0ebcdc5b8a832f1a85d3b44e49..faefa648642205d5e3eb402a3618c7c5d56000b8 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -429,11 +429,17 @@ class CYCLES_RENDER_PT_performance(CyclesButtonsPanel, Panel):
         col.separator()
 
         col.label(text="Acceleration structure:")
+        row = col.row()
+        row.active = use_cpu(context)
+        row.prop(cscene, "use_bvh_embree")
+        row = col.row()
         col.prop(cscene, "debug_use_spatial_splits")
-        col.prop(cscene, "debug_use_hair_bvh")
+        row = col.row()
+        row.active = not cscene.use_bvh_embree
+        row.prop(cscene, "debug_use_hair_bvh")
 
         row = col.row()
-        row.active = not cscene.debug_use_spatial_splits
+        row.active = not cscene.debug_use_spatial_splits and not cscene.use_bvh_embree
         row.prop(cscene, "debug_bvh_time_steps")
 
         col = layout.column()
@@ -809,7 +815,7 @@ class CYCLES_OBJECT_PT_motion_blur(CyclesButtonsPanel, Panel):
     def poll(cls, context):
         ob = context.object
         if CyclesButtonsPanel.poll(context) and ob:
-            if ob.type in {'MESH', 'CURVE', 'CURVE', 'SURFACE', 'FONT', 'META'}:
+            if ob.type in {'MESH', 'CURVE', 'CURVE', 'SURFACE', 'FONT', 'META', 'CAMERA'}:
                 return True
             if ob.dupli_type == 'GROUP' and ob.dupli_group:
                 return True
@@ -841,11 +847,9 @@ class CYCLES_OBJECT_PT_motion_blur(CyclesButtonsPanel, Panel):
         layout.active = (rd.use_motion_blur and cob.use_motion_blur)
 
         row = layout.row()
-        row.prop(cob, "use_deform_motion", text="Deformation")
-
-        sub = row.row()
-        sub.active = cob.use_deform_motion
-        sub.prop(cob, "motion_steps", text="Steps")
+        if ob.type != 'CAMERA':
+            row.prop(cob, "use_deform_motion", text="Deformation")
+        row.prop(cob, "motion_steps", text="Steps")
 
 
 class CYCLES_OBJECT_PT_cycles_settings(CyclesButtonsPanel, Panel):
diff --git a/intern/cycles/blender/addon/version_update.py b/intern/cycles/blender/addon/version_update.py
index 90cecec215df863cf3fb0eb026bdee08230e18d3..292f0a1fa90c2b22113f6a0ba8569b793ab735fa 100644
--- a/intern/cycles/blender/addon/version_update.py
+++ b/intern/cycles/blender/addon/version_update.py
@@ -17,6 +17,7 @@
 # <pep8 compliant>
 
 import bpy
+import math
 
 from bpy.app.handlers import persistent
 
@@ -138,6 +139,56 @@ def displacement_principled_nodes(node):
         if node.subsurface_method != 'RANDOM_WALK':
             node.subsurface_method = 'BURLEY'
 
+def square_roughness_node_insert(material, nodetree, traversed):
+    if nodetree in traversed:
+        return
+    traversed.add(nodetree)
+
+    roughness_node_types = {
+        'ShaderNodeBsdfAnisotropic',
+        'ShaderNodeBsdfGlass',
+        'ShaderNodeBsdfGlossy',
+        'ShaderNodeBsdfRefraction'}
+
+    # Update default values
+    for node in nodetree.nodes:
+        if node.bl_idname == 'ShaderNodeGroup':
+            square_roughness_node_insert(material, node.node_tree, traversed)
+        elif node.bl_idname in roughness_node_types:
+            roughness_input = node.inputs['Roughness']
+            roughness_input.default_value = math.sqrt(max(roughness_input.default_value, 0.0))
+
+    # Gather roughness links to replace
+    roughness_links = []
+    for link in nodetree.links:
+        if link.to_node.bl_idname in roughness_node_types and \
+           link.to_socket.identifier == 'Roughness':
+           roughness_links.append(link)
+
+    # Replace links with sqrt node
+    for link in roughness_links:
+        from_node = link.from_node
+        from_socket = link.from_socket
+        to_node = link.to_node
+        to_socket = link.to_socket
+
+        nodetree.links.remove(link)
+
+        node = nodetree.nodes.new(type='ShaderNodeMath')
+        node.operation = 'POWER'
+        node.location[0] = 0.5 * (from_node.location[0] + to_node.location[0]);
+        node.location[1] = 0.5 * (from_node.location[1] + to_node.location[1]);
+
+        nodetree.links.new(from_socket, node.inputs[0])
+        node.inputs[1].default_value = 0.5
+        nodetree.links.new(node.outputs['Value'], to_socket)
+
+def square_roughness_nodes_insert():
+    traversed = set()
+    for material in bpy.data.materials:
+        if check_is_new_shading_material(material):
+            square_roughness_node_insert(material, material.node_tree, traversed)
+
 
 def mapping_node_order_flip(node):
     """
@@ -376,3 +427,7 @@ def do_versions(self):
                 cmat.displacement_method = 'BUMP'
 
         foreach_cycles_node(displacement_principled_nodes)
+
+    if bpy.data.version <= (2, 79, 3):
+        # Switch to squared roughness convention
+        square_roughness_nodes_insert()
diff --git a/intern/cycles/blender/blender_camera.cpp b/intern/cycles/blender/blender_camera.cpp
index 62e950e3befc95734cca0746a6f809cf0ee04fe7..f00ade320e780b6e8a1a1fff2568d13933d08955 100644
--- a/intern/cycles/blender/blender_camera.cpp
+++ b/intern/cycles/blender/blender_camera.cpp
@@ -83,6 +83,8 @@ struct BlenderCamera {
 	Transform matrix;
 
 	float offscreen_dicing_scale;
+
+	int motion_steps;
 };
 
 static void blender_camera_init(BlenderCamera *bcam,
@@ -226,6 +228,8 @@ static void blender_camera_from_object(BlenderCamera *bcam,
 			bcam->sensor_fit = BlenderCamera::HORIZONTAL;
 		else
 			bcam->sensor_fit = BlenderCamera::VERTICAL;
+
+		bcam->motion_steps = object_motion_steps(b_ob, b_ob);
 	}
 	else {
 		/* from lamp not implemented yet */
@@ -246,8 +250,7 @@ static Transform blender_camera_matrix(const Transform& tfm,
 			result = tfm *
 				make_transform(1.0f, 0.0f, 0.0f, 0.0f,
 				               0.0f, 0.0f, 1.0f, 0.0f,
-				               0.0f, 1.0f, 0.0f, 0.0f,
-				               0.0f, 0.0f, 0.0f, 1.0f);
+				               0.0f, 1.0f, 0.0f, 0.0f);
 		}
 		else {
 			/* Make it so environment camera needs to be pointed in the direction
@@ -257,8 +260,7 @@ static Transform blender_camera_matrix(const Transform& tfm,
 			result = tfm *
 				make_transform( 0.0f, -1.0f, 0.0f, 0.0f,
 				                0.0f,  0.0f, 1.0f, 0.0f,
-				               -1.0f,  0.0f, 0.0f, 0.0f,
-				                0.0f,  0.0f, 0.0f, 1.0f);
+				               -1.0f,  0.0f, 0.0f, 0.0f);
 		}
 	}
 	else {
@@ -455,9 +457,7 @@ static void blender_camera_sync(Camera *cam,
 	cam->matrix = blender_camera_matrix(bcam->matrix,
 	                                    bcam->type,
 	                                    bcam->panorama_type);
-	cam->motion.pre = cam->matrix;
-	cam->motion.post = cam->matrix;
-	cam->use_motion = false;
+	cam->motion.resize(bcam->motion_steps, cam->matrix);
 	cam->use_perspective_motion = false;
 	cam->shuttertime = bcam->shuttertime;
 	cam->fov_pre = cam->fov;
@@ -566,20 +566,15 @@ void BlenderSync::sync_camera_motion(BL::RenderSettings& b_render,
 	Transform tfm = get_transform(b_ob_matrix);
 	tfm = blender_camera_matrix(tfm, cam->type, cam->panorama_type);
 
-	if(tfm != cam->matrix) {
-		VLOG(1) << "Camera " << b_ob.name() << " motion detected.";
-		if(motion_time == 0.0f) {
-			/* When motion blur is not centered in frame, cam->matrix gets reset. */
-			cam->matrix = tfm;
-		}
-		else if(motion_time == -1.0f) {
-			cam->motion.pre = tfm;
-			cam->use_motion = true;
-		}
-		else if(motion_time == 1.0f) {
-			cam->motion.post = tfm;
-			cam->use_motion = true;
-		}
+	if(motion_time == 0.0f) {
+		/* When motion blur is not centered in frame, cam->matrix gets reset. */
+		cam->matrix = tfm;
+	}
+
+	/* Set transform in motion array. */
+	int motion_step = cam->motion_step(motion_time);
+	if(motion_step >= 0) {
+		cam->motion[motion_step] = tfm;
 	}
 
 	if(cam->type == CAMERA_PERSPECTIVE) {
diff --git a/intern/cycles/blender/blender_curves.cpp b/intern/cycles/blender/blender_curves.cpp
index f7cb0b66d299af43852ebb5521dd0d39faf02085..daccb89f5a2936f77f161661fceb4baf4b5a0641 100644
--- a/intern/cycles/blender/blender_curves.cpp
+++ b/intern/cycles/blender/blender_curves.cpp
@@ -633,10 +633,10 @@ static void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CDa
 	}
 }
 
-static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int time_index)
+static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int motion_step)
 {
 	VLOG(1) << "Exporting curve motion segments for mesh " << mesh->name
-	        << ", time index " << time_index;
+	        << ", motion step " << motion_step;
 
 	/* find attribute */
 	Attribute *attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
@@ -651,7 +651,7 @@ static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int
 
 	/* export motion vectors for curve keys */
 	size_t numkeys = mesh->curve_keys.size();
-	float4 *mP = attr_mP->data_float4() + time_index*numkeys;
+	float4 *mP = attr_mP->data_float4() + motion_step*numkeys;
 	bool have_motion = false;
 	int i = 0;
 
@@ -702,12 +702,12 @@ static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int
 			}
 			mesh->curve_attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION);
 		}
-		else if(time_index > 0) {
-			VLOG(1) << "Filling in new motion vertex position for time_index "
-			        << time_index;
+		else if(motion_step > 0) {
+			VLOG(1) << "Filling in new motion vertex position for motion_step "
+			        << motion_step;
 			/* motion, fill up previous steps that we might have skipped because
 			 * they had no motion, but we need them anyway now */
-			for(int step = 0; step < time_index; step++) {
+			for(int step = 0; step < motion_step; step++) {
 				float4 *mP = attr_mP->data_float4() + step*numkeys;
 
 				for(int key = 0; key < numkeys; key++) {
@@ -888,7 +888,7 @@ void BlenderSync::sync_curves(Mesh *mesh,
                               BL::Mesh& b_mesh,
                               BL::Object& b_ob,
                               bool motion,
-                              int time_index)
+                              int motion_step)
 {
 	if(!motion) {
 		/* Clear stored curve data */
@@ -951,7 +951,7 @@ void BlenderSync::sync_curves(Mesh *mesh,
 	}
 	else {
 		if(motion)
-			ExportCurveSegmentsMotion(mesh, &CData, time_index);
+			ExportCurveSegmentsMotion(mesh, &CData, motion_step);
 		else
 			ExportCurveSegments(scene, mesh, &CData);
 	}
diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp
index 998390e92a9d3609eb51be840ca8be24e66ddf8d..7d6ca18b074980b53bb61979fb488a0c2535c167 100644
--- a/intern/cycles/blender/blender_mesh.cpp
+++ b/intern/cycles/blender/blender_mesh.cpp
@@ -1248,36 +1248,10 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob,
 	if(mesh_synced.find(mesh) == mesh_synced.end())
 		return;
 
-	/* for motion pass always compute, for motion blur it can be disabled */
-	int time_index = 0;
-
-	if(scene->need_motion() == Scene::MOTION_BLUR) {
-		if(!mesh->use_motion_blur)
-			return;
-
-		/* see if this mesh needs motion data at this time */
-		vector<float> object_times = object->motion_times();
-		bool found = false;
-
-		foreach(float object_time, object_times) {
-			if(motion_time == object_time) {
-				found = true;
-				break;
-			}
-			else
-				time_index++;
-		}
-
-		if(!found)
-			return;
-	}
-	else {
-		if(motion_time == -1.0f)
-			time_index = 0;
-		else if(motion_time == 1.0f)
-			time_index = 1;
-		else
-			return;
+	/* Find time matching motion step required by mesh. */
+	int motion_step = mesh->motion_step(motion_time);
+	if(motion_step < 0) {
+		return;
 	}
 
 	/* skip empty meshes */
@@ -1319,9 +1293,9 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob,
 				float3 *P = &mesh->verts[0];
 				float3 *N = (attr_N)? attr_N->data_float3(): NULL;
 
-				memcpy(attr_mP->data_float3() + time_index*numverts, P, sizeof(float3)*numverts);
+				memcpy(attr_mP->data_float3() + motion_step*numverts, P, sizeof(float3)*numverts);
 				if(attr_mN)
-					memcpy(attr_mN->data_float3() + time_index*numverts, N, sizeof(float3)*numverts);
+					memcpy(attr_mN->data_float3() + motion_step*numverts, N, sizeof(float3)*numverts);
 			}
 		}
 
@@ -1331,7 +1305,7 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob,
 
 			if(attr_mP) {
 				float3 *keys = &mesh->curve_keys[0];
-				memcpy(attr_mP->data_float3() + time_index*numkeys, keys, sizeof(float3)*numkeys);
+				memcpy(attr_mP->data_float3() + motion_step*numkeys, keys, sizeof(float3)*numkeys);
 			}
 		}
 
@@ -1354,8 +1328,8 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob,
 			new_attribute = true;
 		}
 		/* Load vertex data from mesh. */
-		float3 *mP = attr_mP->data_float3() + time_index*numverts;
-		float3 *mN = (attr_mN)? attr_mN->data_float3() + time_index*numverts: NULL;
+		float3 *mP = attr_mP->data_float3() + motion_step*numverts;
+		float3 *mN = (attr_mN)? attr_mN->data_float3() + motion_step*numverts: NULL;
 		/* NOTE: We don't copy more that existing amount of vertices to prevent
 		 * possible memory corruption.
 		 */
@@ -1384,13 +1358,13 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob,
 				if(attr_mN)
 					mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_NORMAL);
 			}
-			else if(time_index > 0) {
+			else if(motion_step > 0) {
 				VLOG(1) << "Filling deformation motion for object " << b_ob.name();
 				/* motion, fill up previous steps that we might have skipped because
 				 * they had no motion, but we need them anyway now */
 				float3 *P = &mesh->verts[0];
 				float3 *N = (attr_N)? attr_N->data_float3(): NULL;
-				for(int step = 0; step < time_index; step++) {
+				for(int step = 0; step < motion_step; step++) {
 					memcpy(attr_mP->data_float3() + step*numverts, P, sizeof(float3)*numverts);
 					if(attr_mN)
 						memcpy(attr_mN->data_float3() + step*numverts, N, sizeof(float3)*numverts);
@@ -1400,7 +1374,7 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob,
 		else {
 			if(b_mesh.vertices.length() != numverts) {
 				VLOG(1) << "Topology differs, discarding motion blur for object "
-				        << b_ob.name() << " at time " << time_index;
+				        << b_ob.name() << " at time " << motion_step;
 				memcpy(mP, &mesh->verts[0], sizeof(float3)*numverts);
 				if(mN != NULL) {
 					memcpy(mN, attr_N->data_float3(), sizeof(float3)*numverts);
@@ -1411,7 +1385,7 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob,
 
 	/* hair motion */
 	if(numkeys)
-		sync_curves(mesh, b_mesh, b_ob, true, time_index);
+		sync_curves(mesh, b_mesh, b_ob, true, motion_step);
 
 	/* free derived mesh */
 	b_data.meshes.remove(b_mesh, false, true, false);
diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp
index 38ef1bc52498e51e371733e1a200da6864510f5b..077ceb4ebef4a96bbf111f2f78fa5cbf4c63fc7e 100644
--- a/intern/cycles/blender/blender_object.cpp
+++ b/intern/cycles/blender/blender_object.cpp
@@ -327,22 +327,11 @@ Object *BlenderSync::sync_object(BL::Object& b_parent,
 	if(motion) {
 		object = object_map.find(key);
 
-		if(object && (scene->need_motion() == Scene::MOTION_PASS ||
-		              object_use_motion(b_parent, b_ob)))
-		{
-			/* object transformation */
-			if(tfm != object->tfm) {
-				VLOG(1) << "Object " << b_ob.name() << " motion detected.";
-				if(motion_time == -1.0f || motion_time == 1.0f) {
-					object->use_motion = true;
-				}
-			}
-
-			if(motion_time == -1.0f) {
-				object->motion.pre = tfm;
-			}
-			else if(motion_time == 1.0f) {
-				object->motion.post = tfm;
+		if(object && object->use_motion()) {
+			/* Set transform at matching motion time step. */
+			int time_index = object->motion_step(motion_time);
+			if(time_index >= 0) {
+				object->motion[time_index] = tfm;
 			}
 
 			/* mesh deformation */
@@ -389,25 +378,37 @@ Object *BlenderSync::sync_object(BL::Object& b_parent,
 		object->name = b_ob.name().c_str();
 		object->pass_id = b_ob.pass_index();
 		object->tfm = tfm;
-		object->motion.pre = transform_empty();
-		object->motion.post = transform_empty();
-		object->use_motion = false;
+		object->motion.clear();
 
 		/* motion blur */
-		if(scene->need_motion() == Scene::MOTION_BLUR && object->mesh) {
+		Scene::MotionType need_motion = scene->need_motion();
+		if(need_motion != Scene::MOTION_NONE && object->mesh) {
 			Mesh *mesh = object->mesh;
-
 			mesh->use_motion_blur = false;
+			mesh->motion_steps = 0;
+
+			uint motion_steps;
 
-			if(object_use_motion(b_parent, b_ob)) {
-				if(object_use_deform_motion(b_parent, b_ob)) {
-					mesh->motion_steps = object_motion_steps(b_ob);
+			if(scene->need_motion() == Scene::MOTION_BLUR) {
+				motion_steps = object_motion_steps(b_parent, b_ob);
+				if(motion_steps && object_use_deform_motion(b_parent, b_ob)) {
+					mesh->motion_steps = motion_steps;
 					mesh->use_motion_blur = true;
 				}
+			}
+			else {
+				motion_steps = 3;
+				mesh->motion_steps = motion_steps;
+			}
+
+			object->motion.resize(motion_steps, transform_empty());
+
+			if(motion_steps) {
+				object->motion[motion_steps/2] = tfm;
 
-				vector<float> times = object->motion_times();
-				foreach(float time, times)
-					motion_times.insert(time);
+				for(size_t step = 0; step < motion_steps; step++) {
+					motion_times.insert(object->motion_time(step));
+				}
 			}
 		}
 
@@ -694,6 +695,11 @@ void BlenderSync::sync_motion(BL::RenderSettings& b_render,
 
 	/* note iteration over motion_times set happens in sorted order */
 	foreach(float relative_time, motion_times) {
+		/* center time is already handled. */
+		if(relative_time == 0.0f) {
+			continue;
+		}
+
 		VLOG(1) << "Synchronizing motion for the relative time "
 		        << relative_time << ".";
 
diff --git a/intern/cycles/blender/blender_object_cull.cpp b/intern/cycles/blender/blender_object_cull.cpp
index 1d747de647aa821cf1705def42e2e01d93c0056e..bdf7dc469b256ecf33bead5b677243778b82ff48 100644
--- a/intern/cycles/blender/blender_object_cull.cpp
+++ b/intern/cycles/blender/blender_object_cull.cpp
@@ -96,7 +96,7 @@ bool BlenderObjectCulling::test(Scene *scene, BL::Object& b_ob, Transform& tfm)
 bool BlenderObjectCulling::test_camera(Scene *scene, float3 bb[8])
 {
 	Camera *cam = scene->camera;
-	Transform& worldtondc = cam->worldtondc;
+	const ProjectionTransform& worldtondc = cam->worldtondc;
 	float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX),
 	       bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
 	bool all_behind = true;
diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp
index 9d1e87b763ccd782c8fb8fa2ece3065ae8f3e756..00d23b9095e5fa79000f8276642b3a0aa3f453ad 100644
--- a/intern/cycles/blender/blender_session.cpp
+++ b/intern/cycles/blender/blender_session.cpp
@@ -252,6 +252,8 @@ static ShaderEvalType get_shader_type(const string& pass_type)
 		return SHADER_EVAL_NORMAL;
 	else if(strcmp(shader_type, "UV")==0)
 		return SHADER_EVAL_UV;
+	else if(strcmp(shader_type, "ROUGHNESS")==0)
+		return SHADER_EVAL_ROUGHNESS;
 	else if(strcmp(shader_type, "DIFFUSE_COLOR")==0)
 		return SHADER_EVAL_DIFFUSE_COLOR;
 	else if(strcmp(shader_type, "GLOSSY_COLOR")==0)
diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp
index 283aa5600fd24d027f4c50eb767a4e41261398ee..a6e9cfbe617fadd1ab00b8a91e45da30b530b4e6 100644
--- a/intern/cycles/blender/blender_sync.cpp
+++ b/intern/cycles/blender/blender_sync.cpp
@@ -663,7 +663,9 @@ SceneParams BlenderSync::get_scene_params(BL::Scene& b_scene,
 	}
 
 	params.bvh_layout = DebugFlags().cpu.bvh_layout;
-
+#ifdef WITH_EMBREE
+	params.bvh_layout = RNA_boolean_get(&cscene, "use_bvh_embree") ? BVH_LAYOUT_EMBREE : params.bvh_layout;
+#endif
 	return params;
 }
 
diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h
index e7b71ae9310ec9f93dd122c3ea3d6b6fd0029f5b..1e7b0b32518e518d04fb9be3591a50389c1294dc 100644
--- a/intern/cycles/blender/blender_sync.h
+++ b/intern/cycles/blender/blender_sync.h
@@ -118,7 +118,7 @@ private:
 	                 BL::Mesh& b_mesh,
 	                 BL::Object& b_ob,
 	                 bool motion,
-	                 int time_index = 0);
+	                 int motion_step = 0);
 	Object *sync_object(BL::Object& b_parent,
 	                    int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
 	                    BL::DupliObject& b_dupli_ob,
diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h
index 363e19f7a20b6585961d537cec4c5f05f2be3398..c418b19a6373dfbcfcd57d498da28675fc960ccc 100644
--- a/intern/cycles/blender/blender_util.h
+++ b/intern/cycles/blender/blender_util.h
@@ -247,14 +247,15 @@ static inline float *image_get_float_pixels_for_frame(BL::Image& image,
 
 static inline Transform get_transform(const BL::Array<float, 16>& array)
 {
-	Transform tfm;
+	ProjectionTransform projection;
 
-	/* we assume both types to be just 16 floats, and transpose because blender
-	 * use column major matrix order while we use row major */
-	memcpy(&tfm, &array, sizeof(float)*16);
-	tfm = transform_transpose(tfm);
+	/* We assume both types to be just 16 floats, and transpose because blender
+	 * use column major matrix order while we use row major. */
+	memcpy(&projection, &array, sizeof(float)*16);
+	projection = projection_transpose(projection);
 
-	return tfm;
+	/* Drop last row, matrix is assumed to be affine transform. */
+	return projection_to_transform(projection);
 }
 
 static inline float2 get_float2(const BL::Array<float, 2>& array)
@@ -483,33 +484,34 @@ static inline void mesh_texture_space(BL::Mesh& b_mesh,
 	loc = loc*size - make_float3(0.5f, 0.5f, 0.5f);
 }
 
-/* object used for motion blur */
-static inline bool object_use_motion(BL::Object& b_parent, BL::Object& b_ob)
+/* Object motion steps, returns 0 if no motion blur needed. */
+static inline uint object_motion_steps(BL::Object& b_parent, BL::Object& b_ob)
 {
+	/* Get motion enabled and steps from object itself. */
 	PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
 	bool use_motion = get_boolean(cobject, "use_motion_blur");
-	/* If motion blur is enabled for the object we also check
-	 * whether it's enabled for the parent object as well.
-	 *
-	 * This way we can control motion blur from the dupligroup
-	 * duplicator much easier.
-	 */
-	if(use_motion && b_parent.ptr.data != b_ob.ptr.data) {
+	if(!use_motion) {
+		return 0;
+	}
+
+	uint steps = max(1, get_int(cobject, "motion_steps"));
+
+	/* Also check parent object, so motion blur and steps can be
+	 * controlled by dupligroup duplicator for linked groups. */
+	if(b_parent.ptr.data != b_ob.ptr.data) {
 		PointerRNA parent_cobject = RNA_pointer_get(&b_parent.ptr, "cycles");
 		use_motion &= get_boolean(parent_cobject, "use_motion_blur");
-	}
-	return use_motion;
-}
 
-/* object motion steps */
-static inline uint object_motion_steps(BL::Object& b_ob)
-{
-	PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
-	uint steps = get_int(cobject, "motion_steps");
+		if(!use_motion) {
+			return 0;
+		}
+
+		steps = max(steps, get_int(parent_cobject, "motion_steps"));
+	}
 
-	/* use uneven number of steps so we get one keyframe at the current frame,
-	 * and ue 2^(steps - 1) so objects with more/fewer steps still have samples
-	 * at the same times, to avoid sampling at many different times */
+	/* Use uneven number of steps so we get one keyframe at the current frame,
+	 * and use 2^(steps - 1) so objects with more/fewer steps still have samples
+	 * at the same times, to avoid sampling at many different times. */
 	return (2 << (steps - 1)) + 1;
 }
 
diff --git a/intern/cycles/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp
index c5c4c96979f3a847e25d3de292b3b2e07e33f37e..8c0a88e8e1b8e97ebcb04f35a17e748b048a353a 100644
--- a/intern/cycles/bvh/bvh.cpp
+++ b/intern/cycles/bvh/bvh.cpp
@@ -42,9 +42,9 @@ const char *bvh_layout_name(BVHLayout layout)
 	switch(layout) {
 		case BVH_LAYOUT_BVH2: return "BVH2";
 		case BVH_LAYOUT_BVH4: return "BVH4";
-                case BVH_LAYOUT_EMBREE: return "EMBREE";
 		case BVH_LAYOUT_NONE: return "NONE";
 		case BVH_LAYOUT_ALL:  return "ALL";
+		case BVH_LAYOUT_EMBREE: return "EMBREE";
 	}
 	LOG(DFATAL) << "Unsupported BVH layout was passed.";
 	return "";
@@ -111,7 +111,7 @@ BVH *BVH::create(const BVHParams& params, const vector<Object*>& objects)
 
 /* Building */
 
-void BVH::build(Progress& progress)
+void BVH::build(Progress& progress, Stats*)
 {
 	progress.set_substatus("Building BVH");
 
diff --git a/intern/cycles/bvh/bvh.h b/intern/cycles/bvh/bvh.h
index 6078a26ef965c7199505119788c8a1b7b2d38231..d445bf2a68d2e8e00b389418f832e5c0619fee0c 100644
--- a/intern/cycles/bvh/bvh.h
+++ b/intern/cycles/bvh/bvh.h
@@ -25,6 +25,7 @@
 
 CCL_NAMESPACE_BEGIN
 
+class Stats;
 class BVHNode;
 struct BVHStackEntry;
 class BVHParams;
@@ -85,21 +86,21 @@ public:
 	static BVH *create(const BVHParams& params, const vector<Object*>& objects);
 	virtual ~BVH() {}
 
-	virtual void build(Progress& progress);
-	virtual void refit(Progress& progress);
+	virtual void build(Progress& progress, Stats *stats=NULL);
+	void refit(Progress& progress);
 
 protected:
 	BVH(const BVHParams& params, const vector<Object*>& objects);
 
 	/* Refit range of primitives. */
-	virtual void refit_primitives(int start, int end, BoundBox& bbox, uint& visibility);
+	void refit_primitives(int start, int end, BoundBox& bbox, uint& visibility);
 
 	/* triangles and strands */
-	virtual void pack_primitives();
-	virtual void pack_triangle(int idx, float4 storage[3]);
+	void pack_primitives();
+	void pack_triangle(int idx, float4 storage[3]);
 
 	/* merge instance BVH's */
-	virtual void pack_instances(size_t nodes_size, size_t leaf_nodes_size);
+	void pack_instances(size_t nodes_size, size_t leaf_nodes_size);
 
 	/* for subclasses to implement */
 	virtual void pack_nodes(const BVHNode *root) = 0;
diff --git a/intern/cycles/bvh/bvh_embree.cpp b/intern/cycles/bvh/bvh_embree.cpp
index dff4d45927c771a786904933efbda6f1c8c1f47e..d2b7047667dc4cc4cf689976ccbfa97bca6df9e9 100644
--- a/intern/cycles/bvh/bvh_embree.cpp
+++ b/intern/cycles/bvh/bvh_embree.cpp
@@ -45,188 +45,151 @@ CCL_NAMESPACE_BEGIN
  */
 
 
-/* occlusion filter function for single rays and packets */
-//void occlusionFilter(const RTCFilterFunctionNArguments* args)
-//{
-//  /* avoid crashing when debug visualizations are used */
-//  if (args->context == nullptr) return;
-//
-//  assert(args->N == 1);
-//  int* valid = args->valid;
-//  const IntersectContext* context = (const IntersectContext*) args->context;
-//  Ray* ray = (Ray*)args->ray;
-//  RTCHit* hit = (RTCHit*)args->hit;
-//
-//  /* ignore inactive rays */
-//  if (valid[0] != -1) return;
-//
-//  Ray2* ray2 = (Ray2*) context->userRayExt;
-//  assert(ray2);
-//
-//  for (unsigned int i=ray2->firstHit; i<ray2->lastHit; i++) {
-//    unsigned slot= i%HIT_LIST_LENGTH;
-//    if (ray2->hit_geomIDs[slot] == hit->geomID && ray2->hit_primIDs[slot] == hit->primID) {
-//      return;
-//    }
-//  }
-//  /* store hit in hit list */
-//  unsigned int slot = ray2->lastHit%HIT_LIST_LENGTH;
-//  ray2->hit_geomIDs[slot] = hit->geomID;
-//  ray2->hit_primIDs[slot] = hit->primID;
-//  ray2->lastHit++;
-//  if (ray2->lastHit - ray2->firstHit >= HIT_LIST_LENGTH)
-//    ray2->firstHit++;
-//
-//  Vec3fa h = ray->org + ray->dir * ray->tfar;
-//
-//  /* calculate and accumulate transparency */
-//  float T = transparencyFunction(h);
-//  T *= ray2->transparency;
-//  ray2->transparency = T;
-//  if (T != 0.0f) 
-//    valid[0] = 0;
-//}
-
 void rtc_filter_func(const RTCFilterFunctionNArguments* args);
-
-void rtc_filter_func(const RTCFilterFunctionNArguments* args) {
-    
+void rtc_filter_func(const RTCFilterFunctionNArguments* args)
+{
     /* avoid crashing when debug visualizations are used */
-    if (args->context == nullptr) return;
+    if(args->context == nullptr) return;
 
     assert(args->N == 1);
     int* valid = args->valid;
 
     /* ignore inactive rays */
-    if (valid[0] != -1) return;
+    if(valid[0] != -1) return;
 
     const IntersectContext* context = (const IntersectContext*) args->context;
     CCLRay* ray = (CCLRay*) context->userRayExt;
 
     RTCRay* eray = (RTCRay*) args->ray;
     RTCHit* ehit = (RTCHit*) args->hit;
-    
+
     ray->ray = *eray;
     ray->hit = *ehit;
 
     KernelGlobals *kg = ray->kg;
 
     /* For all ray types: check if there is backfacing hair to ignore */
-    if ((kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE)
-            && !(kernel_data.curve.curveflags & CURVE_KN_BACKFACING)
-            && !(kernel_data.curve.curveflags & CURVE_KN_RIBBONS) && ehit->geomID & 1) {
-        if (dot(make_float3(eray->dir_x, eray->dir_y, eray->dir_z), make_float3(ehit->Ng_x, ehit->Ng_y, ehit->Ng_z)) > 0.0f) {
-            ehit->geomID = RTC_INVALID_GEOMETRY_ID;
-            valid[0] = 0;
-            return;
-        }
-    }
-
-    if (ray->type == CCLRay::RAY_REGULAR) {
-        return;
-    } else if (ray->type == CCLRay::RAY_SHADOW_ALL) {
-        /* Append the intersection to the end of the array. */
-        if (ray->num_hits < ray->max_hits) {
-            Intersection *isect = &ray->isect_s[ray->num_hits];
-            ray->num_hits++;
-            ray->isect_to_ccl(isect);
-            int prim = kernel_tex_fetch(__prim_index, isect->prim);
-            int shader = 0;
-            if (kernel_tex_fetch(__prim_type, isect->prim) & PRIMITIVE_ALL_TRIANGLE) {
-                shader = kernel_tex_fetch(__tri_shader, prim);
-            } else {
-                float4 str = kernel_tex_fetch(__curves, prim);
-                shader = __float_as_int(str.z);
-            }
-            int flag = kernel_tex_fetch(__shader_flag, (shader & SHADER_MASK) * SHADER_SIZE);
-            /* If no transparent shadows, all light is blocked. */
-            if (flag & (SD_HAS_TRANSPARENT_SHADOW)) {
-                /* This tells Embree to continue tracing. */
-                ehit->geomID = RTC_INVALID_GEOMETRY_ID;
-                valid[0] = 0;
-            } else {
-                ray->num_hits = ray->max_hits + 1;
-            }
-        } else {
-            /* Increase the number of hits beyond ray->max_hits
-             * so that the caller can detect this as opaque. */
-            ray->num_hits++;
-        }
-        return;
-    } else if (ray->type == CCLRay::RAY_SSS) {
-        /* Only accept hits from the same object and triangles. */
-        if (ehit->instID[0] / 2 != ray->sss_object_id || ehit->geomID & 1) {
-            /* This tells Embree to continue tracing. */
-            ehit->geomID = RTC_INVALID_GEOMETRY_ID;
-            valid[0] = 0;
-            return;
-        }
-
-        /* See triangle_intersect_subsurface() for the native equivalent. */
-        for (int i = min(ray->max_hits, ray->ss_isect->num_hits) - 1; i >= 0; --i) {
-            if (ray->ss_isect->hits[i].t == eray->tfar) {
-                /* This tells Embree to continue tracing. */
-                ehit->geomID = RTC_INVALID_GEOMETRY_ID;
-                valid[0] = 0;
-                return;
-            }
-        }
-
-        ray->ss_isect->num_hits++;
-        int hit;
-
-        if (ray->ss_isect->num_hits <= ray->max_hits) {
-            hit = ray->ss_isect->num_hits - 1;
-        } else {
-            /* reservoir sampling: if we are at the maximum number of
-             * hits, randomly replace element or skip it */
-            hit = lcg_step_uint(ray->lcg_state) % ray->ss_isect->num_hits;
-
-            if (hit >= ray->max_hits) {
-                /* This tells Embree to continue tracing. */
-                ehit->geomID = RTC_INVALID_GEOMETRY_ID;
-                valid[0] = 0;
-                return;
-            }
-        }
-        /* record intersection */
-        ray->isect_to_ccl(&ray->ss_isect->hits[hit]);
-        ray->ss_isect->Ng[hit].x = -ehit->Ng_x;
-        ray->ss_isect->Ng[hit].y = -ehit->Ng_y;
-        ray->ss_isect->Ng[hit].z = -ehit->Ng_z;
-        ray->ss_isect->Ng[hit] = normalize(ray->ss_isect->Ng[hit]);
-        /* this tells Embree to continue tracing */
-        ehit->geomID = RTC_INVALID_GEOMETRY_ID;
-        valid[0] = 0;
-        return;
-    } else if (ray->type == CCLRay::RAY_VOLUME_ALL) {
-        /* Append the intersection to the end of the array-> */
-        if (ray->num_hits < ray->max_hits) {
-            Intersection *isect = &ray->isect_s[ray->num_hits];
-            ray->num_hits++;
-            ray->isect_to_ccl(isect);
-            /* Only primitives from volume object. */
-            uint tri_object = (isect->object == OBJECT_NONE) ? kernel_tex_fetch(__prim_object, isect->prim) : isect->object;
-            int object_flag = kernel_tex_fetch(__object_flag, tri_object);
-            if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
-                ray->num_hits--;
-            }
-            /* This tells Embree to continue tracing. */
-            ehit->geomID = RTC_INVALID_GEOMETRY_ID;
-            valid[0] = 0;
-            return;
-        }
-        return;
+	if((kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE)
+	    && !(kernel_data.curve.curveflags & CURVE_KN_BACKFACING)
+	    && !(kernel_data.curve.curveflags & CURVE_KN_RIBBONS) && ehit->geomID & 1) {
+            if(dot(make_float3(eray->dir_x, eray->dir_y, eray->dir_z), make_float3(ehit->Ng_x, ehit->Ng_y, ehit->Ng_z)) > 0.0f) {
+                    ehit->geomID = RTC_INVALID_GEOMETRY_ID;
+                    valid[0] = 0;
+                    return;
+	}
+    }
+
+    if(ray->type == CCLRay::RAY_REGULAR) {
+	return;
+    } 
+    else if(ray->type == CCLRay::RAY_SHADOW_ALL) {
+	/* Append the intersection to the end of the array. */
+	if(ray->num_hits < ray->max_hits) {
+	    Intersection *isect = &ray->isect_s[ray->num_hits];
+	    ray->num_hits++;
+	    ray->isect_to_ccl(isect);
+	    int prim = kernel_tex_fetch(__prim_index, isect->prim);
+	    int shader = 0;
+	    if(kernel_tex_fetch(__prim_type, isect->prim) & PRIMITIVE_ALL_TRIANGLE) {
+		shader = kernel_tex_fetch(__tri_shader, prim);
+	    } 
+            else {
+		float4 str = kernel_tex_fetch(__curves, prim);
+		shader = __float_as_int(str.z);
+	    }
+			int flag = kernel_tex_fetch(__shaders, shader & SHADER_MASK).flags;
+	    /* If no transparent shadows, all light is blocked. */
+	    if(flag & (SD_HAS_TRANSPARENT_SHADOW)) {
+		/* This tells Embree to continue tracing. */
+		ehit->geomID = RTC_INVALID_GEOMETRY_ID;
+		valid[0] = 0;
+	    } 
+            else {
+		ray->num_hits = ray->max_hits + 1;
+	    }
+	} 
+        else {
+	    /* Increase the number of hits beyond ray->max_hits
+	     * so that the caller can detect this as opaque. */
+	    ray->num_hits++;
+	}
+	return;
+    } 
+    else if(ray->type == CCLRay::RAY_SSS) {
+	/* Only accept hits from the same object and triangles. */
+	if(ehit->instID[0] / 2 != ray->sss_object_id || ehit->geomID & 1) {
+	    /* This tells Embree to continue tracing. */
+	    ehit->geomID = RTC_INVALID_GEOMETRY_ID;
+	    valid[0] = 0;
+	    return;
+	}
+
+	/* See triangle_intersect_subsurface() for the native equivalent. */
+	for (int i = min(ray->max_hits, ray->ss_isect->num_hits) - 1; i >= 0; --i) {
+	    if(ray->ss_isect->hits[i].t == eray->tfar) {
+		/* This tells Embree to continue tracing. */
+		ehit->geomID = RTC_INVALID_GEOMETRY_ID;
+		valid[0] = 0;
+		return;
+	    }
+	}
+
+	ray->ss_isect->num_hits++;
+	int hit;
+
+	if(ray->ss_isect->num_hits <= ray->max_hits) {
+	    hit = ray->ss_isect->num_hits - 1;
+	} 
+        else {
+	    /* reservoir sampling: if we are at the maximum number of
+	     * hits, randomly replace element or skip it */
+	    hit = lcg_step_uint(ray->lcg_state) % ray->ss_isect->num_hits;
+
+	    if(hit >= ray->max_hits) {
+		/* This tells Embree to continue tracing. */
+		ehit->geomID = RTC_INVALID_GEOMETRY_ID;
+		valid[0] = 0;
+		return;
+	    }
+	}
+	/* record intersection */
+	ray->isect_to_ccl(&ray->ss_isect->hits[hit]);
+	ray->ss_isect->Ng[hit].x = -ehit->Ng_x;
+	ray->ss_isect->Ng[hit].y = -ehit->Ng_y;
+	ray->ss_isect->Ng[hit].z = -ehit->Ng_z;
+	ray->ss_isect->Ng[hit] = normalize(ray->ss_isect->Ng[hit]);
+	/* this tells Embree to continue tracing */
+	ehit->geomID = RTC_INVALID_GEOMETRY_ID;
+	valid[0] = 0;
+	return;
+    } else if(ray->type == CCLRay::RAY_VOLUME_ALL) {
+	/* Append the intersection to the end of the array-> */
+	if(ray->num_hits < ray->max_hits) {
+	    Intersection *isect = &ray->isect_s[ray->num_hits];
+	    ray->num_hits++;
+	    ray->isect_to_ccl(isect);
+	    /* Only primitives from volume object. */
+	    uint tri_object = (isect->object == OBJECT_NONE) ? kernel_tex_fetch(__prim_object, isect->prim) : isect->object;
+	    int object_flag = kernel_tex_fetch(__object_flag, tri_object);
+	    if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
+		ray->num_hits--;
+	    }
+	    /* This tells Embree to continue tracing. */
+	    ehit->geomID = RTC_INVALID_GEOMETRY_ID;
+	    valid[0] = 0;
+	    return;
+	}
+	return;
     }
 
     return;
 }
 bool rtc_memory_monitor_func(void* userPtr, const ssize_t bytes, const bool post);
-
-bool rtc_memory_monitor_func(void* userPtr, const ssize_t bytes, const bool) {
+bool rtc_memory_monitor_func(void* userPtr, const ssize_t bytes, const bool) 
+{
     BVHEmbree *bvh = (BVHEmbree*) userPtr;
-    if (bvh) {
-        bvh->mem_monitor(bytes);
+    if(bvh) {
+	bvh->mem_monitor(bytes);
     }
     return true;
 }
@@ -234,12 +197,12 @@ bool rtc_memory_monitor_func(void* userPtr, const ssize_t bytes, const bool) {
 static double progress_start_time = 0.0f;
 
 bool rtc_progress_func(void* user_ptr, const double n);
-
-bool rtc_progress_func(void* user_ptr, const double n) {
+bool rtc_progress_func(void* user_ptr, const double n) 
+{
     Progress *progress = (Progress*) user_ptr;
 
-    if (time_dt() - progress_start_time < 0.25)
-        return true;
+    if(time_dt() - progress_start_time < 0.25)
+	return true;
 
     string msg = string_printf("Building BVH %.0f%%", n * 100.0);
 
@@ -255,41 +218,42 @@ int BVHEmbree::rtc_shared_users = 0;
 thread_mutex BVHEmbree::rtc_shared_mutex;
 
 BVHEmbree::BVHEmbree(const BVHParams& params_, const vector<Object*>& objects_)
-: BVH(params_, objects_), scene(NULL), mem_used(0), top_level(NULL),
+: BVH(params_, objects_), scene(NULL), mem_used(0), top_level(NULL), stats(NULL),
 curve_subdivisions(params.curve_subdivisions), use_curves(params_.curve_flags & CURVE_KN_INTERPOLATE),
-use_ribbons(params.curve_flags & CURVE_KN_RIBBONS), dynamic_scene(true) {
+use_ribbons(params.curve_flags & CURVE_KN_RIBBONS), dynamic_scene(true) 
+{
     _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
     _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
     thread_scoped_lock lock(rtc_shared_mutex);
-    if (rtc_shared_users == 0) {
-        rtc_shared_device = rtcNewDevice("verbose=1");
-
-        /* Check here if Embree was built with the correct flags. */
-        ssize_t ret = rtcGetDeviceProperty(rtc_shared_device, RTC_DEVICE_PROPERTY_RAY_MASK_SUPPORTED);
-        if (ret != 1) {
-            assert(0);
-            VLOG(1) << "Embree is compiled without the RTC_DEVICE_PROPERTY_RAY_MASK_SUPPORTED flag. Ray visiblity will not work.";
-        }
-        ret = rtcGetDeviceProperty(rtc_shared_device, RTC_DEVICE_PROPERTY_FILTER_FUNCTION_SUPPORTED);
-        if (ret != 1) {
-            assert(0);
-            VLOG(1) << "Embree is compiled without the RTC_DEVICE_PROPERTY_FILTER_FUNCTION_SUPPORTED flag. Renders may not look as expected.";
-        }
-        ret = rtcGetDeviceProperty(rtc_shared_device, RTC_DEVICE_PROPERTY_CURVE_GEOMETRY_SUPPORTED);
-        if (ret != 1) {
-            assert(0);
-            VLOG(1) << "Embree is compiled without the RTC_DEVICE_PROPERTY_CURVE_GEOMETRY_SUPPORTED flag. Line primitives will not be rendered.";
-        }
-        ret = rtcGetDeviceProperty(rtc_shared_device, RTC_DEVICE_PROPERTY_TRIANGLE_GEOMETRY_SUPPORTED);
-        if (ret != 1) {
-            assert(0);
-            VLOG(1) << "Embree is compiled without the RTC_DEVICE_PROPERTY_TRIANGLE_GEOMETRY_SUPPORTED flag. Triangle primitives will not be rendered.";
-        }
-        ret = rtcGetDeviceProperty(rtc_shared_device, RTC_DEVICE_PROPERTY_BACKFACE_CULLING_ENABLED);
-        if (ret != 0) {
-            assert(0);
-            VLOG(1) << "Embree is compiled with the RTC_DEVICE_PROPERTY_BACKFACE_CULLING_ENABLED flag. Renders may not look as expected.";
-        }
+    if(rtc_shared_users == 0) {
+	rtc_shared_device = rtcNewDevice("verbose=1");
+
+	/* Check here if Embree was built with the correct flags. */
+	ssize_t ret = rtcGetDeviceProperty(rtc_shared_device, RTC_DEVICE_PROPERTY_RAY_MASK_SUPPORTED);
+	if(ret != 1) {
+	    assert(0);
+	    VLOG(1) << "Embree is compiled without the RTC_DEVICE_PROPERTY_RAY_MASK_SUPPORTED flag. Ray visiblity will not work.";
+	}
+	ret = rtcGetDeviceProperty(rtc_shared_device, RTC_DEVICE_PROPERTY_FILTER_FUNCTION_SUPPORTED);
+	if(ret != 1) {
+	    assert(0);
+	    VLOG(1) << "Embree is compiled without the RTC_DEVICE_PROPERTY_FILTER_FUNCTION_SUPPORTED flag. Renders may not look as expected.";
+	}
+	ret = rtcGetDeviceProperty(rtc_shared_device, RTC_DEVICE_PROPERTY_CURVE_GEOMETRY_SUPPORTED);
+	if(ret != 1) {
+	    assert(0);
+	    VLOG(1) << "Embree is compiled without the RTC_DEVICE_PROPERTY_CURVE_GEOMETRY_SUPPORTED flag. Line primitives will not be rendered.";
+	}
+	ret = rtcGetDeviceProperty(rtc_shared_device, RTC_DEVICE_PROPERTY_TRIANGLE_GEOMETRY_SUPPORTED);
+	if(ret != 1) {
+	    assert(0);
+	    VLOG(1) << "Embree is compiled without the RTC_DEVICE_PROPERTY_TRIANGLE_GEOMETRY_SUPPORTED flag. Triangle primitives will not be rendered.";
+	}
+	ret = rtcGetDeviceProperty(rtc_shared_device, RTC_DEVICE_PROPERTY_BACKFACE_CULLING_ENABLED);
+	if(ret != 0) {
+	    assert(0);
+	    VLOG(1) << "Embree is compiled with the RTC_DEVICE_PROPERTY_BACKFACE_CULLING_ENABLED flag. Renders may not look as expected.";
+	}
     }
     rtc_shared_users++;
 
@@ -301,97 +265,112 @@ use_ribbons(params.curve_flags & CURVE_KN_RIBBONS), dynamic_scene(true) {
     params.bvh_layout = BVH_LAYOUT_EMBREE;
 }
 
-BVHEmbree::~BVHEmbree() {
-    if (!params.top_level) {
-        destroy(scene);
+BVHEmbree::~BVHEmbree() 
+{
+    if(!params.top_level) {
+	destroy(scene);
     }
 }
 
-void BVHEmbree::destroy(RTCScene scene) {
-    if (scene) {
-        rtcReleaseScene(scene);
-        scene = NULL;
+void BVHEmbree::destroy(RTCScene scene) 
+{
+    if(scene) {
+	rtcReleaseScene(scene);
+	scene = NULL;
     }
     thread_scoped_lock lock(rtc_shared_mutex);
     rtc_shared_users--;
-    if (rtc_shared_users == 0) {
-        rtcReleaseDevice(rtc_shared_device);
-        rtc_shared_device = NULL;
+    if(rtc_shared_users == 0) {
+	rtcReleaseDevice(rtc_shared_device);
+	rtc_shared_device = NULL;
     }
 }
 
-void BVHEmbree::delete_rtcScene() {
-    if (scene) {
-        /* When this BVH is used as an instance in a top level BVH, don't delete now
-         * Let the top_level BVH know that it should delete it later. */
-        if (top_level) {
-            top_level->add_delayed_delete_scene(scene);
-        } else {
-            rtcReleaseScene(scene);
-            if (delayed_delete_scenes.size()) {
-
-                foreach(RTCScene s, delayed_delete_scenes) {
-                    rtcReleaseScene(s);
-                }
-            }
-            delayed_delete_scenes.clear();
-        }
-        scene = NULL;
+void BVHEmbree::delete_rtcScene() 
+{
+    if(scene) {
+	/* When this BVH is used as an instance in a top level BVH, don't delete now
+	 * Let the top_level BVH know that it should delete it later. */
+	if(top_level) {
+	    top_level->add_delayed_delete_scene(scene);
+	} 
+        else {
+	    rtcReleaseScene(scene);
+	    if(delayed_delete_scenes.size()) {
+		foreach(RTCScene s, delayed_delete_scenes) {
+		    rtcReleaseScene(s);
+		}
+	    }
+	    delayed_delete_scenes.clear();
+	}
+	scene = NULL;
     }
 }
 
-void BVHEmbree::mem_monitor(ssize_t bytes) {
+void BVHEmbree::mem_monitor(ssize_t bytes)
+{
+	if(stats) {
+		if(bytes > 0) {
+			stats->mem_alloc(bytes);
+		} else {
+			stats->mem_free(-bytes);
+		}
+	}
     mem_used += bytes;
 }
 
-void BVHEmbree::build(Progress& progress) {
+void BVHEmbree::build(Progress& progress, Stats *stats_)
+{
+	stats = stats_;
+
     progress.set_substatus("Building BVH");
 
-    if (scene) {
-        rtcReleaseScene(scene);
-        scene = NULL;
+    if(scene) {
+	rtcReleaseScene(scene);
+	scene = NULL;
     }
 
     RTCSceneFlags flags = RTC_SCENE_FLAG_COMPACT | RTC_SCENE_FLAG_ROBUST;
-    if (params.bvh_type == SceneParams::BVH_DYNAMIC) {
-        flags = (RTCSceneFlags) (flags | RTC_SCENE_FLAG_DYNAMIC);
+    if(params.bvh_type == SceneParams::BVH_DYNAMIC) {
+	flags = (RTCSceneFlags) (flags | RTC_SCENE_FLAG_DYNAMIC);
     }
 
     RTCBuildQuality buildQuality = (params.bvh_type == SceneParams::BVH_DYNAMIC ? RTC_BUILD_QUALITY_LOW : RTC_BUILD_QUALITY_MEDIUM);
-    if (params.use_spatial_split) {
-        buildQuality = RTC_BUILD_QUALITY_HIGH;
+    if(params.use_spatial_split) {
+	buildQuality = RTC_BUILD_QUALITY_HIGH;
     }
 
     scene = rtcNewScene(rtc_shared_device);
-    rtcSetSceneFlags(scene, flags); // EMBREE_FIXME: set proper scene flags
-    rtcSetSceneBuildQuality(scene, buildQuality); // EMBREE_FIXME: set proper build quality
-    //   rtcCommitScene(scene);
+    rtcSetSceneFlags(scene, flags);
+    rtcSetSceneBuildQuality(scene, buildQuality);
 
     int i = 0;
 
     pack.object_node.clear();
 
     foreach(Object *ob, objects) {
-        if (params.top_level) {
-            if (!ob->is_traceable()) {
-                ++i;
-                continue;
-            }
-            if (!ob->mesh->is_instanced()) {
-                add_object(ob, i);
-            } else {
-                add_instance(ob, i);
-            }
-        } else {
-            add_object(ob, i);
-        }
-        ++i;
-        if (progress.get_cancel()) return;
-    }
-
-    if (progress.get_cancel()) {
-        delete_rtcScene();
-        return;
+	if(params.top_level) {
+	    if(!ob->is_traceable()) {
+		++i;
+		continue;
+	    }
+	    if(!ob->mesh->is_instanced()) {
+		add_object(ob, i);
+			}
+			else {
+		add_instance(ob, i);
+	    }
+		}
+		else {
+	    add_object(ob, i);
+	}
+	++i;
+	if(progress.get_cancel()) return;
+    }
+
+    if(progress.get_cancel()) {
+	delete_rtcScene();
+	return;
     }
 
     rtcSetSceneProgressMonitorFunction(scene, rtc_progress_func, &progress);
@@ -399,117 +378,95 @@ void BVHEmbree::build(Progress& progress) {
 
     pack_primitives();
 
-    if (progress.get_cancel()) {
-        delete_rtcScene();
-        return;
+    if(progress.get_cancel()) {
+	delete_rtcScene();
+		stats = NULL;
+	return;
     }
 
     progress.set_substatus("Packing geometry");
     pack_nodes(NULL);
-}
 
-void BVHEmbree::add_object(Object *ob, int i) {
-    //RTCGeometry geom_id = NULL;
+	stats = NULL;
+}
 
-    if (params.primitive_mask & PRIMITIVE_ALL_TRIANGLE && ob->mesh->num_triangles() > 0) {
-        //size_t prim_offset = pack.prim_index.size();
-        add_triangles(ob, i);
+void BVHEmbree::add_object(Object *ob, int i)
+{
+    if(params.primitive_mask & PRIMITIVE_ALL_TRIANGLE && ob->mesh->num_triangles() > 0) {
+	add_triangles(ob, i);
     }
 
-    if (params.primitive_mask & PRIMITIVE_ALL_CURVE && ob->mesh->num_curves() > 0) {
-        // size_t prim_offset = pack.prim_index.size();
-        add_curves(ob, i);
+    if(params.primitive_mask & PRIMITIVE_ALL_CURVE && ob->mesh->num_curves() > 0) {
+	add_curves(ob, i);
     }
 }
 
-void BVHEmbree::add_instance(Object *ob, int i) {
-    if (!ob || !ob->mesh) {
-        assert(0);
-        return;
+void BVHEmbree::add_instance(Object *ob, int i)
+{
+    if(!ob || !ob->mesh) {
+	assert(0);
+	return;
     }
     BVHEmbree *instance_bvh = (BVHEmbree*) (ob->mesh->bvh);
 
-    if (instance_bvh->top_level != this) {
-        instance_bvh->top_level = this;
+    if(instance_bvh->top_level != this) {
+	instance_bvh->top_level = this;
     }
 
-    const size_t num_motion_steps = ob->use_motion ? 3 : 1;
-    //unsigned int geom_id = i * 2;
+	const size_t num_motion_steps = ob->use_motion() ? ob->motion.size() : 1;
     RTCGeometry geom_id = rtcNewGeometry(rtc_shared_device, RTC_GEOMETRY_TYPE_INSTANCE); // EMBREE_FIXME: check if geometry gets properly committed
     rtcSetGeometryInstancedScene(geom_id, instance_bvh->scene);
     rtcSetGeometryTimeStepCount(geom_id, num_motion_steps);
 
-    if (ob->use_motion) {
-        /* Drop animated scales. Embree knows how to apply motion blur to those, but Cycles doesn't.
-         * This is necessary to keep it consistent with Cycles' intersection refinement.
-         * Eventually, Cycles should either also know how to to scaling or rely on Embree to get
-         * transformation matrices for time steps. */
-        MotionTransform decom;
-        Transform decom_single, comp;
-        transform_motion_decompose(&decom, &ob->motion, &ob->tfm);
-        decom_single.x = decom.pre.x;
-        decom_single.y = decom.pre.y;
-        decom_single.z = decom.mid.z;
-        decom_single.w = decom.mid.w;
-        transform_compose(&comp, &decom_single);
-
-        rtcSetGeometryTransform(geom_id, 0, RTC_FORMAT_FLOAT3X4_ROW_MAJOR, (const float*) &comp);
-        rtcSetGeometryTransform(geom_id, 1, RTC_FORMAT_FLOAT3X4_ROW_MAJOR, (const float*) &ob->tfm);
-
-        decom_single.x = decom.post.x;
-        decom_single.y = decom.post.y;
-        transform_compose(&comp, &decom_single);
-        rtcSetGeometryTransform(geom_id, 2, RTC_FORMAT_FLOAT3X4_ROW_MAJOR, (const float*) &comp);
+	if(ob->use_motion()) {
+		for(size_t step = 0; step < num_motion_steps; ++step)
+                    rtcSetGeometryTransform(geom_id, step, RTC_FORMAT_FLOAT3X4_ROW_MAJOR, (const float*)&ob->motion[step]);
     } else {
-        rtcSetGeometryTransform(geom_id, 0, RTC_FORMAT_FLOAT3X4_ROW_MAJOR, (const float*) &ob->tfm);
+	rtcSetGeometryTransform(geom_id, 0, RTC_FORMAT_FLOAT3X4_ROW_MAJOR, (const float*) &ob->tfm);
     }
 
-
-
     pack.prim_index.push_back_slow(-1);
     pack.prim_object.push_back_slow(i);
     pack.prim_type.push_back_slow(PRIMITIVE_NONE);
     pack.prim_tri_index.push_back_slow(-1);
 
-
     rtcSetGeometryUserData(geom_id, (void*) instance_bvh->scene);
     rtcSetGeometryMask(geom_id, ob->visibility);
 
     rtcCommitGeometry(geom_id);
     rtcAttachGeometryByID(scene, geom_id, i * 2);
     rtcReleaseGeometry(geom_id);
-    //return geom_id;
 }
 
-void BVHEmbree::add_triangles(Object *ob, int i) {
+void BVHEmbree::add_triangles(Object *ob, int i)
+{
     size_t prim_offset = pack.prim_index.size();
     Mesh *mesh = ob->mesh;
     const Attribute *attr_mP = NULL;
     size_t num_motion_steps = 1;
-    if (mesh->has_motion_blur()) {
-        attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
-        if (attr_mP) {
-            num_motion_steps = mesh->motion_steps;
-            if (num_motion_steps > RTC_MAX_TIME_STEP_COUNT) {
-                assert(0);
-                num_motion_steps = RTC_MAX_TIME_STEP_COUNT;
-            }
-        }
+    if(mesh->has_motion_blur()) {
+	attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+	if(attr_mP) {
+	    num_motion_steps = mesh->motion_steps;
+	    if(num_motion_steps > RTC_MAX_TIME_STEP_COUNT) {
+		assert(0);
+		num_motion_steps = RTC_MAX_TIME_STEP_COUNT;
+	    }
+	}
     }
 
     const size_t num_triangles = mesh->num_triangles();
-    //    const size_t num_verts = mesh->verts.size();
-    // unsigned int geom_id = i * 2;
+
     RTCGeometry geom_id = rtcNewGeometry(rtc_shared_device, RTC_GEOMETRY_TYPE_TRIANGLE); // EMBREE_FIXME: check if geometry gets properly committed
     rtcSetGeometryBuildQuality(geom_id, params.bvh_type == SceneParams::BVH_DYNAMIC ? RTC_BUILD_QUALITY_REFIT : RTC_BUILD_QUALITY_MEDIUM);
     rtcSetGeometryTimeStepCount(geom_id, num_motion_steps);
 
     unsigned *rtc_indices = (unsigned*) rtcSetNewGeometryBuffer(geom_id, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT3, sizeof (int) * 3, num_triangles);
     for (size_t j = 0; j < num_triangles; j++) {
-        Mesh::Triangle t = mesh->get_triangle(j);
-        rtc_indices[j * 3] = t.v[0];
-        rtc_indices[j * 3 + 1] = t.v[1];
-        rtc_indices[j * 3 + 2] = t.v[2];
+	Mesh::Triangle t = mesh->get_triangle(j);
+	rtc_indices[j * 3] = t.v[0];
+	rtc_indices[j * 3 + 1] = t.v[1];
+	rtc_indices[j * 3 + 2] = t.v[2];
     }
 
     update_tri_vertex_buffer(geom_id, mesh);
@@ -519,10 +476,10 @@ void BVHEmbree::add_triangles(Object *ob, int i) {
     pack.prim_index.reserve(pack.prim_index.size() + num_triangles);
     pack.prim_tri_index.reserve(pack.prim_index.size() + num_triangles);
     for (size_t j = 0; j < num_triangles; j++) {
-        pack.prim_object.push_back_reserved(i);
-        pack.prim_type.push_back_reserved(num_motion_steps > 1 ? PRIMITIVE_MOTION_TRIANGLE : PRIMITIVE_TRIANGLE);
-        pack.prim_index.push_back_reserved(j);
-        pack.prim_tri_index.push_back_reserved(j);
+	pack.prim_object.push_back_reserved(i);
+	pack.prim_type.push_back_reserved(num_motion_steps > 1 ? PRIMITIVE_MOTION_TRIANGLE : PRIMITIVE_TRIANGLE);
+	pack.prim_index.push_back_reserved(j);
+	pack.prim_tri_index.push_back_reserved(j);
     }
 
     rtcSetGeometryUserData(geom_id, (void*) prim_offset);
@@ -534,60 +491,60 @@ void BVHEmbree::add_triangles(Object *ob, int i) {
     rtcReleaseGeometry(geom_id);
 }
 
-void BVHEmbree::update_tri_vertex_buffer(RTCGeometry geom_id, const Mesh* mesh) {
+void BVHEmbree::update_tri_vertex_buffer(RTCGeometry geom_id, const Mesh* mesh) 
+{
     const Attribute *attr_mP = NULL;
     size_t num_motion_steps = 1;
     int t_mid = 0;
-    if (mesh->has_motion_blur()) {
-        attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
-        if (attr_mP) {
-            num_motion_steps = mesh->motion_steps;
-            t_mid = (num_motion_steps - 1) / 2;
-            if (num_motion_steps > RTC_MAX_TIME_STEP_COUNT) {
-                assert(0);
-                num_motion_steps = RTC_MAX_TIME_STEP_COUNT;
-            }
-        }
+    if(mesh->has_motion_blur()) {
+	attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+	if(attr_mP) {
+	    num_motion_steps = mesh->motion_steps;
+	    t_mid = (num_motion_steps - 1) / 2;
+	    if(num_motion_steps > RTC_MAX_TIME_STEP_COUNT) {
+		assert(0);
+		num_motion_steps = RTC_MAX_TIME_STEP_COUNT;
+	    }
+	}
     }
     const size_t num_verts = mesh->verts.size();
 
 
     for (int t = 0; t < num_motion_steps; t++) {
-        //RTCBufferType buffer_type = RTC_BUFFER(RTC_BUFFER_TYPE_VERTEX, t);
-        const float3 *verts;
-        if (t == t_mid) {
-            verts = &mesh->verts[0];
-        } else {
-            int t_ = (t > t_mid) ? (t - 1) : t;
-            verts = &attr_mP->data_float3()[t_ * num_verts];
-        }
-
-        //void *raw_buffer = rtcGetGeometryBufferData(geom_id, RTC_BUFFER_TYPE_VERTEX, t) /* EMBREE_FIXME: check if this should be rtcSetNewGeometryBuffer */;
-        float* raw_buffer = (float*) rtcSetNewGeometryBuffer(geom_id, RTC_BUFFER_TYPE_VERTEX, 0, RTC_FORMAT_FLOAT3, sizeof (float) * 4, num_verts);
-        assert(raw_buffer);
-
-        if (raw_buffer) {
-            float *rtc_verts = (float*) raw_buffer;
-            for (size_t j = 0; j < num_verts; j++) {
-                rtc_verts[0] = verts[j].x;
-                rtc_verts[1] = verts[j].y;
-                rtc_verts[2] = verts[j].z;
-                rtc_verts[3] = 0.0f;
-                rtc_verts += 4;
-            }
-
-        }
+	const float3 *verts;
+	if(t == t_mid) {
+	    verts = &mesh->verts[0];
+	} else {
+	    int t_ = (t > t_mid) ? (t - 1) : t;
+	    verts = &attr_mP->data_float3()[t_ * num_verts];
+	}
+
+	float* raw_buffer = (float*) rtcSetNewGeometryBuffer(geom_id, RTC_BUFFER_TYPE_VERTEX, 0, RTC_FORMAT_FLOAT3, sizeof (float) * 4, num_verts);
+	assert(raw_buffer);
+
+	if(raw_buffer) {
+	    float *rtc_verts = (float*) raw_buffer;
+	    for (size_t j = 0; j < num_verts; j++) {
+		rtc_verts[0] = verts[j].x;
+		rtc_verts[1] = verts[j].y;
+		rtc_verts[2] = verts[j].z;
+		rtc_verts[3] = 0.0f;
+		rtc_verts += 4;
+	    }
+
+	}
     }
 }
 
-void BVHEmbree::update_curve_vertex_buffer(RTCGeometry geom_id, const Mesh* mesh) {
+void BVHEmbree::update_curve_vertex_buffer(RTCGeometry geom_id, const Mesh* mesh) 
+{
     const Attribute *attr_mP = NULL;
     size_t num_motion_steps = 1;
-    if (mesh->has_motion_blur()) {
-        attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
-        if (attr_mP) {
-            num_motion_steps = mesh->motion_steps;
-        }
+    if(mesh->has_motion_blur()) {
+	attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+	if(attr_mP) {
+	    num_motion_steps = mesh->motion_steps;
+	}
     }
 
     const size_t num_keys = mesh->curve_keys.size();
@@ -595,87 +552,89 @@ void BVHEmbree::update_curve_vertex_buffer(RTCGeometry geom_id, const Mesh* mesh
     /* Copy the CV data to Embree */
     int t_mid = (num_motion_steps - 1) / 2;
     const float *curve_radius = &mesh->curve_radius[0];
-    for (int t = 0; t < num_motion_steps; t++) {
-        //RTCBufferType buffer_type = RTC_BUFFER(RTC_BUFFER_TYPE_VERTEX, t);
-        const float3 *verts;
-        if (t == t_mid || attr_mP == NULL) {
-            verts = &mesh->curve_keys[0];
-        } else {
-            int t_ = (t > t_mid) ? (t - 1) : t;
-            verts = &attr_mP->data_float3()[t_ * num_keys];
-        }
-
-        //        void *raw_buffer = rtcGetGeometryBufferData(geom_id, RTC_BUFFER_TYPE_VERTEX, t) /* EMBREE_FIXME: check if this should be rtcSetNewGeometryBuffer */;
-        float* raw_buffer = (float*) rtcSetNewGeometryBuffer(geom_id, RTC_BUFFER_TYPE_VERTEX, t, RTC_FORMAT_FLOAT4, sizeof (float) * 4, num_keys);
-        assert(raw_buffer);
-        if (raw_buffer) {
-            float4 *rtc_verts = (float4*) raw_buffer;
-            if (use_curves) {
-                const size_t num_curves = mesh->num_curves();
-                for (size_t j = 0; j < num_curves; j++) {
-                    Mesh::Curve c = mesh->get_curve(j);
-                    if (c.num_segments() > 0) {
-                        const int& fk = c.first_key;
-                        /* Create Embree's cubic splines that equal the cardinal splines that cycles uses */
-                        //static float fc = 1.0f / ((0.29f - 1.0f) * 6.0f);
-                        const float fc = -0.2347417840375f;
-                        rtc_verts[0] = float3_to_float4(verts[fk]);
-                        rtc_verts[0].w = curve_radius[fk];
-                        rtc_verts[1] = float3_to_float4(-fc * (verts[fk + 1] - verts[fk]) + verts[fk]);
-                        rtc_verts[1].w = lerp(curve_radius[fk], curve_radius[fk + 1], 0.33f);
-                        size_t k = 1;
-                        for (; k < c.num_segments(); k++) {
-                            const float3 d = (verts[fk + k + 1] - verts[fk + k - 1]);
-                            rtc_verts[k * 3 - 1] = float3_to_float4(fc * d + verts[fk + k]);
-                            rtc_verts[k * 3 - 1].w = lerp(curve_radius[fk + k - 1], curve_radius[fk + k], 0.66f);
-                            rtc_verts[k * 3] = float3_to_float4(verts[fk + k]);
-                            rtc_verts[k * 3].w = curve_radius[fk + k];
-                            rtc_verts[k * 3 + 1] = float3_to_float4(-fc * d + verts[fk + k]);
-                            rtc_verts[k * 3 + 1].w = lerp(curve_radius[fk + k], curve_radius[fk + k + 1], 0.33f);
-                        }
-                        rtc_verts[k * 3 - 1] = float3_to_float4(fc * (verts[fk + k] - verts[fk + k - 1]) + verts[fk + k]);
-                        rtc_verts[k * 3 - 1].w = lerp(curve_radius[fk + k - 1], curve_radius[fk + k], 0.66f);
-                        rtc_verts[k * 3] = float3_to_float4(verts[fk + k]);
-                        rtc_verts[k * 3].w = curve_radius[fk + k];
-                        rtc_verts += c.num_segments()*3 + 1;
-                    } else {
-                        assert(0);
-                    }
-                }
-            } else {
-                for (size_t j = 0; j < num_keys; j++) {
-                    rtc_verts[j] = float3_to_float4(verts[j]);
-                    rtc_verts[j].w = curve_radius[j];
-                }
-            }
-
-        }
+    for (int t = 0; t < num_motion_steps; t++) {	//RTCBufferType buffer_type = RTC_BUFFER(RTC_BUFFER_TYPE_VERTEX, t);
+	const float3 *verts;
+	if(t == t_mid || attr_mP == NULL) {
+	    verts = &mesh->curve_keys[0];
+	} else {
+	    int t_ = (t > t_mid) ? (t - 1) : t;
+	    verts = &attr_mP->data_float3()[t_ * num_keys];
+	}
+
+	float* raw_buffer = (float*) rtcSetNewGeometryBuffer(geom_id, RTC_BUFFER_TYPE_VERTEX, t, RTC_FORMAT_FLOAT4, sizeof (float) * 4, num_keys);
+	assert(raw_buffer);
+	if(raw_buffer) {
+	    float4 *rtc_verts = (float4*) raw_buffer;
+	    if(use_curves) {
+		const size_t num_curves = mesh->num_curves();
+		for (size_t j = 0; j < num_curves; j++) {
+		    Mesh::Curve c = mesh->get_curve(j);
+		    if(c.num_segments() > 0) {
+			const int& fk = c.first_key;
+			/* Create Embree's cubic splines that equal the cardinal splines that cycles uses */
+			//static float fc = 1.0f / ((0.29f - 1.0f) * 6.0f);
+			const float fc = -0.2347417840375f;
+			rtc_verts[0] = float3_to_float4(verts[fk]);
+			rtc_verts[0].w = curve_radius[fk];
+			rtc_verts[1] = float3_to_float4(-fc * (verts[fk + 1] - verts[fk]) + verts[fk]);
+			rtc_verts[1].w = lerp(curve_radius[fk], curve_radius[fk + 1], 0.33f);
+			size_t k = 1;
+			for (; k < c.num_segments(); k++) {
+			    const float3 d = (verts[fk + k + 1] - verts[fk + k - 1]);
+			    rtc_verts[k * 3 - 1] = float3_to_float4(fc * d + verts[fk + k]);
+			    rtc_verts[k * 3 - 1].w = lerp(curve_radius[fk + k - 1], curve_radius[fk + k], 0.66f);
+			    rtc_verts[k * 3] = float3_to_float4(verts[fk + k]);
+			    rtc_verts[k * 3].w = curve_radius[fk + k];
+			    rtc_verts[k * 3 + 1] = float3_to_float4(-fc * d + verts[fk + k]);
+			    rtc_verts[k * 3 + 1].w = lerp(curve_radius[fk + k], curve_radius[fk + k + 1], 0.33f);
+			}
+			rtc_verts[k * 3 - 1] = float3_to_float4(fc * (verts[fk + k] - verts[fk + k - 1]) + verts[fk + k]);
+			rtc_verts[k * 3 - 1].w = lerp(curve_radius[fk + k - 1], curve_radius[fk + k], 0.66f);
+			rtc_verts[k * 3] = float3_to_float4(verts[fk + k]);
+			rtc_verts[k * 3].w = curve_radius[fk + k];
+			rtc_verts += c.num_segments()*3 + 1;
+		    } 
+                    else {
+			assert(0);
+		    }
+		}
+	    } 
+            else {
+		for (size_t j = 0; j < num_keys; j++) {
+		    rtc_verts[j] = float3_to_float4(verts[j]);
+		    rtc_verts[j].w = curve_radius[j];
+		}
+	    }
+
+	}
     }
 }
 
-void BVHEmbree::add_curves(Object* ob, int i) {
+void BVHEmbree::add_curves(Object* ob, int i) 
+{
     size_t prim_offset = pack.prim_index.size();
     Mesh *mesh = ob->mesh;
     const Attribute *attr_mP = NULL;
     size_t num_motion_steps = 1;
-    if (mesh->has_motion_blur()) {
-        attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
-        if (attr_mP) {
-            num_motion_steps = mesh->motion_steps;
-        }
+    if(mesh->has_motion_blur()) {
+	attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+	if(attr_mP) {
+	    num_motion_steps = mesh->motion_steps;
+	}
     }
 
     const size_t num_curves = mesh->num_curves();
     size_t num_keys = 0;
     size_t num_segments = 0;
     for (size_t j = 0; j < num_curves; j++) {
-        Mesh::Curve c = mesh->get_curve(j);
-        if (c.num_segments() > 0) {
-            num_segments += c.num_segments();
-            num_keys += use_curves ? (c.num_segments() * 3 + 1) : c.num_keys;
-        } else {
-            assert(0);
-        }
+	Mesh::Curve c = mesh->get_curve(j);
+	if(c.num_segments() > 0) {
+	    num_segments += c.num_segments();
+	    num_keys += use_curves ? (c.num_segments() * 3 + 1) : c.num_keys;
+	} 
+        else {
+	    assert(0);
+	}
     }
 
     /* Make room for Cycles specific data */
@@ -684,71 +643,63 @@ void BVHEmbree::add_curves(Object* ob, int i) {
     pack.prim_index.reserve(pack.prim_index.size() + num_segments);
     pack.prim_tri_index.reserve(pack.prim_index.size() + num_segments);
 
-    RTCGeometry geom_id; // = i * 2 + 1;
-    if (use_curves) {
-        // RTCGeometry geom_2;
-
-        /* curve segments */
-        if (use_ribbons) {
-            geom_id = rtcNewGeometry(rtc_shared_device, RTC_GEOMETRY_TYPE_FLAT_BEZIER_CURVE); // EMBREE_FIXME: check if geometry gets properly committed
-
-        } else {
-            geom_id = rtcNewGeometry(rtc_shared_device, RTC_GEOMETRY_TYPE_ROUND_BEZIER_CURVE); // EMBREE_FIXME: check if geometry gets properly committed
-
-        }
-        rtcSetGeometryTessellationRate(geom_id, curve_subdivisions);
-
-        /* Split the Cycles curves into Embree hair segments, each with 4 CVs */
-        // void* raw_buffer = rtcGetGeometryBufferData(geom_id, RTC_BUFFER_TYPE_INDEX, 0) /* EMBREE_FIXME: check if this should be rtcSetNewGeometryBuffer */;
-        //  unsigned *rtc_indices = (unsigned*) raw_buffer;
-        unsigned *rtc_indices = (unsigned*) rtcSetNewGeometryBuffer(geom_id, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT, sizeof (int), num_segments);
-        size_t rtc_index = 0;
-        size_t curve_start = 0;
-        for (size_t j = 0; j < num_curves; j++) {
-            Mesh::Curve c = mesh->get_curve(j);
-            for (size_t k = 0; k < c.num_segments(); k++) {
-                rtc_indices[rtc_index] = curve_start;
-                curve_start += 3;
-                /* Cycles specific data */
-                pack.prim_object.push_back_reserved(i);
-                pack.prim_type.push_back_reserved(PRIMITIVE_PACK_SEGMENT(num_motion_steps > 1 ? PRIMITIVE_MOTION_CURVE : PRIMITIVE_CURVE, k));
-                pack.prim_index.push_back_reserved(j);
-                pack.prim_tri_index.push_back_reserved(rtc_index);
-
-                rtc_index++;
-            }
-            curve_start += 1;
-        }
-
-
-
-    } else {
-        geom_id = rtcNewGeometry(rtc_shared_device, RTC_GEOMETRY_TYPE_FLAT_LINEAR_CURVE); // EMBREE_FIXME: check if geometry gets properly committed
-
-        /* Split the Cycles curves into Embree line segments, each with 2 CVs */
-        //void* raw_buffer = rtcGetGeometryBufferData(geom_id, RTC_BUFFER_TYPE_INDEX, 0) /* EMBREE_FIXME: check if this should be rtcSetNewGeometryBuffer */;
-        //unsigned *rtc_indices = (unsigned*) raw_buffer;
-        unsigned *rtc_indices = (unsigned*) rtcSetNewGeometryBuffer(geom_id, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT, sizeof (int), num_segments);
-        size_t rtc_index = 0;
-        for (size_t j = 0; j < num_curves; j++) {
-            Mesh::Curve c = mesh->get_curve(j);
-            for (size_t k = 0; k < c.num_segments(); k++) {
-                rtc_indices[rtc_index] = c.first_key + k;
-                /* Cycles specific data */
-                pack.prim_object.push_back_reserved(i);
-                pack.prim_type.push_back_reserved(PRIMITIVE_PACK_SEGMENT(num_motion_steps > 1 ? PRIMITIVE_MOTION_CURVE : PRIMITIVE_CURVE, k));
-                pack.prim_index.push_back_reserved(j);
-                pack.prim_tri_index.push_back_reserved(rtc_index);
-
-                rtc_index++;
-            }
-
-        }
+    RTCGeometry geom_id;
+    if(use_curves) {
+	/* curve segments */
+	if(use_ribbons) {
+	    geom_id = rtcNewGeometry(rtc_shared_device, RTC_GEOMETRY_TYPE_FLAT_BEZIER_CURVE);
+	} 
+        else {
+	    geom_id = rtcNewGeometry(rtc_shared_device, RTC_GEOMETRY_TYPE_ROUND_BEZIER_CURVE);
+	}
+	rtcSetGeometryTessellationRate(geom_id, curve_subdivisions);
+
+	/* Split the Cycles curves into Embree hair segments, each with 4 CVs */
+	unsigned *rtc_indices = (unsigned*) rtcSetNewGeometryBuffer(geom_id, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT, sizeof (int), num_segments);
+	size_t rtc_index = 0;
+	size_t curve_start = 0;
+	for (size_t j = 0; j < num_curves; j++) {
+	    Mesh::Curve c = mesh->get_curve(j);
+	    for (size_t k = 0; k < c.num_segments(); k++) {
+		rtc_indices[rtc_index] = curve_start;
+		curve_start += 3;
+		/* Cycles specific data */
+		pack.prim_object.push_back_reserved(i);
+		pack.prim_type.push_back_reserved(PRIMITIVE_PACK_SEGMENT(num_motion_steps > 1 ? PRIMITIVE_MOTION_CURVE : PRIMITIVE_CURVE, k));
+		pack.prim_index.push_back_reserved(j);
+		pack.prim_tri_index.push_back_reserved(rtc_index);
+
+		rtc_index++;
+	    }
+	    curve_start += 1;
+	}
+
+
+
+    } 
+    else {
+	geom_id = rtcNewGeometry(rtc_shared_device, RTC_GEOMETRY_TYPE_FLAT_LINEAR_CURVE); // EMBREE_FIXME: check if geometry gets properly committed
+
+	/* Split the Cycles curves into Embree line segments, each with 2 CVs */
+	unsigned *rtc_indices = (unsigned*) rtcSetNewGeometryBuffer(geom_id, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT, sizeof (int), num_segments);
+	size_t rtc_index = 0;
+	for (size_t j = 0; j < num_curves; j++) {
+	    Mesh::Curve c = mesh->get_curve(j);
+	    for (size_t k = 0; k < c.num_segments(); k++) {
+		rtc_indices[rtc_index] = c.first_key + k;
+		/* Cycles specific data */
+		pack.prim_object.push_back_reserved(i);
+		pack.prim_type.push_back_reserved(PRIMITIVE_PACK_SEGMENT(num_motion_steps > 1 ? PRIMITIVE_MOTION_CURVE : PRIMITIVE_CURVE, k));
+		pack.prim_index.push_back_reserved(j);
+		pack.prim_tri_index.push_back_reserved(rtc_index);
+
+		rtc_index++;
+	    }
+	}
     }
 
     update_curve_vertex_buffer(geom_id, mesh);
-
-
+    
     rtcSetGeometryBuildQuality(geom_id, params.bvh_type == SceneParams::BVH_DYNAMIC ? RTC_BUILD_QUALITY_REFIT : RTC_BUILD_QUALITY_MEDIUM);
     rtcSetGeometryTimeStepCount(geom_id, num_motion_steps);
 
@@ -756,26 +707,24 @@ void BVHEmbree::add_curves(Object* ob, int i) {
     rtcSetGeometryOccludedFilterFunction(geom_id, rtc_filter_func);
     rtcSetGeometryMask(geom_id, ob->visibility);
 
-
     rtcCommitGeometry(geom_id);
     rtcAttachGeometryByID(scene, geom_id, i * 2 + 1);
     rtcReleaseGeometry(geom_id);
-
-    //return geom_id;
 }
 
-void BVHEmbree::pack_nodes(const BVHNode *) {
-    if (!params.top_level) {
-        return;
+void BVHEmbree::pack_nodes(const BVHNode *) 
+{
+    if(!params.top_level) {
+	return;
     }
 
     for (size_t i = 0; i < pack.prim_index.size(); i++) {
-        if (pack.prim_index[i] != -1) {
-            if (pack.prim_type[i] & PRIMITIVE_ALL_CURVE)
-                pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->curve_offset;
-            else
-                pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->tri_offset;
-        }
+	if(pack.prim_index[i] != -1) {
+	    if(pack.prim_type[i] & PRIMITIVE_ALL_CURVE)
+		pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->curve_offset;
+	    else
+		pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->tri_offset;
+	}
     }
 
     size_t prim_offset = pack.prim_index.size();
@@ -791,16 +740,16 @@ void BVHEmbree::pack_nodes(const BVHNode *) {
     map<Mesh*, int> mesh_map;
 
     foreach(Object *ob, objects) {
-        Mesh *mesh = ob->mesh;
-        BVH *bvh = mesh->bvh;
+	Mesh *mesh = ob->mesh;
+	BVH *bvh = mesh->bvh;
 
-        if (mesh->need_build_bvh()) {
-            if (mesh_map.find(mesh) == mesh_map.end()) {
-                prim_index_size += bvh->pack.prim_index.size();
-                prim_tri_verts_size += bvh->pack.prim_tri_verts.size();
-                mesh_map[mesh] = 1;
-            }
-        }
+	if(mesh->need_build_bvh()) {
+	    if(mesh_map.find(mesh) == mesh_map.end()) {
+		prim_index_size += bvh->pack.prim_index.size();
+		prim_tri_verts_size += bvh->pack.prim_tri_verts.size();
+		mesh_map[mesh] = 1;
+	    }
+	}
     }
 
     mesh_map.clear();
@@ -821,100 +770,99 @@ void BVHEmbree::pack_nodes(const BVHNode *) {
     uint *pack_prim_tri_index = (pack.prim_tri_index.size()) ? &pack.prim_tri_index[0] : NULL;
 
     /* merge */
-    // unsigned geom_id = 0;
-
     foreach(Object *ob, objects) {
-        //    geom_id += 2;
-        Mesh *mesh = ob->mesh;
-
-        /* We assume that if mesh doesn't need own BVH it was already included
-         * into a top-level BVH and no packing here is needed.
-         */
-        if (!mesh->need_build_bvh()) {
-            pack.object_node[object_offset++] = prim_offset;
-            continue;
-        }
-
-        /* if mesh already added once, don't add it again, but used set
-         * node offset for this object */
-        map<Mesh*, int>::iterator it = mesh_map.find(mesh);
-
-        if (mesh_map.find(mesh) != mesh_map.end()) {
-            int noffset = it->second;
-            pack.object_node[object_offset++] = noffset;
-            continue;
-        }
-
-        BVHEmbree *bvh = (BVHEmbree*) mesh->bvh;
-
-        mem_monitor(bvh->mem_used);
-
-        int mesh_tri_offset = mesh->tri_offset;
-        int mesh_curve_offset = mesh->curve_offset;
-
-        /* fill in node indexes for instances */
-        if (bvh->pack.root_index == -1)
-            pack.object_node[object_offset++] = prim_offset; //todo (Stefan)
-        else
-            pack.object_node[object_offset++] = prim_offset; // todo (Stefan)
-
-        mesh_map[mesh] = pack.object_node[object_offset - 1];
-
-        /* merge primitive, object and triangle indexes */
-        if (bvh->pack.prim_index.size()) {
-            size_t bvh_prim_index_size = bvh->pack.prim_index.size();
-            int *bvh_prim_index = &bvh->pack.prim_index[0];
-            int *bvh_prim_type = &bvh->pack.prim_type[0];
-            uint *bvh_prim_visibility = &bvh->pack.prim_visibility[0];
-            uint *bvh_prim_tri_index = &bvh->pack.prim_tri_index[0];
-
-            for (size_t i = 0; i < bvh_prim_index_size; i++) {
-                if (bvh->pack.prim_type[i] & PRIMITIVE_ALL_CURVE) {
-                    pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_curve_offset;
-                    pack_prim_tri_index[pack_prim_index_offset] = -1;
-                } else {
-                    pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_tri_offset;
-                    pack_prim_tri_index[pack_prim_index_offset] =
-                            bvh_prim_tri_index[i] + pack_prim_tri_verts_offset;
-                }
-
-                pack_prim_type[pack_prim_index_offset] = bvh_prim_type[i];
-                pack_prim_visibility[pack_prim_index_offset] = bvh_prim_visibility[i];
-                pack_prim_object[pack_prim_index_offset] = 0; // unused for instances
-
-                pack_prim_index_offset++;
-            }
-        }
-
-        /* Merge triangle vertices data. */
-        if (bvh->pack.prim_tri_verts.size()) {
-            const size_t prim_tri_size = bvh->pack.prim_tri_verts.size();
-            memcpy(pack_prim_tri_verts + pack_prim_tri_verts_offset,
-                    &bvh->pack.prim_tri_verts[0],
-                    prim_tri_size * sizeof (float4));
-            pack_prim_tri_verts_offset += prim_tri_size;
-        }
-
-        prim_offset += bvh->pack.prim_index.size();
+	Mesh *mesh = ob->mesh;
+
+	/* We assume that if mesh doesn't need own BVH it was already included
+	 * into a top-level BVH and no packing here is needed.
+	 */
+	if(!mesh->need_build_bvh()) {
+	    pack.object_node[object_offset++] = prim_offset;
+	    continue;
+	}
+
+	/* if mesh already added once, don't add it again, but used set
+	 * node offset for this object */
+	map<Mesh*, int>::iterator it = mesh_map.find(mesh);
+
+	if(mesh_map.find(mesh) != mesh_map.end()) {
+	    int noffset = it->second;
+	    pack.object_node[object_offset++] = noffset;
+	    continue;
+	}
+
+	BVHEmbree *bvh = (BVHEmbree*) mesh->bvh;
+
+	mem_monitor(bvh->mem_used);
+
+	int mesh_tri_offset = mesh->tri_offset;
+	int mesh_curve_offset = mesh->curve_offset;
+
+	/* fill in node indexes for instances */
+	if(bvh->pack.root_index == -1)
+	    pack.object_node[object_offset++] = prim_offset; //todo (Stefan)
+	else
+	    pack.object_node[object_offset++] = prim_offset; // todo (Stefan)
+
+	mesh_map[mesh] = pack.object_node[object_offset - 1];
+
+	/* merge primitive, object and triangle indexes */
+	if(bvh->pack.prim_index.size()) {
+	    size_t bvh_prim_index_size = bvh->pack.prim_index.size();
+	    int *bvh_prim_index = &bvh->pack.prim_index[0];
+	    int *bvh_prim_type = &bvh->pack.prim_type[0];
+	    uint *bvh_prim_visibility = &bvh->pack.prim_visibility[0];
+	    uint *bvh_prim_tri_index = &bvh->pack.prim_tri_index[0];
+
+	    for (size_t i = 0; i < bvh_prim_index_size; i++) {
+		if(bvh->pack.prim_type[i] & PRIMITIVE_ALL_CURVE) {
+		    pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_curve_offset;
+		    pack_prim_tri_index[pack_prim_index_offset] = -1;
+		} 
+                else {
+		    pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_tri_offset;
+		    pack_prim_tri_index[pack_prim_index_offset] =
+			    bvh_prim_tri_index[i] + pack_prim_tri_verts_offset;
+		}
+
+		pack_prim_type[pack_prim_index_offset] = bvh_prim_type[i];
+		pack_prim_visibility[pack_prim_index_offset] = bvh_prim_visibility[i];
+		pack_prim_object[pack_prim_index_offset] = 0; // unused for instances
+
+		pack_prim_index_offset++;
+	    }
+	}
+
+	/* Merge triangle vertices data. */
+	if(bvh->pack.prim_tri_verts.size()) {
+	    const size_t prim_tri_size = bvh->pack.prim_tri_verts.size();
+	    memcpy(pack_prim_tri_verts + pack_prim_tri_verts_offset,
+		    &bvh->pack.prim_tri_verts[0],
+		    prim_tri_size * sizeof (float4));
+	    pack_prim_tri_verts_offset += prim_tri_size;
+	}
+
+	prim_offset += bvh->pack.prim_index.size();
     }
 }
 
-void BVHEmbree::refit_nodes() {
+void BVHEmbree::refit_nodes() 
+{
     unsigned geom_id = 0;
 
     foreach(Object *ob, objects) {
-        if (!params.top_level || (ob->is_traceable() && !ob->mesh->is_instanced())) {
-            if (params.primitive_mask & PRIMITIVE_ALL_TRIANGLE && ob->mesh->num_triangles() > 0) {
-                update_tri_vertex_buffer(rtcGetGeometry(scene, geom_id), ob->mesh);
-                rtcCommitGeometry(rtcGetGeometry(scene, geom_id));
-            }
-
-            if (params.primitive_mask & PRIMITIVE_ALL_CURVE && ob->mesh->num_curves() > 0) {
-                update_curve_vertex_buffer(rtcGetGeometry(scene, geom_id + 1), ob->mesh);
-                rtcCommitGeometry(rtcGetGeometry(scene, geom_id + 1));
-            }
-        }
-        geom_id += 2;
+	if(!params.top_level || (ob->is_traceable() && !ob->mesh->is_instanced())) {
+	    if(params.primitive_mask & PRIMITIVE_ALL_TRIANGLE && ob->mesh->num_triangles() > 0) {
+		update_tri_vertex_buffer(rtcGetGeometry(scene, geom_id), ob->mesh);
+		rtcCommitGeometry(rtcGetGeometry(scene, geom_id));
+	    }
+
+	    if(params.primitive_mask & PRIMITIVE_ALL_CURVE && ob->mesh->num_curves() > 0) {
+		update_curve_vertex_buffer(rtcGetGeometry(scene, geom_id + 1), ob->mesh);
+		rtcCommitGeometry(rtcGetGeometry(scene, geom_id + 1));
+	    }
+	}
+	geom_id += 2;
     }
     rtcCommitScene(scene);
 }
diff --git a/intern/cycles/bvh/bvh_embree.h b/intern/cycles/bvh/bvh_embree.h
index b5ddc5407aa26ea7c6caa4607d8e6e4194fe2337..249eed8e021898cdb5e66e8890e97b1ccca50741 100644
--- a/intern/cycles/bvh/bvh_embree.h
+++ b/intern/cycles/bvh/bvh_embree.h
@@ -33,9 +33,10 @@ CCL_NAMESPACE_BEGIN
 
 class Mesh;
 
-class BVHEmbree : public BVH {
+class BVHEmbree : public BVH
+{
 public:
-    void build(Progress& progress);
+	void build(Progress& progress, Stats *stats);
     virtual ~BVHEmbree();
     RTCScene scene;
     static void destroy(RTCScene);
@@ -55,9 +56,7 @@ protected:
 
     ssize_t mem_used;
 
-    void add_delayed_delete_scene(RTCScene scene) {
-        delayed_delete_scenes.push_back(scene);
-    }
+	void add_delayed_delete_scene(RTCScene scene) { delayed_delete_scenes.push_back(scene); }
     BVHEmbree *top_level;
 private:
     void delete_rtcScene();
@@ -68,7 +67,7 @@ private:
     static int rtc_shared_users;
     static thread_mutex rtc_shared_mutex;
 
-    //	Stats *stats;
+	Stats *stats;
     vector<RTCScene> delayed_delete_scenes;
     int curve_subdivisions;
     bool use_curves, use_ribbons, dynamic_scene;
diff --git a/intern/cycles/bvh/bvh_params.h b/intern/cycles/bvh/bvh_params.h
index f18c5e51fab5935a2010f7d5f4c71186f6b3fe8b..f80fa53f2ec2d4b167fb7d7ed4c5d90f6354515d 100644
--- a/intern/cycles/bvh/bvh_params.h
+++ b/intern/cycles/bvh/bvh_params.h
@@ -90,8 +90,10 @@ public:
 	/* Same as above, but for triangle primitives. */
 	int num_motion_triangle_steps;
 
+	/* Same as in SceneParams. */
+	int bvh_type;
+
 	/* These are needed for Embree. */
-        int bvh_type;
 	int curve_flags;
 	int curve_subdivisions;
 
@@ -129,7 +131,8 @@ public:
 		num_motion_curve_steps = 0;
 		num_motion_triangle_steps = 0;
 
-                bvh_type = 0;
+		bvh_type = 0;
+
 		curve_flags = 0;
 		curve_subdivisions = 4;
 	}
diff --git a/intern/cycles/device/device_cpu.cpp b/intern/cycles/device/device_cpu.cpp
index 9beb330355d24aadd662b91c3bfd2d7b512ab2d5..fa1ee032efed3c473e9f72099ffb7163263c0a5d 100644
--- a/intern/cycles/device/device_cpu.cpp
+++ b/intern/cycles/device/device_cpu.cpp
@@ -692,6 +692,9 @@ public:
 		int start_sample = tile.start_sample;
 		int end_sample = tile.start_sample + tile.num_samples;
 
+		_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
+		_MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
+		
 		for(int sample = start_sample; sample < end_sample; sample++) {
 			if(task.get_cancel() || task_pool.canceled()) {
 				if(task.need_finish_queue == false)
@@ -1050,11 +1053,9 @@ void device_cpu_info(vector<DeviceInfo>& devices)
 	if (system_cpu_support_sse2()) {
 		info.bvh_layout_mask |= BVH_LAYOUT_BVH4;
 	}
-        
 #ifdef WITH_EMBREE
 	info.bvh_layout_mask |= BVH_LAYOUT_EMBREE;
-#endif
-        
+#endif /* WITH_EMBREE */
 	info.has_volume_decoupled = true;
 	info.has_osl = true;
 	info.has_half_images = true;
diff --git a/intern/cycles/graph/node_type.cpp b/intern/cycles/graph/node_type.cpp
index a3a8fa5f382dcbf807c5ac120e2f2c1668f94136..37aae211e93e692b2c36ec708b2c5333cc474904 100644
--- a/intern/cycles/graph/node_type.cpp
+++ b/intern/cycles/graph/node_type.cpp
@@ -77,7 +77,7 @@ size_t SocketType::max_size()
 
 void *SocketType::zero_default_value()
 {
-	static Transform zero_transform = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
+	static Transform zero_transform = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
 	return &zero_transform;
 }
 
diff --git a/intern/cycles/graph/node_xml.cpp b/intern/cycles/graph/node_xml.cpp
index d26b3b2c2c885dc66984bb94e5dd5ad0e7b332be..f4599e22d40f16887b20904d4d5c4adecc607d61 100644
--- a/intern/cycles/graph/node_xml.cpp
+++ b/intern/cycles/graph/node_xml.cpp
@@ -196,7 +196,7 @@ void xml_read_node(XMLReader& reader, Node *node, xml_node xml_node)
 			case SocketType::TRANSFORM:
 			{
 				array<Transform> value;
-				xml_read_float_array<16>(value, attr);
+				xml_read_float_array<12>(value, attr);
 				if(value.size() == 1) {
 					node->set(socket, value[0]);
 				}
@@ -205,7 +205,7 @@ void xml_read_node(XMLReader& reader, Node *node, xml_node xml_node)
 			case SocketType::TRANSFORM_ARRAY:
 			{
 				array<Transform> value;
-				xml_read_float_array<16>(value, attr);
+				xml_read_float_array<12>(value, attr);
 				node->set(socket, value);
 				break;
 			}
@@ -400,12 +400,10 @@ xml_node xml_write_node(Node *node, xml_node xml_root)
 			{
 				Transform tfm = node->get_transform(socket);
 				std::stringstream ss;
-				for(int i = 0; i < 4; i++) {
-					ss << string_printf("%g %g %g %g", (double)tfm[i][0], (double)tfm[i][1], (double)tfm[i][2], (double)tfm[i][3]);
-					if(i != 3) {
-						ss << " ";
-					}
+				for(int i = 0; i < 3; i++) {
+					ss << string_printf("%g %g %g %g ", (double)tfm[i][0], (double)tfm[i][1], (double)tfm[i][2], (double)tfm[i][3]);
 				}
+				ss << string_printf("%g %g %g %g", 0.0, 0.0, 0.0, 1.0);
 				attr = ss.str().c_str();
 				break;
 			}
@@ -416,11 +414,12 @@ xml_node xml_write_node(Node *node, xml_node xml_root)
 				for(size_t j = 0; j < value.size(); j++) {
 					const Transform& tfm = value[j];
 
-					for(int i = 0; i < 4; i++) {
-						ss << string_printf("%g %g %g %g", (double)tfm[i][0], (double)tfm[i][1], (double)tfm[i][2], (double)tfm[i][3]);
-						if(j != value.size() - 1 || i != 3) {
-							ss << " ";
-						}
+					for(int i = 0; i < 3; i++) {
+						ss << string_printf("%g %g %g %g ", (double)tfm[i][0], (double)tfm[i][1], (double)tfm[i][2], (double)tfm[i][3]);
+					}
+					ss << string_printf("%g %g %g %g", 0.0, 0.0, 0.0, 1.0);
+					if(j != value.size() - 1) {
+						ss << " ";
 					}
 				}
 				attr = ss.str().c_str();
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt
index 50ea03a1f8f48a78a7c2a6ab3ea00270a5f5cd06..9b7f4e00084e62c5e44f7eafa86801b89e6cf924 100644
--- a/intern/cycles/kernel/CMakeLists.txt
+++ b/intern/cycles/kernel/CMakeLists.txt
@@ -254,6 +254,7 @@ set(SRC_UTIL_HEADERS
 	../util/util_math_int3.h
 	../util/util_math_int4.h
 	../util/util_math_matrix.h
+	../util/util_projection.h
 	../util/util_rect.h
 	../util/util_static_assert.h
 	../util/util_transform.h
diff --git a/intern/cycles/kernel/bvh/bvh.h b/intern/cycles/kernel/bvh/bvh.h
index baa9d3642c9eae5b814f2a6711598ad0b21f9c38..02494b4b32cf2ab78e6fda70e1395992cf5aa9f3 100644
--- a/intern/cycles/kernel/bvh/bvh.h
+++ b/intern/cycles/kernel/bvh/bvh.h
@@ -175,15 +175,12 @@ ccl_device_intersect bool scene_intersect(KernelGlobals *kg,
 		isect->t = ray.t;
 		CCLRay rtc_ray(ray, kg, visibility, CCLRay::RAY_REGULAR);
                 
-  IntersectContext context;
-  InitIntersectContext(&context); context.userRayExt=&rtc_ray;
+		IntersectContext context;
+		InitIntersectContext(&context);
+                context.userRayExt = &rtc_ray;
                 
                 rtcIntersect1(kernel_data.bvh.scene, &context.context, (RTCRayHit*) &rtc_ray);
-                        
-                rtc_ray.hit.Ng_x = -rtc_ray.hit.Ng_x; // EMBREE_FIXME: only correct for triangles,quads, and subdivision surfaces
-                rtc_ray.hit.Ng_y = -rtc_ray.hit.Ng_y;
-		rtc_ray.hit.Ng_z = -rtc_ray.hit.Ng_z;
-                        
+        
 		if(rtc_ray.hit.geomID != RTC_INVALID_GEOMETRY_ID && rtc_ray.hit.primID != RTC_INVALID_GEOMETRY_ID) {
 			rtc_ray.isect_to_ccl(isect);
 			return true;
@@ -244,10 +241,11 @@ ccl_device_intersect void scene_intersect_local(KernelGlobals *kg,
 		local_isect->num_hits = 0;
 		rtc_ray.sss_object_id = local_object;
 		
-  IntersectContext context;
-  InitIntersectContext(&context);  context.userRayExt=&rtc_ray;
+		IntersectContext context;
+		InitIntersectContext(&context);
+                context.userRayExt = &rtc_ray;
                 
-                rtcOccluded1(kernel_data.bvh.scene, &context.context, (RTCRay*) &rtc_ray); // EMBREE_FIXME: rtc_ray is occluded when rtc_ray.tfar < 0.0f
+                rtcOccluded1(kernel_data.bvh.scene, &context.context, (RTCRay*) &rtc_ray);
   
 		return;
 	}
@@ -286,10 +284,11 @@ ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals *kg,
 		rtc_ray.max_hits = max_hits;
 		rtc_ray.num_hits = 0;
             
-  IntersectContext context;
-  InitIntersectContext(&context);  context.userRayExt=&rtc_ray;
+		IntersectContext context;
+		InitIntersectContext(&context);
+                context.userRayExt = &rtc_ray;
                 
-                rtcOccluded1(kernel_data.bvh.scene, &context.context, (RTCRay*) &rtc_ray); //EMBREE_FIXME: rtc_ray is occluded when rtc_ray.tfar < 0.0f
+                rtcOccluded1(kernel_data.bvh.scene, &context.context, (RTCRay*) &rtc_ray);
   
 		if(rtc_ray.num_hits > max_hits) {
 			return true;
@@ -396,11 +395,11 @@ ccl_device_intersect uint scene_intersect_volume_all(KernelGlobals *kg,
 		rtc_ray.max_hits = max_hits;
 		rtc_ray.num_hits = 0;
     
-  IntersectContext context;
-  InitIntersectContext(&context);  context.userRayExt=&rtc_ray;
-  
-                rtcOccluded1(kernel_data.bvh.scene, &context.context, (RTCRay*) &rtc_ray);   // EMBREE_FIXME: rtc_ray is occluded when rtc_ray.tfar < 0.0f
+		IntersectContext context;
+		InitIntersectContext(&context);
+                context.userRayExt = &rtc_ray;
   
+                rtcOccluded1(kernel_data.bvh.scene, &context.context, (RTCRay*) &rtc_ray);
 		return rtc_ray.num_hits;
 	}
 #endif
diff --git a/intern/cycles/kernel/bvh/bvh_embree_traversal.h b/intern/cycles/kernel/bvh/bvh_embree_traversal.h
index 217bcad0a88533c8049b0c68b4c3e71d6680006a..70ed82c42991f56fb15925bed242d2f5dfcc1709 100644
--- a/intern/cycles/kernel/bvh/bvh_embree_traversal.h
+++ b/intern/cycles/kernel/bvh/bvh_embree_traversal.h
@@ -18,79 +18,80 @@
 #include "embree3/rtcore_scene.h"
 
 struct RTC_ALIGN(16) CCLRay : public RTCRayHit {
+        typedef enum {
+                RAY_REGULAR = 0,
+                RAY_SHADOW_ALL = 1,
+                RAY_SSS = 2,
+                RAY_VOLUME_ALL = 3,
 
-    typedef enum {
-        RAY_REGULAR = 0,
-        RAY_SHADOW_ALL = 1,
-        RAY_SSS = 2,
-        RAY_VOLUME_ALL = 3,
+        } RayType;
 
-    } RayType;
+        // cycles extensions:
+        ccl::KernelGlobals *kg;
+        RayType type;
 
-    // cycles extensions:
-    ccl::KernelGlobals *kg;
-    RayType type;
+        // for shadow rays
+        ccl::Intersection *isect_s;
+        int max_hits;
+        int num_hits;
 
-    // for shadow rays
-    ccl::Intersection *isect_s;
-    int max_hits;
-    int num_hits;
+        // for SSS Rays:
+        ccl::LocalIntersection *ss_isect;
+        int sss_object_id;
+        ccl::uint *lcg_state;
 
-    // for SSS Rays:
-    ccl::LocalIntersection *ss_isect;
-    int sss_object_id;
-    ccl::uint *lcg_state;
+        CCLRay(const ccl::Ray& ccl_ray, ccl::KernelGlobals *kg_, const ccl::uint visibility, RayType type_)
+        {
+                ray.org_x = ccl_ray.P.x;
+                ray.org_y = ccl_ray.P.y;
+                ray.org_z = ccl_ray.P.z;
+                ray.dir_x = ccl_ray.D.x;
+                ray.dir_y = ccl_ray.D.y;
+                ray.dir_z = ccl_ray.D.z;
+                ray.tnear = 0.0f;
+                ray.tfar = ccl_ray.t;
+                ray.time = ccl_ray.time;
+                ray.mask = visibility;
+                hit.geomID = hit.primID = hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
 
-    CCLRay(const ccl::Ray& ccl_ray, ccl::KernelGlobals *kg_, const ccl::uint visibility, RayType type_) {
-        ray.org_x = ccl_ray.P.x;
-        ray.org_y = ccl_ray.P.y;
-        ray.org_z = ccl_ray.P.z;
-        ray.dir_x = ccl_ray.D.x;
-        ray.dir_y = ccl_ray.D.y;
-        ray.dir_z = ccl_ray.D.z;
-        ray.tnear = 0.0f;
-        ray.tfar = ccl_ray.t;
-        ray.time = ccl_ray.time;
-        ray.mask = visibility;
-        hit.geomID = hit.primID = hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
-
-        kg = kg_;
-        type = type_;
-        max_hits = 1;
-        num_hits = 0;
-        isect_s = NULL;
-        ss_isect = NULL;
-        sss_object_id = -1;
-        lcg_state = NULL;
-    }
-
-    void isect_to_ccl(ccl::Intersection * isect) {
-        bool is_hair = hit.geomID & 1;
-        isect->u = is_hair ? hit.u : 1.0f - hit.v - hit.u;
-        isect->v = is_hair ? hit.v : hit.u;
-        isect->t = ray.tfar;
-        isect->Ng = ccl::make_float3(hit.Ng_x, hit.Ng_y, hit.Ng_z);
-        if (hit.instID[0] != RTC_INVALID_GEOMETRY_ID) {
-            RTCScene inst_scene = (RTCScene) rtcGetGeometryUserData(rtcGetGeometry(kernel_data.bvh.scene, hit.instID[0]));
-            isect->prim = hit.primID + (intptr_t) rtcGetGeometryUserData(rtcGetGeometry(inst_scene, hit.geomID)) + kernel_tex_fetch(__object_node, hit.instID[0] / 2);
-            isect->object = hit.instID[0] / 2;
-        } else {
-            isect->prim = hit.primID + (intptr_t) rtcGetGeometryUserData(rtcGetGeometry(kernel_data.bvh.scene, hit.geomID));
-            isect->object = OBJECT_NONE;
+                kg = kg_;
+                type = type_;
+                max_hits = 1;
+                num_hits = 0;
+                isect_s = NULL;
+                ss_isect = NULL;
+                sss_object_id = -1;
+                lcg_state = NULL;
         }
-        isect->type = kernel_tex_fetch(__prim_type, isect->prim);
-    }
+
+        void isect_to_ccl(ccl::Intersection * isect)
+        {
+                bool is_hair = hit.geomID & 1;
+                isect->u = is_hair ? hit.u : 1.0f - hit.v - hit.u;
+                isect->v = is_hair ? hit.v : hit.u;
+                isect->t = ray.tfar;
+                isect->Ng = ccl::make_float3(hit.Ng_x, hit.Ng_y, hit.Ng_z);
+                if (hit.instID[0] != RTC_INVALID_GEOMETRY_ID) {
+                        RTCScene inst_scene = (RTCScene) rtcGetGeometryUserData(rtcGetGeometry(kernel_data.bvh.scene, hit.instID[0]));
+                        isect->prim = hit.primID + (intptr_t) rtcGetGeometryUserData(rtcGetGeometry(inst_scene, hit.geomID)) + kernel_tex_fetch(__object_node, hit.instID[0] / 2);
+                        isect->object = hit.instID[0] / 2;
+                } else {
+                        isect->prim = hit.primID + (intptr_t) rtcGetGeometryUserData(rtcGetGeometry(kernel_data.bvh.scene, hit.geomID));
+                        isect->object = OBJECT_NONE;
+                }
+                isect->type = kernel_tex_fetch(__prim_type, isect->prim);
+                }
 };
 
-/*! intersection context passed to intersect/occluded calls */
+/* Intersection context passed to intersect/occluded calls */
 struct IntersectContext
 {
   RTCIntersectContext context;
-  void* userRayExt;               //!< can be used to pass extended ray data to callbacks
+  void* userRayExt;
 };
 
 __forceinline void InitIntersectContext(struct IntersectContext* context)
 {
   rtcInitIntersectContext(&context->context);
   context->userRayExt = NULL;
-};
\ No newline at end of file
+};
diff --git a/intern/cycles/kernel/bvh/bvh_nodes.h b/intern/cycles/kernel/bvh/bvh_nodes.h
index 6c33dad5426e96da948993a173260137d447b09f..060b3934a41c26ee1a730e13bed87951d5002203 100644
--- a/intern/cycles/kernel/bvh/bvh_nodes.h
+++ b/intern/cycles/kernel/bvh/bvh_nodes.h
@@ -25,7 +25,6 @@ ccl_device_forceinline Transform bvh_unaligned_node_fetch_space(KernelGlobals *k
 	space.x = kernel_tex_fetch(__bvh_nodes, child_addr+1);
 	space.y = kernel_tex_fetch(__bvh_nodes, child_addr+2);
 	space.z = kernel_tex_fetch(__bvh_nodes, child_addr+3);
-	space.w = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
 	return space;
 }
 
diff --git a/intern/cycles/kernel/bvh/bvh_shadow_all.h b/intern/cycles/kernel/bvh/bvh_shadow_all.h
index efd6798ca5180d27a6bca3c977ae8db763e93a9d..cfc567ff9ca47db729e6fbf979071acf4c84e5b4 100644
--- a/intern/cycles/kernel/bvh/bvh_shadow_all.h
+++ b/intern/cycles/kernel/bvh/bvh_shadow_all.h
@@ -276,7 +276,7 @@ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
 								shader = __float_as_int(str.z);
 							}
 #endif
-							int flag = kernel_tex_fetch(__shader_flag, (shader & SHADER_MASK)*SHADER_SIZE);
+							int flag = kernel_tex_fetch(__shaders, (shader & SHADER_MASK)).flags;
 
 							/* if no transparent shadows, all light is blocked */
 							if(!(flag & SD_HAS_TRANSPARENT_SHADOW)) {
diff --git a/intern/cycles/kernel/bvh/qbvh_shadow_all.h b/intern/cycles/kernel/bvh/qbvh_shadow_all.h
index 522213f30ca4151e3fa94af5c07c7b2a1342e296..46fd178aed6bd32ef6bafd138b8cce977d0e794c 100644
--- a/intern/cycles/kernel/bvh/qbvh_shadow_all.h
+++ b/intern/cycles/kernel/bvh/qbvh_shadow_all.h
@@ -358,7 +358,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
 								shader = __float_as_int(str.z);
 							}
 #endif
-							int flag = kernel_tex_fetch(__shader_flag, (shader & SHADER_MASK)*SHADER_SIZE);
+							int flag = kernel_tex_fetch(__shaders, (shader & SHADER_MASK)).flags;
 
 							/* if no transparent shadows, all light is blocked */
 							if(!(flag & SD_HAS_TRANSPARENT_SHADOW)) {
diff --git a/intern/cycles/kernel/geom/geom_attribute.h b/intern/cycles/kernel/geom/geom_attribute.h
index c72595eed10f8f0083add53990ece92884069147..42c053704d546c8ded41011ca8e0df866388f90c 100644
--- a/intern/cycles/kernel/geom/geom_attribute.h
+++ b/intern/cycles/kernel/geom/geom_attribute.h
@@ -53,9 +53,7 @@ ccl_device_inline AttributeDescriptor attribute_not_found()
 
 ccl_device_inline uint object_attribute_map_offset(KernelGlobals *kg, int object)
 {
-	int offset = object*OBJECT_SIZE + 15;
-	float4 f = kernel_tex_fetch(__objects, offset);
-	return __float_as_uint(f.y);
+	return kernel_tex_fetch(__objects, object).attribute_map_offset;
 }
 
 ccl_device_inline AttributeDescriptor find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id)
@@ -105,7 +103,6 @@ ccl_device Transform primitive_attribute_matrix(KernelGlobals *kg, const ShaderD
 	tfm.x = kernel_tex_fetch(__attributes_float3, desc.offset + 0);
 	tfm.y = kernel_tex_fetch(__attributes_float3, desc.offset + 1);
 	tfm.z = kernel_tex_fetch(__attributes_float3, desc.offset + 2);
-	tfm.w = kernel_tex_fetch(__attributes_float3, desc.offset + 3);
 
 	return tfm;
 }
diff --git a/intern/cycles/kernel/geom/geom_curve_intersect.h b/intern/cycles/kernel/geom/geom_curve_intersect.h
index d979d456959d8184f15a99535cc7c3d207476b4e..c03cd5ca9dd8ea782e25b2efe38a9754df19e394 100644
--- a/intern/cycles/kernel/geom/geom_curve_intersect.h
+++ b/intern/cycles/kernel/geom/geom_curve_intersect.h
@@ -170,8 +170,7 @@ ccl_device_forceinline bool cardinal_curve_intersect(
 		htfm = make_transform(
 			dir.z / d, 0, -dir.x /d, 0,
 			-dir.x * dir.y /d, d, -dir.y * dir.z /d, 0,
-			dir.x, dir.y, dir.z, 0,
-			0, 0, 0, 1);
+			dir.x, dir.y, dir.z, 0);
 
 		float4 v00 = kernel_tex_fetch(__curves, prim);
 
diff --git a/intern/cycles/kernel/geom/geom_object.h b/intern/cycles/kernel/geom/geom_object.h
index 5f5882065eec89a1600149f106e056f3a5d5673c..22a3fd6c9aca1228c9e1881c4e3d13c43b93e775 100644
--- a/intern/cycles/kernel/geom/geom_object.h
+++ b/intern/cycles/kernel/geom/geom_object.h
@@ -28,62 +28,44 @@ CCL_NAMESPACE_BEGIN
 
 enum ObjectTransform {
 	OBJECT_TRANSFORM = 0,
-	OBJECT_INVERSE_TRANSFORM = 4,
-	OBJECT_TRANSFORM_MOTION_PRE = 0,
-	OBJECT_TRANSFORM_MOTION_MID = 4,
-	OBJECT_TRANSFORM_MOTION_POST = 8,
-	OBJECT_PROPERTIES = 12,
-	OBJECT_DUPLI = 13
+	OBJECT_INVERSE_TRANSFORM = 1,
 };
 
 enum ObjectVectorTransform {
-	OBJECT_VECTOR_MOTION_PRE = 0,
-	OBJECT_VECTOR_MOTION_POST = 3
+	OBJECT_PASS_MOTION_PRE = 0,
+	OBJECT_PASS_MOTION_POST = 1
 };
 
 /* Object to world space transformation */
 
 ccl_device_inline Transform object_fetch_transform(KernelGlobals *kg, int object, enum ObjectTransform type)
 {
-	int offset = object*OBJECT_SIZE + (int)type;
-
-	Transform tfm;
-	tfm.x = kernel_tex_fetch(__objects, offset + 0);
-	tfm.y = kernel_tex_fetch(__objects, offset + 1);
-	tfm.z = kernel_tex_fetch(__objects, offset + 2);
-	tfm.w = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
-
-	return tfm;
+	if(type == OBJECT_INVERSE_TRANSFORM) {
+		return kernel_tex_fetch(__objects, object).itfm;
+	}
+	else {
+		return kernel_tex_fetch(__objects, object).tfm;
+	}
 }
 
 /* Lamp to world space transformation */
 
 ccl_device_inline Transform lamp_fetch_transform(KernelGlobals *kg, int lamp, bool inverse)
 {
-	int offset = lamp*LIGHT_SIZE + (inverse? 8 : 5);
-
-	Transform tfm;
-	tfm.x = kernel_tex_fetch(__light_data, offset + 0);
-	tfm.y = kernel_tex_fetch(__light_data, offset + 1);
-	tfm.z = kernel_tex_fetch(__light_data, offset + 2);
-	tfm.w = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
-
-	return tfm;
+	if(inverse) {
+		return kernel_tex_fetch(__lights, lamp).itfm;
+	}
+	else {
+		return kernel_tex_fetch(__lights, lamp).tfm;
+	}
 }
 
 /* Object to world space transformation for motion vectors */
 
-ccl_device_inline Transform object_fetch_vector_transform(KernelGlobals *kg, int object, enum ObjectVectorTransform type)
+ccl_device_inline Transform object_fetch_motion_pass_transform(KernelGlobals *kg, int object, enum ObjectVectorTransform type)
 {
-	int offset = object*OBJECT_VECTOR_SIZE + (int)type;
-
-	Transform tfm;
-	tfm.x = kernel_tex_fetch(__objects_vector, offset + 0);
-	tfm.y = kernel_tex_fetch(__objects_vector, offset + 1);
-	tfm.z = kernel_tex_fetch(__objects_vector, offset + 2);
-	tfm.w = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
-
-	return tfm;
+	int offset = object*OBJECT_MOTION_PASS_SIZE + (int)type;
+	return kernel_tex_fetch(__object_motion_pass, offset);
 }
 
 /* Motion blurred object transformations */
@@ -91,33 +73,18 @@ ccl_device_inline Transform object_fetch_vector_transform(KernelGlobals *kg, int
 #ifdef __OBJECT_MOTION__
 ccl_device_inline Transform object_fetch_transform_motion(KernelGlobals *kg, int object, float time)
 {
-	MotionTransform motion;
-
-	int offset = object*OBJECT_SIZE + (int)OBJECT_TRANSFORM_MOTION_PRE;
-
-	motion.pre.x = kernel_tex_fetch(__objects, offset + 0);
-	motion.pre.y = kernel_tex_fetch(__objects, offset + 1);
-	motion.pre.z = kernel_tex_fetch(__objects, offset + 2);
-	motion.pre.w = kernel_tex_fetch(__objects, offset + 3);
-
-	motion.mid.x = kernel_tex_fetch(__objects, offset + 4);
-	motion.mid.y = kernel_tex_fetch(__objects, offset + 5);
-	motion.mid.z = kernel_tex_fetch(__objects, offset + 6);
-	motion.mid.w = kernel_tex_fetch(__objects, offset + 7);
-
-	motion.post.x = kernel_tex_fetch(__objects, offset + 8);
-	motion.post.y = kernel_tex_fetch(__objects, offset + 9);
-	motion.post.z = kernel_tex_fetch(__objects, offset + 10);
-	motion.post.w = kernel_tex_fetch(__objects, offset + 11);
+	const uint motion_offset = kernel_tex_fetch(__objects, object).motion_offset;
+	const ccl_global DecomposedTransform *motion = &kernel_tex_fetch(__object_motion, motion_offset);
+	const uint num_steps = kernel_tex_fetch(__objects, object).numsteps * 2 + 1;
 
 	Transform tfm;
 #ifdef __EMBREE__
 	if(kernel_data.bvh.scene) {
-		transform_motion_interpolate_straight(&tfm, &motion, time);
+		transform_motion_array_interpolate_straight(&tfm, motion, num_steps, time);
 	}
 	else
 #endif
-	transform_motion_interpolate(&tfm, &motion, time);
+	transform_motion_array_interpolate(&tfm, motion, num_steps, time);
 
 	return tfm;
 }
@@ -243,9 +210,7 @@ ccl_device_inline float3 object_location(KernelGlobals *kg, const ShaderData *sd
 
 ccl_device_inline float object_surface_area(KernelGlobals *kg, int object)
 {
-	int offset = object*OBJECT_SIZE + OBJECT_PROPERTIES;
-	float4 f = kernel_tex_fetch(__objects, offset);
-	return f.x;
+	return kernel_tex_fetch(__objects, object).surface_area;
 }
 
 /* Pass ID number of object */
@@ -255,9 +220,7 @@ ccl_device_inline float object_pass_id(KernelGlobals *kg, int object)
 	if(object == OBJECT_NONE)
 		return 0.0f;
 
-	int offset = object*OBJECT_SIZE + OBJECT_PROPERTIES;
-	float4 f = kernel_tex_fetch(__objects, offset);
-	return f.y;
+	return kernel_tex_fetch(__objects, object).pass_id;
 }
 
 /* Per lamp random number for shader variation */
@@ -267,8 +230,7 @@ ccl_device_inline float lamp_random_number(KernelGlobals *kg, int lamp)
 	if(lamp == LAMP_NONE)
 		return 0.0f;
 
-	float4 f = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 4);
-	return f.y;
+	return kernel_tex_fetch(__lights, lamp).random;
 }
 
 /* Per object random number for shader variation */
@@ -278,9 +240,7 @@ ccl_device_inline float object_random_number(KernelGlobals *kg, int object)
 	if(object == OBJECT_NONE)
 		return 0.0f;
 
-	int offset = object*OBJECT_SIZE + OBJECT_PROPERTIES;
-	float4 f = kernel_tex_fetch(__objects, offset);
-	return f.z;
+	return kernel_tex_fetch(__objects, object).random_number;
 }
 
 /* Particle ID from which this object was generated */
@@ -290,9 +250,7 @@ ccl_device_inline int object_particle_id(KernelGlobals *kg, int object)
 	if(object == OBJECT_NONE)
 		return 0;
 
-	int offset = object*OBJECT_SIZE + OBJECT_PROPERTIES;
-	float4 f = kernel_tex_fetch(__objects, offset);
-	return __float_as_uint(f.w);
+	return kernel_tex_fetch(__objects, object).particle_index;
 }
 
 /* Generated texture coordinate on surface from where object was instanced */
@@ -302,9 +260,10 @@ ccl_device_inline float3 object_dupli_generated(KernelGlobals *kg, int object)
 	if(object == OBJECT_NONE)
 		return make_float3(0.0f, 0.0f, 0.0f);
 
-	int offset = object*OBJECT_SIZE + OBJECT_DUPLI;
-	float4 f = kernel_tex_fetch(__objects, offset);
-	return make_float3(f.x, f.y, f.z);
+	const ccl_global KernelObject *kobject = &kernel_tex_fetch(__objects, object);
+	return make_float3(kobject->dupli_generated[0],
+	                   kobject->dupli_generated[1],
+	                   kobject->dupli_generated[2]);
 }
 
 /* UV texture coordinate on surface from where object was instanced */
@@ -314,27 +273,24 @@ ccl_device_inline float3 object_dupli_uv(KernelGlobals *kg, int object)
 	if(object == OBJECT_NONE)
 		return make_float3(0.0f, 0.0f, 0.0f);
 
-	int offset = object*OBJECT_SIZE + OBJECT_DUPLI;
-	float4 f = kernel_tex_fetch(__objects, offset + 1);
-	return make_float3(f.x, f.y, 0.0f);
+	const ccl_global KernelObject *kobject = &kernel_tex_fetch(__objects, object);
+	return make_float3(kobject->dupli_uv[0],
+	                   kobject->dupli_uv[1],
+	                   0.0f);
 }
 
 /* Information about mesh for motion blurred triangles and curves */
 
 ccl_device_inline void object_motion_info(KernelGlobals *kg, int object, int *numsteps, int *numverts, int *numkeys)
 {
-	int offset = object*OBJECT_SIZE + OBJECT_DUPLI;
-
 	if(numkeys) {
-		float4 f = kernel_tex_fetch(__objects, offset);
-		*numkeys = __float_as_int(f.w);
+		*numkeys = kernel_tex_fetch(__objects, object).numkeys;
 	}
 
-	float4 f = kernel_tex_fetch(__objects, offset + 1);
 	if(numsteps)
-		*numsteps = __float_as_int(f.z);
+		*numsteps = kernel_tex_fetch(__objects, object).numsteps;
 	if(numverts)
-		*numverts = __float_as_int(f.w);
+		*numverts = kernel_tex_fetch(__objects, object).numverts;
 }
 
 /* Offset to an objects patch map */
@@ -344,76 +300,56 @@ ccl_device_inline uint object_patch_map_offset(KernelGlobals *kg, int object)
 	if(object == OBJECT_NONE)
 		return 0;
 
-	int offset = object*OBJECT_SIZE + 15;
-	float4 f = kernel_tex_fetch(__objects, offset);
-	return __float_as_uint(f.x);
+	return kernel_tex_fetch(__objects, object).patch_map_offset;
 }
 
 /* Pass ID for shader */
 
 ccl_device int shader_pass_id(KernelGlobals *kg, const ShaderData *sd)
 {
-	return kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*SHADER_SIZE + 1);
+	return kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).pass_id;
 }
 
 /* Particle data from which object was instanced */
 
 ccl_device_inline uint particle_index(KernelGlobals *kg, int particle)
 {
-	int offset = particle*PARTICLE_SIZE;
-	float4 f = kernel_tex_fetch(__particles, offset + 0);
-	return __float_as_uint(f.x);
+	return kernel_tex_fetch(__particles, particle).index;
 }
 
 ccl_device float particle_age(KernelGlobals *kg, int particle)
 {
-	int offset = particle*PARTICLE_SIZE;
-	float4 f = kernel_tex_fetch(__particles, offset + 0);
-	return f.y;
+	return kernel_tex_fetch(__particles, particle).age;
 }
 
 ccl_device float particle_lifetime(KernelGlobals *kg, int particle)
 {
-	int offset = particle*PARTICLE_SIZE;
-	float4 f = kernel_tex_fetch(__particles, offset + 0);
-	return f.z;
+	return kernel_tex_fetch(__particles, particle).lifetime;
 }
 
 ccl_device float particle_size(KernelGlobals *kg, int particle)
 {
-	int offset = particle*PARTICLE_SIZE;
-	float4 f = kernel_tex_fetch(__particles, offset + 0);
-	return f.w;
+	return kernel_tex_fetch(__particles, particle).size;
 }
 
 ccl_device float4 particle_rotation(KernelGlobals *kg, int particle)
 {
-	int offset = particle*PARTICLE_SIZE;
-	float4 f = kernel_tex_fetch(__particles, offset + 1);
-	return f;
+	return kernel_tex_fetch(__particles, particle).rotation;
 }
 
 ccl_device float3 particle_location(KernelGlobals *kg, int particle)
 {
-	int offset = particle*PARTICLE_SIZE;
-	float4 f = kernel_tex_fetch(__particles, offset + 2);
-	return make_float3(f.x, f.y, f.z);
+	return float4_to_float3(kernel_tex_fetch(__particles, particle).location);
 }
 
 ccl_device float3 particle_velocity(KernelGlobals *kg, int particle)
 {
-	int offset = particle*PARTICLE_SIZE;
-	float4 f2 = kernel_tex_fetch(__particles, offset + 2);
-	float4 f3 = kernel_tex_fetch(__particles, offset + 3);
-	return make_float3(f2.w, f3.x, f3.y);
+	return float4_to_float3(kernel_tex_fetch(__particles, particle).velocity);
 }
 
 ccl_device float3 particle_angular_velocity(KernelGlobals *kg, int particle)
 {
-	int offset = particle*PARTICLE_SIZE;
-	float4 f3 = kernel_tex_fetch(__particles, offset + 3);
-	float4 f4 = kernel_tex_fetch(__particles, offset + 4);
-	return make_float3(f3.z, f3.w, f4.x);
+	return float4_to_float3(kernel_tex_fetch(__particles, particle).angular_velocity);
 }
 
 /* Object intersection in BVH */
diff --git a/intern/cycles/kernel/geom/geom_primitive.h b/intern/cycles/kernel/geom/geom_primitive.h
index 60a1e483b847056ba968a697af07e10df02e96ef..c159be928856c211d051ef15fc1d2426f7ef88f8 100644
--- a/intern/cycles/kernel/geom/geom_primitive.h
+++ b/intern/cycles/kernel/geom/geom_primitive.h
@@ -193,10 +193,10 @@ ccl_device_inline float4 primitive_motion_vector(KernelGlobals *kg, ShaderData *
 	 * transformation was set match the world/object space of motion_pre/post */
 	Transform tfm;
 	
-	tfm = object_fetch_vector_transform(kg, sd->object, OBJECT_VECTOR_MOTION_PRE);
+	tfm = object_fetch_motion_pass_transform(kg, sd->object, OBJECT_PASS_MOTION_PRE);
 	motion_pre = transform_point(&tfm, motion_pre);
 
-	tfm = object_fetch_vector_transform(kg, sd->object, OBJECT_VECTOR_MOTION_POST);
+	tfm = object_fetch_motion_pass_transform(kg, sd->object, OBJECT_PASS_MOTION_POST);
 	motion_post = transform_point(&tfm, motion_post);
 
 	float3 motion_center;
@@ -204,14 +204,14 @@ ccl_device_inline float4 primitive_motion_vector(KernelGlobals *kg, ShaderData *
 	/* camera motion, for perspective/orthographic motion.pre/post will be a
 	 * world-to-raster matrix, for panorama it's world-to-camera */
 	if(kernel_data.cam.type != CAMERA_PANORAMA) {
-		tfm = kernel_data.cam.worldtoraster;
-		motion_center = transform_perspective(&tfm, center);
+		ProjectionTransform projection = kernel_data.cam.worldtoraster;
+		motion_center = transform_perspective(&projection, center);
 
-		tfm = kernel_data.cam.motion.pre;
-		motion_pre = transform_perspective(&tfm, motion_pre);
+		projection = kernel_data.cam.perspective_pre;
+		motion_pre = transform_perspective(&projection, motion_pre);
 
-		tfm = kernel_data.cam.motion.post;
-		motion_post = transform_perspective(&tfm, motion_post);
+		projection = kernel_data.cam.perspective_post;
+		motion_post = transform_perspective(&projection, motion_post);
 	}
 	else {
 		tfm = kernel_data.cam.worldtocamera;
@@ -220,13 +220,13 @@ ccl_device_inline float4 primitive_motion_vector(KernelGlobals *kg, ShaderData *
 		motion_center.x *= kernel_data.cam.width;
 		motion_center.y *= kernel_data.cam.height;
 
-		tfm = kernel_data.cam.motion.pre;
+		tfm = kernel_data.cam.motion_pass_pre;
 		motion_pre = normalize(transform_point(&tfm, motion_pre));
 		motion_pre = float2_to_float3(direction_to_panorama(&kernel_data.cam, motion_pre));
 		motion_pre.x *= kernel_data.cam.width;
 		motion_pre.y *= kernel_data.cam.height;
 
-		tfm = kernel_data.cam.motion.post;
+		tfm = kernel_data.cam.motion_pass_post;
 		motion_post = normalize(transform_point(&tfm, motion_post));
 		motion_post = float2_to_float3(direction_to_panorama(&kernel_data.cam, motion_post));
 		motion_post.x *= kernel_data.cam.width;
diff --git a/intern/cycles/kernel/geom/geom_volume.h b/intern/cycles/kernel/geom/geom_volume.h
index 286d898992e658b251f507c1ce9d7e6bc59b1176..a4e47384b25cbda9cf1fe43cceb0fd539720ef22 100644
--- a/intern/cycles/kernel/geom/geom_volume.h
+++ b/intern/cycles/kernel/geom/geom_volume.h
@@ -68,7 +68,7 @@ ccl_device float3 volume_attribute_float3(KernelGlobals *kg, const ShaderData *s
 	if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f);
 	if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f);
 
-	if(r.w != 0.0f && r.w != 1.0f) {
+	if(r.w > 1e-8f && r.w != 1.0f) {
 		/* For RGBA colors, unpremultiply after interpolation. */
 		return float4_to_float3(r) / r.w;
 	}
diff --git a/intern/cycles/kernel/kernel_bake.h b/intern/cycles/kernel/kernel_bake.h
index b3c2450d10e13848ad28943c0da9bbdf5577dfeb..79e6d1b4862ac96130e3f34ce4a09519dc1b6df2 100644
--- a/intern/cycles/kernel/kernel_bake.h
+++ b/intern/cycles/kernel/kernel_bake.h
@@ -330,15 +330,30 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
 	switch(type) {
 		/* data passes */
 		case SHADER_EVAL_NORMAL:
+		case SHADER_EVAL_ROUGHNESS:
+		case SHADER_EVAL_EMISSION:
 		{
-			float3 N = sd.N;
-			if((sd.flag & SD_HAS_BUMP)) {
-				shader_eval_surface(kg, &sd, &state, 0);
-				N = shader_bsdf_average_normal(kg, &sd);
+			if(type != SHADER_EVAL_NORMAL || (sd.flag & SD_HAS_BUMP)) {
+				int path_flag = (type == SHADER_EVAL_EMISSION) ? PATH_RAY_EMISSION : 0;
+				shader_eval_surface(kg, &sd, &state, path_flag);
 			}
 
-			/* encoding: normal = (2 * color) - 1 */
-			out = N * 0.5f + make_float3(0.5f, 0.5f, 0.5f);
+			if(type == SHADER_EVAL_NORMAL) {
+				float3 N = sd.N;
+				if(sd.flag & SD_HAS_BUMP) {
+					N = shader_bsdf_average_normal(kg, &sd);
+				}
+
+				/* encoding: normal = (2 * color) - 1 */
+				out = N * 0.5f + make_float3(0.5f, 0.5f, 0.5f);
+			}
+			else if(type == SHADER_EVAL_ROUGHNESS) {
+				float roughness = shader_bsdf_average_roughness(&sd);
+				out = make_float3(roughness, roughness, roughness);
+			}
+			else {
+				out = shader_emissive_eval(kg, &sd);
+			}
 			break;
 		}
 		case SHADER_EVAL_UV:
@@ -346,13 +361,6 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
 			out = primitive_uv(kg, &sd);
 			break;
 		}
-		case SHADER_EVAL_EMISSION:
-		{
-			shader_eval_surface(kg, &sd, &state, PATH_RAY_EMISSION);
-			out = shader_emissive_eval(kg, &sd);
-			break;
-		}
-
 #ifdef __PASSES__
 		/* light passes */
 		case SHADER_EVAL_AO:
diff --git a/intern/cycles/kernel/kernel_camera.h b/intern/cycles/kernel/kernel_camera.h
index 96cdb04d95548e43cf62f30223d6b82386717f98..b73ad47dad37b2c8e9c01c8c5d951239fbfa5ce9 100644
--- a/intern/cycles/kernel/kernel_camera.h
+++ b/intern/cycles/kernel/kernel_camera.h
@@ -42,7 +42,7 @@ ccl_device float2 camera_sample_aperture(ccl_constant KernelCamera *cam, float u
 ccl_device void camera_sample_perspective(KernelGlobals *kg, float raster_x, float raster_y, float lens_u, float lens_v, ccl_addr_space Ray *ray)
 {
 	/* create ray form raster position */
-	Transform rastertocamera = kernel_data.cam.rastertocamera;
+	ProjectionTransform rastertocamera = kernel_data.cam.rastertocamera;
 	float3 raster = make_float3(raster_x, raster_y, 0.0f);
 	float3 Pcamera = transform_perspective(&rastertocamera, raster);
 
@@ -54,13 +54,13 @@ ccl_device void camera_sample_perspective(KernelGlobals *kg, float raster_x, flo
 		 * interpolated field of view.
 		 */
 		if(ray->time < 0.5f) {
-			Transform rastertocamera_pre = kernel_data.cam.perspective_motion.pre;
+			ProjectionTransform rastertocamera_pre = kernel_data.cam.perspective_pre;
 			float3 Pcamera_pre =
 			        transform_perspective(&rastertocamera_pre, raster);
 			Pcamera = interp(Pcamera_pre, Pcamera, ray->time * 2.0f);
 		}
 		else {
-			Transform rastertocamera_post = kernel_data.cam.perspective_motion.post;
+			ProjectionTransform rastertocamera_post = kernel_data.cam.perspective_post;
 			float3 Pcamera_post =
 			        transform_perspective(&rastertocamera_post, raster);
 			Pcamera = interp(Pcamera, Pcamera_post, (ray->time - 0.5f) * 2.0f);
@@ -91,17 +91,12 @@ ccl_device void camera_sample_perspective(KernelGlobals *kg, float raster_x, flo
 	Transform cameratoworld = kernel_data.cam.cameratoworld;
 
 #ifdef __CAMERA_MOTION__
-	if(kernel_data.cam.have_motion) {
-#  ifdef __KERNEL_OPENCL__
-		const MotionTransform tfm = kernel_data.cam.motion;
-		transform_motion_interpolate(&cameratoworld,
-									 &tfm,
-		                             ray->time);
-#  else
-		transform_motion_interpolate(&cameratoworld,
-		                             &kernel_data.cam.motion,
-		                             ray->time);
-#  endif
+	if(kernel_data.cam.num_motion_steps) {
+		transform_motion_array_interpolate(
+			&cameratoworld,
+			kernel_tex_array(__camera_motion),
+			kernel_data.cam.num_motion_steps,
+			ray->time);
 	}
 #endif
 
@@ -175,7 +170,7 @@ ccl_device void camera_sample_perspective(KernelGlobals *kg, float raster_x, flo
 ccl_device void camera_sample_orthographic(KernelGlobals *kg, float raster_x, float raster_y, float lens_u, float lens_v, ccl_addr_space Ray *ray)
 {
 	/* create ray form raster position */
-	Transform rastertocamera = kernel_data.cam.rastertocamera;
+	ProjectionTransform rastertocamera = kernel_data.cam.rastertocamera;
 	float3 Pcamera = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f));
 
 	float3 P;
@@ -203,17 +198,12 @@ ccl_device void camera_sample_orthographic(KernelGlobals *kg, float raster_x, fl
 	Transform cameratoworld = kernel_data.cam.cameratoworld;
 
 #ifdef __CAMERA_MOTION__
-	if(kernel_data.cam.have_motion) {
-#  ifdef __KERNEL_OPENCL__
-		const MotionTransform tfm = kernel_data.cam.motion;
-		transform_motion_interpolate(&cameratoworld,
-		                             &tfm,
-		                             ray->time);
-#  else
-		transform_motion_interpolate(&cameratoworld,
-		                             &kernel_data.cam.motion,
-		                             ray->time);
-#  endif
+	if(kernel_data.cam.num_motion_steps) {
+		transform_motion_array_interpolate(
+			&cameratoworld,
+			kernel_tex_array(__camera_motion),
+			kernel_data.cam.num_motion_steps,
+			ray->time);
 	}
 #endif
 
@@ -239,11 +229,12 @@ ccl_device void camera_sample_orthographic(KernelGlobals *kg, float raster_x, fl
 /* Panorama Camera */
 
 ccl_device_inline void camera_sample_panorama(ccl_constant KernelCamera *cam,
+                                              const ccl_global DecomposedTransform *cam_motion,
                                               float raster_x, float raster_y,
                                               float lens_u, float lens_v,
                                               ccl_addr_space Ray *ray)
 {
-	Transform rastertocamera = cam->rastertocamera;
+	ProjectionTransform rastertocamera = cam->rastertocamera;
 	float3 Pcamera = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f));
 
 	/* create ray form raster position */
@@ -281,17 +272,12 @@ ccl_device_inline void camera_sample_panorama(ccl_constant KernelCamera *cam,
 	Transform cameratoworld = cam->cameratoworld;
 
 #ifdef __CAMERA_MOTION__
-	if(cam->have_motion) {
-#  ifdef __KERNEL_OPENCL__
-		const MotionTransform tfm = cam->motion;
-		transform_motion_interpolate(&cameratoworld,
-		                             &tfm,
-		                             ray->time);
-#  else
-		transform_motion_interpolate(&cameratoworld,
-		                             &cam->motion,
-		                             ray->time);
-#  endif
+	if(cam->num_motion_steps) {
+		transform_motion_array_interpolate(
+			&cameratoworld,
+			cam_motion,
+			cam->num_motion_steps,
+			ray->time);
 	}
 #endif
 
@@ -410,12 +396,16 @@ ccl_device_inline void camera_sample(KernelGlobals *kg,
 #endif
 
 	/* sample */
-	if(kernel_data.cam.type == CAMERA_PERSPECTIVE)
+	if(kernel_data.cam.type == CAMERA_PERSPECTIVE) {
 		camera_sample_perspective(kg, raster_x, raster_y, lens_u, lens_v, ray);
-	else if(kernel_data.cam.type == CAMERA_ORTHOGRAPHIC)
+	}
+	else if(kernel_data.cam.type == CAMERA_ORTHOGRAPHIC) {
 		camera_sample_orthographic(kg, raster_x, raster_y, lens_u, lens_v, ray);
-	else
-		camera_sample_panorama(&kernel_data.cam, raster_x, raster_y, lens_u, lens_v, ray);
+	}
+	else {
+		const ccl_global DecomposedTransform *cam_motion = kernel_tex_array(__camera_motion);
+		camera_sample_panorama(&kernel_data.cam, cam_motion, raster_x, raster_y, lens_u, lens_v, ray);
+	}
 }
 
 /* Utilities */
@@ -460,7 +450,7 @@ ccl_device_inline float3 camera_world_to_ndc(KernelGlobals *kg, ShaderData *sd,
 		if(sd->object == PRIM_NONE && kernel_data.cam.type == CAMERA_PERSPECTIVE)
 			P += camera_position(kg);
 
-		Transform tfm = kernel_data.cam.worldtondc;
+		ProjectionTransform tfm = kernel_data.cam.worldtondc;
 		return transform_perspective(&tfm, P);
 	}
 	else {
diff --git a/intern/cycles/kernel/kernel_compat_cpu.h b/intern/cycles/kernel/kernel_compat_cpu.h
index 61cd90e9d2af8e15a20344fb7d97682e38430e2f..d26b668cb11248062b29e1d9a281c15169b2e674 100644
--- a/intern/cycles/kernel/kernel_compat_cpu.h
+++ b/intern/cycles/kernel/kernel_compat_cpu.h
@@ -118,6 +118,7 @@ template<typename T> struct texture  {
 #define kernel_tex_fetch_ssef(tex, index) (kg->tex.fetch_ssef(index))
 #define kernel_tex_fetch_ssei(tex, index) (kg->tex.fetch_ssei(index))
 #define kernel_tex_lookup(tex, t, offset, size) (kg->tex.lookup(t, offset, size))
+#define kernel_tex_array(tex) (kg->tex.data)
 
 #define kernel_data (kg->__data)
 
diff --git a/intern/cycles/kernel/kernel_compat_cuda.h b/intern/cycles/kernel/kernel_compat_cuda.h
index 9bd7a572f5fdd48659a46b7851bf0f3566accf28..ac63bcf7ac9657a1398cb0dc83ec0dc482c748fe 100644
--- a/intern/cycles/kernel/kernel_compat_cuda.h
+++ b/intern/cycles/kernel/kernel_compat_cuda.h
@@ -137,6 +137,7 @@ ccl_device_inline uint ccl_num_groups(uint d)
 
 /* Use arrays for regular data. */
 #define kernel_tex_fetch(t, index) t[(index)]
+#define kernel_tex_array(t) (t)
 
 #define kernel_data __data
 
diff --git a/intern/cycles/kernel/kernel_compat_opencl.h b/intern/cycles/kernel/kernel_compat_opencl.h
index b02e3bc576d8e3018f3a596a8fea36e304c66301..671c47e2225fa2001aa89d2ed0b4c94f3b29acba 100644
--- a/intern/cycles/kernel/kernel_compat_opencl.h
+++ b/intern/cycles/kernel/kernel_compat_opencl.h
@@ -144,7 +144,8 @@
 
 /* data lookup defines */
 #define kernel_data (*kg->data)
-#define kernel_tex_fetch(tex, index) ((const ccl_global tex##_t*)(kg->buffers[kg->tex.cl_buffer] + kg->tex.data))[(index)]
+#define kernel_tex_array(tex) ((const ccl_global tex##_t*)(kg->buffers[kg->tex.cl_buffer] + kg->tex.data))
+#define kernel_tex_fetch(tex, index) kernel_tex_array(tex)[(index)]
 
 /* define NULL */
 #define NULL 0
diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h
index 5875249b4049469451a8701bb6bdc9c7c0719de0..a5556c3be8fbe3d51164c94708e245a703dd69e0 100644
--- a/intern/cycles/kernel/kernel_emission.h
+++ b/intern/cycles/kernel/kernel_emission.h
@@ -29,7 +29,7 @@ ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg,
 	/* setup shading at emitter */
 	float3 eval;
 
-	int shader_flag = kernel_tex_fetch(__shader_flag, (ls->shader & SHADER_MASK)*SHADER_SIZE);
+	int shader_flag = kernel_tex_fetch(__shaders, (ls->shader & SHADER_MASK)).flags;
 
 #ifdef __BACKGROUND_MIS__
 	if(ls->type == LIGHT_BACKGROUND) {
@@ -51,9 +51,9 @@ ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg,
 #endif
 	if(shader_flag & SD_HAS_CONSTANT_EMISSION)
 	{
-		eval.x = __int_as_float(kernel_tex_fetch(__shader_flag, (ls->shader & SHADER_MASK)*SHADER_SIZE + 2));
-		eval.y = __int_as_float(kernel_tex_fetch(__shader_flag, (ls->shader & SHADER_MASK)*SHADER_SIZE + 3));
-		eval.z = __int_as_float(kernel_tex_fetch(__shader_flag, (ls->shader & SHADER_MASK)*SHADER_SIZE + 4));
+		eval.x = kernel_tex_fetch(__shaders, (ls->shader & SHADER_MASK)).constant_emission[0];
+		eval.y = kernel_tex_fetch(__shaders, (ls->shader & SHADER_MASK)).constant_emission[1];
+		eval.z = kernel_tex_fetch(__shaders, (ls->shader & SHADER_MASK)).constant_emission[2];
 		if((ls->prim != PRIM_NONE) && dot(ls->Ng, I) < 0.0f) {
 			ls->Ng = -ls->Ng;
 		}
diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h
index dfa3150dc920fb3a96f703de14e929de1366b17e..efab69ee37dfdf29bd39f2da64051ba14e58b1ea 100644
--- a/intern/cycles/kernel/kernel_light.h
+++ b/intern/cycles/kernel/kernel_light.h
@@ -255,11 +255,11 @@ ccl_device_inline bool background_portal_data_fetch_and_check_side(KernelGlobals
                                                                    float3 *lightpos,
                                                                    float3 *dir)
 {
-	float4 data0 = kernel_tex_fetch(__light_data, (index + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 0);
-	float4 data3 = kernel_tex_fetch(__light_data, (index + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 3);
+	int portal = kernel_data.integrator.portal_offset + index;
+	const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, portal);
 
-	*lightpos = make_float3(data0.y, data0.z, data0.w);
-	*dir = make_float3(data3.y, data3.z, data3.w);
+	*lightpos = make_float3(klight->co[0], klight->co[1], klight->co[2]);
+	*dir = make_float3(klight->area.dir[0], klight->area.dir[1], klight->area.dir[2]);
 
 	/* Check whether portal is on the right side. */
 	if(dot(*dir, P - *lightpos) > 1e-4f)
@@ -291,11 +291,10 @@ ccl_device_inline float background_portal_pdf(KernelGlobals *kg,
 		}
 		num_possible++;
 
-		float4 data1 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 1);
-		float4 data2 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 2);
-
-		float3 axisu = make_float3(data1.y, data1.z, data1.w);
-		float3 axisv = make_float3(data2.y, data2.z, data2.w);
+		int portal = kernel_data.integrator.portal_offset + p;
+		const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, portal);
+		float3 axisu = make_float3(klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]);
+		float3 axisv = make_float3(klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]);
 
 		if(!ray_quad_intersect(P, direction, 1e-4f, FLT_MAX, lightpos, axisu, axisv, dir, NULL, NULL, NULL, NULL))
 			continue;
@@ -346,10 +345,10 @@ ccl_device float3 background_portal_sample(KernelGlobals *kg,
 
 		if(portal == 0) {
 			/* p is the portal to be sampled. */
-			float4 data1 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 1);
-			float4 data2 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 2);
-			float3 axisu = make_float3(data1.y, data1.z, data1.w);
-			float3 axisv = make_float3(data2.y, data2.z, data2.w);
+			int portal = kernel_data.integrator.portal_offset + p;
+			const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, portal);
+			float3 axisu = make_float3(klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]);
+			float3 axisv = make_float3(klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]);
 
 			*pdf = area_light_sample(P, &lightpos,
 			                         axisu, axisv,
@@ -479,14 +478,10 @@ ccl_device float3 sphere_light_sample(float3 P, float3 center, float radius, flo
 	return disk_light_sample(normalize(P - center), randu, randv)*radius;
 }
 
-ccl_device float spot_light_attenuation(float4 data1, float4 data2, LightSample *ls)
+ccl_device float spot_light_attenuation(float3 dir, float spot_angle, float spot_smooth, LightSample *ls)
 {
-	float3 dir = make_float3(data2.y, data2.z, data2.w);
 	float3 I = ls->Ng;
 
-	float spot_angle = data1.w;
-	float spot_smooth = data2.x;
-
 	float attenuation = dot(dir, I);
 
 	if(attenuation <= spot_angle) {
@@ -518,12 +513,10 @@ ccl_device_inline bool lamp_light_sample(KernelGlobals *kg,
                                          float3 P,
                                          LightSample *ls)
 {
-	float4 data0 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 0);
-	float4 data1 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 1);
-
-	LightType type = (LightType)__float_as_int(data0.x);
+	const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, lamp);
+	LightType type = (LightType)klight->type;
 	ls->type = type;
-	ls->shader = __float_as_int(data1.x);
+	ls->shader = klight->shader_id;
 	ls->object = PRIM_NONE;
 	ls->prim = PRIM_NONE;
 	ls->lamp = lamp;
@@ -532,10 +525,10 @@ ccl_device_inline bool lamp_light_sample(KernelGlobals *kg,
 
 	if(type == LIGHT_DISTANT) {
 		/* distant light */
-		float3 lightD = make_float3(data0.y, data0.z, data0.w);
+		float3 lightD = make_float3(klight->co[0], klight->co[1], klight->co[2]);
 		float3 D = lightD;
-		float radius = data1.y;
-		float invarea = data1.w;
+		float radius = klight->distant.radius;
+		float invarea = klight->distant.invarea;
 
 		if(radius > 0.0f)
 			D = distant_light_sample(D, radius, randu, randv);
@@ -562,10 +555,10 @@ ccl_device_inline bool lamp_light_sample(KernelGlobals *kg,
 	}
 #endif
 	else {
-		ls->P = make_float3(data0.y, data0.z, data0.w);
+		ls->P = make_float3(klight->co[0], klight->co[1], klight->co[2]);
 
 		if(type == LIGHT_POINT || type == LIGHT_SPOT) {
-			float radius = data1.y;
+			float radius = klight->spot.radius;
 
 			if(radius > 0.0f)
 				/* sphere light */
@@ -574,14 +567,19 @@ ccl_device_inline bool lamp_light_sample(KernelGlobals *kg,
 			ls->D = normalize_len(ls->P - P, &ls->t);
 			ls->Ng = -ls->D;
 
-			float invarea = data1.z;
+			float invarea = klight->spot.invarea;
 			ls->eval_fac = (0.25f*M_1_PI_F)*invarea;
 			ls->pdf = invarea;
 
 			if(type == LIGHT_SPOT) {
 				/* spot light attenuation */
-				float4 data2 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 2);
-				ls->eval_fac *= spot_light_attenuation(data1, data2, ls);
+				float3 dir = make_float3(klight->spot.dir[0],
+                                         klight->spot.dir[1],
+				                         klight->spot.dir[2]);
+				ls->eval_fac *= spot_light_attenuation(dir,
+				                                       klight->spot.spot_angle,
+				                                       klight->spot.spot_smooth,
+				                                       ls);
 				if(ls->eval_fac == 0.0f) {
 					return false;
 				}
@@ -594,12 +592,15 @@ ccl_device_inline bool lamp_light_sample(KernelGlobals *kg,
 		}
 		else {
 			/* area light */
-			float4 data2 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 2);
-			float4 data3 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 3);
-
-			float3 axisu = make_float3(data1.y, data1.z, data1.w);
-			float3 axisv = make_float3(data2.y, data2.z, data2.w);
-			float3 D = make_float3(data3.y, data3.z, data3.w);
+			float3 axisu = make_float3(klight->area.axisu[0],
+			                           klight->area.axisu[1],
+			                           klight->area.axisu[2]);
+			float3 axisv = make_float3(klight->area.axisv[0],
+			                           klight->area.axisv[1],
+			                           klight->area.axisv[2]);
+			float3 D = make_float3(klight->area.dir[0],
+			                       klight->area.dir[1],
+			                       klight->area.dir[2]);
 
 			if(dot(ls->P - P, D) > 0.0f) {
 				return false;
@@ -618,7 +619,7 @@ ccl_device_inline bool lamp_light_sample(KernelGlobals *kg,
 			ls->Ng = D;
 			ls->D = normalize_len(ls->P - P, &ls->t);
 
-			float invarea = data2.x;
+			float invarea = klight->area.invarea;
 			ls->eval_fac = 0.25f*invarea;
 		}
 	}
@@ -630,12 +631,10 @@ ccl_device_inline bool lamp_light_sample(KernelGlobals *kg,
 
 ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D, float t, LightSample *ls)
 {
-	float4 data0 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 0);
-	float4 data1 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 1);
-
-	LightType type = (LightType)__float_as_int(data0.x);
+	const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, lamp);
+	LightType type = (LightType)klight->type;
 	ls->type = type;
-	ls->shader = __float_as_int(data1.x);
+	ls->shader = klight->shader_id;
 	ls->object = PRIM_NONE;
 	ls->prim = PRIM_NONE;
 	ls->lamp = lamp;
@@ -648,7 +647,7 @@ ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D,
 
 	if(type == LIGHT_DISTANT) {
 		/* distant light */
-		float radius = data1.y;
+		float radius = klight->distant.radius;
 
 		if(radius == 0.0f)
 			return false;
@@ -670,9 +669,9 @@ ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D,
 		 *             P
 		 */
 
-		float3 lightD = make_float3(data0.y, data0.z, data0.w);
+		float3 lightD = make_float3(klight->co[0], klight->co[1], klight->co[2]);
 		float costheta = dot(-lightD, D);
-		float cosangle = data1.z;
+		float cosangle = klight->distant.cosangle;
 
 		if(costheta < cosangle)
 			return false;
@@ -683,13 +682,14 @@ ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D,
 		ls->t = FLT_MAX;
 
 		/* compute pdf */
-		float invarea = data1.w;
+		float invarea = klight->distant.invarea;
 		ls->pdf = invarea/(costheta*costheta*costheta);
 		ls->eval_fac = ls->pdf;
 	}
 	else if(type == LIGHT_POINT || type == LIGHT_SPOT) {
-		float3 lightP = make_float3(data0.y, data0.z, data0.w);
-		float radius = data1.y;
+		float3 lightP = make_float3(klight->co[0], klight->co[1], klight->co[2]);
+
+		float radius = klight->spot.radius;
 
 		/* sphere light */
 		if(radius == 0.0f)
@@ -704,14 +704,19 @@ ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D,
 		ls->Ng = -D;
 		ls->D = D;
 
-		float invarea = data1.z;
+		float invarea = klight->spot.invarea;
 		ls->eval_fac = (0.25f*M_1_PI_F)*invarea;
 		ls->pdf = invarea;
 
 		if(type == LIGHT_SPOT) {
 			/* spot light attenuation */
-			float4 data2 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 2);
-			ls->eval_fac *= spot_light_attenuation(data1, data2, ls);
+			float3 dir = make_float3(klight->spot.dir[0],
+			                         klight->spot.dir[1],
+			                         klight->spot.dir[2]);
+			ls->eval_fac *= spot_light_attenuation(dir,
+			                                       klight->spot.spot_angle,
+			                                       klight->spot.spot_smooth,
+			                                       ls);
 
 			if(ls->eval_fac == 0.0f)
 				return false;
@@ -726,22 +731,25 @@ ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D,
 	}
 	else if(type == LIGHT_AREA) {
 		/* area light */
-		float4 data2 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 2);
-		float4 data3 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 3);
-
-		float invarea = data2.x;
+		float invarea = klight->area.invarea;
 		if(invarea == 0.0f)
 			return false;
 
-		float3 axisu = make_float3(data1.y, data1.z, data1.w);
-		float3 axisv = make_float3(data2.y, data2.z, data2.w);
-		float3 Ng = make_float3(data3.y, data3.z, data3.w);
+		float3 axisu = make_float3(klight->area.axisu[0],
+		                           klight->area.axisu[1],
+		                           klight->area.axisu[2]);
+		float3 axisv = make_float3(klight->area.axisv[0],
+		                           klight->area.axisv[1],
+		                           klight->area.axisv[2]);
+		float3 Ng = make_float3(klight->area.dir[0],
+		                        klight->area.dir[1],
+		                        klight->area.dir[2]);
 
 		/* one sided */
 		if(dot(D, Ng) >= 0.0f)
 			return false;
 
-		float3 light_P = make_float3(data0.y, data0.z, data0.w);
+		float3 light_P = make_float3(klight->co[0], klight->co[1], klight->co[2]);
 
 		if(!ray_quad_intersect(P, D, 0.0f, t, light_P,
 		                       axisu, axisv, Ng,
@@ -784,7 +792,8 @@ ccl_device_inline bool triangle_world_space_vertices(KernelGlobals *kg, int obje
 #ifdef __INSTANCING__
 	if(!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
 #  ifdef __OBJECT_MOTION__
-		Transform tfm = object_fetch_transform_motion_test(kg, object, time, NULL);
+		float object_time = (time >= 0.0f) ? time : 0.5f;
+		Transform tfm = object_fetch_transform_motion_test(kg, object, object_time, NULL);
 #  else
 		Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
 #  endif
@@ -1040,7 +1049,7 @@ ccl_device int light_distribution_sample(KernelGlobals *kg, float *randu)
 		int half_len = len >> 1;
 		int middle = first + half_len;
 
-		if(r < kernel_tex_fetch(__light_distribution, middle).x) {
+		if(r < kernel_tex_fetch(__light_distribution, middle).totarea) {
 			len = half_len;
 		}
 		else {
@@ -1055,8 +1064,8 @@ ccl_device int light_distribution_sample(KernelGlobals *kg, float *randu)
 
 	/* Rescale to reuse random number. this helps the 2D samples within
 	 * each area light be stratified as well. */
-	float distr_min = kernel_tex_fetch(__light_distribution, index).x;
-	float distr_max = kernel_tex_fetch(__light_distribution, index+1).x;
+	float distr_min = kernel_tex_fetch(__light_distribution, index).totarea;
+	float distr_max = kernel_tex_fetch(__light_distribution, index+1).totarea;
 	*randu = (r - distr_min)/(distr_max - distr_min);
 
 	return index;
@@ -1066,8 +1075,7 @@ ccl_device int light_distribution_sample(KernelGlobals *kg, float *randu)
 
 ccl_device bool light_select_reached_max_bounces(KernelGlobals *kg, int index, int bounce)
 {
-	float4 data4 = kernel_tex_fetch(__light_data, index*LIGHT_SIZE + 4);
-	return (bounce > __float_as_int(data4.x));
+	return (bounce > kernel_tex_fetch(__lights, index).max_bounces);
 }
 
 ccl_device_noinline bool light_sample(KernelGlobals *kg,
@@ -1082,12 +1090,12 @@ ccl_device_noinline bool light_sample(KernelGlobals *kg,
 	int index = light_distribution_sample(kg, &randu);
 
 	/* fetch light data */
-	float4 l = kernel_tex_fetch(__light_distribution, index);
-	int prim = __float_as_int(l.y);
+	const ccl_global KernelLightDistribution *kdistribution = &kernel_tex_fetch(__light_distribution, index);
+	int prim = kdistribution->prim;
 
 	if(prim >= 0) {
-		int object = __float_as_int(l.w);
-		int shader_flag = __float_as_int(l.z);
+		int object = kdistribution->mesh_light.object_id;
+		int shader_flag = kdistribution->mesh_light.shader_flag;
 
 		triangle_light_sample(kg, prim, object, randu, randv, time, ls, P);
 		ls->shader |= shader_flag;
@@ -1106,8 +1114,7 @@ ccl_device_noinline bool light_sample(KernelGlobals *kg,
 
 ccl_device int light_select_num_samples(KernelGlobals *kg, int index)
 {
-	float4 data3 = kernel_tex_fetch(__light_data, index*LIGHT_SIZE + 3);
-	return __float_as_int(data3.x);
+	return kernel_tex_fetch(__lights, index).samples;
 }
 
 CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_math.h b/intern/cycles/kernel/kernel_math.h
index bd0e23b77057fb22ba96841b3f1b35eba548387a..96391db7649eb0115d34a097fa02708603b20162 100644
--- a/intern/cycles/kernel/kernel_math.h
+++ b/intern/cycles/kernel/kernel_math.h
@@ -21,6 +21,7 @@
 #include "util/util_math.h"
 #include "util/util_math_fast.h"
 #include "util/util_math_intersect.h"
+#include "util/util_projection.h"
 #include "util/util_texture.h"
 #include "util/util_transform.h"
 
diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h
index b1f66852b7f1029c6942ac189dd81ed3a91cba62..937a50cba8b55d2a5415e066b3744bd80c7df4a5 100644
--- a/intern/cycles/kernel/kernel_shader.h
+++ b/intern/cycles/kernel/kernel_shader.h
@@ -114,7 +114,7 @@ ccl_device_noinline void shader_setup_from_ray(KernelGlobals *kg,
 
 	sd->I = -ray->D;
 
-	sd->flag |= kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*SHADER_SIZE);
+	sd->flag |= kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags;
 
 #ifdef __INSTANCING__
 	if(isect->object != OBJECT_NONE) {
@@ -199,7 +199,7 @@ void shader_setup_from_subsurface(
 		motion_triangle_shader_setup(kg, sd, isect, ray, true);
 	}
 
-	sd->flag |= kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*SHADER_SIZE);
+	sd->flag |= kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags;
 
 #  ifdef __INSTANCING__
 	if(isect->object != OBJECT_NONE) {
@@ -276,7 +276,7 @@ ccl_device_inline void shader_setup_from_sample(KernelGlobals *kg,
 	sd->time = time;
 	sd->ray_length = t;
 
-	sd->flag = kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*SHADER_SIZE);
+	sd->flag = kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags;
 	sd->object_flag = 0;
 	if(sd->object != OBJECT_NONE) {
 		sd->object_flag |= kernel_tex_fetch(__object_flag,
@@ -386,7 +386,7 @@ ccl_device_inline void shader_setup_from_background(KernelGlobals *kg, ShaderDat
 	sd->Ng = -ray->D;
 	sd->I = -ray->D;
 	sd->shader = kernel_data.background.surface_shader;
-	sd->flag = kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*SHADER_SIZE);
+	sd->flag = kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags;
 	sd->object_flag = 0;
 	sd->time = ray->time;
 	sd->ray_length = 0.0f;
@@ -763,6 +763,26 @@ ccl_device int shader_bsdf_sample_closure(KernelGlobals *kg, ShaderData *sd,
 	return label;
 }
 
+ccl_device float shader_bsdf_average_roughness(ShaderData *sd)
+{
+	float roughness = 0.0f;
+	float sum_weight = 0.0f;
+
+	for(int i = 0; i < sd->num_closure; i++) {
+		ShaderClosure *sc = &sd->closure[i];
+
+		if(CLOSURE_IS_BSDF(sc->type)) {
+			/* sqrt once to undo the squaring from multiplying roughness on the
+			 * two axes, and once for the squared roughness convention. */
+			float weight = fabsf(average(sc->weight));
+			roughness += weight * sqrtf(safe_sqrtf(bsdf_get_roughness_squared(sc)));
+			sum_weight += weight;
+		}
+	}
+
+	return (sum_weight > 0.0f) ? roughness / sum_weight : 0.0f;
+}
+
 ccl_device void shader_bsdf_blur(KernelGlobals *kg, ShaderData *sd, float roughness)
 {
 	for(int i = 0; i < sd->num_closure; i++) {
@@ -875,7 +895,7 @@ ccl_device float3 shader_bsdf_average_normal(KernelGlobals *kg, ShaderData *sd)
 	for(int i = 0; i < sd->num_closure; i++) {
 		ShaderClosure *sc = &sd->closure[i];
 		if(CLOSURE_IS_BSDF_OR_BSSRDF(sc->type))
-			N += sc->N*average(sc->weight);
+			N += sc->N*fabsf(average(sc->weight));
 	}
 
 	return (is_zero(N))? sd->N : normalize(N);
@@ -892,11 +912,11 @@ ccl_device float3 shader_bsdf_ao(KernelGlobals *kg, ShaderData *sd, float ao_fac
 		if(CLOSURE_IS_BSDF_DIFFUSE(sc->type)) {
 			const DiffuseBsdf *bsdf = (const DiffuseBsdf*)sc;
 			eval += sc->weight*ao_factor;
-			N += bsdf->N*average(sc->weight);
+			N += bsdf->N*fabsf(average(sc->weight));
 		}
 		else if(CLOSURE_IS_AMBIENT_OCCLUSION(sc->type)) {
 			eval += sc->weight;
-			N += sd->N*average(sc->weight);
+			N += sd->N*fabsf(average(sc->weight));
 		}
 	}
 
@@ -1181,7 +1201,7 @@ ccl_device_inline void shader_eval_volume(KernelGlobals *kg,
 		sd->shader = stack[i].shader;
 
 		sd->flag &= ~SD_SHADER_FLAGS;
-		sd->flag |= kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*SHADER_SIZE);
+		sd->flag |= kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags;
 		sd->object_flag &= ~SD_OBJECT_FLAGS;
 
 		if(sd->object != OBJECT_NONE) {
@@ -1254,7 +1274,7 @@ ccl_device bool shader_transparent_shadow(KernelGlobals *kg, Intersection *isect
 		shader = __float_as_int(str.z);
 	}
 #endif
-	int flag = kernel_tex_fetch(__shader_flag, (shader & SHADER_MASK)*SHADER_SIZE);
+	int flag = kernel_tex_fetch(__shaders, (shader & SHADER_MASK)).flags;
 
 	return (flag & SD_HAS_TRANSPARENT_SHADOW) != 0;
 }
diff --git a/intern/cycles/kernel/kernel_textures.h b/intern/cycles/kernel/kernel_textures.h
index 74b659557e5c29c2bc1ec742206b87e67e234c34..9047b93a0b2281cb5751b840541657f88e818776 100644
--- a/intern/cycles/kernel/kernel_textures.h
+++ b/intern/cycles/kernel/kernel_textures.h
@@ -31,8 +31,13 @@ KERNEL_TEX(uint, __object_node)
 KERNEL_TEX(float2, __prim_time)
 
 /* objects */
-KERNEL_TEX(float4, __objects)
-KERNEL_TEX(float4, __objects_vector)
+KERNEL_TEX(KernelObject, __objects)
+KERNEL_TEX(Transform, __object_motion_pass)
+KERNEL_TEX(DecomposedTransform, __object_motion)
+KERNEL_TEX(uint, __object_flag)
+
+/* cameras */
+KERNEL_TEX(DecomposedTransform, __camera_motion)
 
 /* triangles */
 KERNEL_TEX(uint, __tri_shader)
@@ -55,18 +60,17 @@ KERNEL_TEX(float4, __attributes_float3)
 KERNEL_TEX(uchar4, __attributes_uchar4)
 
 /* lights */
-KERNEL_TEX(float4, __light_distribution)
-KERNEL_TEX(float4, __light_data)
+KERNEL_TEX(KernelLightDistribution, __light_distribution)
+KERNEL_TEX(KernelLight, __lights)
 KERNEL_TEX(float2, __light_background_marginal_cdf)
 KERNEL_TEX(float2, __light_background_conditional_cdf)
 
 /* particles */
-KERNEL_TEX(float4, __particles)
+KERNEL_TEX(KernelParticle, __particles)
 
 /* shaders */
 KERNEL_TEX(uint4, __svm_nodes)
-KERNEL_TEX(uint, __shader_flag)
-KERNEL_TEX(uint, __object_flag)
+KERNEL_TEX(KernelShader, __shaders)
 
 /* lookup tables */
 KERNEL_TEX(float, __lookup_table)
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index 9df13804ea4ae745bed2c9100775ac92d3c397c1..64fef8aa41893e6de82225570d91c30ae3880ed4 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -40,14 +40,10 @@
 CCL_NAMESPACE_BEGIN
 
 /* Constants */
-#define OBJECT_SIZE 		16
-#define OBJECT_VECTOR_SIZE	6
-#define LIGHT_SIZE		11
-#define FILTER_TABLE_SIZE	1024
-#define RAMP_TABLE_SIZE		256
-#define SHUTTER_TABLE_SIZE		256
-#define PARTICLE_SIZE 		5
-#define SHADER_SIZE		5
+#define OBJECT_MOTION_PASS_SIZE 2
+#define FILTER_TABLE_SIZE       1024
+#define RAMP_TABLE_SIZE         256
+#define SHUTTER_TABLE_SIZE      256
 
 #define BSSRDF_MIN_RADIUS			1e-8f
 #define BSSRDF_MAX_HITS				4
@@ -275,6 +271,7 @@ typedef enum ShaderEvalType {
 	/* data passes */
 	SHADER_EVAL_NORMAL,
 	SHADER_EVAL_UV,
+	SHADER_EVAL_ROUGHNESS,
 	SHADER_EVAL_DIFFUSE_COLOR,
 	SHADER_EVAL_GLOSSY_COLOR,
 	SHADER_EVAL_TRANSMISSION_COLOR,
@@ -936,7 +933,7 @@ enum ShaderDataFlag {
 	SD_HAS_BUMP               = (1 << 25),
 	/* Has true displacement. */
 	SD_HAS_DISPLACEMENT       = (1 << 26),
-	/* Has constant emission (value stored in __shader_flag) */
+	/* Has constant emission (value stored in __shaders) */
 	SD_HAS_CONSTANT_EMISSION  = (1 << 27),
 	/* Needs to access attributes */
 	SD_NEED_ATTRIBUTES        = (1 << 28),
@@ -1174,7 +1171,7 @@ typedef struct KernelCamera {
 
 	/* matrices */
 	Transform cameratoworld;
-	Transform rastertocamera;
+	ProjectionTransform rastertocamera;
 
 	/* differentials */
 	float4 dx;
@@ -1188,7 +1185,7 @@ typedef struct KernelCamera {
 
 	/* motion blur */
 	float shuttertime;
-	int have_motion, have_perspective_motion;
+	int num_motion_steps, have_perspective_motion;
 
 	/* clipping */
 	float nearclip;
@@ -1208,22 +1205,22 @@ typedef struct KernelCamera {
 	int is_inside_volume;
 
 	/* more matrices */
-	Transform screentoworld;
-	Transform rastertoworld;
-	/* work around cuda sm 2.0 crash, this seems to
-	 * cross some limit in combination with motion 
-	 * Transform ndctoworld; */
-	Transform worldtoscreen;
-	Transform worldtoraster;
-	Transform worldtondc;
+	ProjectionTransform screentoworld;
+	ProjectionTransform rastertoworld;
+	ProjectionTransform ndctoworld;
+	ProjectionTransform worldtoscreen;
+	ProjectionTransform worldtoraster;
+	ProjectionTransform worldtondc;
 	Transform worldtocamera;
 
-	MotionTransform motion;
+	/* Stores changes in the projeciton matrix. Use for camera zoom motion
+	 * blur and motion pass output for perspective camera. */
+	ProjectionTransform perspective_pre;
+	ProjectionTransform perspective_post;
 
-	/* Denotes changes in the projective matrix, namely in rastertocamera.
-	 * Used for camera zoom motion blur,
-	 */
-	PerspectiveMotionTransform perspective_motion;
+	/* Transforms for motion pass. */
+	Transform motion_pass_pre;
+	Transform motion_pass_post;
 
 	int shutter_table_offset;
 
@@ -1452,6 +1449,110 @@ typedef struct KernelData {
 } KernelData;
 static_assert_align(KernelData, 16);
 
+/* Kernel data structures. */
+
+typedef struct KernelObject {
+	Transform tfm;
+	Transform itfm;
+
+	float surface_area;
+	float pass_id;
+	float random_number;
+	int particle_index;
+
+	float dupli_generated[3];
+	float dupli_uv[2];
+
+	int numkeys;
+	int numsteps;
+	int numverts;
+
+	uint patch_map_offset;
+	uint attribute_map_offset;
+	uint motion_offset;
+	uint pad;
+} KernelObject;;
+static_assert_align(KernelObject, 16);
+
+typedef struct KernelSpotLight {
+	float radius;
+	float invarea;
+	float spot_angle;
+	float spot_smooth;
+	float dir[3];
+} KernelSpotLight;
+
+/* PointLight is SpotLight with only radius and invarea being used. */
+
+typedef struct KernelAreaLight {
+	float axisu[3];
+	float invarea;
+	float axisv[3];
+	float dir[3];
+} KernelAreaLight;
+
+typedef struct KernelDistantLight {
+	float radius;
+	float cosangle;
+	float invarea;
+} KernelDistantLight;
+
+typedef struct KernelLight {
+	int type;
+	float co[3];
+	int shader_id;
+	int samples;
+	float max_bounces;
+	float random;
+	Transform tfm;
+	Transform itfm;
+	union {
+		KernelSpotLight spot;
+		KernelAreaLight area;
+		KernelDistantLight distant;
+	};
+} KernelLight;
+static_assert_align(KernelLight, 16);
+
+typedef struct KernelLightDistribution {
+	float totarea;
+	int prim;
+	union {
+		struct {
+			int shader_flag;
+			int object_id;
+		} mesh_light;
+		struct {
+			float pad;
+			float size;
+		} lamp;
+	};
+} KernelLightDistribution;
+static_assert_align(KernelLightDistribution, 16);
+
+typedef struct KernelParticle {
+	int index;
+	float age;
+	float lifetime;
+	float size;
+	float4 rotation;
+	/* Only xyz are used of the following. float4 instead of float3 are used
+	 * to ensure consistent padding/alignment across devices. */
+	float4 location;
+	float4 velocity;
+	float4 angular_velocity;
+} KernelParticle;
+static_assert_align(KernelParticle, 16);
+
+typedef struct KernelShader {
+	float constant_emission[3];
+	float pad1;
+	int flags;
+	int pass_id;
+	int pad2, pad3;
+} KernelShader;
+static_assert_align(KernelShader, 16);
+
 /* Declarations required for split kernel */
 
 /* Macro for queues */
diff --git a/intern/cycles/kernel/kernel_volume.h b/intern/cycles/kernel/kernel_volume.h
index 058e7dccafdb0251a5f27b4da6b9b1e0bba0566e..88360e5f1ae5afde85cdcd4b4cd8789f1c6e8612 100644
--- a/intern/cycles/kernel/kernel_volume.h
+++ b/intern/cycles/kernel/kernel_volume.h
@@ -104,7 +104,7 @@ ccl_device float kernel_volume_channel_get(float3 value, int channel)
 ccl_device bool volume_stack_is_heterogeneous(KernelGlobals *kg, ccl_addr_space VolumeStack *stack)
 {
 	for(int i = 0; stack[i].shader != SHADER_NONE; i++) {
-		int shader_flag = kernel_tex_fetch(__shader_flag, (stack[i].shader & SHADER_MASK)*SHADER_SIZE);
+		int shader_flag = kernel_tex_fetch(__shaders, (stack[i].shader & SHADER_MASK)).flags;
 
 		if(shader_flag & SD_HETEROGENEOUS_VOLUME) {
 			return true;
@@ -134,7 +134,7 @@ ccl_device int volume_stack_sampling_method(KernelGlobals *kg, VolumeStack *stac
 	int method = -1;
 
 	for(int i = 0; stack[i].shader != SHADER_NONE; i++) {
-		int shader_flag = kernel_tex_fetch(__shader_flag, (stack[i].shader & SHADER_MASK)*SHADER_SIZE);
+		int shader_flag = kernel_tex_fetch(__shaders, (stack[i].shader & SHADER_MASK)).flags;
 
 		if(shader_flag & SD_VOLUME_MIS) {
 			return SD_VOLUME_MIS;
diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp
index ae4c521659c7c17c781e79d67fe79f16a436a843..0c5e5e30e479168a3fc366fe9c4033a12f088451 100644
--- a/intern/cycles/kernel/osl/osl_services.cpp
+++ b/intern/cycles/kernel/osl/osl_services.cpp
@@ -62,11 +62,17 @@ CCL_NAMESPACE_BEGIN
 
 /* RenderServices implementation */
 
-#define COPY_MATRIX44(m1, m2)  { \
-	CHECK_TYPE(m1, OSL::Matrix44*); \
-	CHECK_TYPE(m2, Transform*); \
-	memcpy(m1, m2, sizeof(*m2)); \
-} (void)0
+static void copy_matrix(OSL::Matrix44& m, const Transform& tfm)
+{
+	ProjectionTransform t = projection_transpose(ProjectionTransform(tfm));
+	memcpy(&m, &t, sizeof(m));
+}
+
+static void copy_matrix(OSL::Matrix44& m, const ProjectionTransform& tfm)
+{
+	ProjectionTransform t = projection_transpose(tfm);
+	memcpy(&m, &t, sizeof(m));
+}
 
 /* static ustrings */
 ustring OSLRenderServices::u_distance("distance");
@@ -167,14 +173,12 @@ bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44 &result
 #else
 			Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
 #endif
-			tfm = transform_transpose(tfm);
-			COPY_MATRIX44(&result, &tfm);
+			copy_matrix(result, tfm);
 
 			return true;
 		}
 		else if(sd->type == PRIMITIVE_LAMP) {
-			Transform tfm = transform_transpose(sd->ob_tfm);
-			COPY_MATRIX44(&result, &tfm);
+			copy_matrix(result, sd->ob_tfm);
 
 			return true;
 		}
@@ -203,14 +207,12 @@ bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44
 #else
 			Transform itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
 #endif
-			itfm = transform_transpose(itfm);
-			COPY_MATRIX44(&result, &itfm);
+			copy_matrix(result, itfm);
 
 			return true;
 		}
 		else if(sd->type == PRIMITIVE_LAMP) {
-			Transform tfm = transform_transpose(sd->ob_itfm);
-			COPY_MATRIX44(&result, &tfm);
+			copy_matrix(result, sd->ob_itfm);
 
 			return true;
 		}
@@ -224,23 +226,19 @@ bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44 &result
 	KernelGlobals *kg = kernel_globals;
 
 	if(from == u_ndc) {
-		Transform tfm = transform_transpose(transform_quick_inverse(kernel_data.cam.worldtondc));
-		COPY_MATRIX44(&result, &tfm);
+		copy_matrix(result, kernel_data.cam.ndctoworld);
 		return true;
 	}
 	else if(from == u_raster) {
-		Transform tfm = transform_transpose(kernel_data.cam.rastertoworld);
-		COPY_MATRIX44(&result, &tfm);
+		copy_matrix(result, kernel_data.cam.rastertoworld);
 		return true;
 	}
 	else if(from == u_screen) {
-		Transform tfm = transform_transpose(kernel_data.cam.screentoworld);
-		COPY_MATRIX44(&result, &tfm);
+		copy_matrix(result, kernel_data.cam.screentoworld);
 		return true;
 	}
 	else if(from == u_camera) {
-		Transform tfm = transform_transpose(kernel_data.cam.cameratoworld);
-		COPY_MATRIX44(&result, &tfm);
+		copy_matrix(result, kernel_data.cam.cameratoworld);
 		return true;
 	}
 	else if(from == u_world) {
@@ -256,23 +254,19 @@ bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44
 	KernelGlobals *kg = kernel_globals;
 
 	if(to == u_ndc) {
-		Transform tfm = transform_transpose(kernel_data.cam.worldtondc);
-		COPY_MATRIX44(&result, &tfm);
+		copy_matrix(result, kernel_data.cam.worldtondc);
 		return true;
 	}
 	else if(to == u_raster) {
-		Transform tfm = transform_transpose(kernel_data.cam.worldtoraster);
-		COPY_MATRIX44(&result, &tfm);
+		copy_matrix(result, kernel_data.cam.worldtoraster);
 		return true;
 	}
 	else if(to == u_screen) {
-		Transform tfm = transform_transpose(kernel_data.cam.worldtoscreen);
-		COPY_MATRIX44(&result, &tfm);
+		copy_matrix(result, kernel_data.cam.worldtoscreen);
 		return true;
 	}
 	else if(to == u_camera) {
-		Transform tfm = transform_transpose(kernel_data.cam.worldtocamera);
-		COPY_MATRIX44(&result, &tfm);
+		copy_matrix(result, kernel_data.cam.worldtocamera);
 		return true;
 	}
 	else if(to == u_world) {
@@ -298,14 +292,12 @@ bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44 &result
 			KernelGlobals *kg = sd->osl_globals;
 			Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
 #endif
-			tfm = transform_transpose(tfm);
-			COPY_MATRIX44(&result, &tfm);
+			copy_matrix(result, tfm);
 
 			return true;
 		}
 		else if(sd->type == PRIMITIVE_LAMP) {
-			Transform tfm = transform_transpose(sd->ob_tfm);
-			COPY_MATRIX44(&result, &tfm);
+			copy_matrix(result, sd->ob_tfm);
 
 			return true;
 		}
@@ -329,14 +321,12 @@ bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44
 			KernelGlobals *kg = sd->osl_globals;
 			Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
 #endif
-			tfm = transform_transpose(tfm);
-			COPY_MATRIX44(&result, &tfm);
+			copy_matrix(result, tfm);
 
 			return true;
 		}
 		else if(sd->type == PRIMITIVE_LAMP) {
-			Transform tfm = transform_transpose(sd->ob_itfm);
-			COPY_MATRIX44(&result, &tfm);
+			copy_matrix(result, sd->ob_itfm);
 
 			return true;
 		}
@@ -350,23 +340,19 @@ bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44 &result
 	KernelGlobals *kg = kernel_globals;
 
 	if(from == u_ndc) {
-		Transform tfm = transform_transpose(transform_quick_inverse(kernel_data.cam.worldtondc));
-		COPY_MATRIX44(&result, &tfm);
+		copy_matrix(result, kernel_data.cam.ndctoworld);
 		return true;
 	}
 	else if(from == u_raster) {
-		Transform tfm = transform_transpose(kernel_data.cam.rastertoworld);
-		COPY_MATRIX44(&result, &tfm);
+		copy_matrix(result, kernel_data.cam.rastertoworld);
 		return true;
 	}
 	else if(from == u_screen) {
-		Transform tfm = transform_transpose(kernel_data.cam.screentoworld);
-		COPY_MATRIX44(&result, &tfm);
+		copy_matrix(result, kernel_data.cam.screentoworld);
 		return true;
 	}
 	else if(from == u_camera) {
-		Transform tfm = transform_transpose(kernel_data.cam.cameratoworld);
-		COPY_MATRIX44(&result, &tfm);
+		copy_matrix(result, kernel_data.cam.cameratoworld);
 		return true;
 	}
 
@@ -378,23 +364,19 @@ bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44
 	KernelGlobals *kg = kernel_globals;
 	
 	if(to == u_ndc) {
-		Transform tfm = transform_transpose(kernel_data.cam.worldtondc);
-		COPY_MATRIX44(&result, &tfm);
+		copy_matrix(result, kernel_data.cam.worldtondc);
 		return true;
 	}
 	else if(to == u_raster) {
-		Transform tfm = transform_transpose(kernel_data.cam.worldtoraster);
-		COPY_MATRIX44(&result, &tfm);
+		copy_matrix(result, kernel_data.cam.worldtoraster);
 		return true;
 	}
 	else if(to == u_screen) {
-		Transform tfm = transform_transpose(kernel_data.cam.worldtoscreen);
-		COPY_MATRIX44(&result, &tfm);
+		copy_matrix(result, kernel_data.cam.worldtoscreen);
 		return true;
 	}
 	else if(to == u_camera) {
-		Transform tfm = transform_transpose(kernel_data.cam.worldtocamera);
-		COPY_MATRIX44(&result, &tfm);
+		copy_matrix(result, kernel_data.cam.worldtocamera);
 		return true;
 	}
 	
@@ -570,8 +552,7 @@ static bool set_attribute_float3_3(float3 P[3], TypeDesc type, bool derivatives,
 static bool set_attribute_matrix(const Transform& tfm, TypeDesc type, void *val)
 {
 	if(type == TypeDesc::TypeMatrix) {
-		Transform transpose = transform_transpose(tfm);
-		memcpy(val, &transpose, sizeof(Transform));
+		copy_matrix(*(OSL::Matrix44*)val, tfm);
 		return true;
 	}
 
diff --git a/intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl b/intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl
index bef6d7e8809216f2dc2f1b62e2d6b93a37a2fc21..21e28ece65dca10128a1143cf25840492586a699 100644
--- a/intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl
+++ b/intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl
@@ -33,27 +33,28 @@ shader node_anisotropic_bsdf(
 		T = rotate(T, Rotation * M_2PI, point(0.0, 0.0, 0.0), Normal);
 
 	/* compute roughness */
-	float RoughnessU, RoughnessV;
+	float roughness = Roughness * Roughness;
+	float roughness_u, roughness_v;
 	float aniso = clamp(Anisotropy, -0.99, 0.99);
 
 	if (aniso < 0.0) {
-		RoughnessU = Roughness / (1.0 + aniso);
-		RoughnessV = Roughness * (1.0 + aniso);
+		roughness_u = roughness / (1.0 + aniso);
+		roughness_v = roughness * (1.0 + aniso);
 	}
 	else {
-		RoughnessU = Roughness * (1.0 - aniso);
-		RoughnessV = Roughness / (1.0 - aniso);
+		roughness_u = roughness * (1.0 - aniso);
+		roughness_v = roughness / (1.0 - aniso);
 	}
 
 	if (distribution == "sharp")
 		BSDF = Color * reflection(Normal);
 	else if (distribution == "beckmann")
-		BSDF = Color * microfacet_beckmann_aniso(Normal, T, RoughnessU, RoughnessV);
+		BSDF = Color * microfacet_beckmann_aniso(Normal, T, roughness_u, roughness_v);
 	else if (distribution == "GGX")
-		BSDF = Color * microfacet_ggx_aniso(Normal, T, RoughnessU, RoughnessV);
+		BSDF = Color * microfacet_ggx_aniso(Normal, T, roughness_u, roughness_v);
 	else if (distribution == "Multiscatter GGX")
-		BSDF = Color * microfacet_multi_ggx_aniso(Normal, T, RoughnessU, RoughnessV, Color);
+		BSDF = Color * microfacet_multi_ggx_aniso(Normal, T, roughness_u, roughness_v, Color);
 	else
-		BSDF = Color * ashikhmin_shirley(Normal, T, RoughnessU, RoughnessV);
+		BSDF = Color * ashikhmin_shirley(Normal, T, roughness_u, roughness_v);
 }
 
diff --git a/intern/cycles/kernel/shaders/node_glass_bsdf.osl b/intern/cycles/kernel/shaders/node_glass_bsdf.osl
index a9723a8300a02cb185aa5bc82c9f5ceab06ccd17..2e713861c58dfb25fe372886052b00218115c074 100644
--- a/intern/cycles/kernel/shaders/node_glass_bsdf.osl
+++ b/intern/cycles/kernel/shaders/node_glass_bsdf.osl
@@ -29,16 +29,17 @@ shader node_glass_bsdf(
 	float eta = backfacing() ? 1.0 / f : f;
 	float cosi = dot(I, Normal);
 	float Fr = fresnel_dielectric_cos(cosi, eta);
+	float roughness = Roughness * Roughness;
 
 	if (distribution == "sharp")
 		BSDF = Color * (Fr * reflection(Normal) + (1.0 - Fr) * refraction(Normal, eta));
 	else if (distribution == "beckmann")
-		BSDF = Color * (Fr * microfacet_beckmann(Normal, Roughness) +
-		                (1.0 - Fr) * microfacet_beckmann_refraction(Normal, Roughness, eta));
+		BSDF = Color * (Fr * microfacet_beckmann(Normal, roughness) +
+		                (1.0 - Fr) * microfacet_beckmann_refraction(Normal, roughness, eta));
 	else if (distribution == "Multiscatter GGX")
-		BSDF = Color * microfacet_multi_ggx_glass(Normal, Roughness, eta, Color);
+		BSDF = Color * microfacet_multi_ggx_glass(Normal, roughness, eta, Color);
 	else if (distribution == "GGX")
-		BSDF = Color * (Fr * microfacet_ggx(Normal, Roughness) +
-		                (1.0 - Fr) * microfacet_ggx_refraction(Normal, Roughness, eta));
+		BSDF = Color * (Fr * microfacet_ggx(Normal, roughness) +
+		                (1.0 - Fr) * microfacet_ggx_refraction(Normal, roughness, eta));
 }
 
diff --git a/intern/cycles/kernel/shaders/node_glossy_bsdf.osl b/intern/cycles/kernel/shaders/node_glossy_bsdf.osl
index f4ea7e7dc6a39f2a3d60e38f5c6c8cc266634af1..7415211b56d7ecb326c5cdded89b6085ae09f810 100644
--- a/intern/cycles/kernel/shaders/node_glossy_bsdf.osl
+++ b/intern/cycles/kernel/shaders/node_glossy_bsdf.osl
@@ -24,16 +24,18 @@ shader node_glossy_bsdf(
 	normal Normal = N,
 	output closure color BSDF = 0)
 {
+	float roughness = Roughness * Roughness;
+
 	if (distribution == "sharp")
 		BSDF = Color * reflection(Normal);
 	else if (distribution == "beckmann")
-		BSDF = Color * microfacet_beckmann(Normal, Roughness);
+		BSDF = Color * microfacet_beckmann(Normal, roughness);
 	else if (distribution == "GGX")
-		BSDF = Color * microfacet_ggx(Normal, Roughness);
+		BSDF = Color * microfacet_ggx(Normal, roughness);
 	else if (distribution == "Multiscatter GGX")
-		BSDF = Color * microfacet_multi_ggx(Normal, Roughness, Color);
+		BSDF = Color * microfacet_multi_ggx(Normal, roughness, Color);
 	else
-		BSDF = Color * ashikhmin_shirley(Normal, vector(0, 0, 0), Roughness, Roughness);
+		BSDF = Color * ashikhmin_shirley(Normal, vector(0, 0, 0), roughness, roughness);
 
 }
 
diff --git a/intern/cycles/kernel/shaders/node_refraction_bsdf.osl b/intern/cycles/kernel/shaders/node_refraction_bsdf.osl
index 828becf18181aba8fc85c7460cc45f03a21a8461..eaab728224383d1cc0d81e19722638507d70ada7 100644
--- a/intern/cycles/kernel/shaders/node_refraction_bsdf.osl
+++ b/intern/cycles/kernel/shaders/node_refraction_bsdf.osl
@@ -26,12 +26,13 @@ shader node_refraction_bsdf(
 {
 	float f = max(IOR, 1e-5);
 	float eta = backfacing() ? 1.0 / f : f;
+	float roughness = Roughness * Roughness;
 
 	if (distribution == "sharp")
 		BSDF = Color * refraction(Normal, eta);
 	else if (distribution == "beckmann")
-		BSDF = Color * microfacet_beckmann_refraction(Normal, Roughness, eta);
+		BSDF = Color * microfacet_beckmann_refraction(Normal, roughness, eta);
 	else if (distribution == "GGX")
-		BSDF = Color * microfacet_ggx_refraction(Normal, Roughness, eta);
+		BSDF = Color * microfacet_ggx_refraction(Normal, roughness, eta);
 }
 
diff --git a/intern/cycles/kernel/svm/svm_closure.h b/intern/cycles/kernel/svm/svm_closure.h
index a54095ed127f0b3909fbf998eeb232664db25a6b..886a1333fa34087d2c114878226eceec13ca0ccf 100644
--- a/intern/cycles/kernel/svm/svm_closure.h
+++ b/intern/cycles/kernel/svm/svm_closure.h
@@ -468,10 +468,12 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
 				break;
 			}
 
+			float roughness = sqr(param1);
+
 			bsdf->N = N;
 			bsdf->T = make_float3(0.0f, 0.0f, 0.0f);
-			bsdf->alpha_x = param1;
-			bsdf->alpha_y = param1;
+			bsdf->alpha_x = roughness;
+			bsdf->alpha_y = roughness;
 			bsdf->ior = 0.0f;
 			bsdf->extra = NULL;
 
@@ -525,8 +527,9 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
 					sd->flag |= bsdf_refraction_setup(bsdf);
 				}
 				else {
-					bsdf->alpha_x = param1;
-					bsdf->alpha_y = param1;
+					float roughness = sqr(param1);
+					bsdf->alpha_x = roughness;
+					bsdf->alpha_y = roughness;
 					bsdf->ior = eta;
 
 					if(type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID)
@@ -557,7 +560,7 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
 			/* fresnel */
 			float cosNO = dot(N, sd->I);
 			float fresnel = fresnel_dielectric_cos(cosNO, eta);
-			float roughness = param1;
+			float roughness = sqr(param1);
 
 			/* reflection */
 #ifdef __CAUSTICS_TRICKS__
@@ -611,8 +614,9 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
 			bsdf->extra = extra;
 			bsdf->T = make_float3(0.0f, 0.0f, 0.0f);
 
-			bsdf->alpha_x = param1;
-			bsdf->alpha_y = param1;
+			float roughness = sqr(param1);
+			bsdf->alpha_x = roughness;
+			bsdf->alpha_y = roughness;
 			float eta = fmaxf(param2, 1e-5f);
 			bsdf->ior = (sd->flag & SD_BACKFACING)? 1.0f/eta: eta;
 
@@ -648,7 +652,7 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
 					bsdf->T = rotate_around_axis(bsdf->T, bsdf->N, rotation * M_2PI_F);
 
 				/* compute roughness */
-				float roughness = param1;
+				float roughness = sqr(param1);
 				float anisotropy = clamp(param2, -0.99f, 0.99f);
 
 				if(anisotropy < 0.0f) {
diff --git a/intern/cycles/kernel/svm/svm_mapping.h b/intern/cycles/kernel/svm/svm_mapping.h
index 0a890545af45db3286e1cf9b7d4d6c1ba5638d93..42a7ae9946f401b967fc9b6f3c421d8dfab86a24 100644
--- a/intern/cycles/kernel/svm/svm_mapping.h
+++ b/intern/cycles/kernel/svm/svm_mapping.h
@@ -26,7 +26,6 @@ ccl_device void svm_node_mapping(KernelGlobals *kg, ShaderData *sd, float *stack
 	tfm.x = read_node_float(kg, offset);
 	tfm.y = read_node_float(kg, offset);
 	tfm.z = read_node_float(kg, offset);
-	tfm.w = read_node_float(kg, offset);
 
 	float3 r = transform_point(&tfm, v);
 	stack_store_float3(stack, out_offset, r);
diff --git a/intern/cycles/kernel/svm/svm_tex_coord.h b/intern/cycles/kernel/svm/svm_tex_coord.h
index c94327401f52c8a65d64819874c79c2cfa54ae5a..6ff39e5f587ad23151a8972c4c58564d7fdc5144 100644
--- a/intern/cycles/kernel/svm/svm_tex_coord.h
+++ b/intern/cycles/kernel/svm/svm_tex_coord.h
@@ -42,7 +42,6 @@ ccl_device void svm_node_tex_coord(KernelGlobals *kg,
 				tfm.x = read_node_float(kg, offset);
 				tfm.y = read_node_float(kg, offset);
 				tfm.z = read_node_float(kg, offset);
-				tfm.w = read_node_float(kg, offset);
 				data = transform_point(&tfm, data);
 			}
 			break;
@@ -123,7 +122,6 @@ ccl_device void svm_node_tex_coord_bump_dx(KernelGlobals *kg,
 				tfm.x = read_node_float(kg, offset);
 				tfm.y = read_node_float(kg, offset);
 				tfm.z = read_node_float(kg, offset);
-				tfm.w = read_node_float(kg, offset);
 				data = transform_point(&tfm, data);
 			}
 			break;
@@ -207,7 +205,6 @@ ccl_device void svm_node_tex_coord_bump_dy(KernelGlobals *kg,
 				tfm.x = read_node_float(kg, offset);
 				tfm.y = read_node_float(kg, offset);
 				tfm.z = read_node_float(kg, offset);
-				tfm.w = read_node_float(kg, offset);
 				data = transform_point(&tfm, data);
 			}
 			break;
diff --git a/intern/cycles/kernel/svm/svm_voxel.h b/intern/cycles/kernel/svm/svm_voxel.h
index d967516a5c9b4546e494173a87f60ccff0b81e89..43b433683e06d7c07dca12317730de2e423cc3de 100644
--- a/intern/cycles/kernel/svm/svm_voxel.h
+++ b/intern/cycles/kernel/svm/svm_voxel.h
@@ -39,7 +39,6 @@ ccl_device void svm_node_tex_voxel(KernelGlobals *kg,
 		tfm.x = read_node_float(kg, offset);
 		tfm.y = read_node_float(kg, offset);
 		tfm.z = read_node_float(kg, offset);
-		tfm.w = read_node_float(kg, offset);
 		co = transform_point(&tfm, co);
 	}
 
diff --git a/intern/cycles/render/bake.cpp b/intern/cycles/render/bake.cpp
index 1fef7a0188fb982f28e0022568a0659caeef727f..927e04abc7f4d9c5298c0e5ffa7efc1dd0507e5e 100644
--- a/intern/cycles/render/bake.cpp
+++ b/intern/cycles/render/bake.cpp
@@ -247,7 +247,7 @@ void BakeManager::device_free(Device * /*device*/, DeviceScene * /*dscene*/)
 
 int BakeManager::aa_samples(Scene *scene, BakeData *bake_data, ShaderEvalType type)
 {
-	if(type == SHADER_EVAL_UV) {
+	if(type == SHADER_EVAL_UV || type == SHADER_EVAL_ROUGHNESS) {
 		return 1;
 	}
 	else if(type == SHADER_EVAL_NORMAL) {
diff --git a/intern/cycles/render/buffers.cpp b/intern/cycles/render/buffers.cpp
index 84d10cc477ee4ff23a7b8e54df3fa29fc0608b9a..6f560380b40325bd3537aab4551586280e1e7ff2 100644
--- a/intern/cycles/render/buffers.cpp
+++ b/intern/cycles/render/buffers.cpp
@@ -21,7 +21,6 @@
 
 #include "util/util_foreach.h"
 #include "util/util_hash.h"
-#include "util/util_image.h"
 #include "util/util_math.h"
 #include "util/util_opengl.h"
 #include "util/util_time.h"
@@ -448,37 +447,5 @@ bool DisplayBuffer::draw_ready()
 	return (draw_width != 0 && draw_height != 0);
 }
 
-void DisplayBuffer::write(const string& filename)
-{
-	int w = draw_width;
-	int h = draw_height;
-
-	if(w == 0 || h == 0)
-		return;
-	
-	if(half_float)
-		return;
-
-	/* read buffer from device */
-	uchar4 *pixels = rgba_byte.copy_from_device(0, w, h);
-
-	/* write image */
-	ImageOutput *out = ImageOutput::create(filename);
-	ImageSpec spec(w, h, 4, TypeDesc::UINT8);
-
-	out->open(filename, spec);
-
-	/* conversion for different top/bottom convention */
-	out->write_image(TypeDesc::UINT8,
-		(uchar*)(pixels + (h-1)*w),
-		AutoStride,
-		-w*sizeof(uchar4),
-		AutoStride);
-
-	out->close();
-
-	delete out;
-}
-
 CCL_NAMESPACE_END
 
diff --git a/intern/cycles/render/buffers.h b/intern/cycles/render/buffers.h
index 028bfb83735d549062449de8e21f5bf2f768d055..dfc98fe20619e40707a7d89a58728d284819c928 100644
--- a/intern/cycles/render/buffers.h
+++ b/intern/cycles/render/buffers.h
@@ -113,7 +113,6 @@ public:
 	~DisplayBuffer();
 
 	void reset(BufferParams& params);
-	void write(const string& filename);
 
 	void draw_set(int width, int height);
 	void draw(Device *device, const DeviceDrawParams& draw_params);
diff --git a/intern/cycles/render/camera.cpp b/intern/cycles/render/camera.cpp
index a2fda12ec8506c500cbe35b811bab306bea9d299..38936ffc094f35e72ea3be9eb0f672e54db2c080 100644
--- a/intern/cycles/render/camera.cpp
+++ b/intern/cycles/render/camera.cpp
@@ -82,6 +82,7 @@ NODE_DEFINE(Camera)
 	SOCKET_FLOAT(bladesrotation, "Blades Rotation", 0.0f);
 
 	SOCKET_TRANSFORM(matrix, "Matrix", transform_identity());
+	SOCKET_TRANSFORM_ARRAY(motion, "Motion", array<Transform>());
 
 	SOCKET_FLOAT(aperture_ratio, "Aperture Ratio", 1.0f);
 
@@ -151,9 +152,6 @@ Camera::Camera()
 	height = 512;
 	resolution = 1;
 
-	motion.pre = transform_identity();
-	motion.post = transform_identity();
-	use_motion = false;
 	use_perspective_motion = false;
 
 	shutter_curve.resize(RAMP_TABLE_SIZE);
@@ -163,12 +161,12 @@ Camera::Camera()
 
 	compute_auto_viewplane();
 
-	screentoworld = transform_identity();
-	rastertoworld = transform_identity();
-	ndctoworld = transform_identity();
-	rastertocamera = transform_identity();
+	screentoworld = projection_identity();
+	rastertoworld = projection_identity();
+	ndctoworld = projection_identity();
+	rastertocamera = projection_identity();
 	cameratoworld = transform_identity();
-	worldtoraster = transform_identity();
+	worldtoraster = projection_identity();
 
 	dx = make_float3(0.0f, 0.0f, 0.0f);
 	dy = make_float3(0.0f, 0.0f, 0.0f);
@@ -241,18 +239,18 @@ void Camera::update(Scene *scene)
 	Transform full_rastertoscreen = transform_inverse(full_screentoraster);
 
 	/* screen to camera */
-	Transform cameratoscreen;
+	ProjectionTransform cameratoscreen;
 	if(type == CAMERA_PERSPECTIVE)
-		cameratoscreen = transform_perspective(fov, nearclip, farclip);
+		cameratoscreen = projection_perspective(fov, nearclip, farclip);
 	else if(type == CAMERA_ORTHOGRAPHIC)
-		cameratoscreen = transform_orthographic(nearclip, farclip);
+		cameratoscreen = projection_orthographic(nearclip, farclip);
 	else
-		cameratoscreen = transform_identity();
+		cameratoscreen = projection_identity();
 	
-	Transform screentocamera = transform_inverse(cameratoscreen);
+	ProjectionTransform screentocamera = projection_inverse(cameratoscreen);
 
 	rastertocamera = screentocamera * rastertoscreen;
-	Transform full_rastertocamera = screentocamera * full_rastertoscreen;
+	ProjectionTransform full_rastertocamera = screentocamera * full_rastertoscreen;
 	cameratoraster = screentoraster * cameratoscreen;
 
 	cameratoworld = matrix;
@@ -270,10 +268,10 @@ void Camera::update(Scene *scene)
 
 	/* differentials */
 	if(type == CAMERA_ORTHOGRAPHIC) {
-		dx = transform_direction(&rastertocamera, make_float3(1, 0, 0));
-		dy = transform_direction(&rastertocamera, make_float3(0, 1, 0));
-		full_dx = transform_direction(&full_rastertocamera, make_float3(1, 0, 0));
-		full_dy = transform_direction(&full_rastertocamera, make_float3(0, 1, 0));
+		dx = transform_perspective_direction(&rastertocamera, make_float3(1, 0, 0));
+		dy = transform_perspective_direction(&rastertocamera, make_float3(0, 1, 0));
+		full_dx = transform_perspective_direction(&full_rastertocamera, make_float3(1, 0, 0));
+		full_dy = transform_perspective_direction(&full_rastertocamera, make_float3(0, 1, 0));
 	}
 	else if(type == CAMERA_PERSPECTIVE) {
 		dx = transform_perspective(&rastertocamera, make_float3(1, 0, 0)) -
@@ -302,23 +300,6 @@ void Camera::update(Scene *scene)
 		frustum_top_normal = normalize(make_float3(0.0f, v.z, -v.y));
 	}
 
-	/* TODO(sergey): Support other types of camera. */
-	if(type == CAMERA_PERSPECTIVE) {
-		/* TODO(sergey): Move to an utility function and de-duplicate with
-		 * calculation above.
-		 */
-		Transform screentocamera_pre =
-		        transform_inverse(transform_perspective(fov_pre,
-		                                                nearclip,
-		                                                farclip));
-		Transform screentocamera_post =
-		        transform_inverse(transform_perspective(fov_post,
-		                                                nearclip,
-		                                                farclip));
-		perspective_motion.pre = screentocamera_pre * rastertoscreen;
-		perspective_motion.post = screentocamera_post * rastertoscreen;
-	}
-
 	/* Compute kernel camera data. */
 	KernelCamera *kcam = &kernel_camera;
 
@@ -331,41 +312,65 @@ void Camera::update(Scene *scene)
 	kcam->worldtoscreen = worldtoscreen;
 	kcam->worldtoraster = worldtoraster;
 	kcam->worldtondc = worldtondc;
+	kcam->ndctoworld = ndctoworld;
 
 	/* camera motion */
-	kcam->have_motion = 0;
+	kcam->num_motion_steps = 0;
 	kcam->have_perspective_motion = 0;
+	kernel_camera_motion.clear();
+
+	/* Test if any of the transforms are actually different. */
+	bool have_motion = false;
+	for(size_t i = 0; i < motion.size(); i++) {
+		have_motion = have_motion || motion[i] != matrix;
+	}
 
 	if(need_motion == Scene::MOTION_PASS) {
 		/* TODO(sergey): Support perspective (zoom, fov) motion. */
 		if(type == CAMERA_PANORAMA) {
-			if(use_motion) {
-				kcam->motion.pre = transform_inverse(motion.pre);
-				kcam->motion.post = transform_inverse(motion.post);
+			if(have_motion) {
+				kcam->motion_pass_pre = transform_inverse(motion[0]);
+				kcam->motion_pass_post = transform_inverse(motion[motion.size()-1]);
 			}
 			else {
-				kcam->motion.pre = kcam->worldtocamera;
-				kcam->motion.post = kcam->worldtocamera;
+				kcam->motion_pass_pre = kcam->worldtocamera;
+				kcam->motion_pass_post = kcam->worldtocamera;
 			}
 		}
 		else {
-			if(use_motion) {
-				kcam->motion.pre = cameratoraster * transform_inverse(motion.pre);
-				kcam->motion.post = cameratoraster * transform_inverse(motion.post);
+			if(have_motion) {
+				kcam->perspective_pre = cameratoraster * transform_inverse(motion[0]);
+				kcam->perspective_post = cameratoraster * transform_inverse(motion[motion.size()-1]);
 			}
 			else {
-				kcam->motion.pre = worldtoraster;
-				kcam->motion.post = worldtoraster;
+				kcam->perspective_pre = worldtoraster;
+				kcam->perspective_post = worldtoraster;
 			}
 		}
 	}
 	else if(need_motion == Scene::MOTION_BLUR) {
-		if(use_motion) {
-			transform_motion_decompose(&kcam->motion, &motion, &matrix);
-			kcam->have_motion = 1;
+		if(have_motion) {
+			kernel_camera_motion.resize(motion.size());
+			transform_motion_decompose(kernel_camera_motion.data(), motion.data(), motion.size());
+			kcam->num_motion_steps = motion.size();
 		}
-		if(use_perspective_motion) {
-			kcam->perspective_motion = perspective_motion;
+
+		/* TODO(sergey): Support other types of camera. */
+		if(use_perspective_motion && type == CAMERA_PERSPECTIVE) {
+			/* TODO(sergey): Move to an utility function and de-duplicate with
+			 * calculation above.
+			 */
+			ProjectionTransform screentocamera_pre =
+					projection_inverse(projection_perspective(fov_pre,
+					                                          nearclip,
+					                                          farclip));
+			ProjectionTransform screentocamera_post =
+					projection_inverse(projection_perspective(fov_post,
+					                                          nearclip,
+					                                          farclip));
+
+			kcam->perspective_pre = screentocamera_pre * rastertoscreen;
+			kcam->perspective_post = screentocamera_post * rastertoscreen;
 			kcam->have_perspective_motion = 1;
 		}
 	}
@@ -470,6 +475,16 @@ void Camera::device_update(Device * /* device */,
 	}
 
 	dscene->data.cam = kernel_camera;
+
+	size_t num_motion_steps = kernel_camera_motion.size();
+	if(num_motion_steps) {
+		DecomposedTransform *camera_motion = dscene->camera_motion.alloc(num_motion_steps);
+		memcpy(camera_motion, kernel_camera_motion.data(), sizeof(*camera_motion) * num_motion_steps);
+		dscene->camera_motion.copy_to_device();
+	}
+	else {
+		dscene->camera_motion.free();
+	}
 }
 
 void Camera::device_update_volume(Device * /*device*/,
@@ -496,10 +511,11 @@ void Camera::device_update_volume(Device * /*device*/,
 }
 
 void Camera::device_free(Device * /*device*/,
-                         DeviceScene * /*dscene*/,
+                         DeviceScene *dscene,
                          Scene *scene)
 {
 	scene->lookup_tables->remove_table(&shutter_table_offset);
+	dscene->camera_motion.free();
 }
 
 bool Camera::modified(const Camera& cam)
@@ -510,7 +526,6 @@ bool Camera::modified(const Camera& cam)
 bool Camera::motion_modified(const Camera& cam)
 {
 	return !((motion == cam.motion) &&
-	         (use_motion == cam.use_motion) &&
 	         (use_perspective_motion == cam.use_perspective_motion));
 }
 
@@ -606,7 +621,7 @@ float Camera::world_to_raster_size(float3 P)
 		res = min(len(full_dx), len(full_dy));
 
 		if(offscreen_dicing_scale > 1.0f) {
-			float3 p = transform_perspective(&worldtocamera, P);
+			float3 p = transform_point(&worldtocamera, P);
 			float3 v = transform_perspective(&rastertocamera, make_float3(width, height, 0.0f));
 
 			/* Create point clamped to frustum */
@@ -707,17 +722,17 @@ float Camera::world_to_raster_size(float3 P)
 		 * may be a better way to do this, but calculating differentials from the
 		 * point directly ahead seems to produce good enough results. */
 #if 0
-		float2 dir = direction_to_panorama(&kernel_camera, normalize(D));
+		float2 dir = direction_to_panorama(&kernel_camera, kernel_camera_motion.data(), normalize(D));
 		float3 raster = transform_perspective(&cameratoraster, make_float3(dir.x, dir.y, 0.0f));
 
 		ray.t = 1.0f;
-		camera_sample_panorama(&kernel_camera, raster.x, raster.y, 0.0f, 0.0f, &ray);
+		camera_sample_panorama(&kernel_camera, kernel_camera_motion.data(), raster.x, raster.y, 0.0f, 0.0f, &ray);
 		if(ray.t == 0.0f) {
 			/* No differentials, just use from directly ahead. */
-			camera_sample_panorama(&kernel_camera, 0.5f*width, 0.5f*height, 0.0f, 0.0f, &ray);
+			camera_sample_panorama(&kernel_camera, kernel_camera_motion.data(), 0.5f*width, 0.5f*height, 0.0f, 0.0f, &ray);
 		}
 #else
-		camera_sample_panorama(&kernel_camera, 0.5f*width, 0.5f*height, 0.0f, 0.0f, &ray);
+		camera_sample_panorama(&kernel_camera, kernel_camera_motion.data(), 0.5f*width, 0.5f*height, 0.0f, 0.0f, &ray);
 #endif
 
 		differential_transfer(&ray.dP, ray.dP, ray.D, ray.dD, ray.D, dist);
@@ -729,4 +744,27 @@ float Camera::world_to_raster_size(float3 P)
 	return res;
 }
 
+bool Camera::use_motion() const
+{
+	return motion.size() > 1;
+}
+
+float Camera::motion_time(int step) const
+{
+	return (use_motion()) ? 2.0f * step / (motion.size() - 1) - 1.0f : 0.0f;
+}
+
+int Camera::motion_step(float time) const
+{
+	if(use_motion()) {
+		for(int step = 0; step < motion.size(); step++) {
+			if(time == motion_time(step)) {
+				return step;
+			}
+		}
+	}
+
+	return -1;
+}
+
 CCL_NAMESPACE_END
diff --git a/intern/cycles/render/camera.h b/intern/cycles/render/camera.h
index 4ec0fe3bc6ebfd74deffd2e1f999bc38f5d9ce6e..37d05c01bd935ccde1428da529bec86220b4615e 100644
--- a/intern/cycles/render/camera.h
+++ b/intern/cycles/render/camera.h
@@ -22,6 +22,7 @@
 #include "graph/node.h"
 
 #include "util/util_boundbox.h"
+#include "util/util_projection.h"
 #include "util/util_transform.h"
 #include "util/util_types.h"
 
@@ -140,24 +141,23 @@ public:
 	Transform matrix;
 
 	/* motion */
-	MotionTransform motion;
-	bool use_motion, use_perspective_motion;
+	array<Transform> motion;
+	bool use_perspective_motion;
 	float fov_pre, fov_post;
-	PerspectiveMotionTransform perspective_motion;
 
 	/* computed camera parameters */
-	Transform screentoworld;
-	Transform rastertoworld;
-	Transform ndctoworld;
+	ProjectionTransform screentoworld;
+	ProjectionTransform rastertoworld;
+	ProjectionTransform ndctoworld;
 	Transform cameratoworld;
 
-	Transform worldtoraster;
-	Transform worldtoscreen;
-	Transform worldtondc;
+	ProjectionTransform worldtoraster;
+	ProjectionTransform worldtoscreen;
+	ProjectionTransform worldtondc;
 	Transform worldtocamera;
 
-	Transform rastertocamera;
-	Transform cameratoraster;
+	ProjectionTransform rastertocamera;
+	ProjectionTransform cameratoraster;
 
 	float3 dx;
 	float3 dy;
@@ -176,6 +176,7 @@ public:
 
 	/* Kernel camera data, copied here for dicing. */
 	KernelCamera kernel_camera;
+	array<DecomposedTransform> kernel_camera_motion;
 
 	/* functions */
 	Camera();
@@ -199,6 +200,11 @@ public:
 	/* Calculates the width of a pixel at point in world space. */
 	float world_to_raster_size(float3 P);
 
+	/* Motion blur. */
+	float motion_time(int step) const;
+	int motion_step(float time) const;
+	bool use_motion() const;
+
 private:
 	/* Private utility functions. */
 	float3 transform_raster_to_world(float raster_x, float raster_y);
diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp
index b62453cf5fc9a0241bd00a9c11559adeccfed747..8dec7e4ea643b78f28aefd5907a6fcb35e1b538e 100644
--- a/intern/cycles/render/light.cpp
+++ b/intern/cycles/render/light.cpp
@@ -288,7 +288,7 @@ void LightManager::device_update_distribution(Device *, DeviceScene *dscene, Sce
 	VLOG(1) << "Total " << num_distribution << " of light distribution primitives.";
 
 	/* emission area */
-	float4 *distribution = dscene->light_distribution.alloc(num_distribution + 1);
+	KernelLightDistribution *distribution = dscene->light_distribution.alloc(num_distribution + 1);
 	float totarea = 0.0f;
 
 	/* triangles */
@@ -334,10 +334,10 @@ void LightManager::device_update_distribution(Device *, DeviceScene *dscene, Sce
 			                         : scene->default_surface;
 
 			if(shader->use_mis && shader->has_surface_emission) {
-				distribution[offset].x = totarea;
-				distribution[offset].y = __int_as_float(i + mesh->tri_offset);
-				distribution[offset].z = __int_as_float(shader_flag);
-				distribution[offset].w = __int_as_float(object_id);
+				distribution[offset].totarea = totarea;
+				distribution[offset].prim = i + mesh->tri_offset;
+				distribution[offset].mesh_light.shader_flag = shader_flag;
+				distribution[offset].mesh_light.object_id = object_id;
 				offset++;
 
 				Mesh::Triangle t = mesh->get_triangle(i);
@@ -372,10 +372,10 @@ void LightManager::device_update_distribution(Device *, DeviceScene *dscene, Sce
 		if(!light->is_enabled)
 			continue;
 
-		distribution[offset].x = totarea;
-		distribution[offset].y = __int_as_float(~light_index);
-		distribution[offset].z = 1.0f;
-		distribution[offset].w = light->size;
+		distribution[offset].totarea = totarea;
+		distribution[offset].prim = ~light_index;
+		distribution[offset].lamp.pad = 1.0f;
+		distribution[offset].lamp.size = light->size;
 		totarea += lightarea;
 
 		if(light->size > 0.0f && light->use_mis)
@@ -390,15 +390,15 @@ void LightManager::device_update_distribution(Device *, DeviceScene *dscene, Sce
 	}
 
 	/* normalize cumulative distribution functions */
-	distribution[num_distribution].x = totarea;
-	distribution[num_distribution].y = 0.0f;
-	distribution[num_distribution].z = 0.0f;
-	distribution[num_distribution].w = 0.0f;
+	distribution[num_distribution].totarea = totarea;
+	distribution[num_distribution].prim = 0.0f;
+	distribution[num_distribution].lamp.pad = 0.0f;
+	distribution[num_distribution].lamp.size = 0.0f;
 
 	if(totarea > 0.0f) {
 		for(size_t i = 0; i < num_distribution; i++)
-			distribution[i].x /= totarea;
-		distribution[num_distribution].x = 1.0f;
+			distribution[i].totarea /= totarea;
+		distribution[num_distribution].totarea = 1.0f;
 	}
 
 	if(progress.get_cancel()) return;
@@ -620,7 +620,7 @@ void LightManager::device_update_points(Device *,
 		}
 	}
 
-	float4 *light_data = dscene->light_data.alloc(num_lights*LIGHT_SIZE);
+	KernelLight *klights = dscene->lights.alloc(num_lights);
 
 	if(num_lights == 0) {
 		VLOG(1) << "No effective light, ignoring points update.";
@@ -637,8 +637,8 @@ void LightManager::device_update_points(Device *,
 		float3 co = light->co;
 		Shader *shader = (light->shader) ? light->shader : scene->default_light;
 		int shader_id = scene->shader_manager->get_shader_id(shader);
-		float samples = __int_as_float(light->samples);
-		float max_bounces = __int_as_float(light->max_bounces);
+		int samples = light->samples;
+		int max_bounces = light->max_bounces;
 		float random = (float)light->random_id * (1.0f/(float)0xFFFFFFFF);
 
 		if(!light->cast_shadow)
@@ -661,6 +661,9 @@ void LightManager::device_update_points(Device *,
 			use_light_visibility = true;
 		}
 
+		klights[light_index].type = light->type;
+		klights[light_index].samples = samples;
+
 		if(light->type == LIGHT_POINT) {
 			shader_id &= ~SHADER_AREA_LIGHT;
 
@@ -670,10 +673,12 @@ void LightManager::device_update_points(Device *,
 			if(light->use_mis && radius > 0.0f)
 				shader_id |= SHADER_USE_MIS;
 
-			light_data[light_index*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
-			light_data[light_index*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, invarea, 0.0f);
-			light_data[light_index*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
-			light_data[light_index*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
+			klights[light_index].co[0] = co.x;
+			klights[light_index].co[1] = co.y;
+			klights[light_index].co[2] = co.z;
+
+			klights[light_index].spot.radius = radius;
+			klights[light_index].spot.invarea = invarea;
 		}
 		else if(light->type == LIGHT_DISTANT) {
 			shader_id &= ~SHADER_AREA_LIGHT;
@@ -690,10 +695,13 @@ void LightManager::device_update_points(Device *,
 			if(light->use_mis && area > 0.0f)
 				shader_id |= SHADER_USE_MIS;
 
-			light_data[light_index*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), dir.x, dir.y, dir.z);
-			light_data[light_index*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, cosangle, invarea);
-			light_data[light_index*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
-			light_data[light_index*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
+			klights[light_index].co[0] = dir.x;
+			klights[light_index].co[1] = dir.y;
+			klights[light_index].co[2] = dir.z;
+
+			klights[light_index].distant.invarea = invarea;
+			klights[light_index].distant.radius = radius;
+			klights[light_index].distant.cosangle = cosangle;
 		}
 		else if(light->type == LIGHT_BACKGROUND) {
 			uint visibility = scene->background->visibility;
@@ -717,11 +725,6 @@ void LightManager::device_update_points(Device *,
 				shader_id |= SHADER_EXCLUDE_SCATTER;
 				use_light_visibility = true;
 			}
-
-			light_data[light_index*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), 0.0f, 0.0f, 0.0f);
-			light_data[light_index*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), 0.0f, 0.0f, 0.0f);
-			light_data[light_index*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
-			light_data[light_index*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
 		}
 		else if(light->type == LIGHT_AREA) {
 			float3 axisu = light->axisu*(light->sizeu*light->size);
@@ -735,10 +738,20 @@ void LightManager::device_update_points(Device *,
 			if(light->use_mis && area > 0.0f)
 				shader_id |= SHADER_USE_MIS;
 
-			light_data[light_index*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
-			light_data[light_index*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), axisu.x, axisu.y, axisu.z);
-			light_data[light_index*LIGHT_SIZE + 2] = make_float4(invarea, axisv.x, axisv.y, axisv.z);
-			light_data[light_index*LIGHT_SIZE + 3] = make_float4(samples, dir.x, dir.y, dir.z);
+			klights[light_index].co[0] = co.x;
+			klights[light_index].co[1] = co.y;
+			klights[light_index].co[2] = co.z;
+
+			klights[light_index].area.axisu[0] = axisu.x;
+			klights[light_index].area.axisu[1] = axisu.y;
+			klights[light_index].area.axisu[2] = axisu.z;
+			klights[light_index].area.axisv[0] = axisv.x;
+			klights[light_index].area.axisv[1] = axisv.y;
+			klights[light_index].area.axisv[2] = axisv.z;
+			klights[light_index].area.invarea = invarea;
+			klights[light_index].area.dir[0] = dir.x;
+			klights[light_index].area.dir[1] = dir.y;
+			klights[light_index].area.dir[2] = dir.z;
 		}
 		else if(light->type == LIGHT_SPOT) {
 			shader_id &= ~SHADER_AREA_LIGHT;
@@ -754,18 +767,26 @@ void LightManager::device_update_points(Device *,
 			if(light->use_mis && radius > 0.0f)
 				shader_id |= SHADER_USE_MIS;
 
-			light_data[light_index*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
-			light_data[light_index*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, invarea, spot_angle);
-			light_data[light_index*LIGHT_SIZE + 2] = make_float4(spot_smooth, dir.x, dir.y, dir.z);
-			light_data[light_index*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
+			klights[light_index].co[0] = co.x;
+			klights[light_index].co[1] = co.y;
+			klights[light_index].co[2] = co.z;
+
+			klights[light_index].spot.radius = radius;
+			klights[light_index].spot.invarea = invarea;
+			klights[light_index].spot.spot_angle = spot_angle;
+			klights[light_index].spot.spot_smooth = spot_smooth;
+			klights[light_index].spot.dir[0] = dir.x;
+			klights[light_index].spot.dir[1] = dir.y;
+			klights[light_index].spot.dir[2] = dir.z;
 		}
 
-		light_data[light_index*LIGHT_SIZE + 4] = make_float4(max_bounces, random, 0.0f, 0.0f);
+		klights[light_index].shader_id = shader_id;
+
+		klights[light_index].max_bounces = max_bounces;
+		klights[light_index].random = random;
 
-		Transform tfm = light->tfm;
-		Transform itfm = transform_inverse(tfm);
-		memcpy(&light_data[light_index*LIGHT_SIZE + 5], &tfm, sizeof(float4)*3);
-		memcpy(&light_data[light_index*LIGHT_SIZE + 8], &itfm, sizeof(float4)*3);
+		klights[light_index].tfm = light->tfm;
+		klights[light_index].itfm = transform_inverse(light->tfm);
 
 		light_index++;
 	}
@@ -782,21 +803,27 @@ void LightManager::device_update_points(Device *,
 		float3 axisu = light->axisu*(light->sizeu*light->size);
 		float3 axisv = light->axisv*(light->sizev*light->size);
 		float area = len(axisu)*len(axisv);
-		float invarea = (area > 0.0f) ? 1.0f / area : 1.0f;
+		float invarea = (area > 0.0f)? 1.0f/area: 1.0f;
 		float3 dir = light->dir;
 
 		dir = safe_normalize(dir);
 
-		light_data[light_index*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
-		light_data[light_index*LIGHT_SIZE + 1] = make_float4(area, axisu.x, axisu.y, axisu.z);
-		light_data[light_index*LIGHT_SIZE + 2] = make_float4(invarea, axisv.x, axisv.y, axisv.z);
-		light_data[light_index*LIGHT_SIZE + 3] = make_float4(-1, dir.x, dir.y, dir.z);
-		light_data[light_index*LIGHT_SIZE + 4] = make_float4(-1, 0.0f, 0.0f, 0.0f);
-
-		Transform tfm = light->tfm;
-		Transform itfm = transform_inverse(tfm);
-		memcpy(&light_data[light_index*LIGHT_SIZE + 5], &tfm, sizeof(float4)*3);
-		memcpy(&light_data[light_index*LIGHT_SIZE + 8], &itfm, sizeof(float4)*3);
+		klights[light_index].co[0] = co.x;
+		klights[light_index].co[1] = co.y;
+		klights[light_index].co[2] = co.z;
+
+		klights[light_index].area.axisu[0] = axisu.x;
+		klights[light_index].area.axisu[1] = axisu.y;
+		klights[light_index].area.axisu[2] = axisu.z;
+		klights[light_index].area.axisv[0] = axisv.x;
+		klights[light_index].area.axisv[1] = axisv.y;
+		klights[light_index].area.axisv[2] = axisv.z;
+		klights[light_index].area.invarea = invarea;
+		klights[light_index].area.dir[0] = dir.x;
+		klights[light_index].area.dir[1] = dir.y;
+		klights[light_index].area.dir[2] = dir.z;
+		klights[light_index].tfm = light->tfm;
+		klights[light_index].itfm = transform_inverse(light->tfm);
 
 		light_index++;
 	}
@@ -806,7 +833,7 @@ void LightManager::device_update_points(Device *,
 	VLOG(1) << "Number of lights without contribution: "
 	        << num_scene_lights - light_index;
 
-	dscene->light_data.copy_to_device();
+	dscene->lights.copy_to_device();
 }
 
 void LightManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
@@ -842,7 +869,7 @@ void LightManager::device_update(Device *device, DeviceScene *dscene, Scene *sce
 void LightManager::device_free(Device *, DeviceScene *dscene)
 {
 	dscene->light_distribution.free();
-	dscene->light_data.free();
+	dscene->lights.free();
 	dscene->light_background_marginal_cdf.free();
 	dscene->light_background_conditional_cdf.free();
 }
diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp
index 87bff1fbfb1bdce4405ec59aa9d112e98cc5d43e..1f33cef7c57028a7de76f0eb6f4cfb0ba19039a9 100644
--- a/intern/cycles/render/mesh.cpp
+++ b/intern/cycles/render/mesh.cpp
@@ -884,15 +884,8 @@ void Mesh::add_undisplaced()
 	}
 }
 
-void Mesh::pack_normals(Scene *scene, uint *tri_shader, float4 *vnormal)
+void Mesh::pack_shaders(Scene *scene, uint *tri_shader)
 {
-	Attribute *attr_vN = attributes.find(ATTR_STD_VERTEX_NORMAL);
-	if(attr_vN == NULL) {
-		/* Happens on objects with just hair. */
-		return;
-	}
-
-	float3 *vN = attr_vN->data_float3();
 	uint shader_id = 0;
 	uint last_shader = -1;
 	bool last_smooth = false;
@@ -900,10 +893,6 @@ void Mesh::pack_normals(Scene *scene, uint *tri_shader, float4 *vnormal)
 	size_t triangles_size = num_triangles();
 	int *shader_ptr = shader.data();
 
-	bool do_transform = transform_applied;
-	Transform ntfm = transform_normal;
-
-	/* save shader */
 	for(size_t i = 0; i < triangles_size; i++) {
 		if(shader_ptr[i] != last_shader || last_smooth != smooth[i]) {
 			last_shader = shader_ptr[i];
@@ -915,7 +904,20 @@ void Mesh::pack_normals(Scene *scene, uint *tri_shader, float4 *vnormal)
 
 		tri_shader[i] = shader_id;
 	}
+}
+
+void Mesh::pack_normals(float4 *vnormal)
+{
+	Attribute *attr_vN = attributes.find(ATTR_STD_VERTEX_NORMAL);
+	if(attr_vN == NULL) {
+		/* Happens on objects with just hair. */
+		return;
+	}
+
+	bool do_transform = transform_applied;
+	Transform ntfm = transform_normal;
 
+	float3 *vN = attr_vN->data_float3();
 	size_t verts_size = verts.size();
 
 	for(size_t i = 0; i < verts_size; i++) {
@@ -1129,6 +1131,32 @@ bool Mesh::has_true_displacement() const
 	return false;
 }
 
+float Mesh::motion_time(int step) const
+{
+	return (motion_steps > 1) ? 2.0f * step / (motion_steps - 1) - 1.0f : 0.0f;
+}
+
+int Mesh::motion_step(float time) const
+{
+	if(motion_steps > 1) {
+		int attr_step = 0;
+
+		for(int step = 0; step < motion_steps; step++) {
+			float step_time = motion_time(step);
+			if(step_time == time) {
+				return attr_step;
+			}
+
+			/* Center step is stored in a separate attribute. */
+			if(step != motion_steps / 2) {
+				attr_step++;
+			}
+		}
+	}
+
+	return -1;
+}
+
 bool Mesh::need_build_bvh() const
 {
 	return !transform_applied || has_surface_bssrdf;
@@ -1148,14 +1176,12 @@ bool Mesh::is_instanced() const
 
 MeshManager::MeshManager()
 {
-	bvh = NULL;
 	need_update = true;
 	need_flags_update = true;
 }
 
 MeshManager::~MeshManager()
 {
-	delete bvh;
 }
 
 void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<AttributeRequestSet>& mesh_attributes)
@@ -1459,11 +1485,11 @@ static void update_attribute_element_offset(Mesh *mesh,
 			Transform *tfm = mattr->data_transform();
 			offset = attr_float3_offset;
 
-			assert(attr_float3.size() >= offset + size * 4);
-			for(size_t k = 0; k < size*4; k++) {
+			assert(attr_float3.size() >= offset + size * 3);
+			for(size_t k = 0; k < size*3; k++) {
 				attr_float3[offset+k] = (&tfm->x)[k];
 			}
-			attr_float3_offset += size * 4;
+			attr_float3_offset += size * 3;
 		}
 		else {
 			float4 *data = mattr->data_float4();
@@ -1761,9 +1787,9 @@ void MeshManager::device_update_mesh(Device *,
 		float2 *tri_patch_uv = dscene->tri_patch_uv.alloc(vert_size);
 
 		foreach(Mesh *mesh, scene->meshes) {
-			mesh->pack_normals(scene,
-			                   &tri_shader[mesh->tri_offset],
-			                   &vnormal[mesh->vert_offset]);
+			mesh->pack_shaders(scene,
+			                   &tri_shader[mesh->tri_offset]);
+			mesh->pack_normals(&vnormal[mesh->vert_offset]);
 			mesh->pack_verts(tri_prim_index,
 			                 &tri_vindex[mesh->tri_offset],
 			                 &tri_patch[mesh->tri_offset],
@@ -1861,11 +1887,8 @@ void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene *
 	}
 #endif
 
-        if (bvh != NULL)
-            delete bvh;
-        
-	bvh = BVH::create(bparams, scene->objects);
-	bvh->build(progress);
+	BVH *bvh = BVH::create(bparams, scene->objects);
+	bvh->build(progress, &device->stats);
 
 	if(progress.get_cancel()) {
 #ifdef WITH_EMBREE
@@ -1938,6 +1961,8 @@ void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene *
 		dscene->data.bvh.scene = NULL;
 	}
 #endif
+
+	delete bvh;
 }
 
 void MeshManager::device_update_preprocess(Device *device,
@@ -2074,7 +2099,9 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
 
 	VLOG(1) << "Total " << scene->meshes.size() << " meshes.";
 
-	/* Update normals. */
+	bool true_displacement_used = false;
+	size_t total_tess_needed = 0;
+
 	foreach(Mesh *mesh, scene->meshes) {
 		foreach(Shader *shader, mesh->used_shaders) {
 			if(shader->need_update_mesh)
@@ -2082,6 +2109,7 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
 		}
 
 		if(mesh->need_update) {
+			/* Update normals. */
 			mesh->add_face_normals();
 			mesh->add_vertex_normals();
 
@@ -2089,57 +2117,53 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
 				mesh->add_undisplaced();
 			}
 
+			/* Test if we need tesselation. */
+			if(mesh->subdivision_type != Mesh::SUBDIVISION_NONE &&
+			   mesh->num_subd_verts == 0 &&
+			   mesh->subd_params)
+			{
+				total_tess_needed++;
+			}
+
+			/* Test if we need displacement. */
+			if(mesh->has_true_displacement()) {
+				true_displacement_used = true;
+			}
+
 			if(progress.get_cancel()) return;
 		}
 	}
 
 	/* Tessellate meshes that are using subdivision */
-	size_t total_tess_needed = 0;
-	foreach(Mesh *mesh, scene->meshes) {
-		if(mesh->need_update &&
-		   mesh->subdivision_type != Mesh::SUBDIVISION_NONE &&
-		   mesh->num_subd_verts == 0 &&
-		   mesh->subd_params)
-		{
-			total_tess_needed++;
-		}
-	}
+	if(total_tess_needed) {
+		size_t i = 0;
+		foreach(Mesh *mesh, scene->meshes) {
+			if(mesh->need_update &&
+			   mesh->subdivision_type != Mesh::SUBDIVISION_NONE &&
+			   mesh->num_subd_verts == 0 &&
+			   mesh->subd_params)
+			{
+				string msg = "Tessellating ";
+				if(mesh->name == "")
+					msg += string_printf("%u/%u", (uint)(i+1), (uint)total_tess_needed);
+				else
+					msg += string_printf("%s %u/%u", mesh->name.c_str(), (uint)(i+1), (uint)total_tess_needed);
 
-	size_t i = 0;
-	foreach(Mesh *mesh, scene->meshes) {
-		if(mesh->need_update &&
-		   mesh->subdivision_type != Mesh::SUBDIVISION_NONE &&
-		   mesh->num_subd_verts == 0 &&
-		   mesh->subd_params)
-		{
-			string msg = "Tessellating ";
-			if(mesh->name == "")
-				msg += string_printf("%u/%u", (uint)(i+1), (uint)total_tess_needed);
-			else
-				msg += string_printf("%s %u/%u", mesh->name.c_str(), (uint)(i+1), (uint)total_tess_needed);
+				progress.set_status("Updating Mesh", msg);
 
-			progress.set_status("Updating Mesh", msg);
+				DiagSplit dsplit(*mesh->subd_params);
+				mesh->tessellate(&dsplit);
 
-			DiagSplit dsplit(*mesh->subd_params);
-			mesh->tessellate(&dsplit);
+				i++;
 
-			i++;
+				if(progress.get_cancel()) return;
+			}
 
-			if(progress.get_cancel()) return;
 		}
 	}
 
 	/* Update images needed for true displacement. */
-	bool true_displacement_used = false;
 	bool old_need_object_flags_update = false;
-	foreach(Mesh *mesh, scene->meshes) {
-		if(mesh->need_update &&
-		   mesh->has_true_displacement())
-		{
-			true_displacement_used = true;
-			break;
-		}
-	}
 	if(true_displacement_used) {
 		VLOG(1) << "Updating images used for true displacement.";
 		device_update_displacement_images(device, scene, progress);
@@ -2165,11 +2189,17 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
 
 	/* Update displacement. */
 	bool displacement_done = false;
+	size_t num_bvh = 0;
+
 	foreach(Mesh *mesh, scene->meshes) {
-		if(mesh->need_update &&
-		   displace(device, dscene, scene, mesh, progress))
-		{
-			displacement_done = true;
+		if(mesh->need_update) {
+			if(displace(device, dscene, scene, mesh, progress)) {
+				displacement_done = true;
+			}
+
+			if(mesh->need_build_bvh()) {
+				num_bvh++;
+			}
 		}
 	}
 
@@ -2184,17 +2214,9 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
 		if(progress.get_cancel()) return;
 	}
 
-	/* Update bvh. */
-	size_t num_bvh = 0;
-	foreach(Mesh *mesh, scene->meshes) {
-		if(mesh->need_update && mesh->need_build_bvh()) {
-			num_bvh++;
-		}
-	}
-
 	TaskPool pool;
 
-	i = 0;
+	size_t i = 0;
 	foreach(Mesh *mesh, scene->meshes) {
 		if(mesh->need_update) {
 			pool.push(function_bind(&Mesh::compute_bvh,
diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h
index 62cda1c19b7ec2341b10d86839484fbd3623a451..f3cf78fec4f0321473473afdd5eb5d938692f26d 100644
--- a/intern/cycles/render/mesh.h
+++ b/intern/cycles/render/mesh.h
@@ -279,7 +279,8 @@ public:
 	void add_vertex_normals();
 	void add_undisplaced();
 
-	void pack_normals(Scene *scene, uint *shader, float4 *vnormal);
+	void pack_shaders(Scene *scene, uint *shader);
+	void pack_normals(float4 *vnormal);
 	void pack_verts(const vector<uint>& tri_prim_index,
 	                uint4 *tri_vindex,
 	                uint *tri_patch,
@@ -304,6 +305,11 @@ public:
 	bool has_motion_blur() const;
 	bool has_true_displacement() const;
 
+	/* Convert between normalized -1..1 motion time and index
+	 * in the VERTEX_MOTION attribute. */
+	float motion_time(int step) const;
+	int motion_step(float time) const;
+
 	/* Check whether the mesh should have own BVH built separately. Briefly,
 	 * own BVH is needed for mesh, if:
 	 *
diff --git a/intern/cycles/render/mesh_volume.cpp b/intern/cycles/render/mesh_volume.cpp
index f2347c7961094d331555bca7ce9f2b49f3c3b231..3571beb40d66df53b44e52f7e30d07b5f9d543ea 100644
--- a/intern/cycles/render/mesh_volume.cpp
+++ b/intern/cycles/render/mesh_volume.cpp
@@ -152,22 +152,22 @@ public:
 	void add_node_with_padding(int x, int y, int z);
 
 	void create_mesh(vector<float3> &vertices,
-					 vector<int> &indices,
-					 vector<float3> &face_normals);
+	                 vector<int> &indices,
+	                 vector<float3> &face_normals);
 
 private:
 	void generate_vertices_and_quads(vector<int3> &vertices_is,
-									 vector<QuadData> &quads);
+	                                 vector<QuadData> &quads);
 
 	void deduplicate_vertices(vector<int3> &vertices,
-							  vector<QuadData> &quads);
+	                          vector<QuadData> &quads);
 
 	void convert_object_space(const vector<int3> &vertices,
-							  vector<float3> &out_vertices);
+	                          vector<float3> &out_vertices);
 
 	void convert_quads_to_tris(const vector<QuadData> &quads,
-							   vector<int> &tris,
-							   vector<float3> &face_normals);
+	                           vector<int> &tris,
+	                           vector<float3> &face_normals);
 };
 
 VolumeMeshBuilder::VolumeMeshBuilder(VolumeParams *volume_params)
@@ -224,8 +224,8 @@ void VolumeMeshBuilder::add_node_with_padding(int x, int y, int z)
 }
 
 void VolumeMeshBuilder::create_mesh(vector<float3> &vertices,
-									vector<int> &indices,
-									vector<float3> &face_normals)
+                                    vector<int> &indices,
+                                    vector<float3> &face_normals)
 {
 	/* We create vertices in index space (is), and only convert them to object
 	 * space when done. */
@@ -260,8 +260,8 @@ void VolumeMeshBuilder::generate_vertices_and_quads(
 
 				/* Compute min and max coords of the node in index space. */
 				int3 min = make_int3((x - pad_offset.x)*CUBE_SIZE,
-									 (y - pad_offset.y)*CUBE_SIZE,
-									 (z - pad_offset.z)*CUBE_SIZE);
+				                     (y - pad_offset.y)*CUBE_SIZE,
+				                     (z - pad_offset.z)*CUBE_SIZE);
 
 				/* Maximum is just CUBE_SIZE voxels away from minimum on each axis. */
 				int3 max = make_int3(min.x + CUBE_SIZE, min.y + CUBE_SIZE, min.z + CUBE_SIZE);
@@ -316,7 +316,7 @@ void VolumeMeshBuilder::generate_vertices_and_quads(
 }
 
 void VolumeMeshBuilder::deduplicate_vertices(vector<int3> &vertices,
-											 vector<QuadData> &quads)
+                                             vector<QuadData> &quads)
 {
 	vector<int3> sorted_vertices = vertices;
 	std::sort(sorted_vertices.begin(), sorted_vertices.end());
@@ -355,7 +355,7 @@ void VolumeMeshBuilder::deduplicate_vertices(vector<int3> &vertices,
 }
 
 void VolumeMeshBuilder::convert_object_space(const vector<int3> &vertices,
-											 vector<float3> &out_vertices)
+	                                         vector<float3> &out_vertices)
 {
 	out_vertices.reserve(vertices.size());
 
@@ -369,8 +369,8 @@ void VolumeMeshBuilder::convert_object_space(const vector<int3> &vertices,
 }
 
 void VolumeMeshBuilder::convert_quads_to_tris(const vector<QuadData> &quads,
-											  vector<int> &tris,
-											  vector<float3> &face_normals)
+                                              vector<int> &tris,
+                                              vector<float3> &face_normals)
 {
 	int index_offset = 0;
 	tris.resize(quads.size()*6);
@@ -399,8 +399,8 @@ struct VoxelAttributeGrid {
 };
 
 void MeshManager::create_volume_mesh(Scene *scene,
-									 Mesh *mesh,
-									 Progress& progress)
+                                     Mesh *mesh,
+                                     Progress& progress)
 {
 	string msg = string_printf("Computing Volume Mesh %s", mesh->name.c_str());
 	progress.set_status("Updating Mesh", msg);
@@ -470,8 +470,8 @@ void MeshManager::create_volume_mesh(Scene *scene,
 	const int3 resolution = volume_params.resolution;
 	float3 start_point = make_float3(0.0f, 0.0f, 0.0f);
 	float3 cell_size = make_float3(1.0f/resolution.x,
-								   1.0f/resolution.y,
-								   1.0f/resolution.z);
+	                               1.0f/resolution.y,
+	                               1.0f/resolution.z);
 
 	if(attr) {
 		const Transform *tfm = attr->data_transform();
@@ -575,12 +575,12 @@ void MeshManager::create_volume_mesh(Scene *scene,
 
 	/* Print stats. */
 	VLOG(1) << "Memory usage volume mesh: "
-			<< ((vertices.size() + face_normals.size())*sizeof(float3) + indices.size()*sizeof(int))/(1024.0*1024.0)
-			<< "Mb.";
+	        << ((vertices.size() + face_normals.size())*sizeof(float3) + indices.size()*sizeof(int))/(1024.0*1024.0)
+	        << "Mb.";
 
 	VLOG(1) << "Memory usage volume grid: "
-			<< (resolution.x*resolution.y*resolution.z*sizeof(float))/(1024.0*1024.0)
-			<< "Mb.";
+	        << (resolution.x*resolution.y*resolution.z*sizeof(float))/(1024.0*1024.0)
+	        << "Mb.";
 }
 
 CCL_NAMESPACE_END
diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp
index 41c9730e6fb18092fe5dabebdebcd330020ce7ab..d732189af664a721d6991302c2d0dc12bbb8fb51 100644
--- a/intern/cycles/render/nodes.cpp
+++ b/intern/cycles/render/nodes.cpp
@@ -117,8 +117,7 @@ Transform TextureMapping::compute_transform()
 		case NORMAL:
 			/* no translation for normals, and inverse transpose */
 			mat = rmat*smat;
-			mat = transform_inverse(mat);
-			mat = transform_transpose(mat);
+			mat = transform_transposed_inverse(mat);
 			break;
 	}
 
@@ -153,7 +152,6 @@ void TextureMapping::compile(SVMCompiler& compiler, int offset_in, int offset_ou
 	compiler.add_node(tfm.x);
 	compiler.add_node(tfm.y);
 	compiler.add_node(tfm.z);
-	compiler.add_node(tfm.w);
 
 	if(use_minmax) {
 		compiler.add_node(NODE_MIN_MAX, offset_out, offset_out);
@@ -193,9 +191,7 @@ void TextureMapping::compile_end(SVMCompiler& compiler, ShaderInput *vector_in,
 void TextureMapping::compile(OSLCompiler &compiler)
 {
 	if(!skip()) {
-		Transform tfm = transform_transpose(compute_transform());
-
-		compiler.parameter("mapping", tfm);
+		compiler.parameter("mapping", compute_transform());
 		compiler.parameter("use_mapping", 1);
 	}
 }
@@ -1434,7 +1430,6 @@ void PointDensityTextureNode::compile(SVMCompiler& compiler)
 				compiler.add_node(tfm.x);
 				compiler.add_node(tfm.y);
 				compiler.add_node(tfm.z);
-				compiler.add_node(tfm.w);
 			}
 		}
 		else {
@@ -1478,7 +1473,7 @@ void PointDensityTextureNode::compile(OSLCompiler& compiler)
 			compiler.parameter("filename", string_printf("@%d", slot).c_str());
 		}
 		if(space == NODE_TEX_VOXEL_SPACE_WORLD) {
-			compiler.parameter("mapping", transform_transpose(tfm));
+			compiler.parameter("mapping", tfm);
 			compiler.parameter("use_mapping", 1);
 		}
 		compiler.parameter(this, "interpolation");
@@ -1558,8 +1553,7 @@ void MappingNode::compile(SVMCompiler& compiler)
 
 void MappingNode::compile(OSLCompiler& compiler)
 {
-	Transform tfm = transform_transpose(tex_mapping.compute_transform());
-	compiler.parameter("Matrix", tfm);
+	compiler.parameter("Matrix", tex_mapping.compute_transform());
 	compiler.parameter_point("mapping_min", tex_mapping.min);
 	compiler.parameter_point("mapping_max", tex_mapping.max);
 	compiler.parameter("use_minmax", tex_mapping.use_minmax);
@@ -1864,7 +1858,7 @@ NODE_DEFINE(AnisotropicBsdfNode)
 
 	SOCKET_IN_VECTOR(tangent, "Tangent", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TANGENT);
 
-	SOCKET_IN_FLOAT(roughness, "Roughness", 0.2f);
+	SOCKET_IN_FLOAT(roughness, "Roughness", 0.5f);
 	SOCKET_IN_FLOAT(anisotropy, "Anisotropy", 0.5f);
 	SOCKET_IN_FLOAT(rotation, "Rotation", 0.0f);
 
@@ -1924,7 +1918,7 @@ NODE_DEFINE(GlossyBsdfNode)
 	distribution_enum.insert("ashikhmin_shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID);
 	distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID);
 	SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_ID);
-	SOCKET_IN_FLOAT(roughness, "Roughness", 0.2f);
+	SOCKET_IN_FLOAT(roughness, "Roughness", 0.5f);
 
 	SOCKET_OUT_CLOSURE(BSDF, "BSDF");
 
@@ -3220,7 +3214,6 @@ void TextureCoordinateNode::compile(SVMCompiler& compiler)
 			compiler.add_node(ob_itfm.x);
 			compiler.add_node(ob_itfm.y);
 			compiler.add_node(ob_itfm.z);
-			compiler.add_node(ob_itfm.w);
 		}
 	}
 
@@ -3259,7 +3252,7 @@ void TextureCoordinateNode::compile(OSLCompiler& compiler)
 	if(compiler.output_type() == SHADER_TYPE_VOLUME)
 		compiler.parameter("is_volume", true);
 	compiler.parameter(this, "use_transform");
-	Transform ob_itfm = transform_transpose(transform_inverse(ob_tfm));
+	Transform ob_itfm = transform_transposed_inverse(ob_tfm);
 	compiler.parameter("object_itfm", ob_itfm);
 
 	compiler.parameter(this, "from_dupli");
@@ -5792,6 +5785,15 @@ DisplacementNode::DisplacementNode()
 {
 }
 
+void DisplacementNode::constant_fold(const ConstantFolder& folder)
+{
+	if(folder.all_inputs_constant()) {
+		if((height - midlevel == 0.0f) || (scale == 0.0f)) {
+			folder.make_zero();
+		}
+	}
+}
+
 void DisplacementNode::compile(SVMCompiler& compiler)
 {
 	ShaderInput *height_in = input("Height");
@@ -5843,6 +5845,16 @@ VectorDisplacementNode::VectorDisplacementNode()
 {
 }
 
+void VectorDisplacementNode::constant_fold(const ConstantFolder& folder)
+{
+	if(folder.all_inputs_constant()) {
+		if((vector == make_float3(0.0f, 0.0f, 0.0f) && midlevel == 0.0f) ||
+		   (scale == 0.0f)) {
+			folder.make_zero();
+		}
+	}
+}
+
 void VectorDisplacementNode::attributes(Shader *shader, AttributeRequestSet *attributes)
 {
 	if(shader->has_surface && space == NODE_NORMAL_MAP_TANGENT) {
diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h
index 33df28663416896e375f09b9f6eb60fb354f06ac..58c3d472cd31fb4b264efd6dd9ddab7507bfbb5c 100644
--- a/intern/cycles/render/nodes.h
+++ b/intern/cycles/render/nodes.h
@@ -1063,6 +1063,7 @@ public:
 class DisplacementNode : public ShaderNode {
 public:
 	SHADER_NODE_CLASS(DisplacementNode)
+	void constant_fold(const ConstantFolder& folder);
 	virtual int get_feature() {
 		return NODE_FEATURE_BUMP;
 	}
@@ -1079,6 +1080,7 @@ public:
 	SHADER_NODE_CLASS(VectorDisplacementNode)
 	void attributes(Shader *shader, AttributeRequestSet *attributes);
 	bool has_attribute_dependency() { return true; }
+	void constant_fold(const ConstantFolder& folder);
 	virtual int get_feature() {
 		return NODE_FEATURE_BUMP;
 	}
diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp
index b981d2b88496682f3fc68b3cedfd61dd32f6c8a8..138de250c5f55a39305b3dd89723172ed575a61a 100644
--- a/intern/cycles/render/object.cpp
+++ b/intern/cycles/render/object.cpp
@@ -33,6 +33,52 @@
 
 CCL_NAMESPACE_BEGIN
 
+/* Global state of object transform update. */
+
+struct UpdateObjectTransformState {
+	/* Global state used by device_update_object_transform().
+	 * Common for both threaded and non-threaded update.
+	 */
+
+	/* Type of the motion required by the scene settings. */
+	Scene::MotionType need_motion;
+
+	/* Mapping from particle system to a index in packed particle array.
+	 * Only used for read.
+	 */
+	map<ParticleSystem*, int> particle_offset;
+
+	/* Mesh area.
+	 * Used to avoid calculation of mesh area multiple times. Used for both
+	 * read and write. Acquire surface_area_lock to keep it all thread safe.
+	 */
+	map<Mesh*, float> surface_area_map;
+
+	/* Motion offsets for each object. */
+	array<uint> motion_offset;
+
+	/* Packed object arrays. Those will be filled in. */
+	uint *object_flag;
+	KernelObject *objects;
+	Transform *object_motion_pass;
+	DecomposedTransform *object_motion;
+
+	/* Flags which will be synchronized to Integrator. */
+	bool have_motion;
+	bool have_curves;
+
+	/* ** Scheduling queue. ** */
+
+	Scene *scene;
+
+	/* Some locks to keep everything thread-safe. */
+	thread_spin_lock queue_lock;
+	thread_spin_lock surface_area_lock;
+
+	/* First unused object index in the queue. */
+	int queue_start_object;
+};
+
 /* Object */
 
 NODE_DEFINE(Object)
@@ -48,6 +94,7 @@ NODE_DEFINE(Object)
 	SOCKET_BOOLEAN(hide_on_missing_motion, "Hide on Missing Motion", false);
 	SOCKET_POINT(dupli_generated, "Dupli Generated", make_float3(0.0f, 0.0f, 0.0f));
 	SOCKET_POINT2(dupli_uv, "Dupli UV", make_float2(0.0f, 0.0f));
+	SOCKET_TRANSFORM_ARRAY(motion, "Motion", array<Transform>());
 
 	SOCKET_BOOLEAN(is_shadow_catcher, "Shadow Catcher", false);
 
@@ -60,45 +107,54 @@ Object::Object()
 	particle_system = NULL;
 	particle_index = 0;
 	bounds = BoundBox::empty;
-	motion.pre = transform_empty();
-	motion.mid = transform_empty();
-	motion.post = transform_empty();
-	use_motion = false;
 }
 
 Object::~Object()
 {
 }
 
-void Object::compute_bounds(bool motion_blur)
+void Object::update_motion()
 {
-	BoundBox mbounds = mesh->bounds;
+	if(!use_motion()) {
+		return;
+	}
 
-	if(motion_blur && use_motion) {
-		MotionTransform mtfm = motion;
+	bool have_motion = false;
 
-		if(hide_on_missing_motion) {
-			/* Hide objects that have no valid previous or next transform, for
-			 * example particle that stop existing. TODO: add support for this
-			 * case in the kernel so we don't get render artifacts. */
-			if(mtfm.pre == transform_empty() ||
-			   mtfm.post == transform_empty()) {
-				bounds = BoundBox::empty;
+	for(size_t i = 0; i < motion.size(); i++) {
+		if(motion[i] == transform_empty()) {
+			if(hide_on_missing_motion) {
+				/* Hide objects that have no valid previous or next
+				 * transform, for example particle that stop existing. It
+				 * would be better to handle this in the kernel and make
+				 * objects invisible outside certain motion steps. */
+				tfm = transform_empty();
+				motion.clear();
 				return;
 			}
+			else {
+				/* Otherwise just copy center motion. */
+				motion[i] = tfm;
+			}
 		}
 
-		/* In case of missing motion information for previous/next frame,
-		 * assume there is no motion. */
-		if(mtfm.pre == transform_empty()) {
-			mtfm.pre = tfm;
-		}
-		if(mtfm.post == transform_empty()) {
-			mtfm.post = tfm;
-		}
+		/* Test if any of the transforms are actually different. */
+		have_motion = have_motion || motion[i] != tfm;
+	}
 
-		MotionTransform decomp;
-		transform_motion_decompose(&decomp, &mtfm, &tfm);
+	/* Clear motion array if there is no actual motion. */
+	if(!have_motion) {
+		motion.clear();
+	}
+}
+
+void Object::compute_bounds(bool motion_blur)
+{
+	BoundBox mbounds = mesh->bounds;
+
+	if(motion_blur && use_motion()) {
+		array<DecomposedTransform> decomp(motion.size());
+		transform_motion_decompose(decomp.data(), motion.data(), motion.size());
 
 		bounds = BoundBox::empty;
 
@@ -108,11 +164,12 @@ void Object::compute_bounds(bool motion_blur)
 		for(float t = 0.0f; t < 1.0f; t += (1.0f/128.0f)) {
 			Transform ttfm;
 
-			transform_motion_interpolate(&ttfm, &decomp, t);
+			transform_motion_array_interpolate(&ttfm, decomp.data(), motion.size(), t);
 			bounds.grow(mbounds.transformed(&ttfm));
 		}
 	}
 	else {
+		/* No motion blur case. */
 		if(mesh->transform_applied) {
 			bounds = mbounds;
 		}
@@ -132,7 +189,7 @@ void Object::apply_transform(bool apply_to_motion)
 		/* store matrix to transform later. when accessing these as attributes we
 		 * do not want the transform to be applied for consistency between static
 		 * and dynamic BVH, so we do it on packing. */
-		mesh->transform_normal = transform_transpose(transform_inverse(tfm));
+		mesh->transform_normal = transform_transposed_inverse(tfm);
 
 		/* apply to mesh vertices */
 		for(size_t i = 0; i < mesh->verts.size(); i++)
@@ -232,27 +289,30 @@ void Object::tag_update(Scene *scene)
 	scene->object_manager->need_update = true;
 }
 
-vector<float> Object::motion_times()
+bool Object::use_motion() const
 {
-	/* compute times at which we sample motion for this object */
-	vector<float> times;
-
-	if(!mesh || mesh->motion_steps == 1)
-		return times;
+	return (motion.size() > 1);
+}
 
-	int motion_steps = mesh->motion_steps;
+float Object::motion_time(int step) const
+{
+	return (use_motion()) ? 2.0f * step / (motion.size() - 1) - 1.0f : 0.0f;
+}
 
-	for(int step = 0; step < motion_steps; step++) {
-		if(step != motion_steps / 2) {
-			float time = 2.0f * step / (motion_steps - 1) - 1.0f;
-			times.push_back(time);
+int Object::motion_step(float time) const
+{
+	if(use_motion()) {
+		for(size_t step = 0; step < motion.size(); step++) {
+			if(time == motion_time(step)) {
+				return step;
+			}
 		}
 	}
 
-	return times;
+	return -1;
 }
 
-bool Object::is_traceable()
+bool Object::is_traceable() const
 {
 	/* Mesh itself can be empty,can skip all such objects. */
 	if(!bounds.valid() || bounds.size() == make_float3(0.0f, 0.0f, 0.0f)) {
@@ -289,8 +349,8 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
                                                    Object *ob,
                                                    int object_index)
 {
-	float4 *objects = state->objects;
-	float4 *objects_vector = state->objects_vector;
+	KernelObject& kobject = state->objects[object_index];
+	Transform *object_motion_pass = state->object_motion_pass;
 
 	Mesh *mesh = ob->mesh;
 	uint flag = 0;
@@ -357,15 +417,13 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
 		}
 	}
 
-	/* Pack in texture. */
-	int offset = object_index*OBJECT_SIZE;
-
-	/* OBJECT_TRANSFORM */
-	memcpy(&objects[offset], &tfm, sizeof(float4)*3);
-	/* OBJECT_INVERSE_TRANSFORM */
-	memcpy(&objects[offset+4], &itfm, sizeof(float4)*3);
-	/* OBJECT_PROPERTIES */
-	objects[offset+12] = make_float4(surface_area, pass_id, random_number, __int_as_float(particle_index));
+	kobject.tfm = tfm;
+	kobject.itfm = itfm;
+	kobject.surface_area = surface_area;
+	kobject.pass_id = pass_id;
+	kobject.random_number = random_number;
+	kobject.particle_index = particle_index;
+	kobject.motion_offset = 0;
 
 	if(mesh->use_motion_blur) {
 		state->have_motion = true;
@@ -375,50 +433,56 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
 	}
 
 	if(state->need_motion == Scene::MOTION_PASS) {
-		/* Motion transformations, is world/object space depending if mesh
-		 * comes with deformed position in object space, or if we transform
-		 * the shading point in world space.
-		 */
-		MotionTransform mtfm = ob->motion;
+		/* Clear motion array if there is no actual motion. */
+		ob->update_motion();
 
-		/* In case of missing motion information for previous/next frame,
-		 * assume there is no motion. */
-		if(!ob->use_motion || mtfm.pre == transform_empty()) {
-			mtfm.pre = ob->tfm;
+		/* Compute motion transforms. */
+		Transform tfm_pre, tfm_post;
+		if(ob->use_motion()) {
+			tfm_pre = ob->motion[0];
+			tfm_post = ob->motion[ob->motion.size() - 1];
 		}
-		if(!ob->use_motion || mtfm.post == transform_empty()) {
-			mtfm.post = ob->tfm;
+		else {
+			tfm_pre = tfm;
+			tfm_post = tfm;
 		}
 
+		/* Motion transformations, is world/object space depending if mesh
+		 * comes with deformed position in object space, or if we transform
+		 * the shading point in world space. */
 		if(!mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) {
-			mtfm.pre = mtfm.pre * itfm;
-			mtfm.post = mtfm.post * itfm;
+			tfm_pre = tfm_pre * itfm;
+			tfm_post = tfm_post * itfm;
 		}
 
-		memcpy(&objects_vector[object_index*OBJECT_VECTOR_SIZE+0], &mtfm.pre, sizeof(float4)*3);
-		memcpy(&objects_vector[object_index*OBJECT_VECTOR_SIZE+3], &mtfm.post, sizeof(float4)*3);
+		int motion_pass_offset = object_index*OBJECT_MOTION_PASS_SIZE;
+		object_motion_pass[motion_pass_offset + 0] = tfm_pre;
+		object_motion_pass[motion_pass_offset + 1] = tfm_post;
 	}
 	else if(state->need_motion == Scene::MOTION_BLUR) {
-		if(ob->use_motion) {
-			/* decompose transformations for interpolation. */
-			MotionTransform decomp;
+		if(ob->use_motion()) {
+			kobject.motion_offset = state->motion_offset[object_index];
 
-			transform_motion_decompose(&decomp, &ob->motion, &ob->tfm);
-			memcpy(&objects[offset], &decomp, sizeof(float4)*12);
+			/* Decompose transforms for interpolation. */
+			DecomposedTransform *decomp = state->object_motion + kobject.motion_offset;
+			transform_motion_decompose(decomp, ob->motion.data(), ob->motion.size());
 			flag |= SD_OBJECT_MOTION;
 			state->have_motion = true;
 		}
 	}
 
 	/* Dupli object coords and motion info. */
+	kobject.dupli_generated[0] = ob->dupli_generated[0];
+	kobject.dupli_generated[1] = ob->dupli_generated[1];
+	kobject.dupli_generated[2] = ob->dupli_generated[2];
+	kobject.numkeys = mesh->curve_keys.size();
+	kobject.dupli_uv[0] = ob->dupli_uv[0];
+	kobject.dupli_uv[1] = ob->dupli_uv[1];
 	int totalsteps = mesh->motion_steps;
-	int numsteps = (totalsteps - 1)/2;
-	int numverts = mesh->verts.size();
-	int numkeys = mesh->curve_keys.size();
-
-	objects[offset+13] = make_float4(ob->dupli_generated[0], ob->dupli_generated[1], ob->dupli_generated[2], __int_as_float(numkeys));
-	objects[offset+14] = make_float4(ob->dupli_uv[0], ob->dupli_uv[1], __int_as_float(numsteps), __int_as_float(numverts));
-	objects[offset+15] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+	kobject.numsteps = (totalsteps - 1)/2;
+	kobject.numverts = mesh->verts.size();;
+	kobject.patch_map_offset = 0;
+	kobject.attribute_map_offset = 0;
 
 	/* Object flag. */
 	if(ob->use_holdout) {
@@ -475,7 +539,6 @@ void ObjectManager::device_update_object_transform_task(
 
 void ObjectManager::device_update_transforms(DeviceScene *dscene,
                                              Scene *scene,
-                                             uint *object_flag,
                                              Progress& progress)
 {
 	UpdateObjectTransformState state;
@@ -485,13 +548,29 @@ void ObjectManager::device_update_transforms(DeviceScene *dscene,
 	state.scene = scene;
 	state.queue_start_object = 0;
 
-	state.object_flag = object_flag;
-	state.objects = dscene->objects.alloc(OBJECT_SIZE*scene->objects.size());
+	state.objects = dscene->objects.alloc(scene->objects.size());
+	state.object_flag = dscene->object_flag.alloc(scene->objects.size());
+	state.object_motion = NULL;
+	state.object_motion_pass = NULL;
+
 	if(state.need_motion == Scene::MOTION_PASS) {
-		state.objects_vector = dscene->objects_vector.alloc(OBJECT_VECTOR_SIZE*scene->objects.size());
+		state.object_motion_pass = dscene->object_motion_pass.alloc(OBJECT_MOTION_PASS_SIZE*scene->objects.size());
 	}
-	else {
-		state.objects_vector = NULL;
+	else if(state.need_motion == Scene::MOTION_BLUR) {
+		/* Set object offsets into global object motion array. */
+		uint *motion_offsets = state.motion_offset.resize(scene->objects.size());
+		uint motion_offset = 0;
+
+		foreach(Object *ob, scene->objects) {
+			*motion_offsets = motion_offset;
+			motion_offsets++;
+
+			/* Clear motion array if there is no actual motion. */
+			ob->update_motion();
+			motion_offset += ob->motion.size();
+		}
+
+		state.object_motion = dscene->object_motion.alloc(motion_offset);
 	}
 
 	/* Particle system device offsets
@@ -534,7 +613,10 @@ void ObjectManager::device_update_transforms(DeviceScene *dscene,
 
 	dscene->objects.copy_to_device();
 	if(state.need_motion == Scene::MOTION_PASS) {
-		dscene->objects_vector.copy_to_device();
+		dscene->object_motion_pass.copy_to_device();
+	}
+	else if(state.need_motion == Scene::MOTION_BLUR) {
+		dscene->object_motion.copy_to_device();
 	}
 
 	dscene->data.bvh.have_motion = state.have_motion;
@@ -554,12 +636,9 @@ void ObjectManager::device_update(Device *device, DeviceScene *dscene, Scene *sc
 	if(scene->objects.size() == 0)
 		return;
 
-	/* object info flag */
-	uint *object_flag = dscene->object_flag.alloc(scene->objects.size());
-
 	/* set object transform matrices, before applying static transforms */
 	progress.set_status("Updating Objects", "Copying Transformations to device");
-	device_update_transforms(dscene, scene, object_flag, progress);
+	device_update_transforms(dscene, scene, progress);
 
 	if(progress.get_cancel()) return;
 
@@ -567,7 +646,7 @@ void ObjectManager::device_update(Device *device, DeviceScene *dscene, Scene *sc
 	/* todo: do before to support getting object level coords? */
 	if(scene->params.bvh_type == SceneParams::BVH_STATIC) {
 		progress.set_status("Updating Objects", "Applying Static Transformations");
-		apply_static_transforms(dscene, scene, object_flag, progress);
+		apply_static_transforms(dscene, scene, progress);
 	}
 }
 
@@ -586,9 +665,10 @@ void ObjectManager::device_update_flags(Device *,
 	if(scene->objects.size() == 0)
 		return;
 
-	/* object info flag */
+	/* Object info flag. */
 	uint *object_flag = dscene->object_flag.data();
 
+	/* Object volume intersection. */
 	vector<Object *> volume_objects;
 	bool has_volume_objects = false;
 	foreach(Object *object, scene->objects) {
@@ -642,7 +722,7 @@ void ObjectManager::device_update_flags(Device *,
 		++object_index;
 	}
 
-	/* allocate object flag */
+	/* Copy object flag. */
 	dscene->object_flag.copy_to_device();
 }
 
@@ -652,27 +732,26 @@ void ObjectManager::device_update_mesh_offsets(Device *, DeviceScene *dscene, Sc
 		return;
 	}
 
-	uint4* objects = (uint4*)dscene->objects.data();
+	KernelObject *kobjects = dscene->objects.data();
 
 	bool update = false;
 	int object_index = 0;
 
 	foreach(Object *object, scene->objects) {
 		Mesh* mesh = object->mesh;
-		int offset = object_index*OBJECT_SIZE + 15;
 
 		if(mesh->patch_table) {
 			uint patch_map_offset = 2*(mesh->patch_table_offset + mesh->patch_table->total_size() -
 			                           mesh->patch_table->num_nodes * PATCH_NODE_SIZE) - mesh->patch_offset;
 
-			if(objects[offset].x != patch_map_offset) {
-				objects[offset].x = patch_map_offset;
+			if(kobjects[object_index].patch_map_offset != patch_map_offset) {
+				kobjects[object_index].patch_map_offset = patch_map_offset;
 				update = true;
 			}
 		}
 
-		if(objects[offset].y != mesh->attr_map_offset) {
-			objects[offset].y = mesh->attr_map_offset;
+		if(kobjects[object_index].attribute_map_offset != mesh->attr_map_offset) {
+			kobjects[object_index].attribute_map_offset = mesh->attr_map_offset;
 			update = true;
 		}
 
@@ -687,11 +766,12 @@ void ObjectManager::device_update_mesh_offsets(Device *, DeviceScene *dscene, Sc
 void ObjectManager::device_free(Device *, DeviceScene *dscene)
 {
 	dscene->objects.free();
-	dscene->objects_vector.free();
+	dscene->object_motion_pass.free();
+	dscene->object_motion.free();
 	dscene->object_flag.free();
 }
 
-void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, uint *object_flag, Progress& progress)
+void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, Progress& progress)
 {
 	/* todo: normals and displacement should be done before applying transform! */
 	/* todo: create objects/meshes in right order! */
@@ -715,6 +795,8 @@ void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, u
 
 	if(progress.get_cancel()) return;
 
+	uint *object_flag = dscene->object_flag.data();
+
 	/* apply transforms for objects with single user meshes */
 	foreach(Object *object, scene->objects) {
 		/* Annoying feedback loop here: we can't use is_instanced() because
@@ -725,7 +807,7 @@ void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, u
 		if((mesh_users[object->mesh] == 1 && !object->mesh->has_surface_bssrdf) &&
 		   !object->mesh->has_true_displacement() && object->mesh->subdivision_type == Mesh::SUBDIVISION_NONE)
 		{
-			if(!(motion_blur && object->use_motion)) {
+			if(!(motion_blur && object->use_motion())) {
 				if(!object->mesh->transform_applied) {
 					object->apply_transform(apply_to_motion);
 					object->mesh->transform_applied = true;
diff --git a/intern/cycles/render/object.h b/intern/cycles/render/object.h
index acdb1b641238441ed4c2b7b03bf81a74129d1282..c7212ae25f915baefc538af9760b1f887ce084cf 100644
--- a/intern/cycles/render/object.h
+++ b/intern/cycles/render/object.h
@@ -35,6 +35,7 @@ class ParticleSystem;
 class Progress;
 class Scene;
 struct Transform;
+struct UpdateObjectTransformState;
 
 /* Object */
 
@@ -49,8 +50,7 @@ public:
 	int pass_id;
 	vector<ParamValue> attributes;
 	uint visibility;
-	MotionTransform motion;
-	bool use_motion;
+	array<Transform> motion;
 	bool hide_on_missing_motion;
 	bool use_holdout;
 	bool is_shadow_catcher;
@@ -69,12 +69,17 @@ public:
 	void compute_bounds(bool motion_blur);
 	void apply_transform(bool apply_to_motion);
 
-	vector<float> motion_times();
+	/* Convert between normalized -1..1 motion time and index
+	 * in the motion array. */
+	bool use_motion() const;
+	float motion_time(int step) const;
+	int motion_step(float time) const;
+	void update_motion();
 
 	/* Check whether object is traceable and it worth adding it to
 	 * kernel scene.
 	 */
-	bool is_traceable();
+	bool is_traceable() const;
 
 	/* Combine object's visibility with all possible internal run-time
 	 * determined flags which denotes trace-time visibility.
@@ -95,7 +100,6 @@ public:
 	void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
 	void device_update_transforms(DeviceScene *dscene,
 	                              Scene *scene,
-	                              uint *object_flag,
 	                              Progress& progress);
 
 	void device_update_flags(Device *device,
@@ -109,49 +113,9 @@ public:
 
 	void tag_update(Scene *scene);
 
-	void apply_static_transforms(DeviceScene *dscene, Scene *scene, uint *object_flag, Progress& progress);
+	void apply_static_transforms(DeviceScene *dscene, Scene *scene, Progress& progress);
 
 protected:
-	/* Global state of object transform update. */
-	struct UpdateObjectTransformState {
-		/* Global state used by device_update_object_transform().
-		 * Common for both threaded and non-threaded update.
-		 */
-
-		/* Type of the motion required by the scene settings. */
-		Scene::MotionType need_motion;
-
-		/* Mapping from particle system to a index in packed particle array.
-		 * Only used for read.
-		 */
-		map<ParticleSystem*, int> particle_offset;
-
-		/* Mesh area.
-		 * Used to avoid calculation of mesh area multiple times. Used for both
-		 * read and write. Acquire surface_area_lock to keep it all thread safe.
-		 */
-		map<Mesh*, float> surface_area_map;
-
-		/* Packed object arrays. Those will be filled in. */
-		uint *object_flag;
-		float4 *objects;
-		float4 *objects_vector;
-
-		/* Flags which will be synchronized to Integrator. */
-		bool have_motion;
-		bool have_curves;
-
-		/* ** Scheduling queue. ** */
-
-		Scene *scene;
-
-		/* Some locks to keep everything thread-safe. */
-		thread_spin_lock queue_lock;
-		thread_spin_lock surface_area_lock;
-
-		/* First unused object index in the queue. */
-		int queue_start_object;
-	};
 	void device_update_object_transform(UpdateObjectTransformState *state,
 	                                    Object *ob,
 	                                    const int object_index);
diff --git a/intern/cycles/render/osl.cpp b/intern/cycles/render/osl.cpp
index 9e931280691d79a25f19617f93b6df7bdca9d86c..f1a22350060b547735508edf0e4a552d508bbf86 100644
--- a/intern/cycles/render/osl.cpp
+++ b/intern/cycles/render/osl.cpp
@@ -34,6 +34,7 @@
 #include "util/util_md5.h"
 #include "util/util_path.h"
 #include "util/util_progress.h"
+#include "util/util_projection.h"
 
 #endif
 
@@ -832,7 +833,9 @@ void OSLCompiler::parameter(ShaderNode* node, const char *name)
 		case SocketType::TRANSFORM:
 		{
 			Transform value = node->get_transform(socket);
-			ss->Parameter(uname, TypeDesc::TypeMatrix, &value);
+			ProjectionTransform projection(value);
+			projection = projection_transpose(projection);
+			ss->Parameter(uname, TypeDesc::TypeMatrix, &projection);
 			break;
 		}
 		case SocketType::BOOLEAN_ARRAY:
@@ -900,7 +903,11 @@ void OSLCompiler::parameter(ShaderNode* node, const char *name)
 		case SocketType::TRANSFORM_ARRAY:
 		{
 			const array<Transform>& value = node->get_transform_array(socket);
-			ss->Parameter(uname, array_typedesc(TypeDesc::TypeMatrix, value.size()), value.data());
+			array<ProjectionTransform> fvalue(value.size());
+			for(size_t i = 0; i < value.size(); i++) {
+				fvalue[i] = projection_transpose(ProjectionTransform(value[i]));
+			}
+			ss->Parameter(uname, array_typedesc(TypeDesc::TypeMatrix, fvalue.size()), fvalue.data());
 			break;
 		}
 		case SocketType::CLOSURE:
@@ -967,7 +974,9 @@ void OSLCompiler::parameter(const char *name, ustring s)
 void OSLCompiler::parameter(const char *name, const Transform& tfm)
 {
 	OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
-	ss->Parameter(name, TypeDesc::TypeMatrix, (float*)&tfm);
+	ProjectionTransform projection(tfm);
+	projection = projection_transpose(projection);
+	ss->Parameter(name, TypeDesc::TypeMatrix, (float*)&projection);
 }
 
 void OSLCompiler::parameter_array(const char *name, const float f[], int arraylen)
diff --git a/intern/cycles/render/particles.cpp b/intern/cycles/render/particles.cpp
index 3ee620c9d0120672c8626edf04138a2ef4cb5857..e4be3306d7e472dd32130791807a4ab37d3bb798 100644
--- a/intern/cycles/render/particles.cpp
+++ b/intern/cycles/render/particles.cpp
@@ -62,14 +62,10 @@ void ParticleSystemManager::device_update_particles(Device *, DeviceScene *dscen
 	for(size_t j = 0; j < scene->particle_systems.size(); j++)
 		num_particles += scene->particle_systems[j]->particles.size();
 	
-	float4 *particles = dscene->particles.alloc(PARTICLE_SIZE*num_particles);
+	KernelParticle *kparticles = dscene->particles.alloc(num_particles);
 	
 	/* dummy particle */
-	particles[0] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
-	particles[1] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
-	particles[2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
-	particles[3] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
-	particles[4] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+	memset(kparticles, 0, sizeof(KernelParticle));
 	
 	int i = 1;
 	for(size_t j = 0; j < scene->particle_systems.size(); j++) {
@@ -78,13 +74,15 @@ void ParticleSystemManager::device_update_particles(Device *, DeviceScene *dscen
 		for(size_t k = 0; k < psys->particles.size(); k++) {
 			/* pack in texture */
 			Particle& pa = psys->particles[k];
-			int offset = i*PARTICLE_SIZE;
 			
-			particles[offset] = make_float4(__uint_as_float(pa.index), pa.age, pa.lifetime, pa.size);
-			particles[offset+1] = pa.rotation;
-			particles[offset+2] = make_float4(pa.location.x, pa.location.y, pa.location.z, pa.velocity.x);
-			particles[offset+3] = make_float4(pa.velocity.y, pa.velocity.z, pa.angular_velocity.x, pa.angular_velocity.y);
-			particles[offset+4] = make_float4(pa.angular_velocity.z, 0.0f, 0.0f, 0.0f);
+			kparticles[i].index = pa.index;
+			kparticles[i].age = pa.age;
+			kparticles[i].lifetime = pa.lifetime;
+			kparticles[i].size = pa.size;
+			kparticles[i].rotation = pa.rotation;
+			kparticles[i].location = float3_to_float4(pa.location);
+			kparticles[i].velocity = float3_to_float4(pa.velocity);
+			kparticles[i].angular_velocity = float3_to_float4(pa.angular_velocity);
 			
 			i++;
 			
diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp
index 1e5866e2806adc2efb07d9ba858608a71b6bb188..2393f9db8aa7046e78a28ec8eba46a1abe7e2bae 100644
--- a/intern/cycles/render/scene.cpp
+++ b/intern/cycles/render/scene.cpp
@@ -60,19 +60,21 @@ DeviceScene::DeviceScene(Device *device)
   curve_keys(device, "__curve_keys", MEM_TEXTURE),
   patches(device, "__patches", MEM_TEXTURE),
   objects(device, "__objects", MEM_TEXTURE),
-  objects_vector(device, "__objects_vector", MEM_TEXTURE),
+  object_motion_pass(device, "__object_motion_pass", MEM_TEXTURE),
+  object_motion(device, "__object_motion", MEM_TEXTURE),
+  object_flag(device, "__object_flag", MEM_TEXTURE),
+  camera_motion(device, "__camera_motion", MEM_TEXTURE),
   attributes_map(device, "__attributes_map", MEM_TEXTURE),
   attributes_float(device, "__attributes_float", MEM_TEXTURE),
   attributes_float3(device, "__attributes_float3", MEM_TEXTURE),
   attributes_uchar4(device, "__attributes_uchar4", MEM_TEXTURE),
   light_distribution(device, "__light_distribution", MEM_TEXTURE),
-  light_data(device, "__light_data", MEM_TEXTURE),
+  lights(device, "__lights", MEM_TEXTURE),
   light_background_marginal_cdf(device, "__light_background_marginal_cdf", MEM_TEXTURE),
   light_background_conditional_cdf(device, "__light_background_conditional_cdf", MEM_TEXTURE),
   particles(device, "__particles", MEM_TEXTURE),
   svm_nodes(device, "__svm_nodes", MEM_TEXTURE),
-  shader_flag(device, "__shader_flag", MEM_TEXTURE),
-  object_flag(device, "__object_flag", MEM_TEXTURE),
+  shaders(device, "__shaders", MEM_TEXTURE),
   lookup_table(device, "__lookup_table", MEM_TEXTURE),
   sobol_directions(device, "__sobol_directions", MEM_TEXTURE)
 {
@@ -213,6 +215,11 @@ void Scene::device_update(Device *device_, Progress& progress)
 
 	if(progress.get_cancel() || device->have_error()) return;
 	
+	progress.set_status("Updating Hair Systems");
+	curve_system_manager->device_update(device, &dscene, this, progress);
+
+	if(progress.get_cancel() || device->have_error()) return;
+
 	progress.set_status("Updating Particle Systems");
 	particle_system_manager->device_update(device, &dscene, this, progress);
 
diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h
index ea9485ff23064fd73660378117f654d2be98d5e7..9700732f9484203d0a7b650ba855ad112223b49f 100644
--- a/intern/cycles/render/scene.h
+++ b/intern/cycles/render/scene.h
@@ -86,8 +86,13 @@ public:
 	device_vector<uint> patches;
 
 	/* objects */
-	device_vector<float4> objects;
-	device_vector<float4> objects_vector;
+	device_vector<KernelObject> objects;
+	device_vector<Transform> object_motion_pass;
+	device_vector<DecomposedTransform> object_motion;
+	device_vector<uint> object_flag;
+
+	/* cameras */
+	device_vector<DecomposedTransform> camera_motion;
 
 	/* attributes */
 	device_vector<uint4> attributes_map;
@@ -96,18 +101,17 @@ public:
 	device_vector<uchar4> attributes_uchar4;
 
 	/* lights */
-	device_vector<float4> light_distribution;
-	device_vector<float4> light_data;
+	device_vector<KernelLightDistribution> light_distribution;
+	device_vector<KernelLight> lights;
 	device_vector<float2> light_background_marginal_cdf;
 	device_vector<float2> light_background_conditional_cdf;
 
 	/* particles */
-	device_vector<float4> particles;
+	device_vector<KernelParticle> particles;
 
 	/* shaders */
 	device_vector<int4> svm_nodes;
-	device_vector<uint> shader_flag;
-	device_vector<uint> object_flag;
+	device_vector<KernelShader> shaders;
 
 	/* lookup tables */
 	device_vector<float> lookup_table;
@@ -158,7 +162,6 @@ public:
 	bool use_bvh_spatial_split;
 	bool use_bvh_unaligned_nodes;
 	int num_bvh_time_steps;
-
 	bool persistent_data;
 	int texture_limit;
 
diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp
index e8d9558c38df25c61b12ab394b1de50161840464..bb636dd962abbc5e9c1a26ad700ba14a67367bc5 100644
--- a/intern/cycles/render/session.cpp
+++ b/intern/cycles/render/session.cpp
@@ -55,7 +55,7 @@ Session::Session(const SessionParams& params_)
 
 	device = Device::create(params.device, stats, params.background);
 
-	if(params.background && params.output_path.empty()) {
+	if(params.background && !params.write_render_cb) {
 		buffers = NULL;
 		display = NULL;
 	}
@@ -101,7 +101,7 @@ Session::~Session()
 		wait();
 	}
 
-	if(!params.output_path.empty()) {
+	if(params.write_render_cb) {
 		/* tonemap and write out image if requested */
 		delete display;
 
@@ -109,8 +109,10 @@ Session::~Session()
 		display->reset(buffers->params);
 		tonemap(params.samples);
 
-		progress.set_status("Writing Image", params.output_path);
-		display->write(params.output_path);
+		int w = display->draw_width;
+		int h = display->draw_height;
+		uchar4 *pixels = display->rgba_byte.copy_from_device(0, w, h);
+		params.write_render_cb((uchar*)pixels, w, h, 4);
 	}
 
 	/* clean up */
@@ -656,13 +658,13 @@ DeviceRequestedFeatures Session::get_requested_device_features()
 	 */
 	requested_features.use_hair = false;
 	requested_features.use_object_motion = false;
-	requested_features.use_camera_motion = scene->camera->use_motion;
+	requested_features.use_camera_motion = scene->camera->use_motion();
 	foreach(Object *object, scene->objects) {
 		Mesh *mesh = object->mesh;
 		if(mesh->num_curves()) {
 			requested_features.use_hair = true;
 		}
-		requested_features.use_object_motion |= object->use_motion | mesh->use_motion_blur;
+		requested_features.use_object_motion |= object->use_motion() | mesh->use_motion_blur;
 		requested_features.use_camera_motion |= mesh->use_motion_blur;
 #ifdef WITH_OPENSUBDIV
 		if(mesh->subdivision_type != Mesh::SUBDIVISION_NONE) {
diff --git a/intern/cycles/render/session.h b/intern/cycles/render/session.h
index 8495d95666b772b598a77b4f213c06a371611701..e63cad0d9777c8b6dfebc533efad3df8905b1309 100644
--- a/intern/cycles/render/session.h
+++ b/intern/cycles/render/session.h
@@ -45,7 +45,6 @@ public:
 	DeviceInfo device;
 	bool background;
 	bool progressive_refine;
-	string output_path;
 
 	bool progressive;
 	bool experimental;
@@ -71,11 +70,15 @@ public:
 
 	ShadingSystem shadingsystem;
 
+	function<bool(const uchar *pixels,
+	              int width,
+	              int height,
+	              int channels)> write_render_cb;
+
 	SessionParams()
 	{
 		background = false;
 		progressive_refine = false;
-		output_path = "";
 
 		progressive = false;
 		experimental = false;
@@ -106,7 +109,6 @@ public:
 	{ return !(device == params.device
 		&& background == params.background
 		&& progressive_refine == params.progressive_refine
-		&& output_path == params.output_path
 		/* && samples == params.samples */
 		&& progressive == params.progressive
 		&& experimental == params.experimental
diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp
index 578c61a3e7958f6b761e473620fd077fa7d8479d..ec52c51e337f16112f37040541685542b15d0aae 100644
--- a/intern/cycles/render/shader.cpp
+++ b/intern/cycles/render/shader.cpp
@@ -432,14 +432,12 @@ void ShaderManager::device_update_common(Device *device,
                                          Scene *scene,
                                          Progress& /*progress*/)
 {
-	dscene->shader_flag.free();
+	dscene->shaders.free();
 
 	if(scene->shaders.size() == 0)
 		return;
 
-	uint shader_flag_size = scene->shaders.size()*SHADER_SIZE;
-	uint *shader_flag = dscene->shader_flag.alloc(shader_flag_size);
-	uint i = 0;
+	KernelShader *kshader = dscene->shaders.alloc(scene->shaders.size());
 	bool has_volumes = false;
 	bool has_transparent_shadow = false;
 
@@ -487,16 +485,17 @@ void ShaderManager::device_update_common(Device *device,
 			flag |= SD_HAS_CONSTANT_EMISSION;
 
 		/* regular shader */
-		shader_flag[i++] = flag;
-		shader_flag[i++] = shader->pass_id;
-		shader_flag[i++] = __float_as_int(constant_emission.x);
-		shader_flag[i++] = __float_as_int(constant_emission.y);
-		shader_flag[i++] = __float_as_int(constant_emission.z);
+		kshader->flags = flag;
+		kshader->pass_id = shader->pass_id;
+		kshader->constant_emission[0] = constant_emission.x;
+		kshader->constant_emission[1] = constant_emission.y;
+		kshader->constant_emission[2] = constant_emission.z;
+		kshader++;
 
 		has_transparent_shadow |= (flag & SD_HAS_TRANSPARENT_SHADOW) != 0;
 	}
 
-	dscene->shader_flag.copy_to_device();
+	dscene->shaders.copy_to_device();
 
 	/* lookup tables */
 	KernelTables *ktables = &dscene->data.tables;
@@ -525,7 +524,7 @@ void ShaderManager::device_free_common(Device *, DeviceScene *dscene, Scene *sce
 {
 	scene->lookup_tables->remove_table(&beckmann_table_offset);
 
-	dscene->shader_flag.free();
+	dscene->shaders.free();
 }
 
 void ShaderManager::add_default(Scene *scene)
diff --git a/intern/cycles/util/CMakeLists.txt b/intern/cycles/util/CMakeLists.txt
index 66c4f22a7e2fcaf5b44174a7368405307d967f8f..24043e2231bc6c121c55126da62d6d3549c45bc9 100644
--- a/intern/cycles/util/CMakeLists.txt
+++ b/intern/cycles/util/CMakeLists.txt
@@ -67,6 +67,7 @@ set(SRC_HEADERS
 	util_param.h
 	util_path.h
 	util_progress.h
+	util_projection.h
 	util_queue.h
 	util_rect.h
 	util_set.h
diff --git a/intern/cycles/util/util_projection.h b/intern/cycles/util/util_projection.h
new file mode 100644
index 0000000000000000000000000000000000000000..dbcb9877a48d289f63443996e5f6b777f4614078
--- /dev/null
+++ b/intern/cycles/util/util_projection.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2011-2018 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_PROJECTION_H__
+#define __UTIL_PROJECTION_H__
+
+#include "util/util_transform.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* 4x4 projection matrix, perspective or orthographic. */
+
+typedef struct ProjectionTransform {
+	float4 x, y, z, w; /* rows */
+
+#ifndef __KERNEL_GPU__
+	ProjectionTransform()
+	{
+	}
+
+	explicit ProjectionTransform(const Transform& tfm)
+	: x(tfm.x),
+	  y(tfm.y),
+	  z(tfm.z),
+	  w(make_float4(0.0f, 0.0f, 0.0f, 1.0f))
+	{
+	}
+#endif
+} ProjectionTransform;
+
+typedef struct PerspectiveMotionTransform {
+	ProjectionTransform pre;
+	ProjectionTransform post;
+} PerspectiveMotionTransform;
+
+/* Functions */
+
+ccl_device_inline float3 transform_perspective(const ProjectionTransform *t, const float3 a)
+{
+	float4 b = make_float4(a.x, a.y, a.z, 1.0f);
+	float3 c = make_float3(dot(t->x, b), dot(t->y, b), dot(t->z, b));
+	float w = dot(t->w, b);
+
+	return (w != 0.0f)? c/w: make_float3(0.0f, 0.0f, 0.0f);
+}
+
+ccl_device_inline float3 transform_perspective_direction(const ProjectionTransform *t, const float3 a)
+{
+	float3 c = make_float3(
+		a.x*t->x.x + a.y*t->x.y + a.z*t->x.z,
+		a.x*t->y.x + a.y*t->y.y + a.z*t->y.z,
+		a.x*t->z.x + a.y*t->z.y + a.z*t->z.z);
+
+	return c;
+}
+
+#ifndef __KERNEL_GPU__
+
+ccl_device_inline Transform projection_to_transform(const ProjectionTransform& a)
+{
+	Transform tfm = {a.x, a.y, a.z};
+	return tfm;
+}
+
+ccl_device_inline ProjectionTransform projection_transpose(const ProjectionTransform& a)
+{
+	ProjectionTransform t;
+
+	t.x.x = a.x.x; t.x.y = a.y.x; t.x.z = a.z.x; t.x.w = a.w.x;
+	t.y.x = a.x.y; t.y.y = a.y.y; t.y.z = a.z.y; t.y.w = a.w.y;
+	t.z.x = a.x.z; t.z.y = a.y.z; t.z.z = a.z.z; t.z.w = a.w.z;
+	t.w.x = a.x.w; t.w.y = a.y.w; t.w.z = a.z.w; t.w.w = a.w.w;
+
+	return t;
+}
+
+ProjectionTransform projection_inverse(const ProjectionTransform& a);
+
+ccl_device_inline ProjectionTransform make_projection(
+	float a, float b, float c, float d,
+	float e, float f, float g, float h,
+	float i, float j, float k, float l,
+	float m, float n, float o, float p)
+{
+	ProjectionTransform t;
+
+	t.x.x = a; t.x.y = b; t.x.z = c; t.x.w = d;
+	t.y.x = e; t.y.y = f; t.y.z = g; t.y.w = h;
+	t.z.x = i; t.z.y = j; t.z.z = k; t.z.w = l;
+	t.w.x = m; t.w.y = n; t.w.z = o; t.w.w = p;
+
+	return t;
+}
+ccl_device_inline ProjectionTransform projection_identity()
+{
+	return make_projection(
+		1.0f, 0.0f, 0.0f, 0.0f,
+		0.0f, 1.0f, 0.0f, 0.0f,
+		0.0f, 0.0f, 1.0f, 0.0f,
+		0.0f, 0.0f, 0.0f, 1.0f);
+}
+
+ccl_device_inline ProjectionTransform operator*(const ProjectionTransform& a, const ProjectionTransform& b)
+{
+	ProjectionTransform c = projection_transpose(b);
+	ProjectionTransform t;
+
+	t.x = make_float4(dot(a.x, c.x), dot(a.x, c.y), dot(a.x, c.z), dot(a.x, c.w));
+	t.y = make_float4(dot(a.y, c.x), dot(a.y, c.y), dot(a.y, c.z), dot(a.y, c.w));
+	t.z = make_float4(dot(a.z, c.x), dot(a.z, c.y), dot(a.z, c.z), dot(a.z, c.w));
+	t.w = make_float4(dot(a.w, c.x), dot(a.w, c.y), dot(a.w, c.z), dot(a.w, c.w));
+
+	return t;
+}
+
+ccl_device_inline ProjectionTransform operator*(const ProjectionTransform& a, const Transform& b)
+{
+	return a * ProjectionTransform(b);
+}
+
+ccl_device_inline ProjectionTransform operator*(const Transform& a, const ProjectionTransform& b)
+{
+	return ProjectionTransform(a) * b;
+}
+
+ccl_device_inline void print_projection(const char *label, const ProjectionTransform& t)
+{
+	print_float4(label, t.x);
+	print_float4(label, t.y);
+	print_float4(label, t.z);
+	print_float4(label, t.w);
+	printf("\n");
+}
+
+ccl_device_inline ProjectionTransform projection_perspective(float fov, float n, float f)
+{
+	ProjectionTransform persp = make_projection(
+		1, 0, 0, 0,
+		0, 1, 0, 0,
+		0, 0, f / (f - n), -f*n / (f - n),
+		0, 0, 1, 0);
+
+	float inv_angle = 1.0f/tanf(0.5f*fov);
+
+	Transform scale = transform_scale(inv_angle, inv_angle, 1);
+
+	return scale * persp;
+}
+
+ccl_device_inline ProjectionTransform projection_orthographic(float znear, float zfar)
+{
+	Transform t =
+		transform_scale(1.0f, 1.0f, 1.0f / (zfar-znear)) *
+		transform_translate(0.0f, 0.0f, -znear);
+
+	return ProjectionTransform(t);
+}
+
+#endif /* __KERNEL_GPU__ */
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_PROJECTION_H__ */
+
diff --git a/intern/cycles/util/util_transform.cpp b/intern/cycles/util/util_transform.cpp
index c127054533999a4b3585a9ca7d5e156002d778bc..206c3da23ebd013c236ffbef14fc7458b283d037 100644
--- a/intern/cycles/util/util_transform.cpp
+++ b/intern/cycles/util/util_transform.cpp
@@ -46,6 +46,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include "util/util_projection.h"
 #include "util/util_transform.h"
 
 #include "util/util_boundbox.h"
@@ -129,9 +130,9 @@ static bool transform_matrix4_gj_inverse(float R[][4], float M[][4])
 	return true;
 }
 
-Transform transform_inverse(const Transform& tfm)
+ProjectionTransform projection_inverse(const ProjectionTransform& tfm)
 {
-	Transform tfmR = transform_identity();
+	ProjectionTransform tfmR = projection_identity();
 	float M[4][4], R[4][4];
 
 	memcpy(R, &tfmR, sizeof(R));
@@ -145,7 +146,7 @@ Transform transform_inverse(const Transform& tfm)
 		M[2][2] += 1e-8f;
 
 		if(UNLIKELY(!transform_matrix4_gj_inverse(R, M))) {
-			return transform_identity();
+			return projection_identity();
 		}
 	}
 
@@ -154,6 +155,19 @@ Transform transform_inverse(const Transform& tfm)
 	return tfmR;
 }
 
+Transform transform_inverse(const Transform& tfm)
+{
+	ProjectionTransform projection(tfm);
+	return projection_to_transform(projection_inverse(projection));
+}
+
+Transform transform_transposed_inverse(const Transform& tfm)
+{
+	ProjectionTransform projection(tfm);
+	ProjectionTransform iprojection = projection_inverse(projection);
+	return projection_to_transform(projection_transpose(iprojection));
+}
+
 /* Motion Transform */
 
 float4 transform_to_quat(const Transform& tfm)
@@ -202,14 +216,14 @@ float4 transform_to_quat(const Transform& tfm)
 	return qt;
 }
 
-static void transform_decompose(Transform *decomp, const Transform *tfm)
+static void transform_decompose(DecomposedTransform *decomp, const Transform *tfm)
 {
 	/* extract translation */
 	decomp->y = make_float4(tfm->x.w, tfm->y.w, tfm->z.w, 0.0f);
 
 	/* extract rotation */
 	Transform M = *tfm;
-	M.x.w = 0.0f; M.y.w = 0.0f; M.z.w = 0.0f; M.w.w = 1.0f;
+	M.x.w = 0.0f; M.y.w = 0.0f; M.z.w = 0.0f;
 
 	Transform R = M;
 	float norm;
@@ -217,9 +231,9 @@ static void transform_decompose(Transform *decomp, const Transform *tfm)
 
 	do {
 		Transform Rnext;
-		Transform Rit = transform_inverse(transform_transpose(R));
+		Transform Rit = transform_transposed_inverse(R);
 
-		for(int i = 0; i < 4; i++)
+		for(int i = 0; i < 3; i++)
 			for(int j = 0; j < 4; j++)
 				Rnext[i][j] = 0.5f * (R[i][j] + Rit[i][j]);
 		
@@ -247,18 +261,18 @@ static void transform_decompose(Transform *decomp, const Transform *tfm)
 	decomp->w = make_float4(scale.y.z, scale.z.x, scale.z.y, scale.z.z);
 }
 
-void transform_motion_decompose(MotionTransform *decomp, const MotionTransform *motion, const Transform *mid)
+void transform_motion_decompose(DecomposedTransform *decomp, const Transform *motion, size_t size)
 {
-	transform_decompose(&decomp->pre, &motion->pre);
-	transform_decompose(&decomp->mid, mid);
-	transform_decompose(&decomp->post, &motion->post);
-
-	/* ensure rotation around shortest angle, negated quaternions are the same
-	 * but this means we don't have to do the check in quat_interpolate */
-	if(dot(decomp->pre.x, decomp->mid.x) < 0.0f)
-		decomp->pre.x = -decomp->pre.x;
-	if(dot(decomp->mid.x, decomp->post.x) < 0.0f)
-		decomp->mid.x = -decomp->mid.x;
+	for(size_t i = 0; i < size; i++) {
+		transform_decompose(decomp + i, motion + i);
+
+		if(i > 0) {
+			/* Ensure rotation around shortest angle, negated quaternions are the same
+			 * but this means we don't have to do the check in quat_interpolate */
+			if(dot(decomp[i-1].x, decomp[i].x) < 0.0f)
+				decomp[i-1].x = -decomp[i-1].x;
+		}
+	}
 }
 
 Transform transform_from_viewplane(BoundBox2D& viewplane)
diff --git a/intern/cycles/util/util_transform.h b/intern/cycles/util/util_transform.h
index 6f0238b98e384631b4c4731d653bb846fa524c9f..4124d3d78a12a6c39bf4fdc6b50d7b275f8a418b 100644
--- a/intern/cycles/util/util_transform.h
+++ b/intern/cycles/util/util_transform.h
@@ -26,10 +26,10 @@
 
 CCL_NAMESPACE_BEGIN
 
-/* Data Types */
+/* Affine transformation, stored as 4x3 matrix. */
 
 typedef struct Transform {
-	float4 x, y, z, w; /* rows */
+	float4 x, y, z;
 
 #ifndef __KERNEL_GPU__
 	float4 operator[](int i) const { return *(&x + i); }
@@ -37,32 +37,16 @@ typedef struct Transform {
 #endif
 } Transform;
 
-/* transform decomposed in rotation/translation/scale. we use the same data
+/* Transform decomposed in rotation/translation/scale. we use the same data
  * structure as Transform, and tightly pack decomposition into it. first the
  * rotation (4), then translation (3), then 3x3 scale matrix (9). */
 
-typedef struct ccl_may_alias MotionTransform {
-	Transform pre;
-	Transform mid;
-	Transform post;
-} MotionTransform;
-
-typedef struct PerspectiveMotionTransform {
-	Transform pre;
-	Transform post;
-} PerspectiveMotionTransform;
+typedef struct DecomposedTransform {
+	float4 x, y, z, w;
+} DecomposedTransform;
 
 /* Functions */
 
-ccl_device_inline float3 transform_perspective(const Transform *t, const float3 a)
-{
-	float4 b = make_float4(a.x, a.y, a.z, 1.0f);
-	float3 c = make_float3(dot(t->x, b), dot(t->y, b), dot(t->z, b));
-	float w = dot(t->w, b);
-
-	return (w != 0.0f)? c/w: make_float3(0.0f, 0.0f, 0.0f);
-}
-
 ccl_device_inline float3 transform_point(const Transform *t, const float3 a)
 {
 	/* TODO(sergey): Disabled for now, causes crashes in certain cases. */
@@ -73,7 +57,7 @@ ccl_device_inline float3 transform_point(const Transform *t, const float3 a)
 	x = _mm_loadu_ps(&t->x.x);
 	y = _mm_loadu_ps(&t->y.x);
 	z = _mm_loadu_ps(&t->z.x);
-	w = _mm_loadu_ps(&t->w.x);
+	w = _mm_set_ps(1.0f, 0.0f, 0.0f, 0.0f);
 
 	_MM_TRANSPOSE4_PS(x, y, z, w);
 
@@ -129,29 +113,15 @@ ccl_device_inline float3 transform_direction_transposed(const Transform *t, cons
 	return make_float3(dot(x, a), dot(y, a), dot(z, a));
 }
 
-ccl_device_inline Transform transform_transpose(const Transform a)
-{
-	Transform t;
-
-	t.x.x = a.x.x; t.x.y = a.y.x; t.x.z = a.z.x; t.x.w = a.w.x;
-	t.y.x = a.x.y; t.y.y = a.y.y; t.y.z = a.z.y; t.y.w = a.w.y;
-	t.z.x = a.x.z; t.z.y = a.y.z; t.z.z = a.z.z; t.z.w = a.w.z;
-	t.w.x = a.x.w; t.w.y = a.y.w; t.w.z = a.z.w; t.w.w = a.w.w;
-
-	return t;
-}
-
 ccl_device_inline Transform make_transform(float a, float b, float c, float d,
                                            float e, float f, float g, float h,
-                                           float i, float j, float k, float l,
-                                           float m, float n, float o, float p)
+                                           float i, float j, float k, float l)
 {
 	Transform t;
 
 	t.x.x = a; t.x.y = b; t.x.z = c; t.x.w = d;
 	t.y.x = e; t.y.y = f; t.y.z = g; t.y.w = h;
 	t.z.x = i; t.z.y = j; t.z.z = k; t.z.w = l;
-	t.w.x = m; t.w.y = n; t.w.z = o; t.w.w = p;
 
 	return t;
 }
@@ -165,21 +135,22 @@ ccl_device_inline Transform make_transform_frame(float3 N)
 	const float3 dy = normalize(cross(N, dx));
 	return make_transform(dx.x, dx.y, dx.z, 0.0f,
 	                      dy.x, dy.y, dy.z, 0.0f,
-	                      N.x , N.y,  N.z,  0.0f,
-	                      0.0f, 0.0f, 0.0f, 1.0f);
+	                      N.x , N.y,  N.z,  0.0f);
 }
 
 #ifndef __KERNEL_GPU__
 
 ccl_device_inline Transform operator*(const Transform a, const Transform b)
 {
-	Transform c = transform_transpose(b);
-	Transform t;
+	float4 c_x = make_float4(b.x.x, b.y.x, b.z.x, 0.0f);
+	float4 c_y = make_float4(b.x.y, b.y.y, b.z.y, 0.0f);
+	float4 c_z = make_float4(b.x.z, b.y.z, b.z.z, 0.0f);
+	float4 c_w = make_float4(b.x.w, b.y.w, b.z.w, 1.0f);
 
-	t.x = make_float4(dot(a.x, c.x), dot(a.x, c.y), dot(a.x, c.z), dot(a.x, c.w));
-	t.y = make_float4(dot(a.y, c.x), dot(a.y, c.y), dot(a.y, c.z), dot(a.y, c.w));
-	t.z = make_float4(dot(a.z, c.x), dot(a.z, c.y), dot(a.z, c.z), dot(a.z, c.w));
-	t.w = make_float4(dot(a.w, c.x), dot(a.w, c.y), dot(a.w, c.z), dot(a.w, c.w));
+	Transform t;
+	t.x = make_float4(dot(a.x, c_x), dot(a.x, c_y), dot(a.x, c_z), dot(a.x, c_w));
+	t.y = make_float4(dot(a.y, c_x), dot(a.y, c_y), dot(a.y, c_z), dot(a.y, c_w));
+	t.z = make_float4(dot(a.z, c_x), dot(a.z, c_y), dot(a.z, c_z), dot(a.z, c_w));
 
 	return t;
 }
@@ -189,7 +160,6 @@ ccl_device_inline void print_transform(const char *label, const Transform& t)
 	print_float4(label, t.x);
 	print_float4(label, t.y);
 	print_float4(label, t.z);
-	print_float4(label, t.w);
 	printf("\n");
 }
 
@@ -198,8 +168,7 @@ ccl_device_inline Transform transform_translate(float3 t)
 	return make_transform(
 		1, 0, 0, t.x,
 		0, 1, 0, t.y,
-		0, 0, 1, t.z,
-		0, 0, 0, 1);
+		0, 0, 1, t.z);
 }
 
 ccl_device_inline Transform transform_translate(float x, float y, float z)
@@ -212,8 +181,7 @@ ccl_device_inline Transform transform_scale(float3 s)
 	return make_transform(
 		s.x, 0, 0, 0,
 		0, s.y, 0, 0,
-		0, 0, s.z, 0,
-		0, 0, 0, 1);
+		0, 0, s.z, 0);
 }
 
 ccl_device_inline Transform transform_scale(float x, float y, float z)
@@ -221,21 +189,6 @@ ccl_device_inline Transform transform_scale(float x, float y, float z)
 	return transform_scale(make_float3(x, y, z));
 }
 
-ccl_device_inline Transform transform_perspective(float fov, float n, float f)
-{
-	Transform persp = make_transform(
-		1, 0, 0, 0,
-		0, 1, 0, 0,
-		0, 0, f / (f - n), -f*n / (f - n),
-		0, 0, 1, 0);
-
-	float inv_angle = 1.0f/tanf(0.5f*fov);
-
-	Transform scale = transform_scale(inv_angle, inv_angle, 1);
-
-	return scale * persp;
-}
-
 ccl_device_inline Transform transform_rotate(float angle, float3 axis)
 {
 	float s = sinf(angle);
@@ -258,9 +211,7 @@ ccl_device_inline Transform transform_rotate(float angle, float3 axis)
 		axis.z*axis.x*t - s*axis.y,
 		axis.z*axis.y*t + s*axis.x,
 		axis.z*axis.z*t + c,
-		0.0f,
-
-		0.0f, 0.0f, 0.0f, 1.0f);
+		0.0f);
 }
 
 /* Euler is assumed to be in XYZ order. */
@@ -272,12 +223,6 @@ ccl_device_inline Transform transform_euler(float3 euler)
 		transform_rotate(euler.x, make_float3(1.0f, 0.0f, 0.0f));
 }
 
-ccl_device_inline Transform transform_orthographic(float znear, float zfar)
-{
-	return transform_scale(1.0f, 1.0f, 1.0f / (zfar-znear)) *
-		transform_translate(0.0f, 0.0f, -znear);
-}
-
 ccl_device_inline Transform transform_identity()
 {
 	return transform_scale(1.0f, 1.0f, 1.0f);
@@ -306,20 +251,20 @@ ccl_device_inline void transform_set_column(Transform *t, int column, float3 val
 }
 
 Transform transform_inverse(const Transform& a);
+Transform transform_transposed_inverse(const Transform& a);
 
 ccl_device_inline bool transform_uniform_scale(const Transform& tfm, float& scale)
 {
 	/* the epsilon here is quite arbitrary, but this function is only used for
-	 * surface area and bump, where we except it to not be so sensitive */
-	Transform ttfm = transform_transpose(tfm);
+	 * surface area and bump, where we expect it to not be so sensitive */
 	float eps = 1e-6f;
 	
 	float sx = len_squared(float4_to_float3(tfm.x));
 	float sy = len_squared(float4_to_float3(tfm.y));
 	float sz = len_squared(float4_to_float3(tfm.z));
-	float stx = len_squared(float4_to_float3(ttfm.x));
-	float sty = len_squared(float4_to_float3(ttfm.y));
-	float stz = len_squared(float4_to_float3(ttfm.z));
+	float stx = len_squared(transform_get_column(&tfm, 0));
+	float sty = len_squared(transform_get_column(&tfm, 1));
+	float stz = len_squared(transform_get_column(&tfm, 2));
 
 	if(fabsf(sx - sy) < eps && fabsf(sx - sz) < eps &&
 	   fabsf(sx - stx) < eps && fabsf(sx - sty) < eps &&
@@ -355,7 +300,6 @@ ccl_device_inline Transform transform_clear_scale(const Transform& tfm)
 ccl_device_inline Transform transform_empty()
 {
 	return make_transform(
-		0, 0, 0, 0,
 		0, 0, 0, 0,
 		0, 0, 0, 0,
 		0, 0, 0, 0);
@@ -414,12 +358,11 @@ ccl_device_inline Transform transform_quick_inverse(Transform M)
 	R.x = make_float4(Rx.x, Rx.y, Rx.z, dot(Rx, T));
 	R.y = make_float4(Ry.x, Ry.y, Ry.z, dot(Ry, T));
 	R.z = make_float4(Rz.x, Rz.y, Rz.z, dot(Rz, T));
-	R.w = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
 
 	return R;
 }
 
-ccl_device_inline void transform_compose(Transform *tfm, const Transform *decomp)
+ccl_device_inline void transform_compose(Transform *tfm, const DecomposedTransform *decomp)
 {
 	/* rotation */
 	float q0, q1, q2, q3, qda, qdb, qdc, qaa, qab, qac, qbb, qbc, qcc;
@@ -452,114 +395,64 @@ ccl_device_inline void transform_compose(Transform *tfm, const Transform *decomp
 	tfm->x = make_float4(dot(rotation_x, scale_x), dot(rotation_x, scale_y), dot(rotation_x, scale_z), decomp->y.x);
 	tfm->y = make_float4(dot(rotation_y, scale_x), dot(rotation_y, scale_y), dot(rotation_y, scale_z), decomp->y.y);
 	tfm->z = make_float4(dot(rotation_z, scale_x), dot(rotation_z, scale_y), dot(rotation_z, scale_z), decomp->y.z);
-	tfm->w = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
 }
 
-/* Disabled for now, need arc-length parametrization for constant speed motion.
- * #define CURVED_MOTION_INTERPOLATE */
-
-ccl_device void transform_motion_interpolate(Transform *tfm, const MotionTransform *motion, float t)
+/* Interpolate from array of decomposed transforms. */
+ccl_device void transform_motion_array_interpolate(Transform *tfm,
+                                                   const ccl_global DecomposedTransform *motion,
+                                                   uint numsteps,
+                                                   float time)
 {
-	/* possible optimization: is it worth it adding a check to skip scaling?
-	 * it's probably quite uncommon to have scaling objects. or can we skip
-	 * just shearing perhaps? */
-	Transform decomp;
-
-#ifdef CURVED_MOTION_INTERPOLATE
-	/* 3 point bezier curve interpolation for position */
-	float3 Ppre = float4_to_float3(motion->pre.y);
-	float3 Pmid = float4_to_float3(motion->mid.y);
-	float3 Ppost = float4_to_float3(motion->post.y);
-
-	float3 Pcontrol = 2.0f*Pmid - 0.5f*(Ppre + Ppost);
-	float3 P = Ppre*t*t + Pcontrol*2.0f*t*(1.0f - t) + Ppost*(1.0f - t)*(1.0f - t);
-
-	decomp.y.x = P.x;
-	decomp.y.y = P.y;
-	decomp.y.z = P.z;
-#endif
-
-	/* linear interpolation for rotation and scale */
-	if(t < 0.5f) {
-		t *= 2.0f;
+	/* Figure out which steps we need to interpolate. */
+	int maxstep = numsteps-1;
+	int step = min((int)(time*maxstep), maxstep-1);
+	float t = time*maxstep - step;
 
-		decomp.x = quat_interpolate(motion->pre.x, motion->mid.x, t);
-#ifdef CURVED_MOTION_INTERPOLATE
-		decomp.y.w = (1.0f - t)*motion->pre.y.w + t*motion->mid.y.w;
-#else
-		decomp.y = (1.0f - t)*motion->pre.y + t*motion->mid.y;
-#endif
-		decomp.z = (1.0f - t)*motion->pre.z + t*motion->mid.z;
-		decomp.w = (1.0f - t)*motion->pre.w + t*motion->mid.w;
-	}
-	else {
-		t = (t - 0.5f)*2.0f;
+	const ccl_global DecomposedTransform *a = motion + step;
+	const ccl_global DecomposedTransform *b = motion + step + 1;
 
-		decomp.x = quat_interpolate(motion->mid.x, motion->post.x, t);
-#ifdef CURVED_MOTION_INTERPOLATE
-		decomp.y.w = (1.0f - t)*motion->mid.y.w + t*motion->post.y.w;
-#else
-		decomp.y = (1.0f - t)*motion->mid.y + t*motion->post.y;
-#endif
-		decomp.z = (1.0f - t)*motion->mid.z + t*motion->post.z;
-		decomp.w = (1.0f - t)*motion->mid.w + t*motion->post.w;
-	}
+	/* Interpolate rotation, translation and scale. */
+	DecomposedTransform decomp;
+	decomp.x = quat_interpolate(a->x, b->x, t);
+	decomp.y = (1.0f - t)*a->y + t*b->y;
+	decomp.z = (1.0f - t)*a->z + t*b->z;
+	decomp.w = (1.0f - t)*a->w + t*b->w;
 
-	/* compose rotation, translation, scale into matrix */
+	/* Compose rotation, translation, scale into matrix. */
 	transform_compose(tfm, &decomp);
 }
 
-ccl_device void transform_motion_interpolate_straight(Transform *tfm, const MotionTransform *motion, float t)
+ccl_device void transform_motion_array_interpolate_straight(Transform *tfm, const ccl_global DecomposedTransform *motion, uint numsteps, float time)
 {
-	Transform decomp;
-	Transform step1, step2;
-
-	decomp.x = motion->mid.x;
-	decomp.y = motion->mid.y;
-	decomp.z = motion->mid.z;
-	decomp.w = motion->mid.w;
-
-	/* linear interpolation for rotation and scale */
-	if(t < 0.5f) {
-		t *= 2.0f;
+	/* Figure out which steps we need to interpolate. */
+	int maxstep = numsteps - 1;
+	int step = min((int)(time*maxstep), maxstep - 1);
+	float t = time * maxstep - step;
 
-		transform_compose(&step2, &decomp);
-
-		decomp.x = motion->pre.x;
-		decomp.y = motion->pre.y;
-
-		transform_compose(&step1, &decomp);
-	}
-	else {
-		t = (t - 0.5f)*2.0f;
-
-		transform_compose(&step1, &decomp);
+	const ccl_global DecomposedTransform *a = motion + step;
+	const ccl_global DecomposedTransform *b = motion + step + 1;
+	Transform step1, step2;
 
-		decomp.x = motion->post.x;
-		decomp.y = motion->post.y;
-
-		transform_compose(&step2, &decomp);
-	}
+	transform_compose(&step1, a);
+	transform_compose(&step2, b);
 
 	/* matrix lerp */
 	tfm->x = (1.0f - t) * step1.x + t * step2.x;
 	tfm->y = (1.0f - t) * step1.y + t * step2.y;
 	tfm->z = (1.0f - t) * step1.z + t * step2.z;
-	tfm->w = (1.0f - t) * step1.w + t * step2.w;
-
 }
 
 #ifndef __KERNEL_GPU__
 
 class BoundBox2D;
 
-ccl_device_inline bool operator==(const MotionTransform& A, const MotionTransform& B)
+ccl_device_inline bool operator==(const DecomposedTransform& A, const DecomposedTransform& B)
 {
-	return (A.pre == B.pre && A.post == B.post);
+	return memcmp(&A, &B, sizeof(DecomposedTransform)) == 0;
 }
 
 float4 transform_to_quat(const Transform& tfm);
-void transform_motion_decompose(MotionTransform *decomp, const MotionTransform *motion, const Transform *mid);
+void transform_motion_decompose(DecomposedTransform *decomp, const Transform *motion, size_t size);
 Transform transform_from_viewplane(BoundBox2D& viewplane);
 
 #endif
diff --git a/intern/cycles/util/util_vector.h b/intern/cycles/util/util_vector.h
index 625c19c7c46422c156daddc8e7861058e3fd2cc8..e98e4e3418141a287995a1a8f0e2cc018b19ab1d 100644
--- a/intern/cycles/util/util_vector.h
+++ b/intern/cycles/util/util_vector.h
@@ -215,6 +215,18 @@ public:
 		return data_;
 	}
 
+	T* resize(size_t newsize, const T& value)
+	{
+		size_t oldsize = size();
+		resize(newsize);
+
+		for(size_t i = oldsize; i < size(); i++) {
+			data_[i] = value;
+		}
+
+		return data_;
+	}
+
 	void clear()
 	{
 		if(data_ != NULL) {
diff --git a/intern/ffmpeg/ffmpeg_compat.h b/intern/ffmpeg/ffmpeg_compat.h
index 9c06c8a6d67ccd44119880f91240b1a781a18ef4..1eb6c3ba2dca1aff0660eae270c7575334850686 100644
--- a/intern/ffmpeg/ffmpeg_compat.h
+++ b/intern/ffmpeg/ffmpeg_compat.h
@@ -48,6 +48,16 @@
 
 #include <libswscale/swscale.h>
 
+/* Stupid way to distinguish FFmpeg from Libav:
+ * - FFmpeg's MICRO version starts from 100 and goes up, while
+ * - Libav's micro is always below 100.
+ */
+#if LIBAVCODEC_VERSION_MICRO >= 100
+#  define AV_USING_FFMPEG
+#else
+#  define AV_USING_LIBAV
+#endif
+
 #if (LIBAVFORMAT_VERSION_MAJOR > 52) || ((LIBAVFORMAT_VERSION_MAJOR >= 52) && (LIBAVFORMAT_VERSION_MINOR >= 105))
 #  define FFMPEG_HAVE_AVIO 1
 #endif
@@ -428,8 +438,45 @@ void av_frame_free(AVFrame **frame)
 #endif
 
 FFMPEG_INLINE
-AVRational av_get_r_frame_rate_compat(const AVStream *stream)
+const char* av_get_metadata_key_value(AVDictionary *metadata, const char *key)
 {
+	if (metadata == NULL) {
+		return NULL;
+	}
+	AVDictionaryEntry *tag = NULL;
+	while ((tag = av_dict_get(metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {
+		if (!strcmp(tag->key, key)) {
+			return tag->value;
+		}
+	}
+	return NULL;
+}
+
+FFMPEG_INLINE
+bool av_check_encoded_with_ffmpeg(AVFormatContext *ctx)
+{
+	const char* encoder = av_get_metadata_key_value(ctx->metadata, "ENCODER");
+	if (encoder != NULL && !strncmp(encoder, "Lavf", 4)) {
+		return true;
+	}
+	return false;
+}
+
+FFMPEG_INLINE
+AVRational av_get_r_frame_rate_compat(AVFormatContext *ctx,
+                                      const AVStream *stream)
+{
+	/* If the video is encoded with FFmpeg and we are decoding with FFmpeg
+	 * as well it seems to be more reliable to use r_frame_rate (tbr).
+	 *
+	 * For other cases we fall back to avg_frame_rate (fps) when possible.
+	 */
+#ifdef AV_USING_FFMPEG
+	if (av_check_encoded_with_ffmpeg(ctx)) {
+		return stream->r_frame_rate;
+	}
+#endif
+
 #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 23, 1)
 	/* For until r_frame_rate was deprecated use it. */
 	return stream->r_frame_rate;
diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt
index 5a97da28d1752624b2fab233537356d61bbfc16c..ba569ff4166b5d2acb27f6ff4409ecd97bad4c2f 100644
--- a/intern/ghost/CMakeLists.txt
+++ b/intern/ghost/CMakeLists.txt
@@ -177,10 +177,12 @@ elseif(WITH_X11)
 		intern/GHOST_DisplayManagerX11.cpp
 		intern/GHOST_SystemX11.cpp
 		intern/GHOST_WindowX11.cpp
+		intern/GHOST_TaskbarX11.cpp
 
 		intern/GHOST_DisplayManagerX11.h
 		intern/GHOST_SystemX11.h
 		intern/GHOST_WindowX11.h
+		intern/GHOST_TaskbarX11.h
 	)
 
 	if(NOT WITH_GL_EGL)
diff --git a/intern/ghost/intern/GHOST_TaskbarX11.cpp b/intern/ghost/intern/GHOST_TaskbarX11.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b47068df39f51517d23f3eac521e2be349baaf08
--- /dev/null
+++ b/intern/ghost/intern/GHOST_TaskbarX11.cpp
@@ -0,0 +1,130 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s):
+ *   Lukas Stockner
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file ghost/intern/GHOST_TaskbarX11.cpp
+ *  \ingroup GHOST
+ */
+
+#include "GHOST_TaskbarX11.h"
+
+#include <dlfcn.h>
+#include <cstdio>
+#include <cassert>
+#include <cstdlib>
+
+typedef void*(*unity_get_entry_t)(const char*);
+typedef void(*unity_set_progress_t)(void*, double);
+typedef void(*unity_set_progress_visible_t)(void*, int);
+typedef int(*unity_event_loop_t)(void*, int);
+
+static unity_get_entry_t unity_get_entry;
+static unity_set_progress_t unity_set_progress;
+static unity_set_progress_visible_t unity_set_progress_visible;
+static unity_event_loop_t unity_event_loop;
+
+static bool libunity_initialized = false;
+static bool libunity_available = false;
+void* libunity_handle = NULL;
+
+void GHOST_TaskBarX11::free()
+{
+	if(libunity_handle) {
+		dlclose(libunity_handle);
+		libunity_handle = NULL;
+	}
+}
+
+bool GHOST_TaskBarX11::init()
+{
+	if(libunity_initialized) {
+		return libunity_available;
+	}
+
+	libunity_initialized = true;
+
+	const char *libunity_names[] = {"libunity.so.4", "libunity.so.6", "libunity.so.9", "libunity.so", NULL};
+	for(int i = 0; libunity_names[i]; i++) {
+		libunity_handle = dlopen(libunity_names[i], RTLD_LAZY);
+		if(libunity_handle) {
+			break;
+		}
+	}
+
+	if(!libunity_handle) {
+		return false;
+	}
+
+	unity_get_entry = (unity_get_entry_t) dlsym(libunity_handle, "unity_launcher_entry_get_for_desktop_id");
+	if(!unity_get_entry) {
+		fprintf(stderr, "failed to load libunity: %s\n", dlerror());
+		return false;
+	}
+	unity_set_progress = (unity_set_progress_t) dlsym(libunity_handle, "unity_launcher_entry_set_progress");
+	if(!unity_set_progress) {
+		fprintf(stderr, "failed to load libunity: %s\n", dlerror());
+		return false;
+	}
+	unity_set_progress_visible = (unity_set_progress_visible_t) dlsym(libunity_handle, "unity_launcher_entry_set_progress_visible");
+	if(!unity_set_progress_visible) {
+		fprintf(stderr, "failed to load libunity: %s\n", dlerror());
+		return false;
+	}
+	unity_event_loop = (unity_event_loop_t) dlsym(libunity_handle, "g_main_context_iteration");
+	if(!unity_event_loop) {
+		fprintf(stderr, "failed to load libunity: %s\n", dlerror());
+		return false;
+	}
+
+	atexit(GHOST_TaskBarX11::free);
+
+	libunity_available = true;
+	return true;
+}
+
+GHOST_TaskBarX11::GHOST_TaskBarX11(const char *name)
+{
+	if(GHOST_TaskBarX11::init()) {
+		handle = unity_get_entry(name);
+	}
+	else {
+		handle = NULL;
+	}
+}
+
+bool GHOST_TaskBarX11::is_valid()
+{
+	return (handle != NULL);
+}
+
+void GHOST_TaskBarX11::set_progress(double progress)
+{
+	assert(is_valid());
+	unity_set_progress(handle, progress);
+}
+
+void GHOST_TaskBarX11::set_progress_enabled(bool enabled)
+{
+	assert(is_valid());
+	unity_set_progress_visible(handle, enabled ? 1 : 0);
+	unity_event_loop(NULL, 0);
+}
\ No newline at end of file
diff --git a/intern/ghost/intern/GHOST_TaskbarX11.h b/intern/ghost/intern/GHOST_TaskbarX11.h
new file mode 100644
index 0000000000000000000000000000000000000000..ed0e5f9b3295cd6043c0b46c63b66235b7a2b77c
--- /dev/null
+++ b/intern/ghost/intern/GHOST_TaskbarX11.h
@@ -0,0 +1,45 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s):
+ *   Lukas Stockner
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file ghost/intern/GHOST_TaskbarX11.h
+ *  \ingroup GHOST
+ */
+#ifndef __GHOST_TASKBARX11_H__
+#define __GHOST_TASKBARX11_H__
+
+class GHOST_TaskBarX11
+{
+public:
+	static bool init();
+	static void free();
+
+	GHOST_TaskBarX11(const char *name);
+
+	bool is_valid();
+	void set_progress(double progress);
+	void set_progress_enabled(bool enabled);
+private:
+	void *handle;
+};
+
+#endif /*__GHOST_TASKBARX11_H__*/
diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp
index 1abdec374035854d198ff0dc97cf2b6629274e1a..13fef7d1db1d5fd0cf13805d85dad0ef692015c9 100644
--- a/intern/ghost/intern/GHOST_WindowX11.cpp
+++ b/intern/ghost/intern/GHOST_WindowX11.cpp
@@ -334,6 +334,7 @@ GHOST_WindowX11(GHOST_SystemX11 *system,
       m_empty_cursor(None),
       m_custom_cursor(None),
       m_visible_cursor(None),
+      m_taskbar("blender.desktop"),
 #ifdef WITH_XDND
       m_dropTarget(NULL),
 #endif
@@ -1717,3 +1718,24 @@ getDPIHint()
 	int dpi = pixelDiagonal / inchDiagonal;
 	return dpi;
 }
+
+GHOST_TSuccess GHOST_WindowX11::setProgressBar(float progress)
+{
+	if (m_taskbar.is_valid()) {
+		m_taskbar.set_progress(progress);
+		m_taskbar.set_progress_enabled(true);
+		return GHOST_kSuccess;
+	}
+
+	return GHOST_kFailure;
+}
+
+GHOST_TSuccess GHOST_WindowX11::endProgressBar()
+{
+	if (m_taskbar.is_valid()) {
+		m_taskbar.set_progress_enabled(false);
+		return GHOST_kSuccess;
+	}
+
+	return GHOST_kFailure;
+}
diff --git a/intern/ghost/intern/GHOST_WindowX11.h b/intern/ghost/intern/GHOST_WindowX11.h
index 5c54c1e8162bb3746ca20f12a90234db2c43c6a3..236fe0b76b00cce36d3dce00b133a0473c34ffbd 100644
--- a/intern/ghost/intern/GHOST_WindowX11.h
+++ b/intern/ghost/intern/GHOST_WindowX11.h
@@ -41,6 +41,8 @@
 #  include <X11/extensions/XInput.h>
 #endif
 
+#include "GHOST_TaskbarX11.h"
+
 #include <map>
 
 class STR_String;
@@ -166,6 +168,9 @@ public:
 	invalidate(
 	    );
 
+	GHOST_TSuccess setProgressBar(float progress);
+	GHOST_TSuccess endProgressBar();
+
 	/**
 	 * Destructor.
 	 * Closes the window and disposes resources allocated.
@@ -347,6 +352,8 @@ private:
 	/** Cache of XC_* ID's to XCursor structures */
 	std::map<unsigned int, Cursor> m_standard_cursors;
 
+	GHOST_TaskBarX11 m_taskbar;
+
 #ifdef WITH_XDND
 	GHOST_DropTargetX11 *m_dropTarget;
 #endif
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index ce3d6fffbb3eb5bfcc727022b1ad7ed721307ac9..e61a6abbbca51a14c37184e35257858c90d39e62 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -1513,12 +1513,15 @@ class USERPREF_PT_addons(Panel):
                             split.operator(
                                 "wm.url_open", text="Documentation", icon='HELP',
                             ).url = info["wiki_url"]
-                        split.operator(
-                            "wm.url_open", text="Report a Bug", icon='URL',
-                        ).url = info.get(
-                            "tracker_url",
-                            "https://developer.blender.org/maniphest/task/edit/form/2",
-                        )
+                        # Only add "Report a Bug" button if tracker_url is set
+                        # or the add-on is bundled (use official tracker then).
+                        if info.get("tracker_url") or not user_addon:
+                            split.operator(
+                                "wm.url_open", text="Report a Bug", icon='URL',
+                            ).url = info.get(
+                                "tracker_url",
+                                "https://developer.blender.org/maniphest/task/edit/form/2",
+                            )
                         if user_addon:
                             split.operator(
                                 "wm.addon_remove", text="Remove", icon='CANCEL',
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 6cd93e19e95d9a3cc5f4682fe9555952fe0c12ba..b5d906b2968cbc4c96d7c93f2a9f7ef750120a4e 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -28,7 +28,7 @@
  * and keep comment above the defines.
  * Use STRINGIFY() rather than defining with quotes */
 #define BLENDER_VERSION         279
-#define BLENDER_SUBVERSION      3
+#define BLENDER_SUBVERSION      4
 /* Several breakages with 270, e.g. constraint deg vs rad */
 #define BLENDER_MINVERSION      270
 #define BLENDER_MINSUBVERSION   6
diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h
index f3d44164b1e493423e21f878a5689ce3dbf91633..832b41646131e91eb8f2c63da1263bd368d47493 100644
--- a/source/blender/blenkernel/BKE_global.h
+++ b/source/blender/blenkernel/BKE_global.h
@@ -125,12 +125,17 @@ enum {
 	G_DEBUG_DEPSGRAPH_BUILD      = (1 << 8),   /* depsgraph construction messages */
 	G_DEBUG_DEPSGRAPH_EVAL       = (1 << 9),   /* depsgraph evaluation messages */
 	G_DEBUG_DEPSGRAPH_TAG        = (1 << 10),  /* depsgraph tagging messages */
-	G_DEBUG_DEPSGRAPH_NO_THREADS = (1 << 11),  /* single threaded depsgraph */
-	G_DEBUG_DEPSGRAPH = (G_DEBUG_DEPSGRAPH_BUILD | G_DEBUG_DEPSGRAPH_EVAL | G_DEBUG_DEPSGRAPH_TAG),
-	G_DEBUG_SIMDATA =   (1 << 12), /* sim debug data display */
-	G_DEBUG_GPU_MEM =   (1 << 13), /* gpu memory in status bar */
-	G_DEBUG_GPU =       (1 << 14), /* gpu debug */
-	G_DEBUG_IO = (1 << 15),   /* IO Debugging (for Collada, ...)*/
+	G_DEBUG_DEPSGRAPH_TIME       = (1 << 11),  /* depsgraph timing statistics and messages */
+	G_DEBUG_DEPSGRAPH_NO_THREADS = (1 << 12),  /* single threaded depsgraph */
+	G_DEBUG_DEPSGRAPH_PRETTY     = (1 << 13),  /* use pretty colors in depsgraph messages */
+	G_DEBUG_DEPSGRAPH = (G_DEBUG_DEPSGRAPH_BUILD |
+	                     G_DEBUG_DEPSGRAPH_EVAL |
+	                     G_DEBUG_DEPSGRAPH_TAG |
+	                     G_DEBUG_DEPSGRAPH_TIME),
+	G_DEBUG_SIMDATA =   (1 << 14), /* sim debug data display */
+	G_DEBUG_GPU_MEM =   (1 << 15), /* gpu memory in status bar */
+	G_DEBUG_GPU =       (1 << 16), /* gpu debug */
+	G_DEBUG_IO = (1 << 17),   /* IO Debugging (for Collada, ...)*/
 };
 
 #define G_DEBUG_ALL  (G_DEBUG | G_DEBUG_FFMPEG | G_DEBUG_PYTHON | G_DEBUG_EVENTS | G_DEBUG_WM | G_DEBUG_JOBS | \
diff --git a/source/blender/blenkernel/BKE_icons.h b/source/blender/blenkernel/BKE_icons.h
index 39e6b1457552f24eab047b73a448d60e7d090baa..a9ca5cc8bbbc32d1d484f63aedf998adfe3e1551 100644
--- a/source/blender/blenkernel/BKE_icons.h
+++ b/source/blender/blenkernel/BKE_icons.h
@@ -58,19 +58,19 @@ int BKE_icon_id_ensure(struct ID *id);
 int BKE_icon_preview_ensure(struct ID *id, struct PreviewImage *preview);
 
 /* retrieve icon for id */
-struct Icon *BKE_icon_get(int icon_id);
+struct Icon *BKE_icon_get(const int icon_id);
 
 /* set icon for id if not already defined */
 /* used for inserting the internal icons */
-void BKE_icon_set(int icon_id, struct Icon *icon);
+void BKE_icon_set(const int icon_id, struct Icon *icon);
 
 /* remove icon and free data if library object becomes invalid */
 void BKE_icon_id_delete(struct ID *id);
 
-void BKE_icon_delete(int icon_id);
+void BKE_icon_delete(const int icon_id);
 
 /* report changes - icon needs to be recalculated */
-void BKE_icon_changed(int icon_id);
+void BKE_icon_changed(const int icon_id);
 
 /* free all icons */
 void BKE_icons_free(void);
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 05ba3ac1df4a7c9ff395ca45d7ce5c4ec8ba50ec..efad8e48e3dd7f6e430862f655d903b45d5ff4f1 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -573,7 +573,6 @@ void            BKE_node_preview_set_pixel(struct bNodePreview *preview, const f
 
 /** \} */
 
-
 /* -------------------------------------------------------------------- */
 /** \name Node Type Access
  * \{ */
@@ -603,6 +602,7 @@ void            node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpufu
 void            node_type_internal_links(struct bNodeType *ntype, void (*update_internal_links)(struct bNodeTree *, struct bNode *));
 void            node_type_compatibility(struct bNodeType *ntype, short compatibility);
 
+/** \} */
 
 /* -------------------------------------------------------------------- */
 /** \name Node Generic Functions
@@ -692,7 +692,7 @@ bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter,
 
 /* -------------------------------------------------------------------- */
 /** \name Shader Nodes
- */
+ * \{ */
 struct ShadeInput;
 struct ShadeResult;
 
@@ -816,7 +816,7 @@ void            ntreeGPUMaterialNodes(struct bNodeTree *ntree, struct GPUMateria
 
 /* -------------------------------------------------------------------- */
 /** \name Composite Nodes
- */
+ * \{ */
 
 /* output socket defines */
 #define RRES_OUT_IMAGE					0
@@ -1000,7 +1000,7 @@ void ntreeCompositColorBalanceSyncFromCDL(bNodeTree *ntree, bNode *node);
 
 /* -------------------------------------------------------------------- */
 /** \name Texture Nodes
- */
+ * \{ */
 
 struct TexResult;
 
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index 4d232e9ed6ca2d8d1c10938b25117d0ff391a168..5578290c41ab3d69680096557cccd1677bdddf08 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -127,10 +127,12 @@ struct Object *BKE_object_pose_armature_get(struct Object *ob);
 
 void BKE_object_get_parent_matrix(struct Scene *scene, struct Object *ob, struct Object *par, float parentmat[4][4]);
 void BKE_object_where_is_calc(struct Scene *scene, struct Object *ob);
-void BKE_object_where_is_calc_ex(struct Scene *scene, struct RigidBodyWorld *rbw, struct Object *ob, float r_originmat[3][3]);
+void BKE_object_where_is_calc_ex(
+        struct Scene *scene, struct RigidBodyWorld *rbw, struct Object *ob, float r_originmat[3][3]);
 void BKE_object_where_is_calc_time(struct Scene *scene, struct Object *ob, float ctime);
-void BKE_object_where_is_calc_time_ex(struct Scene *scene, struct Object *ob, float ctime,
-                                      struct RigidBodyWorld *rbw, float r_originmat[3][3]);
+void BKE_object_where_is_calc_time_ex(
+        struct Scene *scene, struct Object *ob, float ctime,
+        struct RigidBodyWorld *rbw, float r_originmat[3][3]);
 void BKE_object_where_is_calc_mat4(struct Scene *scene, struct Object *ob, float obmat[4][4]);
 
 /* possibly belong in own moduke? */
@@ -146,15 +148,18 @@ void BKE_object_dimensions_set(struct Object *ob, const float value[3]);
 void BKE_object_empty_draw_type_set(struct Object *ob, const int value);
 void BKE_object_boundbox_flag(struct Object *ob, int flag, const bool set);
 void BKE_object_minmax(struct Object *ob, float r_min[3], float r_max[3], const bool use_hidden);
-bool BKE_object_minmax_dupli(struct Scene *scene, struct Object *ob, float r_min[3], float r_max[3], const bool use_hidden);
+bool BKE_object_minmax_dupli(
+        struct Scene *scene, struct Object *ob, float r_min[3], float r_max[3], const bool use_hidden);
 
 /* sometimes min-max isn't enough, we need to loop over each point */
-void BKE_object_foreach_display_point(struct Object *ob, float obmat[4][4],
-                                      void (*func_cb)(const float[3], void *), void *user_data);
-void BKE_scene_foreach_display_point(struct Scene *scene,
-                                     struct View3D *v3d,
-                                     const short flag,
-                                     void (*func_cb)(const float[3], void *), void *user_data);
+void BKE_object_foreach_display_point(
+        struct Object *ob, float obmat[4][4],
+        void (*func_cb)(const float[3], void *), void *user_data);
+void BKE_scene_foreach_display_point(
+        struct Scene *scene,
+        struct View3D *v3d,
+        const short flag,
+        void (*func_cb)(const float[3], void *), void *user_data);
 
 bool BKE_object_parent_loop_check(const struct Object *parent, const struct Object *ob);
 
@@ -170,49 +175,61 @@ typedef struct ObjectTfmProtectedChannels {
 	float rotAngle,   drotAngle;
 } ObjectTfmProtectedChannels;
 
-void BKE_object_tfm_protected_backup(const struct Object *ob,
-                                     ObjectTfmProtectedChannels *obtfm);
+void BKE_object_tfm_protected_backup(
+        const struct Object *ob,
+        ObjectTfmProtectedChannels *obtfm);
 
-void BKE_object_tfm_protected_restore(struct Object *ob,
-                                      const ObjectTfmProtectedChannels *obtfm,
-                                      const short protectflag);
+void BKE_object_tfm_protected_restore(
+        struct Object *ob,
+        const ObjectTfmProtectedChannels *obtfm,
+        const short protectflag);
 
 /* Dependency graph evaluation callbacks. */
-void BKE_object_eval_local_transform(struct EvaluationContext *eval_ctx,
-                                     struct Object *ob);
-void BKE_object_eval_parent(struct EvaluationContext *eval_ctx,
-                            struct Scene *scene,
-                            struct Object *ob);
-void BKE_object_eval_constraints(struct EvaluationContext *eval_ctx,
-                                 struct Scene *scene,
-                                 struct Object *ob);
+void BKE_object_eval_local_transform(
+        struct EvaluationContext *eval_ctx,
+        struct Object *ob);
+void BKE_object_eval_parent(
+        struct EvaluationContext *eval_ctx,
+        struct Scene *scene,
+        struct Object *ob);
+void BKE_object_eval_constraints(
+        struct EvaluationContext *eval_ctx,
+        struct Scene *scene,
+        struct Object *ob);
 void BKE_object_eval_done(struct EvaluationContext *eval_ctx, struct Object *ob);
 
-bool BKE_object_eval_proxy_copy(struct EvaluationContext *eval_ctx,
-                                struct Object *object);
-void BKE_object_eval_uber_transform(struct EvaluationContext *eval_ctx,
-                                    struct Object *ob);
-void BKE_object_eval_uber_data(struct EvaluationContext *eval_ctx,
-                               struct Scene *scene,
-                               struct Object *ob);
-
-void BKE_object_eval_cloth(struct EvaluationContext *eval_ctx,
-                           struct Scene *scene,
-                           struct Object *object);
-
-
-void BKE_object_eval_transform_all(struct EvaluationContext *eval_ctx,
-                                   struct Scene *scene,
-                                   struct Object *object);
-
-void BKE_object_handle_data_update(struct EvaluationContext *eval_ctx,
-                                   struct Scene *scene,
-                                   struct Object *ob);
+bool BKE_object_eval_proxy_copy(
+        struct EvaluationContext *eval_ctx,
+        struct Object *object);
+void BKE_object_eval_uber_transform(
+        struct EvaluationContext *eval_ctx,
+        struct Object *ob);
+void BKE_object_eval_uber_data(
+        struct EvaluationContext *eval_ctx,
+        struct Scene *scene,
+        struct Object *ob);
+
+void BKE_object_eval_cloth(
+        struct EvaluationContext *eval_ctx,
+        struct Scene *scene,
+        struct Object *object);
+
+
+void BKE_object_eval_transform_all(
+        struct EvaluationContext *eval_ctx,
+        struct Scene *scene,
+        struct Object *object);
+
+void BKE_object_handle_data_update(
+        struct EvaluationContext *eval_ctx,
+        struct Scene *scene,
+        struct Object *ob);
 void BKE_object_handle_update(struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob);
-void BKE_object_handle_update_ex(struct EvaluationContext *eval_ctx,
-                                 struct Scene *scene, struct Object *ob,
-                                 struct RigidBodyWorld *rbw,
-                                 const bool do_proxy_update);
+void BKE_object_handle_update_ex(
+        struct EvaluationContext *eval_ctx,
+        struct Scene *scene, struct Object *ob,
+        struct RigidBodyWorld *rbw,
+        const bool do_proxy_update);
 void BKE_object_sculpt_modifiers_changed(struct Object *ob);
 
 int BKE_object_obdata_texspace_get(struct Object *ob, short **r_texflag, float **r_loc, float **r_size, float **r_rot);
@@ -255,7 +272,8 @@ typedef enum eObjectSet {
 	OB_SET_ALL       /* All Objects      */
 } eObjectSet;
 
-struct LinkNode *BKE_object_relational_superset(struct Scene *scene, eObjectSet objectSet, eObRelationTypes includeFilter);
+struct LinkNode *BKE_object_relational_superset(
+        struct Scene *scene, eObjectSet objectSet, eObRelationTypes includeFilter);
 struct LinkNode *BKE_object_groups(struct Object *ob);
 void             BKE_object_groups_clear(struct Scene *scene, struct Base *base, struct Object *object);
 
@@ -263,9 +281,10 @@ struct KDTree *BKE_object_as_kdtree(struct Object *ob, int *r_tot);
 
 bool BKE_object_modifier_use_time(struct Object *ob, struct ModifierData *md);
 
-bool BKE_object_modifier_update_subframe(struct Scene *scene, struct Object *ob, bool update_mesh,
-                                         int parent_recursion, float frame,
-                                         int type);
+bool BKE_object_modifier_update_subframe(
+        struct Scene *scene, struct Object *ob, bool update_mesh,
+        int parent_recursion, float frame,
+        int type);
 
 #ifdef __cplusplus
 }
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index 095ef6fa1bdf4a76784c91fd4f3d7895b2142b92..e2c371348e547958bb0d540f5bcad9ace80fd176 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -76,6 +76,8 @@
 
 #include "atomic_ops.h"
 
+#include "DEG_depsgraph.h"
+
 /* ***************************************** */
 /* AnimData API */
 
@@ -2918,15 +2920,13 @@ void BKE_animsys_evaluate_all_animation(Main *main, Scene *scene, float ctime)
 /* ************** */
 /* Evaluation API */
 
-#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) printf
-
 void BKE_animsys_eval_animdata(EvaluationContext *eval_ctx, ID *id)
 {
 	AnimData *adt = BKE_animdata_from_id(id);
 	Scene *scene = NULL; /* XXX: this is only needed for flushing RNA updates,
 	                      * which should get handled as part of the dependency graph instead...
 	                      */
-	DEBUG_PRINT("%s on %s, time=%f\n\n", __func__, id->name, (double)eval_ctx->ctime);
+	DEG_debug_print_eval_time(__func__, id->name, id, eval_ctx->ctime);
 	BKE_animsys_evaluate_animdata(scene, id, adt, eval_ctx->ctime, ADT_RECALC_ANIM);
 }
 
@@ -2939,11 +2939,8 @@ void BKE_animsys_eval_driver(EvaluationContext *eval_ctx,
 	PointerRNA id_ptr;
 	bool ok = false;
 
-	DEBUG_PRINT("%s on %s (%s[%d])\n",
-	            __func__,
-	            id->name,
-	            fcu->rna_path,
-	            fcu->array_index);
+	DEG_debug_print_eval_subdata_index(
+	        __func__, id->name, id, "fcu", fcu->rna_path, fcu, fcu->array_index);
 
 	RNA_id_pointer_create(id, &id_ptr);
 
@@ -2976,5 +2973,3 @@ void BKE_animsys_eval_driver(EvaluationContext *eval_ctx,
 		}
 	}
 }
-
-#undef DEBUG_PRINT
diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c
index 2e9b2f7d20fa526514c1af02d1662ad8137d9868..e6bb0d6b7ce8b1bfeb33876d8d8a2eb74ecab4a4 100644
--- a/source/blender/blenkernel/intern/armature_update.c
+++ b/source/blender/blenkernel/intern/armature_update.c
@@ -53,12 +53,6 @@
 
 #include "DEG_depsgraph.h"
 
-#ifdef WITH_LEGACY_DEPSGRAPH
-#  define DEBUG_PRINT if (!DEG_depsgraph_use_legacy() && G.debug & G_DEBUG_DEPSGRAPH_EVAL) printf
-#else
-#  define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) printf
-#endif
-
 /* ********************** SPLINE IK SOLVER ******************* */
 
 /* Temporary evaluation tree data used for Spline IK */
@@ -565,7 +559,7 @@ void BKE_pose_eval_init(EvaluationContext *UNUSED(eval_ctx),
 {
 	bPoseChannel *pchan;
 
-	DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
+	DEG_debug_print_eval(__func__, ob->id.name, ob);
 
 	BLI_assert(ob->type == OB_ARMATURE);
 
@@ -587,7 +581,7 @@ void BKE_pose_eval_init_ik(EvaluationContext *UNUSED(eval_ctx),
                            Object *ob,
                            bPose *UNUSED(pose))
 {
-	DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
+	DEG_debug_print_eval(__func__, ob->id.name, ob);
 	BLI_assert(ob->type == OB_ARMATURE);
 	const float ctime = BKE_scene_frame_get(scene); /* not accurate... */
 	bArmature *arm = (bArmature *)ob->data;
@@ -608,7 +602,8 @@ void BKE_pose_eval_bone(EvaluationContext *UNUSED(eval_ctx),
                         Object *ob,
                         bPoseChannel *pchan)
 {
-	DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, pchan->name);
+	DEG_debug_print_eval_subdata(
+	        __func__, ob->id.name, ob, "pchan", pchan->name, pchan);
 	BLI_assert(ob->type == OB_ARMATURE);
 	bArmature *arm = (bArmature *)ob->data;
 	if (arm->edbo || (arm->flag & ARM_RESTPOS)) {
@@ -643,7 +638,8 @@ void BKE_pose_constraints_evaluate(EvaluationContext *UNUSED(eval_ctx),
                                    Object *ob,
                                    bPoseChannel *pchan)
 {
-	DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, pchan->name);
+	DEG_debug_print_eval_subdata(
+	        __func__, ob->id.name, ob, "pchan", pchan->name, pchan);
 	bArmature *arm = (bArmature *)ob->data;
 	if (arm->flag & ARM_RESTPOS) {
 		return;
@@ -663,7 +659,7 @@ void BKE_pose_bone_done(EvaluationContext *UNUSED(eval_ctx),
                         bPoseChannel *pchan)
 {
 	float imat[4][4];
-	DEBUG_PRINT("%s on pchan %s\n", __func__, pchan->name);
+	DEG_debug_print_eval(__func__, pchan->name, pchan);
 	if (pchan->bone) {
 		invert_m4_m4(imat, pchan->bone->arm_mat);
 		mul_m4_m4m4(pchan->chan_mat, pchan->pose_mat, imat);
@@ -675,7 +671,8 @@ void BKE_pose_iktree_evaluate(EvaluationContext *UNUSED(eval_ctx),
                               Object *ob,
                               bPoseChannel *rootchan)
 {
-	DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, rootchan->name);
+	DEG_debug_print_eval_subdata(
+	        __func__, ob->id.name, ob, "rootchan", rootchan->name, rootchan);
 	BLI_assert(ob->type == OB_ARMATURE);
 	const float ctime = BKE_scene_frame_get(scene); /* not accurate... */
 	bArmature *arm = (bArmature *)ob->data;
@@ -689,8 +686,10 @@ void BKE_pose_splineik_evaluate(EvaluationContext *UNUSED(eval_ctx),
                                 Scene *scene,
                                 Object *ob,
                                 bPoseChannel *rootchan)
+
 {
-	DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, rootchan->name);
+	DEG_debug_print_eval_subdata(
+	        __func__, ob->id.name, ob, "rootchan", rootchan->name, rootchan);
 	BLI_assert(ob->type == OB_ARMATURE);
 	const float ctime = BKE_scene_frame_get(scene); /* not accurate... */
 	bArmature *arm = (bArmature *)ob->data;
@@ -706,7 +705,7 @@ void BKE_pose_eval_flush(EvaluationContext *UNUSED(eval_ctx),
                          bPose *UNUSED(pose))
 {
 	float ctime = BKE_scene_frame_get(scene); /* not accurate... */
-	DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
+	DEG_debug_print_eval(__func__, ob->id.name, ob);
 	BLI_assert(ob->type == OB_ARMATURE);
 
 	/* 6. release the IK tree */
@@ -718,7 +717,7 @@ void BKE_pose_eval_flush(EvaluationContext *UNUSED(eval_ctx),
 void BKE_pose_eval_proxy_copy(EvaluationContext *UNUSED(eval_ctx), Object *ob)
 {
 	BLI_assert(ID_IS_LINKED(ob) && ob->proxy_from != NULL);
-	DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
+	DEG_debug_print_eval(__func__, ob->id.name, ob);
 	if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) {
 		printf("Proxy copy error, lib Object: %s proxy Object: %s\n",
 		       ob->id.name + 2, ob->proxy_from->id.name + 2);
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index f0759748fee27d9f4e6cf0fa1042e84b72fc937e..943cab0a9fc96a615c6d85786220694168cd4980 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -65,6 +65,8 @@
 #include "BKE_object.h"
 #include "BKE_material.h"
 
+#include "DEG_depsgraph.h"
+
 /* globals */
 
 /* local */
@@ -5253,9 +5255,7 @@ void BKE_curve_rect_from_textbox(const struct Curve *cu, const struct TextBox *t
 void BKE_curve_eval_geometry(EvaluationContext *UNUSED(eval_ctx),
                              Curve *curve)
 {
-	if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) {
-		printf("%s on %s\n", __func__, curve->id.name);
-	}
+	DEG_debug_print_eval(__func__, curve->id.name, curve);
 	if (curve->bb == NULL || (curve->bb->flag & BOUNDBOX_DIRTY)) {
 		BKE_curve_texspace_calc(curve);
 	}
diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c
index a98a1b13402d410795860512df06594c4040b97d..7302d62d20fd356574f63ecbf254765ac3749619 100644
--- a/source/blender/blenkernel/intern/icons.c
+++ b/source/blender/blenkernel/intern/icons.c
@@ -431,23 +431,28 @@ void BKE_previewimg_ensure(PreviewImage *prv, const int size)
 	}
 }
 
-void BKE_icon_changed(int id)
+void BKE_icon_changed(const int icon_id)
 {
 	Icon *icon = NULL;
 	
-	if (!id || G.background) return;
+	if (!icon_id || G.background) return;
 
-	icon = BLI_ghash_lookup(gIcons, SET_INT_IN_POINTER(id));
+	icon = BLI_ghash_lookup(gIcons, SET_INT_IN_POINTER(icon_id));
 	
 	if (icon) {
-		PreviewImage *prv = BKE_previewimg_id_ensure((ID *)icon->obj);
+		/* We *only* expect ID-tied icons here, not non-ID icon/preview! */
+		BLI_assert(icon->type != 0);
+
+		/* Do not enforce creation of previews for valid ID types using BKE_previewimg_id_ensure() here ,
+		 * we only want to ensure *existing* preview images are properly tagged as changed/invalid, that's all. */
+		PreviewImage **p_prv = BKE_previewimg_id_get_p((ID *)icon->obj);
 
-		/* all previews changed */
-		if (prv) {
+		/* If we have previews, they all are now invalid changed. */
+		if (p_prv && *p_prv) {
 			int i;
 			for (i = 0; i < NUM_ICON_SIZES; ++i) {
-				prv->flag[i] |= PRV_CHANGED;
-				prv->changed_timestamp[i]++;
+				(*p_prv)->flag[i] |= PRV_CHANGED;
+				(*p_prv)->changed_timestamp[i]++;
 			}
 		}
 	}
@@ -547,7 +552,7 @@ int BKE_icon_preview_ensure(ID *id, PreviewImage *preview)
 	return preview->icon_id;
 }
 
-Icon *BKE_icon_get(int icon_id)
+Icon *BKE_icon_get(const int icon_id)
 {
 	Icon *icon = NULL;
 
@@ -561,7 +566,7 @@ Icon *BKE_icon_get(int icon_id)
 	return icon;
 }
 
-void BKE_icon_set(int icon_id, struct Icon *icon)
+void BKE_icon_set(const int icon_id, struct Icon *icon)
 {
 	void **val_p;
 
@@ -584,7 +589,7 @@ void BKE_icon_id_delete(struct ID *id)
 /**
  * Remove icon and free data.
  */
-void BKE_icon_delete(int icon_id)
+void BKE_icon_delete(const int icon_id)
 {
 	Icon *icon;
 
diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c
index 45b41fa01ed88596a4e53756c4f7eecdfd97b630..5c13ba7907da34c8c02a944694719f48a7b45820 100644
--- a/source/blender/blenkernel/intern/idprop.c
+++ b/source/blender/blenkernel/intern/idprop.c
@@ -878,9 +878,10 @@ bool IDP_EqualsProperties_ex(IDProperty *prop1, IDProperty *prop2, const bool is
 			if (prop1->len != prop2->len)
 				return false;
 
-			for (i = 0; i < prop1->len; i++)
-				if (!IDP_EqualsProperties(&array1[i], &array2[i]))
+			for (i = 0; i < prop1->len; i++) {
+				if (!IDP_EqualsProperties_ex(&array1[i], &array2[i], is_strict))
 					return false;
+			}
 			return true;
 		}
 		case IDP_ID:
diff --git a/source/blender/blenkernel/intern/mask_evaluate.c b/source/blender/blenkernel/intern/mask_evaluate.c
index 9875b74548aed0956522d8225015fc8623dff593..889f65da6891591cc8aad7b24bfa183b51fb4817 100644
--- a/source/blender/blenkernel/intern/mask_evaluate.c
+++ b/source/blender/blenkernel/intern/mask_evaluate.c
@@ -46,6 +46,7 @@
 #include "BKE_global.h"
 #include "BKE_mask.h"
 
+#include "DEG_depsgraph.h"
 
 unsigned int BKE_mask_spline_resolution(MaskSpline *spline, int width, int height)
 {
@@ -897,11 +898,9 @@ void BKE_mask_layer_evaluate_deform(MaskLayer *masklay, const float ctime)
 	}
 }
 
-#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) printf
-
 void BKE_mask_eval_animation(struct EvaluationContext *eval_ctx, Mask *mask)
 {
-	DEBUG_PRINT("%s on %s (%p)\n", __func__, mask->id.name, mask);
+	DEG_debug_print_eval(__func__, mask->id.name, mask);
 	for (MaskLayer *mask_layer = mask->masklayers.first;
 	     mask_layer != NULL;
 	     mask_layer = mask_layer->next)
@@ -912,7 +911,7 @@ void BKE_mask_eval_animation(struct EvaluationContext *eval_ctx, Mask *mask)
 
 void BKE_mask_eval_update(struct EvaluationContext *eval_ctx, Mask *mask)
 {
-	DEBUG_PRINT("%s on %s (%p)\n", __func__, mask->id.name, mask);
+	DEG_debug_print_eval(__func__, mask->id.name, mask);
 	for (MaskLayer *mask_layer = mask->masklayers.first;
 	     mask_layer != NULL;
 	     mask_layer = mask_layer->next)
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index 34cc4809db30ce62712335a715830163f06012be..c8b44511edd2871b7d62252b32a805ac966e09ec 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -2636,9 +2636,7 @@ Mesh *BKE_mesh_new_from_object(
 void BKE_mesh_eval_geometry(EvaluationContext *UNUSED(eval_ctx),
                             Mesh *mesh)
 {
-	if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) {
-		printf("%s on %s\n", __func__, mesh->id.name);
-	}
+	DEG_debug_print_eval(__func__, mesh->id.name, mesh);
 	if (mesh->bb == NULL || (mesh->bb->flag & BOUNDBOX_DIRTY)) {
 		BKE_mesh_texspace_calc(mesh);
 	}
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index 69a55256e5e226a0baa7e4245114222492d8c6d4..a67c9de6deba97ae7ba26f4feb2e8028f2d680bd 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -2533,6 +2533,7 @@ void BKE_mesh_calc_volume(
 	}
 }
 
+/** \} */
 
 /* -------------------------------------------------------------------- */
 
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index 607307554da383c754c6cf626921cea2789f9420..9ed715d75910d360d625b4c3b57e38af3839ea2c 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -73,12 +73,12 @@
 #include "IMB_imbuf.h"
 #include "IMB_moviecache.h"
 
+#include "DEG_depsgraph.h"
+
 #ifdef WITH_OPENEXR
 #  include "intern/openexr/openexr_multi.h"
 #endif
 
-#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) printf
-
 /*********************** movieclip buffer loaders *************************/
 
 static int sequence_guess_offset(const char *full_name, int head_len, unsigned short numlen)
@@ -1611,6 +1611,6 @@ bool BKE_movieclip_put_frame_if_possible(MovieClip *clip,
 
 void BKE_movieclip_eval_update(struct EvaluationContext *UNUSED(eval_ctx), MovieClip *clip)
 {
-	DEBUG_PRINT("%s on %s (%p)\n", __func__, clip->id.name, clip);
+	DEG_debug_print_eval(__func__, clip->id.name, clip);
 	BKE_tracking_dopesheet_tag_update(&clip->tracking);
 }
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index 85cf7d8560dabfbbc65a915a3390acd68246c465..e2e28d4b251ded1169ed6e4886990edff9ec82ae 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -61,18 +61,12 @@
 
 #include "DEG_depsgraph.h"
 
-#ifdef WITH_LEGACY_DEPSGRAPH
-#  define DEBUG_PRINT if (!DEG_depsgraph_use_legacy() && G.debug & G_DEBUG_DEPSGRAPH_EVAL) printf
-#else
-#  define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) printf
-#endif
-
 static ThreadMutex material_lock = BLI_MUTEX_INITIALIZER;
 
 void BKE_object_eval_local_transform(EvaluationContext *UNUSED(eval_ctx),
                                      Object *ob)
 {
-	DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
+	DEG_debug_print_eval(__func__, ob->id.name, ob);
 
 	/* calculate local matrix */
 	BKE_object_to_mat4(ob, ob->obmat);
@@ -90,7 +84,7 @@ void BKE_object_eval_parent(EvaluationContext *UNUSED(eval_ctx),
 	float tmat[4][4];
 	float locmat[4][4];
 
-	DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
+	DEG_debug_print_eval(__func__, ob->id.name, ob);
 
 	/* get local matrix (but don't calculate it, as that was done already!) */
 	// XXX: redundant?
@@ -119,7 +113,7 @@ void BKE_object_eval_constraints(EvaluationContext *UNUSED(eval_ctx),
 	bConstraintOb *cob;
 	float ctime = BKE_scene_frame_get(scene);
 
-	DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
+	DEG_debug_print_eval(__func__, ob->id.name, ob);
 
 	/* evaluate constraints stack */
 	/* TODO: split this into:
@@ -137,7 +131,7 @@ void BKE_object_eval_constraints(EvaluationContext *UNUSED(eval_ctx),
 
 void BKE_object_eval_done(EvaluationContext *UNUSED(eval_ctx), Object *ob)
 {
-	DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
+	DEG_debug_print_eval(__func__, ob->id.name, ob);
 
 	/* Set negative scale flag in object. */
 	if (is_negative_m4(ob->obmat)) ob->transflag |= OB_NEG_SCALE;
@@ -332,7 +326,7 @@ void BKE_object_eval_uber_data(EvaluationContext *eval_ctx,
                                Scene *scene,
                                Object *ob)
 {
-	DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
+	DEG_debug_print_eval(__func__, ob->id.name, ob);
 	BLI_assert(ob->type != OB_ARMATURE);
 	BKE_object_handle_data_update(eval_ctx, scene, ob);
 
@@ -343,7 +337,7 @@ void BKE_object_eval_cloth(EvaluationContext *UNUSED(eval_ctx),
                            Scene *scene,
                            Object *object)
 {
-	DEBUG_PRINT("%s on %s\n", __func__, object->id.name);
+	DEG_debug_print_eval(__func__, object->id.name, object);
 	BKE_ptcache_object_reset(scene, object, PTCACHE_RESET_DEPSGRAPH);
 }
 
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index 2a1e0f559d7990d65c105ef063253fa490e51d04..1a18528ba846671bc9240352b3d6ff6f9f1ac239 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -93,6 +93,7 @@
 #include "PIL_time.h"
 
 #include "RE_shader_ext.h"
+#include "DEG_depsgraph.h"
 
 /* fluid sim particle import */
 #ifdef WITH_MOD_FLUID
@@ -4405,8 +4406,6 @@ void BKE_particle_system_eval_init(EvaluationContext *UNUSED(eval_ctx),
                                    Scene *scene,
                                    Object *ob)
 {
-	if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) {
-		printf("%s on %s\n", __func__, ob->id.name);
-	}
+	DEG_debug_print_eval(__func__, ob->id.name, ob);
 	BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_DEPSGRAPH);
 }
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index 56e65b6f2c51eedb20b0151156649e6b6091da89..c10f54a99eb970b5f3fa49232fbfc121e16df950 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -66,6 +66,8 @@
 #include "BKE_rigidbody.h"
 #include "BKE_scene.h"
 
+#include "DEG_depsgraph.h"
+
 /* ************************************** */
 /* Memory Management */
 
@@ -1689,11 +1691,7 @@ void BKE_rigidbody_rebuild_sim(EvaluationContext *UNUSED(eval_ctx),
                                Scene *scene)
 {
 	float ctime = BKE_scene_frame_get(scene);
-
-	if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) {
-		printf("%s at %f\n", __func__, ctime);
-	}
-
+	DEG_debug_print_eval_time(__func__, scene->id.name, scene, ctime);
 	/* rebuild sim data (i.e. after resetting to start of timeline) */
 	if (BKE_scene_check_rigidbody_active(scene)) {
 		BKE_rigidbody_rebuild_world(scene, ctime);
@@ -1704,11 +1702,7 @@ void BKE_rigidbody_eval_simulation(EvaluationContext *UNUSED(eval_ctx),
                                    Scene *scene)
 {
 	float ctime = BKE_scene_frame_get(scene);
-
-	if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) {
-		printf("%s at %f\n", __func__, ctime);
-	}
-
+	DEG_debug_print_eval_time(__func__, scene->id.name, scene, ctime);
 	/* evaluate rigidbody sim */
 	if (BKE_scene_check_rigidbody_active(scene)) {
 		BKE_rigidbody_do_simulation(scene, ctime);
@@ -1721,11 +1715,7 @@ void BKE_rigidbody_object_sync_transforms(EvaluationContext *UNUSED(eval_ctx),
 {
 	RigidBodyWorld *rbw = scene->rigidbody_world;
 	float ctime = BKE_scene_frame_get(scene);
-
-	if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) {
-		printf("%s on %s\n", __func__, ob->id.name);
-	}
-
+	DEG_debug_print_eval_time(__func__, ob->id.name, ob, ctime);
 	/* read values pushed into RBO from sim/cache... */
 	BKE_rigidbody_sync_transforms(rbw, ob, ctime);
 }
diff --git a/source/blender/blenlib/BLI_array.h b/source/blender/blenlib/BLI_array.h
index 825acb18e91c97252648616b566b1e0e14130609..8e94b8197ef495ede23ad31f1b1d41231c426bc6 100644
--- a/source/blender/blenlib/BLI_array.h
+++ b/source/blender/blenlib/BLI_array.h
@@ -62,9 +62,10 @@
  * Doing the realloc in a macro isn't so simple,
  * so use a function the macros can use.
  */
-void _bli_array_grow_func(void **arr_p, const void *arr_static,
-                          const int sizeof_arr_p, const int arr_count, const int num,
-                          const char *alloc_str);
+void _bli_array_grow_func(
+        void **arr_p, const void *arr_static,
+        const int sizeof_arr_p, const int arr_len, const int num,
+        const char *alloc_str);
 
 
 /* -------------------------------------------------------------------- */
@@ -74,18 +75,18 @@ void _bli_array_grow_func(void **arr_p, const void *arr_static,
 
 /** use ``sizeof(*(arr))`` to ensure the array exists and is an array */
 #define BLI_array_declare(arr)                                                \
-	int   _##arr##_count = ((void)(sizeof(*(arr))), 0);                       \
+	int   _##arr##_len = ((void)(sizeof(*(arr))), 0);                         \
 	void *_##arr##_static = NULL
 
 /**
  * this will use stack space, up to maxstatic array elements, before
  * switching to dynamic heap allocation */
 #define BLI_array_staticdeclare(arr, maxstatic)                               \
-	int   _##arr##_count = 0;                                                 \
+	int   _##arr##_len = 0;                                                   \
 	char  _##arr##_static[maxstatic * sizeof(*(arr))]
 
 /** returns the logical size of the array, not including buffering. */
-#define BLI_array_count(arr) ((void)0, _##arr##_count)
+#define BLI_array_len(arr) ((void)0, _##arr##_len)
 
 /**
  * Grow the array by a fixed number of items.
@@ -95,23 +96,23 @@ void _bli_array_grow_func(void **arr_p, const void *arr_static,
 #define BLI_array_reserve(arr, num)  (void)(                                  \
 	(((void *)(arr) == NULL) &&                                               \
 	 ((void *)(_##arr##_static) != NULL) &&                                   \
-	/* don't add _##arr##_count below because it must be zero */              \
-	 (_bli_array_totalsize_static(arr) >= _##arr##_count + (num))) ?          \
+	/* don't add _##arr##_len below because it must be zero */                \
+	 (_bli_array_totalsize_static(arr) >= _##arr##_len + (num))) ?            \
 	/* we have an empty array and a static var big enough */                  \
 	(void)(arr = (void *)_##arr##_static)                                     \
 	    :                                                                     \
 	/* use existing static array or allocate */                               \
-	(LIKELY(_bli_array_totalsize(arr) >= _##arr##_count + (num)) ?            \
+	(LIKELY(_bli_array_totalsize(arr) >= _##arr##_len + (num)) ?              \
 	 (void)0 /* do nothing */ :                                               \
 	 _bli_array_grow_func((void **)&(arr), _##arr##_static,                   \
-	                       sizeof(*(arr)), _##arr##_count, num,               \
+	                       sizeof(*(arr)), _##arr##_len, num,                 \
 	                       "BLI_array." #arr))                                \
 	)
 
 
 /** returns length of array */
 #define BLI_array_grow_items(arr, num) \
-	(BLI_array_reserve(arr, num), (_##arr##_count += num))
+	(BLI_array_reserve(arr, num), (_##arr##_len += num))
 
 #define BLI_array_grow_one(arr) \
 	BLI_array_grow_items(arr, 1)
@@ -119,7 +120,7 @@ void _bli_array_grow_func(void **arr_p, const void *arr_static,
 /** appends an item to the array. */
 #define BLI_array_append(arr, item)  (                                        \
 	(void) BLI_array_grow_one(arr),                                           \
-	(void) (arr[_##arr##_count - 1] = item)                                   \
+	(void) (arr[_##arr##_len - 1] = item)                                     \
 )
 
 /**
@@ -127,13 +128,13 @@ void _bli_array_grow_func(void **arr_p, const void *arr_static,
  * item is not a pointer, but actual data value.*/
 #define BLI_array_append_r(arr, item)  (                                      \
 	(void) BLI_array_grow_one(arr),                                           \
-	(void) (arr[_##arr##_count - 1] = item),                                  \
-	(&arr[_##arr##_count - 1])                                                \
+	(void) (arr[_##arr##_len - 1] = item),                                    \
+	(&arr[_##arr##_len - 1])                                                  \
 )
 
 /** appends (grows) & returns a pointer to the uninitialized memory */
 #define BLI_array_append_ret(arr) \
-	(BLI_array_reserve(arr, 1), &arr[(_##arr##_count++)])
+	(BLI_array_reserve(arr, 1), &arr[(_##arr##_len++)])
 
 #define BLI_array_free(arr) {                                                 \
 	if (arr && (char *)arr != _##arr##_static) {                              \
@@ -143,26 +144,26 @@ void _bli_array_grow_func(void **arr_p, const void *arr_static,
 } ((void)0)
 
 #define BLI_array_pop(arr)  (                                                 \
-	(arr && _##arr##_count) ?                                                 \
-	    arr[--_##arr##_count] :                                               \
+	(arr && _##arr##_len) ?                                                   \
+	    arr[--_##arr##_len] :                                                 \
 	    NULL                                                                  \
 )
 
 /**
- * resets the logical size of an array to zero, but doesn't
+ * Resets the logical size of an array to zero, but doesn't
  * free the memory. */
 #define BLI_array_clear(arr)                                                  \
-	{ _##arr##_count = 0; } (void)0
+	{ _##arr##_len = 0; } ((void)0)
 
 /**
- * set the count of the array, doesn't actually increase the allocated array
+ * Set the length of the array, doesn't actually increase the allocated array
  * size.  don't use this unless you know what you're doing. */
-#define BLI_array_count_set(arr, count)                                      \
-	{ _##arr##_count = (count); }(void)0
+#define BLI_array_len_set(arr, len)                                           \
+	{ _##arr##_len = (len); } ((void)0)
 
 /** only to prevent unused warnings */
 #define BLI_array_fake_user(arr)                                              \
-	((void)_##arr##_count,                                                    \
+	((void)_##arr##_len,                                                      \
 	 (void)_##arr##_static)
 
 /** \} */
@@ -191,7 +192,7 @@ void _bli_array_grow_func(void **arr_p, const void *arr_static,
 #define BLI_array_fixedstack_free(arr)                                        \
 	if (_##arr##_is_static) {                                                 \
 		MEM_freeN(arr);                                                       \
-	} (void)0
+	} ((void)0)
 
 /** \} */
 
diff --git a/source/blender/blenlib/BLI_assert.h b/source/blender/blenlib/BLI_assert.h
new file mode 100644
index 0000000000000000000000000000000000000000..9fb0954e77fee5daaf20465b05320b2b534cc76e
--- /dev/null
+++ b/source/blender/blenlib/BLI_assert.h
@@ -0,0 +1,111 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BLI_ASSERT_H__
+#define __BLI_ASSERT_H__
+
+/** \file BLI_assert.h
+ *  \ingroup bli
+ *
+ * Defines:
+ * - #BLI_assert
+ * - #BLI_STATIC_ASSERT
+ * - #BLI_STATIC_ASSERT_ALIGN
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef NDEBUG /* for BLI_assert */
+#include <stdio.h>
+#endif
+
+/* BLI_assert(), default only to print
+ * for aborting need to define WITH_ASSERT_ABORT
+ */
+/* For 'abort' only. */
+#include <stdlib.h>
+
+#ifndef NDEBUG
+#  include "BLI_system.h"
+#  ifdef WITH_ASSERT_ABORT
+#    define _BLI_DUMMY_ABORT abort
+#  else
+#    define _BLI_DUMMY_ABORT() (void)0
+#  endif
+#  if defined(__GNUC__) || defined(_MSC_VER) /* check __func__ is available */
+#    define BLI_assert(a)                                                     \
+	(void)((!(a)) ?  (                                                        \
+		(                                                                     \
+		BLI_system_backtrace(stderr),                                         \
+		fprintf(stderr,                                                       \
+			"BLI_assert failed: %s:%d, %s(), at \'%s\'\n",                    \
+			__FILE__, __LINE__, __func__, "" #a),                             \
+		_BLI_DUMMY_ABORT(),                                                   \
+		NULL)) : NULL)
+#  else
+#    define BLI_assert(a)                                                     \
+	(void)((!(a)) ?  (                                                        \
+		(                                                                     \
+		fprintf(stderr,                                                       \
+			"BLI_assert failed: %s:%d, at \'%s\'\n",                          \
+			__FILE__, __LINE__, "" #a),                                       \
+		_BLI_DUMMY_ABORT(),                                                   \
+		NULL)) : NULL)
+#  endif
+#else
+#  define BLI_assert(a) (void)0
+#endif
+
+/* C++ can't use _Static_assert, expects static_assert() but c++0x only,
+ * Coverity also errors out. */
+#if (!defined(__cplusplus)) && \
+    (!defined(__COVERITY__)) && \
+    (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 406))  /* gcc4.6+ only */
+#  define BLI_STATIC_ASSERT(a, msg) __extension__ _Static_assert(a, msg);
+#else
+/* Code adapted from http://www.pixelbeat.org/programming/gcc/static_assert.html */
+/* Note we need the two concats below because arguments to ## are not expanded, so we need to
+ * expand __LINE__ with one indirection before doing the actual concatenation. */
+#  define ASSERT_CONCAT_(a, b) a##b
+#  define ASSERT_CONCAT(a, b) ASSERT_CONCAT_(a, b)
+   /* These can't be used after statements in c89. */
+#  if defined(__COUNTER__)  /* MSVC */
+#    define BLI_STATIC_ASSERT(a, msg) \
+         ; enum { ASSERT_CONCAT(static_assert_, __COUNTER__) = 1 / (int)(!!(a)) };
+#  else  /* older gcc, clang... */
+    /* This can't be used twice on the same line so ensure if using in headers
+     * that the headers are not included twice (by wrapping in #ifndef...#endif)
+     * Note it doesn't cause an issue when used on same line of separate modules
+     * compiled with gcc -combine -fwhole-program. */
+#    define BLI_STATIC_ASSERT(a, msg) \
+         ; enum { ASSERT_CONCAT(assert_line_, __LINE__) = 1 / (int)(!!(a)) };
+#  endif
+#endif
+
+#define BLI_STATIC_ASSERT_ALIGN(st, align) \
+  BLI_STATIC_ASSERT((sizeof(st) % (align) == 0), "Structure must be strictly aligned")
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* __BLI_ASSERT_H__ */
diff --git a/source/blender/blenlib/BLI_console.h b/source/blender/blenlib/BLI_console.h
new file mode 100644
index 0000000000000000000000000000000000000000..bf433f78f70010be83786a34ccbc29694942bd31
--- /dev/null
+++ b/source/blender/blenlib/BLI_console.h
@@ -0,0 +1,42 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Srrgey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BLI_CONSOLE_H__
+#define __BLI_CONSOLE_H__
+
+/** \file BLI_console.h
+ *  \ingroup bli
+ *  \brief Set of utility functions and constants to work with consoles.
+ */
+
+/* Format string where one could BLI_snprintf() R, G and B values
+ * and get proper marker to start colored output in the console.
+ */
+#define TRUECOLOR_ANSI_COLOR_FORMAT "\x1b[38;2;%d;%d;%dm"
+
+/* Marker which indicates that colored output is finished. */
+#define TRUECOLOR_ANSI_COLOR_FINISH "\x1b[0m"
+
+#endif  /* __BLI_CONSOLE_H__ */
diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h
index ec591c6bb483104011c229b82b94424b8c5d7e03..7003eb039dd5f5eb253dbf8a39bde11f8354f4f8 100644
--- a/source/blender/blenlib/BLI_ghash.h
+++ b/source/blender/blenlib/BLI_ghash.h
@@ -199,6 +199,8 @@ void   BLI_gset_clear(GSet *gs, GSetKeyFreeFP keyfreefp);
 void  *BLI_gset_lookup(GSet *gh, const void *key) ATTR_WARN_UNUSED_RESULT;
 void  *BLI_gset_pop_key(GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT;
 
+/** \} */
+
 /** \name GSet Iterator
  * \{ */
 
@@ -286,7 +288,7 @@ double BLI_gset_calc_quality(GSet *gs);
  *
  * \note '_p' suffix denotes void pointer arg,
  * so we can have functions that take correctly typed args too.
- * \{ */
+ */
 
 unsigned int    BLI_ghashutil_ptrhash(const void *key);
 bool            BLI_ghashutil_ptrcmp(const void *a, const void *b);
diff --git a/source/blender/blenlib/BLI_hash.h b/source/blender/blenlib/BLI_hash.h
index fa79481e25cbc87b3c25fc82dc22ac2669770b39..f74010479a98f6c5f616720013d0d839032da3dd 100644
--- a/source/blender/blenlib/BLI_hash.h
+++ b/source/blender/blenlib/BLI_hash.h
@@ -68,4 +68,16 @@ BLI_INLINE float BLI_hash_int_01(unsigned int k)
 	return (float)BLI_hash_int(k) * (1.0f / (float)0xFFFFFFFF);
 }
 
+BLI_INLINE void BLI_hash_pointer_to_color(const void *ptr, int *r, int *g, int *b)
+{
+	size_t val = (size_t)ptr;
+	const size_t hash_a = BLI_hash_int(val & 0x0000ffff);
+	const size_t hash_b = BLI_hash_int((uint)((val & 0xffff0000) >> 32));
+	const size_t hash =
+	        hash_a ^ (hash_b + 0x9e3779b9 + (hash_a << 6) + (hash_a >> 2));
+	*r = (hash & 0xff0000) >> 16;
+	*g = (hash & 0x00ff00) >> 8;
+	*b = hash & 0x0000ff;
+}
+
 #endif // __BLI_HASH_H__
diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h
index 3b24cae018d21ed90c088f10b1c3b145738d1b35..6f8e48d83b22c062d3e31d2b11bbdb31ea88b3d0 100644
--- a/source/blender/blenlib/BLI_math_base.h
+++ b/source/blender/blenlib/BLI_math_base.h
@@ -35,6 +35,7 @@
 #endif
 
 #include <math.h>
+#include "BLI_assert.h"
 #include "BLI_math_inline.h"
 
 #ifndef M_PI
diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h
index 890849babc3092533e86650176dc675607479626..46b3748c7cef0e5ba984f1e9e4c735f606273a09 100644
--- a/source/blender/blenlib/BLI_utildefines.h
+++ b/source/blender/blenlib/BLI_utildefines.h
@@ -41,9 +41,8 @@ extern "C" {
 #include "BLI_compiler_compat.h"
 #include "BLI_utildefines_variadic.h"
 
-#ifndef NDEBUG /* for BLI_assert */
-#include <stdio.h>
-#endif
+/* We could remove in future. */
+#include "BLI_assert.h"
 
 /* useful for finding bad use of min/max */
 #if 0
@@ -615,74 +614,6 @@ extern bool BLI_memory_is_zero(const void *arr, const size_t arr_size);
 #  define UNUSED_VARS_NDEBUG UNUSED_VARS
 #endif
 
-
-/* BLI_assert(), default only to print
- * for aborting need to define WITH_ASSERT_ABORT
- */
-/* For 'abort' only. */
-#include <stdlib.h>
-
-#ifndef NDEBUG
-#  include "BLI_system.h"
-#  ifdef WITH_ASSERT_ABORT
-#    define _BLI_DUMMY_ABORT abort
-#  else
-#    define _BLI_DUMMY_ABORT() (void)0
-#  endif
-#  if defined(__GNUC__) || defined(_MSC_VER) /* check __func__ is available */
-#    define BLI_assert(a)                                                     \
-	(void)((!(a)) ?  (                                                        \
-		(                                                                     \
-		BLI_system_backtrace(stderr),                                         \
-		fprintf(stderr,                                                       \
-			"BLI_assert failed: %s:%d, %s(), at \'%s\'\n",                    \
-			__FILE__, __LINE__, __func__, STRINGIFY(a)),                      \
-		_BLI_DUMMY_ABORT(),                                                   \
-		NULL)) : NULL)
-#  else
-#    define BLI_assert(a)                                                     \
-	(void)((!(a)) ?  (                                                        \
-		(                                                                     \
-		fprintf(stderr,                                                       \
-			"BLI_assert failed: %s:%d, at \'%s\'\n",                          \
-			__FILE__, __LINE__, STRINGIFY(a)),                                \
-		_BLI_DUMMY_ABORT(),                                                   \
-		NULL)) : NULL)
-#  endif
-#else
-#  define BLI_assert(a) (void)0
-#endif
-
-/* C++ can't use _Static_assert, expects static_assert() but c++0x only,
- * Coverity also errors out. */
-#if (!defined(__cplusplus)) && \
-    (!defined(__COVERITY__)) && \
-    (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 406))  /* gcc4.6+ only */
-#  define BLI_STATIC_ASSERT(a, msg) __extension__ _Static_assert(a, msg);
-#else
-/* Code adapted from http://www.pixelbeat.org/programming/gcc/static_assert.html */
-/* Note we need the two concats below because arguments to ## are not expanded, so we need to
- * expand __LINE__ with one indirection before doing the actual concatenation. */
-#  define ASSERT_CONCAT_(a, b) a##b
-#  define ASSERT_CONCAT(a, b) ASSERT_CONCAT_(a, b)
-   /* These can't be used after statements in c89. */
-#  if defined(__COUNTER__)  /* MSVC */
-#    define BLI_STATIC_ASSERT(a, msg) \
-         ; enum { ASSERT_CONCAT(static_assert_, __COUNTER__) = 1 / (int)(!!(a)) };
-#  else  /* older gcc, clang... */
-    /* This can't be used twice on the same line so ensure if using in headers
-     * that the headers are not included twice (by wrapping in #ifndef...#endif)
-     * Note it doesn't cause an issue when used on same line of separate modules
-     * compiled with gcc -combine -fwhole-program. */
-#    define BLI_STATIC_ASSERT(a, msg) \
-         ; enum { ASSERT_CONCAT(assert_line_, __LINE__) = 1 / (int)(!!(a)) };
-#  endif
-#endif
-
-
-#define BLI_STATIC_ASSERT_ALIGN(st, align) \
-  BLI_STATIC_ASSERT((sizeof(st) % (align) == 0), "Structure must be strictly aligned")
-
 /* hints for branch prediction, only use in code that runs a _lot_ where */
 #ifdef __GNUC__
 #  define LIKELY(x)       __builtin_expect(!!(x), 1)
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index d137de58e178dfee2d553ea0987fcc99e4270ced..33a8379def533f8e190fd08ee34ab813a9b3859d 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -138,6 +138,7 @@ set(SRC
 	BLI_compiler_attrs.h
 	BLI_compiler_compat.h
 	BLI_compiler_typecheck.h
+	BLI_console.h
 	BLI_convexhull_2d.h
 	BLI_dial_2d.h
 	BLI_dlrbTree.h
diff --git a/source/blender/blenlib/intern/BLI_array.c b/source/blender/blenlib/intern/BLI_array.c
index f681d222e695789c3307db595b0f7c9ac7e78964..d16dd36763da2391b914270391070090145a5ac2 100644
--- a/source/blender/blenlib/intern/BLI_array.c
+++ b/source/blender/blenlib/intern/BLI_array.c
@@ -66,21 +66,23 @@
 /**
  * This function is only to be called via macros.
  *
- * \note The caller must adjust \a arr_count
+ * \note The caller must adjust \a arr_len
  */
-void _bli_array_grow_func(void **arr_p, const void *arr_static,
-                          const int sizeof_arr_p, const int arr_count, const int num,
-                          const char *alloc_str)
+void _bli_array_grow_func(
+        void **arr_p, const void *arr_static,
+        const int sizeof_arr_p, const int arr_len, const int num,
+        const char *alloc_str)
 {
 	void *arr = *arr_p;
 	void *arr_tmp;
 
-	arr_tmp = MEM_mallocN(sizeof_arr_p *
-	                      ((num < arr_count) ?
-	                      (arr_count * 2 + 2) : (arr_count + num)), alloc_str);
+	arr_tmp = MEM_mallocN(
+	        sizeof_arr_p *
+	        ((num < arr_len) ?
+	         (arr_len * 2 + 2) : (arr_len + num)), alloc_str);
 
 	if (arr) {
-		memcpy(arr_tmp, arr, sizeof_arr_p * arr_count);
+		memcpy(arr_tmp, arr, sizeof_arr_p * arr_len);
 
 		if (arr != arr_static) {
 			MEM_freeN(arr);
@@ -91,6 +93,6 @@ void _bli_array_grow_func(void **arr_p, const void *arr_static,
 
 	/* caller must do */
 #if 0
-	arr_count += num;
+	arr_len += num;
 #endif
 }
diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c
index fc8e786e5ffb593cdd7aaa26c5d3ed5e564559b9..ec75c1401590c1bf7aec3df800eb54bceb1f4370 100644
--- a/source/blender/blenlib/intern/BLI_ghash.c
+++ b/source/blender/blenlib/intern/BLI_ghash.c
@@ -1345,7 +1345,7 @@ void *BLI_gset_lookup(GSet *gs, const void *key)
 
 /**
  * Returns the pointer to the key if it's found, removing it from the GSet.
- * \node Caller must handle freeing.
+ * \note Caller must handle freeing.
  */
 void *BLI_gset_pop_key(GSet *gs, const void *key)
 {
diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c
index d6c587806033cae6ed864f0f59695bcafa206943..06e8ade68a218f7665524f92c03d4063a8c07ab4 100644
--- a/source/blender/blenlib/intern/BLI_kdopbvh.c
+++ b/source/blender/blenlib/intern/BLI_kdopbvh.c
@@ -856,9 +856,8 @@ static void non_recursive_bvh_div_nodes_task_cb(
 		else {
 			break;
 		}
-
-		parent->totnode = (char)(k + 1);
 	}
+	parent->totnode = (char)k;
 }
 
 /**
@@ -1924,6 +1923,7 @@ void BLI_bvhtree_ray_cast_all(
 	BLI_bvhtree_ray_cast_all_ex(tree, co, dir, radius, hit_dist, callback, userdata, BVH_RAYCAST_DEFAULT);
 }
 
+/** \} */
 
 /* -------------------------------------------------------------------- */
 
diff --git a/source/blender/blenlib/intern/array_store.c b/source/blender/blenlib/intern/array_store.c
index acf15b1c892efa3960199a635d9591953c16232f..df93dad4c320538f1c5b2be83860baba81b0c4bb 100644
--- a/source/blender/blenlib/intern/array_store.c
+++ b/source/blender/blenlib/intern/array_store.c
@@ -299,7 +299,7 @@ typedef struct BChunk {
 } BChunk;
 
 /**
- * Links to store #BChunk data in #BChunkList.chunks.
+ * Links to store #BChunk data in #BChunkList.chunk_refs.
  */
 typedef struct BChunkRef {
 	struct BChunkRef *next, *prev;
@@ -749,6 +749,7 @@ static void bchunk_list_fill_from_array(
 	ASSERT_CHUNKLIST_DATA(chunk_list, data);
 }
 
+/** \} */
 
 /* ---------------------------------------------------------------------------
  * Internal Table Lookup Functions
@@ -1013,6 +1014,10 @@ static const BChunkRef *table_lookup(
 
 /** \} */
 
+/** \name Main Data De-Duplication Function
+ *
+ * \{ */
+
 /**
  * \param data: Data to store in the returned value.
  * \param data_len_original: Length of data in bytes.
@@ -1504,6 +1509,8 @@ void BLI_array_store_clear(
 	BLI_mempool_clear(bs->memory.chunk);
 }
 
+/** \} */
+
 /** \name BArrayStore Statistics
  * \{ */
 
diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c
index 1f517471407ef272d628b6bd8e48d22b1081bdc3..eed06c7841b3dc69173462990e044d0e9b2c455c 100644
--- a/source/blender/blenlib/intern/math_base_inline.c
+++ b/source/blender/blenlib/intern/math_base_inline.c
@@ -368,10 +368,8 @@ MINLINE int compare_ff_relative(float a, float b, const float max_diff, const in
 {
 	union {float f; int i;} ua, ub;
 
-#if 0  /* No BLI_assert in INLINE :/ */
 	BLI_assert(sizeof(float) == sizeof(int));
 	BLI_assert(max_ulps < (1 << 22));
-#endif
 
 	if (fabsf(a - b) <= max_diff) {
 		return 1;
diff --git a/source/blender/blenlib/intern/math_bits_inline.c b/source/blender/blenlib/intern/math_bits_inline.c
index 37fdcd7878a5f45f6f77946ad15078cfcb44436d..9b16756134e3285820104db3a44a2de1c2edf1af 100644
--- a/source/blender/blenlib/intern/math_bits_inline.c
+++ b/source/blender/blenlib/intern/math_bits_inline.c
@@ -34,7 +34,7 @@
 MINLINE int bitscan_forward_i(int a)
 {
 	BLI_assert(a != 0);
-#  ifdef _MSC_VER
+#ifdef _MSC_VER
 	unsigned long ctz;
 	_BitScanForward(&ctz, a);
 	return ctz;
@@ -63,7 +63,7 @@ MINLINE unsigned int bitscan_forward_clear_uint(unsigned int *a)
 MINLINE int bitscan_reverse_i(int a)
 {
 	BLI_assert(a != 0);
-#  ifdef _MSC_VER
+#ifdef _MSC_VER
 	unsigned long clz;
 	_BitScanReverse(&clz, a);
 	return clz;
diff --git a/source/blender/blenlib/intern/polyfill_2d_beautify.c b/source/blender/blenlib/intern/polyfill_2d_beautify.c
index 9eb2ebc0bab59d595b77c0462c3251cbe7457188..17f3205aaff10a77ee2c0c85cc508f70efa385f1 100644
--- a/source/blender/blenlib/intern/polyfill_2d_beautify.c
+++ b/source/blender/blenlib/intern/polyfill_2d_beautify.c
@@ -265,7 +265,8 @@ static void polyedge_rotate(
         struct HalfEdge *e)
 {
 	/** CCW winding, rotate internal edge to new vertical state.
-	 * <pre>
+	 *
+	 * \code{.unparsed}
 	 *   Before         After
 	 *      X             X
 	 *     / \           /|\
@@ -276,7 +277,7 @@ static void polyedge_rotate(
 	 *  e2\   /e1     e2\ | /e1
 	 *     \ /           \|/
 	 *      X             X
-	 * </pre>
+	 * \endcode
 	 */
 	struct HalfEdge *ed[6];
 	uint ed_index[6];
diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c
index 6022732025b7994372a2d1b52a20e7763867020b..c0e4b8f8168fb6b7f2c6d1cfd33cfcc73360a89b 100644
--- a/source/blender/blenlib/intern/string.c
+++ b/source/blender/blenlib/intern/string.c
@@ -208,7 +208,7 @@ size_t BLI_strcpy_rlen(char *__restrict dst, const char *__restrict src)
 }
 
 /**
- * Portable replacement for #vsnprintf
+ * Portable replacement for `vsnprintf`.
  */
 size_t BLI_vsnprintf(char *__restrict buffer, size_t maxncpy, const char *__restrict format, va_list arg)
 {
@@ -503,7 +503,7 @@ int BLI_strcaseeq(const char *a, const char *b)
 }
 
 /**
- * Portable replacement for #strcasestr (not available in MSVC)
+ * Portable replacement for `strcasestr` (not available in MSVC)
  */
 char *BLI_strcasestr(const char *s, const char *find)
 {
diff --git a/source/blender/blenlib/intern/task.c b/source/blender/blenlib/intern/task.c
index 53c0c560c0d321a30b2c17426c45ccefe1a64c50..5d3c6b35ac1b8cdedf22bc43b449c9745ac30f91 100644
--- a/source/blender/blenlib/intern/task.c
+++ b/source/blender/blenlib/intern/task.c
@@ -1310,11 +1310,11 @@ static void parallel_mempool_func(
 /**
  * This function allows to parallelize for loops over Mempool items.
  *
- * \param pool The iterable BLI_mempool to loop over.
- * \param userdata Common userdata passed to all instances of \a func.
- * \param func Callback function.
- * \param use_threading If \a true, actually split-execute loop in threads, else just do a sequential forloop
- *                      (allows caller to use any kind of test to switch on parallelization or not).
+ * \param mempool: The iterable BLI_mempool to loop over.
+ * \param userdata: Common userdata passed to all instances of \a func.
+ * \param func: Callback function.
+ * \param use_threading: If \a true, actually split-execute loop in threads, else just do a sequential for loop
+ * (allows caller to use any kind of test to switch on parallelization or not).
  *
  * \note There is no static scheduling here.
  */
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index d6868e67fc72380969a794f0b5526910f00a79d8..e1059a50412ceb546c6079f4de56104ee78a8dbd 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -8241,6 +8241,7 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short
 	id->us = ID_FAKE_USERS(id);
 	id->icon_id = 0;
 	id->newid = NULL;  /* Needed because .blend may have been saved with crap value here... */
+	id->recalc = 0;
 	
 	/* this case cannot be direct_linked: it's just the ID part */
 	if (bhead->code == ID_ID) {
diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c
index aba0160622f714ab206721e7fa4d896ec4239cca..c4b29e91fb421b9af01e61f5d8e81838786d8430 100644
--- a/source/blender/bmesh/intern/bmesh_core.c
+++ b/source/blender/bmesh/intern/bmesh_core.c
@@ -1282,8 +1282,8 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
 	}
 
 	/* create region face */
-	f_new = BLI_array_count(edges) ?
-	        BM_face_create_ngon(bm, v1, v2, edges, BLI_array_count(edges), faces[0], BM_CREATE_NOP) : NULL;
+	f_new = BLI_array_len(edges) ?
+	        BM_face_create_ngon(bm, v1, v2, edges, BLI_array_len(edges), faces[0], BM_CREATE_NOP) : NULL;
 	if (UNLIKELY(f_new == NULL)) {
 		/* Invalid boundary region to join faces */
 		goto error;
@@ -1347,11 +1347,11 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
 
 	/* delete old geometry */
 	if (do_del) {
-		for (i = 0; i < BLI_array_count(deledges); i++) {
+		for (i = 0; i < BLI_array_len(deledges); i++) {
 			BM_edge_kill(bm, deledges[i]);
 		}
 
-		for (i = 0; i < BLI_array_count(delverts); i++) {
+		for (i = 0; i < BLI_array_len(delverts); i++) {
 			BM_vert_kill(bm, delverts[i]);
 		}
 	}
diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c
index 20c49d70b027c68f243218eb8f81d9a10aa20648..7f7f48e37bd08416d59c62b9bf00055c3de574f8 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.c
+++ b/source/blender/bmesh/intern/bmesh_mesh.c
@@ -521,7 +521,7 @@ void BM_verts_calc_normal_vcos(BMesh *bm, const float (*fnos)[3], const float (*
 }
 
 /**
- * Helpers for #BM_mesh_loop_normals_update and #BM_loops_calc_normals_vnos
+ * Helpers for #BM_mesh_loop_normals_update and #BM_loops_calc_normal_vcos
  */
 static void bm_mesh_edges_sharp_tag(
         BMesh *bm,
diff --git a/source/blender/bmesh/intern/bmesh_mods.c b/source/blender/bmesh/intern/bmesh_mods.c
index 1cd51528e0620b39e401944d042e1c42fd1a2da4..961cc4587840bd4abcfab486bf8475185ba14955 100644
--- a/source/blender/bmesh/intern/bmesh_mods.c
+++ b/source/blender/bmesh/intern/bmesh_mods.c
@@ -482,8 +482,8 @@ BMEdge *BM_vert_collapse_faces(
 			BLI_array_append(faces, f);
 		}
 
-		if (BLI_array_count(faces) >= 2) {
-			BMFace *f2 = BM_faces_join(bm, faces, BLI_array_count(faces), true);
+		if (BLI_array_len(faces) >= 2) {
+			BMFace *f2 = BM_faces_join(bm, faces, BLI_array_len(faces), true);
 			if (f2) {
 				BMLoop *l_a, *l_b;
 
@@ -499,7 +499,7 @@ BMEdge *BM_vert_collapse_faces(
 			}
 		}
 
-		BLI_assert(BLI_array_count(faces) < 8);
+		BLI_assert(BLI_array_len(faces) < 8);
 
 		BLI_array_free(faces);
 	}
@@ -608,7 +608,7 @@ BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
 		} while (l != e->l);
 		
 		/* flag existing faces so we can differentiate oldfaces from new faces */
-		for (i = 0; i < BLI_array_count(oldfaces); i++) {
+		for (i = 0; i < BLI_array_len(oldfaces); i++) {
 			BM_ELEM_API_FLAG_ENABLE(oldfaces[i], _FLAG_OVERLAP);
 			oldfaces[i] = BM_face_copy(bm, bm, oldfaces[i], true, true);
 			BM_ELEM_API_FLAG_DISABLE(oldfaces[i], _FLAG_OVERLAP);
@@ -639,7 +639,7 @@ BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
 		int i, j;
 
 		/* interpolate new/changed loop data from copied old faces */
-		for (i = 0; i < BLI_array_count(oldfaces); i++) {
+		for (i = 0; i < BLI_array_len(oldfaces); i++) {
 			float f_center_old[3];
 
 			BM_face_calc_center_mean(oldfaces[i], f_center_old);
@@ -671,7 +671,7 @@ BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
 		}
 		
 		/* destroy the old faces */
-		for (i = 0; i < BLI_array_count(oldfaces); i++) {
+		for (i = 0; i < BLI_array_len(oldfaces); i++) {
 			BM_face_verts_kill(bm, oldfaces[i]);
 		}
 		
diff --git a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c
index 41775bdf2d0ed4fda526d0fb67152bff5a771f8d..85dfd3f58e28348498664d38bb005a2fd06ab56f 100644
--- a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c
+++ b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c
@@ -665,7 +665,7 @@ bool BM_face_split_edgenet(
 		BM_ELEM_API_FLAG_DISABLE(l_iter->v, VERT_VISIT);
 	} while ((l_iter = l_iter->next) != l_first);
 
-	if (BLI_array_count(face_arr)) {
+	if (BLI_array_len(face_arr)) {
 		bmesh_face_swap_data(f, face_arr[0]);
 		BM_face_kill(bm, face_arr[0]);
 		face_arr[0] = f;
@@ -674,13 +674,13 @@ bool BM_face_split_edgenet(
 		BM_ELEM_API_FLAG_DISABLE(f, FACE_NET);
 	}
 
-	for (i = 0; i < BLI_array_count(face_arr); i++) {
+	for (i = 0; i < BLI_array_len(face_arr); i++) {
 		BM_ELEM_API_FLAG_DISABLE(face_arr[i], FACE_NET);
 	}
 
 	if (r_face_arr) {
 		*r_face_arr = face_arr;
-		*r_face_arr_len = BLI_array_count(face_arr);
+		*r_face_arr_len = BLI_array_len(face_arr);
 	}
 	else {
 		if (face_arr) {
@@ -860,7 +860,7 @@ static void bvhtree_test_edges_isect_2d_ray_cb(
 /**
  * Store values for:
  * - #bm_face_split_edgenet_find_connection
- * - #test_edges_isect_2d
+ * - #test_edges_isect_2d_vert
  * ... which don't change each call.
  */
 struct EdgeGroup_FindConnection_Args {
diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c
index 32f726df01d03a82d3dbc113922c25ae8aac4e30..3a76f4ca271fa926f4ba5bbfcaba5b5c7936905d 100644
--- a/source/blender/bmesh/intern/bmesh_queries.c
+++ b/source/blender/bmesh/intern/bmesh_queries.c
@@ -1526,9 +1526,9 @@ float BM_loop_calc_face_angle(const BMLoop *l)
  *
  * Calculate the normal at this loop corner or fallback to the face normal on straight lines.
  *
- * \param l The loop to calculate the normal at
- * \param epsilon: Value to avoid numeric errors (1e-5f works well).
- * \param r_normal Resulting normal
+ * \param l: The loop to calculate the normal at.
+ * \param epsilon_sq: Value to avoid numeric errors (1e-5f works well).
+ * \param r_normal: Resulting normal.
  */
 float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, const float epsilon_sq, float r_normal[3])
 {
diff --git a/source/blender/bmesh/operators/bmo_dissolve.c b/source/blender/bmesh/operators/bmo_dissolve.c
index 5a2f07be70a1a7603d638d356f4124f335f3bb90..816d2e8d009c7fc68b3cad179ac081914a2838d6 100644
--- a/source/blender/bmesh/operators/bmo_dissolve.c
+++ b/source/blender/bmesh/operators/bmo_dissolve.c
@@ -179,7 +179,7 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op)
 		}
 		BMW_end(&regwalker);
 		
-		for (i = 0; i < BLI_array_count(faces); i++) {
+		for (i = 0; i < BLI_array_len(faces); i++) {
 			f_iter = faces[i];
 			BMO_face_flag_disable(bm, f_iter, FACE_TAG);
 			BMO_face_flag_enable(bm, f_iter, FACE_ORIG);
@@ -198,7 +198,7 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op)
 	/* track how many faces we should end up with */
 	int totface_target = bm->totface;
 
-	for (i = 0; i < BLI_array_count(regions); i++) {
+	for (i = 0; i < BLI_array_len(regions); i++) {
 		BMFace *f_new;
 		int tot = 0;
 		
@@ -259,7 +259,7 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op)
 
 cleanup:
 	/* free/cleanup */
-	for (i = 0; i < BLI_array_count(regions); i++) {
+	for (i = 0; i < BLI_array_len(regions); i++) {
 		if (regions[i]) MEM_freeN(regions[i]);
 	}
 
diff --git a/source/blender/bmesh/operators/bmo_edgenet.c b/source/blender/bmesh/operators/bmo_edgenet.c
index 744ef866128b6766932e4bd2a9cfad2d254954f1..931ac684b07156b5aa97a59e3f2ccb1fe723bbd0 100644
--- a/source/blender/bmesh/operators/bmo_edgenet.c
+++ b/source/blender/bmesh/operators/bmo_edgenet.c
@@ -179,22 +179,22 @@ void bmo_edgenet_prepare_exec(BMesh *bm, BMOperator *op)
 
 		if (!count) {
 			edges1 = edges;
-			BLI_array_count_set(edges1, BLI_array_count(edges));
+			BLI_array_len_set(edges1, BLI_array_len(edges));
 		}
 		else {
 			edges2 = edges;
-			BLI_array_count_set(edges2, BLI_array_count(edges));
+			BLI_array_len_set(edges2, BLI_array_len(edges));
 		}
 
 		BLI_array_clear(edges);
 		count++;
 	}
 
-	if (edges1 && BLI_array_count(edges1) > 2 &&
-	    BM_edge_share_vert_check(edges1[0], edges1[BLI_array_count(edges1) - 1]))
+	if (edges1 && BLI_array_len(edges1) > 2 &&
+	    BM_edge_share_vert_check(edges1[0], edges1[BLI_array_len(edges1) - 1]))
 	{
-		if (edges2 && BLI_array_count(edges2) > 2 &&
-		    BM_edge_share_vert_check(edges2[0], edges2[BLI_array_count(edges2) - 1]))
+		if (edges2 && BLI_array_len(edges2) > 2 &&
+		    BM_edge_share_vert_check(edges2[0], edges2[BLI_array_len(edges2) - 1]))
 		{
 			BLI_array_free(edges1);
 			BLI_array_free(edges2);
@@ -206,8 +206,8 @@ void bmo_edgenet_prepare_exec(BMesh *bm, BMOperator *op)
 		}
 	}
 
-	if (edges2 && BLI_array_count(edges2) > 2 &&
-	    BM_edge_share_vert_check(edges2[0], edges2[BLI_array_count(edges2) - 1]))
+	if (edges2 && BLI_array_len(edges2) > 2 &&
+	    BM_edge_share_vert_check(edges2[0], edges2[BLI_array_len(edges2) - 1]))
 	{
 		edges2 = NULL;
 	}
@@ -218,23 +218,23 @@ void bmo_edgenet_prepare_exec(BMesh *bm, BMOperator *op)
 		float dvec1[3];
 		float dvec2[3];
 
-		if (BLI_array_count(edges1) == 1) {
+		if (BLI_array_len(edges1) == 1) {
 			v1 = edges1[0]->v1;
 			v2 = edges1[0]->v2;
 		}
 		else {
 			v1 = BM_vert_in_edge(edges1[1], edges1[0]->v1) ? edges1[0]->v2 : edges1[0]->v1;
-			i  = BLI_array_count(edges1) - 1;
+			i  = BLI_array_len(edges1) - 1;
 			v2 = BM_vert_in_edge(edges1[i - 1], edges1[i]->v1) ? edges1[i]->v2 : edges1[i]->v1;
 		}
 
-		if (BLI_array_count(edges2) == 1) {
+		if (BLI_array_len(edges2) == 1) {
 			v3 = edges2[0]->v1;
 			v4 = edges2[0]->v2;
 		}
 		else {
 			v3 = BM_vert_in_edge(edges2[1], edges2[0]->v1) ? edges2[0]->v2 : edges2[0]->v1;
-			i  = BLI_array_count(edges2) - 1;
+			i  = BLI_array_len(edges2) - 1;
 			v4 = BM_vert_in_edge(edges2[i - 1], edges2[i]->v1) ? edges2[i]->v2 : edges2[i]->v1;
 		}
 
@@ -265,9 +265,9 @@ void bmo_edgenet_prepare_exec(BMesh *bm, BMOperator *op)
 	else if (edges1) {
 		BMVert *v1, *v2;
 
-		if (BLI_array_count(edges1) > 1) {
+		if (BLI_array_len(edges1) > 1) {
 			v1 = BM_vert_in_edge(edges1[1], edges1[0]->v1) ? edges1[0]->v2 : edges1[0]->v1;
-			i  = BLI_array_count(edges1) - 1;
+			i  = BLI_array_len(edges1) - 1;
 			v2 = BM_vert_in_edge(edges1[i - 1], edges1[i]->v1) ? edges1[i]->v2 : edges1[i]->v1;
 			e  = BM_edge_create(bm, v1, v2, NULL, BM_CREATE_NO_DOUBLE);
 			BMO_edge_flag_enable(bm, e, ELE_NEW);
diff --git a/source/blender/bmesh/operators/bmo_subdivide.c b/source/blender/bmesh/operators/bmo_subdivide.c
index 7d3419b591014c5064e59d62b92ef574185d8df5..8f998797a16c81890b19c56e4133c346e7c374b4 100644
--- a/source/blender/bmesh/operators/bmo_subdivide.c
+++ b/source/blender/bmesh/operators/bmo_subdivide.c
@@ -1157,7 +1157,7 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op)
 				loops[a] = l;
 			}
 			
-			vlen = BLI_array_count(loops);
+			vlen = BLI_array_len(loops);
 
 			/* find the boundary of one of the split edges */
 			for (a = 1; a < vlen; a++) {
@@ -1236,9 +1236,9 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op)
 			 * - concave corner of an ngon.
 			 * - 2 edges being used in 2+ ngons.
 			 */
-//			BM_face_splits_check_legal(bm, face, loops_split, BLI_array_count(loops_split));
+//			BM_face_splits_check_legal(bm, face, loops_split, BLI_array_len(loops_split));
 
-			for (j = 0; j < BLI_array_count(loops_split); j++) {
+			for (j = 0; j < BLI_array_len(loops_split); j++) {
 				if (loops_split[j][0]) {
 					BMFace *f_new;
 					BLI_assert(BM_edge_exists(loops_split[j][0]->v, loops_split[j][1]->v) == NULL);
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index beee9065eceeb6316143e346cdcf1389e40b666d..457e74ce1aa020cadea1b308e4e983b113ae5501 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -3209,7 +3209,7 @@ static void build_center_ngon(BMesh *bm, BevVert *bv, int mat_nr)
 			BLI_array_append(ve, NULL);
 		}
 	} while ((v = v->next) != vm->boundstart);
-	bev_create_ngon(bm, vv, BLI_array_count(vv), vf, frep, ve, mat_nr, true);
+	bev_create_ngon(bm, vv, BLI_array_len(vv), vf, frep, ve, mat_nr, true);
 
 	BLI_array_free(vv);
 	BLI_array_free(vf);
@@ -3960,7 +3960,7 @@ static int bevel_edge_order_extend(BMesh *bm, BevVert *bv, int i)
 			BLI_array_append(sucs, bme2);
 		}
 	}
-	nsucs = BLI_array_count(sucs);
+	nsucs = BLI_array_len(sucs);
 
 	bestj = j = i;
 	for (sucindex = 0; sucindex < nsucs; sucindex++) {
@@ -4500,15 +4500,15 @@ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f)
 		}
 	}
 	if (do_rebuild) {
-		n = BLI_array_count(vv);
+		n = BLI_array_len(vv);
 		f_new = bev_create_ngon(bm, vv, n, NULL, f, NULL, -1, true);
 
-		for (k = 0; k < BLI_array_count(vv_fix); k++) {
+		for (k = 0; k < BLI_array_len(vv_fix); k++) {
 			bev_merge_uvs(bm, vv_fix[k]);
 		}
 
 		/* copy attributes from old edges */
-		BLI_assert(n == BLI_array_count(ee));
+		BLI_assert(n == BLI_array_len(ee));
 		bme_prev = ee[n - 1];
 		for (k = 0; k < n; k++) {
 			bme_new = BM_edge_exists(vv[k], vv[(k + 1) % n]);
diff --git a/source/blender/collada/AnimationExporter.cpp b/source/blender/collada/AnimationExporter.cpp
index 97d3b6b29b89f3e3c52070b47b9fa43aa4104965..a59665f897fd8a77a59990f6e0369e76063f3448 100644
--- a/source/blender/collada/AnimationExporter.cpp
+++ b/source/blender/collada/AnimationExporter.cpp
@@ -771,7 +771,7 @@ void AnimationExporter::dae_baked_animation(std::vector<float> &fra, Object *ob_
 
 	addSampler(sampler);
 
-	std::string target = get_joint_id(bone, ob_arm) + "/transform";
+	std::string target = get_joint_id(ob_arm, bone) + "/transform";
 	addChannel(COLLADABU::URI(empty, sampler_id), target);
 
 	closeAnimation();
@@ -1926,15 +1926,21 @@ void AnimationExporter::sample_animation(float *v, std::vector<float> &frames, i
 
 bool AnimationExporter::validateConstraints(bConstraint *con)
 {
-	bool valid = true;
 	const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
 	/* these we can skip completely (invalid constraints...) */
-	if (cti == NULL) valid = false;
-	if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) valid = false;
+	if (cti == NULL)
+		return false;
+	if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF))
+		return false;
+
 	/* these constraints can't be evaluated anyway */
-	if (cti->evaluate_constraint == NULL) valid = false;
+	if (cti->evaluate_constraint == NULL)
+		return false;
+
 	/* influence == 0 should be ignored */
-	if (con->enforce == 0.0f) valid = false;
+	if (con->enforce == 0.0f)
+		return false;
 
-	return valid;
+	/* validation passed */
+	return true;
 }
diff --git a/source/blender/collada/AnimationImporter.cpp b/source/blender/collada/AnimationImporter.cpp
index ed3d953166fc8d034f16a24f57a5946b9be87ca5..f7ea8342eae63fa84353e61f22123d1189744c8c 100644
--- a/source/blender/collada/AnimationImporter.cpp
+++ b/source/blender/collada/AnimationImporter.cpp
@@ -70,14 +70,15 @@ FCurve *AnimationImporter::create_fcurve(int array_index, const char *rna_path)
 	fcu->array_index = array_index;
 	return fcu;
 }
-	
-void AnimationImporter::create_bezt(FCurve *fcu, float frame, float output)
+
+void AnimationImporter::add_bezt(FCurve *fcu, float frame, float value, eBezTriple_Interpolation ipo)
 {
+	//float fps = (float)FPS;
 	BezTriple bez;
 	memset(&bez, 0, sizeof(BezTriple));
 	bez.vec[1][0] = frame;
-	bez.vec[1][1] = output;
-	bez.ipo = U.ipo_new; /* use default interpolation mode here... */
+	bez.vec[1][1] = value;
+	bez.ipo = ipo; /* use default interpolation mode here... */
 	bez.f1 = bez.f2 = bez.f3 = SELECT;
 	bez.h1 = bez.h2 = HD_AUTO;
 	insert_bezt_fcurve(fcu, &bez, 0);
@@ -401,7 +402,7 @@ virtual void AnimationImporter::change_eul_to_quat(Object *ob, bAction *act)
 				eul_to_quat(quat, eul);
 
 				for (int k = 0; k < 4; k++)
-					create_bezt(quatcu[k], frame, quat[k]);
+					create_bezt(quatcu[k], frame, quat[k], U.ipo_new);
 			}
 		}
 
@@ -1560,7 +1561,8 @@ Object *AnimationImporter::translate_animation_OLD(COLLADAFW::Node *node,
 			copy_m4_m4(mat, matfra);
 		}
 
-		float val[4], rot[4], loc[3], scale[3];
+		float val[4] = {};
+		float rot[4], loc[3], scale[3];
 
 		switch (tm_type) {
 			case COLLADAFW::Transformation::ROTATE:
@@ -1832,14 +1834,14 @@ bool AnimationImporter::evaluate_animation(COLLADAFW::Transformation *tm, float
 				}
 
 				COLLADABU::Math::Matrix4 matrix;
-				int i = 0, j = 0;
+				int mi = 0, mj = 0;
 
 				for (std::vector<FCurve *>::iterator it = curves.begin(); it != curves.end(); it++) {
-					matrix.setElement(i, j, evaluate_fcurve(*it, fra));
-					j++;
-					if (j == 4) {
-						i++;
-						j = 0;
+					matrix.setElement(mi, mj, evaluate_fcurve(*it, fra));
+					mj++;
+					if (mj == 4) {
+						mi++;
+						mj = 0;
 					}
 					fcurve_is_used(*it);
 				}
@@ -2006,19 +2008,6 @@ void AnimationImporter::add_bone_fcurve(Object *ob, COLLADAFW::Node *node, FCurv
 	action_groups_add_channel(act, grp, fcu);
 }
 
-void AnimationImporter::add_bezt(FCurve *fcu, float fra, float value)
-{
-	//float fps = (float)FPS;
-	BezTriple bez;
-	memset(&bez, 0, sizeof(BezTriple));
-	bez.vec[1][0] = fra;
-	bez.vec[1][1] = value;
-	bez.ipo = BEZT_IPO_LIN; /* use default interpolation mode here... */
-	bez.f1 = bez.f2 = bez.f3 = SELECT;
-	bez.h1 = bez.h2 = HD_AUTO;
-	insert_bezt_fcurve(fcu, &bez, 0);
-	calchandles_fcurve(fcu);
-}
 
 void AnimationImporter::set_import_from_version(std::string import_from_version)
 {
diff --git a/source/blender/collada/AnimationImporter.h b/source/blender/collada/AnimationImporter.h
index 15dee8ff5f46e4e817d7e3921702fe659e7a5dc9..7dc4131dd69971a672bcc28a5054ed4af6323935 100644
--- a/source/blender/collada/AnimationImporter.h
+++ b/source/blender/collada/AnimationImporter.h
@@ -78,7 +78,7 @@ private:
 	
 	FCurve *create_fcurve(int array_index, const char *rna_path);
 	
-	void create_bezt(FCurve *fcu, float frame, float output);
+	void add_bezt(FCurve *fcu, float frame, float value, eBezTriple_Interpolation ipo=BEZT_IPO_LIN);
 
 	// create one or several fcurves depending on the number of parameters being animated
 	void animation_to_fcurves(COLLADAFW::AnimationCurve *curve);
@@ -214,8 +214,6 @@ public:
 
 	void add_bone_fcurve(Object *ob, COLLADAFW::Node *node, FCurve *fcu);
 
-	void add_bezt(FCurve *fcu, float fra, float value);
-
 	void extra_data_importer(std::string elementName);
 };
 
diff --git a/source/blender/collada/ArmatureExporter.cpp b/source/blender/collada/ArmatureExporter.cpp
index d2495a8cb9f4dc38d8ad522bb8f94dbab21f8f7c..92ec8b470a833ebdbfb0b6201feec1663db67dc9 100644
--- a/source/blender/collada/ArmatureExporter.cpp
+++ b/source/blender/collada/ArmatureExporter.cpp
@@ -89,7 +89,7 @@ void ArmatureExporter::add_armature_bones(Object *ob_arm, Scene *sce,
 void ArmatureExporter::write_bone_URLs(COLLADASW::InstanceController &ins, Object *ob_arm, Bone *bone)
 {
 	if (bc_is_root_bone(bone, this->export_settings->deform_bones_only))
-		ins.addSkeleton(COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_joint_id(bone, ob_arm)));
+		ins.addSkeleton(COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_joint_id(ob_arm, bone)));
 	else {
 		for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
 			write_bone_URLs(ins, ob_arm, child);
@@ -165,9 +165,9 @@ void ArmatureExporter::add_bone_node(Bone *bone, Object *ob_arm, Scene *sce,
                                      std::list<Object *>& child_objects)
 {
 	if (!(this->export_settings->deform_bones_only && bone->flag & BONE_NO_DEFORM)) {
-		std::string node_id = get_joint_id(bone, ob_arm);
+		std::string node_id = get_joint_id(ob_arm, bone);
 		std::string node_name = std::string(bone->name);
-		std::string node_sid = get_joint_sid(bone, ob_arm);
+		std::string node_sid = get_joint_sid(bone);
 
 		COLLADASW::Node node(mSW);
 
diff --git a/source/blender/collada/ArmatureImporter.cpp b/source/blender/collada/ArmatureImporter.cpp
index 0ea8324ed7c5dcdca6cc3fc4234971abf93a8799..c62aa0541768757bd492894355c2ec491c6b779c 100644
--- a/source/blender/collada/ArmatureImporter.cpp
+++ b/source/blender/collada/ArmatureImporter.cpp
@@ -282,12 +282,11 @@ void ArmatureImporter::connect_bone_chains(bArmature *armature, Bone *parentbone
 	BoneExtensionMap &extended_bones = bone_extension_manager.getExtensionMap(armature);
 	BoneExtended *dominant_child = NULL;
 	int maxlen = 0;
-	Bone *child;
 
 	if (parentbone == NULL)
 		return;
 
-	child = (Bone *)parentbone->childbase.first;
+	Bone *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];
@@ -337,8 +336,8 @@ void ArmatureImporter::connect_bone_chains(bArmature *armature, Bone *parentbone
 				}
 			}
 		}
-		for (Bone *child = (Bone *)parentbone->childbase.first; child; child = child->next) {
-			ArmatureImporter::connect_bone_chains(armature, child, UNLIMITED_CHAIN_MAX);
+		for (Bone *ch = (Bone *)parentbone->childbase.first; ch; ch = ch->next) {
+			ArmatureImporter::connect_bone_chains(armature, ch, UNLIMITED_CHAIN_MAX);
 		}
 	}
 	else if (maxlen>1 && maxlen > this->import_settings->min_chain_length) {
@@ -348,8 +347,8 @@ void ArmatureImporter::connect_bone_chains(bArmature *armature, Bone *parentbone
 	else {
 		/* can't connect this Bone. Proceed with children ... */
 		if (pbe) pbe->set_leaf_bone(true);
-		for (Bone *child = (Bone *)parentbone->childbase.first; child; child = child->next) {
-			ArmatureImporter::connect_bone_chains(armature, child, UNLIMITED_CHAIN_MAX);
+		for (Bone *ch = (Bone *)parentbone->childbase.first; ch; ch = ch->next) {
+			ArmatureImporter::connect_bone_chains(armature, ch, UNLIMITED_CHAIN_MAX);
 		}
 	}
 
diff --git a/source/blender/collada/ControllerExporter.cpp b/source/blender/collada/ControllerExporter.cpp
index 4afe71f47ba8a51828095402e84541449749eb5d..14e8e0323a857d6d44ef79d1a59e9845abe38317 100644
--- a/source/blender/collada/ControllerExporter.cpp
+++ b/source/blender/collada/ControllerExporter.cpp
@@ -71,7 +71,7 @@ bool ControllerExporter::is_skinned_mesh(Object *ob)
 void ControllerExporter::write_bone_URLs(COLLADASW::InstanceController &ins, Object *ob_arm, Bone *bone)
 {
 	if (bc_is_root_bone(bone, this->export_settings->deform_bones_only))
-		ins.addSkeleton(COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_joint_id(bone, ob_arm)));
+		ins.addSkeleton(COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_joint_id(ob_arm, bone)));
 	else {
 		for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
 			write_bone_URLs(ins, ob_arm, child);
@@ -458,7 +458,7 @@ std::string ControllerExporter::add_joints_source(Object *ob_arm, ListBase *defb
 	for (def = (bDeformGroup *)defbase->first; def; def = def->next) {
 		Bone *bone = get_bone_from_defgroup(ob_arm, def);
 		if (bone)
-			source.appendValues(get_joint_sid(bone, ob_arm));
+			source.appendValues(get_joint_sid(bone));
 	}
 
 	source.finish();
diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp
index f7fdfb06a405413c35553f42b64a94be05beab84..08ac6e65c116445dd2eaa42fb9f905af7c43bcd3 100644
--- a/source/blender/collada/DocumentImporter.cpp
+++ b/source/blender/collada/DocumentImporter.cpp
@@ -190,8 +190,8 @@ void DocumentImporter::finish()
 	std::vector<Object *> *objects_to_scale = new std::vector<Object *>();
 
 	/** TODO Break up and put into 2-pass parsing of DAE */
-	std::vector<const COLLADAFW::VisualScene *>::iterator it;
-	for (it = vscenes.begin(); it != vscenes.end(); it++) {
+	std::vector<const COLLADAFW::VisualScene *>::iterator sit;
+	for (sit = vscenes.begin(); sit != vscenes.end(); sit++) {
 		PointerRNA sceneptr, unit_settings;
 		PropertyRNA *system, *scale;
 		
@@ -222,7 +222,7 @@ void DocumentImporter::finish()
 		}
 
 		// Write nodes to scene
-		const COLLADAFW::NodePointerArray& roots = (*it)->getRootNodes();
+		const COLLADAFW::NodePointerArray& roots = (*sit)->getRootNodes();
 		for (unsigned int i = 0; i < roots.getCount(); i++) {
 			std::vector<Object *> *objects_done = write_node(roots[i], NULL, sce, NULL, false);
 			objects_to_scale->insert(objects_to_scale->end(), objects_done->begin(), objects_done->end());
@@ -247,8 +247,8 @@ void DocumentImporter::finish()
 	armature_importer.fix_animation();
 #endif
 
-	for (std::vector<const COLLADAFW::VisualScene *>::iterator it = vscenes.begin(); it != vscenes.end(); it++) {
-		const COLLADAFW::NodePointerArray& roots = (*it)->getRootNodes();
+	for (std::vector<const COLLADAFW::VisualScene *>::iterator vsit = vscenes.begin(); vsit != vscenes.end(); vsit++) {
+		const COLLADAFW::NodePointerArray& roots = (*vsit)->getRootNodes();
 
 		for (unsigned int i = 0; i < roots.getCount(); i++) {
 			translate_anim_recursive(roots[i], NULL, NULL);
@@ -256,13 +256,12 @@ void DocumentImporter::finish()
 	}
 
 	if (libnode_ob.size()) {
-		Scene *sce = CTX_data_scene(mContext);
 
 		fprintf(stderr, "got %d library nodes to free\n", (int)libnode_ob.size());
 		// free all library_nodes
-		std::vector<Object *>::iterator it;
-		for (it = libnode_ob.begin(); it != libnode_ob.end(); it++) {
-			Object *ob = *it;
+		std::vector<Object *>::iterator lit;
+		for (lit = libnode_ob.begin(); lit != libnode_ob.end(); lit++) {
+			Object *ob = *lit;
 
 			Base *base = BKE_scene_base_find(sce, ob);
 			if (base) {
@@ -475,9 +474,9 @@ void DocumentImporter::create_constraints(ExtraTags *et, Object *ob)
 {
 	if (et && et->isProfile("blender")) {
 		std::string name;
-		short* type = 0;
-		et->setData("type", type);
-		BKE_constraint_add_for_object(ob, "Test_con", *type);
+		short type = 0;
+		et->setData("type", &type);
+		BKE_constraint_add_for_object(ob, "Test_con", type);
 		
 	}
 }
@@ -588,8 +587,8 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLA
 			++lamp_done;
 		}
 		while (controller_done < controller.getCount()) {
-			COLLADAFW::InstanceGeometry *geom = (COLLADAFW::InstanceGeometry *)controller[controller_done];
-			ob = mesh_importer.create_mesh_object(node, geom, true, uid_material_map, material_texture_mapping_map);
+			COLLADAFW::InstanceGeometry *geometry = (COLLADAFW::InstanceGeometry *)controller[controller_done];
+			ob = mesh_importer.create_mesh_object(node, geometry, true, uid_material_map, material_texture_mapping_map);
 			if (ob == NULL) {
 				report_unknown_reference(*node, "instance_controller");
 			}
diff --git a/source/blender/collada/GeometryExporter.cpp b/source/blender/collada/GeometryExporter.cpp
index 73b00fd07ecf6dfd3b729d01e1fee77d26ddc48c..bc0275001d36eccd5d8b5bdecc1596d8d4b9dd2c 100644
--- a/source/blender/collada/GeometryExporter.cpp
+++ b/source/blender/collada/GeometryExporter.cpp
@@ -149,8 +149,8 @@ void GeometryExporter::operator()(Object *ob)
 		}
 		else {
 			bool all_uv_layers = !this->export_settings->active_uv_only;
-			std::set<Image *> uv_images = bc_getUVImages(ob, all_uv_layers);
-			createPolylists(uv_images, has_uvs, has_color, ob, me, geom_id, norind);
+			std::set<Image *> uv_image_set = bc_getUVImages(ob, all_uv_layers);
+			createPolylists(uv_image_set, has_uvs, has_color, ob, me, geom_id, norind);
 		}
 	}
 	
diff --git a/source/blender/collada/ImageExporter.cpp b/source/blender/collada/ImageExporter.cpp
index 93be7de62361d500241f5ef6d38de6ecaf794452..99547551a128ed658cb41c85eef194fbfcfead0f 100644
--- a/source/blender/collada/ImageExporter.cpp
+++ b/source/blender/collada/ImageExporter.cpp
@@ -203,8 +203,8 @@ bool ImagesExporter::hasImages(Scene *sce)
 	
 	for (node = this->export_settings->export_set; node; node = node->next) {
 		Object *ob = (Object *)node->link;
-		int a;
-		for (a = 0; a < ob->totcol; a++) {
+
+		for (int a = 0; a < ob->totcol; a++) {
 			Material *ma = give_current_material(ob, a + 1);
 
 			// no material, but check all of the slots
diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp
index 6ca53c64299e75f89f98ed295b3b96a79792c261..2e265125a43a8a99f0ed580bdee9bf329a9501bc 100644
--- a/source/blender/collada/MeshImporter.cpp
+++ b/source/blender/collada/MeshImporter.cpp
@@ -552,7 +552,7 @@ void MeshImporter::mesh_add_edges(Mesh *mesh, int len)
 {
 	CustomData edata;
 	MEdge *medge;
-	int i, totedge;
+	int totedge;
 
 	if (len == 0)
 		return;
@@ -572,7 +572,7 @@ void MeshImporter::mesh_add_edges(Mesh *mesh, int len)
 
 	/* set default flags */
 	medge = &mesh->medge[mesh->totedge];
-	for (i = 0; i < len; i++, medge++)
+	for (int i = 0; i < len; i++, medge++)
 		medge->flag = ME_EDGEDRAW | ME_EDGERENDER | SELECT;
 
 	mesh->totedge = totedge;
@@ -606,12 +606,12 @@ void MeshImporter::read_lines(COLLADAFW::Mesh *mesh, Mesh *me)
 				unsigned int edge_count  = mp->getFaceCount();
 				unsigned int *indices    = mp->getPositionIndices().getData();
 				
-				for (int i = 0; i < edge_count; i++, med++) {
+				for (int j = 0; j < edge_count; j++, med++) {
 					med->bweight = 0;
 					med->crease  = 0;
 					med->flag   |= ME_LOOSEEDGE;
-					med->v1      = indices[2 * i];
-					med->v2      = indices[2 * i + 1];
+					med->v1      = indices[2 * j];
+					med->v2      = indices[2 * j + 1];
 				}
 			}
 		}
diff --git a/source/blender/collada/collada_internal.cpp b/source/blender/collada/collada_internal.cpp
index 8974acb346053c5b0acfd5f1a51db95aca71d79a..f2cc56777d84477b6c441a845c79db00b716c973 100644
--- a/source/blender/collada/collada_internal.cpp
+++ b/source/blender/collada/collada_internal.cpp
@@ -327,12 +327,12 @@ std::string get_light_id(Object *ob)
 	return translate_id(id_name(ob)) + "-light";
 }
 
-std::string get_joint_id(Bone *bone, Object *ob_arm)
+std::string get_joint_id(Object *ob, Bone *bone)
 {
-	return translate_id(id_name(ob_arm) + "_" + bone->name);
+	return translate_id(id_name(ob) + "_" + bone->name);
 }
 
-std::string get_joint_sid(Bone *bone, Object *ob_arm)
+std::string get_joint_sid(Bone *bone)
 {
 	return translate_id(bone->name);
 }
diff --git a/source/blender/collada/collada_internal.h b/source/blender/collada/collada_internal.h
index 5f3fa34edc1e12f31154b0c32f46592dcf8124c2..fc848100b791d82b0d4e6e6e69918d58704c9b21 100644
--- a/source/blender/collada/collada_internal.h
+++ b/source/blender/collada/collada_internal.h
@@ -97,8 +97,8 @@ extern std::string get_geometry_id(Object *ob, bool use_instantiation);
 
 extern std::string get_light_id(Object *ob);
 
-extern std::string get_joint_id(Bone *bone, Object *ob_arm);
-extern std::string get_joint_sid(Bone *bone, Object *ob_arm);
+extern std::string get_joint_id(Object *ob, Bone *bone);
+extern std::string get_joint_sid(Bone *bone);
 
 extern std::string get_camera_id(Object *ob);
 
diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h
index 0837f14727565fe0946a28cf2cd25be961f25012..72e90f49748c65789f34893a4c6ace6407176c4e 100644
--- a/source/blender/depsgraph/DEG_depsgraph.h
+++ b/source/blender/depsgraph/DEG_depsgraph.h
@@ -208,6 +208,32 @@ void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func,
 
 void DEG_editors_update_pre(struct Main *bmain, struct Scene *scene, bool time);
 
+/* Evaluation Debug ------------------------------ */
+
+void DEG_debug_print_eval(const char* function_name,
+                          const char* object_name,
+                          const void* object_address);
+
+void DEG_debug_print_eval_subdata(const char *function_name,
+                                  const char *object_name,
+                                  const void *object_address,
+                                  const char *subdata_comment,
+                                  const char *subdata_name,
+                                  const void *subdata_address);
+
+void DEG_debug_print_eval_subdata_index(const char *function_name,
+                                        const char *object_name,
+                                        const void *object_address,
+                                        const char *subdata_comment,
+                                        const char *subdata_name,
+                                        const void *subdata_address,
+                                        const int subdata_index);
+
+void DEG_debug_print_eval_time(const char* function_name,
+                               const char* object_name,
+                               const void* object_address,
+                               float time);
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc
index 2e87786639cb9a9bb52a6f373715cce7f275aaea..66ddaa6b0d5ac4a2256692068ce9f60c5b9f74f2 100644
--- a/source/blender/depsgraph/intern/depsgraph.cc
+++ b/source/blender/depsgraph/intern/depsgraph.cc
@@ -35,6 +35,8 @@
 #include "MEM_guardedalloc.h"
 
 #include "BLI_utildefines.h"
+#include "BLI_console.h"
+#include "BLI_hash.h"
 #include "BLI_ghash.h"
 #include "BLI_listbase.h"
 
@@ -458,6 +460,31 @@ void deg_editors_scene_update(Main *bmain, Scene *scene, bool updated)
 	}
 }
 
+bool deg_terminal_do_color(void)
+{
+	return (G.debug & G_DEBUG_DEPSGRAPH_PRETTY) != 0;
+}
+
+string deg_color_for_pointer(const void *pointer)
+{
+	if (!deg_terminal_do_color()) {
+		return "";
+	}
+	int r, g, b;
+	BLI_hash_pointer_to_color(pointer, &r, &g, &b);
+	char buffer[64];
+	BLI_snprintf(buffer, sizeof(buffer), TRUECOLOR_ANSI_COLOR_FORMAT, r, g, b);
+	return string(buffer);
+}
+
+string deg_color_end(void)
+{
+	if (!deg_terminal_do_color()) {
+		return "";
+	}
+	return string(TRUECOLOR_ANSI_COLOR_FINISH);
+}
+
 }  // namespace DEG
 
 /* **************** */
@@ -494,3 +521,85 @@ void DEG_editors_update_pre(Main *bmain, Scene *scene, bool time)
 		DEG::deg_editor_update_scene_pre_cb(bmain, scene, time);
 	}
 }
+
+/* Evaluation and debug */
+
+void DEG_debug_print_eval(const char *function_name,
+                          const char *object_name,
+                          const void *object_address)
+{
+	if ((G.debug & G_DEBUG_DEPSGRAPH_EVAL) == 0) {
+		return;
+	}
+	printf("%s on %s %s(%p)%s\n",
+	       function_name,
+	       object_name,
+	       DEG::deg_color_for_pointer(object_address).c_str(),
+	       object_address,
+	       DEG::deg_color_end().c_str());
+}
+
+void DEG_debug_print_eval_subdata(const char *function_name,
+                                  const char *object_name,
+                                  const void *object_address,
+                                  const char *subdata_comment,
+                                  const char *subdata_name,
+                                  const void *subdata_address)
+{
+	if ((G.debug & G_DEBUG_DEPSGRAPH_EVAL) == 0) {
+		return;
+	}
+	printf("%s on %s %s(%p)%s %s %s %s(%p)%s\n",
+	       function_name,
+	       object_name,
+	       DEG::deg_color_for_pointer(object_address).c_str(),
+	       object_address,
+	       DEG::deg_color_end().c_str(),
+	       subdata_comment,
+	       subdata_name,
+	       DEG::deg_color_for_pointer(subdata_address).c_str(),
+	       subdata_address,
+	       DEG::deg_color_end().c_str());
+}
+
+void DEG_debug_print_eval_subdata_index(const char *function_name,
+                                        const char *object_name,
+                                        const void *object_address,
+                                        const char *subdata_comment,
+                                        const char *subdata_name,
+                                        const void *subdata_address,
+                                        const int subdata_index)
+{
+	if ((G.debug & G_DEBUG_DEPSGRAPH_EVAL) == 0) {
+		return;
+	}
+	printf("%s on %s %s(%p)^%s %s %s[%d] %s(%p)%s\n",
+	       function_name,
+	       object_name,
+	       DEG::deg_color_for_pointer(object_address).c_str(),
+	       object_address,
+	       DEG::deg_color_end().c_str(),
+	       subdata_comment,
+	       subdata_name,
+	       subdata_index,
+	       DEG::deg_color_for_pointer(subdata_address).c_str(),
+	       subdata_address,
+	       DEG::deg_color_end().c_str());
+}
+
+void DEG_debug_print_eval_time(const char *function_name,
+                               const char *object_name,
+                               const void *object_address,
+                               float time)
+{
+	if ((G.debug & G_DEBUG_DEPSGRAPH_EVAL) == 0) {
+		return;
+	}
+	printf("%s on %s %s(%p)%s at time %f\n",
+	       function_name,
+	       object_name,
+	       DEG::deg_color_for_pointer(object_address).c_str(),
+	       object_address,
+	       DEG::deg_color_end().c_str(),
+	       time);
+}
diff --git a/source/blender/depsgraph/intern/depsgraph_intern.h b/source/blender/depsgraph/intern/depsgraph_intern.h
index 2ac97c53db79c28affb3185489ff311f6188ec74..89432e17f87c548d4c52ad5b7129716de6b27d2c 100644
--- a/source/blender/depsgraph/intern/depsgraph_intern.h
+++ b/source/blender/depsgraph/intern/depsgraph_intern.h
@@ -116,4 +116,8 @@ void deg_editors_scene_update(struct Main *bmain, struct Scene *scene, bool upda
 		} \
 	} while (0)
 
+bool deg_terminal_do_color(void);
+string deg_color_for_pointer(const void *pointer);
+string deg_color_end(void);
+
 }  // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc
index 18ad4d1598595768b50f266d52ea9748a499c684..5f7bb4c3de5fca71a0b96ebe3608a834fedbd391 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval.cc
@@ -260,6 +260,7 @@ void deg_evaluate_on_refresh(EvaluationContext *eval_ctx,
 	                 __func__,
 	                 layers,
 	                 graph->layers);
+	const bool do_time_debug = ((G.debug & G_DEBUG_DEPSGRAPH_TIME) != 0);
 	/* Set time for the current graph evaluation context. */
 	TimeSourceDepsNode *time_src = graph->find_time_source();
 	eval_ctx->ctime = time_src->cfra;
@@ -268,7 +269,7 @@ void deg_evaluate_on_refresh(EvaluationContext *eval_ctx,
 	state.eval_ctx = eval_ctx;
 	state.graph = graph;
 	state.layers = layers;
-	state.do_stats = (G.debug_value != 0);
+	state.do_stats = do_time_debug;
 	/* Set up task scheduler and pull for threaded evaluation. */
 	TaskScheduler *task_scheduler;
 	bool need_free_scheduler;
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index 4d68053fbc8fe72acd664eb19136b4b7b84de5e1..e9ab949dc95c93e9b63503931aada685edbfb3a0 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -3085,7 +3085,7 @@ static bool select_anim_channel_keys(bAnimContext *ac, int channel_index, bool e
 			for (ale = anim_data.first; ale; ale = ale->next) {
 				FCurve *fcu_inner = (FCurve *)ale->key_data;
 
-				if (fcu_inner) {
+				if (fcu_inner != NULL && fcu_inner->bezt != NULL) {
 					for (i = 0, bezt = fcu_inner->bezt; i < fcu_inner->totvert; i++, bezt++) {
 						bezt->f2 = bezt->f1 = bezt->f3 = 0;
 					}
diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c
index cd7e3b4cb3922dcbe7bf04e32bcaf80f0f9738cd..32635541a3559f048f7b4e54759476514a0797b6 100644
--- a/source/blender/editors/armature/armature_naming.c
+++ b/source/blender/editors/armature/armature_naming.c
@@ -313,7 +313,7 @@ typedef struct BoneFlipNameData {
  *
  * \param arm: Armature the bones belong to
  * \param bones_names: List of BoneConflict elems.
- * \param do_flip_numbers: if set, try to get rid of dot-numbers at end of bone names.
+ * \param do_strip_numbers: if set, try to get rid of dot-numbers at end of bone names.
  */
 void ED_armature_bones_flip_names(bArmature *arm, ListBase *bones_names, const bool do_strip_numbers)
 {
diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c
index 587ae6991a228a8dba3263ee2f3d5ae4f77a4bd3..d9d5fa395d67846e10d5d695516f5fe2584edb3d 100644
--- a/source/blender/editors/armature/pose_lib.c
+++ b/source/blender/editors/armature/pose_lib.c
@@ -833,7 +833,6 @@ typedef struct tPoseLib_PreviewData {
 	bAction *act;           /* poselib to use */
 	TimeMarker *marker;     /* 'active' pose */
 
-	int selcount;           /* number of selected elements to work on */
 	int totcount;           /* total number of elements to work on */
 
 	short state;            /* state of main loop */
@@ -866,7 +865,8 @@ enum {
 /* defines for tPoseLib_PreviewData->flag values */
 enum {
 	PL_PREVIEW_FIRSTTIME    = (1 << 0),
-	PL_PREVIEW_SHOWORIGINAL = (1 << 1)
+	PL_PREVIEW_SHOWORIGINAL = (1 << 1),
+	PL_PREVIEW_ANY_BONE_SELECTED = (1 << 2),
 };
 
 /* ---------------------------- */
@@ -886,7 +886,20 @@ static void poselib_backup_posecopy(tPoseLib_PreviewData *pld)
 {
 	bActionGroup *agrp;
 	bPoseChannel *pchan;
-	
+	bool selected = false;
+
+	/* determine whether any bone is selected. */
+	LISTBASE_FOREACH (bPoseChannel *, bchan, &pld->pose->chanbase) {
+		selected = bchan->bone != NULL && bchan->bone->flag & BONE_SELECTED;
+		if (selected) {
+			pld->flag |= PL_PREVIEW_ANY_BONE_SELECTED;
+			break;
+		}
+	}
+	if (!selected) {
+		pld->flag &= ~PL_PREVIEW_ANY_BONE_SELECTED;
+	}
+
 	/* for each posechannel that has an actionchannel in */
 	for (agrp = pld->act->groups.first; agrp; agrp = agrp->next) {
 		/* try to find posechannel */
@@ -908,8 +921,6 @@ static void poselib_backup_posecopy(tPoseLib_PreviewData *pld)
 			BLI_addtail(&pld->backups, plb);
 			
 			/* mark as being affected */
-			if ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED))
-				pld->selcount++;
 			pld->totcount++;
 		}
 	}
@@ -970,6 +981,7 @@ static void poselib_apply_pose(tPoseLib_PreviewData *pld)
 	KeyframeEditData ked = {{NULL}};
 	KeyframeEditFunc group_ok_cb;
 	int frame = 1;
+	const bool any_bone_selected = pld->flag & PL_PREVIEW_ANY_BONE_SELECTED;
 	
 	/* get the frame */
 	if (pld->marker)
@@ -982,8 +994,7 @@ static void poselib_apply_pose(tPoseLib_PreviewData *pld)
 	group_ok_cb = ANIM_editkeyframes_ok(BEZT_OK_FRAMERANGE);
 	ked.f1 = ((float)frame) - 0.5f;
 	ked.f2 = ((float)frame) + 0.5f;
-	
-	
+
 	/* start applying - only those channels which have a key at this point in time! */
 	for (agrp = act->groups.first; agrp; agrp = agrp->next) {
 		/* check if group has any keyframes */
@@ -995,7 +1006,7 @@ static void poselib_apply_pose(tPoseLib_PreviewData *pld)
 				bool ok = 0;
 				
 				/* check if this bone should get any animation applied */
-				if (pld->selcount == 0) {
+				if (!any_bone_selected) {
 					/* if no bones are selected, then any bone is ok */
 					ok = 1;
 				}
@@ -1008,7 +1019,7 @@ static void poselib_apply_pose(tPoseLib_PreviewData *pld)
 						ok = 1;
 					}
 				}
-				
+
 				if (ok) 
 					animsys_evaluate_action_group(ptr, act, agrp, NULL, (float)frame);
 			}
@@ -1027,14 +1038,15 @@ static void poselib_keytag_pose(bContext *C, Scene *scene, tPoseLib_PreviewData
 	KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_WHOLE_CHARACTER_ID);
 	ListBase dsources = {NULL, NULL};
 	bool autokey = autokeyframe_cfra_can_key(scene, &pld->ob->id);
-	
+	const bool any_bone_selected = pld->flag & PL_PREVIEW_ANY_BONE_SELECTED;
+
 	/* start tagging/keying */
 	for (agrp = act->groups.first; agrp; agrp = agrp->next) {
 		/* only for selected bones unless there aren't any selected, in which case all are included  */
 		pchan = BKE_pose_channel_find_name(pose, agrp->name);
 		
 		if (pchan) {
-			if ((pld->selcount == 0) || ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED))) {
+			if (!any_bone_selected || ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED))) {
 				if (autokey) {
 					/* add datasource override for the PoseChannel, to be used later */
 					ANIM_relative_keyingset_add_source(&dsources, &pld->ob->id, &RNA_PoseBone, pchan); 
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index 84698b33e259a0ade90435af983b95c7009b9523..40d796aeed1283c4819f2047638434f6e53873e0 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -47,6 +47,7 @@ struct bDeformGroup;
 struct MDeformVert;
 struct Scene;
 struct Mesh;
+struct MTexPoly;
 struct UvVertMap;
 struct UvMapVert;
 struct BMEditMesh;
@@ -79,7 +80,7 @@ void EDBM_mesh_normals_update(struct BMEditMesh *em);
 void EDBM_mesh_clear(struct BMEditMesh *em);
 
 void EDBM_selectmode_to_scene(struct bContext *C);
-void EDBM_mesh_make(struct ToolSettings *ts, struct Object *ob, const bool add_key_index);
+void EDBM_mesh_make(struct Object *ob, const int select_mode, const bool add_key_index);
 void EDBM_mesh_free(struct BMEditMesh *em);
 void EDBM_mesh_load(struct Object *ob);
 struct DerivedMesh *EDBM_mesh_deform_dm_get(struct BMEditMesh *em);
@@ -112,8 +113,10 @@ struct UvElementMap *BM_uv_element_map_create(
 void                 BM_uv_element_map_free(struct UvElementMap *vmap);
 struct UvElement    *BM_uv_element_get(struct UvElementMap *map, struct BMFace *efa, struct BMLoop *l);
 
-bool             EDBM_mtexpoly_check(struct BMEditMesh *em);
-struct MTexPoly *EDBM_mtexpoly_active_get(struct BMEditMesh *em, struct BMFace **r_act_efa, const bool sloppy, const bool selected);
+bool           EDBM_uv_check(struct BMEditMesh *em);
+struct BMFace *EDBM_uv_active_face_get(
+        struct BMEditMesh *em, const bool sloppy, const bool selected,
+        struct MTexPoly **r_tf);
 
 void              BM_uv_vert_map_free(struct UvVertMap *vmap);
 struct UvMapVert *BM_uv_vert_map_at_index(struct UvVertMap *vmap, unsigned int v);
@@ -137,8 +140,9 @@ bool EDBM_backbuf_border_init(struct ViewContext *vc, short xmin, short ymin, sh
 bool EDBM_backbuf_check(unsigned int index);
 void EDBM_backbuf_free(void);
 
-bool EDBM_backbuf_border_mask_init(struct ViewContext *vc, const int mcords[][2], short tot,
-                                   short xmin, short ymin, short xmax, short ymax);
+bool EDBM_backbuf_border_mask_init(
+        struct ViewContext *vc, const int mcords[][2], short tot,
+        short xmin, short ymin, short xmax, short ymax);
 bool EDBM_backbuf_circle_init(struct ViewContext *vc, short xs, short ys, short rads);
 
 struct BMVert *EDBM_vert_find_nearest_ex(
@@ -218,9 +222,11 @@ typedef struct MirrTopoStore_t {
 	int prev_ob_mode;
 } MirrTopoStore_t;
 
-bool ED_mesh_mirrtopo_recalc_check(struct Mesh *me, struct DerivedMesh *dm, const int ob_mode, MirrTopoStore_t *mesh_topo_store);
-void ED_mesh_mirrtopo_init(struct Mesh *me, struct DerivedMesh *dm, const int ob_mode, MirrTopoStore_t *mesh_topo_store,
-                           const bool skip_em_vert_array_init);
+bool ED_mesh_mirrtopo_recalc_check(
+        struct Mesh *me, struct DerivedMesh *dm, const int ob_mode, MirrTopoStore_t *mesh_topo_store);
+void ED_mesh_mirrtopo_init(
+        struct Mesh *me, struct DerivedMesh *dm, const int ob_mode, MirrTopoStore_t *mesh_topo_store,
+        const bool skip_em_vert_array_init);
 void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store);
 
 
diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index 354a9655a48051246a8767c65e05abc1c0cef42d..d2d4732eedb9870ef9434d387ac070945ff77990 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -49,48 +49,63 @@ struct wmKeyConfig;
 void ED_operatortypes_uvedit(void);
 void ED_keymap_uvedit(struct wmKeyConfig *keyconf);
 
-void ED_uvedit_assign_image(struct Main *bmain, struct Scene *scene, struct Object *obedit, struct Image *ima, struct Image *previma);
+void ED_uvedit_assign_image(
+        struct Main *bmain, struct Scene *scene, struct Object *obedit, struct Image *ima, struct Image *previma);
 bool ED_uvedit_minmax(struct Scene *scene, struct Image *ima, struct Object *obedit, float min[2], float max[2]);
 void ED_uvedit_select_all(struct BMesh *bm);
 
-bool ED_object_get_active_image(struct Object *ob, int mat_nr,
-                                struct Image **r_ima, struct ImageUser **r_iuser, struct bNode **r_node, struct bNodeTree **r_ntree);
+bool ED_object_get_active_image(
+        struct Object *ob, int mat_nr,
+        struct Image **r_ima, struct ImageUser **r_iuser, struct bNode **r_node, struct bNodeTree **r_ntree);
 void ED_object_assign_active_image(struct Main *bmain, struct Object *ob, int mat_nr, struct Image *ima);
 
 bool ED_uvedit_test(struct Object *obedit);
 
 /* visibility and selection */
 bool uvedit_face_visible_test(struct Scene *scene, struct Image *ima, struct BMFace *efa, struct MTexPoly *tf);
-bool uvedit_face_select_test(struct Scene *scene, struct BMFace *efa,
-                             const int cd_loop_uv_offset);
-bool uvedit_edge_select_test(struct Scene *scene, struct BMLoop *l,
-                             const int cd_loop_uv_offset);
-bool uvedit_uv_select_test(struct Scene *scene, struct BMLoop *l,
-                           const int cd_loop_uv_offset);
+bool uvedit_face_select_test(
+        struct Scene *scene, struct BMFace *efa,
+        const int cd_loop_uv_offset);
+bool uvedit_edge_select_test(
+        struct Scene *scene, struct BMLoop *l,
+        const int cd_loop_uv_offset);
+bool uvedit_uv_select_test(
+        struct Scene *scene, struct BMLoop *l,
+        const int cd_loop_uv_offset);
 /* uv face */
-bool uvedit_face_select_set(struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa, const bool select,
-                            const bool do_history, const int cd_loop_uv_offset);
-bool uvedit_face_select_enable(struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa,
-                               const bool do_history, const int cd_loop_uv_offset);
-bool uvedit_face_select_disable(struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa,
-                                const int cd_loop_uv_offset);
+bool uvedit_face_select_set(
+        struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa, const bool select,
+        const bool do_history, const int cd_loop_uv_offset);
+bool uvedit_face_select_enable(
+        struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa,
+        const bool do_history, const int cd_loop_uv_offset);
+bool uvedit_face_select_disable(
+        struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa,
+        const int cd_loop_uv_offset);
 /* uv edge */
-void uvedit_edge_select_set(struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l, const bool select,
-                            const bool do_history, const int cd_loop_uv_offset);
-void uvedit_edge_select_enable(struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l,
-                               const bool do_history, const int cd_loop_uv_offset);
-void uvedit_edge_select_disable(struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l,
-                                const int cd_loop_uv_offset);
+void uvedit_edge_select_set(
+        struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l, const bool select,
+        const bool do_history, const int cd_loop_uv_offset);
+void uvedit_edge_select_enable(
+        struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l,
+        const bool do_history, const int cd_loop_uv_offset);
+void uvedit_edge_select_disable(
+        struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l,
+        const int cd_loop_uv_offset);
 /* uv vert */
-void uvedit_uv_select_set(struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l, const bool select,
-                          const bool do_history, const int cd_loop_uv_offset);
-void uvedit_uv_select_enable(struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l,
-                             const bool do_history, const int cd_loop_uv_offset);
-void uvedit_uv_select_disable(struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l,
-                              const int cd_loop_uv_offset);
-
-bool ED_uvedit_nearest_uv(struct Scene *scene, struct Object *obedit, struct Image *ima,
-                          const float co[2], float r_uv[2]);
+void uvedit_uv_select_set(
+        struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l, const bool select,
+        const bool do_history, const int cd_loop_uv_offset);
+void uvedit_uv_select_enable(
+        struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l,
+        const bool do_history, const int cd_loop_uv_offset);
+void uvedit_uv_select_disable(
+        struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l,
+        const int cd_loop_uv_offset);
+
+bool ED_uvedit_nearest_uv(
+        struct Scene *scene, struct Object *obedit, struct Image *ima,
+        const float co[2], float r_uv[2]);
 
 void ED_uvedit_get_aspect(struct Scene *scene, struct Object *ob, struct BMesh *em, float *aspx, float *aspy);
 
@@ -100,7 +115,9 @@ void ED_uvedit_live_unwrap_re_solve(void);
 void ED_uvedit_live_unwrap_end(short cancel);
 
 void ED_uvedit_live_unwrap(struct Scene *scene, struct Object *obedit);
-void ED_uvedit_pack_islands(struct Scene *scene, struct Object *ob, struct BMesh *bm, bool selected, bool correct_aspect, bool do_rotate);
+void ED_uvedit_pack_islands(
+        struct Scene *scene, struct Object *ob, struct BMesh *bm,
+        bool selected, bool correct_aspect, bool do_rotate);
 void ED_uvedit_unwrap_cube_project(
         struct BMesh *bm, float cube_size, bool use_select, const float center[3]);
 
@@ -109,8 +126,11 @@ void ED_unwrap_lscm(struct Scene *scene, struct Object *obedit, const short sel)
 
 
 /* uvedit_draw.c */
-void ED_image_draw_cursor(struct ARegion *ar, const float cursor[2]);
-void ED_uvedit_draw_main(struct SpaceImage *sima, struct ARegion *ar, struct Scene *scene, struct Object *obedit, struct Object *obact);
+void ED_image_draw_cursor(
+        struct ARegion *ar, const float cursor[2]);
+void ED_uvedit_draw_main(
+        struct SpaceImage *sima, struct ARegion *ar, struct Scene *scene,
+        struct Object *obedit, struct Object *obact);
 
 /* uvedit_buttons.c */
 void ED_uvedit_buttons_register(struct ARegionType *art);
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index 0357fc8ff01fc873972bb07ad546c7e1c4602d4e..62244979c126d46a0bebf798d8ae933eb83992c7 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -1301,7 +1301,7 @@ int UI_idcode_icon_get(const int idcode)
 {
 	switch (idcode) {
 		case ID_AC:
-			return ICON_ANIM_DATA;
+			return ICON_ACTION;
 		case ID_AR:
 			return ICON_ARMATURE_DATA;
 		case ID_BR:
diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c
index ca4ab30a08d74791d656575a9820109123439261..08181af2ef316cfcb56656ca8a2fb7beb1c021af 100644
--- a/source/blender/editors/io/io_alembic.c
+++ b/source/blender/editors/io/io_alembic.c
@@ -59,6 +59,8 @@
 #include "RNA_define.h"
 #include "RNA_enum_types.h"
 
+#include "ED_object.h"
+
 #include "UI_interface.h"
 #include "UI_resources.h"
 
@@ -543,6 +545,22 @@ static int wm_alembic_import_exec(bContext *C, wmOperator *op)
 		}
 	}
 
+	/* Switch to object mode to avoid being stuck in other modes (T54326). */
+	if (CTX_data_mode_enum(C) != CTX_MODE_OBJECT) {
+		Object *obedit = CTX_data_edit_object(C);
+
+		if (obedit != NULL) {
+			ED_object_mode_toggle(C, obedit->mode);
+		}
+		else {
+			Object *ob = CTX_data_active_object(C);
+
+			if (ob) {
+				ED_object_mode_toggle(C, ob->mode);
+			}
+		}
+	}
+
 	bool ok = ABC_import(C, filename, scale, is_sequence, set_frame_range,
 	                     sequence_len, offset, validate_meshes,
 	                     as_background_job);
diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt
index 8783367ef7ef522175b8ac96f0567367d2c640a9..725d31a64ba927c4937de0964f1526ae7d546afd 100644
--- a/source/blender/editors/mesh/CMakeLists.txt
+++ b/source/blender/editors/mesh/CMakeLists.txt
@@ -58,6 +58,7 @@ set(SRC
 	editmesh_undo.c
 	editmesh_utils.c
 	mesh_data.c
+	mesh_mirror.c
 	mesh_ops.c
 	meshtools.c
 
diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c
index 87c8c55b0a1571a59aefa0496cc489ec8791bd52..c453284a617b8d00caa8f155a3c11cf6dbd05902 100644
--- a/source/blender/editors/mesh/editface.c
+++ b/source/blender/editors/mesh/editface.c
@@ -24,7 +24,6 @@
  *  \ingroup edmesh
  */
 
-
 #include "MEM_guardedalloc.h"
 
 #include "BLI_blenlib.h"
@@ -41,7 +40,6 @@
 #include "BKE_global.h"
 #include "BKE_mesh.h"
 #include "BKE_context.h"
-#include "BKE_editmesh.h"
 
 #include "BIF_gl.h"
 
@@ -605,258 +603,3 @@ void paintvert_select_ungrouped(Object *ob, bool extend, bool flush_flags)
 		paintvert_flush_flags(ob);
 	}
 }
-
-/* ********************* MESH VERTEX MIRR TOPO LOOKUP *************** */
-/* note, this is not the best place for the function to be but moved
- * here for the purpose of syncing with bmesh */
-
-typedef unsigned int MirrTopoHash_t;
-
-typedef struct MirrTopoVert_t {
-	MirrTopoHash_t hash;
-	int v_index;
-} MirrTopoVert_t;
-
-static int mirrtopo_hash_sort(const void *l1, const void *l2)
-{
-	if      ((MirrTopoHash_t)(intptr_t)l1 > (MirrTopoHash_t)(intptr_t)l2) return 1;
-	else if ((MirrTopoHash_t)(intptr_t)l1 < (MirrTopoHash_t)(intptr_t)l2) return -1;
-	return 0;
-}
-
-static int mirrtopo_vert_sort(const void *v1, const void *v2)
-{
-	if      (((MirrTopoVert_t *)v1)->hash > ((MirrTopoVert_t *)v2)->hash) return 1;
-	else if (((MirrTopoVert_t *)v1)->hash < ((MirrTopoVert_t *)v2)->hash) return -1;
-	return 0;
-}
-
-bool ED_mesh_mirrtopo_recalc_check(Mesh *me, DerivedMesh *dm, const int ob_mode, MirrTopoStore_t *mesh_topo_store)
-{
-	int totvert;
-	int totedge;
-
-	if (dm) {
-		totvert = dm->getNumVerts(dm);
-		totedge = dm->getNumEdges(dm);
-	}
-	else if (me->edit_btmesh) {
-		totvert = me->edit_btmesh->bm->totvert;
-		totedge = me->edit_btmesh->bm->totedge;
-	}
-	else {
-		totvert = me->totvert;
-		totedge = me->totedge;
-	}
-
-	if ((mesh_topo_store->index_lookup == NULL) ||
-	    (mesh_topo_store->prev_ob_mode != ob_mode) ||
-	    (totvert != mesh_topo_store->prev_vert_tot) ||
-	    (totedge != mesh_topo_store->prev_edge_tot))
-	{
-		return true;
-	}
-	else {
-		return false;
-	}
-
-}
-
-void ED_mesh_mirrtopo_init(Mesh *me, DerivedMesh *dm, const int ob_mode, MirrTopoStore_t *mesh_topo_store,
-                           const bool skip_em_vert_array_init)
-{
-	MEdge *medge = NULL, *med;
-	BMEditMesh *em = dm ?  NULL : me->edit_btmesh;
-
-	/* editmode*/
-	BMEdge *eed;
-	BMIter iter;
-
-	int a, last;
-	int totvert, totedge;
-	int tot_unique = -1, tot_unique_prev = -1;
-	int tot_unique_edges = 0, tot_unique_edges_prev;
-
-	MirrTopoHash_t *topo_hash = NULL;
-	MirrTopoHash_t *topo_hash_prev = NULL;
-	MirrTopoVert_t *topo_pairs;
-	MirrTopoHash_t  topo_pass = 1;
-
-	intptr_t *index_lookup; /* direct access to mesh_topo_store->index_lookup */
-
-	/* reallocate if needed */
-	ED_mesh_mirrtopo_free(mesh_topo_store);
-
-	mesh_topo_store->prev_ob_mode = ob_mode;
-
-	if (em) {
-		BM_mesh_elem_index_ensure(em->bm, BM_VERT);
-
-		totvert = em->bm->totvert;
-	}
-	else {
-		totvert = dm ? dm->getNumVerts(dm) : me->totvert;
-	}
-
-	topo_hash = MEM_callocN(totvert * sizeof(MirrTopoHash_t), "TopoMirr");
-
-	/* Initialize the vert-edge-user counts used to detect unique topology */
-	if (em) {
-		totedge = me->edit_btmesh->bm->totedge;
-
-		BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
-			const int i1 = BM_elem_index_get(eed->v1), i2 = BM_elem_index_get(eed->v2);
-			topo_hash[i1]++;
-			topo_hash[i2]++;
-		}
-	}
-	else {
-		totedge = dm ? dm->getNumEdges(dm) : me->totedge;
-		medge = dm ? dm->getEdgeArray(dm) : me->medge;
-
-		for (a = 0, med = medge; a < totedge; a++, med++) {
-			const unsigned int i1 = med->v1, i2 = med->v2;
-			topo_hash[i1]++;
-			topo_hash[i2]++;
-		}
-	}
-
-	topo_hash_prev = MEM_dupallocN(topo_hash);
-
-	tot_unique_prev = -1;
-	tot_unique_edges_prev = -1;
-	while (1) {
-		/* use the number of edges per vert to give verts unique topology IDs */
-
-		tot_unique_edges = 0;
-
-		/* This can make really big numbers, wrapping around here is fine */
-		if (em) {
-			BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
-				const int i1 = BM_elem_index_get(eed->v1), i2 = BM_elem_index_get(eed->v2);
-				topo_hash[i1] += topo_hash_prev[i2] * topo_pass;
-				topo_hash[i2] += topo_hash_prev[i1] * topo_pass;
-				tot_unique_edges += (topo_hash[i1] != topo_hash[i2]);
-			}
-		}
-		else {
-			for (a = 0, med = medge; a < totedge; a++, med++) {
-				const unsigned int i1 = med->v1, i2 = med->v2;
-				topo_hash[i1] += topo_hash_prev[i2] * topo_pass;
-				topo_hash[i2] += topo_hash_prev[i1] * topo_pass;
-				tot_unique_edges += (topo_hash[i1] != topo_hash[i2]);
-			}
-		}
-		memcpy(topo_hash_prev, topo_hash, sizeof(MirrTopoHash_t) * totvert);
-
-		/* sort so we can count unique values */
-		qsort(topo_hash_prev, totvert, sizeof(MirrTopoHash_t), mirrtopo_hash_sort);
-
-		tot_unique = 1; /* account for skiping the first value */
-		for (a = 1; a < totvert; a++) {
-			if (topo_hash_prev[a - 1] != topo_hash_prev[a]) {
-				tot_unique++;
-			}
-		}
-
-		if ((tot_unique <= tot_unique_prev) && (tot_unique_edges <= tot_unique_edges_prev)) {
-			/* Finish searching for unique values when 1 loop dosnt give a
-			 * higher number of unique values compared to the previous loop */
-			break;
-		}
-		else {
-			tot_unique_prev = tot_unique;
-			tot_unique_edges_prev = tot_unique_edges;
-		}
-		/* Copy the hash calculated this iter, so we can use them next time */
-		memcpy(topo_hash_prev, topo_hash, sizeof(MirrTopoHash_t) * totvert);
-
-		topo_pass++;
-	}
-
-	/* Hash/Index pairs are needed for sorting to find index pairs */
-	topo_pairs = MEM_callocN(sizeof(MirrTopoVert_t) * totvert, "MirrTopoPairs");
-
-	/* since we are looping through verts, initialize these values here too */
-	index_lookup = MEM_mallocN(totvert * sizeof(*index_lookup), "mesh_topo_lookup");
-
-	if (em) {
-		if (skip_em_vert_array_init == false) {
-			BM_mesh_elem_table_ensure(em->bm, BM_VERT);
-		}
-	}
-
-	for (a = 0; a < totvert; a++) {
-		topo_pairs[a].hash    = topo_hash[a];
-		topo_pairs[a].v_index = a;
-
-		/* initialize lookup */
-		index_lookup[a] = -1;
-	}
-
-	qsort(topo_pairs, totvert, sizeof(MirrTopoVert_t), mirrtopo_vert_sort);
-
-	last = 0;
-
-	/* Get the pairs out of the sorted hashes, note, totvert+1 means we can use the previous 2,
-	 * but you cant ever access the last 'a' index of MirrTopoPairs */
-	if (em) {
-		BMVert **vtable = em->bm->vtable;
-		for (a = 1; a <= totvert; a++) {
-			/* printf("I %d %ld %d\n", (a - last), MirrTopoPairs[a].hash, MirrTopoPairs[a].v_indexs); */
-			if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) {
-				const int match_count = a - last;
-				if (match_count == 2) {
-					const int j = topo_pairs[a - 1].v_index, k = topo_pairs[a - 2].v_index;
-					index_lookup[j] = (intptr_t)vtable[k];
-					index_lookup[k] = (intptr_t)vtable[j];
-				}
-				else if (match_count == 1) {
-					/* Center vertex. */
-					const int j = topo_pairs[a - 1].v_index;
-					index_lookup[j] = (intptr_t)vtable[j];
-				}
-				last = a;
-			}
-		}
-	}
-	else {
-		/* same as above, for mesh */
-		for (a = 1; a <= totvert; a++) {
-			if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) {
-				const int match_count = a - last;
-				if (match_count == 2) {
-					const int j = topo_pairs[a - 1].v_index, k = topo_pairs[a - 2].v_index;
-					index_lookup[j] = k;
-					index_lookup[k] = j;
-				}
-				else if (match_count == 1) {
-					/* Center vertex. */
-					const int j = topo_pairs[a - 1].v_index;
-					index_lookup[j] = j;
-				}
-				last = a;
-			}
-		}
-	}
-
-	MEM_freeN(topo_pairs);
-	topo_pairs = NULL;
-
-	MEM_freeN(topo_hash);
-	MEM_freeN(topo_hash_prev);
-
-	mesh_topo_store->index_lookup  = index_lookup;
-	mesh_topo_store->prev_vert_tot = totvert;
-	mesh_topo_store->prev_edge_tot = totedge;
-}
-
-void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store)
-{
-	if (mesh_topo_store->index_lookup) {
-		MEM_freeN(mesh_topo_store->index_lookup);
-	}
-	mesh_topo_store->index_lookup  = NULL;
-	mesh_topo_store->prev_vert_tot = -1;
-	mesh_topo_store->prev_edge_tot = -1;
-}
diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c
index 77772cfc8cce68db2319e1ff5c713557ec3965aa..22cb28f0b1b84caa6026814a30972a7778f5f3f6 100644
--- a/source/blender/editors/mesh/editmesh_add.c
+++ b/source/blender/editors/mesh/editmesh_add.c
@@ -60,9 +60,10 @@
 
 /* ********* add primitive operators ************* */
 
-static Object *make_prim_init(bContext *C, const char *idname,
-                              float *dia, float mat[4][4],
-                              bool *was_editmode, const float loc[3], const float rot[3], const unsigned int layer)
+static Object *make_prim_init(
+        bContext *C, const char *idname,
+        float *dia, float mat[4][4],
+        bool *was_editmode, const float loc[3], const float rot[3], const unsigned int layer)
 {
 	Object *obedit = CTX_data_edit_object(C);
 
diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c
index 5ac90ec29e68a5eb19224913d0ba8e9d5477f8f6..2c98f05bd27c0b15d4a815fe4a433da3fcca0d9f 100644
--- a/source/blender/editors/mesh/editmesh_extrude.c
+++ b/source/blender/editors/mesh/editmesh_extrude.c
@@ -54,6 +54,10 @@
 
 #include "mesh_intern.h"  /* own include */
 
+/* -------------------------------------------------------------------- */
+/** \name Extrude Internal Utilities
+ * \{ */
+
 static void edbm_extrude_edge_exclude_mirror(
         Object *obedit, BMEditMesh *em,
         const char hflag,
@@ -142,7 +146,7 @@ static bool edbm_extrude_discrete_faces(BMEditMesh *em, wmOperator *op, const ch
 	EDBM_flag_disable_all(em, BM_ELEM_SELECT);
 
 	BMO_op_exec(em->bm, &bmop);
-	
+
 	BMO_ITER (f, &siter, bmop.slots_out, "faces.out", BM_FACE) {
 		BM_face_select_set(em->bm, f, true);
 
@@ -242,7 +246,7 @@ static bool edbm_extrude_ex(
 	BMOIter siter;
 	BMOperator extop;
 	BMElem *ele;
-	
+
 	/* needed to remove the faces left behind */
 	if (htype & BM_FACE) {
 		htype |= BM_EDGE;
@@ -264,7 +268,7 @@ static bool edbm_extrude_ex(
 	BM_SELECT_HISTORY_RESTORE(bm);
 
 	BMO_op_exec(bm, &extop);
-	
+
 	BMO_ITER (ele, &siter, extop.slots_out, "geom.out", BM_ALL_NOLOOP) {
 		BM_elem_select_set(bm, ele, true);
 	}
@@ -274,14 +278,20 @@ static bool edbm_extrude_ex(
 	return true;
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Extrude Repeat Operator
+ * \{ */
+
 static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op)
 {
 	Object *obedit = CTX_data_edit_object(C);
 	BMEditMesh *em = BKE_editmesh_from_object(obedit);
 	RegionView3D *rv3d = CTX_wm_region_view3d(C);
-		
+
 	const int steps = RNA_int_get(op->ptr, "steps");
-	
+
 	const float offs = RNA_float_get(op->ptr, "offset");
 	float dvec[3], tmat[3][3], bmat[3][3];
 	short a;
@@ -302,7 +312,7 @@ static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op)
 		        "translate vec=%v verts=%hv",
 		        dvec, BM_ELEM_SELECT);
 	}
-	
+
 	EDBM_mesh_normals_update(em);
 
 	EDBM_update_generic(em, true, true);
@@ -316,19 +326,25 @@ void MESH_OT_extrude_repeat(wmOperatorType *ot)
 	ot->name = "Extrude Repeat Mesh";
 	ot->description = "Extrude selected vertices, edges or faces repeatedly";
 	ot->idname = "MESH_OT_extrude_repeat";
-	
+
 	/* api callbacks */
 	ot->exec = edbm_extrude_repeat_exec;
 	ot->poll = ED_operator_editmesh_view3d;
-	
+
 	/* flags */
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-	
+
 	/* props */
 	RNA_def_float_distance(ot->srna, "offset", 2.0f, 0.0f, 1e12f, "Offset", "", 0.0f, 100.0f);
 	RNA_def_int(ot->srna, "steps", 10, 0, 1000000, "Steps", "", 0, 180);
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Extrude Operator
+ * \{ */
+
 /* generic extern called extruder */
 static bool edbm_extrude_mesh(Object *obedit, BMEditMesh *em, wmOperator *op)
 {
@@ -365,7 +381,7 @@ static bool edbm_extrude_mesh(Object *obedit, BMEditMesh *em, wmOperator *op)
 			changed = edbm_extrude_edges_indiv(em, op, BM_ELEM_SELECT);
 			break;
 	}
-	
+
 	if (changed) {
 		return true;
 	}
@@ -380,7 +396,7 @@ static int edbm_extrude_region_exec(bContext *C, wmOperator *op)
 {
 	Object *obedit = CTX_data_edit_object(C);
 	BMEditMesh *em = BKE_editmesh_from_object(obedit);
-	
+
 	edbm_extrude_mesh(obedit, em, op);
 
 	/* This normally happens when pushing undo but modal operators
@@ -389,7 +405,7 @@ static int edbm_extrude_region_exec(bContext *C, wmOperator *op)
 	EDBM_mesh_normals_update(em);
 
 	EDBM_update_generic(em, true, true);
-	
+
 	return OPERATOR_FINISHED;
 }
 
@@ -399,27 +415,33 @@ void MESH_OT_extrude_region(wmOperatorType *ot)
 	ot->name = "Extrude Region";
 	ot->idname = "MESH_OT_extrude_region";
 	ot->description = "Extrude region of faces";
-	
+
 	/* api callbacks */
 	//ot->invoke = mesh_extrude_region_invoke;
 	ot->exec = edbm_extrude_region_exec;
 	ot->poll = ED_operator_editmesh;
-	
+
 	/* flags */
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
 	Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY);
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Extrude Verts Operator
+ * \{ */
+
 static int edbm_extrude_verts_exec(bContext *C, wmOperator *op)
 {
 	Object *obedit = CTX_data_edit_object(C);
 	BMEditMesh *em = BKE_editmesh_from_object(obedit);
 
 	edbm_extrude_verts_indiv(em, op, BM_ELEM_SELECT);
-	
+
 	EDBM_update_generic(em, true, true);
-	
+
 	return OPERATOR_FINISHED;
 }
 
@@ -429,11 +451,11 @@ void MESH_OT_extrude_verts_indiv(wmOperatorType *ot)
 	ot->name = "Extrude Only Vertices";
 	ot->idname = "MESH_OT_extrude_verts_indiv";
 	ot->description = "Extrude individual vertices only";
-	
+
 	/* api callbacks */
 	ot->exec = edbm_extrude_verts_exec;
 	ot->poll = ED_operator_editmesh;
-	
+
 	/* flags */
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
@@ -441,15 +463,21 @@ void MESH_OT_extrude_verts_indiv(wmOperatorType *ot)
 	Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY);
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Extrude Edges Operator
+ * \{ */
+
 static int edbm_extrude_edges_exec(bContext *C, wmOperator *op)
 {
 	Object *obedit = CTX_data_edit_object(C);
 	BMEditMesh *em = BKE_editmesh_from_object(obedit);
 
 	edbm_extrude_edges_indiv(em, op, BM_ELEM_SELECT);
-	
+
 	EDBM_update_generic(em, true, true);
-	
+
 	return OPERATOR_FINISHED;
 }
 
@@ -459,11 +487,11 @@ void MESH_OT_extrude_edges_indiv(wmOperatorType *ot)
 	ot->name = "Extrude Only Edges";
 	ot->idname = "MESH_OT_extrude_edges_indiv";
 	ot->description = "Extrude individual edges only";
-	
+
 	/* api callbacks */
 	ot->exec = edbm_extrude_edges_exec;
 	ot->poll = ED_operator_editmesh;
-	
+
 	/* flags */
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
@@ -471,15 +499,21 @@ void MESH_OT_extrude_edges_indiv(wmOperatorType *ot)
 	Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY);
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Extrude Faces Operator
+ * \{ */
+
 static int edbm_extrude_faces_exec(bContext *C, wmOperator *op)
 {
 	Object *obedit = CTX_data_edit_object(C);
 	BMEditMesh *em = BKE_editmesh_from_object(obedit);
 
 	edbm_extrude_discrete_faces(em, op, BM_ELEM_SELECT);
-	
+
 	EDBM_update_generic(em, true, true);
-	
+
 	return OPERATOR_FINISHED;
 }
 
@@ -489,18 +523,25 @@ void MESH_OT_extrude_faces_indiv(wmOperatorType *ot)
 	ot->name = "Extrude Individual Faces";
 	ot->idname = "MESH_OT_extrude_faces_indiv";
 	ot->description = "Extrude individual faces only";
-	
+
 	/* api callbacks */
 	ot->exec = edbm_extrude_faces_exec;
 	ot->poll = ED_operator_editmesh;
-	
+
 	/* flags */
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
 	Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY);
 }
 
-/* *************** add-click-mesh (extrude) operator ************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Dupli-Extrude Operator
+ *
+ * Add-click-mesh (extrude) operator.
+ * \{ */
+
 static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *event)
 {
 	ViewContext vc;
@@ -521,7 +562,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
 
 	zero_v3(center);
 	verts_len = 0;
-	
+
 	BM_ITER_MESH (v1, &iter, vc.em->bm, BM_VERTS_OF_MESH) {
 		if (BM_elem_flag_test(v1, BM_ELEM_SELECT)) {
 			add_v3_v3(center, v1->co);
@@ -584,7 +625,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
 			cross_v3_v3v3(nor, view_vec, cross);
 			normalize_v3(nor);
 		}
-		
+
 		/* center */
 		copy_v3_v3(ofs, center);
 
@@ -593,7 +634,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
 		mul_m4_v3(vc.obedit->imat, ofs); // back in object space
 
 		sub_v3_v3(ofs, center);
-		
+
 		/* calculate rotation */
 		unit_m3(mat);
 		if (done) {
@@ -616,7 +657,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
 				axis_angle_to_mat3(mat, axis, angle);
 			}
 		}
-		
+
 		if (rot_src) {
 			EDBM_op_callf(vc.em, op, "rotate verts=%hv cent=%v matrix=%m3",
 			              BM_ELEM_SELECT, center, mat);
@@ -641,7 +682,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
 		ED_view3d_win_to_3d_int(vc.v3d, vc.ar, center, event->mval, center);
 
 		mul_m4_v3(vc.obedit->imat, center); // back in object space
-		
+
 		EDBM_op_init(vc.em, &bmop, op, "create_vert co=%v", center);
 		BMO_op_exec(vc.em->bm, &bmop);
 
@@ -673,17 +714,22 @@ void MESH_OT_dupli_extrude_cursor(wmOperatorType *ot)
 	ot->name = "Duplicate or Extrude to Cursor";
 	ot->idname = "MESH_OT_dupli_extrude_cursor";
 	ot->description = "Duplicate and extrude selected vertices, edges or faces towards the mouse cursor";
-	
+
 	/* api callbacks */
 	ot->invoke = edbm_dupli_extrude_cursor_invoke;
 	ot->poll = ED_operator_editmesh_region_view3d;
-	
+
 	/* flags */
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
 	RNA_def_boolean(ot->srna, "rotate_source", true, "Rotate Source", "Rotate initial selection giving better shape");
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Spin Operator
+ * \{ */
 
 static int edbm_spin_exec(bContext *C, wmOperator *op)
 {
@@ -780,6 +826,12 @@ void MESH_OT_spin(wmOperatorType *ot)
 
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Screw Operator
+ * \{ */
+
 static int edbm_screw_exec(bContext *C, wmOperator *op)
 {
 	Object *obedit = CTX_data_edit_object(C);
@@ -910,3 +962,5 @@ void MESH_OT_screw(wmOperatorType *ot)
 	RNA_def_float_vector(ot->srna, "axis", 3, NULL, -1.0f, 1.0f,
 	                     "Axis", "Axis in global view space", -1.0f, 1.0f);
 }
+
+/** \} */
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index 76a0d874a0b3fdb91479fdb61f2b68fbb2622a14..3ce9257de0c69ae625e55de792a24d2758568e93 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -1762,7 +1762,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
 	}
 
 	kcd->linehits = linehits;
-	kcd->totlinehit = BLI_array_count(linehits);
+	kcd->totlinehit = BLI_array_len(linehits);
 
 	/* find position along screen line, used for sorting */
 	for (i = 0; i < kcd->totlinehit; i++) {
diff --git a/source/blender/editors/mesh/editmesh_path.c b/source/blender/editors/mesh/editmesh_path.c
index a85d2425b3c9e0d8e4be32fd3def47cd284eb726..bf5a7e3a053c7e79b07ae58c01a2d59fa8e5ab75 100644
--- a/source/blender/editors/mesh/editmesh_path.c
+++ b/source/blender/editors/mesh/editmesh_path.c
@@ -61,6 +61,10 @@
 
 #include "mesh_intern.h"  /* own include */
 
+/* -------------------------------------------------------------------- */
+/** \name Path Select Struct & Properties
+ * \{ */
+
 struct PathSelectParams {
 	bool track_active;  /* ensure the active element is the last selected item (handy for picking) */
 	bool use_topology_distance;
@@ -100,8 +104,11 @@ struct UserData {
 	const struct PathSelectParams *op_params;
 };
 
+/** \} */
+
 /* -------------------------------------------------------------------- */
-/* Vert Path */
+/** \name Vert Path
+ * \{ */
 
 /* callbacks */
 static bool verttag_filter_cb(BMVert *v, void *UNUSED(user_data_v))
@@ -204,10 +211,11 @@ static void mouse_mesh_shortest_path_vert(
 	EDBM_update_generic(em, false, false);
 }
 
-
+/** \} */
 
 /* -------------------------------------------------------------------- */
-/* Edge Path */
+/** \name Edge Path
+ * \{ */
 
 /* callbacks */
 static bool edgetag_filter_cb(BMEdge *e, void *UNUSED(user_data_v))
@@ -427,10 +435,11 @@ static void mouse_mesh_shortest_path_edge(
 	EDBM_update_generic(em, false, false);
 }
 
-
+/** \} */
 
 /* -------------------------------------------------------------------- */
-/* Face Path */
+/** \name Face Path
+ * \{ */
 
 /* callbacks */
 static bool facetag_filter_cb(BMFace *f, void *UNUSED(user_data_v))
@@ -478,7 +487,6 @@ static void mouse_mesh_shortest_path_face(
 			        facetag_filter_cb, &user_data);
 		}
 
-
 		if (f_act != f_dst) {
 			if (path) {
 				if (op_params->track_active) {
@@ -539,10 +547,11 @@ static void mouse_mesh_shortest_path_face(
 	EDBM_update_generic(em, false, false);
 }
 
-
+/** \} */
 
 /* -------------------------------------------------------------------- */
-/* Main Operator for vert/edge/face tag */
+/** \name Main Operator for vert/edge/face tag
+ * \{ */
 
 static bool edbm_shortest_path_pick_ex(
         Scene *scene, const struct PathSelectParams *op_params,
@@ -709,9 +718,11 @@ void MESH_OT_shortest_path_pick(wmOperatorType *ot)
 	RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
 }
 
+/** \} */
 
 /* -------------------------------------------------------------------- */
-/* Select path between existing selection */
+/** \name Select Path Between Existing Selection
+ * \{ */
 
 static int edbm_shortest_path_select_exec(bContext *C, wmOperator *op)
 {
@@ -796,3 +807,5 @@ void MESH_OT_shortest_path_select(wmOperatorType *ot)
 	/* properties */
 	path_select_properties(ot);
 }
+
+/** \} */
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index f0ad491e148ce92e798e212d49680fa6bea0acd1..181fc4c0c52b9a2383ea28a95830c67c914da498 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -73,7 +73,9 @@
 /* use bmesh operator flags for a few operators */
 #define BMO_ELE_TAG 1
 
-/* ****************************** MIRROR **************** */
+/* -------------------------------------------------------------------- */
+/** \name Select Mirror
+ * \{ */
 
 void EDBM_select_mirrored(
         BMEditMesh *em, const int axis, const bool extend,
@@ -166,21 +168,34 @@ void EDBM_select_mirrored(
 	*r_totfail = totfail;
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Auto-Merge
+ *
+ * Used after transform operations.
+ * \{ */
+
 void EDBM_automerge(Scene *scene, Object *obedit, bool update, const char hflag)
 {
 	bool ok;
 	BMEditMesh *em = BKE_editmesh_from_object(obedit);
 
-	ok = BMO_op_callf(em->bm, BMO_FLAG_DEFAULTS,
-	                  "automerge verts=%hv dist=%f",
-	                  hflag, scene->toolsettings->doublimit);
+	ok = BMO_op_callf(
+	        em->bm, BMO_FLAG_DEFAULTS,
+	        "automerge verts=%hv dist=%f",
+	        hflag, scene->toolsettings->doublimit);
 
 	if (LIKELY(ok) && update) {
 		EDBM_update_generic(em, true, true);
 	}
 }
 
-/* ****************************** SELECTION ROUTINES **************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Back-Buffer OpenGL Selection
+ * \{ */
 
 unsigned int bm_solidoffs = 0, bm_wireoffs = 0, bm_vertoffs = 0;    /* set in drawobject.c ... for colorindices */
 
@@ -199,21 +214,21 @@ bool EDBM_backbuf_border_init(ViewContext *vc, short xmin, short ymin, short xma
 	struct ImBuf *buf;
 	unsigned int *dr;
 	int a;
-	
+
 	if (vc->obedit == NULL || !V3D_IS_ZBUF(vc->v3d)) {
 		return false;
 	}
-	
+
 	buf = ED_view3d_backbuf_read(vc, xmin, ymin, xmax, ymax);
 	if ((buf == NULL) || (bm_vertoffs == 0)) {
 		return false;
 	}
 
 	dr = buf->rect;
-	
+
 	/* build selection lookup */
 	selbuf = edbm_backbuf_alloc(bm_vertoffs + 1);
-	
+
 	a = (xmax - xmin + 1) * (ymax - ymin + 1);
 	while (a--) {
 		if (*dr > 0 && *dr <= bm_vertoffs) {
@@ -263,9 +278,9 @@ static void edbm_mask_lasso_px_cb(int x, int x_end, int y, void *user_data)
 
 /* mcords is a polygon mask
  * - grab backbuffer,
- * - draw with black in backbuffer, 
+ * - draw with black in backbuffer,
  * - grab again and compare
- * returns 'OK' 
+ * returns 'OK'
  */
 bool EDBM_backbuf_border_mask_init(ViewContext *vc, const int mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax)
 {
@@ -273,7 +288,7 @@ bool EDBM_backbuf_border_mask_init(ViewContext *vc, const int mcords[][2], short
 	struct ImBuf *buf;
 	int a;
 	struct LassoMaskData lasso_mask_data;
-	
+
 	/* method in use for face selecting too */
 	if (vc->obedit == NULL) {
 		if (!BKE_paint_select_elem_test(vc->obact)) {
@@ -302,7 +317,7 @@ bool EDBM_backbuf_border_mask_init(ViewContext *vc, const int mcords[][2], short
 
 	/* build selection lookup */
 	selbuf = edbm_backbuf_alloc(bm_vertoffs + 1);
-	
+
 	a = (xmax - xmin + 1) * (ymax - ymin + 1);
 	while (a--) {
 		if (*dr > 0 && *dr <= bm_vertoffs && *dr_mask == true) {
@@ -323,7 +338,7 @@ bool EDBM_backbuf_circle_init(ViewContext *vc, short xs, short ys, short rads)
 	unsigned int *dr;
 	short xmin, ymin, xmax, ymax, xc, yc;
 	int radsq;
-	
+
 	/* method in use for face selecting too */
 	if (vc->obedit == NULL) {
 		if (!BKE_paint_select_elem_test(vc->obact)) {
@@ -342,7 +357,7 @@ bool EDBM_backbuf_circle_init(ViewContext *vc, short xs, short ys, short rads)
 	}
 
 	dr = buf->rect;
-	
+
 	/* build selection lookup */
 	selbuf = edbm_backbuf_alloc(bm_vertoffs + 1);
 	radsq = rads * rads;
@@ -358,12 +373,12 @@ bool EDBM_backbuf_circle_init(ViewContext *vc, short xs, short ys, short rads)
 
 	IMB_freeImBuf(buf);
 	return true;
-	
+
 }
 
+/** \} */
 
 /* -------------------------------------------------------------------- */
-
 /** \name Find Nearest Vert/Edge/Face
  *
  * \note Screen-space manhatten distances are used here,
@@ -445,14 +460,14 @@ BMVert *EDBM_vert_find_nearest_ex(
 		float dist_test;
 		unsigned int index;
 		BMVert *eve;
-		
+
 		/* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */
 		ED_view3d_backbuf_validate(vc);
 
 		index = ED_view3d_backbuf_sample_rect(
 		        vc, vc->mval, dist_px, bm_wireoffs, 0xFFFFFF, &dist_test);
 		eve = index ? BM_vert_at_index_find_or_table(bm, index - 1) : NULL;
-		
+
 		if (eve) {
 			if (dist_test < *r_dist) {
 				*r_dist = dist_test;
@@ -811,7 +826,7 @@ BMFace *EDBM_face_find_nearest_ex(
 
 		index = ED_view3d_backbuf_sample(vc, vc->mval[0], vc->mval[1]);
 		efa = index ? BM_face_at_index_find_or_table(bm, index - 1) : NULL;
-		
+
 		if (r_efa_zbuf) {
 			*r_efa_zbuf = efa;
 		}
@@ -889,8 +904,8 @@ BMFace *EDBM_face_find_nearest(ViewContext *vc, float *r_dist)
 #undef FIND_NEAR_CYCLE_THRESHOLD_MIN
 
 
-/* best distance based on screen coords. 
- * use em->selectmode to define how to use 
+/* best distance based on screen coords.
+ * use em->selectmode to define how to use
  * selected vertices and edges get disadvantage
  * return 1 if found one
  */
@@ -906,7 +921,7 @@ static int unified_findnearest(ViewContext *vc, BMVert **r_eve, BMEdge **r_eed,
 	float dist = dist_init;
 	BMFace *efa_zbuf = NULL;
 	BMEdge *eed_zbuf = NULL;
-	
+
 	BMVert *eve = NULL;
 	BMEdge *eed = NULL;
 	BMFace *efa = NULL;
@@ -968,8 +983,10 @@ static int unified_findnearest(ViewContext *vc, BMVert **r_eve, BMEdge **r_eed,
 
 /** \} */
 
+/* -------------------------------------------------------------------- */
+/** \name Select Similar (Vert/Edge/Face) Operator
+ * \{ */
 
-/* ****************  SIMILAR "group" SELECTS. FACE, EDGE AND VERTEX ************** */
 static const EnumPropertyItem prop_similar_compare_types[] = {
 	{SIM_CMP_EQ, "EQUAL", 0, "Equal", ""},
 	{SIM_CMP_GT, "GREATER", 0, "Greater", ""},
@@ -1046,7 +1063,7 @@ static int similar_face_select_exec(bContext *C, wmOperator *op)
 	EDBM_update_generic(em, false, false);
 
 	return OPERATOR_FINISHED;
-}	
+}
 
 /* ***************************************************** */
 
@@ -1152,8 +1169,9 @@ static int edbm_select_similar_exec(bContext *C, wmOperator *op)
 	else                 return similar_face_select_exec(C, op);
 }
 
-static const EnumPropertyItem *select_similar_type_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop),
-                                                   bool *r_free)
+static const EnumPropertyItem *select_similar_type_itemf(
+        bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop),
+        bool *r_free)
 {
 	Object *obedit;
 
@@ -1205,15 +1223,15 @@ void MESH_OT_select_similar(wmOperatorType *ot)
 	ot->name = "Select Similar";
 	ot->idname = "MESH_OT_select_similar";
 	ot->description = "Select similar vertices, edges or faces by property types";
-	
+
 	/* api callbacks */
 	ot->invoke = WM_menu_invoke;
 	ot->exec = edbm_select_similar_exec;
 	ot->poll = ED_operator_editmesh;
-	
+
 	/* flags */
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-	
+
 	/* properties */
 	prop = ot->prop = RNA_def_enum(ot->srna, "type", prop_similar_types, SIMVERT_NORMAL, "Type", "");
 	RNA_def_enum_funcs(prop, select_similar_type_itemf);
@@ -1223,9 +1241,11 @@ void MESH_OT_select_similar(wmOperatorType *ot)
 	RNA_def_float(ot->srna, "threshold", 0.0f, 0.0f, 1.0f, "Threshold", "", 0.0f, 1.0f);
 }
 
+/** \} */
 
 /* -------------------------------------------------------------------- */
-/* Select Similar Regions */
+/** \name Select Similar Region Operator
+ * \{ */
 
 static int edbm_select_similar_region_exec(bContext *C, wmOperator *op)
 {
@@ -1246,9 +1266,10 @@ static int edbm_select_similar_region_exec(bContext *C, wmOperator *op)
 	}
 
 	groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totfacesel, __func__);
-	group_tot = BM_mesh_calc_face_groups(bm, groups_array, &group_index,
-	                                     NULL, NULL,
-	                                     BM_ELEM_SELECT, BM_VERT);
+	group_tot = BM_mesh_calc_face_groups(
+	        bm, groups_array, &group_index,
+	        NULL, NULL,
+	        BM_ELEM_SELECT, BM_VERT);
 
 	BM_mesh_elem_table_ensure(bm, BM_FACE);
 
@@ -1313,8 +1334,11 @@ void MESH_OT_select_similar_region(wmOperatorType *ot)
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 }
 
+/** \} */
 
-/* ****************  Mode Select *************** */
+/* -------------------------------------------------------------------- */
+/** \name Select Mode Vert/Edge/Face Operator
+ * \{ */
 
 static int edbm_select_mode_exec(bContext *C, wmOperator *op)
 {
@@ -1385,12 +1409,15 @@ void MESH_OT_select_mode(wmOperatorType *ot)
 	RNA_def_enum(ot->srna, "action", actions_items, 2, "Action", "Selection action to execute");
 }
 
-/* ***************************************************** */
+/** \} */
 
-/* ****************  LOOP SELECTS *************** */
+/* -------------------------------------------------------------------- */
+/** \name Select Loop (Non Modal) Operator
+ * \{ */
 
-static void walker_select_count(BMEditMesh *em, int walkercode, void *start, const bool select, const bool select_mix,
-                                int *r_totsel, int *r_totunsel)
+static void walker_select_count(
+        BMEditMesh *em, int walkercode, void *start, const bool select, const bool select_mix,
+        int *r_totsel, int *r_totunsel)
 {
 	BMesh *bm = em->bm;
 	BMElem *ele;
@@ -1445,7 +1472,7 @@ static int edbm_loop_multiselect_exec(bContext *C, wmOperator *op)
 	BMEdge **edarray;
 	int edindex;
 	const bool is_ring = RNA_boolean_get(op->ptr, "ring");
-	
+
 	BMIter iter;
 	int totedgesel = 0;
 
@@ -1454,17 +1481,17 @@ static int edbm_loop_multiselect_exec(bContext *C, wmOperator *op)
 			totedgesel++;
 		}
 	}
-	
+
 	edarray = MEM_mallocN(sizeof(BMEdge *) * totedgesel, "edge array");
 	edindex = 0;
-	
+
 	BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
 		if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
 			edarray[edindex] = eed;
 			edindex++;
 		}
 	}
-	
+
 	if (is_ring) {
 		for (edindex = 0; edindex < totedgesel; edindex += 1) {
 			eed = edarray[edindex];
@@ -1481,7 +1508,7 @@ static int edbm_loop_multiselect_exec(bContext *C, wmOperator *op)
 	}
 	MEM_freeN(edarray);
 //	if (EM_texFaceCheck())
-	
+
 	WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
 
 	return OPERATOR_FINISHED;
@@ -1493,23 +1520,23 @@ void MESH_OT_loop_multi_select(wmOperatorType *ot)
 	ot->name = "Multi Select Loops";
 	ot->idname = "MESH_OT_loop_multi_select";
 	ot->description = "Select a loop of connected edges by connection type";
-	
+
 	/* api callbacks */
 	ot->exec = edbm_loop_multiselect_exec;
 	ot->poll = ED_operator_editmesh;
-	
+
 	/* flags */
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-	
+
 	/* properties */
 	RNA_def_boolean(ot->srna, "ring", 0, "Ring", "");
 }
 
-		
-/* ***************** MAIN MOUSE SELECTION ************** */
-
+/** \} */
 
-/* ***************** loop select (non modal) ************** */
+/* -------------------------------------------------------------------- */
+/** \name Select Loop (Cursor Pick) Operator
+ * \{ */
 
 static void mouse_mesh_loop_face(BMEditMesh *em, BMEdge *eed, bool select, bool select_clear)
 {
@@ -1564,7 +1591,6 @@ static void mouse_mesh_loop_edge(BMEditMesh *em, BMEdge *eed, bool select, bool
 	}
 }
 
-
 static bool mouse_mesh_loop(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle, bool ring)
 {
 	ViewContext vc;
@@ -1641,11 +1667,15 @@ static bool mouse_mesh_loop(bContext *C, const int mval[2], bool extend, bool de
 			/* We can't be sure this has already been set... */
 			ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
 
-			if (ED_view3d_project_float_object(vc.ar, eed->v1->co, v1_co, V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) {
+			if (ED_view3d_project_float_object(
+			            vc.ar, eed->v1->co, v1_co, V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
+			{
 				length_1 = len_squared_v2v2(mvalf, v1_co);
 			}
 
-			if (ED_view3d_project_float_object(vc.ar, eed->v2->co, v2_co, V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) {
+			if (ED_view3d_project_float_object(
+			            vc.ar, eed->v2->co, v2_co, V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
+			{
 				length_2 = len_squared_v2v2(mvalf, v2_co);
 			}
 #if 0
@@ -1672,7 +1702,9 @@ static bool mouse_mesh_loop(bContext *C, const int mval[2], bool extend, bool de
 					float co[2], tdist;
 
 					BM_face_calc_center_mean(f, cent);
-					if (ED_view3d_project_float_object(vc.ar, cent, co, V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) {
+					if (ED_view3d_project_float_object(
+					            vc.ar, cent, co, V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
+					{
 						tdist = len_squared_v2v2(mvalf, co);
 						if (tdist < best_dist) {
 /*							printf("Best face: %p (%f)\n", f, tdist);*/
@@ -1696,14 +1728,15 @@ static bool mouse_mesh_loop(bContext *C, const int mval[2], bool extend, bool de
 
 static int edbm_select_loop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
 {
-	
+
 	view3d_operator_needs_opengl(C);
-	
-	if (mouse_mesh_loop(C, event->mval,
-	                    RNA_boolean_get(op->ptr, "extend"),
-	                    RNA_boolean_get(op->ptr, "deselect"),
-	                    RNA_boolean_get(op->ptr, "toggle"),
-	                    RNA_boolean_get(op->ptr, "ring")))
+
+	if (mouse_mesh_loop(
+	            C, event->mval,
+	            RNA_boolean_get(op->ptr, "extend"),
+	            RNA_boolean_get(op->ptr, "deselect"),
+	            RNA_boolean_get(op->ptr, "toggle"),
+	            RNA_boolean_get(op->ptr, "ring")))
 	{
 		return OPERATOR_FINISHED;
 	}
@@ -1718,14 +1751,14 @@ void MESH_OT_loop_select(wmOperatorType *ot)
 	ot->name = "Loop Select";
 	ot->idname = "MESH_OT_loop_select";
 	ot->description = "Select a loop of connected edges";
-	
+
 	/* api callbacks */
 	ot->invoke = edbm_select_loop_invoke;
 	ot->poll = ED_operator_editmesh_region_view3d;
-	
+
 	/* flags */
 	ot->flag = OPTYPE_UNDO;
-	
+
 	/* properties */
 	RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "Extend the selection");
 	RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Remove from the selection");
@@ -1739,11 +1772,11 @@ void MESH_OT_edgering_select(wmOperatorType *ot)
 	ot->name = "Edge Ring Select";
 	ot->idname = "MESH_OT_edgering_select";
 	ot->description = "Select an edge ring";
-	
+
 	/* callbacks */
 	ot->invoke = edbm_select_loop_invoke;
 	ot->poll = ED_operator_editmesh_region_view3d;
-	
+
 	/* flags */
 	ot->flag = OPTYPE_UNDO;
 
@@ -1753,7 +1786,12 @@ void MESH_OT_edgering_select(wmOperatorType *ot)
 	RNA_def_boolean(ot->srna, "ring", 1, "Select Ring", "Select ring");
 }
 
-/* ******************** (de)select all operator **************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name (De)Select All Operator
+ * \{ */
+
 static int edbm_select_all_exec(bContext *C, wmOperator *op)
 {
 	Object *obedit = CTX_data_edit_object(C);
@@ -1798,6 +1836,12 @@ void MESH_OT_select_all(wmOperatorType *ot)
 	WM_operator_properties_select_all(ot);
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Interior Faces Operator
+ * \{ */
+
 static int edbm_faces_select_interior_exec(bContext *C, wmOperator *UNUSED(op))
 {
 	Object *obedit = CTX_data_edit_object(C);
@@ -1829,10 +1873,15 @@ void MESH_OT_select_interior_faces(wmOperatorType *ot)
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Picking API
+ *
+ * Here actual select happens,
+ * Gets called via generic mouse select operator.
+ * \{ */
 
-/* ************************************************** */
-/* here actual select happens */
-/* gets called via generic mouse select operator */
 bool EDBM_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
 {
 	ViewContext vc;
@@ -1948,6 +1997,12 @@ bool EDBM_select_pick(bContext *C, const int mval[2], bool extend, bool deselect
 	return false;
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Mode Utilities
+ * \{ */
+
 static void edbm_strip_selections(BMEditMesh *em)
 {
 	BMEditSelection *ese, *nextese;
@@ -1986,11 +2041,11 @@ void EDBM_selectmode_set(BMEditMesh *em)
 	BMEdge *eed;
 	BMFace *efa;
 	BMIter iter;
-	
+
 	em->bm->selectmode = em->selectmode;
 
 	edbm_strip_selections(em); /* strip BMEditSelections from em->selected that are not relevant to new mode */
-	
+
 	if (em->bm->totvertsel == 0 &&
 	    em->bm->totedgesel == 0 &&
 	    em->bm->totfacesel == 0)
@@ -2153,8 +2208,9 @@ void EDBM_selectmode_convert(BMEditMesh *em, const short selectmode_old, const s
 }
 
 /* user facing function, does notification */
-bool EDBM_selectmode_toggle(bContext *C, const short selectmode_new,
-                            const int action, const bool use_extend, const bool use_expand)
+bool EDBM_selectmode_toggle(
+        bContext *C, const short selectmode_new,
+        const int action, const bool use_extend, const bool use_expand)
 {
 	ToolSettings *ts = CTX_data_tool_settings(C);
 	Object *obedit = CTX_data_edit_object(C);
@@ -2250,9 +2306,10 @@ bool EDBM_selectmode_toggle(bContext *C, const short selectmode_new,
  *
  * \return true if the mode is changed.
  */
-bool EDBM_selectmode_disable(Scene *scene, BMEditMesh *em,
-                             const short selectmode_disable,
-                             const short selectmode_fallback)
+bool EDBM_selectmode_disable(
+        Scene *scene, BMEditMesh *em,
+        const short selectmode_disable,
+        const short selectmode_fallback)
 {
 	/* note essential, but switch out of vertex mode since the
 	 * selected regions wont be nicely isolated after flushing */
@@ -2275,6 +2332,12 @@ bool EDBM_selectmode_disable(Scene *scene, BMEditMesh *em,
 	}
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Toggle
+ * \{ */
+
 void EDBM_deselect_by_material(BMEditMesh *em, const short index, const bool select)
 {
 	BMIter iter;
@@ -2303,7 +2366,7 @@ void EDBM_select_swap(BMEditMesh *em) /* exported for UV */
 	BMVert *eve;
 	BMEdge *eed;
 	BMFace *efa;
-	
+
 	if (em->bm->selectmode & SCE_SELECT_VERTEX) {
 		BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
 			if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN))
@@ -2326,9 +2389,17 @@ void EDBM_select_swap(BMEditMesh *em) /* exported for UV */
 		}
 
 	}
-//	if (EM_texFaceCheck())
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Interior Faces
+ *
+ * \note This algorithm is limited to single faces and could be improved, see:
+ * https://blender.stackexchange.com/questions/18916
+ * \{ */
+
 bool EDBM_select_interior_faces(BMEditMesh *em)
 {
 	BMesh *bm = em->bm;
@@ -2361,8 +2432,13 @@ bool EDBM_select_interior_faces(BMEditMesh *em)
 	return changed;
 }
 
+/** \} */
 
-/************************ Select Linked Operator *************************/
+/* -------------------------------------------------------------------- */
+/** \name Select Linked Operator
+ *
+ * Support delimiting on different edge properties.
+ * \{ */
 
 /* so we can have last-used default depend on selection mode (rare exception!) */
 #define USE_LINKED_SELECT_DEFAULT_HACK
@@ -2422,10 +2498,10 @@ static bool select_linked_delimit_test(
  * Gets the default from the operator fallback to own last-used value
  * (selected based on mode)
  */
-static int select_linked_delimit_default_from_op(wmOperator *op, BMEditMesh *em)
+static int select_linked_delimit_default_from_op(wmOperator *op, int select_mode)
 {
 	static char delimit_last_store[2] = {0, BMO_DELIM_SEAM};
-	int delimit_last_index = (em->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) == 0;
+	int delimit_last_index = (select_mode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) == 0;
 	char *delimit_last = &delimit_last_store[delimit_last_index];
 	PropertyRNA *prop_delimit = RNA_struct_find_property(op->ptr, "delimit");
 	int delimit;
@@ -2495,7 +2571,7 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op)
 	BMWalker walker;
 
 #ifdef USE_LINKED_SELECT_DEFAULT_HACK
-	int delimit = select_linked_delimit_default_from_op(op, em);
+	int delimit = select_linked_delimit_default_from_op(op, em->selectmode);
 #else
 	int delimit = RNA_enum_get(op->ptr, "delimit");
 #endif
@@ -2683,6 +2759,12 @@ void MESH_OT_select_linked(wmOperatorType *ot)
 #endif
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Linked (Cursor Pick) Operator
+ * \{ */
+
 static int edbm_select_linked_pick_exec(bContext *C, wmOperator *op);
 
 static void edbm_select_linked_pick_ex(BMEditMesh *em, BMElem *ele, bool sel, int delimit)
@@ -2827,7 +2909,7 @@ static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmE
 	}
 
 #ifdef USE_LINKED_SELECT_DEFAULT_HACK
-	int delimit = select_linked_delimit_default_from_op(op, em);
+	int delimit = select_linked_delimit_default_from_op(op, em->selectmode);
 #else
 	int delimit = RNA_enum_get(op->ptr, "delimit");
 #endif
@@ -2864,7 +2946,7 @@ static int edbm_select_linked_pick_exec(bContext *C, wmOperator *op)
 	BMElem *ele = EDBM_elem_from_index_any(em, index);
 
 #ifdef USE_LINKED_SELECT_DEFAULT_HACK
-	int delimit = select_linked_delimit_default_from_op(op, em);
+	int delimit = select_linked_delimit_default_from_op(op, em->selectmode);
 #else
 	int delimit = RNA_enum_get(op->ptr, "delimit");
 #endif
@@ -2884,15 +2966,15 @@ void MESH_OT_select_linked_pick(wmOperatorType *ot)
 	ot->name = "Select Linked";
 	ot->idname = "MESH_OT_select_linked_pick";
 	ot->description = "(De)select all vertices linked to the edge under the mouse cursor";
-	
+
 	/* api callbacks */
 	ot->invoke = edbm_select_linked_pick_invoke;
 	ot->exec = edbm_select_linked_pick_exec;
 	ot->poll = ED_operator_editmesh;
-	
+
 	/* flags */
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-	
+
 	RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
 	prop = RNA_def_enum_flag(ot->srna, "delimit", rna_enum_mesh_delimit_mode_items, BMO_DELIM_SEAM, "Delimit",
 	                         "Delimit selected region");
@@ -2905,6 +2987,11 @@ void MESH_OT_select_linked_pick(wmOperatorType *ot)
 	RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Face by Sides Operator
+ * \{ */
 
 static int edbm_select_face_by_sides_exec(bContext *C, wmOperator *op)
 {
@@ -2980,6 +3067,11 @@ void MESH_OT_select_face_by_sides(wmOperatorType *ot)
 	RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend the selection");
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Loose Operator
+ * \{ */
 
 static int edbm_select_loose_exec(bContext *C, wmOperator *op)
 {
@@ -3051,6 +3143,11 @@ void MESH_OT_select_loose(wmOperatorType *ot)
 	RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Mirror Operator
+ * \{ */
 
 static int edbm_select_mirror_exec(bContext *C, wmOperator *op)
 {
@@ -3099,7 +3196,11 @@ void MESH_OT_select_mirror(wmOperatorType *ot)
 	RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the existing selection");
 }
 
-/* ******************** **************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select More Operator
+ * \{ */
 
 static int edbm_select_more_exec(bContext *C, wmOperator *op)
 {
@@ -3123,13 +3224,19 @@ void MESH_OT_select_more(wmOperatorType *ot)
 	/* api callbacks */
 	ot->exec = edbm_select_more_exec;
 	ot->poll = ED_operator_editmesh;
-	
+
 	/* flags */
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
 	RNA_def_boolean(ot->srna, "use_face_step", true, "Face Step", "Connected faces (instead of edges)");
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select More Operator
+ * \{ */
+
 static int edbm_select_less_exec(bContext *C, wmOperator *op)
 {
 	Object *obedit = CTX_data_edit_object(C);
@@ -3152,13 +3259,19 @@ void MESH_OT_select_less(wmOperatorType *ot)
 	/* api callbacks */
 	ot->exec = edbm_select_less_exec;
 	ot->poll = ED_operator_editmesh;
-	
+
 	/* flags */
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
 	RNA_def_boolean(ot->srna, "use_face_step", true, "Face Step", "Connected faces (instead of edges)");
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select N'th Operator
+ * \{ */
+
 /**
  * Check if we're connected to another selected efge.
  */
@@ -3382,12 +3495,17 @@ void MESH_OT_select_nth(wmOperatorType *ot)
 void em_setup_viewcontext(bContext *C, ViewContext *vc)
 {
 	ED_view3d_viewcontext_init(C, vc);
-	
+
 	if (vc->obedit) {
 		vc->em = BKE_editmesh_from_object(vc->obedit);
 	}
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Sharp Edges Operator
+ * \{ */
 
 static int edbm_select_sharp_edges_exec(bContext *C, wmOperator *op)
 {
@@ -3428,20 +3546,26 @@ void MESH_OT_edges_select_sharp(wmOperatorType *ot)
 	ot->name = "Select Sharp Edges";
 	ot->description = "Select all sharp-enough edges";
 	ot->idname = "MESH_OT_edges_select_sharp";
-	
+
 	/* api callbacks */
 	ot->exec = edbm_select_sharp_edges_exec;
 	ot->poll = ED_operator_editmesh;
-	
+
 	/* flags */
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-	
+
 	/* props */
 	prop = RNA_def_float_rotation(ot->srna, "sharpness", 0, NULL, DEG2RADF(0.01f), DEG2RADF(180.0f),
 	                              "Sharpness", "", DEG2RADF(1.0f), DEG2RADF(180.0f));
 	RNA_def_property_float_default(prop, DEG2RADF(30.0f));
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Linked Flat Faces Operator
+ * \{ */
+
 static int edbm_select_linked_flat_faces_exec(bContext *C, wmOperator *op)
 {
 	Object *obedit = CTX_data_edit_object(C);
@@ -3509,20 +3633,26 @@ void MESH_OT_faces_select_linked_flat(wmOperatorType *ot)
 	ot->name = "Select Linked Flat Faces";
 	ot->description = "Select linked faces by angle";
 	ot->idname = "MESH_OT_faces_select_linked_flat";
-	
+
 	/* api callbacks */
 	ot->exec = edbm_select_linked_flat_faces_exec;
 	ot->poll = ED_operator_editmesh;
-	
+
 	/* flags */
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-	
+
 	/* props */
 	prop = RNA_def_float_rotation(ot->srna, "sharpness", 0, NULL, DEG2RADF(0.01f), DEG2RADF(180.0f),
 	                              "Sharpness", "", DEG2RADF(1.0f), DEG2RADF(180.0f));
 	RNA_def_property_float_default(prop, DEG2RADF(1.0f));
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Non-Manifold Operator
+ * \{ */
+
 static int edbm_select_non_manifold_exec(bContext *C, wmOperator *op)
 {
 	Object *obedit = CTX_data_edit_object(C);
@@ -3544,12 +3674,12 @@ static int edbm_select_non_manifold_exec(bContext *C, wmOperator *op)
 	/* Selects isolated verts, and edges that do not have 2 neighboring
 	 * faces
 	 */
-	
+
 	if (em->selectmode == SCE_SELECT_FACE) {
 		BKE_report(op->reports, RPT_ERROR, "Does not work in face selection mode");
 		return OPERATOR_CANCELLED;
 	}
-	
+
 	if (use_verts) {
 		BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
 			if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
@@ -3559,7 +3689,7 @@ static int edbm_select_non_manifold_exec(bContext *C, wmOperator *op)
 			}
 		}
 	}
-	
+
 	if (use_wire || use_boundary || use_multi_face || use_non_contiguous) {
 		BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
 			if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
@@ -3590,11 +3720,11 @@ void MESH_OT_select_non_manifold(wmOperatorType *ot)
 	ot->name = "Select Non Manifold";
 	ot->description = "Select all non-manifold vertices or edges";
 	ot->idname = "MESH_OT_select_non_manifold";
-	
+
 	/* api callbacks */
 	ot->exec = edbm_select_non_manifold_exec;
 	ot->poll = ED_operator_editmesh;
-	
+
 	/* flags */
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
@@ -3614,6 +3744,12 @@ void MESH_OT_select_non_manifold(wmOperatorType *ot)
 	                "Vertices connecting multiple face regions");
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Random Operator
+ * \{ */
+
 static int edbm_select_random_exec(bContext *C, wmOperator *op)
 {
 	Object *obedit = CTX_data_edit_object(C);
@@ -3660,9 +3796,9 @@ static int edbm_select_random_exec(bContext *C, wmOperator *op)
 	else {
 		EDBM_deselect_flush(em);
 	}
-	
+
 	WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
-	
+
 	return OPERATOR_FINISHED;
 }
 
@@ -3679,11 +3815,17 @@ void MESH_OT_select_random(wmOperatorType *ot)
 
 	/* flags */
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-	
+
 	/* props */
 	WM_operator_properties_select_random(ot);
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Ungrouped Operator
+ * \{ */
+
 static int edbm_select_ungrouped_poll(bContext *C)
 {
 	if (ED_operator_editmesh(C)) {
@@ -3750,6 +3892,11 @@ void MESH_OT_select_ungrouped(wmOperatorType *ot)
 	RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Axis Operator
+ * \{ */
 
 /* BMESH_TODO - some way to select on an arbitrary axis */
 static int edbm_select_axis_exec(bContext *C, wmOperator *op)
@@ -3836,6 +3983,12 @@ void MESH_OT_select_axis(wmOperatorType *ot)
 	RNA_def_float(ot->srna, "threshold", 0.0001f, 0.000001f, 50.0f,  "Threshold", "", 0.00001f, 10.0f);
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Region to Loop Operator
+ * \{ */
+
 static int edbm_region_to_loop_exec(bContext *C, wmOperator *UNUSED(op))
 {
 	Object *obedit = CTX_data_edit_object(C);
@@ -3849,22 +4002,22 @@ static int edbm_region_to_loop_exec(bContext *C, wmOperator *UNUSED(op))
 	BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
 		BMLoop *l1, *l2;
 		BMIter liter1, liter2;
-		
+
 		BM_ITER_ELEM (l1, &liter1, f, BM_LOOPS_OF_FACE) {
 			int tot = 0, totsel = 0;
-			
+
 			BM_ITER_ELEM (l2, &liter2, l1->e, BM_LOOPS_OF_EDGE) {
 				tot++;
 				totsel += BM_elem_flag_test(l2->f, BM_ELEM_SELECT) != 0;
 			}
-			
+
 			if ((tot != totsel && totsel > 0) || (totsel == 1 && tot == 1))
 				BM_elem_flag_enable(l1->e, BM_ELEM_TAG);
 		}
 	}
 
 	EDBM_flag_disable_all(em, BM_ELEM_SELECT);
-	
+
 	BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
 		if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
 			BM_edge_select_set(em->bm, e, true);
@@ -3899,29 +4052,36 @@ void MESH_OT_region_to_loop(wmOperatorType *ot)
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 }
 
-static int loop_find_region(BMLoop *l, int flag,
-                            GSet *visit_face_set, BMFace ***region_out)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Loop to Region Operator
+ * \{ */
+
+static int loop_find_region(
+        BMLoop *l, int flag,
+        GSet *visit_face_set, BMFace ***region_out)
 {
 	BMFace **region = NULL;
 	BMFace **stack = NULL;
 	BLI_array_declare(region);
 	BLI_array_declare(stack);
 	BMFace *f;
-	
+
 	BLI_array_append(stack, l->f);
 	BLI_gset_insert(visit_face_set, l->f);
-	
-	while (BLI_array_count(stack) > 0) {
+
+	while (BLI_array_len(stack) > 0) {
 		BMIter liter1, liter2;
 		BMLoop *l1, *l2;
-		
+
 		f = BLI_array_pop(stack);
 		BLI_array_append(region, f);
-		
+
 		BM_ITER_ELEM (l1, &liter1, f, BM_LOOPS_OF_FACE) {
 			if (BM_elem_flag_test(l1->e, flag))
 				continue;
-			
+
 			BM_ITER_ELEM (l2, &liter2, l1->e, BM_LOOPS_OF_EDGE) {
 				/* avoids finding same region twice
 				 * (otherwise) the logic works fine without */
@@ -3935,11 +4095,11 @@ static int loop_find_region(BMLoop *l, int flag,
 			}
 		}
 	}
-	
+
 	BLI_array_free(stack);
-	
+
 	*region_out = region;
-	return BLI_array_count(region);
+	return BLI_array_len(region);
 }
 
 static int verg_radial(const void *va, const void *vb)
@@ -3947,10 +4107,9 @@ static int verg_radial(const void *va, const void *vb)
 	const BMEdge *e_a = *((const BMEdge **)va);
 	const BMEdge *e_b = *((const BMEdge **)vb);
 
-	int a, b;
-	a = BM_edge_face_count(e_a);
-	b = BM_edge_face_count(e_b);
-	
+	const int a = BM_edge_face_count(e_a);
+	const int b = BM_edge_face_count(e_b);
+
 	if (a > b) return -1;
 	if (a < b) return  1;
 	return  0;
@@ -3969,7 +4128,7 @@ static int loop_find_regions(BMEditMesh *em, const bool selbigger)
 	const int edges_len = em->bm->totedgesel;
 	BMEdge *e, **edges;
 	int count = 0, i;
-	
+
 	visit_face_set = BLI_gset_ptr_new_ex(__func__, edges_len);
 	edges = MEM_mallocN(sizeof(*edges) * edges_len, __func__);
 
@@ -3983,21 +4142,21 @@ static int loop_find_regions(BMEditMesh *em, const bool selbigger)
 			BM_elem_flag_disable(e, BM_ELEM_TAG);
 		}
 	}
-	
+
 	/* sort edges by radial cycle length */
 	qsort(edges, edges_len, sizeof(*edges), verg_radial);
-	
+
 	for (i = 0; i < edges_len; i++) {
 		BMIter liter;
 		BMLoop *l;
 		BMFace **region = NULL, **region_out;
 		int c, tot = 0;
-		
+
 		e = edges[i];
-		
+
 		if (!BM_elem_flag_test(e, BM_ELEM_TAG))
 			continue;
-		
+
 		BM_ITER_ELEM (l, &liter, e, BM_LOOPS_OF_EDGE) {
 			if (BLI_gset_haskey(visit_face_set, l->f))
 				continue;
@@ -4019,26 +4178,26 @@ static int loop_find_regions(BMEditMesh *em, const bool selbigger)
 				MEM_freeN(region_out);
 			}
 		}
-		
+
 		if (region) {
 			int j;
-			
+
 			for (j = 0; j < tot; j++) {
 				BM_elem_flag_enable(region[j], BM_ELEM_TAG);
 				BM_ITER_ELEM (l, &liter, region[j], BM_LOOPS_OF_FACE) {
 					BM_elem_flag_disable(l->e, BM_ELEM_TAG);
 				}
 			}
-			
+
 			count += tot;
-			
+
 			MEM_freeN(region);
 		}
 	}
-	
+
 	MEM_freeN(edges);
 	BLI_gset_free(visit_face_set, NULL);
-	
+
 	return count;
 }
 
@@ -4049,25 +4208,23 @@ static int edbm_loop_to_region_exec(bContext *C, wmOperator *op)
 	BMIter iter;
 	BMFace *f;
 	const bool select_bigger = RNA_boolean_get(op->ptr, "select_bigger");
-	int a, b;
-
 
 	/* find the set of regions with smallest number of total faces */
 	BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
-	a = loop_find_regions(em, select_bigger);
-	b = loop_find_regions(em, !select_bigger);
+	const int a = loop_find_regions(em, select_bigger);
+	const int b = loop_find_regions(em, !select_bigger);
 
 	BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
 	loop_find_regions(em, ((a <= b) != select_bigger) ? select_bigger : !select_bigger);
-	
+
 	EDBM_flag_disable_all(em, BM_ELEM_SELECT);
-	
+
 	BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
 		if (BM_elem_flag_test(f, BM_ELEM_TAG) && !BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
 			BM_face_select_set(em->bm, f, true);
 		}
 	}
-	
+
 	EDBM_selectmode_flush(em);
 
 	WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
@@ -4087,9 +4244,8 @@ void MESH_OT_loop_to_region(wmOperatorType *ot)
 
 	/* flags */
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-	
+
 	RNA_def_boolean(ot->srna, "select_bigger", 0, "Select Bigger", "Select bigger regions instead of smaller ones");
 }
 
-
-/************************ Select Path Operator *************************/
+/** \} */
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index c979a73e9645b70985d681b26fb1dd0885c5b74c..84299f12cefe62b7e37054ede5fb468773a69fbe 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -84,6 +84,10 @@
 
 #define USE_FACE_CREATE_SEL_EXTEND
 
+/* -------------------------------------------------------------------- */
+/** \name Subdivide Operator
+ * \{ */
+
 static int edbm_subdivide_exec(bContext *C, wmOperator *op)
 {
 	Object *obedit = CTX_data_edit_object(C);
@@ -93,19 +97,20 @@ static int edbm_subdivide_exec(bContext *C, wmOperator *op)
 	const float fractal = RNA_float_get(op->ptr, "fractal") / 2.5f;
 	const float along_normal = RNA_float_get(op->ptr, "fractal_along_normal");
 
-	if (RNA_boolean_get(op->ptr, "quadtri") && 
+	if (RNA_boolean_get(op->ptr, "quadtri") &&
 	    RNA_enum_get(op->ptr, "quadcorner") == SUBD_CORNER_STRAIGHT_CUT)
 	{
 		RNA_enum_set(op->ptr, "quadcorner", SUBD_CORNER_INNERVERT);
 	}
-	
-	BM_mesh_esubdivide(em->bm, BM_ELEM_SELECT,
-	                   smooth, SUBD_FALLOFF_LIN, false,
-	                   fractal, along_normal,
-	                   cuts,
-	                   SUBDIV_SELECT_ORIG, RNA_enum_get(op->ptr, "quadcorner"),
-	                   RNA_boolean_get(op->ptr, "quadtri"), true, false,
-	                   RNA_int_get(op->ptr, "seed"));
+
+	BM_mesh_esubdivide(
+	        em->bm, BM_ELEM_SELECT,
+	        smooth, SUBD_FALLOFF_LIN, false,
+	        fractal, along_normal,
+	        cuts,
+	        SUBDIV_SELECT_ORIG, RNA_enum_get(op->ptr, "quadcorner"),
+	        RNA_boolean_get(op->ptr, "quadtri"), true, false,
+	        RNA_int_get(op->ptr, "seed"));
 
 	EDBM_update_generic(em, true, true);
 
@@ -154,10 +159,14 @@ void MESH_OT_subdivide(wmOperatorType *ot)
 	RNA_def_int(ot->srna, "seed", 0, 0, INT_MAX, "Random Seed", "Seed for the random number generator", 0, 255);
 }
 
+/** \} */
+
 /* -------------------------------------------------------------------- */
-/* Edge Ring Subdiv
- * (bridge code shares props)
- */
+/** \name Edge Ring Subdivide Operator
+ *
+ * Bridge code shares props.
+ *
+ * \{ */
 
 struct EdgeRingOpSubdProps {
 	int interp_mode;
@@ -219,11 +228,12 @@ static int edbm_subdivide_edge_ring_exec(bContext *C, wmOperator *op)
 
 	mesh_operator_edgering_props_get(op, &op_props);
 
-	if (!EDBM_op_callf(em, op,
-	                   "subdivide_edgering edges=%he interp_mode=%i cuts=%i smooth=%f "
-	                   "profile_shape=%i profile_shape_factor=%f",
-	                   BM_ELEM_SELECT, op_props.interp_mode, op_props.cuts, op_props.smooth,
-	                   op_props.profile_shape, op_props.profile_shape_factor))
+	if (!EDBM_op_callf(
+	            em, op,
+	            "subdivide_edgering edges=%he interp_mode=%i cuts=%i smooth=%f "
+	            "profile_shape=%i profile_shape_factor=%f",
+	            BM_ELEM_SELECT, op_props.interp_mode, op_props.cuts, op_props.smooth,
+	            op_props.profile_shape, op_props.profile_shape_factor))
 	{
 		return OPERATOR_CANCELLED;
 	}
@@ -251,6 +261,11 @@ void MESH_OT_subdivide_edgering(wmOperatorType *ot)
 	mesh_operator_edgering_props(ot, 1, 10);
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Un-Subdivide Operator
+ * \{ */
 
 static int edbm_unsubdivide_exec(bContext *C, wmOperator *op)
 {
@@ -332,6 +347,11 @@ void EMBM_project_snap_verts(bContext *C, ARegion *ar, BMEditMesh *em)
 	ED_transform_snap_object_context_destroy(snap_context);
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Delete Operator
+ * \{ */
 
 /* Note, these values must match delete_mesh() event values */
 enum {
@@ -386,7 +406,7 @@ static int edbm_delete_exec(bContext *C, wmOperator *op)
 	EDBM_flag_disable_all(em, BM_ELEM_SELECT);
 
 	EDBM_update_generic(em, true, true);
-	
+
 	return OPERATOR_FINISHED;
 }
 
@@ -405,13 +425,13 @@ void MESH_OT_delete(wmOperatorType *ot)
 	ot->name = "Delete";
 	ot->description = "Delete selected vertices, edges or faces";
 	ot->idname = "MESH_OT_delete";
-	
+
 	/* api callbacks */
 	ot->invoke = WM_menu_invoke;
 	ot->exec = edbm_delete_exec;
-	
+
 	ot->poll = ED_operator_editmesh;
-	
+
 	/* flags */
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
@@ -420,6 +440,11 @@ void MESH_OT_delete(wmOperatorType *ot)
 	                        "Type", "Method used for deleting mesh data");
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Delete Loose Operator
+ * \{ */
 
 static bool bm_face_is_loose(BMFace *f)
 {
@@ -518,6 +543,11 @@ void MESH_OT_delete_loose(wmOperatorType *ot)
 	RNA_def_boolean(ot->srna, "use_faces", false, "Faces", "Remove loose faces");
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Collapse Edge Operator
+ * \{ */
 
 static int edbm_collapse_edge_exec(bContext *C, wmOperator *op)
 {
@@ -547,6 +577,12 @@ void MESH_OT_edge_collapse(wmOperatorType *ot)
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Create Edge/Face Operator
+ * \{ */
+
 static bool edbm_add_edge_face__smooth_get(BMesh *bm)
 {
 	BMEdge *e;
@@ -616,8 +652,9 @@ static BMElem *edbm_add_edge_face_exec__tricky_extend_sel(BMesh *bm)
 			     (BM_edge_share_face_check(ed_pair[0], ed_pair[1]) == false))
 			    )
 			{
-				BMEdge *e_other = BM_edge_exists(BM_edge_other_vert(ed_pair[0], v),
-				                                 BM_edge_other_vert(ed_pair[1], v));
+				BMEdge *e_other = BM_edge_exists(
+				        BM_edge_other_vert(ed_pair[0], v),
+				        BM_edge_other_vert(ed_pair[1], v));
 				BM_edge_select_set(bm, ed_pair[0], true);
 				BM_edge_select_set(bm, ed_pair[1], true);
 				if (e_other) {
@@ -740,13 +777,14 @@ static int edbm_add_edge_face_exec(bContext *C, wmOperator *op)
 	ele_desel = edbm_add_edge_face_exec__tricky_extend_sel(em->bm);
 #endif
 
-	if (!EDBM_op_init(em, &bmop, op,
-	                  "contextual_create geom=%hfev mat_nr=%i use_smooth=%b",
-	                  BM_ELEM_SELECT, em->mat_nr, use_smooth))
+	if (!EDBM_op_init(
+	            em, &bmop, op,
+	            "contextual_create geom=%hfev mat_nr=%i use_smooth=%b",
+	            BM_ELEM_SELECT, em->mat_nr, use_smooth))
 	{
 		return OPERATOR_CANCELLED;
 	}
-	
+
 	BMO_op_exec(em->bm, &bmop);
 
 	/* cancel if nothing was done */
@@ -796,16 +834,20 @@ void MESH_OT_edge_face_add(wmOperatorType *ot)
 	ot->name = "Make Edge/Face";
 	ot->description = "Add an edge or face to selected";
 	ot->idname = "MESH_OT_edge_face_add";
-	
+
 	/* api callbacks */
 	ot->exec = edbm_add_edge_face_exec;
 	ot->poll = ED_operator_editmesh;
-	
+
 	/* flags */
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 }
 
-/* ************************* SEAMS AND EDGES **************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mark Edge (Seam) Operator
+ * \{ */
 
 static int edbm_mark_seam_exec(bContext *C, wmOperator *op)
 {
@@ -817,7 +859,7 @@ static int edbm_mark_seam_exec(bContext *C, wmOperator *op)
 	BMEdge *eed;
 	BMIter iter;
 	const bool clear = RNA_boolean_get(op->ptr, "clear");
-	
+
 	/* auto-enable seams drawing */
 	if (clear == 0) {
 		me->drawflag |= ME_DRAWSEAMS;
@@ -827,7 +869,7 @@ static int edbm_mark_seam_exec(bContext *C, wmOperator *op)
 		BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
 			if (!BM_elem_flag_test(eed, BM_ELEM_SELECT) || BM_elem_flag_test(eed, BM_ELEM_HIDDEN))
 				continue;
-			
+
 			BM_elem_flag_disable(eed, BM_ELEM_SEAM);
 		}
 	}
@@ -853,18 +895,24 @@ void MESH_OT_mark_seam(wmOperatorType *ot)
 	ot->name = "Mark Seam";
 	ot->idname = "MESH_OT_mark_seam";
 	ot->description = "(Un)mark selected edges as a seam";
-	
+
 	/* api callbacks */
 	ot->exec = edbm_mark_seam_exec;
 	ot->poll = ED_operator_editmesh;
-	
+
 	/* flags */
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-	
+
 	prop = RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
 	RNA_def_property_flag(prop, PROP_SKIP_SAVE);
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mark Edge (Sharp) Operator
+ * \{ */
+
 static int edbm_mark_sharp_exec(bContext *C, wmOperator *op)
 {
 	Object *obedit = CTX_data_edit_object(C);
@@ -907,14 +955,14 @@ void MESH_OT_mark_sharp(wmOperatorType *ot)
 	ot->name = "Mark Sharp";
 	ot->idname = "MESH_OT_mark_sharp";
 	ot->description = "(Un)mark selected edges as sharp";
-	
+
 	/* api callbacks */
 	ot->exec = edbm_mark_sharp_exec;
 	ot->poll = ED_operator_editmesh;
-	
+
 	/* flags */
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-	
+
 	prop = RNA_def_boolean(ot->srna, "clear", false, "Clear", "");
 	RNA_def_property_flag(prop, PROP_SKIP_SAVE);
 	prop = RNA_def_boolean(ot->srna, "use_verts", false, "Vertices",
@@ -958,17 +1006,19 @@ static int edbm_vert_connect_exec(bContext *C, wmOperator *op)
 	}
 
 	if (is_pair) {
-		if (!EDBM_op_init(em, &bmop, op,
-		                  "connect_vert_pair verts=%eb verts_exclude=%hv faces_exclude=%hf",
-		                  verts, verts_len, BM_ELEM_HIDDEN, BM_ELEM_HIDDEN))
+		if (!EDBM_op_init(
+		            em, &bmop, op,
+		            "connect_vert_pair verts=%eb verts_exclude=%hv faces_exclude=%hf",
+		            verts, verts_len, BM_ELEM_HIDDEN, BM_ELEM_HIDDEN))
 		{
 			goto finally;
 		}
 	}
 	else {
-		if (!EDBM_op_init(em, &bmop, op,
-		                  "connect_verts verts=%eb faces_exclude=%hf check_degenerate=%b",
-		                  verts, verts_len, BM_ELEM_HIDDEN, check_degenerate))
+		if (!EDBM_op_init(
+		            em, &bmop, op,
+		            "connect_verts verts=%eb faces_exclude=%hf check_degenerate=%b",
+		            verts, verts_len, BM_ELEM_HIDDEN, check_degenerate))
 		{
 			goto finally;
 		}
@@ -1005,15 +1055,20 @@ void MESH_OT_vert_connect(wmOperatorType *ot)
 	ot->name = "Vertex Connect";
 	ot->idname = "MESH_OT_vert_connect";
 	ot->description = "Connect selected vertices of faces, splitting the face";
-	
+
 	/* api callbacks */
 	ot->exec = edbm_vert_connect_exec;
 	ot->poll = ED_operator_editmesh;
-	
+
 	/* flags */
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Split Concave Faces Operator
+ * \{ */
 
 /**
  * check that endpoints are verts and only have a single selected edge connected.
@@ -1318,6 +1373,11 @@ void MESH_OT_vert_connect_concave(wmOperatorType *ot)
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Split Non-Planar Faces Operator
+ * \{ */
 
 static int edbm_vert_connect_nonplaner_exec(bContext *C, wmOperator *op)
 {
@@ -1362,6 +1422,12 @@ void MESH_OT_vert_connect_nonplanar(wmOperatorType *ot)
 	RNA_def_property_float_default(prop, DEG2RADF(5.0f));
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Make Planar Faces Operator
+ * \{ */
+
 static int edbm_face_make_planar_exec(bContext *C, wmOperator *op)
 {
 	Object *obedit = CTX_data_edit_object(C);
@@ -1399,6 +1465,11 @@ void MESH_OT_face_make_planar(wmOperatorType *ot)
 	RNA_def_int(ot->srna, "repeat", 1, 1, 10000, "Iterations", "", 1, 200);
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Split Edge Operator
+ * \{ */
 
 static int edbm_edge_split_exec(bContext *C, wmOperator *op)
 {
@@ -1413,7 +1484,7 @@ static int edbm_edge_split_exec(bContext *C, wmOperator *op)
 	{
 		return OPERATOR_CANCELLED;
 	}
-	
+
 	if (em->selectmode == SCE_SELECT_FACE) {
 		EDBM_select_flush(em);
 	}
@@ -1429,16 +1500,20 @@ void MESH_OT_edge_split(wmOperatorType *ot)
 	ot->name = "Edge Split";
 	ot->idname = "MESH_OT_edge_split";
 	ot->description = "Split selected edges so that each neighbor face gets its own copy";
-	
+
 	/* api callbacks */
 	ot->exec = edbm_edge_split_exec;
 	ot->poll = ED_operator_editmesh;
-	
+
 	/* flags */
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 }
 
-/****************** add duplicate operator ***************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Duplicate Operator
+ * \{ */
 
 static int edbm_duplicate_exec(bContext *C, wmOperator *op)
 {
@@ -1469,7 +1544,7 @@ static int edbm_duplicate_exec(bContext *C, wmOperator *op)
 	}
 
 	EDBM_update_generic(em, true, true);
-	
+
 	return OPERATOR_FINISHED;
 }
 
@@ -1478,7 +1553,7 @@ static int edbm_duplicate_invoke(bContext *C, wmOperator *op, const wmEvent *UNU
 	WM_cursor_wait(1);
 	edbm_duplicate_exec(C, op);
 	WM_cursor_wait(0);
-	
+
 	return OPERATOR_FINISHED;
 }
 
@@ -1488,29 +1563,34 @@ void MESH_OT_duplicate(wmOperatorType *ot)
 	ot->name = "Duplicate";
 	ot->description = "Duplicate selected vertices, edges or faces";
 	ot->idname = "MESH_OT_duplicate";
-	
+
 	/* api callbacks */
 	ot->invoke = edbm_duplicate_invoke;
 	ot->exec = edbm_duplicate_exec;
-	
+
 	ot->poll = ED_operator_editmesh;
-	
+
 	/* to give to transform */
 	RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX);
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Flip Normals Operator
+ * \{ */
 static int edbm_flip_normals_exec(bContext *C, wmOperator *op)
 {
 	Object *obedit = CTX_data_edit_object(C);
 	BMEditMesh *em = BKE_editmesh_from_object(obedit);
-	
+
 	if (!EDBM_op_callf(
 	        em, op, "reverse_faces faces=%hf flip_multires=%b",
 	        BM_ELEM_SELECT, true))
 	{
 		return OPERATOR_CANCELLED;
 	}
-	
+
 	EDBM_update_generic(em, true, false);
 
 	return OPERATOR_FINISHED;
@@ -1522,15 +1602,21 @@ void MESH_OT_flip_normals(wmOperatorType *ot)
 	ot->name = "Flip Normals";
 	ot->description = "Flip the direction of selected faces' normals (and of their vertices)";
 	ot->idname = "MESH_OT_flip_normals";
-	
+
 	/* api callbacks */
 	ot->exec = edbm_flip_normals_exec;
 	ot->poll = ED_operator_editmesh;
-	
+
 	/* flags */
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Rotate Edge Operator
+ * \{ */
+
 /**
  * Rotate the edges between selected faces, otherwise rotate the selected edges.
  */
@@ -1564,7 +1650,7 @@ static int edbm_edge_rotate_selected_exec(bContext *C, wmOperator *op)
 			}
 		}
 	}
-	
+
 	/* ok, we don't have two adjacent faces, but we do have two selected ones.
 	 * that's an error condition.*/
 	if (tot == 0) {
@@ -1623,12 +1709,17 @@ void MESH_OT_edge_rotate(wmOperatorType *ot)
 	RNA_def_boolean(ot->srna, "use_ccw", false, "Counter Clockwise", "");
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Hide Operator
+ * \{ */
 
 static int edbm_hide_exec(bContext *C, wmOperator *op)
 {
 	Object *obedit = CTX_data_edit_object(C);
 	BMEditMesh *em = BKE_editmesh_from_object(obedit);
-	
+
 	EDBM_mesh_hide(em, RNA_boolean_get(op->ptr, "unselected"));
 
 	EDBM_update_generic(em, true, false);
@@ -1642,18 +1733,24 @@ void MESH_OT_hide(wmOperatorType *ot)
 	ot->name = "Hide Selection";
 	ot->idname = "MESH_OT_hide";
 	ot->description = "Hide (un)selected vertices, edges or faces";
-	
+
 	/* api callbacks */
 	ot->exec = edbm_hide_exec;
 	ot->poll = ED_operator_editmesh;
 
 	/* flags */
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-	
+
 	/* props */
 	RNA_def_boolean(ot->srna, "unselected", false, "Unselected", "Hide unselected rather than selected");
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Reveal Operator
+ * \{ */
+
 static int edbm_reveal_exec(bContext *C, wmOperator *op)
 {
 	Object *obedit = CTX_data_edit_object(C);
@@ -1673,22 +1770,28 @@ void MESH_OT_reveal(wmOperatorType *ot)
 	ot->name = "Reveal Hidden";
 	ot->idname = "MESH_OT_reveal";
 	ot->description = "Reveal all hidden vertices, edges and faces";
-	
+
 	/* api callbacks */
 	ot->exec = edbm_reveal_exec;
 	ot->poll = ED_operator_editmesh;
-	
+
 	/* flags */
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
 	RNA_def_boolean(ot->srna, "select", true, "Select", "");
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Recalculate Normals Operator
+ * \{ */
+
 static int edbm_normals_make_consistent_exec(bContext *C, wmOperator *op)
 {
 	Object *obedit = CTX_data_edit_object(C);
 	BMEditMesh *em = BKE_editmesh_from_object(obedit);
-	
+
 	/* doflip has to do with bmesh_rationalize_normals, it's an internal
 	 * thing */
 	if (!EDBM_op_callf(em, op, "recalc_face_normals faces=%hf", BM_ELEM_SELECT))
@@ -1709,18 +1812,22 @@ void MESH_OT_normals_make_consistent(wmOperatorType *ot)
 	ot->name = "Make Normals Consistent";
 	ot->description = "Make face and vertex normals point either outside or inside the mesh";
 	ot->idname = "MESH_OT_normals_make_consistent";
-	
+
 	/* api callbacks */
 	ot->exec = edbm_normals_make_consistent_exec;
 	ot->poll = ED_operator_editmesh;
-	
+
 	/* flags */
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-	
+
 	RNA_def_boolean(ot->srna, "inside", false, "Inside", "");
 }
 
+/** \} */
 
+/* -------------------------------------------------------------------- */
+/** \name Smooth Vertex Operator
+ * \{ */
 
 static int edbm_do_smooth_vertex_exec(bContext *C, wmOperator *op)
 {
@@ -1744,12 +1851,12 @@ static int edbm_do_smooth_vertex_exec(bContext *C, wmOperator *op)
 	}
 
 	/* if there is a mirror modifier with clipping, flag the verts that
-	 * are within tolerance of the plane(s) of reflection 
+	 * are within tolerance of the plane(s) of reflection
 	 */
 	for (md = obedit->modifiers.first; md; md = md->next) {
 		if (md->type == eModifierType_Mirror && (md->mode & eModifierMode_Realtime)) {
 			MirrorModifierData *mmd = (MirrorModifierData *)md;
-		
+
 			if (mmd->flag & MOD_MIR_CLIPPING) {
 				if (mmd->flag & MOD_MIR_AXIS_X)
 					mirrx = true;
@@ -1768,10 +1875,11 @@ static int edbm_do_smooth_vertex_exec(bContext *C, wmOperator *op)
 		repeat = 1;
 
 	for (i = 0; i < repeat; i++) {
-		if (!EDBM_op_callf(em, op,
-		                   "smooth_vert verts=%hv factor=%f mirror_clip_x=%b mirror_clip_y=%b mirror_clip_z=%b "
-		                   "clip_dist=%f use_axis_x=%b use_axis_y=%b use_axis_z=%b",
-		                   BM_ELEM_SELECT, fac, mirrx, mirry, mirrz, clip_dist, xaxis, yaxis, zaxis))
+		if (!EDBM_op_callf(
+		            em, op,
+		            "smooth_vert verts=%hv factor=%f mirror_clip_x=%b mirror_clip_y=%b mirror_clip_z=%b "
+		            "clip_dist=%f use_axis_x=%b use_axis_y=%b use_axis_z=%b",
+		            BM_ELEM_SELECT, fac, mirrx, mirry, mirrz, clip_dist, xaxis, yaxis, zaxis))
 		{
 			return OPERATOR_CANCELLED;
 		}
@@ -1786,19 +1894,20 @@ static int edbm_do_smooth_vertex_exec(bContext *C, wmOperator *op)
 	EDBM_update_generic(em, true, false);
 
 	return OPERATOR_FINISHED;
-}	
-	
+}
+
+
 void MESH_OT_vertices_smooth(wmOperatorType *ot)
 {
 	/* identifiers */
 	ot->name = "Smooth Vertex";
 	ot->description = "Flatten angles of selected vertices";
 	ot->idname = "MESH_OT_vertices_smooth";
-	
+
 	/* api callbacks */
 	ot->exec = edbm_do_smooth_vertex_exec;
 	ot->poll = ED_operator_editmesh;
-	
+
 	/* flags */
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
@@ -1809,6 +1918,12 @@ void MESH_OT_vertices_smooth(wmOperatorType *ot)
 	RNA_def_boolean(ot->srna, "zaxis", true, "Z-Axis", "Smooth along the Z axis");
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Laplacian Vertex Smooth Operator
+ * \{ */
+
 static int edbm_do_smooth_laplacian_vertex_exec(bContext *C, wmOperator *op)
 {
 	Object *obedit = CTX_data_edit_object(C);
@@ -1828,7 +1943,7 @@ static int edbm_do_smooth_laplacian_vertex_exec(bContext *C, wmOperator *op)
 			if (f->len > 4) {
 				BKE_report(op->reports, RPT_WARNING, "Selected faces must be triangles or quads");
 				return OPERATOR_CANCELLED;
-			}	
+			}
 		}
 	}
 
@@ -1846,11 +1961,12 @@ static int edbm_do_smooth_laplacian_vertex_exec(bContext *C, wmOperator *op)
 	preserve_volume = RNA_boolean_get(op->ptr, "preserve_volume");
 	if (!repeat)
 		repeat = 1;
-	
+
 	for (i = 0; i < repeat; i++) {
-		if (!EDBM_op_callf(em, op,
-		                   "smooth_laplacian_vert verts=%hv lambda_factor=%f lambda_border=%f use_x=%b use_y=%b use_z=%b preserve_volume=%b",
-		                   BM_ELEM_SELECT, lambda_factor, lambda_border, usex, usey, usez, preserve_volume))
+		if (!EDBM_op_callf(
+		            em, op,
+		            "smooth_laplacian_vert verts=%hv lambda_factor=%f lambda_border=%f use_x=%b use_y=%b use_z=%b preserve_volume=%b",
+		            BM_ELEM_SELECT, lambda_factor, lambda_border, usex, usey, usez, preserve_volume))
 		{
 			return OPERATOR_CANCELLED;
 		}
@@ -1873,11 +1989,11 @@ void MESH_OT_vertices_smooth_laplacian(wmOperatorType *ot)
 	ot->name = "Laplacian Smooth Vertex";
 	ot->description = "Laplacian smooth of selected vertices";
 	ot->idname = "MESH_OT_vertices_smooth_laplacian";
-	
+
 	/* api callbacks */
 	ot->exec = edbm_do_smooth_laplacian_vertex_exec;
 	ot->poll = ED_operator_editmesh;
-	
+
 	/* flags */
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
@@ -1893,7 +2009,11 @@ void MESH_OT_vertices_smooth_laplacian(wmOperatorType *ot)
 	RNA_def_boolean(ot->srna, "preserve_volume", true, "Preserve Volume", "Apply volume preservation after smooth");
 }
 
-/********************** Smooth/Solid Operators *************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Set Faces Smooth Shading Operator
+ * \{ */
 
 static void mesh_set_smooth_faces(BMEditMesh *em, short smooth)
 {
@@ -1901,7 +2021,7 @@ static void mesh_set_smooth_faces(BMEditMesh *em, short smooth)
 	BMFace *efa;
 
 	if (em == NULL) return;
-	
+
 	BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
 		if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
 			BM_elem_flag_set(efa, BM_ELEM_SMOOTH, smooth);
@@ -1936,6 +2056,12 @@ void MESH_OT_faces_shade_smooth(wmOperatorType *ot)
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Set Faces Flat Shading Operator
+ * \{ */
+
 static int edbm_faces_shade_flat_exec(bContext *C, wmOperator *UNUSED(op))
 {
 	Object *obedit = CTX_data_edit_object(C);
@@ -1963,8 +2089,11 @@ void MESH_OT_faces_shade_flat(wmOperatorType *ot)
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 }
 
+/** \} */
 
-/********************** UV/Color Operators *************************/
+/* -------------------------------------------------------------------- */
+/** \name UV/Color Rotate/Reverse Operator
+ * \{ */
 
 static int edbm_rotate_uvs_exec(bContext *C, wmOperator *op)
 {
@@ -2134,6 +2263,11 @@ void MESH_OT_colors_reverse(wmOperatorType *ot)
 	//RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror colors around");
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Merge Vertices Operator
+ * \{ */
 
 enum {
 	MESH_MERGE_LAST     = 1,
@@ -2170,7 +2304,7 @@ static bool merge_firstlast(BMEditMesh *em, const bool use_first, const bool use
 
 	if (!BM_elem_flag_test(mergevert, BM_ELEM_SELECT))
 		return false;
-	
+
 	if (use_uvmerge) {
 		if (!EDBM_op_callf(em, wmop, "pointmerge_facedata verts=%hv vert_snap=%e", BM_ELEM_SELECT, mergevert))
 			return false;
@@ -2182,8 +2316,9 @@ static bool merge_firstlast(BMEditMesh *em, const bool use_first, const bool use
 	return true;
 }
 
-static bool merge_target(BMEditMesh *em, Scene *scene, View3D *v3d, Object *ob,
-                         const bool use_cursor, const bool use_uvmerge, wmOperator *wmop)
+static bool merge_target(
+        BMEditMesh *em, Scene *scene, View3D *v3d, Object *ob,
+        const bool use_cursor, const bool use_uvmerge, wmOperator *wmop)
 {
 	BMIter iter;
 	BMVert *v;
@@ -2204,7 +2339,7 @@ static bool merge_target(BMEditMesh *em, Scene *scene, View3D *v3d, Object *ob,
 			add_v3_v3(cent, v->co);
 			i++;
 		}
-		
+
 		if (!i)
 			return false;
 
@@ -2216,7 +2351,7 @@ static bool merge_target(BMEditMesh *em, Scene *scene, View3D *v3d, Object *ob,
 
 	if (!vco)
 		return false;
-	
+
 	if (use_uvmerge) {
 		if (!EDBM_op_callf(em, wmop, "average_vert_facedata verts=%hv", BM_ELEM_SELECT))
 			return false;
@@ -2283,14 +2418,14 @@ static const EnumPropertyItem merge_type_items[] = {
 };
 
 static const EnumPropertyItem *merge_type_itemf(bContext *C, PointerRNA *UNUSED(ptr),  PropertyRNA *UNUSED(prop), bool *r_free)
-{	
+{
 	Object *obedit;
 	EnumPropertyItem *item = NULL;
 	int totitem = 0;
-	
+
 	if (!C) /* needed for docs */
 		return merge_type_items;
-	
+
 	obedit = CTX_data_edit_object(C);
 	if (obedit && obedit->type == OB_MESH) {
 		BMEditMesh *em = BKE_editmesh_from_object(obedit);
@@ -2320,7 +2455,7 @@ static const EnumPropertyItem *merge_type_itemf(bContext *C, PointerRNA *UNUSED(
 
 		return item;
 	}
-	
+
 	return NULL;
 }
 
@@ -2345,6 +2480,11 @@ void MESH_OT_merge(wmOperatorType *ot)
 	RNA_def_boolean(ot->srna, "uvs", false, "UVs", "Move UVs according to merge");
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Remove Doubles Operator
+ * \{ */
 
 static int edbm_remove_doubles_exec(bContext *C, wmOperator *op)
 {
@@ -2367,9 +2507,10 @@ static int edbm_remove_doubles_exec(bContext *C, wmOperator *op)
 
 
 	if (use_unselected) {
-		EDBM_op_init(em, &bmop, op,
-		             "automerge verts=%hv dist=%f",
-		             BM_ELEM_SELECT, threshold);
+		EDBM_op_init(
+		        em, &bmop, op,
+		        "automerge verts=%hv dist=%f",
+		        BM_ELEM_SELECT, threshold);
 		BMO_op_exec(em->bm, &bmop);
 
 		if (!EDBM_op_finish(em, &bmop, op, true)) {
@@ -2377,9 +2518,10 @@ static int edbm_remove_doubles_exec(bContext *C, wmOperator *op)
 		}
 	}
 	else {
-		EDBM_op_init(em, &bmop, op,
-		             "find_doubles verts=%hv dist=%f",
-		             BM_ELEM_SELECT, threshold);
+		EDBM_op_init(
+		        em, &bmop, op,
+		        "find_doubles verts=%hv dist=%f",
+		        BM_ELEM_SELECT, threshold);
 		BMO_op_exec(em->bm, &bmop);
 
 		if (!EDBM_op_callf(em, op, "weld_verts targetmap=%S", &bmop, "targetmap.out")) {
@@ -2391,7 +2533,7 @@ static int edbm_remove_doubles_exec(bContext *C, wmOperator *op)
 			return OPERATOR_CANCELLED;
 		}
 	}
-	
+
 	count = totvert_orig - em->bm->totvert;
 	BKE_reportf(op->reports, RPT_INFO, "Removed %d vertices", count);
 
@@ -2423,8 +2565,11 @@ void MESH_OT_remove_doubles(wmOperatorType *ot)
 	RNA_def_boolean(ot->srna, "use_unselected", false, "Unselected", "Merge selected to other unselected vertices");
 }
 
+/** \} */
 
-/************************ Shape Operators *************************/
+/* -------------------------------------------------------------------- */
+/** \name Shape Key Propagate Operator
+ * \{ */
 
 /* BMESH_TODO this should be properly encapsulated in a bmop.  but later.*/
 static void shape_propagate(BMEditMesh *em, wmOperator *op)
@@ -2438,7 +2583,7 @@ static void shape_propagate(BMEditMesh *em, wmOperator *op)
 		BKE_report(op->reports, RPT_ERROR, "Mesh does not have shape keys");
 		return;
 	}
-	
+
 	BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
 		if (!BM_elem_flag_test(eve, BM_ELEM_SELECT) || BM_elem_flag_test(eve, BM_ELEM_HIDDEN))
 			continue;
@@ -2489,6 +2634,12 @@ void MESH_OT_shape_propagate_to_all(wmOperatorType *ot)
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Blend from Shape Operator
+ * \{ */
+
 /* BMESH_TODO this should be properly encapsulated in a bmop.  but later.*/
 static int edbm_blend_from_shape_exec(bContext *C, wmOperator *op)
 {
@@ -2515,23 +2666,23 @@ static int edbm_blend_from_shape_exec(bContext *C, wmOperator *op)
 	if (key) {
 		kb = BLI_findlink(&key->block, shape);
 	}
-	
+
 	/* perform blending on selected vertices*/
 	BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
 		if (!BM_elem_flag_test(eve, BM_ELEM_SELECT) || BM_elem_flag_test(eve, BM_ELEM_HIDDEN))
 			continue;
-		
+
 		/* get coordinates of shapekey we're blending from */
 		sco = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, shape);
 		copy_v3_v3(co, sco);
-		
+
 		if (use_add) {
 			/* in add mode, we add relative shape key offset */
 			if (kb) {
 				const float *rco = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, kb->relative);
 				sub_v3_v3v3(co, co, rco);
 			}
-			
+
 			madd_v3_v3fl(eve->co, co, blend);
 		}
 		else {
@@ -2546,7 +2697,7 @@ static int edbm_blend_from_shape_exec(bContext *C, wmOperator *op)
 }
 
 static const EnumPropertyItem *shape_itemf(bContext *C, PointerRNA *UNUSED(ptr),  PropertyRNA *UNUSED(prop), bool *r_free)
-{	
+{
 	Object *obedit = CTX_data_edit_object(C);
 	BMEditMesh *em;
 	EnumPropertyItem *item = NULL;
@@ -2619,6 +2770,12 @@ void MESH_OT_blend_from_shape(wmOperatorType *ot)
 	RNA_def_boolean(ot->srna, "add", true, "Add", "Add rather than blend between shapes");
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Solidify Mesh Operator
+ * \{ */
+
 static int edbm_solidify_exec(bContext *C, wmOperator *op)
 {
 	Object *obedit = CTX_data_edit_object(C);
@@ -2673,6 +2830,12 @@ void MESH_OT_solidify(wmOperatorType *ot)
 	RNA_def_property_ui_range(prop, -10.0, 10.0, 0.1, 4);
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Knife Subdivide Operator
+ * \{ */
+
 /* ******************************************************************** */
 /* Knife Subdivide Tool.  Subdivides edges intersected by a mouse trail
  * drawn by user.
@@ -2706,8 +2869,9 @@ static const EnumPropertyItem knife_items[] = {
 
 /* bm_edge_seg_isect() Determines if and where a mouse trail intersects an BMEdge */
 
-static float bm_edge_seg_isect(const float sco_a[2], const float sco_b[2],
-                               float (*mouse_path)[2], int len, char mode, int *isected)
+static float bm_edge_seg_isect(
+        const float sco_a[2], const float sco_b[2],
+        float (*mouse_path)[2], int len, char mode, int *isected)
 {
 #define MAXSLOPE 100000
 	float x11, y11, x12 = 0, y12 = 0, x2max, x2min, y2max;
@@ -2716,17 +2880,17 @@ static float bm_edge_seg_isect(const float sco_a[2], const float sco_b[2],
 	float yi, x1min, x1max, y1max, y1min, perc = 0;
 	float threshold = 0.0;
 	int i;
-	
+
 	//threshold = 0.000001; /* tolerance for vertex intersection */
 	// XXX threshold = scene->toolsettings->select_thresh / 100;
-	
+
 	/* Get screen coords of verts */
 	x21 = sco_a[0];
 	y21 = sco_a[1];
-	
+
 	x22 = sco_b[0];
 	y22 = sco_b[1];
-	
+
 	xdiff2 = (x22 - x21);
 	if (xdiff2) {
 		m2 = (y22 - y21) / xdiff2;
@@ -2752,7 +2916,7 @@ static float bm_edge_seg_isect(const float sco_a[2], const float sco_b[2],
 			}
 			x12 = mouse_path[i][0];
 			y12 = mouse_path[i][1];
-			
+
 			/* test e->v1 */
 			if ((x11 == x21 && y11 == y21) || (x12 == x21 && y12 == y21)) {
 				perc = 0;
@@ -2767,7 +2931,7 @@ static float bm_edge_seg_isect(const float sco_a[2], const float sco_b[2],
 			}
 		}
 	}
-	
+
 	/* now check for edge intersect (may produce vertex intersection as well) */
 	for (i = 0; i < len; i++) {
 		if (i > 0) {
@@ -2780,14 +2944,14 @@ static float bm_edge_seg_isect(const float sco_a[2], const float sco_b[2],
 		}
 		x12 = mouse_path[i][0];
 		y12 = mouse_path[i][1];
-		
+
 		/* Perp. Distance from point to line */
 		if (m2 != MAXSLOPE) dist = (y12 - m2 * x12 - b2);  /* /sqrt(m2 * m2 + 1); Only looking for */
 		/* change in sign.  Skip extra math */
 		else dist = x22 - x12;
-		
+
 		if (i == 0) lastdist = dist;
-		
+
 		/* if dist changes sign, and intersect point in edge's Bound Box */
 		if ((lastdist * dist) <= 0) {
 			xdiff1 = (x12 - x11); /* Equation of line between last 2 points */
@@ -2803,14 +2967,14 @@ static float bm_edge_seg_isect(const float sco_a[2], const float sco_b[2],
 			x2min = min_ff(x21, x22) - 0.001f; /* due to round off error */
 			y2max = max_ff(y21, y22) + 0.001f;
 			y2min = min_ff(y21, y22) - 0.001f;
-			
+
 			/* Found an intersect,  calc intersect point */
 			if (m1 == m2) { /* co-incident lines */
 				/* cut at 50% of overlap area */
 				x1max = max_ff(x11, x12);
 				x1min = min_ff(x11, x12);
 				xi = (min_ff(x2max, x1max) + max_ff(x2min, x1min)) / 2.0f;
-				
+
 				y1max = max_ff(y11, y12);
 				y1min = min_ff(y11, y12);
 				yi = (min_ff(y2max, y1max) + max_ff(y2min, y1min)) / 2.0f;
@@ -2827,7 +2991,7 @@ static float bm_edge_seg_isect(const float sco_a[2], const float sco_b[2],
 				xi = (b1 - b2) / (m2 - m1);
 				yi = (b1 * m2 - m1 * b2) / (m2 - m1);
 			}
-			
+
 			/* Intersect inside bounding box of edge?*/
 			if ((xi >= x2min) && (xi <= x2max) && (yi <= y2max) && (yi >= y2min)) {
 				/* test for vertex intersect that may be 'close enough'*/
@@ -2850,7 +3014,7 @@ static float bm_edge_seg_isect(const float sco_a[2], const float sco_b[2],
 				if ((m2 <= 1.0f) && (m2 >= -1.0f)) perc = (xi - x21) / (x22 - x21);
 				else perc = (yi - y21) / (y22 - y21);  /* lower slope more accurate */
 				//isect = 32768.0 * (perc + 0.0000153); /* Percentage in 1 / 32768ths */
-				
+
 				break;
 			}
 		}
@@ -2879,11 +3043,11 @@ static int edbm_knife_cut_exec(bContext *C, wmOperator *op)
 
 	/* allocd vars */
 	float (*screen_vert_coords)[2], (*sco)[2], (*mouse_path)[2];
-	
+
 	/* edit-object needed for matrix, and ar->regiondata for projections to work */
 	if (ELEM(NULL, obedit, ar, ar->regiondata))
 		return OPERATOR_CANCELLED;
-	
+
 	if (bm->totvertsel < 2) {
 		BKE_report(op->reports, RPT_ERROR, "No edges are selected to operate on");
 		return OPERATOR_CANCELLED;
@@ -2968,7 +3132,7 @@ static int edbm_knife_cut_exec(bContext *C, wmOperator *op)
 	BMO_slot_bool_set(bmop.slots_in, "use_grid_fill", false);
 
 	BMO_slot_float_set(bmop.slots_in, "radius", 0);
-	
+
 	BMO_op_exec(bm, &bmop);
 	if (!EDBM_op_finish(em, &bmop, op, true)) {
 		return OPERATOR_CANCELLED;
@@ -2986,13 +3150,13 @@ void MESH_OT_knife_cut(wmOperatorType *ot)
 	ot->name = "Knife Cut";
 	ot->description = "Cut selected edges and faces into parts";
 	ot->idname = "MESH_OT_knife_cut";
-	
+
 	ot->invoke = WM_gesture_lines_invoke;
 	ot->modal = WM_gesture_lines_modal;
 	ot->exec = edbm_knife_cut_exec;
-	
+
 	ot->poll = EDBM_view3d_poll;
-	
+
 	/* flags */
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
@@ -3002,13 +3166,16 @@ void MESH_OT_knife_cut(wmOperatorType *ot)
 	RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
 
 	RNA_def_enum(ot->srna, "type", knife_items, KNIFE_EXACT, "Type", "");
-	
+
 	/* internal */
 	RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, BC_NUMCURSORS, "Cursor", "", 0, BC_NUMCURSORS);
 }
 
+/** \} */
 
-/* *************** Operator: separate parts *************/
+/* -------------------------------------------------------------------- */
+/** \name Separate Parts Operator
+ * \{ */
 
 enum {
 	MESH_SEPARATE_SELECTED = 0,
@@ -3059,7 +3226,7 @@ static Base *mesh_separate_tagged(Main *bmain, Scene *scene, Base *base_old, BMe
 
 	BM_mesh_free(bm_new);
 	((Mesh *)base_new->object->data)->edit_btmesh = NULL;
-	
+
 	return base_new;
 }
 
@@ -3287,7 +3454,7 @@ static int edbm_separate_exec(bContext *C, wmOperator *op)
 	Scene *scene = CTX_data_scene(C);
 	const int type = RNA_enum_get(op->ptr, "type");
 	int retval = 0;
-	
+
 	if (ED_operator_editmesh(C)) {
 		Base *base = CTX_data_active_base(C);
 		BMEditMesh *em = BKE_editmesh_from_object(base->object);
@@ -3400,18 +3567,23 @@ void MESH_OT_separate(wmOperatorType *ot)
 	ot->name = "Separate";
 	ot->description = "Separate selected geometry into a new mesh";
 	ot->idname = "MESH_OT_separate";
-	
+
 	/* api callbacks */
 	ot->invoke = WM_menu_invoke;
 	ot->exec = edbm_separate_exec;
 	ot->poll = ED_operator_scene_editable; /* object and editmode */
-	
+
 	/* flags */
 	ot->flag = OPTYPE_UNDO;
-	
+
 	ot->prop = RNA_def_enum(ot->srna, "type", prop_separate_types, MESH_SEPARATE_SELECTED, "Type", "");
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Triangle Fill Operator
+ * \{ */
 
 static int edbm_fill_exec(bContext *C, wmOperator *op)
 {
@@ -3433,9 +3605,9 @@ static int edbm_fill_exec(bContext *C, wmOperator *op)
 	{
 		return OPERATOR_CANCELLED;
 	}
-	
+
 	BMO_op_exec(em->bm, &bmop);
-	
+
 	if (totface_orig != em->bm->totface) {
 		/* select new geometry */
 		BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_FACE | BM_EDGE, BM_ELEM_SELECT, true);
@@ -3473,9 +3645,11 @@ void MESH_OT_fill(wmOperatorType *ot)
 	RNA_def_boolean(ot->srna, "use_beauty", true, "Beauty", "Use best triangulation division");
 }
 
+/** \} */
 
 /* -------------------------------------------------------------------- */
-/* Grid Fill (and helper functions) */
+/** \name Grid Fill Operator
+ * \{ */
 
 static bool bm_edge_test_fill_grid_cb(BMEdge *e, void *UNUSED(bm_v))
 {
@@ -3666,10 +3840,11 @@ static int edbm_fill_grid_exec(bContext *C, wmOperator *op)
 	/* end tricky prepare code */
 
 
-	if (!EDBM_op_init(em, &bmop, op,
-	                  "grid_fill edges=%he mat_nr=%i use_smooth=%b use_interp_simple=%b",
-	                  use_prepare ? BM_ELEM_TAG : BM_ELEM_SELECT,
-	                  em->mat_nr, use_smooth, use_interp_simple))
+	if (!EDBM_op_init(
+	            em, &bmop, op,
+	            "grid_fill edges=%he mat_nr=%i use_smooth=%b use_interp_simple=%b",
+	            use_prepare ? BM_ELEM_TAG : BM_ELEM_SELECT,
+	            em->mat_nr, use_smooth, use_interp_simple))
 	{
 		return OPERATOR_CANCELLED;
 	}
@@ -3719,6 +3894,12 @@ void MESH_OT_fill_grid(wmOperatorType *ot)
 	RNA_def_boolean(ot->srna, "use_interp_simple", false, "Simple Blending", "");
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Hole Fill Operator
+ * \{ */
+
 static int edbm_fill_holes_exec(bContext *C, wmOperator *op)
 {
 	Object *obedit = CTX_data_edit_object(C);
@@ -3758,6 +3939,12 @@ void MESH_OT_fill_holes(wmOperatorType *ot)
 	            "Sides", "Number of sides in hole required to fill (zero fills all holes)", 0, 100);
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Beauty Fill Operator
+ * \{ */
+
 static int edbm_beautify_fill_exec(bContext *C, wmOperator *op)
 {
 	Object *obedit = CTX_data_edit_object(C);
@@ -3775,9 +3962,10 @@ static int edbm_beautify_fill_exec(bContext *C, wmOperator *op)
 		BMEdge *e;
 
 		BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
-			BM_elem_flag_set(e, BM_ELEM_TAG,
-			                 (BM_elem_flag_test(e, BM_ELEM_SELECT) &&
-			                  BM_edge_calc_face_angle_ex(e, angle_max) < angle_limit));
+			BM_elem_flag_set(
+			        e, BM_ELEM_TAG,
+			        (BM_elem_flag_test(e, BM_ELEM_SELECT) &&
+			         BM_edge_calc_face_angle_ex(e, angle_max) < angle_limit));
 
 		}
 
@@ -3793,7 +3981,7 @@ static int edbm_beautify_fill_exec(bContext *C, wmOperator *op)
 	}
 
 	EDBM_update_generic(em, true, true);
-	
+
 	return OPERATOR_FINISHED;
 }
 
@@ -3819,8 +4007,11 @@ void MESH_OT_beautify_fill(wmOperatorType *ot)
 	RNA_def_property_float_default(prop, DEG2RADF(180.0f));
 }
 
+/** \} */
 
-/********************** Poke Face **********************/
+/* -------------------------------------------------------------------- */
+/** \name Poke Face Operator
+ * \{ */
 
 static int edbm_poke_face_exec(bContext *C, wmOperator *op)
 {
@@ -3880,7 +4071,11 @@ void MESH_OT_poke(wmOperatorType *ot)
 	             "Poke Center", "Poke Face Center Calculation");
 }
 
-/********************** Quad/Tri Operators *************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Triangulate Face Operator
+ * \{ */
 
 static int edbm_quads_convert_to_tris_exec(bContext *C, wmOperator *op)
 {
@@ -3935,6 +4130,12 @@ void MESH_OT_quads_convert_to_tris(wmOperatorType *ot)
 	             "Polygon Method", "Method for splitting the polygons into triangles");
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Convert to Quads Operator
+ * \{ */
+
 static int edbm_tris_convert_to_quads_exec(bContext *C, wmOperator *op)
 {
 	Object *obedit = CTX_data_edit_object(C);
@@ -4025,10 +4226,10 @@ void MESH_OT_tris_convert_to_quads(wmOperatorType *ot)
 	join_triangle_props(ot);
 }
 
+/** \} */
 
 /* -------------------------------------------------------------------- */
-
-/** \name Decimate
+/** \name Decimate Operator
  *
  * \note The function to decimate is intended for use as a modifier,
  * while its handy allow access as a tool - this does cause access to be a little awkward
@@ -4214,9 +4415,9 @@ void MESH_OT_decimate(wmOperatorType *ot)
 
 /** \} */
 
-
 /* -------------------------------------------------------------------- */
-/* Dissolve */
+/** \name Dissolve Vertices Operator
+ * \{ */
 
 static void edbm_dissolve_prop__use_verts(wmOperatorType *ot, bool value, int flag)
 {
@@ -4248,9 +4449,10 @@ static int edbm_dissolve_verts_exec(bContext *C, wmOperator *op)
 	const bool use_face_split = RNA_boolean_get(op->ptr, "use_face_split");
 	const bool use_boundary_tear = RNA_boolean_get(op->ptr, "use_boundary_tear");
 
-	if (!EDBM_op_callf(em, op,
-	                   "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b",
-	                   BM_ELEM_SELECT, use_face_split, use_boundary_tear))
+	if (!EDBM_op_callf(
+	            em, op,
+	            "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b",
+	            BM_ELEM_SELECT, use_face_split, use_boundary_tear))
 	{
 		return OPERATOR_CANCELLED;
 	}
@@ -4278,6 +4480,12 @@ void MESH_OT_dissolve_verts(wmOperatorType *ot)
 	edbm_dissolve_prop__use_boundary_tear(ot);
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Dissolve Edges Operator
+ * \{ */
+
 static int edbm_dissolve_edges_exec(bContext *C, wmOperator *op)
 {
 	Object *obedit = CTX_data_edit_object(C);
@@ -4286,9 +4494,10 @@ static int edbm_dissolve_edges_exec(bContext *C, wmOperator *op)
 	const bool use_verts = RNA_boolean_get(op->ptr, "use_verts");
 	const bool use_face_split = RNA_boolean_get(op->ptr, "use_face_split");
 
-	if (!EDBM_op_callf(em, op,
-	                   "dissolve_edges edges=%he use_verts=%b use_face_split=%b",
-	                   BM_ELEM_SELECT, use_verts, use_face_split))
+	if (!EDBM_op_callf(
+	            em, op,
+	            "dissolve_edges edges=%he use_verts=%b use_face_split=%b",
+	            BM_ELEM_SELECT, use_verts, use_face_split))
 	{
 		return OPERATOR_CANCELLED;
 	}
@@ -4316,6 +4525,12 @@ void MESH_OT_dissolve_edges(wmOperatorType *ot)
 	edbm_dissolve_prop__use_face_split(ot);
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Dissolve Faces Operator
+ * \{ */
+
 static int edbm_dissolve_faces_exec(bContext *C, wmOperator *op)
 {
 	Object *obedit = CTX_data_edit_object(C);
@@ -4354,6 +4569,11 @@ void MESH_OT_dissolve_faces(wmOperatorType *ot)
 	edbm_dissolve_prop__use_verts(ot, false, 0);
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Dissolve (Context Sensitive) Operator
+ * \{ */
 
 static int edbm_dissolve_mode_exec(bContext *C, wmOperator *op)
 {
@@ -4399,6 +4619,12 @@ void MESH_OT_dissolve_mode(wmOperatorType *ot)
 	edbm_dissolve_prop__use_boundary_tear(ot);
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Limited Dissolve Operator
+ * \{ */
+
 static int edbm_dissolve_limited_exec(bContext *C, wmOperator *op)
 {
 	Object *obedit = CTX_data_edit_object(C);
@@ -4476,6 +4702,12 @@ void MESH_OT_dissolve_limited(wmOperatorType *ot)
 	                  "Delimit dissolve operation");
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Degenerate Dissolve Operator
+ * \{ */
+
 static int edbm_dissolve_degenerate_exec(bContext *C, wmOperator *op)
 {
 	Object *obedit = CTX_data_edit_object(C);
@@ -4520,6 +4752,11 @@ void MESH_OT_dissolve_degenerate(wmOperatorType *ot)
 	                       "Minimum distance between elements to merge", 1e-5f, 10.0f);
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Delete Edge-Loop Operator
+ * \{ */
 
 /* internally uses dissolve */
 static int edbm_delete_edgeloop_exec(bContext *C, wmOperator *op)
@@ -4546,9 +4783,10 @@ static int edbm_delete_edgeloop_exec(bContext *C, wmOperator *op)
 		}
 	}
 
-	if (!EDBM_op_callf(em, op,
-	                   "dissolve_edges edges=%he use_verts=%b use_face_split=%b",
-	                   BM_ELEM_SELECT, true, use_face_split))
+	if (!EDBM_op_callf(
+	            em, op,
+	            "dissolve_edges edges=%he use_verts=%b use_face_split=%b",
+	            BM_ELEM_SELECT, true, use_face_split))
 	{
 		return OPERATOR_CANCELLED;
 	}
@@ -4580,6 +4818,12 @@ void MESH_OT_delete_edgeloop(wmOperatorType *ot)
 	                "Split off face corners to maintain surrounding geometry");
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Split Geometry Operator
+ * \{ */
+
 static int edbm_split_exec(bContext *C, wmOperator *op)
 {
 	Object *ob = CTX_data_edit_object(C);
@@ -4617,16 +4861,21 @@ void MESH_OT_split(wmOperatorType *ot)
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 }
 
-/******************************************************************************
- * qsort routines.
- * Now unified, for vertices/edges/faces. */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sort Geometry Elements Operator
+ *
+ * Unified for vertices/edges/faces.
+ *
+ * \{ */
 
 enum {
 	SRT_VIEW_ZAXIS = 1,  /* Use view Z (deep) axis. */
 	SRT_VIEW_XAXIS,      /* Use view X (left to right) axis. */
 	SRT_CURSOR_DISTANCE, /* Use distance from element to 3D cursor. */
 	SRT_MATERIAL,        /* Face only: use mat number. */
-	SRT_SELECTED,        /* Move selected elements in first, without modifying 
+	SRT_SELECTED,        /* Move selected elements in first, without modifying
 	                      * relative order of selected and unselected elements. */
 	SRT_RANDOMIZE,       /* Randomize selected elements. */
 	SRT_REVERSE,         /* Reverse current order of selected elements. */
@@ -4645,10 +4894,11 @@ static int bmelemsort_comp(const void *v1, const void *v2)
 }
 
 /* Reorders vertices/edges/faces using a given methods. Loops are not supported. */
-static void sort_bmelem_flag(Scene *scene, Object *ob,
-                             View3D *v3d, RegionView3D *rv3d,
-                             const int types, const int flag, const int action,
-                             const int reverse, const unsigned int seed)
+static void sort_bmelem_flag(
+        Scene *scene, Object *ob,
+        View3D *v3d, RegionView3D *rv3d,
+        const int types, const int flag, const int action,
+        const int reverse, const unsigned int seed)
 {
 	BMEditMesh *em = BKE_editmesh_from_object(ob);
 
@@ -5114,8 +5364,9 @@ static int edbm_sort_elements_exec(bContext *C, wmOperator *op)
 		RNA_enum_set(op->ptr, "elements", elem_types);
 	}
 
-	sort_bmelem_flag(scene, ob, v3d, rv3d,
-	                 elem_types, BM_ELEM_SELECT, action, use_reverse, seed);
+	sort_bmelem_flag(
+	        scene, ob, v3d, rv3d,
+	        elem_types, BM_ELEM_SELECT, action, use_reverse, seed);
 	return OPERATOR_FINISHED;
 }
 
@@ -5204,7 +5455,11 @@ void MESH_OT_sort_elements(wmOperatorType *ot)
 	RNA_def_int(ot->srna, "seed", 0, 0, INT_MAX, "Seed", "Seed for random-based operations", 0, 255);
 }
 
-/****** end of qsort stuff ****/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Noise (Deform Vertices) Operator
+ * \{ */
 
 static int edbm_noise_exec(bContext *C, wmOperator *op)
 {
@@ -5237,7 +5492,7 @@ static int edbm_noise_exec(bContext *C, wmOperator *op)
 				vec[0] = fac * (b2 - BLI_hnoise(tex->noisesize, eve->co[0] + ofs, eve->co[1], eve->co[2]));
 				vec[1] = fac * (b2 - BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1] + ofs, eve->co[2]));
 				vec[2] = fac * (b2 - BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1], eve->co[2] + ofs));
-				
+
 				add_v3_v3(eve->co, vec);
 			}
 		}
@@ -5278,6 +5533,11 @@ void MESH_OT_noise(wmOperatorType *ot)
 	RNA_def_float(ot->srna, "factor", 0.1f, -1e4f, 1e4f, "Factor", "", 0.0f, 1.0f);
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Bridge Operator
+ * \{ */
 
 enum {
 	MESH_BRIDGELOOP_SINGLE = 0,
@@ -5364,9 +5624,10 @@ static int edbm_bridge_edge_loops_exec(bContext *C, wmOperator *op)
 		edge_hflag = BM_ELEM_SELECT;
 	}
 
-	EDBM_op_init(em, &bmop, op,
-	             "bridge_loops edges=%he use_pairs=%b use_cyclic=%b use_merge=%b merge_factor=%f twist_offset=%i",
-	             edge_hflag, use_pairs, use_cyclic, use_merge, merge_factor, twist_offset);
+	EDBM_op_init(
+	        em, &bmop, op,
+	        "bridge_loops edges=%he use_pairs=%b use_cyclic=%b use_merge=%b merge_factor=%f twist_offset=%i",
+	        edge_hflag, use_pairs, use_cyclic, use_merge, merge_factor, twist_offset);
 
 	if (use_faces && totface_del) {
 		int i;
@@ -5374,9 +5635,10 @@ static int edbm_bridge_edge_loops_exec(bContext *C, wmOperator *op)
 		for (i = 0; i < totface_del; i++) {
 			BM_elem_flag_enable(totface_del_arr[i], BM_ELEM_TAG);
 		}
-		BMO_op_callf(em->bm, BMO_FLAG_DEFAULTS,
-		             "delete geom=%hf context=%i",
-		             BM_ELEM_TAG, DEL_FACES_KEEP_BOUNDARY);
+		BMO_op_callf(
+		        em->bm, BMO_FLAG_DEFAULTS,
+		        "delete geom=%hf context=%i",
+		        BM_ELEM_TAG, DEL_FACES_KEEP_BOUNDARY);
 	}
 
 	BMO_op_exec(em->bm, &bmop);
@@ -5442,11 +5704,11 @@ void MESH_OT_bridge_edge_loops(wmOperatorType *ot)
 	ot->name = "Bridge Edge Loops";
 	ot->description = "Make faces between two or more edge loops";
 	ot->idname = "MESH_OT_bridge_edge_loops";
-	
+
 	/* api callbacks */
 	ot->exec = edbm_bridge_edge_loops_exec;
 	ot->poll = ED_operator_editmesh;
-	
+
 	/* flags */
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
@@ -5460,6 +5722,12 @@ void MESH_OT_bridge_edge_loops(wmOperatorType *ot)
 	mesh_operator_edgering_props(ot, 0, 0);
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Wire-Frame Operator
+ * \{ */
+
 static int edbm_wireframe_exec(bContext *C, wmOperator *op)
 {
 	Object *obedit = CTX_data_edit_object(C);
@@ -5474,11 +5742,12 @@ static int edbm_wireframe_exec(bContext *C, wmOperator *op)
 	const float thickness          = RNA_float_get(op->ptr,   "thickness");
 	const float offset             = RNA_float_get(op->ptr,   "offset");
 
-	EDBM_op_init(em, &bmop, op,
-	             "wireframe faces=%hf use_replace=%b use_boundary=%b use_even_offset=%b use_relative_offset=%b "
-	             "use_crease=%b crease_weight=%f thickness=%f offset=%f",
-	             BM_ELEM_SELECT, use_replace, use_boundary, use_even_offset, use_relative_offset,
-	             use_crease, crease_weight, thickness, offset);
+	EDBM_op_init(
+	        em, &bmop, op,
+	        "wireframe faces=%hf use_replace=%b use_boundary=%b use_even_offset=%b use_relative_offset=%b "
+	        "use_crease=%b crease_weight=%f thickness=%f offset=%f",
+	        BM_ELEM_SELECT, use_replace, use_boundary, use_even_offset, use_relative_offset,
+	        use_crease, crease_weight, thickness, offset);
 
 	BMO_op_exec(em->bm, &bmop);
 
@@ -5524,6 +5793,12 @@ void MESH_OT_wireframe(wmOperatorType *ot)
 	RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 2);
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Offset Edge-Loop Operator
+ * \{ */
+
 static int edbm_offset_edgeloop_exec(bContext *C, wmOperator *op)
 {
 	Object *obedit = CTX_data_edit_object(C);
@@ -5578,6 +5853,12 @@ void MESH_OT_offset_edge_loops(wmOperatorType *ot)
 	RNA_def_boolean(ot->srna, "use_cap_endpoint", false, "Cap Endpoint", "Extend loop around end-points");
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Convex Hull Operator
+ * \{ */
+
 #ifdef WITH_BULLET
 static int edbm_convex_hull_exec(bContext *C, wmOperator *op)
 {
@@ -5585,10 +5866,11 @@ static int edbm_convex_hull_exec(bContext *C, wmOperator *op)
 	BMEditMesh *em = BKE_editmesh_from_object(obedit);
 	BMOperator bmop;
 
-	EDBM_op_init(em, &bmop, op, "convex_hull input=%hvef "
-	             "use_existing_faces=%b",
-	             BM_ELEM_SELECT,
-	             RNA_boolean_get(op->ptr, "use_existing_faces"));
+	EDBM_op_init(
+	        em, &bmop, op, "convex_hull input=%hvef "
+	        "use_existing_faces=%b",
+	        BM_ELEM_SELECT,
+	        RNA_boolean_get(op->ptr, "use_existing_faces"));
 	BMO_op_exec(em->bm, &bmop);
 
 	/* Hull fails if input is coplanar */
@@ -5601,8 +5883,9 @@ static int edbm_convex_hull_exec(bContext *C, wmOperator *op)
 
 	/* Delete unused vertices, edges, and faces */
 	if (RNA_boolean_get(op->ptr, "delete_unused")) {
-		if (!EDBM_op_callf(em, op, "delete geom=%S context=%i",
-		                   &bmop, "geom_unused.out", DEL_ONLYTAGGED))
+		if (!EDBM_op_callf(
+		            em, op, "delete geom=%S context=%i",
+		            &bmop, "geom_unused.out", DEL_ONLYTAGGED))
 		{
 			EDBM_op_finish(em, &bmop, op, true);
 			return OPERATOR_CANCELLED;
@@ -5611,8 +5894,9 @@ static int edbm_convex_hull_exec(bContext *C, wmOperator *op)
 
 	/* Delete hole edges/faces */
 	if (RNA_boolean_get(op->ptr, "make_holes")) {
-		if (!EDBM_op_callf(em, op, "delete geom=%S context=%i",
-		                   &bmop, "geom_holes.out", DEL_ONLYTAGGED))
+		if (!EDBM_op_callf(
+		            em, op, "delete geom=%S context=%i",
+		            &bmop, "geom_holes.out", DEL_ONLYTAGGED))
 		{
 			EDBM_op_finish(em, &bmop, op, true);
 			return OPERATOR_CANCELLED;
@@ -5680,7 +5964,13 @@ void MESH_OT_convex_hull(wmOperatorType *ot)
 
 	join_triangle_props(ot);
 }
-#endif
+#endif  /* WITH_BULLET */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Symmetrize Operator
+ * \{ */
 
 static int mesh_symmetrize_exec(bContext *C, wmOperator *op)
 {
@@ -5690,9 +5980,10 @@ static int mesh_symmetrize_exec(bContext *C, wmOperator *op)
 
 	const float thresh = RNA_float_get(op->ptr, "threshold");
 
-	EDBM_op_init(em, &bmop, op,
-	             "symmetrize input=%hvef direction=%i dist=%f",
-	             BM_ELEM_SELECT, RNA_enum_get(op->ptr, "direction"), thresh);
+	EDBM_op_init(
+	        em, &bmop, op,
+	        "symmetrize input=%hvef direction=%i dist=%f",
+	        BM_ELEM_SELECT, RNA_enum_get(op->ptr, "direction"), thresh);
 	BMO_op_exec(em->bm, &bmop);
 
 	EDBM_flag_disable_all(em, BM_ELEM_SELECT);
@@ -5723,12 +6014,19 @@ void MESH_OT_symmetrize(struct wmOperatorType *ot)
 	/* flags */
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
-	ot->prop = RNA_def_enum(ot->srna, "direction", rna_enum_symmetrize_direction_items,
-	                        BMO_SYMMETRIZE_NEGATIVE_X,
-	                        "Direction", "Which sides to copy from and to");
+	ot->prop = RNA_def_enum(
+	        ot->srna, "direction", rna_enum_symmetrize_direction_items,
+	        BMO_SYMMETRIZE_NEGATIVE_X,
+	        "Direction", "Which sides to copy from and to");
 	RNA_def_float(ot->srna, "threshold", 1e-4f, 0.0f, 10.0f, "Threshold", "", 1e-5f, 0.1f);
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Snap to Symmetry Operator
+ * \{ */
+
 static int mesh_symmetry_snap_exec(bContext *C, wmOperator *op)
 {
 	const float eps = 0.00001f;
@@ -5847,16 +6145,23 @@ void MESH_OT_symmetry_snap(struct wmOperatorType *ot)
 	/* flags */
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
-	ot->prop = RNA_def_enum(ot->srna, "direction", rna_enum_symmetrize_direction_items,
-	                        BMO_SYMMETRIZE_NEGATIVE_X,
-	                        "Direction", "Which sides to copy from and to");
+	ot->prop = RNA_def_enum(
+	        ot->srna, "direction", rna_enum_symmetrize_direction_items,
+	        BMO_SYMMETRIZE_NEGATIVE_X,
+	        "Direction", "Which sides to copy from and to");
 	RNA_def_float_distance(ot->srna, "threshold", 0.05f, 0.0f, 10.0f, "Threshold", "", 1e-4f, 1.0f);
 	RNA_def_float(ot->srna, "factor", 0.5f, 0.0f, 1.0f, "Factor", "", 0.0f, 1.0f);
 	RNA_def_boolean(ot->srna, "use_center", true, "Center", "Snap mid verts to the axis center");
 }
 
+/** \} */
+
 #ifdef WITH_FREESTYLE
 
+/* -------------------------------------------------------------------- */
+/** \name Mark Edge (FreeStyle) Operator
+ * \{ */
+
 static int edbm_mark_freestyle_edge_exec(bContext *C, wmOperator *op)
 {
 	Object *obedit = CTX_data_edit_object(C);
@@ -5922,6 +6227,12 @@ void MESH_OT_mark_freestyle_edge(wmOperatorType *ot)
 	RNA_def_property_flag(prop, PROP_SKIP_SAVE);
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mark Face (FreeStyle) Operator
+ * \{ */
+
 static int edbm_mark_freestyle_face_exec(bContext *C, wmOperator *op)
 {
 	Object *obedit = CTX_data_edit_object(C);
@@ -5986,4 +6297,6 @@ void MESH_OT_mark_freestyle_face(wmOperatorType *ot)
 	RNA_def_property_flag(prop, PROP_SKIP_SAVE);
 }
 
-#endif
+/** \} */
+
+#endif  /* WITH_FREESTYLE */
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index c4440fa190ad463a6675b6d0e6c1d69227034cf7..d25304cef89580300327141a056a0974bc03c4d0 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -63,8 +63,14 @@
 
 #include "mesh_intern.h"  /* own include */
 
-/* mesh backup implementation. This would greatly benefit from some sort of binary diffing
- * just as the undo stack would. So leaving this as an interface for further work */
+/* -------------------------------------------------------------------- */
+/** \name Redo API
+ * \{ */
+
+/* Mesh backup implementation.
+ * This would greatly benefit from some sort of binary diffing
+ * just as the undo stack would.
+ * So leaving this as an interface for further work */
 
 BMBackup EDBM_redo_state_store(BMEditMesh *em)
 {
@@ -76,8 +82,9 @@ BMBackup EDBM_redo_state_store(BMEditMesh *em)
 void EDBM_redo_state_restore(BMBackup backup, BMEditMesh *em, int recalctess)
 {
 	BMesh *tmpbm;
-	if (!em || !backup.bmcopy)
+	if (!em || !backup.bmcopy) {
 		return;
+	}
 
 	BM_mesh_data_free(em->bm);
 	tmpbm = BM_mesh_copy(backup.bmcopy);
@@ -85,8 +92,9 @@ void EDBM_redo_state_restore(BMBackup backup, BMEditMesh *em, int recalctess)
 	MEM_freeN(tmpbm);
 	tmpbm = NULL;
 
-	if (recalctess)
+	if (recalctess) {
 		BKE_editmesh_tessface_calc(em);
+	}
 }
 
 void EDBM_redo_state_free(BMBackup *backup, BMEditMesh *em, int recalctess)
@@ -99,68 +107,21 @@ void EDBM_redo_state_free(BMBackup *backup, BMEditMesh *em, int recalctess)
 		BM_mesh_data_free(backup->bmcopy);
 	}
 
-	if (backup->bmcopy)
+	if (backup->bmcopy) {
 		MEM_freeN(backup->bmcopy);
+	}
 	backup->bmcopy = NULL;
 
-	if (recalctess && em)
+	if (recalctess && em) {
 		BKE_editmesh_tessface_calc(em);
-}
-
-void EDBM_mesh_normals_update(BMEditMesh *em)
-{
-	BM_mesh_normals_update(em->bm);
-}
-
-void EDBM_mesh_clear(BMEditMesh *em)
-{
-	/* clear bmesh */
-	BM_mesh_clear(em->bm);
-	
-	/* free derived meshes */
-	BKE_editmesh_free_derivedmesh(em);
-	
-	/* free tessellation data */
-	em->tottri = 0;
-	if (em->looptris) {
-		MEM_freeN(em->looptris);
-		em->looptris = NULL;
 	}
 }
 
-void EDBM_stats_update(BMEditMesh *em)
-{
-	const char iter_types[3] = {BM_VERTS_OF_MESH,
-	                            BM_EDGES_OF_MESH,
-	                            BM_FACES_OF_MESH};
-
-	BMIter iter;
-	BMElem *ele;
-	int *tots[3];
-	int i;
+/** \} */
 
-	tots[0] = &em->bm->totvertsel;
-	tots[1] = &em->bm->totedgesel;
-	tots[2] = &em->bm->totfacesel;
-	
-	em->bm->totvertsel = em->bm->totedgesel = em->bm->totfacesel = 0;
-
-	for (i = 0; i < 3; i++) {
-		ele = BM_iter_new(&iter, em->bm, iter_types[i], NULL);
-		for ( ; ele; ele = BM_iter_step(&iter)) {
-			if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
-				(*tots[i])++;
-			}
-		}
-	}
-}
-
-DerivedMesh *EDBM_mesh_deform_dm_get(BMEditMesh *em)
-{
-	return ((em->derivedFinal != NULL) &&
-	        (em->derivedFinal->type == DM_TYPE_EDITBMESH) &&
-	        (em->derivedFinal->deformedOnly != false)) ? em->derivedFinal : NULL;
-}
+/* -------------------------------------------------------------------- */
+/** \name BMesh Operator (BMO) API Wrapper
+ * \{ */
 
 bool EDBM_op_init(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const char *fmt, ...)
 {
@@ -174,9 +135,10 @@ bool EDBM_op_init(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const char *
 		va_end(list);
 		return false;
 	}
-	
-	if (!em->emcopy)
+
+	if (!em->emcopy) {
 		em->emcopy = BKE_editmesh_copy(em);
+	}
 	em->emcopyusers++;
 
 	va_end(list);
@@ -184,12 +146,11 @@ bool EDBM_op_init(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const char *
 	return true;
 }
 
-
 /* returns 0 on error, 1 on success.  executes and finishes a bmesh operator */
 bool EDBM_op_finish(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const bool do_report)
 {
 	const char *errmsg;
-	
+
 	BMO_op_finish(em->bm, bmop);
 
 	if (BMO_error_get(em->bm, &errmsg, NULL)) {
@@ -244,8 +205,9 @@ bool EDBM_op_callf(BMEditMesh *em, wmOperator *op, const char *fmt, ...)
 		return false;
 	}
 
-	if (!em->emcopy)
+	if (!em->emcopy) {
 		em->emcopy = BKE_editmesh_copy(em);
+	}
 	em->emcopyusers++;
 
 	BMO_op_exec(bm, &bmop);
@@ -254,9 +216,10 @@ bool EDBM_op_callf(BMEditMesh *em, wmOperator *op, const char *fmt, ...)
 	return EDBM_op_finish(em, &bmop, op, true);
 }
 
-bool EDBM_op_call_and_selectf(BMEditMesh *em, wmOperator *op,
-                              const char *select_slot_out, const bool select_extend,
-                              const char *fmt, ...)
+bool EDBM_op_call_and_selectf(
+        BMEditMesh *em, wmOperator *op,
+        const char *select_slot_out, const bool select_extend,
+        const char *fmt, ...)
 {
 	BMOpSlot *slot_select_out;
 	BMesh *bm = em->bm;
@@ -272,8 +235,9 @@ bool EDBM_op_call_and_selectf(BMEditMesh *em, wmOperator *op,
 		return false;
 	}
 
-	if (!em->emcopy)
+	if (!em->emcopy) {
 		em->emcopy = BKE_editmesh_copy(em);
+	}
 	em->emcopyusers++;
 
 	BMO_op_exec(bm, &bmop);
@@ -305,8 +269,9 @@ bool EDBM_op_call_silentf(BMEditMesh *em, const char *fmt, ...)
 		return false;
 	}
 
-	if (!em->emcopy)
+	if (!em->emcopy) {
 		em->emcopy = BKE_editmesh_copy(em);
+	}
 	em->emcopyusers++;
 
 	BMO_op_exec(bm, &bmop);
@@ -315,22 +280,15 @@ bool EDBM_op_call_silentf(BMEditMesh *em, const char *fmt, ...)
 	return EDBM_op_finish(em, &bmop, NULL, false);
 }
 
-void EDBM_selectmode_to_scene(bContext *C)
-{
-	Scene *scene = CTX_data_scene(C);
-	Object *obedit = CTX_data_edit_object(C);
-	BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
-	if (!em)
-		return;
+/** \} */
 
-	scene->toolsettings->selectmode = em->selectmode;
-
-	/* Request redraw of header buttons (to show new select mode) */
-	WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, scene);
-}
+/* -------------------------------------------------------------------- */
+/** \name Edit BMesh API
+ *
+ * Make/Clear/Free functions.
+ * \{ */
 
-void EDBM_mesh_make(ToolSettings *ts, Object *ob, const bool add_key_index)
+void EDBM_mesh_make(Object *ob, const int select_mode, const bool add_key_index)
 {
 	Mesh *me = ob->data;
 	BMesh *bm;
@@ -357,7 +315,7 @@ void EDBM_mesh_make(ToolSettings *ts, Object *ob, const bool add_key_index)
 	me->edit_btmesh = BKE_editmesh_create(bm, false);
 #endif
 
-	me->edit_btmesh->selectmode = me->edit_btmesh->bm->selectmode = ts->selectmode;
+	me->edit_btmesh->selectmode = me->edit_btmesh->bm->selectmode = select_mode;
 	me->edit_btmesh->mat_nr = (ob->actcol > 0) ? ob->actcol - 1 : 0;
 	me->edit_btmesh->ob = ob;
 
@@ -412,6 +370,22 @@ void EDBM_mesh_load(Object *ob)
 #endif
 }
 
+void EDBM_mesh_clear(BMEditMesh *em)
+{
+	/* clear bmesh */
+	BM_mesh_clear(em->bm);
+
+	/* free derived meshes */
+	BKE_editmesh_free_derivedmesh(em);
+
+	/* free tessellation data */
+	em->tottri = 0;
+	if (em->looptris) {
+		MEM_freeN(em->looptris);
+		em->looptris = NULL;
+	}
+}
+
 /**
  * Should only be called on the active editmesh, otherwise call #BKE_editmesh_free
  */
@@ -426,6 +400,28 @@ void EDBM_mesh_free(BMEditMesh *em)
 	BKE_editmesh_free(em);
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Selection Utilities
+ * \{ */
+
+void EDBM_selectmode_to_scene(bContext *C)
+{
+	Scene *scene = CTX_data_scene(C);
+	Object *obedit = CTX_data_edit_object(C);
+	BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+	if (!em) {
+		return;
+	}
+
+	scene->toolsettings->selectmode = em->selectmode;
+
+	/* Request redraw of header buttons (to show new select mode) */
+	WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, scene);
+}
+
 void EDBM_selectmode_flush_ex(BMEditMesh *em, const short selectmode)
 {
 	BM_mesh_select_mode_flush_ex(em->bm, selectmode);
@@ -443,7 +439,6 @@ void EDBM_deselect_flush(BMEditMesh *em)
 	BM_mesh_deselect_flush(em->bm);
 }
 
-
 void EDBM_select_flush(BMEditMesh *em)
 {
 	/* function below doesnt use. just do this to keep the values in sync */
@@ -456,9 +451,10 @@ void EDBM_select_more(BMEditMesh *em, const bool use_face_step)
 	BMOperator bmop;
 	const bool use_faces = (em->selectmode == SCE_SELECT_FACE);
 
-	BMO_op_initf(em->bm, &bmop, BMO_FLAG_DEFAULTS,
-	             "region_extend geom=%hvef use_contract=%b use_faces=%b use_face_step=%b",
-	             BM_ELEM_SELECT, false, use_faces, use_face_step);
+	BMO_op_initf(
+	        em->bm, &bmop, BMO_FLAG_DEFAULTS,
+	        "region_extend geom=%hvef use_contract=%b use_faces=%b use_face_step=%b",
+	        BM_ELEM_SELECT, false, use_faces, use_face_step);
 	BMO_op_exec(em->bm, &bmop);
 	/* don't flush selection in edge/vertex mode  */
 	BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, use_faces ? true : false);
@@ -472,9 +468,10 @@ void EDBM_select_less(BMEditMesh *em, const bool use_face_step)
 	BMOperator bmop;
 	const bool use_faces = (em->selectmode == SCE_SELECT_FACE);
 
-	BMO_op_initf(em->bm, &bmop, BMO_FLAG_DEFAULTS,
-	             "region_extend geom=%hvef use_contract=%b use_faces=%b use_face_step=%b",
-	             BM_ELEM_SELECT, true, use_faces, use_face_step);
+	BMO_op_initf(
+	        em->bm, &bmop, BMO_FLAG_DEFAULTS,
+	        "region_extend geom=%hvef use_contract=%b use_faces=%b use_face_step=%b",
+	        BM_ELEM_SELECT, true, use_faces, use_face_step);
 	BMO_op_exec(em->bm, &bmop);
 	/* don't flush selection in edge/vertex mode  */
 	BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, use_faces ? true : false);
@@ -496,6 +493,12 @@ void EDBM_flag_enable_all(BMEditMesh *em, const char hflag)
 	BM_mesh_elem_hflag_enable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, hflag, true);
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name UV Vertex Map API
+ * \{ */
+
 /**
  * Return a new UVVertMap from the editmesh
  */
@@ -519,7 +522,7 @@ UvVertMap *BM_uv_vert_map_create(
 	BLI_buffer_declare_static(vec2f, tf_uv_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE);
 
 	BM_mesh_elem_index_ensure(bm, BM_VERT | BM_FACE);
-	
+
 	totfaces = bm->totface;
 	totverts = bm->totvert;
 	totuv = 0;
@@ -549,7 +552,7 @@ UvVertMap *BM_uv_vert_map_create(
 		BKE_mesh_uv_vert_map_free(vmap);
 		return NULL;
 	}
-	
+
 	BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, a) {
 		if ((use_select == false) || BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
 			float (*tf_uv)[2];
@@ -562,7 +565,7 @@ UvVertMap *BM_uv_vert_map_create(
 				buf->tfindex = i;
 				buf->f = a;
 				buf->separate = 0;
-				
+
 				buf->next = vmap->vert[BM_elem_index_get(l->v)];
 				vmap->vert[BM_elem_index_get(l->v)] = buf;
 				buf++;
@@ -578,7 +581,7 @@ UvVertMap *BM_uv_vert_map_create(
 			}
 		}
 	}
-	
+
 	/* sort individual uvs for each vert */
 	BM_ITER_MESH_INDEX (ev, &iter, bm, BM_VERTS_OF_MESH, a) {
 		UvMapVert *newvlist = NULL, *vlist = vmap->vert[a];
@@ -593,11 +596,11 @@ UvVertMap *BM_uv_vert_map_create(
 
 			efa = BM_face_at_index(bm, v->f);
 			/* tf = CustomData_bmesh_get(&bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */
-			
+
 			l = BM_iter_at_index(bm, BM_LOOPS_OF_FACE, efa, v->tfindex);
 			luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
 			uv = luv->uv;
-			
+
 			lastv = NULL;
 			iterv = vlist;
 
@@ -605,11 +608,11 @@ UvVertMap *BM_uv_vert_map_create(
 				next = iterv->next;
 				efa = BM_face_at_index(bm, iterv->f);
 				/* tf = CustomData_bmesh_get(&bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */
-				
+
 				l = BM_iter_at_index(bm, BM_LOOPS_OF_FACE, efa, iterv->tfindex);
 				luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
 				uv2 = luv->uv;
-				
+
 				sub_v2_v2v2(uvdiff, uv2, uv);
 
 				if (fabsf(uvdiff[0]) < limit[0] && fabsf(uvdiff[1]) < limit[1] &&
@@ -642,13 +645,11 @@ UvVertMap *BM_uv_vert_map_create(
 	return vmap;
 }
 
-
 UvMapVert *BM_uv_vert_map_at_index(UvVertMap *vmap, unsigned int v)
 {
 	return vmap->vert[v];
 }
 
-
 /* A specialized vert map used by stitch operator */
 UvElementMap *BM_uv_element_map_create(
         BMesh *bm,
@@ -906,42 +907,51 @@ void BM_uv_element_map_free(UvElementMap *element_map)
 
 UvElement *BM_uv_element_get(UvElementMap *map, BMFace *efa, BMLoop *l)
 {
-	UvElement *element;
-
-	element = map->vert[BM_elem_index_get(l->v)];
-
-	for (; element; element = element->next)
-		if (element->l->f == efa)
+	for (UvElement *element = map->vert[BM_elem_index_get(l->v)];
+	     element;
+	     element = element->next)
+	{
+		if (element->l->f == efa) {
 			return element;
+		}
+	}
 
 	return NULL;
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Data Layer Checks
+ * \{ */
+
 /* last_sel, use em->act_face otherwise get the last selected face in the editselections
  * at the moment, last_sel is mainly useful for making sure the space image dosnt flicker */
-MTexPoly *EDBM_mtexpoly_active_get(BMEditMesh *em, BMFace **r_act_efa, const bool sloppy, const bool selected)
+BMFace *EDBM_uv_active_face_get(BMEditMesh *em, const bool sloppy, const bool selected, MTexPoly **r_tf)
 {
 	BMFace *efa = NULL;
-	
-	if (!EDBM_mtexpoly_check(em))
+
+	if (!EDBM_uv_check(em)) {
 		return NULL;
-	
+	}
+
 	efa = BM_mesh_active_face_get(em->bm, sloppy, selected);
 
 	if (efa) {
-		if (r_act_efa) *r_act_efa = efa;
-		return CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+		if (r_tf) *r_tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+		return efa;
 	}
 
-	if (r_act_efa) *r_act_efa = NULL;
+	if (r_tf) *r_tf = NULL;
 	return NULL;
 }
 
 /* can we edit UV's for this mesh?*/
-bool EDBM_mtexpoly_check(BMEditMesh *em)
+bool EDBM_uv_check(BMEditMesh *em)
 {
 	/* some of these checks could be a touch overkill */
-	return em && em->bm->totface && CustomData_has_layer(&em->bm->pdata, CD_MTEXPOLY) &&
+	return em && em->bm->totface &&
+	       CustomData_has_layer(&em->bm->pdata, CD_MTEXPOLY) &&
 	       CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV);
 }
 
@@ -951,6 +961,12 @@ bool EDBM_vert_color_check(BMEditMesh *em)
 	return em && em->bm->totface && CustomData_has_layer(&em->bm->ldata, CD_MLOOPCOL);
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mirror Cache API
+ * \{ */
+
 static BMVert *cache_mirr_intptr_as_bmvert(intptr_t *index_lookup, int index)
 {
 	intptr_t eve_i = index_lookup[index];
@@ -985,9 +1001,10 @@ static BMVert *cache_mirr_intptr_as_bmvert(intptr_t *index_lookup, int index)
  * \param maxdist  Distance for close point test.
  * \param r_index  Optional array to write into, as an alternative to a customdata layer (length of total verts).
  */
-void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em, const int axis, const bool use_self, const bool use_select,
-                                      /* extra args */
-                                      const bool use_topology, float maxdist, int *r_index)
+void EDBM_verts_mirror_cache_begin_ex(
+        BMEditMesh *em, const int axis, const bool use_self, const bool use_select,
+        /* extra args */
+        const bool use_topology, float maxdist, int *r_index)
 {
 	Mesh *me = (Mesh *)em->ob->data;
 	BMesh *bm = em->bm;
@@ -1011,8 +1028,9 @@ void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em, const int axis, const bool
 			em->mirror_cdlayer = CustomData_get_named_layer_index(&bm->vdata, CD_PROP_INT, layer_id);
 		}
 
-		cd_vmirr_offset = CustomData_get_n_offset(&bm->vdata, CD_PROP_INT,
-		                                          em->mirror_cdlayer - CustomData_get_layer_index(&bm->vdata, CD_PROP_INT));
+		cd_vmirr_offset = CustomData_get_n_offset(
+		        &bm->vdata, CD_PROP_INT,
+		        em->mirror_cdlayer - CustomData_get_layer_index(&bm->vdata, CD_PROP_INT));
 
 		bm->vdata.layers[em->mirror_cdlayer].flag |= CD_FLAG_TEMPORARY;
 	}
@@ -1085,14 +1103,16 @@ void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em, const int axis, const bool
 	}
 }
 
-void EDBM_verts_mirror_cache_begin(BMEditMesh *em, const int axis,
-                                   const bool use_self, const bool use_select,
-                                   const bool use_topology)
+void EDBM_verts_mirror_cache_begin(
+        BMEditMesh *em, const int axis,
+        const bool use_self, const bool use_select,
+        const bool use_topology)
 {
-	EDBM_verts_mirror_cache_begin_ex(em, axis,
-	                                 use_self, use_select,
-	                                 /* extra args */
-	                                 use_topology, BM_SEARCH_MAXDIST_MIRR, NULL);
+	EDBM_verts_mirror_cache_begin_ex(
+	        em, axis,
+	        use_self, use_select,
+	        /* extra args */
+	        use_topology, BM_SEARCH_MAXDIST_MIRR, NULL);
 }
 
 BMVert *EDBM_verts_mirror_get(BMEditMesh *em, BMVert *v)
@@ -1180,6 +1200,11 @@ void EDBM_verts_mirror_apply(BMEditMesh *em, const int sel_from, const int sel_t
 	}
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Hide/Reveal API
+ * \{ */
 
 /* swap is 0 or 1, if 1 it hides not selected */
 void EDBM_mesh_hide(BMEditMesh *em, bool swap)
@@ -1214,17 +1239,18 @@ void EDBM_mesh_hide(BMEditMesh *em, bool swap)
 	 */
 }
 
-
 void EDBM_mesh_reveal(BMEditMesh *em, bool select)
 {
-	const char iter_types[3] = {BM_VERTS_OF_MESH,
-	                            BM_EDGES_OF_MESH,
-	                            BM_FACES_OF_MESH};
+	const char iter_types[3] = {
+		BM_VERTS_OF_MESH,
+		BM_EDGES_OF_MESH,
+		BM_FACES_OF_MESH,
+	};
 
 	const bool sels[3] = {
-	    (em->selectmode & SCE_SELECT_VERTEX) != 0,
-	    (em->selectmode & SCE_SELECT_EDGE) != 0,
-	    (em->selectmode & SCE_SELECT_FACE) != 0,
+		(em->selectmode & SCE_SELECT_VERTEX) != 0,
+		(em->selectmode & SCE_SELECT_EDGE) != 0,
+		(em->selectmode & SCE_SELECT_FACE) != 0,
 	};
 	int i;
 
@@ -1264,6 +1290,46 @@ void EDBM_mesh_reveal(BMEditMesh *em, bool select)
 	EDBM_mesh_normals_update(em);
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Update API
+ * \{ */
+
+void EDBM_mesh_normals_update(BMEditMesh *em)
+{
+	BM_mesh_normals_update(em->bm);
+}
+
+void EDBM_stats_update(BMEditMesh *em)
+{
+	const char iter_types[3] = {
+		BM_VERTS_OF_MESH,
+		BM_EDGES_OF_MESH,
+		BM_FACES_OF_MESH,
+	};
+
+	BMIter iter;
+	BMElem *ele;
+	int *tots[3];
+	int i;
+
+	tots[0] = &em->bm->totvertsel;
+	tots[1] = &em->bm->totedgesel;
+	tots[2] = &em->bm->totfacesel;
+
+	em->bm->totvertsel = em->bm->totedgesel = em->bm->totfacesel = 0;
+
+	for (i = 0; i < 3; i++) {
+		ele = BM_iter_new(&iter, em->bm, iter_types[i], NULL);
+		for ( ; ele; ele = BM_iter_step(&iter)) {
+			if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
+				(*tots[i])++;
+			}
+		}
+	}
+}
+
 /* so many tools call these that we better make it a generic function.
  */
 void EDBM_update_generic(BMEditMesh *em, const bool do_tessface, const bool is_destructive)
@@ -1299,15 +1365,41 @@ void EDBM_update_generic(BMEditMesh *em, const bool do_tessface, const bool is_d
 #endif
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Data Access
+ * \{ */
+
+DerivedMesh *EDBM_mesh_deform_dm_get(BMEditMesh *em)
+{
+	return ((em->derivedFinal != NULL) &&
+	        (em->derivedFinal->type == DM_TYPE_EDITBMESH) &&
+	        (em->derivedFinal->deformedOnly != false)) ? em->derivedFinal : NULL;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Operator Helpers
+ * \{ */
+
 /* poll call for mesh operators requiring a view3d context */
 int EDBM_view3d_poll(bContext *C)
 {
-	if (ED_operator_editmesh(C) && ED_operator_view3d_active(C))
+	if (ED_operator_editmesh(C) && ED_operator_view3d_active(C)) {
 		return 1;
+	}
 
 	return 0;
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BMesh Element API
+ * \{ */
+
 BMElem *EDBM_elem_from_selectmode(BMEditMesh *em, BMVert *eve, BMEdge *eed, BMFace *efa)
 {
 	BMElem *ele = NULL;
@@ -1372,22 +1464,19 @@ BMElem *EDBM_elem_from_index_any(BMEditMesh *em, int index)
 	return NULL;
 }
 
-/* -------------------------------------------------------------------- */
-/* BMBVH functions */
-// XXX
-#if 0 //BMESH_TODO: not implemented yet
-int BMBVH_VertVisible(BMBVHTree *tree, BMEdge *e, RegionView3D *r3d)
-{
+/** \} */
 
-}
-#endif
+/* -------------------------------------------------------------------- */
+/** \name BMesh BVH API
+ * \{ */
 
 static BMFace *edge_ray_cast(struct BMBVHTree *tree, const float co[3], const float dir[3], float *r_hitout, BMEdge *e)
 {
 	BMFace *f = BKE_bmbvh_ray_cast(tree, co, dir, 0.0f, NULL, r_hitout, NULL);
 
-	if (f && BM_edge_in_face(e, f))
+	if (f && BM_edge_in_face(e, f)) {
 		return NULL;
+	}
 
 	return f;
 }
@@ -1406,8 +1495,10 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree, BMEdge *e, ARegion *ar, View3D *v
 	float origin[3], invmat[4][4];
 	float epsilon = 0.01f;
 	float end[3];
-	const float mval_f[2] = {ar->winx / 2.0f,
-	                         ar->winy / 2.0f};
+	const float mval_f[2] = {
+		ar->winx / 2.0f,
+		ar->winy / 2.0f,
+	};
 
 	ED_view3d_win_to_segment(ar, v3d, mval_f, origin, end, false);
 
@@ -1443,12 +1534,17 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree, BMEdge *e, ARegion *ar, View3D *v
 
 	/* do three samplings: left, middle, right */
 	f = edge_ray_cast(tree, co1, dir1, NULL, e);
-	if (f && !edge_ray_cast(tree, co2, dir2, NULL, e))
+	if (f && !edge_ray_cast(tree, co2, dir2, NULL, e)) {
 		return true;
-	else if (f && !edge_ray_cast(tree, co3, dir3, NULL, e))
+	}
+	else if (f && !edge_ray_cast(tree, co3, dir3, NULL, e)) {
 		return true;
-	else if (!f)
+	}
+	else if (!f) {
 		return true;
+	}
 
 	return false;
 }
+
+/** \} */
diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c
index cfeda36214c2e9e7c593d2402b3c628de18a0f5e..84d2ac3cef1e3fc4e49c8d1359435335eda6bd3d 100644
--- a/source/blender/editors/mesh/mesh_data.c
+++ b/source/blender/editors/mesh/mesh_data.c
@@ -596,7 +596,7 @@ static int drop_named_image_invoke(bContext *C, wmOperator *op, const wmEvent *e
 	obedit = base->object;
 	me = obedit->data;
 	if (me->edit_btmesh == NULL) {
-		EDBM_mesh_make(scene->toolsettings, obedit, false);
+		EDBM_mesh_make(obedit, scene->toolsettings->selectmode, false);
 		exitmode = 1;
 	}
 	if (me->edit_btmesh == NULL)
diff --git a/source/blender/editors/mesh/mesh_mirror.c b/source/blender/editors/mesh/mesh_mirror.c
new file mode 100644
index 0000000000000000000000000000000000000000..96b9f054252afc5f6f9fcc2c4f496049782e695c
--- /dev/null
+++ b/source/blender/editors/mesh/mesh_mirror.c
@@ -0,0 +1,374 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Foundation, Campbell Barton
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/mesh/mesh_mirror.c
+ *  \ingroup edmesh
+ *
+ * Mirror calculation for edit-mode and object mode.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_bitmap.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_DerivedMesh.h"
+#include "BLI_kdtree.h"
+#include "BKE_editmesh.h"
+
+#include "ED_mesh.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Mesh Spatial Mirror API
+ * \{ */
+
+#define KD_THRESH      0.00002f
+
+static struct { void *tree; } MirrKdStore = {NULL};
+
+/* mode is 's' start, or 'e' end, or 'u' use */
+/* if end, ob can be NULL */
+int ED_mesh_mirror_spatial_table(Object *ob, BMEditMesh *em, DerivedMesh *dm, const float co[3], char mode)
+{
+	if (mode == 'u') {        /* use table */
+		if (MirrKdStore.tree == NULL)
+			ED_mesh_mirror_spatial_table(ob, em, dm, NULL, 's');
+
+		if (MirrKdStore.tree) {
+			KDTreeNearest nearest;
+			const int i = BLI_kdtree_find_nearest(MirrKdStore.tree, co, &nearest);
+
+			if (i != -1) {
+				if (nearest.dist < KD_THRESH) {
+					return i;
+				}
+			}
+		}
+		return -1;
+	}
+	else if (mode == 's') {   /* start table */
+		Mesh *me = ob->data;
+		const bool use_em = (!dm && em && me->edit_btmesh == em);
+		const int totvert = use_em ? em->bm->totvert : dm ? dm->getNumVerts(dm) : me->totvert;
+
+		if (MirrKdStore.tree) /* happens when entering this call without ending it */
+			ED_mesh_mirror_spatial_table(ob, em, dm, co, 'e');
+
+		MirrKdStore.tree = BLI_kdtree_new(totvert);
+
+		if (use_em) {
+			BMVert *eve;
+			BMIter iter;
+			int i;
+
+			/* this needs to be valid for index lookups later (callers need) */
+			BM_mesh_elem_table_ensure(em->bm, BM_VERT);
+
+			BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
+				BLI_kdtree_insert(MirrKdStore.tree, i, eve->co);
+			}
+		}
+		else {
+			MVert *mvert = dm ? dm->getVertArray(dm) : me->mvert;
+			int i;
+			
+			for (i = 0; i < totvert; i++, mvert++) {
+				BLI_kdtree_insert(MirrKdStore.tree, i, mvert->co);
+			}
+		}
+
+		BLI_kdtree_balance(MirrKdStore.tree);
+	}
+	else if (mode == 'e') { /* end table */
+		if (MirrKdStore.tree) {
+			BLI_kdtree_free(MirrKdStore.tree);
+			MirrKdStore.tree = NULL;
+		}
+	}
+	else {
+		BLI_assert(0);
+	}
+
+	return 0;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mesh Topology Mirror API
+ * \{ */
+
+typedef unsigned int MirrTopoHash_t;
+
+typedef struct MirrTopoVert_t {
+	MirrTopoHash_t hash;
+	int v_index;
+} MirrTopoVert_t;
+
+static int mirrtopo_hash_sort(const void *l1, const void *l2)
+{
+	if      ((MirrTopoHash_t)(intptr_t)l1 > (MirrTopoHash_t)(intptr_t)l2) return 1;
+	else if ((MirrTopoHash_t)(intptr_t)l1 < (MirrTopoHash_t)(intptr_t)l2) return -1;
+	return 0;
+}
+
+static int mirrtopo_vert_sort(const void *v1, const void *v2)
+{
+	if      (((MirrTopoVert_t *)v1)->hash > ((MirrTopoVert_t *)v2)->hash) return 1;
+	else if (((MirrTopoVert_t *)v1)->hash < ((MirrTopoVert_t *)v2)->hash) return -1;
+	return 0;
+}
+
+bool ED_mesh_mirrtopo_recalc_check(Mesh *me, DerivedMesh *dm, const int ob_mode, MirrTopoStore_t *mesh_topo_store)
+{
+	int totvert;
+	int totedge;
+
+	if (dm) {
+		totvert = dm->getNumVerts(dm);
+		totedge = dm->getNumEdges(dm);
+	}
+	else if (me->edit_btmesh) {
+		totvert = me->edit_btmesh->bm->totvert;
+		totedge = me->edit_btmesh->bm->totedge;
+	}
+	else {
+		totvert = me->totvert;
+		totedge = me->totedge;
+	}
+
+	if ((mesh_topo_store->index_lookup == NULL) ||
+	    (mesh_topo_store->prev_ob_mode != ob_mode) ||
+	    (totvert != mesh_topo_store->prev_vert_tot) ||
+	    (totedge != mesh_topo_store->prev_edge_tot))
+	{
+		return true;
+	}
+	else {
+		return false;
+	}
+
+}
+
+void ED_mesh_mirrtopo_init(Mesh *me, DerivedMesh *dm, const int ob_mode, MirrTopoStore_t *mesh_topo_store,
+                           const bool skip_em_vert_array_init)
+{
+	MEdge *medge = NULL, *med;
+	BMEditMesh *em = dm ?  NULL : me->edit_btmesh;
+
+	/* editmode*/
+	BMEdge *eed;
+	BMIter iter;
+
+	int a, last;
+	int totvert, totedge;
+	int tot_unique = -1, tot_unique_prev = -1;
+	int tot_unique_edges = 0, tot_unique_edges_prev;
+
+	MirrTopoHash_t *topo_hash = NULL;
+	MirrTopoHash_t *topo_hash_prev = NULL;
+	MirrTopoVert_t *topo_pairs;
+	MirrTopoHash_t  topo_pass = 1;
+
+	intptr_t *index_lookup; /* direct access to mesh_topo_store->index_lookup */
+
+	/* reallocate if needed */
+	ED_mesh_mirrtopo_free(mesh_topo_store);
+
+	mesh_topo_store->prev_ob_mode = ob_mode;
+
+	if (em) {
+		BM_mesh_elem_index_ensure(em->bm, BM_VERT);
+
+		totvert = em->bm->totvert;
+	}
+	else {
+		totvert = dm ? dm->getNumVerts(dm) : me->totvert;
+	}
+
+	topo_hash = MEM_callocN(totvert * sizeof(MirrTopoHash_t), "TopoMirr");
+
+	/* Initialize the vert-edge-user counts used to detect unique topology */
+	if (em) {
+		totedge = me->edit_btmesh->bm->totedge;
+
+		BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
+			const int i1 = BM_elem_index_get(eed->v1), i2 = BM_elem_index_get(eed->v2);
+			topo_hash[i1]++;
+			topo_hash[i2]++;
+		}
+	}
+	else {
+		totedge = dm ? dm->getNumEdges(dm) : me->totedge;
+		medge = dm ? dm->getEdgeArray(dm) : me->medge;
+
+		for (a = 0, med = medge; a < totedge; a++, med++) {
+			const unsigned int i1 = med->v1, i2 = med->v2;
+			topo_hash[i1]++;
+			topo_hash[i2]++;
+		}
+	}
+
+	topo_hash_prev = MEM_dupallocN(topo_hash);
+
+	tot_unique_prev = -1;
+	tot_unique_edges_prev = -1;
+	while (1) {
+		/* use the number of edges per vert to give verts unique topology IDs */
+
+		tot_unique_edges = 0;
+
+		/* This can make really big numbers, wrapping around here is fine */
+		if (em) {
+			BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
+				const int i1 = BM_elem_index_get(eed->v1), i2 = BM_elem_index_get(eed->v2);
+				topo_hash[i1] += topo_hash_prev[i2] * topo_pass;
+				topo_hash[i2] += topo_hash_prev[i1] * topo_pass;
+				tot_unique_edges += (topo_hash[i1] != topo_hash[i2]);
+			}
+		}
+		else {
+			for (a = 0, med = medge; a < totedge; a++, med++) {
+				const unsigned int i1 = med->v1, i2 = med->v2;
+				topo_hash[i1] += topo_hash_prev[i2] * topo_pass;
+				topo_hash[i2] += topo_hash_prev[i1] * topo_pass;
+				tot_unique_edges += (topo_hash[i1] != topo_hash[i2]);
+			}
+		}
+		memcpy(topo_hash_prev, topo_hash, sizeof(MirrTopoHash_t) * totvert);
+
+		/* sort so we can count unique values */
+		qsort(topo_hash_prev, totvert, sizeof(MirrTopoHash_t), mirrtopo_hash_sort);
+
+		tot_unique = 1; /* account for skiping the first value */
+		for (a = 1; a < totvert; a++) {
+			if (topo_hash_prev[a - 1] != topo_hash_prev[a]) {
+				tot_unique++;
+			}
+		}
+
+		if ((tot_unique <= tot_unique_prev) && (tot_unique_edges <= tot_unique_edges_prev)) {
+			/* Finish searching for unique values when 1 loop dosnt give a
+			 * higher number of unique values compared to the previous loop */
+			break;
+		}
+		else {
+			tot_unique_prev = tot_unique;
+			tot_unique_edges_prev = tot_unique_edges;
+		}
+		/* Copy the hash calculated this iter, so we can use them next time */
+		memcpy(topo_hash_prev, topo_hash, sizeof(MirrTopoHash_t) * totvert);
+
+		topo_pass++;
+	}
+
+	/* Hash/Index pairs are needed for sorting to find index pairs */
+	topo_pairs = MEM_callocN(sizeof(MirrTopoVert_t) * totvert, "MirrTopoPairs");
+
+	/* since we are looping through verts, initialize these values here too */
+	index_lookup = MEM_mallocN(totvert * sizeof(*index_lookup), "mesh_topo_lookup");
+
+	if (em) {
+		if (skip_em_vert_array_init == false) {
+			BM_mesh_elem_table_ensure(em->bm, BM_VERT);
+		}
+	}
+
+	for (a = 0; a < totvert; a++) {
+		topo_pairs[a].hash    = topo_hash[a];
+		topo_pairs[a].v_index = a;
+
+		/* initialize lookup */
+		index_lookup[a] = -1;
+	}
+
+	qsort(topo_pairs, totvert, sizeof(MirrTopoVert_t), mirrtopo_vert_sort);
+
+	last = 0;
+
+	/* Get the pairs out of the sorted hashes, note, totvert+1 means we can use the previous 2,
+	 * but you cant ever access the last 'a' index of MirrTopoPairs */
+	if (em) {
+		BMVert **vtable = em->bm->vtable;
+		for (a = 1; a <= totvert; a++) {
+			/* printf("I %d %ld %d\n", (a - last), MirrTopoPairs[a].hash, MirrTopoPairs[a].v_indexs); */
+			if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) {
+				const int match_count = a - last;
+				if (match_count == 2) {
+					const int j = topo_pairs[a - 1].v_index, k = topo_pairs[a - 2].v_index;
+					index_lookup[j] = (intptr_t)vtable[k];
+					index_lookup[k] = (intptr_t)vtable[j];
+				}
+				else if (match_count == 1) {
+					/* Center vertex. */
+					const int j = topo_pairs[a - 1].v_index;
+					index_lookup[j] = (intptr_t)vtable[j];
+				}
+				last = a;
+			}
+		}
+	}
+	else {
+		/* same as above, for mesh */
+		for (a = 1; a <= totvert; a++) {
+			if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) {
+				const int match_count = a - last;
+				if (match_count == 2) {
+					const int j = topo_pairs[a - 1].v_index, k = topo_pairs[a - 2].v_index;
+					index_lookup[j] = k;
+					index_lookup[k] = j;
+				}
+				else if (match_count == 1) {
+					/* Center vertex. */
+					const int j = topo_pairs[a - 1].v_index;
+					index_lookup[j] = j;
+				}
+				last = a;
+			}
+		}
+	}
+
+	MEM_freeN(topo_pairs);
+	topo_pairs = NULL;
+
+	MEM_freeN(topo_hash);
+	MEM_freeN(topo_hash_prev);
+
+	mesh_topo_store->index_lookup  = index_lookup;
+	mesh_topo_store->prev_vert_tot = totvert;
+	mesh_topo_store->prev_edge_tot = totedge;
+}
+
+void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store)
+{
+	if (mesh_topo_store->index_lookup) {
+		MEM_freeN(mesh_topo_store->index_lookup);
+	}
+	mesh_topo_store->index_lookup  = NULL;
+	mesh_topo_store->prev_vert_tot = -1;
+	mesh_topo_store->prev_edge_tot = -1;
+}
+
+/** \} */
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index b66821c4e378c254ce4dbe2fb53738b94c45ef9b..d3d29b611821ea67959e69c064d45eb42e258157 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -46,8 +46,6 @@
 #include "BLI_math.h"
 #include "BLI_blenlib.h"
 
-
-#include "BLI_kdtree.h"
 #include "BKE_context.h"
 #include "BKE_depsgraph.h"
 #include "BKE_deform.h"
@@ -554,12 +552,10 @@ int join_mesh_exec(bContext *C, wmOperator *op)
 		if (ma)
 			id_us_min(&ma->id);
 	}
-	if (ob->mat) MEM_freeN(ob->mat);
-	if (ob->matbits) MEM_freeN(ob->matbits);
-	if (me->mat) MEM_freeN(me->mat);
-	ob->mat = me->mat = NULL;
-	ob->matbits = NULL;
-	
+	MEM_SAFE_FREE(ob->mat);
+	MEM_SAFE_FREE(ob->matbits);
+	MEM_SAFE_FREE(me->mat);
+
 	if (totcol) {
 		me->mat = matar;
 		ob->mat = MEM_callocN(sizeof(*ob->mat) * totcol, "join obmatar");
@@ -671,84 +667,6 @@ int join_mesh_shapes_exec(bContext *C, wmOperator *op)
 	return OPERATOR_FINISHED;
 }
 
-/* -------------------------------------------------------------------- */
-/* Mesh Mirror (Spatial) */
-
-/** \name Mesh Spatial Mirror API
- * \{ */
-
-#define KD_THRESH      0.00002f
-
-static struct { void *tree; } MirrKdStore = {NULL};
-
-/* mode is 's' start, or 'e' end, or 'u' use */
-/* if end, ob can be NULL */
-int ED_mesh_mirror_spatial_table(Object *ob, BMEditMesh *em, DerivedMesh *dm, const float co[3], char mode)
-{
-	if (mode == 'u') {        /* use table */
-		if (MirrKdStore.tree == NULL)
-			ED_mesh_mirror_spatial_table(ob, em, dm, NULL, 's');
-
-		if (MirrKdStore.tree) {
-			KDTreeNearest nearest;
-			const int i = BLI_kdtree_find_nearest(MirrKdStore.tree, co, &nearest);
-
-			if (i != -1) {
-				if (nearest.dist < KD_THRESH) {
-					return i;
-				}
-			}
-		}
-		return -1;
-	}
-	else if (mode == 's') {   /* start table */
-		Mesh *me = ob->data;
-		const bool use_em = (!dm && em && me->edit_btmesh == em);
-		const int totvert = use_em ? em->bm->totvert : dm ? dm->getNumVerts(dm) : me->totvert;
-
-		if (MirrKdStore.tree) /* happens when entering this call without ending it */
-			ED_mesh_mirror_spatial_table(ob, em, dm, co, 'e');
-
-		MirrKdStore.tree = BLI_kdtree_new(totvert);
-
-		if (use_em) {
-			BMVert *eve;
-			BMIter iter;
-			int i;
-
-			/* this needs to be valid for index lookups later (callers need) */
-			BM_mesh_elem_table_ensure(em->bm, BM_VERT);
-
-			BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
-				BLI_kdtree_insert(MirrKdStore.tree, i, eve->co);
-			}
-		}
-		else {
-			MVert *mvert = dm ? dm->getVertArray(dm) : me->mvert;
-			int i;
-			
-			for (i = 0; i < totvert; i++, mvert++) {
-				BLI_kdtree_insert(MirrKdStore.tree, i, mvert->co);
-			}
-		}
-
-		BLI_kdtree_balance(MirrKdStore.tree);
-	}
-	else if (mode == 'e') { /* end table */
-		if (MirrKdStore.tree) {
-			BLI_kdtree_free(MirrKdStore.tree);
-			MirrKdStore.tree = NULL;
-		}
-	}
-	else {
-		BLI_assert(0);
-	}
-
-	return 0;
-}
-
-/** \} */
-
 
 /* -------------------------------------------------------------------- */
 /* Mesh Mirror (Topology) */
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index 32f0f1f9bec0ec351982ecb0656bbb623e4a348e..add2ab9865212f7ffa614b7d9ab4ac30cc9f3f47 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -564,7 +564,7 @@ void ED_object_editmode_enter(bContext *C, int flag)
 
 		const bool use_key_index = mesh_needs_keyindex(ob->data);
 
-		EDBM_mesh_make(scene->toolsettings, ob, use_key_index);
+		EDBM_mesh_make(ob, scene->toolsettings->selectmode, use_key_index);
 
 		em = BKE_editmesh_from_object(ob);
 		if (LIKELY(em)) {
diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c
index 42e3a4a6837aa1024713f293872e08a442cbe9f2..e9203fa1972f1fd87ba417fc27919f93b49a0c19 100644
--- a/source/blender/editors/object/object_hook.c
+++ b/source/blender/editors/object/object_hook.c
@@ -316,7 +316,7 @@ static bool object_hook_index_array(Scene *scene, Object *obedit,
 			BMEditMesh *em;
 
 			EDBM_mesh_load(obedit);
-			EDBM_mesh_make(scene->toolsettings, obedit, true);
+			EDBM_mesh_make(obedit, scene->toolsettings->selectmode, true);
 
 			DAG_id_tag_update(obedit->data, 0);
 
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index f8c80f2a9333fcf2e7f2504151d180aedf383e65..83d67cea2f09c155b3c64ba1327473c2f8de9d7c 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -140,7 +140,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
 		BMEditMesh *em;
 
 		EDBM_mesh_load(obedit);
-		EDBM_mesh_make(scene->toolsettings, obedit, true);
+		EDBM_mesh_make(obedit, scene->toolsettings->selectmode, true);
 
 		DAG_id_tag_update(obedit->data, 0);
 
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index c62ed74eaff160d4ba5a9f38390f77c731ca68ae..c6c20182ac32947ec85ddf70d7e8d0b22301509e 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -1187,7 +1187,7 @@ static int *getSurroundingVerts(Mesh *me, int vert, int *count)
 				}
 
 				/* Append a and b verts to array, if not yet present. */
-				k = BLI_array_count(verts);
+				k = BLI_array_len(verts);
 				/* XXX Maybe a == b is enough? */
 				while (k-- && !(a == b && a == -1)) {
 					if (verts[k] == a)
@@ -1209,7 +1209,7 @@ static int *getSurroundingVerts(Mesh *me, int vert, int *count)
 	}
 
 	/* Do not free the array! */
-	*count = BLI_array_count(verts);
+	*count = BLI_array_len(verts);
 	return verts;
 }
 
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c
index 58b4c0fe2220dc51e4624a59e8b16a5365db9aaa..c27570aabc5c541d468b437071bb92baa37929a6 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.c
@@ -521,10 +521,8 @@ static void render_image_update_pass_and_layer(RenderJob *rj, RenderResult *rr,
 			int layer = BLI_findstringindex(&main_rr->layers,
 			                                (char *)rr->renlay->name,
 			                                offsetof(RenderLayer, name));
-			if (layer != rj->last_layer) {
-				sima->iuser.layer = layer;
-				rj->last_layer = layer;
-			}
+			sima->iuser.layer = layer;
+			rj->last_layer = layer;
 		}
 
 		iuser->pass = sima->iuser.pass;
@@ -621,7 +619,21 @@ static void render_image_restore_layer(RenderJob *rj)
 				if (sa == rj->sa) {
 					if (sa->spacetype == SPACE_IMAGE) {
 						SpaceImage *sima = sa->spacedata.first;
-						sima->iuser.layer = rj->orig_layer;
+
+						if (RE_HasSingleLayer(rj->re)) {
+							/* For single layer renders keep the active layer
+							 * visible, or show the compositing result. */
+							RenderResult *rr = RE_AcquireResultRead(rj->re);
+							if(RE_HasCombinedLayer(rr)) {
+								sima->iuser.layer = 0;
+							}
+							RE_ReleaseResult(rj->re);
+						}
+						else {
+							/* For multiple layer render, set back the layer
+							 * that was set at the start of rendering. */
+							sima->iuser.layer = rj->orig_layer;
+						}
 					}
 					return;
 				}
diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c
index 5ef9d4a64999d6b4fa0ebe7cd4efb4f6a542d1b4..e39750227c065ccea679b0ddc33a14f3de365c67 100644
--- a/source/blender/editors/sculpt_paint/sculpt_uv.c
+++ b/source/blender/editors/sculpt_paint/sculpt_uv.c
@@ -173,7 +173,7 @@ static int uv_sculpt_brush_poll_do(bContext *C, const bool check_region)
 	}
 
 	em = BKE_editmesh_from_object(obedit);
-	ret = EDBM_mtexpoly_check(em);
+	ret = EDBM_uv_check(em);
 
 	if (ret) {
 		ARegion *ar = CTX_wm_region(C);
@@ -650,9 +650,9 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm
 		/* we need to find the active island here */
 		if (do_island_optimization) {
 			UvElement *element;
-			NearestHit hit;
+			UvNearestHit hit = UV_NEAREST_HIT_INIT;
 			Image *ima = CTX_data_edit_image(C);
-			uv_find_nearest_vert(scene, ima, em, co, NULL, &hit);
+			uv_find_nearest_vert(scene, ima, em, co, 0.0f, &hit);
 
 			element = BM_uv_element_get(data->elementMap, hit.efa, hit.l);
 			island_index = element->island;
diff --git a/source/blender/editors/space_image/image_edit.c b/source/blender/editors/space_image/image_edit.c
index 8f2f65954089fc6f5399513cd2a103d5735d014d..9d7944a25d3ac4312c9b7a4ba10cbb0ccd755186 100644
--- a/source/blender/editors/space_image/image_edit.c
+++ b/source/blender/editors/space_image/image_edit.c
@@ -365,7 +365,7 @@ bool ED_space_image_show_uvedit(SpaceImage *sima, Object *obedit)
 		struct BMEditMesh *em = BKE_editmesh_from_object(obedit);
 		bool ret;
 
-		ret = EDBM_mtexpoly_check(em);
+		ret = EDBM_uv_check(em);
 
 		return ret;
 	}
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index ba67eb4683f48a796386312339f2e7d28b62ea7c..bac3b9f8df7000b9662d1db0ab6583fa478e7f53 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -434,12 +434,9 @@ static void image_refresh(const bContext *C, ScrArea *sa)
 		}
 		else {
 			/* old shading system, we set texface */
-			MTexPoly *tf;
-			
-			if (em && EDBM_mtexpoly_check(em)) {
-				tf = EDBM_mtexpoly_active_get(em, NULL, sloppy, selected);
-
-				if (tf) {
+			if (em && EDBM_uv_check(em)) {
+				MTexPoly *tf;
+				if (EDBM_uv_active_face_get(em, sloppy, selected, &tf)) {
 					/* don't need to check for pin here, see above */
 					sima->image = tf->tpage;
 					
diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c
index 5d0877a1eff1ed9d6d9845d477449798aca15ab0..508a16926e67de8b86d69c40c19ebf47ba8d2a02 100644
--- a/source/blender/editors/space_node/node_templates.c
+++ b/source/blender/editors/space_node/node_templates.c
@@ -482,10 +482,10 @@ static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname)
 	}
 	NODE_TYPES_END
 
-	qsort(sorted_ntypes, BLI_array_count(sorted_ntypes), sizeof(bNodeType *), ui_node_item_name_compare);
+	qsort(sorted_ntypes, BLI_array_len(sorted_ntypes), sizeof(bNodeType *), ui_node_item_name_compare);
 
 	/* generate UI */
-	for (int j = 0; j < BLI_array_count(sorted_ntypes); j++) {
+	for (int j = 0; j < BLI_array_len(sorted_ntypes); j++) {
 		bNodeType *ntype = sorted_ntypes[j];
 		NodeLinkItem *items;
 		int totitems;
diff --git a/source/blender/editors/space_view3d/view3d_camera_control.c b/source/blender/editors/space_view3d/view3d_camera_control.c
index f717f1c0a4353832b3c8941891d7f91b21790c0c..e27b3fe13f9857e0987d31c6f98037adab419a96 100644
--- a/source/blender/editors/space_view3d/view3d_camera_control.c
+++ b/source/blender/editors/space_view3d/view3d_camera_control.c
@@ -31,10 +31,10 @@
  *
  * Typical view-control usage:
  *
- * - acquire a view-control (#ED_view3d_control_acquire).
+ * - acquire a view-control (#ED_view3d_cameracontrol_acquire).
  * - modify ``rv3d->ofs``, ``rv3d->viewquat``.
- * - update the view data (#ED_view3d_control_acquire) - within a loop which draws the viewport.
- * - finish and release the view-control (#ED_view3d_control_release),
+ * - update the view data (#ED_view3d_cameracontrol_acquire) - within a loop which draws the viewport.
+ * - finish and release the view-control (#ED_view3d_cameracontrol_release),
  *   either keeping the current view or restoring the initial view.
  *
  * Notes:
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index 1cdbd4da1c4162a3ea27845589144b82432e7155..1f9f941a507bf609a2fcdcb02bdf47c922b1b499 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -246,9 +246,10 @@ typedef struct LassoSelectUserData {
 	bool is_changed;
 } LassoSelectUserData;
 
-static void view3d_userdata_lassoselect_init(LassoSelectUserData *r_data,
-                                             ViewContext *vc, const rcti *rect, const int (*mcords)[2],
-                                             const int moves, const bool select)
+static void view3d_userdata_lassoselect_init(
+        LassoSelectUserData *r_data,
+        ViewContext *vc, const rcti *rect, const int (*mcords)[2],
+        const int moves, const bool select)
 {
 	r_data->vc = vc;
 
@@ -323,7 +324,8 @@ static bool edge_inside_rect(const rctf *rect, const float v1[2], const float v2
 	return 1;
 }
 
-static void do_lasso_select_pose__doSelectBone(void *userData, struct bPoseChannel *pchan, const float screen_co_a[2], const float screen_co_b[2])
+static void do_lasso_select_pose__doSelectBone(
+        void *userData, struct bPoseChannel *pchan, const float screen_co_a[2], const float screen_co_b[2])
 {
 	LassoSelectUserData *data = userData;
 	bArmature *arm = data->vc->obact->data;
@@ -410,8 +412,9 @@ static void object_deselect_all_visible(Scene *scene, View3D *v3d)
 	}
 }
 
-static void do_lasso_select_objects(ViewContext *vc, const int mcords[][2], const short moves,
-                                    const bool extend, const bool select)
+static void do_lasso_select_objects(
+        ViewContext *vc, const int mcords[][2], const short moves,
+        const bool extend, const bool select)
 {
 	Base *base;
 	
@@ -444,7 +447,8 @@ static void do_lasso_select_mesh__doSelectVert(void *userData, BMVert *eve, cons
 		BM_vert_select_set(data->vc->em->bm, eve, data->select);
 	}
 }
-static void do_lasso_select_mesh__doSelectEdge(void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index)
+static void do_lasso_select_mesh__doSelectEdge(
+        void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index)
 {
 	LassoSelectUserData *data = userData;
 
@@ -536,7 +540,8 @@ static void do_lasso_select_mesh(ViewContext *vc, const int mcords[][2], short m
 	EDBM_selectmode_flush(vc->em);
 }
 
-static void do_lasso_select_curve__doSelect(void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2])
+static void do_lasso_select_curve__doSelect(
+        void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2])
 {
 	LassoSelectUserData *data = userData;
 	Object *obedit = data->vc->obedit;
@@ -611,7 +616,8 @@ static void do_lasso_select_lattice(ViewContext *vc, const int mcords[][2], shor
 	lattice_foreachScreenVert(vc, do_lasso_select_lattice__doSelect, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
 }
 
-static void do_lasso_select_armature__doSelectBone(void *userData, struct EditBone *ebone, const float screen_co_a[2], const float screen_co_b[2])
+static void do_lasso_select_armature__doSelectBone(
+        void *userData, struct EditBone *ebone, const float screen_co_a[2], const float screen_co_b[2])
 {
 	LassoSelectUserData *data = userData;
 	bArmature *arm = data->vc->obedit->data;
@@ -717,7 +723,8 @@ static void do_lasso_select_meta(ViewContext *vc, const int mcords[][2], short m
 	mball_foreachScreenElem(vc, do_lasso_select_mball__doSelectElem, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
 }
 
-static void do_lasso_select_meshobject__doSelectVert(void *userData, MVert *mv, const float screen_co[2], int UNUSED(index))
+static void do_lasso_select_meshobject__doSelectVert(
+        void *userData, MVert *mv, const float screen_co[2], int UNUSED(index))
 {
 	LassoSelectUserData *data = userData;
 
@@ -822,9 +829,10 @@ static void do_lasso_select_node(int mcords[][2], short moves, const bool select
 }
 #endif
 
-static void view3d_lasso_select(bContext *C, ViewContext *vc,
-                                const int mcords[][2], short moves,
-                                bool extend, bool select)
+static void view3d_lasso_select(
+        bContext *C, ViewContext *vc,
+        const int mcords[][2], short moves,
+        bool extend, bool select)
 {
 	Object *ob = CTX_data_active_object(C);
 
@@ -928,7 +936,8 @@ typedef struct SelMenuItemF {
 static SelMenuItemF object_mouse_select_menu_data[SEL_MENU_SIZE];
 
 /* special (crappy) operator only for menu select */
-static const EnumPropertyItem *object_select_menu_enum_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
+static const EnumPropertyItem *object_select_menu_enum_itemf(
+        bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
 {
 	EnumPropertyItem *item = NULL, item_tmp = {0};
 	int totitem = 0;
@@ -1403,8 +1412,9 @@ static bool ed_object_select_pick(
 			while (base) {
 				if (BASE_SELECTABLE(v3d, base)) {
 					float screen_co[2];
-					if (ED_view3d_project_float_global(ar, base->object->obmat[3], screen_co,
-					                                   V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
+					if (ED_view3d_project_float_global(
+					            ar, base->object->obmat[3], screen_co,
+					            V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
 					{
 						float dist_temp = len_manhattan_v2v2(mval_fl, screen_co);
 						if (base == BASACT) dist_temp += 10.0f;
@@ -1590,8 +1600,9 @@ typedef struct BoxSelectUserData {
 	bool is_changed;
 } BoxSelectUserData;
 
-static void view3d_userdata_boxselect_init(BoxSelectUserData *r_data,
-                                           ViewContext *vc, const rcti *rect, const bool select)
+static void view3d_userdata_boxselect_init(
+        BoxSelectUserData *r_data,
+        ViewContext *vc, const rcti *rect, const bool select)
 {
 	r_data->vc = vc;
 
@@ -1704,7 +1715,8 @@ static int do_paintvert_box_select(ViewContext *vc, rcti *rect, bool select, boo
 	return OPERATOR_FINISHED;
 }
 
-static void do_nurbs_box_select__doSelect(void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2])
+static void do_nurbs_box_select__doSelect(
+        void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2])
 {
 	BoxSelectUserData *data = userData;
 	Object *obedit = data->vc->obedit;
@@ -1782,7 +1794,8 @@ static void do_mesh_box_select__doSelectVert(void *userData, BMVert *eve, const
 		BM_vert_select_set(data->vc->em->bm, eve, data->select);
 	}
 }
-static void do_mesh_box_select__doSelectEdge(void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index)
+static void do_mesh_box_select__doSelectEdge(
+        void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index)
 {
 	BoxSelectUserData *data = userData;
 
@@ -2338,8 +2351,9 @@ typedef struct CircleSelectUserData {
 	bool is_changed;
 } CircleSelectUserData;
 
-static void view3d_userdata_circleselect_init(CircleSelectUserData *r_data,
-                                              ViewContext *vc, const bool select, const int mval[2], const float rad)
+static void view3d_userdata_circleselect_init(
+        CircleSelectUserData *r_data,
+        ViewContext *vc, const bool select, const int mval[2], const float rad)
 {
 	r_data->vc = vc;
 	r_data->select = select;
@@ -2362,7 +2376,8 @@ static void mesh_circle_doSelectVert(void *userData, BMVert *eve, const float sc
 		BM_vert_select_set(data->vc->em->bm, eve, data->select);
 	}
 }
-static void mesh_circle_doSelectEdge(void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int UNUSED(index))
+static void mesh_circle_doSelectEdge(
+        void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int UNUSED(index))
 {
 	CircleSelectUserData *data = userData;
 
@@ -2439,7 +2454,8 @@ static void paint_facesel_circle_select(ViewContext *vc, const bool select, cons
 	}
 }
 
-static void paint_vertsel_circle_select_doSelectVert(void *userData, MVert *mv, const float screen_co[2], int UNUSED(index))
+static void paint_vertsel_circle_select_doSelectVert(
+        void *userData, MVert *mv, const float screen_co[2], int UNUSED(index))
 {
 	CircleSelectUserData *data = userData;
 
@@ -2480,7 +2496,8 @@ static void paint_vertsel_circle_select(ViewContext *vc, const bool select, cons
 }
 
 
-static void nurbscurve_circle_doSelect(void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2])
+static void nurbscurve_circle_doSelect(
+        void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2])
 {
 	CircleSelectUserData *data = userData;
 	Object *obedit = data->vc->obedit;
@@ -2554,7 +2571,8 @@ static bool pchan_circle_doSelectJoint(void *userData, bPoseChannel *pchan, cons
 	}
 	return 0;
 }
-static void do_circle_select_pose__doSelectBone(void *userData, struct bPoseChannel *pchan, const float screen_co_a[2], const float screen_co_b[2])
+static void do_circle_select_pose__doSelectBone(
+        void *userData, struct bPoseChannel *pchan, const float screen_co_a[2], const float screen_co_b[2])
 {
 	CircleSelectUserData *data = userData;
 	bArmature *arm = data->vc->obact->data;
@@ -2640,7 +2658,8 @@ static bool armature_circle_doSelectJoint(void *userData, EditBone *ebone, const
 	}
 	return 0;
 }
-static void do_circle_select_armature__doSelectBone(void *userData, struct EditBone *ebone, const float screen_co_a[2], const float screen_co_b[2])
+static void do_circle_select_armature__doSelectBone(
+        void *userData, struct EditBone *ebone, const float screen_co_a[2], const float screen_co_b[2])
 {
 	CircleSelectUserData *data = userData;
 	bArmature *arm = data->vc->obedit->data;
@@ -2761,8 +2780,9 @@ static bool object_circle_select(ViewContext *vc, const bool select, const int m
 	for (base = FIRSTBASE; base; base = base->next) {
 		if (BASE_SELECTABLE(vc->v3d, base) && ((base->flag & SELECT) != select_flag)) {
 			float screen_co[2];
-			if (ED_view3d_project_float_global(vc->ar, base->object->obmat[3], screen_co,
-			                                   V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
+			if (ED_view3d_project_float_global(
+			            vc->ar, base->object->obmat[3], screen_co,
+			            V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
 			{
 				if (len_squared_v2v2(mval_fl, screen_co) <= radius_squared) {
 					ED_base_object_select(base, select ? BA_SELECT : BA_DESELECT);
diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c
index 5fd29971fa551ca1f8403b89f076e8b03873aebd..193a29928ef3555ddc53aafabd26b02216b7acec 100644
--- a/source/blender/editors/transform/transform_manipulator.c
+++ b/source/blender/editors/transform/transform_manipulator.c
@@ -720,7 +720,7 @@ static float screen_aligned(RegionView3D *rv3d, float mat[4][4])
  * \param start: Starting segment (based on \a nrings).
  * \param end: End segment.
  * \param nsides: Number of points in ring.
- * \param nrigns: Number of rings.
+ * \param nrings: Number of rings.
  */
 static void partial_doughnut(float radring, float radhole, int start, int end, int nsides, int nrings)
 {
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index eafb3650d3619c0c51a33c693e0eac65f83812e8..d248d0df4e32eff1eb3a3acadcedbf12f9767cb5 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -59,6 +59,10 @@
 
 #include "transform.h"
 
+/* -------------------------------------------------------------------- */
+/** Internal Data Types
+ * \{ */
+
 enum eViewProj {
 	VIEW_PROJ_NONE = -1,
 	VIEW_PROJ_ORTHO = 0,
@@ -132,10 +136,8 @@ struct SnapObjectContext {
 
 /** \} */
 
-
 /* -------------------------------------------------------------------- */
-
-/** Common utilities
+/** Common Utilities
  * \{ */
 
 
@@ -256,9 +258,7 @@ static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt);
 
 /** \} */
 
-
 /* -------------------------------------------------------------------- */
-
 /** \name Ray Cast Funcs
  * \{ */
 
@@ -785,7 +785,6 @@ static void raycast_obj_cb(SnapObjectContext *sctx, bool is_obedit, Object *ob,
  * Walks through all objects in the scene to find the `hit` on object surface.
  *
  * \param sctx: Snap context to store data.
- * \param snapdata: struct generated in `set_snapdata`.
  * \param snap_select : from enum eSnapSelect.
  * \param use_object_edit_cage : Uses the coordinates of BMesh(if any) to do the snapping.
  * \param obj_list: List with objects to snap (created in `create_object_list`).
@@ -842,9 +841,7 @@ static bool raycastObjects(
 
 /** \} */
 
-
 /* -------------------------------------------------------------------- */
-
 /** Snap Nearest utilities
  * \{ */
 
@@ -1154,9 +1151,7 @@ static float dist_squared_to_projected_aabb_simple(
 
 /** \} */
 
-
 /* -------------------------------------------------------------------- */
-
 /** Walk DFS
  * \{ */
 
@@ -1252,7 +1247,6 @@ static bool cb_nearest_walk_order(const BVHTreeAxisRange *UNUSED(bounds), char a
 /** \} */
 
 /* -------------------------------------------------------------------- */
-
 /** \name Internal Object Snapping API
  * \{ */
 
@@ -2076,9 +2070,7 @@ static bool snapObjectsRay(
 
 /** \} */
 
-
 /* -------------------------------------------------------------------- */
-
 /** \name Public Object Snapping API
  * \{ */
 
diff --git a/source/blender/editors/util/editmode_undo.c b/source/blender/editors/util/editmode_undo.c
index 2dcfe949f3f27f54f4fd30b0141a8effe24b7196..fa697a0f006dfd73c6d17cebbbf274ea92aeadbd 100644
--- a/source/blender/editors/util/editmode_undo.c
+++ b/source/blender/editors/util/editmode_undo.c
@@ -181,9 +181,6 @@ void undo_editmode_push(
 	}
 }
 
-/** \} */
-
-
 /* helper to remove clean other objects from undo stack */
 static void undo_clean_stack(bContext *C)
 {
diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c
index fecacd079970dee2a1a1242c1d6b15ad483a8f51..7b793697077350f6b594e2e621feb32d32942243 100644
--- a/source/blender/editors/uvedit/uvedit_draw.c
+++ b/source/blender/editors/uvedit/uvedit_draw.c
@@ -570,7 +570,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
 	const int cd_loop_uv_offset  = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
 	const int cd_poly_tex_offset = CustomData_get_offset(&bm->pdata, CD_MTEXPOLY);
 
-	activetf = EDBM_mtexpoly_active_get(em, &efa_act, false, false); /* will be set to NULL if hidden */
+	efa_act = EDBM_uv_active_face_get(em, false, false, &activetf); /* will be set to NULL if hidden */
 #ifndef USE_EDBM_LOOPTRIS
 	activef = BM_mesh_active_face_get(bm, false, false);
 #endif
@@ -967,7 +967,7 @@ static void draw_uv_shadows_get(SpaceImage *sima, Object *ob, Object *obedit, bo
 	if ((sima->mode == SI_MODE_PAINT) && obedit && obedit->type == OB_MESH) {
 		struct BMEditMesh *em = BKE_editmesh_from_object(obedit);
 		
-		*show_shadow = EDBM_mtexpoly_check(em);
+		*show_shadow = EDBM_uv_check(em);
 	}
 	
 	*show_texpaint = (ob && ob->type == OB_MESH && ob->mode == OB_MODE_TEXTURE_PAINT);
diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h
index e028c08091cc366cbbd9059ce9307fee50451955..b5ff46e921997a5e5b39ca314b9ee19a2999b2d7 100644
--- a/source/blender/editors/uvedit/uvedit_intern.h
+++ b/source/blender/editors/uvedit/uvedit_intern.h
@@ -51,18 +51,31 @@ void  uv_poly_center(struct BMFace *f, float r_cent[2], const int cd_loop_uv_off
 
 /* find nearest */
 
-typedef struct NearestHit {
+typedef struct UvNearestHit {
+	/** Always set if we have a hit. */
 	struct BMFace *efa;
 	struct MTexPoly *tf;
 	struct BMLoop *l;
 	struct MLoopUV *luv, *luv_next;
-	int lindex;  /* index of loop within face */
-} NearestHit;
+	/** Index of loop within face. */
+	int lindex;
+	/** Needs to be set before calling nearest functions. */
+	float dist_sq;
+} UvNearestHit;
 
-void uv_find_nearest_vert(struct Scene *scene, struct Image *ima, struct BMEditMesh *em,
-                          const float co[2], const float penalty[2], struct NearestHit *hit);
-void uv_find_nearest_edge(struct Scene *scene, struct Image *ima, struct BMEditMesh *em,
-                          const float co[2], struct NearestHit *hit);
+#define UV_NEAREST_HIT_INIT { .dist_sq = FLT_MAX, }
+
+bool uv_find_nearest_vert(
+        struct Scene *scene, struct Image *ima, struct BMEditMesh *em,
+        const float co[2], const float penalty_dist, struct UvNearestHit *hit_final);
+
+bool uv_find_nearest_edge(
+        struct Scene *scene, struct Image *ima, struct BMEditMesh *em,
+        const float co[2], struct UvNearestHit *hit_final);
+
+bool uv_find_nearest_face(
+        struct Scene *scene, struct Image *ima, struct BMEditMesh *em,
+        const float co[2], struct UvNearestHit *hit_final);
 
 /* utility tool functions */
 
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index bf5a06f0a1c9d78bc82d5271b46ec933a1d42903..852c4ae5958bee407bfb5c627577ac8ad87fa13c 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -29,7 +29,6 @@
  *  \ingroup eduv
  */
 
-
 #include <stdlib.h>
 #include <string.h>
 #include <math.h>
@@ -92,7 +91,9 @@ static void uv_select_all_perform(Scene *scene, Image *ima, BMEditMesh *em, int
 static void uv_select_flush_from_tag_face(SpaceImage *sima, Scene *scene, Object *obedit, const bool select);
 static void uv_select_flush_from_tag_loop(SpaceImage *sima, Scene *scene, Object *obedit, const bool select);
 
-/************************* state testing ************************/
+/* -------------------------------------------------------------------- */
+/** \name State Testing
+ * \{ */
 
 bool ED_uvedit_test(Object *obedit)
 {
@@ -106,7 +107,7 @@ bool ED_uvedit_test(Object *obedit)
 		return 0;
 
 	em = BKE_editmesh_from_object(obedit);
-	ret = EDBM_mtexpoly_check(em);
+	ret = EDBM_uv_check(em);
 	
 	return ret;
 }
@@ -133,15 +134,21 @@ static int UNUSED_FUNCTION(ED_operator_uvmap_mesh) (bContext *C)
 
 	return 0;
 }
-/**************************** object active image *****************************/
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Active Image
+ * \{ */
 
 static bool is_image_texture_node(bNode *node)
 {
 	return ELEM(node->type, SH_NODE_TEX_IMAGE, SH_NODE_TEX_ENVIRONMENT);
 }
 
-bool ED_object_get_active_image(Object *ob, int mat_nr,
-                                Image **r_ima, ImageUser **r_iuser, bNode **r_node, bNodeTree **r_ntree)
+bool ED_object_get_active_image(
+        Object *ob, int mat_nr,
+        Image **r_ima, ImageUser **r_iuser, bNode **r_node, bNodeTree **r_ntree)
 {
 	Material *ma = give_current_material(ob, mat_nr);
 	bNodeTree *ntree = (ma && ma->use_nodes) ? ma->nodetree : NULL;
@@ -174,7 +181,11 @@ void ED_object_assign_active_image(Main *bmain, Object *ob, int mat_nr, Image *i
 	}
 }
 
-/************************* assign image ************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Assign Image
+ * \{ */
 
 //#define USE_SWITCH_ASPECT
 
@@ -316,7 +327,11 @@ static bool uvedit_set_tile(Object *obedit, Image *ima, int curtile)
 	return true;
 }
 
-/*********************** space conversion *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Space Conversion
+ * \{ */
 
 static void uvedit_pixel_to_float(SpaceImage *sima, float *dist, float pixeldist)
 {
@@ -334,7 +349,11 @@ static void uvedit_pixel_to_float(SpaceImage *sima, float *dist, float pixeldist
 	dist[1] = pixeldist / height;
 }
 
-/*************** visibility and selection utilities **************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Visibility and Selection Utilities
+ * \{ */
 
 static void uvedit_vertex_select_tagged(BMEditMesh *em, Scene *scene, bool select, int cd_loop_uv_offset)
 {
@@ -371,8 +390,9 @@ bool uvedit_face_visible_test(Scene *scene, Image *ima, BMFace *efa, MTexPoly *t
 		return uvedit_face_visible_nolocal(scene, efa);
 }
 
-bool uvedit_face_select_test(Scene *scene, BMFace *efa,
-                             const int cd_loop_uv_offset)
+bool uvedit_face_select_test(
+        Scene *scene, BMFace *efa,
+        const int cd_loop_uv_offset)
 {
 	ToolSettings *ts = scene->toolsettings;
 	if (ts->uv_flag & UV_SYNC_SELECTION) {
@@ -393,8 +413,9 @@ bool uvedit_face_select_test(Scene *scene, BMFace *efa,
 	}
 }
 
-bool uvedit_face_select_set(struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa, const bool select,
-                            const bool do_history, const int cd_loop_uv_offset)
+bool uvedit_face_select_set(
+        struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa, const bool select,
+        const bool do_history, const int cd_loop_uv_offset)
 {
 	if (select) {
 		return uvedit_face_select_enable(scene, em, efa, do_history, cd_loop_uv_offset);
@@ -404,8 +425,9 @@ bool uvedit_face_select_set(struct Scene *scene, struct BMEditMesh *em, struct B
 	}
 }
 
-bool uvedit_face_select_enable(Scene *scene, BMEditMesh *em, BMFace *efa, const bool do_history,
-                               const int cd_loop_uv_offset)
+bool uvedit_face_select_enable(
+        Scene *scene, BMEditMesh *em, BMFace *efa, const bool do_history,
+        const int cd_loop_uv_offset)
 {
 	ToolSettings *ts = scene->toolsettings;
 
@@ -431,8 +453,9 @@ bool uvedit_face_select_enable(Scene *scene, BMEditMesh *em, BMFace *efa, const
 	return false;
 }
 
-bool uvedit_face_select_disable(Scene *scene, BMEditMesh *em, BMFace *efa,
-                                const int cd_loop_uv_offset)
+bool uvedit_face_select_disable(
+        Scene *scene, BMEditMesh *em, BMFace *efa,
+        const int cd_loop_uv_offset)
 {
 	ToolSettings *ts = scene->toolsettings;
 
@@ -455,8 +478,9 @@ bool uvedit_face_select_disable(Scene *scene, BMEditMesh *em, BMFace *efa,
 	return false;
 }
 
-bool uvedit_edge_select_test(Scene *scene, BMLoop *l,
-                             const int cd_loop_uv_offset)
+bool uvedit_edge_select_test(
+        Scene *scene, BMLoop *l,
+        const int cd_loop_uv_offset)
 {
 	ToolSettings *ts = scene->toolsettings;
 
@@ -482,8 +506,9 @@ bool uvedit_edge_select_test(Scene *scene, BMLoop *l,
 	}
 }
 
-void uvedit_edge_select_set(BMEditMesh *em, Scene *scene, BMLoop *l, const bool select,
-                            const bool do_history, const int cd_loop_uv_offset)
+void uvedit_edge_select_set(
+        BMEditMesh *em, Scene *scene, BMLoop *l, const bool select,
+        const bool do_history, const int cd_loop_uv_offset)
 
 {
 	if (select) {
@@ -494,8 +519,9 @@ void uvedit_edge_select_set(BMEditMesh *em, Scene *scene, BMLoop *l, const bool
 	}
 }
 
-void uvedit_edge_select_enable(BMEditMesh *em, Scene *scene, BMLoop *l, const bool do_history,
-                               const int cd_loop_uv_offset)
+void uvedit_edge_select_enable(
+        BMEditMesh *em, Scene *scene, BMLoop *l, const bool do_history,
+        const int cd_loop_uv_offset)
 
 {
 	ToolSettings *ts = scene->toolsettings;
@@ -525,8 +551,9 @@ void uvedit_edge_select_enable(BMEditMesh *em, Scene *scene, BMLoop *l, const bo
 	}
 }
 
-void uvedit_edge_select_disable(BMEditMesh *em, Scene *scene, BMLoop *l,
-                                const int cd_loop_uv_offset)
+void uvedit_edge_select_disable(
+        BMEditMesh *em, Scene *scene, BMLoop *l,
+        const int cd_loop_uv_offset)
 
 {
 	ToolSettings *ts = scene->toolsettings;
@@ -552,8 +579,9 @@ void uvedit_edge_select_disable(BMEditMesh *em, Scene *scene, BMLoop *l,
 	}
 }
 
-bool uvedit_uv_select_test(Scene *scene, BMLoop *l,
-                           const int cd_loop_uv_offset)
+bool uvedit_uv_select_test(
+        Scene *scene, BMLoop *l,
+        const int cd_loop_uv_offset)
 {
 	ToolSettings *ts = scene->toolsettings;
 
@@ -569,8 +597,9 @@ bool uvedit_uv_select_test(Scene *scene, BMLoop *l,
 	}
 }
 
-void uvedit_uv_select_set(BMEditMesh *em, Scene *scene, BMLoop *l, const bool select,
-                          const bool do_history, const int cd_loop_uv_offset)
+void uvedit_uv_select_set(
+        BMEditMesh *em, Scene *scene, BMLoop *l, const bool select,
+        const bool do_history, const int cd_loop_uv_offset)
 {
 	if (select) {
 		uvedit_uv_select_enable(em, scene, l, do_history, cd_loop_uv_offset);
@@ -580,8 +609,9 @@ void uvedit_uv_select_set(BMEditMesh *em, Scene *scene, BMLoop *l, const bool se
 	}
 }
 
-void uvedit_uv_select_enable(BMEditMesh *em, Scene *scene, BMLoop *l,
-                             const bool do_history, const int cd_loop_uv_offset)
+void uvedit_uv_select_enable(
+        BMEditMesh *em, Scene *scene, BMLoop *l,
+        const bool do_history, const int cd_loop_uv_offset)
 {
 	ToolSettings *ts = scene->toolsettings;
 
@@ -601,8 +631,9 @@ void uvedit_uv_select_enable(BMEditMesh *em, Scene *scene, BMLoop *l,
 	}
 }
 
-void uvedit_uv_select_disable(BMEditMesh *em, Scene *scene, BMLoop *l,
-                              const int cd_loop_uv_offset)
+void uvedit_uv_select_disable(
+        BMEditMesh *em, Scene *scene, BMLoop *l,
+        const int cd_loop_uv_offset)
 {
 	ToolSettings *ts = scene->toolsettings;
 
@@ -618,7 +649,11 @@ void uvedit_uv_select_disable(BMEditMesh *em, Scene *scene, BMLoop *l,
 	}
 }
 
-/*********************** live unwrap utilities ***********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Live Unwrap Utilities
+ * \{ */
 
 void uvedit_live_unwrap_update(SpaceImage *sima, Scene *scene, Object *obedit)
 {
@@ -629,7 +664,12 @@ void uvedit_live_unwrap_update(SpaceImage *sima, Scene *scene, Object *obedit)
 	}
 }
 
-/*********************** geometric utilities ***********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Geometric Utilities
+ * \{ */
+
 void uv_poly_center(BMFace *f, float r_cent[2], const int cd_loop_uv_offset)
 {
 	BMLoop *l;
@@ -758,89 +798,104 @@ static bool uvedit_center(Scene *scene, Image *ima, Object *obedit, float cent[2
 	return changed;
 }
 
-/************************** find nearest ****************************/
+/** \} */
 
-void uv_find_nearest_edge(Scene *scene, Image *ima, BMEditMesh *em, const float co[2], NearestHit *hit)
+/* -------------------------------------------------------------------- */
+/** \name Find Nearest Elements
+ * \{ */
+
+bool uv_find_nearest_edge(
+        Scene *scene, Image *ima, BMEditMesh *em, const float co[2],
+        UvNearestHit *hit)
 {
 	MTexPoly *tf;
 	BMFace *efa;
 	BMLoop *l;
 	BMIter iter, liter;
 	MLoopUV *luv, *luv_next;
-	float mindist_squared, dist_squared;
 	int i;
+	bool found = false;
 
 	const int cd_loop_uv_offset  = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
 	const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
 
-	mindist_squared = 1e10f;
-	memset(hit, 0, sizeof(*hit));
-
 	BM_mesh_elem_index_ensure(em->bm, BM_VERT);
-	
+
 	BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
 		tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
-		if (!uvedit_face_visible_test(scene, ima, efa, tf))
+		if (!uvedit_face_visible_test(scene, ima, efa, tf)) {
 			continue;
-		
+		}
 		BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
 			luv      = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
 			luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
 
-			dist_squared = dist_squared_to_line_segment_v2(co, luv->uv, luv_next->uv);
+			const float dist_test_sq = dist_squared_to_line_segment_v2(co, luv->uv, luv_next->uv);
 
-			if (dist_squared < mindist_squared) {
+			if (dist_test_sq < hit->dist_sq) {
 				hit->tf = tf;
 				hit->efa = efa;
-				
+
 				hit->l = l;
 				hit->luv = luv;
 				hit->luv_next = luv_next;
 				hit->lindex = i;
 
-				mindist_squared = dist_squared;
+				hit->dist_sq = dist_test_sq;
+				found = true;
 			}
 		}
 	}
+	return found;
 }
 
-static void uv_find_nearest_face(Scene *scene, Image *ima, BMEditMesh *em, const float co[2], NearestHit *hit)
+bool uv_find_nearest_face(
+        Scene *scene, Image *ima, BMEditMesh *em, const float co[2],
+        UvNearestHit *hit_final)
 {
-	MTexPoly *tf;
-	BMFace *efa;
-	BMIter iter;
-	float mindist, dist, cent[2];
+	bool found = false;
 
 	const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
 	const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
 
-	mindist = 1e10f;
-	memset(hit, 0, sizeof(*hit));
+	/* this will fill in hit.vert1 and hit.vert2 */
+	float dist_sq_init = hit_final->dist_sq;
+	UvNearestHit hit = *hit_final;
+	if (uv_find_nearest_edge(scene, ima, em, co, &hit)) {
+		hit.dist_sq = dist_sq_init;
+		hit.l = NULL;
+		hit.luv = hit.luv_next = NULL;
 
-	/*this will fill in hit.vert1 and hit.vert2*/
-	uv_find_nearest_edge(scene, ima, em, co, hit);
-	hit->l = NULL;
-	hit->luv = hit->luv_next = NULL;
+		BMIter iter;
+		BMFace *efa;
 
-	BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
-		tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
-		if (!uvedit_face_visible_test(scene, ima, efa, tf))
-			continue;
+		BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+			MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
+			if (!uvedit_face_visible_test(scene, ima, efa, tf)) {
+				continue;
+			}
 
-		uv_poly_center(efa, cent, cd_loop_uv_offset);
+			float cent[2];
+			uv_poly_center(efa, cent, cd_loop_uv_offset);
 
-		dist = len_manhattan_v2v2(co, cent);
+			const float dist_test_sq = len_squared_v2v2(co, cent);
 
-		if (dist < mindist) {
-			hit->tf = tf;
-			hit->efa = efa;
-			mindist = dist;
+			if (dist_test_sq < hit.dist_sq) {
+				hit.efa = efa;
+				hit.dist_sq = dist_test_sq;
+				found = true;
+			}
 		}
 	}
+	if (found) {
+		*hit_final = hit;
+	}
+	return found;
 }
 
-static bool uv_nearest_between(const BMLoop *l, const float co[2],
-                               const int cd_loop_uv_offset)
+static bool uv_nearest_between(
+        const BMLoop *l, const float co[2],
+        const int cd_loop_uv_offset)
 {
 	const float *uv_prev = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset))->uv;
 	const float *uv_curr = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l,       cd_loop_uv_offset))->uv;
@@ -850,60 +905,74 @@ static bool uv_nearest_between(const BMLoop *l, const float co[2],
 	        (line_point_side_v2(uv_next, uv_curr, co) <= 0.0f));
 }
 
-void uv_find_nearest_vert(Scene *scene, Image *ima, BMEditMesh *em,
-                          float const co[2], const float penalty[2], NearestHit *hit)
+bool uv_find_nearest_vert(
+        Scene *scene, Image *ima, BMEditMesh *em,
+        float const co[2], const float penalty_dist, UvNearestHit *hit_final)
 {
-	BMFace *efa;
-	BMLoop *l;
-	BMIter iter, liter;
-	MTexPoly *tf;
-	MLoopUV *luv;
-	float mindist, dist;
-	int i;
+	bool found = false;
 
-	const int cd_loop_uv_offset  = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-	const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
+	/* this will fill in hit.vert1 and hit.vert2 */
+	float dist_sq_init = hit_final->dist_sq;
+	UvNearestHit hit = *hit_final;
+	if (uv_find_nearest_edge(scene, ima, em, co, &hit)) {
+		hit.dist_sq = dist_sq_init;
 
-	/*this will fill in hit.vert1 and hit.vert2*/
-	uv_find_nearest_edge(scene, ima, em, co, hit);
-	hit->l = NULL;
-	hit->luv = hit->luv_next = NULL;
+		hit.l = NULL;
+		hit.luv = hit.luv_next = NULL;
 
-	mindist = 1e10f;
-	memset(hit, 0, sizeof(*hit));
-	
-	BM_mesh_elem_index_ensure(em->bm, BM_VERT);
+		BMFace *efa;
+		BMIter iter;
 
-	BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
-		tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
-		if (!uvedit_face_visible_test(scene, ima, efa, tf))
-			continue;
+		BM_mesh_elem_index_ensure(em->bm, BM_VERT);
 
-		BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
-			luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-			if (penalty && uvedit_uv_select_test(scene, l, cd_loop_uv_offset))
-				dist = len_manhattan_v2v2(co, luv->uv) + len_manhattan_v2(penalty);
-			else
-				dist = len_manhattan_v2v2(co, luv->uv);
+		const int cd_loop_uv_offset  = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+		const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
 
-			if (dist <= mindist) {
-				if (dist == mindist) {
-					if (!uv_nearest_between(l, co, cd_loop_uv_offset)) {
-						continue;
-					}
+		BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+			MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
+			if (!uvedit_face_visible_test(scene, ima, efa, tf)) {
+				continue;
+			}
+
+			BMIter liter;
+			BMLoop *l;
+			int i;
+			BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
+				float dist_test_sq;
+				MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+				if (penalty_dist != 0.0f && uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+					dist_test_sq = len_v2v2(co, luv->uv) + penalty_dist;
+					dist_test_sq = SQUARE(dist_test_sq);
+				}
+				else {
+					dist_test_sq = len_squared_v2v2(co, luv->uv);
 				}
 
-				mindist = dist;
+				if (dist_test_sq <= hit.dist_sq) {
+					if (dist_test_sq == hit.dist_sq) {
+						if (!uv_nearest_between(l, co, cd_loop_uv_offset)) {
+							continue;
+						}
+					}
 
-				hit->l = l;
-				hit->luv = luv;
-				hit->luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
-				hit->tf = tf;
-				hit->efa = efa;
-				hit->lindex = i;
+					hit.dist_sq = dist_test_sq;
+
+					hit.l = l;
+					hit.luv = luv;
+					hit.luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
+					hit.efa = efa;
+					hit.lindex = i;
+					found = true;
+				}
 			}
 		}
 	}
+
+	if (found) {
+		*hit_final = hit;
+	}
+
+	return found;
 }
 
 bool ED_uvedit_nearest_uv(Scene *scene, Object *obedit, Image *ima, const float co[2], float r_uv[2])
@@ -944,7 +1013,11 @@ bool ED_uvedit_nearest_uv(Scene *scene, Object *obedit, Image *ima, const float
 	return found;
 }
 
-/*********************** loop select ***********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Loop Select
+ * \{ */
 
 static void uv_select_edgeloop_vertex_loop_flag(UvMapVert *first)
 {
@@ -1029,8 +1102,9 @@ static bool uv_select_edgeloop_edge_tag_faces(BMEditMesh *em, UvMapVert *first1,
 	return true;
 }
 
-static int uv_select_edgeloop(Scene *scene, Image *ima, BMEditMesh *em, NearestHit *hit,
-                              const float limit[2], const bool extend)
+static int uv_select_edgeloop(
+        Scene *scene, Image *ima, BMEditMesh *em, UvNearestHit *hit,
+        const float limit[2], const bool extend)
 {
 	BMFace *efa;
 	BMIter iter, liter;
@@ -1131,14 +1205,19 @@ static int uv_select_edgeloop(Scene *scene, Image *ima, BMEditMesh *em, NearestH
 	return (select) ? 1 : -1;
 }
 
-/*********************** linked select ***********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Linked
+ * \{ */
 
-static void uv_select_linked(Scene *scene, Image *ima, BMEditMesh *em, const float limit[2], NearestHit *hit, bool extend, bool select_faces)
+static void uv_select_linked(
+        Scene *scene, Image *ima, BMEditMesh *em, const float limit[2], UvNearestHit *hit_final,
+        bool extend, bool select_faces)
 {
 	BMFace *efa;
 	BMLoop *l;
 	BMIter iter, liter;
-	MTexPoly *tf;
 	MLoopUV *luv;
 	UvVertMap *vmap;
 	UvMapVert *vlist, *iterv, *startv;
@@ -1165,9 +1244,10 @@ static void uv_select_linked(Scene *scene, Image *ima, BMEditMesh *em, const flo
 	stack = MEM_mallocN(sizeof(*stack) * (em->bm->totface + 1), "UvLinkStack");
 	flag = MEM_callocN(sizeof(*flag) * em->bm->totface, "UvLinkFlag");
 
-	if (!hit) {
+	if (hit_final == NULL) {
+		/* Use existing selection */
 		BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
-			tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
+			MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
 
 			if (uvedit_face_visible_test(scene, ima, efa, tf)) {
 				if (select_faces) {
@@ -1195,7 +1275,7 @@ static void uv_select_linked(Scene *scene, Image *ima, BMEditMesh *em, const flo
 	}
 	else {
 		BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
-			if (efa == hit->efa) {
+			if (efa == hit_final->efa) {
 				stack[stacksize] = a;
 				stacksize++;
 				flag[a] = 1;
@@ -1350,6 +1430,12 @@ static float *uv_sel_co_from_eve(Scene *scene, Image *ima, BMEditMesh *em, BMVer
 	return NULL;
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select More/Less Operator
+ * \{ */
+
 static int uv_select_more_less(bContext *C, const bool select)
 {
 	Scene *scene = CTX_data_scene(C);
@@ -1490,7 +1576,11 @@ static void UV_OT_select_less(wmOperatorType *ot)
 	ot->poll = ED_operator_uvedit_space_image;
 }
 
-/* ******************** align operator **************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Weld Align Operator
+ * \{ */
 
 static void uv_weld_align(bContext *C, int tool)
 {
@@ -1602,8 +1692,10 @@ static void uv_weld_align(bContext *C, int tool)
 
 		/* flush vertex tags to edges */
 		BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
-			BM_elem_flag_set(eed, BM_ELEM_TAG, (BM_elem_flag_test(eed->v1, BM_ELEM_TAG) &&
-			                                    BM_elem_flag_test(eed->v2, BM_ELEM_TAG)));
+			BM_elem_flag_set(
+			        eed, BM_ELEM_TAG,
+			        (BM_elem_flag_test(eed->v1, BM_ELEM_TAG) &&
+			         BM_elem_flag_test(eed->v2, BM_ELEM_TAG)));
 		}
 
 		/* find a vertex with only one tagged edge */
@@ -1654,11 +1746,11 @@ static void uv_weld_align(bContext *C, int tool)
 			}
 
 			/* now we have all verts, make into a line */
-			if (BLI_array_count(eve_line) > 2) {
+			if (BLI_array_len(eve_line) > 2) {
 
 				/* we know the returns from these must be valid */
 				const float *uv_start = uv_sel_co_from_eve(scene, ima, em, eve_line[0]);
-				const float *uv_end   = uv_sel_co_from_eve(scene, ima, em, eve_line[BLI_array_count(eve_line) - 1]);
+				const float *uv_end   = uv_sel_co_from_eve(scene, ima, em, eve_line[BLI_array_len(eve_line) - 1]);
 				/* For t & u modes */
 				float a = 0.0f;
 
@@ -1676,7 +1768,7 @@ static void uv_weld_align(bContext *C, int tool)
 				}
 
 				/* go over all verts except for endpoints */
-				for (i = 0; i < BLI_array_count(eve_line); i++) {
+				for (i = 0; i < BLI_array_len(eve_line); i++) {
 					BM_ITER_ELEM (l, &liter, eve_line[i], BM_LOOPS_OF_VERT) {
 						tf = BM_ELEM_CD_GET_VOID_P(l->f, cd_poly_tex_offset);
 
@@ -1749,7 +1841,12 @@ static void UV_OT_align(wmOperatorType *ot)
 	/* properties */
 	RNA_def_enum(ot->srna, "axis", axis_items, 'a', "Axis", "Axis to align UV locations on");
 }
-/* ******************** weld near operator **************** */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Remove Doubles Operator
+ * \{ */
 
 typedef struct UVvert {
 	MLoopUV *uv_loop;
@@ -1789,7 +1886,7 @@ static int uv_remove_doubles_exec(bContext *C, wmOperator *op)
 		MLoopUV **loop_arr = NULL;
 		BLI_array_declare(loop_arr);
 
-		/* TODO, use qsort as with MESH_OT_remove_doubles, this isn't optimal */
+		/* TODO, use kd-tree as with MESH_OT_remove_doubles, this isn't optimal */
 		BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
 			tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
 			if (!uvedit_face_visible_test(scene, ima, efa, tf))
@@ -1807,7 +1904,7 @@ static int uv_remove_doubles_exec(bContext *C, wmOperator *op)
 			}
 		}
 
-		for (uv_a_index = 0; uv_a_index < BLI_array_count(vert_arr); uv_a_index++) {
+		for (uv_a_index = 0; uv_a_index < BLI_array_len(vert_arr); uv_a_index++) {
 			if (vert_arr[uv_a_index].weld == false) {
 				float uv_min[2];
 				float uv_max[2];
@@ -1821,7 +1918,7 @@ static int uv_remove_doubles_exec(bContext *C, wmOperator *op)
 				copy_v2_v2(uv_min, uv_a);
 
 				vert_arr[uv_a_index].weld = true;
-				for (uv_b_index = uv_a_index + 1; uv_b_index < BLI_array_count(vert_arr); uv_b_index++) {
+				for (uv_b_index = uv_a_index + 1; uv_b_index < BLI_array_len(vert_arr); uv_b_index++) {
 					uv_b = vert_arr[uv_b_index].uv_loop->uv;
 					if ((vert_arr[uv_b_index].weld == false) &&
 					    (len_manhattan_v2v2(uv_a, uv_b) < threshold))
@@ -1831,10 +1928,10 @@ static int uv_remove_doubles_exec(bContext *C, wmOperator *op)
 						vert_arr[uv_b_index].weld = true;
 					}
 				}
-				if (BLI_array_count(loop_arr)) {
+				if (BLI_array_len(loop_arr)) {
 					float uv_mid[2];
 					mid_v2_v2v2(uv_mid, uv_min, uv_max);
-					for (uv_b_index = 0; uv_b_index < BLI_array_count(loop_arr); uv_b_index++) {
+					for (uv_b_index = 0; uv_b_index < BLI_array_len(loop_arr); uv_b_index++) {
 						copy_v2_v2(loop_arr[uv_b_index]->uv, uv_mid);
 					}
 				}
@@ -1869,12 +1966,12 @@ static int uv_remove_doubles_exec(bContext *C, wmOperator *op)
 			}
 		}
 
-		for (uv_a_index = 0; uv_a_index < BLI_array_count(loop_arr); uv_a_index++) {
+		for (uv_a_index = 0; uv_a_index < BLI_array_len(loop_arr); uv_a_index++) {
 			float dist_best = FLT_MAX, dist;
 			const float *uv_best = NULL;
 
 			uv_a = loop_arr[uv_a_index]->uv;
-			for (uv_b_index = 0; uv_b_index < BLI_array_count(loop_arr_unselected); uv_b_index++) {
+			for (uv_b_index = 0; uv_b_index < BLI_array_len(loop_arr_unselected); uv_b_index++) {
 				uv_b = loop_arr_unselected[uv_b_index]->uv;
 				dist = len_manhattan_v2v2(uv_a, uv_b);
 				if ((dist < threshold) && (dist < dist_best)) {
@@ -1914,7 +2011,12 @@ static void UV_OT_remove_doubles(wmOperatorType *ot)
 	              "Merge Distance", "Maximum distance between welded vertices", 0.0f, 1.0f);
 	RNA_def_boolean(ot->srna, "use_unselected", 0, "Unselected", "Merge selected to other unselected vertices");
 }
-/* ******************** weld operator **************** */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Weld Near Operator
+ * \{ */
 
 static int uv_weld_exec(bContext *C, wmOperator *UNUSED(op))
 {
@@ -1936,8 +2038,11 @@ static void UV_OT_weld(wmOperatorType *ot)
 	ot->poll = ED_operator_uvedit;
 }
 
+/** \} */
 
-/* ******************** (de)select all operator **************** */
+/* -------------------------------------------------------------------- */
+/** \name (De)Select All Operator
+ * \{ */
 
 static void uv_select_all_perform(Scene *scene, Image *ima, BMEditMesh *em, int action)
 {
@@ -2046,9 +2151,13 @@ static void UV_OT_select_all(wmOperatorType *ot)
 	WM_operator_properties_select_all(ot);
 }
 
-/* ******************** mouse select operator **************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mouse Select Operator
+ * \{ */
 
-static bool uv_sticky_select(float *limit, int hitv[4], int v, float *hituv[4], float *uv, int sticky, int hitlen)
+static bool uv_sticky_select(float *limit, int hitv[], int v, float *hituv[], float *uv, int sticky, int hitlen)
 {
 	int i;
 
@@ -2084,12 +2193,11 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
 	BMIter iter, liter;
 	MTexPoly *tf;
 	MLoopUV *luv;
-	NearestHit hit;
+	UvNearestHit hit = UV_NEAREST_HIT_INIT;
 	int i, selectmode, sticky, sync, *hitv = NULL;
 	bool select = true;
 	int flush = 0, hitlen = 0; /* 0 == don't flush, 1 == sel, -1 == desel;  only use when selection sync is enabled */
 	float limit[2], **hituv = NULL;
-	float penalty[2];
 
 	const int cd_loop_uv_offset  = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
 	const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
@@ -2100,8 +2208,13 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
 	 * shift-selecting can consider an adjacent point close enough to add to
 	 * the selection rather than de-selecting the closest. */
 
-	uvedit_pixel_to_float(sima, limit, 0.05f);
-	uvedit_pixel_to_float(sima, penalty, 5.0f / (sima ? sima->zoom : 1.0f));
+	float penalty_dist;
+	{
+		float penalty[2];
+		uvedit_pixel_to_float(sima, limit, 0.05f);
+		uvedit_pixel_to_float(sima, penalty, 5.0f / (sima ? sima->zoom : 1.0f));
+		penalty_dist = len_v2(penalty);
+	}
 
 	/* retrieve operation mode */
 	if (ts->uv_flag & UV_SYNC_SELECTION) {
@@ -2125,8 +2238,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
 	/* find nearest element */
 	if (loop) {
 		/* find edge */
-		uv_find_nearest_edge(scene, ima, em, co, &hit);
-		if (hit.efa == NULL) {
+		if (!uv_find_nearest_edge(scene, ima, em, co, &hit)) {
 			return OPERATOR_CANCELLED;
 		}
 
@@ -2134,8 +2246,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
 	}
 	else if (selectmode == UV_SELECT_VERTEX) {
 		/* find vertex */
-		uv_find_nearest_vert(scene, ima, em, co, penalty, &hit);
-		if (hit.efa == NULL) {
+		if (!uv_find_nearest_vert(scene, ima, em, co, penalty_dist, &hit)) {
 			return OPERATOR_CANCELLED;
 		}
 
@@ -2151,8 +2262,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
 	}
 	else if (selectmode == UV_SELECT_EDGE) {
 		/* find edge */
-		uv_find_nearest_edge(scene, ima, em, co, &hit);
-		if (hit.efa == NULL) {
+		if (!uv_find_nearest_edge(scene, ima, em, co, &hit)) {
 			return OPERATOR_CANCELLED;
 		}
 
@@ -2170,11 +2280,10 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
 	}
 	else if (selectmode == UV_SELECT_FACE) {
 		/* find face */
-		uv_find_nearest_face(scene, ima, em, co, &hit);
-		if (hit.efa == NULL) {
+		if (!uv_find_nearest_face(scene, ima, em, co, &hit)) {
 			return OPERATOR_CANCELLED;
 		}
-		
+
 		/* make active */
 		BM_mesh_active_face_set(em->bm, hit.efa);
 
@@ -2191,9 +2300,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
 		hitlen = hit.efa->len;
 	}
 	else if (selectmode == UV_SELECT_ISLAND) {
-		uv_find_nearest_edge(scene, ima, em, co, &hit);
-
-		if (hit.efa == NULL) {
+		if (!uv_find_nearest_edge(scene, ima, em, co, &hit)) {
 			return OPERATOR_CANCELLED;
 		}
 
@@ -2373,7 +2480,11 @@ static void UV_OT_select(wmOperatorType *ot)
 	                     "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", -100.0f, 100.0f);
 }
 
-/* ******************** loop select operator **************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Loop Select Operator
+ * \{ */
 
 static int uv_select_loop_exec(bContext *C, wmOperator *op)
 {
@@ -2418,7 +2529,11 @@ static void UV_OT_select_loop(wmOperatorType *ot)
 	                     "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", -100.0f, 100.0f);
 }
 
-/* ******************** linked select operator **************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Linked Operator
+ * \{ */
 
 static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent *event, int pick)
 {
@@ -2432,7 +2547,7 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent
 	int extend;
 	bool select_faces = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE);
 
-	NearestHit hit, *hit_p = NULL;
+	UvNearestHit hit = UV_NEAREST_HIT_INIT;
 
 	if ((ts->uv_flag & UV_SYNC_SELECTION) && !(ts->selectmode & SCE_SELECT_FACE)) {
 		BKE_report(op->reports, RPT_ERROR, "Select linked only works in face select mode when sync selection is enabled");
@@ -2457,11 +2572,12 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent
 			RNA_float_get_array(op->ptr, "location", co);
 		}
 
-		uv_find_nearest_edge(scene, ima, em, co, &hit);
-		hit_p = &hit;
+		if (!uv_find_nearest_edge(scene, ima, em, co, &hit)) {
+			return OPERATOR_CANCELLED;
+		}
 	}
 
-	uv_select_linked(scene, ima, em, limit, hit_p, extend, select_faces);
+	uv_select_linked(scene, ima, em, limit, pick ? &hit : NULL, extend, select_faces);
 
 	DAG_id_tag_update(obedit->data, 0);
 	WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
@@ -2628,17 +2744,21 @@ static void uv_select_sync_flush(ToolSettings *ts, BMEditMesh *em, const short s
 	}
 }
 
-
+/** \} */
 
 /* -------------------------------------------------------------------- */
-/* Utility functions to flush the uv-selection from tags */
+/** \name Select/Tag Flushing Utils
+ *
+ * Utility functions to flush the uv-selection from tags.
+ * \{ */
 
 /**
  * helper function for #uv_select_flush_from_tag_loop and uv_select_flush_from_tag_face
  */
-static void uv_select_flush_from_tag_sticky_loc_internal(Scene *scene, BMEditMesh *em, UvVertMap *vmap,
-                                                         const unsigned int efa_index, BMLoop *l,
-                                                         const bool select, const int cd_loop_uv_offset)
+static void uv_select_flush_from_tag_sticky_loc_internal(
+        Scene *scene, BMEditMesh *em, UvVertMap *vmap,
+        const unsigned int efa_index, BMLoop *l,
+        const bool select, const int cd_loop_uv_offset)
 {
 	UvMapVert *start_vlist = NULL, *vlist_iter;
 	BMFace *efa_vlist;
@@ -2742,8 +2862,9 @@ static void uv_select_flush_from_tag_face(SpaceImage *sima, Scene *scene, Object
 				/* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
 				
 				BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
-					uv_select_flush_from_tag_sticky_loc_internal(scene, em, vmap, efa_index, l,
-					                                             select, cd_loop_uv_offset);
+					uv_select_flush_from_tag_sticky_loc_internal(
+					        scene, em, vmap, efa_index, l,
+					        select, cd_loop_uv_offset);
 				}
 			}
 		}
@@ -2829,8 +2950,9 @@ static void uv_select_flush_from_tag_loop(SpaceImage *sima, Scene *scene, Object
 
 			BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
 				if (BM_elem_flag_test(l, BM_ELEM_TAG)) {
-					uv_select_flush_from_tag_sticky_loc_internal(scene, em, vmap, efa_index, l,
-					                                             select, cd_loop_uv_offset);
+					uv_select_flush_from_tag_sticky_loc_internal(
+					        scene, em, vmap, efa_index, l,
+					        select, cd_loop_uv_offset);
 				}
 			}
 		}
@@ -2848,7 +2970,11 @@ static void uv_select_flush_from_tag_loop(SpaceImage *sima, Scene *scene, Object
 	}
 }
 
-/* ******************** border select operator **************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Border Select Operator
+ * \{ */
 
 static int uv_border_select_exec(bContext *C, wmOperator *op)
 {
@@ -2866,9 +2992,10 @@ static int uv_border_select_exec(bContext *C, wmOperator *op)
 	MLoopUV *luv;
 	rctf rectf;
 	bool changed, pinned, select, extend;
-	const bool use_face_center = (ts->uv_flag & UV_SYNC_SELECTION) ?
-	                            (ts->selectmode == SCE_SELECT_FACE) :
-	                            (ts->uv_selectmode == UV_SELECT_FACE);
+	const bool use_face_center = (
+	        (ts->uv_flag & UV_SYNC_SELECTION) ?
+	        (ts->selectmode == SCE_SELECT_FACE) :
+	        (ts->uv_selectmode == UV_SELECT_FACE));
 
 	const int cd_loop_uv_offset  = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
 	const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
@@ -2981,7 +3108,11 @@ static void UV_OT_select_border(wmOperatorType *ot)
 	WM_operator_properties_gesture_border_select(ot);
 }
 
-/* ******************** circle select operator **************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Circle Select Operator
+ * \{ */
 
 static int uv_inside_circle(const float uv[2], const float offset[2], const float ellipse[2])
 {
@@ -3008,9 +3139,10 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op)
 	float zoomx, zoomy, offset[2], ellipse[2];
 	const bool select = !RNA_boolean_get(op->ptr, "deselect");
 	bool changed = false;
-	const bool use_face_center = (ts->uv_flag & UV_SYNC_SELECTION) ?
-	                             (ts->selectmode == SCE_SELECT_FACE) :
-	                             (ts->uv_selectmode == UV_SELECT_FACE);
+	const bool use_face_center = (
+	        (ts->uv_flag & UV_SYNC_SELECTION) ?
+	        (ts->selectmode == SCE_SELECT_FACE) :
+	        (ts->uv_selectmode == UV_SELECT_FACE));
 
 	const int cd_loop_uv_offset  = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
 
@@ -3099,11 +3231,15 @@ static void UV_OT_circle_select(wmOperatorType *ot)
 	WM_operator_properties_gesture_circle_select(ot);
 }
 
+/** \} */
 
-/* ******************** lasso select operator **************** */
+/* -------------------------------------------------------------------- */
+/** \name Lasso Select Operator
+ * \{ */
 
-static bool do_lasso_select_mesh_uv(bContext *C, const int mcords[][2], short moves,
-                                    const bool select, const bool extend)
+static bool do_lasso_select_mesh_uv(
+        bContext *C, const int mcords[][2], short moves,
+        const bool select, const bool extend)
 {
 	SpaceImage *sima = CTX_wm_space_image(C);
 	Image *ima = CTX_data_edit_image(C);
@@ -3167,9 +3303,10 @@ static bool do_lasso_select_mesh_uv(bContext *C, const int mcords[][2], short mo
 				BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
 					if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) {
 						MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-						if (UI_view2d_view_to_region_clip(&ar->v2d,
-						                                  luv->uv[0], luv->uv[1],
-						                                  &screen_uv[0], &screen_uv[1]) &&
+						if (UI_view2d_view_to_region_clip(
+						            &ar->v2d,
+						            luv->uv[0], luv->uv[1],
+						            &screen_uv[0], &screen_uv[1]) &&
 						    BLI_rcti_isect_pt_v(&rect, screen_uv) &&
 						    BLI_lasso_is_point_inside(mcords, moves, screen_uv[0], screen_uv[1], V2D_IS_CLIPPED))
 						{
@@ -3238,9 +3375,11 @@ static void UV_OT_select_lasso(wmOperatorType *ot)
 	WM_operator_properties_gesture_lasso_select(ot);
 }
 
+/** \} */
 
-
-/* ******************** snap cursor operator **************** */
+/* -------------------------------------------------------------------- */
+/** \name Snap Cursor Operator
+ * \{ */
 
 static void uv_snap_to_pixel(float uvco[2], float w, float h)
 {
@@ -3308,7 +3447,11 @@ static void UV_OT_snap_cursor(wmOperatorType *ot)
 	RNA_def_enum(ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UVs to");
 }
 
-/* ******************** snap selection operator **************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Snap Selection Operator
+ * \{ */
 
 static bool uv_snap_uvs_to_cursor(Scene *scene, Image *ima, Object *obedit, const float cursor[2])
 {
@@ -3529,7 +3672,11 @@ static void UV_OT_snap_selected(wmOperatorType *ot)
 	RNA_def_enum(ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UVs to");
 }
 
-/* ******************** pin operator **************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Pin UV's Operator
+ * \{ */
 
 static int uv_pin_exec(bContext *C, wmOperator *op)
 {
@@ -3587,7 +3734,11 @@ static void UV_OT_pin(wmOperatorType *ot)
 	RNA_def_boolean(ot->srna, "clear", 0, "Clear", "Clear pinning for the selection instead of setting it");
 }
 
-/******************* select pinned operator ***************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Pinned UV's Operator
+ * \{ */
 
 static int uv_select_pinned_exec(bContext *C, wmOperator *UNUSED(op))
 {
@@ -3635,15 +3786,20 @@ static void UV_OT_select_pinned(wmOperatorType *ot)
 	ot->poll = ED_operator_uvedit;
 }
 
-/********************** hide operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Hide Operator
+ * \{ */
 
 /* check if we are selected or unselected based on 'bool_test' arg,
  * needed for select swap support */
 #define UV_SEL_TEST(luv, bool_test) ((((luv)->flag & MLOOPUV_VERTSEL) == MLOOPUV_VERTSEL) == bool_test)
 
 /* is every UV vert selected or unselected depending on bool_test */
-static bool bm_face_is_all_uv_sel(BMFace *f, bool select_test,
-                                  const int cd_loop_uv_offset)
+static bool bm_face_is_all_uv_sel(
+        BMFace *f, bool select_test,
+        const int cd_loop_uv_offset)
 {
 	BMLoop *l_iter;
 	BMLoop *l_first;
@@ -3773,7 +3929,11 @@ static void UV_OT_hide(wmOperatorType *ot)
 	RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
 }
 
-/****************** reveal operator ******************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Reveal Operator
+ * \{ */
 
 static int uv_reveal_exec(bContext *C, wmOperator *op)
 {
@@ -3908,7 +4068,11 @@ static void UV_OT_reveal(wmOperatorType *ot)
 	RNA_def_boolean(ot->srna, "select", true, "Select", "");
 }
 
-/******************** set 3d cursor operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Set 2D Cursor Operator
+ * \{ */
 
 static int uv_set_2d_cursor_poll(bContext *C)
 {
@@ -3971,7 +4135,11 @@ static void UV_OT_cursor_set(wmOperatorType *ot)
 	                     "Cursor location in normalized (0.0-1.0) coordinates", -10.0f, 10.0f);
 }
 
-/********************** set tile operator **********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Set Tile Operator
+ * \{ */
 
 static int set_tile_exec(bContext *C, wmOperator *op)
 {
@@ -4037,6 +4205,11 @@ static void UV_OT_tile_set(wmOperatorType *ot)
 	RNA_def_int_vector(ot->srna, "tile", 2, NULL, 0, INT_MAX, "Tile", "Tile coordinate", 0, 10);
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Seam from UV Islands Operator
+ * \{ */
 
 static int uv_seams_from_islands_exec(bContext *C, wmOperator *op)
 {
@@ -4055,7 +4228,7 @@ static int uv_seams_from_islands_exec(bContext *C, wmOperator *op)
 	em = me->edit_btmesh;
 	bm = em->bm;
 
-	if (!EDBM_mtexpoly_check(em)) {
+	if (!EDBM_uv_check(em)) {
 		return OPERATOR_CANCELLED;
 	}
 
@@ -4172,6 +4345,12 @@ static void UV_OT_seams_from_islands(wmOperatorType *ot)
 	RNA_def_boolean(ot->srna, "mark_sharp", 0, "Mark Sharp", "Mark boundary edges as sharp");
 }
 
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mark Seam Operator
+ * \{ */
+
 static int uv_mark_seam_exec(bContext *C, wmOperator *op)
 {
 	Object *ob = CTX_data_edit_object(C);
@@ -4244,8 +4423,11 @@ static void UV_OT_mark_seam(wmOperatorType *ot)
 	RNA_def_boolean(ot->srna, "clear", false, "Clear Seams", "Clear instead of marking seams");
 }
 
+/** \} */
 
-/* ************************** registration **********************************/
+/* -------------------------------------------------------------------- */
+/** \name Operator Registration & Keymap
+ * \{ */
 
 void ED_operatortypes_uvedit(void)
 {
@@ -4381,3 +4563,4 @@ void ED_keymap_uvedit(wmKeyConfig *keyconf)
 	transform_keymap_for_space(keyconf, keymap, SPACE_IMAGE);
 }
 
+/** \} */
diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c
index da36170310a79f145ba73da444015750a5f72537..057417b898f45a73c4e84d797a31bacefd1727e7 100644
--- a/source/blender/editors/uvedit/uvedit_smart_stitch.c
+++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c
@@ -2058,16 +2058,16 @@ static void stitch_select(bContext *C, Scene *scene, const wmEvent *event, Stitc
 {
 	/* add uv under mouse to processed uv's */
 	float co[2];
-	NearestHit hit;
+	UvNearestHit hit = UV_NEAREST_HIT_INIT;
 	ARegion *ar = CTX_wm_region(C);
 	Image *ima = CTX_data_edit_image(C);
 
 	UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
 
 	if (state->mode == STITCH_VERT) {
-		uv_find_nearest_vert(scene, ima, state->em, co, NULL, &hit);
-
-		if (hit.efa) {
+		if (uv_find_nearest_vert(
+		            scene, ima, state->em, co, 0.0f, &hit))
+		{
 			/* Add vertex to selection, deselect all common uv's of vert other
 			 * than selected and update the preview. This behavior was decided so that
 			 * you can do stuff like deselect the opposite stitchable vertex and the initial still gets deselected */
@@ -2079,9 +2079,9 @@ static void stitch_select(bContext *C, Scene *scene, const wmEvent *event, Stitc
 		}
 	}
 	else {
-		uv_find_nearest_edge(scene, ima, state->em, co, &hit);
-
-		if (hit.efa) {
+		if (uv_find_nearest_edge(
+		            scene, ima, state->em, co, &hit))
+		{
 			UvEdge *edge = uv_edge_get(hit.l, state);
 			stitch_select_edge(edge, state, false);
 		}
diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl
index 1f5ffbdcc7e25df60f0e3147bd85b02876dc04c5..a0ca719e207d3ba363efb551bb4f7985050fa3f3 100644
--- a/source/blender/gpu/shaders/gpu_shader_material.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_material.glsl
@@ -2599,7 +2599,8 @@ void node_bsdf_glossy(vec4 color, float roughness, vec3 N, out vec4 result)
 		vec3 light_specular = gl_LightSource[i].specular.rgb;
 
 		/* we mix in some diffuse so low roughness still shows up */
-		float bsdf = 0.5 * pow(max(dot(N, H), 0.0), 1.0 / roughness);
+		float r2 = roughness * roughness;
+		float bsdf = 0.5 * pow(max(dot(N, H), 0.0), 1.0 / r2);
 		bsdf += 0.5 * max(dot(N, light_position), 0.0);
 		L += light_specular * bsdf;
 	}
diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c
index 5472cae3ef22832adc8fd8372c4e1421dd1c3705..a770b34ecc6ae4d0cb37acd10d54919cd8db3663 100644
--- a/source/blender/imbuf/intern/anim_movie.c
+++ b/source/blender/imbuf/intern/anim_movie.c
@@ -511,7 +511,7 @@ static int startffmpeg(struct anim *anim)
 		return -1;
 	}
 
-	frame_rate = av_get_r_frame_rate_compat(pFormatCtx->streams[videoStream]);
+	frame_rate = av_get_r_frame_rate_compat(pFormatCtx, pFormatCtx->streams[videoStream]);
 	if (pFormatCtx->streams[videoStream]->nb_frames != 0) {
 		anim->duration = pFormatCtx->streams[videoStream]->nb_frames;
 	}
@@ -989,7 +989,7 @@ static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position,
 
 	v_st = anim->pFormatCtx->streams[anim->videoStream];
 
-	frame_rate = av_q2d(av_get_r_frame_rate_compat(v_st));
+	frame_rate = av_q2d(av_get_r_frame_rate_compat(anim->pFormatCtx, v_st));
 
 	st_time = anim->pFormatCtx->start_time;
 	pts_time_base = av_q2d(v_st->time_base);
diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c
index 009258079ee7aa3a9f0ff57b580a43eb21e00a0f..eaf4dfd84b4ca58cc6ff8df9e5ece26e0f0b9942 100644
--- a/source/blender/imbuf/intern/indexer.c
+++ b/source/blender/imbuf/intern/indexer.c
@@ -909,7 +909,7 @@ static int index_rebuild_ffmpeg(FFmpegIndexBuilderContext *context,
 
 	stream_size = avio_size(context->iFormatCtx->pb);
 
-	context->frame_rate = av_q2d(av_get_r_frame_rate_compat(context->iStream));
+	context->frame_rate = av_q2d(av_get_r_frame_rate_compat(context->iFormatCtx, context->iStream));
 	context->pts_time_base = av_q2d(context->iStream->time_base);
 
 	while (av_read_frame(context->iFormatCtx, &next_packet) >= 0) {
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index 4cb1c13a44a98b1c3319f359337f916d65d39250..4e85d70d3829a56dac489ccd6d3a73725c4bd49d 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -1621,14 +1621,13 @@ static bool exr_has_alpha(MultiPartInputFile& file)
 
 static bool imb_exr_is_multilayer_file(MultiPartInputFile& file)
 {
-	const StringAttribute *comments = file.header(0).findTypedAttribute<StringAttribute>("BlenderMultiChannel");
 	const ChannelList& channels = file.header(0).channels();
 	std::set <std::string> layerNames;
 
 	/* will not include empty layer names */
 	channels.layers(layerNames);
 
-	if (comments || layerNames.size() > 1)
+	if (layerNames.size() > 1)
 		return true;
 
 	if (layerNames.size()) {
@@ -1667,7 +1666,7 @@ static void imb_exr_type_by_channels(ChannelList& channels, StringVector& views,
 	}
 	else {
 		*r_singlelayer = false;
-		*r_multilayer = true;
+		*r_multilayer = (layerNames.size() > 1);
 		*r_multiview = false;
 		return;
 	}
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 1cc5cbf8c423f5fdca76bdfb0a31f5fca29f6838..b41e649b628bd76090dfaa6e3d45d07da6212d26 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -251,6 +251,7 @@ typedef enum eScenePassType {
 	SCE_PASS_SUBSURFACE_DIRECT        = (1 << 28),
 	SCE_PASS_SUBSURFACE_INDIRECT      = (1 << 29),
 	SCE_PASS_SUBSURFACE_COLOR         = (1 << 30),
+	SCE_PASS_ROUGHNESS                = (1 << 31),
 } eScenePassType;
 
 #define RE_PASSNAME_COMBINED "Combined"
diff --git a/source/blender/makesdna/intern/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c
index dec93f97c6c54f73768d2cf4bdb1408654bdd10a..2e21223d042dfca04f90ae2f821a461375925261 100644
--- a/source/blender/makesdna/intern/dna_genfile.c
+++ b/source/blender/makesdna/intern/dna_genfile.c
@@ -57,7 +57,7 @@
  * \section dna_genfile Overview
  *
  * - please note: no builtin security to detect input of double structs
- * - if you want a struct not to be in DNA file: add two hash marks above it (#<enter>#<enter>)
+ * - if you want a struct not to be in DNA file: add two hash marks above it `(#<enter>#<enter>)`.
  *
  * Structure DNA data is added to each blender file and to each executable, this to detect
  * in .blend files new variables in structs, changed array sizes, etc. It's also used for
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 6a67e036c5d3ca78b4cab635f4cc753038b98cb7..1fd17afdc6008851a80c00f79158523042bd6697 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -430,7 +430,6 @@ static void rna_Brush_icon_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Poi
 	br->id.icon_id = 0;
 
 	if (br->flag & BRUSH_CUSTOM_ICON) {
-		BKE_previewimg_id_ensure(&br->id);
 		BKE_icon_changed(BKE_icon_id_ensure(&br->id));
 	}
 
diff --git a/source/blender/makesrna/intern/rna_dynamicpaint.c b/source/blender/makesrna/intern/rna_dynamicpaint.c
index 6d93c56885e9cd12e35340a9e1962528c5c88534..94fda7097ee4c3487a83a7341d1302ddd61b5c5b 100644
--- a/source/blender/makesrna/intern/rna_dynamicpaint.c
+++ b/source/blender/makesrna/intern/rna_dynamicpaint.c
@@ -722,11 +722,11 @@ static void rna_def_canvas_surface(BlenderRNA *brna)
 	RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_DPAINT_WAVE_OPEN_BORDERS);
 	RNA_def_property_ui_text(prop, "Open Borders", "Pass waves through mesh edges");
 
-	
 	/* cache */
 	prop = RNA_def_property(srna, "point_cache", PROP_POINTER, PROP_NONE);
 	RNA_def_property_flag(prop, PROP_NEVER_NULL);
 	RNA_def_property_pointer_sdna(prop, NULL, "pointcache");
+	RNA_def_property_struct_type(prop, "PointCache");
 	RNA_def_property_ui_text(prop, "Point Cache", "");
 
 	/* is cache used */
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index e6e7069488575e099a400b13057f886f981f0dae..1d77030fe00d841de93d4a77f5659b11657ae554 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -273,7 +273,7 @@ static void rna_Object_active_shape_update(Main *bmain, Scene *scene, PointerRNA
 		switch (ob->type) {
 			case OB_MESH:
 				EDBM_mesh_load(ob);
-				EDBM_mesh_make(scene->toolsettings, ob, true);
+				EDBM_mesh_make(ob, scene->toolsettings->selectmode, true);
 
 				DAG_id_tag_update(ob->data, 0);
 
diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c
index b3808e4dde0390ca237e625663ccf0bd96eb97a6..c9c3372000f2fe7cc439d0a0d0feca23b6f0933d 100644
--- a/source/blender/makesrna/intern/rna_object_force.c
+++ b/source/blender/makesrna/intern/rna_object_force.c
@@ -768,31 +768,8 @@ static const EnumPropertyItem *rna_Effector_shape_itemf(bContext *UNUSED(C), Poi
 
 #else
 
-/* ptcache.point_caches */
-static void rna_def_ptcache_point_caches(BlenderRNA *brna, PropertyRNA *cprop)
+static void rna_def_pointcache_common(StructRNA *srna)
 {
-	StructRNA *srna;
-	PropertyRNA *prop;
-
-	/* FunctionRNA *func; */
-	/* PropertyRNA *parm; */
-
-	RNA_def_property_srna(cprop, "PointCaches");
-	srna = RNA_def_struct(brna, "PointCaches", NULL);
-	RNA_def_struct_sdna(srna, "PointCache");
-	RNA_def_struct_ui_text(srna, "Point Caches", "Collection of point caches");
-
-	prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
-	RNA_def_property_int_funcs(prop, "rna_Cache_active_point_cache_index_get",
-	                           "rna_Cache_active_point_cache_index_set",
-	                           "rna_Cache_active_point_cache_index_range");
-	RNA_def_property_ui_text(prop, "Active Point Cache Index", "");
-	RNA_def_property_update(prop, NC_OBJECT, "rna_Cache_change");
-}
-
-static void rna_def_pointcache(BlenderRNA *brna)
-{
-	StructRNA *srna;
 	PropertyRNA *prop;
 
 	static const EnumPropertyItem point_cache_compress_items[] = {
@@ -802,16 +779,12 @@ static void rna_def_pointcache(BlenderRNA *brna)
 		{0, NULL, 0, NULL, NULL}
 	};
 
-	srna = RNA_def_struct(brna, "PointCache", NULL);
-	RNA_def_struct_ui_text(srna, "Point Cache", "Point cache for physics simulations");
-	RNA_def_struct_ui_icon(srna, ICON_PHYSICS);
-	
 	prop = RNA_def_property(srna, "frame_start", PROP_INT, PROP_TIME);
 	RNA_def_property_int_sdna(prop, NULL, "startframe");
 	RNA_def_property_range(prop, -MAXFRAME, MAXFRAME);
 	RNA_def_property_ui_range(prop, 1, MAXFRAME, 1, 1);
 	RNA_def_property_ui_text(prop, "Start", "Frame on which the simulation starts");
-	
+
 	prop = RNA_def_property(srna, "frame_end", PROP_INT, PROP_TIME);
 	RNA_def_property_int_sdna(prop, NULL, "endframe");
 	RNA_def_property_range(prop, 1, MAXFRAME);
@@ -892,13 +865,59 @@ static void rna_def_pointcache(BlenderRNA *brna)
 	                         "Use this file's path for the disk cache when library linked into another file "
 	                         "(for local bakes per scene file, disable this option)");
 	RNA_def_property_update(prop, NC_OBJECT, "rna_Cache_idname_change");
+}
+
+static void rna_def_ptcache_point_caches(BlenderRNA *brna, PropertyRNA *cprop)
+{
+	StructRNA *srna;
+	PropertyRNA *prop;
+
+	/* FunctionRNA *func; */
+	/* PropertyRNA *parm; */
+
+	RNA_def_property_srna(cprop, "PointCaches");
+	srna = RNA_def_struct(brna, "PointCaches", NULL);
+	RNA_def_struct_sdna(srna, "PointCache");
+	RNA_def_struct_ui_text(srna, "Point Caches", "Collection of point caches");
+
+	prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
+	RNA_def_property_int_funcs(prop, "rna_Cache_active_point_cache_index_get",
+	                           "rna_Cache_active_point_cache_index_set",
+	                           "rna_Cache_active_point_cache_index_range");
+	RNA_def_property_ui_text(prop, "Active Point Cache Index", "");
+	RNA_def_property_update(prop, NC_OBJECT, "rna_Cache_change");
+
+	/* And define another RNA type for those collection items. */
+	srna = RNA_def_struct(brna, "PointCacheItem", NULL);
+	RNA_def_struct_sdna(srna, "PointCache");
+	RNA_def_struct_ui_text(srna, "Point Cache", "point cache for physics simulations");
+	RNA_def_struct_ui_icon(srna, ICON_PHYSICS);
+
+	rna_def_pointcache_common(srna);
+}
+
+static void rna_def_pointcache_active(BlenderRNA *brna)
+{
+	StructRNA *srna;
+	PropertyRNA *prop;
+
+	srna = RNA_def_struct(brna, "PointCache", NULL);
+	RNA_def_struct_ui_text(srna, "Active Point Cache", "Active point cache for physics simulations");
+	RNA_def_struct_ui_icon(srna, ICON_PHYSICS);
+
+	rna_def_pointcache_common(srna);
 
+	/* This first-level RNA pointer also has list of all caches from owning ID.
+	 * Those caches items have exact same content as 'active' one, except for that collection,
+	 * to prevent ugly recursive layout pattern.
+	 * Note: This shall probably be redone from scratch in a proper way at some poitn, but for now that will do,
+	 *       and shall not break anything in the API. */
 	prop = RNA_def_property(srna, "point_caches", PROP_COLLECTION, PROP_NONE);
 	RNA_def_property_collection_funcs(prop, "rna_Cache_list_begin", "rna_iterator_listbase_next",
 	                                  "rna_iterator_listbase_end", "rna_iterator_listbase_get",
 	                                  NULL, NULL, NULL, NULL);
-	RNA_def_property_struct_type(prop, "PointCache");
-	RNA_def_property_ui_text(prop, "Point Cache List", "Point cache list");
+	RNA_def_property_struct_type(prop, "PointCacheItem");
+	RNA_def_property_ui_text(prop, "Point Cache List", "");
 	rna_def_ptcache_point_caches(brna, prop);
 }
 
@@ -1878,7 +1897,7 @@ static void rna_def_softbody(BlenderRNA *brna)
 
 void RNA_def_object_force(BlenderRNA *brna)
 {
-	rna_def_pointcache(brna);
+	rna_def_pointcache_active(brna);
 	rna_def_collision(brna);
 	rna_def_effector_weight(brna);
 	rna_def_field(brna);
diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c
index d3b3ed51981c929b8006303b91f3f8c91f03ff76..98ae6eb048083087ee61f3b9e555c502e054a7a2 100644
--- a/source/blender/makesrna/intern/rna_render.c
+++ b/source/blender/makesrna/intern/rna_render.c
@@ -89,6 +89,7 @@ const EnumPropertyItem rna_enum_bake_pass_type_items[] = {
 	{SCE_PASS_SHADOW, "SHADOW", 0, "Shadow", ""},
 	{SCE_PASS_NORMAL, "NORMAL", 0, "Normal", ""},
 	{SCE_PASS_UV, "UV", 0, "UV", ""},
+	{SCE_PASS_ROUGHNESS, "ROUGHNESS", 0, "ROUGHNESS", ""},
 	{SCE_PASS_EMIT, "EMIT", 0, "Emit", ""},
 	{SCE_PASS_ENVIRONMENT, "ENVIRONMENT", 0, "Environment", ""},
 	{SCE_PASS_DIFFUSE_COLOR, "DIFFUSE", 0, "Diffuse", ""},
diff --git a/source/blender/makesrna/intern/rna_rigidbody.c b/source/blender/makesrna/intern/rna_rigidbody.c
index 335b7d31acf396302fccc3c977e0ab9508351d42..188200eaff9334ca45c2a191a78ac0503800a6bd 100644
--- a/source/blender/makesrna/intern/rna_rigidbody.c
+++ b/source/blender/makesrna/intern/rna_rigidbody.c
@@ -803,6 +803,7 @@ static void rna_def_rigidbody_world(BlenderRNA *brna)
 	prop = RNA_def_property(srna, "point_cache", PROP_POINTER, PROP_NONE);
 	RNA_def_property_flag(prop, PROP_NEVER_NULL);
 	RNA_def_property_pointer_sdna(prop, NULL, "pointcache");
+	RNA_def_property_struct_type(prop, "PointCache");
 	RNA_def_property_ui_text(prop, "Point Cache", "");
 
 	/* effector weights */
diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c
index 3043e636b318b72be47638dee2bc741f966758f7..2a63f465dc26b2d830ba48e4de1a6132df542b22 100644
--- a/source/blender/makesrna/intern/rna_scene_api.c
+++ b/source/blender/makesrna/intern/rna_scene_api.c
@@ -112,7 +112,7 @@ static void rna_Scene_uvedit_aspect(Scene *scene, Object *ob, float *aspect)
 	if ((ob->type == OB_MESH) && (ob->mode == OB_MODE_EDIT)) {
 		BMEditMesh *em;
 		em = BKE_editmesh_from_object(ob);
-		if (EDBM_mtexpoly_check(em)) {
+		if (EDBM_uv_check(em)) {
 			ED_uvedit_get_aspect(scene, ob, em->bm, aspect, aspect + 1);
 			return;
 		}
diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c
index 54daba706c783ac5957771642cad923f570c792c..3bfe1fbcb83c3596f29e227f1f10f165f04356f0 100644
--- a/source/blender/makesrna/intern/rna_smoke.c
+++ b/source/blender/makesrna/intern/rna_smoke.c
@@ -622,6 +622,7 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
 	prop = RNA_def_property(srna, "point_cache", PROP_POINTER, PROP_NONE);
 	RNA_def_property_flag(prop, PROP_NEVER_NULL);
 	RNA_def_property_pointer_sdna(prop, NULL, "point_cache[0]");
+	RNA_def_property_struct_type(prop, "PointCache");
 	RNA_def_property_ui_text(prop, "Point Cache", "");
 
 	prop = RNA_def_property(srna, "point_cache_compress_type", PROP_ENUM, PROP_NONE);
diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c
index 5a13f92f237b134765f89d4a9604a57e40d9fc0e..dda0c413f57d8c5c63e02aca765ef5631db5131b 100644
--- a/source/blender/modifiers/intern/MOD_skin.c
+++ b/source/blender/modifiers/intern/MOD_skin.c
@@ -1304,9 +1304,9 @@ static void skin_fix_hole_no_good_verts(BMesh *bm, Frame *frame, BMFace *split_f
 	else if (split_face->len > 4) {
 		/* Maintain a dynamic vert array containing the split_face's
 		 * vertices, avoids frequent allocs in collapse_face_corners() */
-		if (BLI_array_count(vert_buf) < split_face->len) {
+		if (BLI_array_len(vert_buf) < split_face->len) {
 			BLI_array_grow_items(vert_buf, (split_face->len -
-			                                BLI_array_count(vert_buf)));
+			                                BLI_array_len(vert_buf)));
 		}
 
 		/* Get split face's verts */
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c
index 01ca0bd6512bb9a1ae55164572cec4745d75f6b7..6410441797a60b34badd82b7797c8d0d8fb4887b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c
@@ -31,7 +31,7 @@
 
 static bNodeSocketTemplate sh_node_bsdf_anisotropic_in[] = {
 	{	SOCK_RGBA, 1, N_("Color"),			0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
-	{	SOCK_FLOAT, 1, N_("Roughness"),	    0.2f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+	{	SOCK_FLOAT, 1, N_("Roughness"),	    0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
 	{	SOCK_FLOAT, 1, N_("Anisotropy"),	0.5f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f},
 	{	SOCK_FLOAT, 1, N_("Rotation"),		0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
 	{	SOCK_VECTOR, 1, N_("Normal"),		0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c
index 7e1bc971c7353919641d6aec7f0a275b93e37cea..c13fd89d6e5096f5fc00448ba0062c5dbc4e7805 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c
@@ -31,7 +31,7 @@
 
 static bNodeSocketTemplate sh_node_bsdf_glossy_in[] = {
 	{	SOCK_RGBA,  1, N_("Color"),		0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
-	{	SOCK_FLOAT, 1, N_("Roughness"),	0.2f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+	{	SOCK_FLOAT, 1, N_("Roughness"),	0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
 	{	SOCK_VECTOR, 1, N_("Normal"),	0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
 	{	-1, 0, ""	}
 };
diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c
index c5ff2592746daa41f118d3ec791f6e66a679b860..1e2ce3727272f68561781e45d3567466982d6aba 100644
--- a/source/blender/python/intern/bpy_app.c
+++ b/source/blender/python/intern/bpy_app.c
@@ -360,6 +360,8 @@ static PyGetSetDef bpy_app_getsets[] = {
 	{(char *)"debug_depsgraph_build", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_DEPSGRAPH_BUILD},
 	{(char *)"debug_depsgraph_eval", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_DEPSGRAPH_EVAL},
 	{(char *)"debug_depsgraph_tag", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_DEPSGRAPH_TAG},
+	{(char *)"debug_depsgraph_time", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_DEPSGRAPH_TIME},
+	{(char *)"debug_depsgraph_pretty", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_DEPSGRAPH_PRETTY},
 	{(char *)"debug_simdata",   bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_SIMDATA},
 	{(char *)"debug_gpumem",    bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_GPU_MEM},
 
diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c
index 924e46a8c000410bbc5a377cc0906b3924f83c1c..cc6a536789569d1aabadeedb8a87561ad040c9f8 100644
--- a/source/blender/python/mathutils/mathutils_Matrix.c
+++ b/source/blender/python/mathutils/mathutils_Matrix.c
@@ -1710,10 +1710,18 @@ static PyObject *Matrix_lerp(MatrixObject *self, PyObject *args)
 
 	/* TODO, different sized matrix */
 	if (self->num_col == 4 && self->num_row == 4) {
+#ifdef MATH_STANDALONE
+		blend_m4_m4m4((float (*)[4])mat, (float (*)[4])self->matrix, (float (*)[4])mat2->matrix, fac);
+#else
 		interp_m4_m4m4((float (*)[4])mat, (float (*)[4])self->matrix, (float (*)[4])mat2->matrix, fac);
+#endif
 	}
 	else if (self->num_col == 3 && self->num_row == 3) {
+#ifdef MATH_STANDALONE
+		blend_m3_m3m3((float (*)[3])mat, (float (*)[3])self->matrix, (float (*)[3])mat2->matrix, fac);
+#else
 		interp_m3_m3m3((float (*)[3])mat, (float (*)[3])self->matrix, (float (*)[3])mat2->matrix, fac);
+#endif
 	}
 	else {
 		PyErr_SetString(PyExc_ValueError,
diff --git a/source/blender/python/mathutils/mathutils_geometry.c b/source/blender/python/mathutils/mathutils_geometry.c
index fa0d271f7d327c304f7aedd616c18a6e5fa9f540..d935949fd8c40f3802d630b394115494f0e7c87e 100644
--- a/source/blender/python/mathutils/mathutils_geometry.c
+++ b/source/blender/python/mathutils/mathutils_geometry.c
@@ -742,7 +742,7 @@ static PyObject *M_Geometry_intersect_point_line(PyObject *UNUSED(self), PyObjec
 	float lambda;
 	PyObject *ret;
 	int size = 2;
-	
+
 	if (!PyArg_ParseTuple(
 	        args, "OOO:intersect_point_line",
 	        &py_pt, &py_line_a, &py_line_b))
@@ -760,7 +760,7 @@ static PyObject *M_Geometry_intersect_point_line(PyObject *UNUSED(self), PyObjec
 
 	/* do the calculation */
 	lambda = closest_to_line_v3(pt_out, pt, line_a, line_b);
-	
+
 	ret = PyTuple_New(2);
 	PyTuple_SET_ITEMS(ret,
 	        Vector_CreatePyObject(pt_out, size, NULL),
@@ -882,7 +882,7 @@ static PyObject *M_Geometry_intersect_point_quad_2d(PyObject *UNUSED(self), PyOb
 	PyObject *py_pt, *py_quad[4];
 	float pt[2], quad[4][2];
 	int i;
-	
+
 	if (!PyArg_ParseTuple(
 	        args, "OOOOO:intersect_point_quad_2d",
 	        &py_pt, UNPACK4_EX(&, py_quad, )))
@@ -954,12 +954,12 @@ PyDoc_STRVAR(M_Geometry_barycentric_transform_doc,
 "   :type tri_a2: :class:`mathutils.Vector`\n"
 "   :arg tri_a3: source triangle vertex.\n"
 "   :type tri_a3: :class:`mathutils.Vector`\n"
-"   :arg tri_a1: target triangle vertex.\n"
-"   :type tri_a1: :class:`mathutils.Vector`\n"
-"   :arg tri_a2: target triangle vertex.\n"
-"   :type tri_a2: :class:`mathutils.Vector`\n"
-"   :arg tri_a3: target triangle vertex.\n"
-"   :type tri_a3: :class:`mathutils.Vector`\n"
+"   :arg tri_b1: target triangle vertex.\n"
+"   :type tri_b1: :class:`mathutils.Vector`\n"
+"   :arg tri_b2: target triangle vertex.\n"
+"   :type tri_b2: :class:`mathutils.Vector`\n"
+"   :arg tri_b3: target triangle vertex.\n"
+"   :type tri_b3: :class:`mathutils.Vector`\n"
 "   :return: The transformed point\n"
 "   :rtype: :class:`mathutils.Vector`'s\n"
 );
diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h
index bb056675887fd5ec5db0ea8cdb8d3abeedf9d1de..de71b8d10236f17e3c685ccc2dd9b9e0b43343f0 100644
--- a/source/blender/render/extern/include/RE_pipeline.h
+++ b/source/blender/render/extern/include/RE_pipeline.h
@@ -236,6 +236,8 @@ void RE_render_result_rect_from_ibuf(
 struct RenderLayer *RE_GetRenderLayer(struct RenderResult *rr, const char *name);
 float *RE_RenderLayerGetPass(volatile struct RenderLayer *rl, const char *name, const char *viewname);
 
+bool RE_HasSingleLayer(struct Render *re);
+
 /* add passes for grease pencil */
 struct RenderPass *RE_create_gp_pass(struct RenderResult *rr, const char *layername, const char *viewname);
 
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index 7cab5f43acac3ff983c0fa53f592770add700e42..e17a503cd4ec4b1324a59779b62ccb9cfff86558 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -257,6 +257,11 @@ RenderLayer *RE_GetRenderLayer(RenderResult *rr, const char *name)
 	}
 }
 
+bool RE_HasSingleLayer(Render *re)
+{
+	return (re->r.scemode & R_SINGLE_LAYER);
+}
+
 RenderResult *RE_MultilayerConvert(void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty)
 {
 	return render_result_new_from_exr(exrhandle, colorspace, predivide, rectx, recty);
@@ -264,12 +269,19 @@ RenderResult *RE_MultilayerConvert(void *exrhandle, const char *colorspace, bool
 
 RenderLayer *render_get_active_layer(Render *re, RenderResult *rr)
 {
-	RenderLayer *rl = BLI_findlink(&rr->layers, re->r.actlay);
-	
-	if (rl)
-		return rl;
-	else 
-		return rr->layers.first;
+	SceneRenderLayer *srl = BLI_findlink(&re->r.layers, re->r.actlay);
+
+	if (srl) {
+		RenderLayer *rl = BLI_findstring(&rr->layers,
+		                                 srl->name,
+		                                 offsetof(RenderLayer, name));
+
+		if (rl) {
+			return rl;
+		}
+	}
+
+	return rr->layers.first;
 }
 
 static int render_scene_needs_vector(Render *re)
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 8079cd0c2a9ff8a6157cf6a2b38c8eecb2276480..2a50de62ddadfabbfc4d335ffddf36973e1e89e3 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -3885,6 +3885,7 @@ static const EnumPropertyItem *rna_id_itemf(
 
 	for (; id; id = id->next) {
 		if ((filter_ids != NULL) && filter_ids(user_data, id) == false) {
+			i++;
 			continue;
 		}
 		if (local == false || !ID_IS_LINKED(id)) {
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index bf3d28e39e0e1db27f9e5dd595761300cb9642ae..cbf06e8c6e9dec9e4548406bfe7308b1391691e6 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -448,12 +448,7 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm
 	
 	ghostwin = GHOST_CreateWindow(g_system, title,
 	                              win->posx, posy, win->sizex, win->sizey,
-#ifdef __APPLE__
-	                              /* we agreed to not set any fullscreen or iconized state on startup */
-	                              GHOST_kWindowStateNormal,
-#else
 	                              (GHOST_TWindowState)win->windowstate,
-#endif
 	                              GHOST_kDrawingContextTypeOpenGL,
 	                              glSettings);
 	
@@ -510,7 +505,7 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm
 }
 
 /**
- * Initialize #wmWindows without ghostwin, open these and clear.
+ * Initialize #wmWindow without ghostwin, open these and clear.
  *
  * window size is read from window, if 0 it uses prefsize
  * called in #WM_check, also inits stuff after file read.
diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c
index 880c866085d571dfb53cde08f32be83cf52039a4..9486546b92338ea0b746e72ccde5e0c5c5bf327a 100644
--- a/source/blenderplayer/bad_level_call_stubs/stubs.c
+++ b/source/blenderplayer/bad_level_call_stubs/stubs.c
@@ -224,10 +224,10 @@ bool BPY_string_is_keyword(const char *str) { return false; }
 /*new render funcs */
 void EDBM_selectmode_set(struct BMEditMesh *em) RET_NONE
 void EDBM_mesh_load(struct Object *ob) RET_NONE
-void EDBM_mesh_make(struct ToolSettings *ts, struct Object *ob, const bool use_key_index) RET_NONE
+void EDBM_mesh_make(struct Object *ob, const int select_mode, const bool use_key_index) RET_NONE
 void EDBM_mesh_normals_update(struct BMEditMesh *em) RET_NONE
 void *g_system;
-bool EDBM_mtexpoly_check(struct BMEditMesh *em) RET_ZERO
+bool EDBM_uv_check(struct BMEditMesh *em) RET_ZERO
 
 float *RE_RenderLayerGetPass(volatile struct RenderLayer *rl, const char *name, const char *viewname) RET_NULL
 float RE_filter_value(int type, float x) RET_ZERO
diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c
index 45af15817404b4d2ef70d39ad0d1da9a614d88c0..25f8d732c5828ef1e62b176e534b2313d0162c11 100644
--- a/source/creator/creator_args.c
+++ b/source/creator/creator_args.c
@@ -505,7 +505,7 @@ static int arg_handle_print_help(int UNUSED(argc), const char **UNUSED(argv), vo
 	printf("\n");
 	printf("Window Options:\n");
 	BLI_argsPrintArgDoc(ba, "--window-border");
-	BLI_argsPrintArgDoc(ba, "--window-borderless");
+	BLI_argsPrintArgDoc(ba, "--window-fullscreen");
 	BLI_argsPrintArgDoc(ba, "--window-geometry");
 	BLI_argsPrintArgDoc(ba, "--start-console");
 	BLI_argsPrintArgDoc(ba, "--no-native-pixels");
@@ -755,10 +755,14 @@ static const char arg_handle_debug_mode_generic_set_doc_depsgraph_build[] =
 "\n\tEnable debug messages from dependency graph related on graph construction.";
 static const char arg_handle_debug_mode_generic_set_doc_depsgraph_tag[] =
 "\n\tEnable debug messages from dependency graph related on tagging.";
+static const char arg_handle_debug_mode_generic_set_doc_depsgraph_time[] =
+"\n\tEnable debug messages from dependency graph related on timing.";
 static const char arg_handle_debug_mode_generic_set_doc_depsgraph_eval[] =
 "\n\tEnable debug messages from dependency graph related on evaluation.";
 static const char arg_handle_debug_mode_generic_set_doc_depsgraph_no_threads[] =
 "\n\tSwitch dependency graph to a single threaded evaluation.";
+static const char arg_handle_debug_mode_generic_set_doc_depsgraph_pretty[] =
+"\n\tEnable colors for dependency graph debug messages.";
 static const char arg_handle_debug_mode_generic_set_doc_gpumem[] =
 "\n\tEnable GPU memory stats in status bar.";
 
@@ -972,7 +976,7 @@ static int arg_handle_with_borders(int UNUSED(argc), const char **UNUSED(argv),
 }
 
 static const char arg_handle_without_borders_doc[] =
-"\n\tForce opening without borders."
+"\n\tForce opening in fullscreen mode."
 ;
 static int arg_handle_without_borders(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
 {
@@ -1872,8 +1876,12 @@ void main_args_setup(bContext *C, bArgs *ba, SYS_SystemHandle *syshandle)
 	            CB_EX(arg_handle_debug_mode_generic_set, depsgraph_eval), (void *)G_DEBUG_DEPSGRAPH_EVAL);
 	BLI_argsAdd(ba, 1, NULL, "--debug-depsgraph-tag",
 	            CB_EX(arg_handle_debug_mode_generic_set, depsgraph_tag), (void *)G_DEBUG_DEPSGRAPH_TAG);
+	BLI_argsAdd(ba, 1, NULL, "--debug-depsgraph-time",
+	            CB_EX(arg_handle_debug_mode_generic_set, depsgraph_time), (void *)G_DEBUG_DEPSGRAPH_TIME);
 	BLI_argsAdd(ba, 1, NULL, "--debug-depsgraph-no-threads",
 	            CB_EX(arg_handle_debug_mode_generic_set, depsgraph_no_threads), (void *)G_DEBUG_DEPSGRAPH_NO_THREADS);
+	BLI_argsAdd(ba, 1, NULL, "--debug-depsgraph-pretty",
+	            CB_EX(arg_handle_debug_mode_generic_set, depsgraph_pretty), (void *)G_DEBUG_DEPSGRAPH_PRETTY);
 	BLI_argsAdd(ba, 1, NULL, "--debug-gpumem",
 	            CB_EX(arg_handle_debug_mode_generic_set, gpumem), (void *)G_DEBUG_GPU_MEM);
 
@@ -1892,7 +1900,7 @@ void main_args_setup(bContext *C, bArgs *ba, SYS_SystemHandle *syshandle)
 	/* second pass: custom window stuff */
 	BLI_argsAdd(ba, 2, "-p", "--window-geometry", CB(arg_handle_window_geometry), NULL);
 	BLI_argsAdd(ba, 2, "-w", "--window-border", CB(arg_handle_with_borders), NULL);
-	BLI_argsAdd(ba, 2, "-W", "--window-borderless", CB(arg_handle_without_borders), NULL);
+	BLI_argsAdd(ba, 2, "-W", "--window-fullscreen", CB(arg_handle_without_borders), NULL);
 	BLI_argsAdd(ba, 2, "-con", "--start-console", CB(arg_handle_start_with_console), NULL);
 	BLI_argsAdd(ba, 2, "-R", NULL, CB(arg_handle_register_extension), NULL);
 	BLI_argsAdd(ba, 2, "-r", NULL, CB_EX(arg_handle_register_extension, silent), ba);
diff --git a/source/gameengine/VideoTexture/VideoFFmpeg.cpp b/source/gameengine/VideoTexture/VideoFFmpeg.cpp
index 10196804656c4cae3e7434b7113aa009df2ba391..11ec97ca5f8e59831132869f0be6f1403433520c 100644
--- a/source/gameengine/VideoTexture/VideoFFmpeg.cpp
+++ b/source/gameengine/VideoTexture/VideoFFmpeg.cpp
@@ -228,7 +228,7 @@ int VideoFFmpeg::openStream(const char *filename, AVInputFormat *inputFormat, AV
 		codecCtx->frame_rate_base=1000;
 	m_baseFrameRate = (double)codecCtx->frame_rate / (double)codecCtx->frame_rate_base;
 #else
-	m_baseFrameRate = av_q2d(av_get_r_frame_rate_compat(formatCtx->streams[videoStream]));
+	m_baseFrameRate = av_q2d(av_get_r_frame_rate_compat(formatCtx, formatCtx->streams[videoStream]));
 #endif
 	if (m_baseFrameRate <= 0.0) 
 		m_baseFrameRate = defFrameRate;
diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt
index 6419c3f36e2aa70bca608044ef33c82dce6e06ef..9b1807b796b3018d75e903bf9599dca9536f4b35 100644
--- a/tests/python/CMakeLists.txt
+++ b/tests/python/CMakeLists.txt
@@ -27,6 +27,7 @@
 set(USE_EXPERIMENTAL_TESTS FALSE)
 
 set(TEST_SRC_DIR ${CMAKE_SOURCE_DIR}/../lib/tests)
+set(TEST_DATA_SRC_DIR ${CMAKE_SOURCE_DIR}/../lib/tests_data)
 set(TEST_OUT_DIR ${CMAKE_BINARY_DIR}/tests)
 
 # ugh, any better way to do this on testing only?
@@ -546,20 +547,22 @@ if(WITH_CYCLES)
 			add_cycles_render_test(opengl)
 		endif()
 		add_cycles_render_test(bake)
+		add_cycles_render_test(bsdf)
 		add_cycles_render_test(denoise)
 		add_cycles_render_test(displacement)
+		add_cycles_render_test(hair)
 		add_cycles_render_test(image_data_types)
 		add_cycles_render_test(image_mapping)
 		add_cycles_render_test(image_texture_limit)
+		add_cycles_render_test(integrator)
 		add_cycles_render_test(light)
-		add_cycles_render_test(mblur)
+		add_cycles_render_test(mesh)
+		add_cycles_render_test(motion_blur)
+		add_cycles_render_test(render_layer)
 		add_cycles_render_test(reports)
-		add_cycles_render_test(render)
 		add_cycles_render_test(shader)
-		add_cycles_render_test(shader_tangent)
 		add_cycles_render_test(shadow_catcher)
 		add_cycles_render_test(sss)
-		add_cycles_render_test(texture_space)
 		add_cycles_render_test(volume)
 	else()
 		MESSAGE(STATUS "Disabling Cycles tests because tests folder does not exist")
@@ -617,4 +620,13 @@ if(WITH_ALEMBIC)
 	)
 endif()
 
+if(WITH_CODEC_FFMPEG)
+	add_python_test(
+		ffmpeg_tests
+		${CMAKE_CURRENT_LIST_DIR}/ffmpeg_tests.py
+		--blender "$<TARGET_FILE:blender>"
+		--testdir "${TEST_DATA_SRC_DIR}/ffmpeg"
+	)
+endif()
+
 add_subdirectory(collada)
diff --git a/tests/python/ffmpeg_tests.py b/tests/python/ffmpeg_tests.py
new file mode 100755
index 0000000000000000000000000000000000000000..9493d6f7a17777bc4a2fc02f94e65f9e777476cb
--- /dev/null
+++ b/tests/python/ffmpeg_tests.py
@@ -0,0 +1,86 @@
+#!/usr/bin/env python3
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+import argparse
+import functools
+import shutil
+import pathlib
+import subprocess
+import sys
+import tempfile
+import unittest
+
+from modules.test_utils import AbstractBlenderRunnerTest
+
+
+class AbstractFFmpegTest(AbstractBlenderRunnerTest):
+    @classmethod
+    def setUpClass(cls):
+        cls.blender = args.blender
+        cls.testdir = pathlib.Path(args.testdir)
+
+
+class AbstractFFmpegSequencerTest(AbstractFFmpegTest):
+    def get_script_for_file(self, filename: pathlib.Path) -> str:
+        movie = self.testdir / filename
+        return \
+            "import bpy; " \
+            "bpy.context.scene.sequence_editor_create(); " \
+            "strip = bpy.context.scene.sequence_editor.sequences.new_movie(" \
+            "'test_movie', %r, channel=1, frame_start=1); " \
+            "print(f'fps:{strip.fps}')" % movie.as_posix()
+
+    def get_movie_file_fps(self, filename: pathlib.Path) -> float:
+        script = self.get_script_for_file(filename)
+        output = self.run_blender('', script)
+        for line in output.splitlines():
+            if line.startswith('fps:'):
+                return float(line.split(':')[1])
+        return 0.0
+
+
+class FPSDetectionTest(AbstractFFmpegSequencerTest):
+    def test_T51153(self):
+        self.assertAlmostEqual(
+            self.get_movie_file_fps('T51153_bad_clip_2.mts'), 
+            29.97,
+            places=2)
+
+    def test_T53857(self):
+        self.assertAlmostEqual(
+            self.get_movie_file_fps('T53857_2018-01-22_15-30-49.mkv'),
+            30.0,
+            places=2)
+
+    def test_T54148(self):
+        self.assertAlmostEqual(
+            self.get_movie_file_fps('T54148_magn_0.mkv'),
+            1.0,
+            places=2)
+
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser()
+    parser.add_argument('--blender', required=True)
+    parser.add_argument('--testdir', required=True)
+    args, remaining = parser.parse_known_args()
+
+    unittest.main(argv=sys.argv[0:1] + remaining)
diff --git a/tests/python/modules/test_utils.py b/tests/python/modules/test_utils.py
index 6ca498d8cdf6f9ef2b076cc2fd2b490895cb2735..55ef882c49cf013f251debcd0d8fd6310e286bd4 100755
--- a/tests/python/modules/test_utils.py
+++ b/tests/python/modules/test_utils.py
@@ -75,18 +75,24 @@ class AbstractBlenderRunnerTest(unittest.TestCase):
         assert self.blender, "Path to Blender binary is to be set in setUpClass()"
         assert self.testdir, "Path to tests binary is to be set in setUpClass()"
 
-        blendfile = self.testdir / filepath
+        blendfile = self.testdir / filepath if filepath else ""
 
-        command = (
+        command = [
             self.blender,
             '--background',
             '-noaudio',
             '--factory-startup',
             '--enable-autoexec',
-            str(blendfile),
+        ]
+
+        if blendfile:
+            command.append(str(blendfile))
+
+        command.extend([
             '-E', 'CYCLES',
             '--python-exit-code', '47',
             '--python-expr', python_script,
+            ]
         )
 
         proc = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,