Merge branch 'master' into blender2.8
authorCampbell Barton <ideasman42@gmail.com>
Sun, 17 Jun 2018 15:10:19 +0000 (17:10 +0200)
committerCampbell Barton <ideasman42@gmail.com>
Sun, 17 Jun 2018 15:10:19 +0000 (17:10 +0200)
173 files changed:
1  2 
source/blender/alembic/intern/abc_exporter.cc
source/blender/alembic/intern/abc_mesh.h
source/blender/blenkernel/BKE_DerivedMesh.h
source/blender/blenkernel/BKE_action.h
source/blender/blenkernel/BKE_animsys.h
source/blender/blenkernel/BKE_armature.h
source/blender/blenkernel/BKE_cloth.h
source/blender/blenkernel/BKE_constraint.h
source/blender/blenkernel/BKE_context.h
source/blender/blenkernel/BKE_customdata.h
source/blender/blenkernel/BKE_displist.h
source/blender/blenkernel/BKE_dynamicpaint.h
source/blender/blenkernel/BKE_editmesh.h
source/blender/blenkernel/BKE_effect.h
source/blender/blenkernel/BKE_fcurve.h
source/blender/blenkernel/BKE_global.h
source/blender/blenkernel/BKE_idprop.h
source/blender/blenkernel/BKE_image.h
source/blender/blenkernel/BKE_modifier.h
source/blender/blenkernel/BKE_node.h
source/blender/blenkernel/BKE_paint.h
source/blender/blenkernel/BKE_particle.h
source/blender/blenkernel/BKE_rigidbody.h
source/blender/blenkernel/BKE_sequencer.h
source/blender/blenkernel/intern/CCGSubSurf.c
source/blender/blenkernel/intern/DerivedMesh.c
source/blender/blenkernel/intern/action.c
source/blender/blenkernel/intern/anim.c
source/blender/blenkernel/intern/anim_sys.c
source/blender/blenkernel/intern/appdir.c
source/blender/blenkernel/intern/armature.c
source/blender/blenkernel/intern/armature_update.c
source/blender/blenkernel/intern/blender.c
source/blender/blenkernel/intern/boids.c
source/blender/blenkernel/intern/bvhutils.c
source/blender/blenkernel/intern/camera.c
source/blender/blenkernel/intern/cdderivedmesh.c
source/blender/blenkernel/intern/cloth.c
source/blender/blenkernel/intern/collision.c
source/blender/blenkernel/intern/constraint.c
source/blender/blenkernel/intern/context.c
source/blender/blenkernel/intern/curve.c
source/blender/blenkernel/intern/customdata.c
source/blender/blenkernel/intern/effect.c
source/blender/blenkernel/intern/fcurve.c
source/blender/blenkernel/intern/font.c
source/blender/blenkernel/intern/icons.c
source/blender/blenkernel/intern/idcode.c
source/blender/blenkernel/intern/idprop.c
source/blender/blenkernel/intern/ipo.c
source/blender/blenkernel/intern/lamp.c
source/blender/blenkernel/intern/lattice.c
source/blender/blenkernel/intern/library.c
source/blender/blenkernel/intern/library_remap.c
source/blender/blenkernel/intern/material.c
source/blender/blenkernel/intern/mball.c
source/blender/blenkernel/intern/mesh.c
source/blender/blenkernel/intern/mesh_evaluate.c
source/blender/blenkernel/intern/modifier.c
source/blender/blenkernel/intern/multires.c
source/blender/blenkernel/intern/nla.c
source/blender/blenkernel/intern/node.c
source/blender/blenkernel/intern/object.c
source/blender/blenkernel/intern/object_deform.c
source/blender/blenkernel/intern/object_dupli.c
source/blender/blenkernel/intern/paint.c
source/blender/blenkernel/intern/particle.c
source/blender/blenkernel/intern/particle_distribute.c
source/blender/blenkernel/intern/particle_system.c
source/blender/blenkernel/intern/pbvh.c
source/blender/blenkernel/intern/pointcache.c
source/blender/blenkernel/intern/rigidbody.c
source/blender/blenkernel/intern/scene.c
source/blender/blenkernel/intern/screen.c
source/blender/blenkernel/intern/seqeffects.c
source/blender/blenkernel/intern/sequencer.c
source/blender/blenkernel/intern/shrinkwrap.c
source/blender/blenkernel/intern/smoke.c
source/blender/blenkernel/intern/softbody.c
source/blender/blenkernel/intern/sound.c
source/blender/blenkernel/intern/studiolight.c
source/blender/blenkernel/intern/subsurf_ccg.c
source/blender/blenkernel/intern/text.c
source/blender/blenkernel/intern/texture.c
source/blender/blenkernel/intern/world.c
source/blender/blenkernel/intern/writeavi.c
source/blender/blenkernel/intern/writeffmpeg.c
source/blender/blenkernel/nla_private.h
source/blender/blenloader/BLO_readfile.h
source/blender/blenloader/CMakeLists.txt
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/readfile.h
source/blender/blenloader/intern/versioning_250.c
source/blender/blenloader/intern/versioning_260.c
source/blender/blenloader/intern/versioning_270.c
source/blender/blenloader/intern/versioning_defaults.c
source/blender/compositor/operations/COM_RenderLayersProg.cpp
source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp
source/blender/compositor/operations/COM_ScreenLensDistortionOperation.h
source/blender/freestyle/intern/application/Controller.cpp
source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
source/blender/freestyle/intern/scene_graph/IndexedFaceSet.h
source/blender/freestyle/intern/stroke/Stroke.h
source/blender/imbuf/intern/indexer.c
source/blender/imbuf/intern/thumbs.c
source/blender/imbuf/intern/thumbs_blend.c
source/blender/makesdna/DNA_ID.h
source/blender/makesdna/DNA_action_types.h
source/blender/makesdna/DNA_anim_types.h
source/blender/makesdna/DNA_armature_types.h
source/blender/makesdna/DNA_camera_types.h
source/blender/makesdna/DNA_cloth_types.h
source/blender/makesdna/DNA_constraint_types.h
source/blender/makesdna/DNA_curve_types.h
source/blender/makesdna/DNA_dynamicpaint_types.h
source/blender/makesdna/DNA_effect_types.h
source/blender/makesdna/DNA_gpencil_types.h
source/blender/makesdna/DNA_group_types.h
source/blender/makesdna/DNA_image_types.h
source/blender/makesdna/DNA_lamp_types.h
source/blender/makesdna/DNA_lattice_types.h
source/blender/makesdna/DNA_material_types.h
source/blender/makesdna/DNA_mesh_types.h
source/blender/makesdna/DNA_meshdata_types.h
source/blender/makesdna/DNA_meta_types.h
source/blender/makesdna/DNA_modifier_types.h
source/blender/makesdna/DNA_node_types.h
source/blender/makesdna/DNA_object_force_types.h
source/blender/makesdna/DNA_object_types.h
source/blender/makesdna/DNA_particle_types.h
source/blender/makesdna/DNA_rigidbody_types.h
source/blender/makesdna/DNA_scene_types.h
source/blender/makesdna/DNA_screen_types.h
source/blender/makesdna/DNA_smoke_types.h
source/blender/makesdna/DNA_texture_types.h
source/blender/makesdna/DNA_userdef_types.h
source/blender/makesdna/DNA_view2d_types.h
source/blender/makesdna/DNA_view3d_types.h
source/blender/makesdna/DNA_windowmanager_types.h
source/blender/makesdna/DNA_world_types.h
source/blender/makesdna/intern/dna_genfile.c
source/blender/makesdna/intern/makesdna.c
source/blender/modifiers/CMakeLists.txt
source/blender/modifiers/intern/MOD_armature.c
source/blender/modifiers/intern/MOD_bevel.c
source/blender/modifiers/intern/MOD_boolean.c
source/blender/modifiers/intern/MOD_build.c
source/blender/modifiers/intern/MOD_cast.c
source/blender/modifiers/intern/MOD_cloth.c
source/blender/modifiers/intern/MOD_collision.c
source/blender/modifiers/intern/MOD_dynamicpaint.c
source/blender/modifiers/intern/MOD_explode.c
source/blender/modifiers/intern/MOD_fluidsim.c
source/blender/modifiers/intern/MOD_fluidsim_util.c
source/blender/modifiers/intern/MOD_hook.c
source/blender/modifiers/intern/MOD_mask.c
source/blender/modifiers/intern/MOD_meshdeform.c
source/blender/modifiers/intern/MOD_mirror.c
source/blender/modifiers/intern/MOD_multires.c
source/blender/modifiers/intern/MOD_particlesystem.c
source/blender/modifiers/intern/MOD_remesh.c
source/blender/modifiers/intern/MOD_screw.c
source/blender/modifiers/intern/MOD_shrinkwrap.c
source/blender/modifiers/intern/MOD_skin.c
source/blender/modifiers/intern/MOD_smoke.c
source/blender/modifiers/intern/MOD_smooth.c
source/blender/modifiers/intern/MOD_surface.c
source/blender/modifiers/intern/MOD_util.c
source/blender/modifiers/intern/MOD_uvproject.c
source/blender/modifiers/intern/MOD_weightvgproximity.c
source/creator/CMakeLists.txt
source/creator/creator.c

@@@ -72,18 -74,19 +72,18 @@@ private
                         std::vector<int32_t> &creaseLengths,
                         std::vector<float> &creaseSharpness);
  
 -      DerivedMesh *getFinalMesh();
 -      void freeMesh(DerivedMesh *dm);
 +      struct Mesh *getFinalMesh(bool &r_needsfree);
  
 -      void getMaterialIndices(DerivedMesh *dm, std::vector<int32_t> &indices);
 +      void getMaterialIndices(struct Mesh *mesh, std::vector<int32_t> &indices);
  
 -      void writeArbGeoParams(DerivedMesh *dm);
 -      void getGeoGroups(DerivedMesh *dm, std::map<std::string, std::vector<int32_t> > &geoGroups);
 +      void writeArbGeoParams(struct Mesh *mesh);
 +      void getGeoGroups(struct Mesh *mesh, std::map<std::string, std::vector<int32_t> > &geoGroups);
-       
        /* fluid surfaces support */
 -      void getVelocities(DerivedMesh *dm, std::vector<Imath::V3f> &vels);
 +      void getVelocities(struct Mesh *mesh, std::vector<Imath::V3f> &vels);
  
        template <typename Schema>
 -      void writeFaceSets(DerivedMesh *dm, Schema &schema);
 +      void writeFaceSets(struct Mesh *mesh, Schema &schema);
  };
  
  /* ************************************************************************** */
Simple merge
@@@ -101,10 -99,10 +101,10 @@@ typedef struct bConstraintTypeInfo 
        int (*get_constraint_targets)(struct bConstraint *con, struct ListBase *list);
        /* for single-target constraints only: flush data back to source data, and the free memory used */
        void (*flush_constraint_targets)(struct bConstraint *con, struct ListBase *list, bool no_copy);
-       
        /* evaluation */
        /* set the ct->matrix for the given constraint target (at the given ctime) */
 -      void (*get_target_matrix)(struct bConstraint *con, struct bConstraintOb *cob, struct bConstraintTarget *ct, float ctime);
 +      void (*get_target_matrix)(struct Depsgraph *depsgraph, struct bConstraint *con, struct bConstraintOb *cob, struct bConstraintTarget *ct, float ctime);
        /* evaluate the constraint for the given time */
        void (*evaluate_constraint)(struct bConstraint *con, struct bConstraintOb *cob, struct ListBase *targets);
  } bConstraintTypeInfo;
Simple merge
@@@ -202,8 -197,17 +202,8 @@@ typedef struct ModifierTypeInfo 
         *
         * The derivedData argument should always be non-NULL; the modifier
         * should read the object data from the derived object instead of the
-        * actual object data. 
+        * actual object data.
         *
 -       * The useRenderParams argument indicates if the modifier is being
 -       * applied in the service of the renderer which may alter quality
 -       * settings.
 -       *
 -       * The isFinalCalc parameter indicates if the modifier is being
 -       * calculated for a final result or for something temporary
 -       * (like orcos). This is a hack at the moment, it is meant so subsurf
 -       * can know if it is safe to reuse its internal cache.
 -       *
         * The modifier may reuse the derivedData argument (i.e. return it in
         * modified form), but must not release it.
         */
         * are expected from editmode objects. The same qualifications regarding
         * derivedData apply as for applyModifier.
         */
 -      struct DerivedMesh *(*applyModifierEM)(struct ModifierData *md, struct Object *ob,
 -                                             struct BMEditMesh *editData,
 -                                             struct DerivedMesh *derivedData,
 -                                             ModifierApplyFlag flag);
 +      struct DerivedMesh *(*applyModifierEM_DM)(struct ModifierData *md, const struct ModifierEvalContext *ctx,
 +                                                struct BMEditMesh *editData,
 +                                                struct DerivedMesh *derivedData);
 +
 +
 +      /********************* Deform modifier functions *********************/
 +
 +      /* Only for deform types, should apply the deformation
 +       * to the given vertex array. If the deformer requires information from
 +       * the object it can obtain it from the mesh argument if non-NULL,
 +       * and otherwise the ob argument.
 +       */
 +      void (*deformVerts)(struct ModifierData *md,  const struct ModifierEvalContext *ctx,
 +                          struct Mesh *mesh, float (*vertexCos)[3], int numVerts);
 +
 +      /* Like deformMatricesEM but called from object mode (for supporting modifiers in sculpt mode) */
 +      void (*deformMatrices)(struct ModifierData *md,  const struct ModifierEvalContext *ctx,
 +                             struct Mesh *mesh, float (*vertexCos)[3], float (*defMats)[3][3], int numVerts);
 +
 +      /* Like deformVerts but called during editmode (for supporting modifiers)
 +       */
 +      void (*deformVertsEM)(struct ModifierData *md,  const struct ModifierEvalContext *ctx,
 +                            struct BMEditMesh *editData,
 +                            struct Mesh *mesh, float (*vertexCos)[3], int numVerts);
 +
 +      /* Set deform matrix per vertex for crazyspace correction */
 +      void (*deformMatricesEM)(struct ModifierData *md,  const struct ModifierEvalContext *ctx,
 +                               struct BMEditMesh *editData,
 +                               struct Mesh *mesh, float (*vertexCos)[3], float (*defMats)[3][3], int numVerts);
 +
 +      /********************* Non-deform modifier functions *********************/
 +
 +      /* For non-deform types: apply the modifier and return a mesh object.
 +       *
 +       * The mesh argument should always be non-NULL; the modifier
 +       * should read the object data from the mesh object instead of the
-        * actual object data. 
++       * actual object data.
 +       *
 +       * The modifier may reuse the mesh argument (i.e. return it in
 +       * modified form), but must not release it.
 +       */
 +      struct Mesh *(*applyModifier)(struct ModifierData *md, const struct ModifierEvalContext *ctx,
 +                                    struct Mesh *mesh);
 +
 +      /* Like applyModifier but called during editmode (for supporting
 +       * modifiers).
-        * 
++       *
 +       * The mesh object that is returned must support the operations that
 +       * are expected from editmode objects. The same qualifications regarding
 +       * mesh apply as for applyModifier.
 +       */
 +      struct Mesh *(*applyModifierEM)(struct ModifierData *md, const struct ModifierEvalContext *ctx,
 +                                      struct BMEditMesh *editData,
 +                                      struct Mesh *mesh);
  
  
        /********************* Optional functions *********************/
         *
         * This function is optional.
         */
 -      /* TODO(sergey): Remove once we finally switched to the new depsgraph. */
        void (*updateDepsgraph)(struct ModifierData *md,
                                const ModifierUpdateDepsgraphContext *ctx);
-  
        /* Should return true if the modifier needs to be recalculated on time
         * changes.
         *
Simple merge
@@@ -184,10 -181,9 +184,10 @@@ typedef struct SculptSession 
        int totvert, totpoly;
        struct KeyBlock *kb;
        float *vmask;
-       
        /* Mesh connectivity */
 -      const struct MeshElemMap *pmap;
 +      struct MeshElemMap *pmap;
 +      int *pmap_mem;
  
        /* BMesh for dynamic topology sculpting */
        struct BMesh *bm;
@@@ -61,10 -60,8 +61,10 @@@ struct LinkNode
  struct KDTree;
  struct RNG;
  struct BVHTreeRay;
- struct BVHTreeRayHit; 
+ struct BVHTreeRayHit;
  struct EdgeHash;
 +struct Depsgraph;
 +struct ViewLayer;
  
  #define PARTICLE_COLLISION_MAX_COLLISIONS 10
  
@@@ -346,8 -347,9 +346,8 @@@ void DM_init
        dm->numPolyData = numPolys;
  
        DM_init_funcs(dm);
-       
        dm->needsFree = 1;
 -      dm->auto_bump_scale = -1.0f;
        dm->dirty = 0;
  
        /* don't use CustomData_reset(...); because we dont want to touch customdata */
@@@ -1167,10 -1154,9 +1167,10 @@@ DerivedMesh *mesh_create_derived_for_mo
        const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
        DerivedMesh *dm;
        KeyBlock *kb;
 +      ModifierEvalContext mectx = {depsgraph, ob, 0};
  
        md->scene = scene;
-       
        if (!(md->mode & eModifierMode_Realtime)) {
                return NULL;
        }
  
                if (build_shapekey_layers)
                        add_shapekey_layers(tdm, me, ob);
-               
 -              dm = modwrap_applyModifier(md, ob, tdm, 0);
 +              dm = modwrap_applyModifier(md, &mectx, tdm);
                ASSERT_IS_VALID_DM(dm);
  
                if (tdm != dm) tdm->release(tdm);
@@@ -2130,22 -1878,14 +2130,22 @@@ static void mesh_calc_modifiers
                 * places that wish to use the original mesh but with deformed
                 * coordinates (vpaint, etc.)
                 */
 -              if (r_deform) {
 -                      *r_deform = CDDM_from_mesh(me);
 -
 -                      if (build_shapekey_layers)
 -                              add_shapekey_layers(dm, me, ob);
 +              if (r_deform_mesh) {
 +                      BKE_id_copy_ex(
 +                              NULL, &me->id, (ID **)r_deform_mesh,
 +                              (LIB_ID_CREATE_NO_MAIN |
 +                               LIB_ID_CREATE_NO_USER_REFCOUNT |
 +                               LIB_ID_CREATE_NO_DEG_TAG |
 +                               LIB_ID_COPY_CD_REFERENCE),
 +                              false);
 +
 +                      /* XXX: Is build_shapekey_layers ever even true? This should have crashed long ago... */
 +                      BLI_assert(!build_shapekey_layers);
 +                      //if (build_shapekey_layers)
 +                      //      add_shapekey_layers(*r_deform_mesh, me, ob);
-                       
                        if (deformedVerts) {
 -                              CDDM_apply_vert_coords(*r_deform, deformedVerts);
 +                              BKE_mesh_apply_vert_coords(*r_deform_mesh, deformedVerts);
                        }
                }
        }
  
  
        /* Now apply all remaining modifiers. If useDeform is off then skip
-        * OnlyDeform ones. 
+        * OnlyDeform ones.
         */
 -      dm = NULL;
 -      orcodm = NULL;
 -      clothorcodm = NULL;
 +      Mesh *mesh = NULL;
 +      Mesh *orco_mesh = NULL;
 +      Mesh *cloth_orco_mesh = NULL;
  
        for (; md; md = md->next, curr = curr->next) {
                const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
                                }
                        }
  
-                       
 -                      /* set the DerivedMesh to only copy needed data */
 +                      /* set the Mesh to only copy needed data */
                        mask = curr->mask;
                        /* needMapping check here fixes bug [#28112], otherwise it's
                         * possible that it won't be copied */
@@@ -3170,33 -2790,13 +3170,33 @@@ DerivedMesh *mesh_get_derived_deform(st
  
        return ob->derivedDeform;
  }
 +#endif
 +Mesh *mesh_get_eval_deform(struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask)
 +{
 +      /* if there's no derived mesh or the last data mask used doesn't include
 +       * the data we need, rebuild the derived mesh
 +       */
 +      bool need_mapping;
 +
 +      dataMask |= object_get_datamask(depsgraph, ob, &need_mapping);
 +
 +      if (!ob->runtime.mesh_deform_eval ||
 +          ((dataMask & ob->lastDataMask) != dataMask) ||
 +          (need_mapping != ob->lastNeedMapping))
 +      {
 +              mesh_build_data(depsgraph, scene, ob, dataMask, false, need_mapping);
 +      }
 +
 +      return ob->runtime.mesh_deform_eval;
 +}
  
 -DerivedMesh *mesh_create_derived_render(Scene *scene, Object *ob, CustomDataMask dataMask)
 +
 +DerivedMesh *mesh_create_derived_render(struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask)
  {
        DerivedMesh *final;
-       
 -      mesh_calc_modifiers(
 -              scene, ob, NULL, true, 1, false, dataMask, -1, false, false, false,
 +      mesh_calc_modifiers_dm(
 +              depsgraph, scene, ob, NULL, 1, false, dataMask, -1, false, false, false,
                NULL, &final);
  
        return final;
@@@ -3235,13 -2835,53 +3235,13 @@@ DerivedMesh *mesh_create_derived_view
  }
  
  DerivedMesh *mesh_create_derived_no_deform(
 -        Scene *scene, Object *ob, float (*vertCos)[3],
 -        CustomDataMask dataMask)
 +        struct Depsgraph *depsgraph, Scene *scene, Object *ob,
 +        float (*vertCos)[3], CustomDataMask dataMask)
  {
        DerivedMesh *final;
-       
 -      mesh_calc_modifiers(
 -              scene, ob, vertCos, false, 0, false, dataMask, -1, false, false, false,
 -              NULL, &final);
 -
 -      return final;
 -}
 -
 -DerivedMesh *mesh_create_derived_no_virtual(
 -        Scene *scene, Object *ob, float (*vertCos)[3],
 -        CustomDataMask dataMask)
 -{
 -      DerivedMesh *final;
 -
 -      mesh_calc_modifiers(
 -              scene, ob, vertCos, false, -1, false, dataMask, -1, false, false, false,
 -              NULL, &final);
 -
 -      return final;
 -}
 -
 -DerivedMesh *mesh_create_derived_physics(
 -        Scene *scene, Object *ob, float (*vertCos)[3],
 -        CustomDataMask dataMask)
 -{
 -      DerivedMesh *final;
 -
 -      mesh_calc_modifiers(
 -              scene, ob, vertCos, false, -1, true, dataMask, -1, false, false, false,
 -              NULL, &final);
 -
 -      return final;
 -}
 -
 -DerivedMesh *mesh_create_derived_no_deform_render(
 -        Scene *scene, Object *ob,
 -        float (*vertCos)[3],
 -        CustomDataMask dataMask)
 -{
 -      DerivedMesh *final;
 -
 -      mesh_calc_modifiers(
 -              scene, ob, vertCos, true, 0, false, dataMask, -1, false, false, false,
 +      mesh_calc_modifiers_dm(
 +              depsgraph, scene, ob, vertCos, 0, false, dataMask, -1, false, false, false,
                NULL, &final);
  
        return final;
@@@ -421,12 -420,12 +421,12 @@@ bPoseChannel *BKE_pose_channel_find_nam
  bPoseChannel *BKE_pose_channel_verify(bPose *pose, const char *name)
  {
        bPoseChannel *chan;
-       
        if (pose == NULL)
                return NULL;
-       
        /* See if this channel exists */
 -      chan = BLI_findstring(&pose->chanbase, name, offsetof(bPoseChannel, name));
 +      chan = BKE_pose_channel_find_name(pose, name);
        if (chan) {
                return chan;
        }
        chan->stiffness[0] = chan->stiffness[1] = chan->stiffness[2] = 0.0f;
        chan->ikrotweight = chan->iklinweight = 0.0f;
        unit_m4(chan->constinv);
-       
        chan->protectflag = OB_LOCK_ROT4D;  /* lock by components by default */
-       
        BLI_addtail(&pose->chanbase, chan);
 -      BKE_pose_channels_hash_free(pose);
 +      if (pose->chanhash) {
 +              BLI_ghash_insert(pose->chanhash, chan->name, chan);
 +      }
-       
        return chan;
  }
  
@@@ -584,11 -581,9 +584,11 @@@ void BKE_pose_copy_data_ex(bPose **dst
                if (copy_constraints) {
                        BKE_constraints_copy_ex(&listb, &pchan->constraints, flag, true);  // BKE_constraints_copy NULLs listb
                        pchan->constraints = listb;
 -                      pchan->mpath = NULL; /* motion paths should not get copied yet... */
 +
 +                      /* XXX: This is needed for motionpath drawing to work. Dunno why it was setting to null before... */
 +                      pchan->mpath = animviz_copy_motionpath(pchan->mpath);
                }
-               
                if (pchan->prop) {
                        pchan->prop = IDP_CopyProperty_ex(pchan->prop, flag);
                }
@@@ -1386,10 -1428,10 +1386,10 @@@ void BKE_pose_tag_recalc(Main *bmain, b
        /* Depsgraph components depends on actual pose state,
         * if pose was changed depsgraph is to be updated as well.
         */
 -      DAG_relations_tag_update(bmain);
 +      DEG_relations_tag_update(bmain);
  }
  
- /* For the calculation of the effects of an Action at the given frame on an object 
+ /* For the calculation of the effects of an Action at the given frame on an object
   * This is currently only used for the Action Constraint
   */
  void what_does_obaction(Object *ob, Object *workob, bPose *pose, bAction *act, char groupname[], float cframe)
        }
        else {
                AnimData adt = {NULL};
-               
                /* init animdata, and attach to workob */
                workob->adt = &adt;
-               
                adt.recalc = ADT_RECALC_ANIM;
                adt.action = act;
-               
                /* execute effects of Action on to workob (or it's PoseChannels) */
 -              BKE_animsys_evaluate_animdata(NULL, &workob->id, &adt, cframe, ADT_RECALC_ANIM);
 +              BKE_animsys_evaluate_animdata(NULL, NULL, &workob->id, &adt, cframe, ADT_RECALC_ANIM);
        }
  }
  
@@@ -114,10 -102,6 +114,10 @@@ void animviz_free_motionpath_cache(bMot
        if (mpath->points)
                MEM_freeN(mpath->points);
  
-       
 +      GWN_VERTBUF_DISCARD_SAFE(mpath->points_vbo);
 +      GWN_BATCH_DISCARD_SAFE(mpath->batch_line);
 +      GWN_BATCH_DISCARD_SAFE(mpath->batch_points);
++
        /* reset the relevant parameters */
        mpath->points = NULL;
        mpath->length = 0;
@@@ -262,19 -225,11 +262,19 @@@ bMotionPath *animviz_verify_motionpaths
  /* Motion path needing to be baked (mpt) */
  typedef struct MPathTarget {
        struct MPathTarget *next, *prev;
-       
        bMotionPath *mpath;         /* motion path in question */
  
-       
 +      DLRBT_Tree keys;         /* temp, to know where the keyframes are */
++
 +      /* Original (Source Objects) */
        Object *ob;                 /* source object */
        bPoseChannel *pchan;        /* source posechannel (if applicable) */
-       
++
 +      /* "Evaluated" Copies (these come from the background COW copie
 +       * that provide all the coordinates we want to save off)
 +       */
 +      Object *ob_eval;             /* evaluated object */
  } MPathTarget;
  
  /* ........ */
@@@ -346,38 -368,28 +346,38 @@@ static void motionpaths_calc_bake_targe
        for (mpt = targets->first; mpt; mpt = mpt->next) {
                bMotionPath *mpath = mpt->mpath;
                bMotionPathVert *mpv;
-               
-               /* current frame must be within the range the cache works for 
+               /* current frame must be within the range the cache works for
                 *      - is inclusive of the first frame, but not the last otherwise we get buffer overruns
                 */
 -              if ((CFRA < mpath->start_frame) || (CFRA >= mpath->end_frame))
 +              if ((CFRA < mpath->start_frame) || (CFRA >= mpath->end_frame)) {
                        continue;
-               
 +              }
                /* get the relevant cache vert to write to */
                mpv = mpath->points + (CFRA - mpath->start_frame);
-               
 -              /* pose-channel or object path baking? */
 +              Object *ob_eval = mpt->ob_eval;
 +
 +              /* Lookup evaluated pose channel, here because the depsgraph
 +               * evaluation can change them so they are not cached in mpt. */
 +              bPoseChannel *pchan_eval = NULL;
                if (mpt->pchan) {
 +                      pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, mpt->pchan->name);
 +              }
 +
 +              /* pose-channel or object path baking? */
 +              if (pchan_eval) {
                        /* heads or tails */
                        if (mpath->flag & MOTIONPATH_FLAG_BHEAD) {
 -                              copy_v3_v3(mpv->co, mpt->pchan->pose_head);
 +                              copy_v3_v3(mpv->co, pchan_eval->pose_head);
                        }
                        else {
 -                              copy_v3_v3(mpv->co, mpt->pchan->pose_tail);
 +                              copy_v3_v3(mpv->co, pchan_eval->pose_tail);
                        }
-                       
                        /* result must be in worldspace */
 -                      mul_m4_v3(mpt->ob->obmat, mpv->co);
 +                      mul_m4_v3(ob_eval->obmat, mpv->co);
                }
                else {
                        /* worldspace object location */
                efra = MAX2(efra, mpt->mpath->end_frame);
        }
        if (efra <= sfra) return;
-       
-       
 -      /* optimize the depsgraph for faster updates */
 -      /* TODO: whether this is used should depend on some setting for the level of optimizations used */
 -      motionpaths_calc_optimise_depsgraph(bmain, scene, targets);
++
 +      /* get copies of objects/bones to get the calculated results from
 +       * (for copy-on-write evaluation), so that we actually get some results
 +       */
 +      // TODO: Create a copy of background depsgraph that only contain these entities, and only evaluates them..
 +      for (mpt = targets->first; mpt; mpt = mpt->next) {
 +              mpt->ob_eval = DEG_get_evaluated_object(depsgraph, mpt->ob);
 +
 +              AnimData *adt = BKE_animdata_from_id(&mpt->ob_eval->id);
 +
 +              /* build list of all keyframes in active action for object or pchan */
 +              BLI_dlrbTree_init(&mpt->keys);
 +
 +              if (adt) {
 +                      bAnimVizSettings *avs;
 +
 +                      /* get pointer to animviz settings for each target */
 +                      if (mpt->pchan)
 +                              avs = &mpt->ob->pose->avs;
 +                      else
 +                              avs = &mpt->ob->avs;
 +
 +                      /* it is assumed that keyframes for bones are all grouped in a single group
 +                       * unless an option is set to always use the whole action
 +                       */
 +                      if ((mpt->pchan) && (avs->path_viewflag & MOTIONPATH_VIEW_KFACT) == 0) {
 +                              bActionGroup *agrp = BKE_action_group_find_name(adt->action, mpt->pchan->name);
 +
 +                              if (agrp) {
 +                                      agroup_to_keylist(adt, agrp, &mpt->keys, NULL);
 +                                      BLI_dlrbTree_linkedlist_sync(&mpt->keys);
 +                              }
 +                      }
 +                      else {
 +                              action_to_keylist(adt, adt->action, &mpt->keys, NULL);
 +                              BLI_dlrbTree_linkedlist_sync(&mpt->keys);
 +                      }
 +              }
 +      }
  
        /* calculate path over requested range */
        for (CFRA = sfra; CFRA <= efra; CFRA++) {
                /* perform baking for targets */
                motionpaths_calc_bake_targets(scene, targets);
        }
-       
        /* reset original environment */
 +      // XXX: Soon to be obsolete
        CFRA = cfra;
 -      motionpaths_calc_update_scene(bmain, scene);
 +      motionpaths_calc_update_scene(bmain, depsgraph);
-       
        /* clear recalc flags from targets */
        for (mpt = targets->first; mpt; mpt = mpt->next) {
                bAnimVizSettings *avs;
-               
 +              bMotionPath *mpath = mpt->mpath;
                /* get pointer to animviz settings for each target */
                if (mpt->pchan)
                        avs = &mpt->ob->pose->avs;
                else
                        avs = &mpt->ob->avs;
-               
                /* clear the flag requesting recalculation of targets */
                avs->recalc &= ~ANIMVIZ_RECALC_PATHS;
 +
 +              /* Clean temp data */
 +              BLI_dlrbTree_free(&mpt->keys);
 +
 +              /* Free previous batches to force update. */
 +              GWN_VERTBUF_DISCARD_SAFE(mpath->points_vbo);
 +              GWN_BATCH_DISCARD_SAFE(mpath->batch_line);
 +              GWN_BATCH_DISCARD_SAFE(mpath->batch_points);
        }
  }
  
@@@ -251,12 -250,9 +251,12 @@@ void BKE_animdata_free(ID *id, const bo
                        /* free drivers - stored as a list of F-Curves */
                        free_fcurves(&adt->drivers);
  
-                       
 +                      /* free driver array cache */
 +                      MEM_SAFE_FREE(adt->driver_array);
++
                        /* free overrides */
                        /* TODO... */
-                       
                        /* free animdata now */
                        MEM_freeN(adt);
                        iat->adt = NULL;
  /* Copying -------------------------------------------- */
  
  /* Make a copy of the given AnimData - to be used when copying datablocks */
 -AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const bool do_action)
 +AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const bool do_action, const bool do_id_user)
  {
        AnimData *dadt;
-       
        /* sanity check before duplicating struct */
        if (adt == NULL)
                return NULL;
  
        /* duplicate NLA data */
        BKE_nla_tracks_copy(bmain, &dadt->nla_tracks, &adt->nla_tracks);
-       
        /* duplicate drivers (F-Curves) */
        copy_fcurves(&dadt->drivers, &adt->drivers);
-       
 +      dadt->driver_array = NULL;
        /* don't copy overrides */
        BLI_listbase_clear(&dadt->overrides);
-       
        /* return */
        return dadt;
  }
@@@ -1862,16 -1831,11 +1862,16 @@@ static void animsys_evaluate_action_ex
        /* check if mapper is appropriate for use here (we set to NULL if it's inappropriate) */
        if (act == NULL) return;
        if ((remap) && (remap->target != act)) remap = NULL;
-       
        action_idcode_patch_check(ptr->id.data, act);
-       
        /* calculate then execute each curve */
 -      animsys_evaluate_fcurves(ptr, &act->curves, remap, ctime);
 +      animsys_evaluate_fcurves(depsgraph, ptr, &act->curves, remap, ctime);
 +}
 +
 +void animsys_evaluate_action(Depsgraph *depsgraph, PointerRNA *ptr, bAction *act, AnimMapper *remap, float ctime)
 +{
 +      animsys_evaluate_action_ex(depsgraph, ptr, act, remap, ctime);
  }
  
  /* ***************************************** */
@@@ -1905,14 -1869,14 +1905,14 @@@ static void nlastrip_evaluate_controls(
        /* now strip's evaluate F-Curves for these settings (if applicable) */
        if (strip->fcurves.first) {
                PointerRNA strip_ptr;
-               
                /* create RNA-pointer needed to set values */
                RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr);
-               
                /* execute these settings as per normal */
 -              animsys_evaluate_fcurves(&strip_ptr, &strip->fcurves, NULL, ctime);
 +              animsys_evaluate_fcurves(depsgraph, &strip_ptr, &strip->fcurves, NULL, ctime);
        }
-       
        /* analytically generate values for influence and time (if applicable)
         *  - we do this after the F-Curves have been evaluated to override the effects of those
         *    in case the override has been turned off.
@@@ -2009,10 -1973,10 +2009,10 @@@ NlaEvalStrip *nlastrips_ctime_get_strip
         *      - negative influence is not supported yet... how would that be defined?
         */
        /* TODO: this sounds a bit hacky having a few isolated F-Curves stuck on some data it operates on... */
 -      nlastrip_evaluate_controls(estrip, ctime);
 +      nlastrip_evaluate_controls(depsgraph, estrip, ctime);
        if (estrip->influence <= 0.0f)
                return NULL;
-               
        /* check if strip has valid data to evaluate,
         * and/or perform any additional type-specific actions
         */
                        /* there must be strips to transition from and to (i.e. prev and next required) */
                        if (ELEM(NULL, estrip->prev, estrip->next))
                                return NULL;
-                               
                        /* evaluate controls for the relevant extents of the bordering strips... */
 -                      nlastrip_evaluate_controls(estrip->prev, estrip->start);
 -                      nlastrip_evaluate_controls(estrip->next, estrip->end);
 +                      nlastrip_evaluate_controls(depsgraph, estrip->prev, estrip->start);
 +                      nlastrip_evaluate_controls(depsgraph, estrip->next, estrip->end);
                        break;
        }
-       
        /* add to list of strips we need to evaluate */
        nes = MEM_callocN(sizeof(NlaEvalStrip), "NlaEvalStrip");
-       
        nes->strip = estrip;
        nes->strip_mode = side;
        nes->track_index = index;
@@@ -2416,17 -2379,17 +2416,17 @@@ static void nlastrip_evaluate_transitio
        /* first strip */
        tmp_nes.strip_mode = NES_TIME_TRANSITION_START;
        tmp_nes.strip = s1;
 -      nlastrip_evaluate(ptr, &tmp_channels, &tmp_modifiers, &tmp_nes);
 +      nlastrip_evaluate(depsgraph, ptr, &tmp_channels, &tmp_modifiers, &tmp_nes);
-       
        /* second strip */
        tmp_nes.strip_mode = NES_TIME_TRANSITION_END;
        tmp_nes.strip = s2;
 -      nlastrip_evaluate(ptr, &tmp_channels, &tmp_modifiers, &tmp_nes);
 +      nlastrip_evaluate(depsgraph, ptr, &tmp_channels, &tmp_modifiers, &tmp_nes);
-       
-       
        /* accumulate temp-buffer and full-buffer, using the 'real' strip */
        nlaevalchan_buffers_accumulate(channels, &tmp_channels, nes);
-       
        /* unlink this strip's modifiers from the parent's modifiers again */
        nlaeval_fmodifiers_split_stacks(&nes->strip->modifiers, modifiers);
  }
@@@ -2447,20 -2409,20 +2447,20 @@@ static void nlastrip_evaluate_meta
         *
         * NOTE: keep this in sync with animsys_evaluate_nla()
         */
-       
        /* join this strip's modifiers to the parent's modifiers (own modifiers first) */
-       nlaeval_fmodifiers_join_stacks(&tmp_modifiers, &strip->modifiers, modifiers); 
-       
+       nlaeval_fmodifiers_join_stacks(&tmp_modifiers, &strip->modifiers, modifiers);
        /* find the child-strip to evaluate */
        evaltime = (nes->strip_time * (strip->end - strip->start)) + strip->start;
 -      tmp_nes = nlastrips_ctime_get_strip(NULL, &strip->strips, -1, evaltime);
 +      tmp_nes = nlastrips_ctime_get_strip(depsgraph, NULL, &strip->strips, -1, evaltime);
-       
-       /* directly evaluate child strip into accumulation buffer... 
+       /* directly evaluate child strip into accumulation buffer...
         * - there's no need to use a temporary buffer (as it causes issues [T40082])
         */
        if (tmp_nes) {
 -              nlastrip_evaluate(ptr, channels, &tmp_modifiers, tmp_nes);
 +              nlastrip_evaluate(depsgraph, ptr, channels, &tmp_modifiers, tmp_nes);
-               
                /* free temp eval-strip */
                MEM_freeN(tmp_nes);
        }
  }
  
  /* evaluates the given evaluation strip */
 -void nlastrip_evaluate(PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes)
 +void nlastrip_evaluate(Depsgraph *depsgraph, PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes)
  {
        NlaStrip *strip = nes->strip;
-       
        /* to prevent potential infinite recursion problems (i.e. transition strip, beside meta strip containing a transition
         * several levels deep inside it), we tag the current strip as being evaluated, and clear this when we leave
         */
                        nlastrip_evaluate_actionclip(ptr, channels, modifiers, nes);
                        break;
                case NLASTRIP_TYPE_TRANSITION: /* transition */
 -                      nlastrip_evaluate_transition(ptr, channels, modifiers, nes);
 +                      nlastrip_evaluate_transition(depsgraph, ptr, channels, modifiers, nes);
                        break;
                case NLASTRIP_TYPE_META: /* meta */
 -                      nlastrip_evaluate_meta(ptr, channels, modifiers, nes);
 +                      nlastrip_evaluate_meta(depsgraph, ptr, channels, modifiers, nes);
                        break;
-                       
                default: /* do nothing */
                        break;
        }
@@@ -2593,15 -2555,15 +2593,15 @@@ static void animsys_evaluate_nla(Depsgr
                 */
                if (nlt->strips.first)
                        has_strips = true;
-                       
                /* otherwise, get strip to evaluate for this channel */
 -              nes = nlastrips_ctime_get_strip(&estrips, &nlt->strips, track_index, ctime);
 +              nes = nlastrips_ctime_get_strip(depsgraph, &estrips, &nlt->strips, track_index, ctime);
                if (nes) nes->track = nlt;
        }
-       
        /* add 'active' Action (may be tweaking track) as last strip to evaluate in NLA stack
         *      - only do this if we're not exclusively evaluating the 'solo' NLA-track
-        *      - however, if the 'solo' track houses the current 'tweaking' strip, 
+        *      - however, if the 'solo' track houses the current 'tweaking' strip,
         *        then we should allow this to play, otherwise nothing happens
         */
        if ((adt->action) && ((adt->flag & ADT_NLA_SOLO_TRACK) == 0 || (adt->flag & ADT_NLA_EDIT_ON))) {
                                /* NOTE: must set this, or else the default setting overrides, and this setting doesn't work */
                                dummy_strip.flag |= NLASTRIP_FLAG_USR_INFLUENCE;
                        }
-                       
                        /* add this to our list of evaluation strips */
 -                      nlastrips_ctime_get_strip(&estrips, &dummy_trackslist, -1, ctime);
 +                      nlastrips_ctime_get_strip(depsgraph, &estrips, &dummy_trackslist, -1, ctime);
                }
                else {
                        /* special case - evaluate as if there isn't any NLA data */
                        /* TODO: this is really just a stop-gap measure... */
                        if (G.debug & G_DEBUG) printf("NLA Eval: Stopgap for active action on NLA Stack - no strips case\n");
-                       
 -                      animsys_evaluate_action(ptr, adt->action, adt->remap, ctime);
 +                      animsys_evaluate_action(depsgraph, ptr, adt->action, adt->remap, ctime);
                        BLI_freelistN(&estrips);
                        return;
                }
        /* only continue if there are strips to evaluate */
        if (BLI_listbase_is_empty(&estrips))
                return;
-       
-       
        /* 2. for each strip, evaluate then accumulate on top of existing channels, but don't set values yet */
        for (nes = estrips.first; nes; nes = nes->next)
 -              nlastrip_evaluate(ptr, echannels, NULL, nes);
 +              nlastrip_evaluate(depsgraph, ptr, echannels, NULL, nes);
-               
        /* 3. free temporary evaluation data that's not used elsewhere */
        BLI_freelistN(&estrips);
 -
 -      /* Tag ID as updated so render engines will recognize changes in data
 -       * which is animated but doesn't have actions.
 -       */
 -      if (ptr->id.data != NULL) {
 -              ID *id = ptr->id.data;
 -              if (!(id->recalc & ID_RECALC_SKIP_ANIM_TAG)) {
 -                      id->recalc |= ID_RECALC;
 -                      DAG_id_type_tag(G.main, GS(id->name));
 -              }
 -      }
  }
  
- /* NLA Evaluation function (mostly for use through do_animdata) 
+ /* NLA Evaluation function (mostly for use through do_animdata)
   *    - All channels that will be affected are not cleared anymore. Instead, we just evaluate into
   *            some temp channels, where values can be accumulated in one go.
   */
@@@ -2674,11 -2647,11 +2674,11 @@@ static void animsys_calculate_nla(Depsg
         * and also when the user jumps between different times instead of moving sequentially... */
  
        /* evaluate the NLA stack, obtaining a set of values to flush */
 -      animsys_evaluate_nla(&echannels, ptr, adt, ctime);
 +      animsys_evaluate_nla(depsgraph, &echannels, ptr, adt, ctime);
-       
        /* flush effects of accumulating channels in NLA to the actual data they affect */
        nladata_flush_channels(&echannels);
-       
        /* free temp data */
        BLI_freelistN(&echannels);
  }
@@@ -2753,10 -2726,10 +2753,10 @@@ static void animsys_evaluate_overrides(
   * and that the flags for which parts of the anim-data settings need to be recalculated
   * have been set already by the depsgraph. Now, we use the recalc
   */
 -void BKE_animsys_evaluate_animdata(Scene *scene, ID *id, AnimData *adt, float ctime, short recalc)
 +void BKE_animsys_evaluate_animdata(Depsgraph *depsgraph, Scene *scene, ID *id, AnimData *adt, float ctime, short recalc)
  {
        PointerRNA id_ptr;
-       
        /* sanity checks */
        if (ELEM(NULL, id, adt))
                return;
        if ((recalc & ADT_RECALC_ANIM) || (adt->recalc & ADT_RECALC_ANIM)) {
                /* evaluate NLA data */
                if ((adt->nla_tracks.first) && !(adt->flag & ADT_NLA_EVAL_OFF)) {
-                       /* evaluate NLA-stack 
+                       /* evaluate NLA-stack
                         *      - active action is evaluated as part of the NLA stack as the last item
                         */
 -                      animsys_calculate_nla(&id_ptr, adt, ctime);
 +                      animsys_calculate_nla(depsgraph, &id_ptr, adt, ctime);
                }
                /* evaluate Active Action only */
                else if (adt->action)
 -                      animsys_evaluate_action(&id_ptr, adt->action, adt->remap, ctime);
 +                      animsys_evaluate_action_ex(depsgraph, &id_ptr, adt->action, adt->remap, ctime);
-               
                /* reset tag */
                adt->recalc &= ~ADT_RECALC_ANIM;
        }
@@@ -2856,15 -2829,15 +2856,15 @@@ void BKE_animsys_evaluate_all_animation
                        NtId_Type *ntp = (NtId_Type *)id; \
                        if (ntp->nodetree) { \
                                AnimData *adt2 = BKE_animdata_from_id((ID *)ntp->nodetree); \
 -                              BKE_animsys_evaluate_animdata(scene, (ID *)ntp->nodetree, adt2, ctime, ADT_RECALC_ANIM); \
 +                              BKE_animsys_evaluate_animdata(depsgraph, scene, (ID *)ntp->nodetree, adt2, ctime, ADT_RECALC_ANIM); \
                        } \
 -                      BKE_animsys_evaluate_animdata(scene, id, adt, ctime, aflag); \
 +                      BKE_animsys_evaluate_animdata(depsgraph, scene, id, adt, ctime, aflag); \
                } \
        } (void)0
-       
-       /* optimization: 
-        * when there are no actions, don't go over database and loop over heaps of datablocks, 
-        * which should ultimately be empty, since it is not possible for now to have any animation 
+       /* optimization:
+        * when there are no actions, don't go over database and loop over heaps of datablocks,
+        * which should ultimately be empty, since it is not possible for now to have any animation
         * without some actions, and drivers wouldn't get affected by any state changes
         *
         * however, if there are some curves, we will need to make sure that their 'ctime' property gets
@@@ -112,12 -113,10 +112,12 @@@ static void splineik_init_tree_from_pch
                 *       currently for paths to work it needs to go through the bevlist/displist system (ton)
                 */
  
 +              /* TODO: Make sure this doesn't crash. */
 +#if 0
                /* only happens on reload file, but violates depsgraph still... fix! */
                if (ELEM(NULL,  ikData->tar->curve_cache, ikData->tar->curve_cache->path, ikData->tar->curve_cache->path->data)) {
 -                      BKE_displist_make_curveTypes(scene, ikData->tar, 0);
 +                      BKE_displist_make_curveTypes(depsgraph, scene, ikData->tar, 0);
-                       
                        /* path building may fail in EditMode after removing verts [#33268]*/
                        if (ELEM(NULL, ikData->tar->curve_cache->path, ikData->tar->curve_cache->path->data)) {
                                /* BLI_assert(cu->path != NULL); */
@@@ -94,10 -92,10 +94,10 @@@ void BKE_blender_free(void
        IMB_exit();
        BKE_cachefiles_exit();
        BKE_images_exit();
 -      DAG_exit();
 +      DEG_free_node_types();
  
        BKE_brush_system_exit();
-       RE_texture_rng_exit();  
+       RE_texture_rng_exit();
  
        BLI_callback_global_finalize();
  
@@@ -721,9 -2179,12 +721,9 @@@ static void loops_to_customdata_corners
        MLoopUV *mloopuv;
        int i, j, hasPCol = CustomData_has_layer(&bm->ldata, CD_PREVIEW_MLOOPCOL);
  
 -      for (i = 0; i < numTex; i++) {
 +      for (i = 0; i < numUV; i++) {
                texface = CustomData_get_n(facedata, CD_MTFACE, cdindex, i);
-       
 -              texpoly = CustomData_bmesh_get_n(&bm->pdata, f->head.data, CD_MTEXPOLY, i);
 -
 -              ME_MTEXFACE_CPY(texface, texpoly);
                for (j = 0; j < 3; j++) {
                        l = l3[j];
                        mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPUV, i);
@@@ -690,10 -688,10 +690,10 @@@ static void cloth_apply_vgroup ( ClothM
  
        clothObj = clmd->clothObject;
  
 -      mvert_num = dm->getNumVerts(dm);
 +      mvert_num = mesh->totvert;
  
        verts = clothObj->verts;
-       
        if (cloth_uses_vgroup(clmd)) {
                for (i = 0; i < mvert_num; i++, verts++) {
  
@@@ -859,12 -857,12 +859,12 @@@ static int cloth_from_object(Object *ob
                verts->impulse_count = 0;
                copy_v3_v3 ( verts->impulse, tnull );
        }
-       
        // apply / set vertex groups
        // has to be happen before springs are build!
 -      cloth_apply_vgroup (clmd, dm);
 +      cloth_apply_vgroup (clmd, mesh);
  
 -      if ( !cloth_build_springs ( clmd, dm ) ) {
 +      if ( !cloth_build_springs ( clmd, mesh ) ) {
                cloth_free_modifier ( clmd );
                modifier_setError(&(clmd->modifier), "Cannot build springs");
                printf("cloth_free_modifier cloth_build_springs\n");
                BKE_cloth_solver_set_positions(clmd);
  
        clmd->clothObject->bvhtree = bvhtree_build_from_cloth ( clmd, MAX2(clmd->coll_parms->epsilon, clmd->coll_parms->distance_repel) );
-       
 -      for (i = 0; i < dm->getNumVerts(dm); i++) {
 +      for (i = 0; i < mesh->totvert; i++) {
                maxdist = MAX2(maxdist, clmd->coll_parms->selfepsilon* ( cloth->verts[i].avg_spring_len*2.0f));
        }
-       
        clmd->clothObject->bvhselftree = bvhselftree_build_from_cloth ( clmd, maxdist );
  
        return 1;
@@@ -515,13 -511,15 +515,13 @@@ static void add_collision_object(Objec
  }
  
  // return all collision objects in scene
- // collision object will exclude self 
+ // collision object will exclude self
 -Object **get_collisionobjects_ext(Scene *scene, Object *self, Group *group, int layer, unsigned int *numcollobj, unsigned int modifier_type, bool dupli)
 +Object **get_collisionobjects_ext(Scene *scene, Object *self, Collection *collection, unsigned int *numcollobj, unsigned int modifier_type, bool dupli)
  {
 -      Base *base;
        Object **objs;
 -      GroupObject *go;
        unsigned int numobj= 0, maxobj= 100;
        int level = dupli ? 0 : 1;
-       
        objs= MEM_callocN(sizeof(Object *)*maxobj, "CollisionObjectsArray");
  
        /* gather all collision objects */
@@@ -592,17 -584,15 +592,17 @@@ static void add_collider_cache_object(L
        }
  }
  
 -ListBase *get_collider_cache(Scene *scene, Object *self, Group *group)
 +ListBase *get_collider_cache(Scene *scene, Object *self, Collection *collection)
  {
 -      GroupObject *go;
        ListBase *objs= NULL;
-       
        /* add object in same layer in scene */
 -      if (group) {
 -              for (go= group->gobject.first; go; go= go->next)
 -                      add_collider_cache_object(&objs, go->ob, self, 0);
 +      if (collection) {
 +              FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(collection, object)
 +              {
 +                      add_collider_cache_object(&objs, object, self, 0);
 +              }
 +              FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
        }
        else {
                Scene *sce_iter;
@@@ -119,17 -121,16 +119,17 @@@ void BKE_constraint_unique_name(bConstr
  
  /* package an object/bone for use in constraint evaluation */
  /* This function MEM_calloc's a bConstraintOb struct, that will need to be freed after evaluation */
 -bConstraintOb *BKE_constraints_make_evalob(Scene *scene, Object *ob, void *subdata, short datatype)
 +bConstraintOb *BKE_constraints_make_evalob(Depsgraph *depsgraph, Scene *scene, Object *ob, void *subdata, short datatype)
  {
        bConstraintOb *cob;
-       
        /* create regardless of whether we have any data! */
        cob = MEM_callocN(sizeof(bConstraintOb), "bConstraintOb");
-       
        /* for system time, part of deglobalization, code nicer later with local time (ton) */
        cob->scene = scene;
-       
 +      cob->depsgraph = depsgraph;
        /* based on type of available data */
        switch (datatype) {
                case CONSTRAINT_OBTYPE_OBJECT:
@@@ -685,10 -686,10 +685,10 @@@ static bConstraintTypeInfo CTI_CONSTRNA
  };
  #endif
  
- /* This function should be used for the get_target_matrix member of all 
+ /* This function should be used for the get_target_matrix member of all
   * constraints that are not picky about what happens to their target matrix.
   */
 -static void default_get_tarmat(bConstraint *con, bConstraintOb *UNUSED(cob), bConstraintTarget *ct, float UNUSED(ctime))
 +static void default_get_tarmat(struct Depsgraph *UNUSED(depsgraph), bConstraint *con, bConstraintOb *UNUSED(cob), bConstraintTarget *ct, float UNUSED(ctime))
  {
        if (VALID_CONS_TARGET(ct))
                constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail);
@@@ -1157,11 -1158,11 +1157,11 @@@ static void kinematic_flush_tars(bConst
        }
  }
  
 -static void kinematic_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
 +static void kinematic_get_tarmat(struct Depsgraph *UNUSED(depsgraph), bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
  {
        bKinematicConstraint *data = con->data;
-       
-       if (VALID_CONS_TARGET(ct)) 
+       if (VALID_CONS_TARGET(ct))
                constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail);
        else if (ct) {
                if (data->flag & CONSTRAINT_IK_AUTO) {
@@@ -1244,12 -1245,10 +1244,12 @@@ static void followpath_flush_tars(bCons
        }
  }
  
 -static void followpath_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
 +static void followpath_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
 +                                  bConstraint *con, bConstraintOb *UNUSED(cob),
 +                                  bConstraintTarget *ct, float UNUSED(ctime))
  {
        bFollowPathConstraint *data = con->data;
-       
        if (VALID_CONS_TARGET(ct) && (ct->tar->type == OB_CURVE)) {
                Curve *cu = ct->tar->data;
                float vec[4], dir[3], radius;
                unit_m4(ct->matrix);
  
                /* note: when creating constraints that follow path, the curve gets the CU_PATH set now,
-                *              currently for paths to work it needs to go through the bevlist/displist system (ton) 
+                *              currently for paths to work it needs to go through the bevlist/displist system (ton)
                 */
  
 -#ifdef CYCLIC_DEPENDENCY_WORKAROUND
 -              if (ct->tar->curve_cache == NULL) {
 -                      BKE_displist_make_curveTypes(cob->scene, ct->tar, false);
 -              }
 -#endif
 -
 -              if (ct->tar->curve_cache->path && ct->tar->curve_cache->path->data) {
 +              if (ct->tar->curve_cache && ct->tar->curve_cache->path && ct->tar->curve_cache->path->data) {
                        float quat[4];
                        if ((data->followflag & FOLLOWPATH_STATIC) == 0) {
                                /* animated position along curve depending on time */
@@@ -2139,10 -2146,10 +2139,10 @@@ static void actcon_flush_tars(bConstrai
        }
  }
  
 -static void actcon_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
 +static void actcon_get_tarmat(struct Depsgraph *UNUSED(depsgraph), bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
  {
        bActionConstraint *data = con->data;
-       
        if (VALID_CONS_TARGET(ct)) {
                float tempmat[4][4], vec[3];
                float s, t;
@@@ -3405,10 -3478,10 +3405,10 @@@ static void shrinkwrap_flush_tars(bCons
  }
  
  
 -static void shrinkwrap_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
 +static void shrinkwrap_get_tarmat(struct Depsgraph *UNUSED(depsgraph), bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
  {
        bShrinkwrapConstraint *scon = (bShrinkwrapConstraint *) con->data;
-       
        if (VALID_CONS_TARGET(ct) && (ct->tar->type == OB_MESH) ) {
                bool fail = false;
                float co[3] = {0.0f, 0.0f, 0.0f};
@@@ -4853,19 -4909,19 +4853,19 @@@ void BKE_constraint_target_matrix_get(s
                                break;
                        }
                }
-               
                /* get targets - we only need the first one though (and there should only be one) */
                cti->get_constraint_targets(con, &targets);
-               
                /* only calculate the target matrix on the first target */
                ct = (bConstraintTarget *)BLI_findlink(&targets, index);
-               
                if (ct) {
                        if (cti->get_target_matrix)
 -                              cti->get_target_matrix(con, cob, ct, ctime);
 +                              cti->get_target_matrix(depsgraph, con, cob, ct, ctime);
                        copy_m4_m4(mat, ct->matrix);
                }
-               
                /* free targets + 'constraint-ob' */
                if (cti->flush_constraint_targets)
                        cti->flush_constraint_targets(con, &targets, 1);
  }
  
  /* Get the list of targets required for solving a constraint */
 -void BKE_constraint_targets_for_solving_get(bConstraint *con, bConstraintOb *cob, ListBase *targets, float ctime)
 +void BKE_constraint_targets_for_solving_get(struct Depsgraph *depsgraph, bConstraint *con, bConstraintOb *cob, ListBase *targets, float ctime)
  {
        const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
-       
        if (cti && cti->get_constraint_targets) {
                bConstraintTarget *ct;
-               
-               /* get targets 
+               /* get targets
                 *  - constraints should use ct->matrix, not directly accessing values
-                *      - ct->matrix members have not yet been calculated here! 
+                *      - ct->matrix members have not yet been calculated here!
                 */
                cti->get_constraint_targets(con, targets);
-               
-               /* set matrices 
+               /* set matrices
                 *  - calculate if possible, otherwise just initialize as identity matrix
                 */
                if (cti->get_target_matrix) {
@@@ -4940,20 -4996,20 +4940,20 @@@ void BKE_constraints_solve(struct Depsg
                 *  - value should have been set from animation data already
                 */
                enf = con->enforce;
-               
                /* make copy of worldspace matrix pre-constraint for use with blending later */
                copy_m4_m4(oldmat, cob->matrix);
-               
                /* move owner matrix into right space */
                BKE_constraint_mat_convertspace(cob->ob, cob->pchan, cob->matrix, CONSTRAINT_SPACE_WORLD, con->ownspace, false);
-               
                /* prepare targets for constraint solving */
 -              BKE_constraint_targets_for_solving_get(con, cob, &targets, ctime);
 +              BKE_constraint_targets_for_solving_get(depsgraph, con, cob, &targets, ctime);
-               
                /* Solve the constraint and put result in cob->matrix */
                cti->evaluate_constraint(con, cob, &targets);
-               
-               /* clear targets after use 
+               /* clear targets after use
                 *      - this should free temp targets but no data should be copied back
                 *        as constraints may have done some nasty things to it...
                 */
@@@ -1219,12 -1228,13 +1219,12 @@@ static const LayerTypeInfo LAYERTYPEINF
         layerInterp_origspace_face, layerSwap_origspace_face, layerDefault_origspace_face},
        /* 14: CD_ORCO */
        {sizeof(float) * 3, "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
 -      /* 15: CD_MTEXPOLY */
 +      /* 15: CD_MTEXPOLY */  /* DEPRECATED */
        /* note, when we expose the UV Map / TexFace split to the user, change this back to face Texture */
 -      {sizeof(MTexPoly), "MTexPoly", 1, N_("UVMap") /* "Face Texture" */, NULL, NULL, NULL, NULL, NULL,
 -       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, layerMaxNum_tface},
 +      {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
        /* 16: CD_MLOOPUV */
        {sizeof(MLoopUV), "MLoopUV", 1, N_("UVMap"), NULL, NULL, layerInterp_mloopuv, NULL, NULL,
-        layerEqual_mloopuv, layerMultiply_mloopuv, layerInitMinMax_mloopuv, 
+        layerEqual_mloopuv, layerMultiply_mloopuv, layerInitMinMax_mloopuv,
         layerAdd_mloopuv, layerDoMinMax_mloopuv, layerCopyValue_mloopuv, NULL, NULL, NULL, layerMaxNum_tface},
        /* 17: CD_MLOOPCOL */
        {sizeof(MLoopCol), "MLoopCol", 1, N_("Col"), NULL, NULL, layerInterp_mloopcol, NULL,
@@@ -1920,12 -1925,11 +1920,12 @@@ void *CustomData_add_layer
  }
  
  /*same as above but accepts a name*/
 -void *CustomData_add_layer_named(CustomData *data, int type, int alloctype,
 -                                 void *layerdata, int totelem, const char *name)
 +void *CustomData_add_layer_named(
 +        CustomData *data, int type, eCDAllocType alloctype,
 +        void *layerdata, int totelem, const char *name)
  {
        CustomDataLayer *layer;
-       
        layer = customData_add_layer__internal(data, type, alloctype, layerdata,
                                               totelem, name);
        CustomData_update_typemap(data);
@@@ -1922,16 -1922,15 +1922,16 @@@ float driver_get_variable_value(Channel
  /* Evaluate an Channel-Driver to get a 'time' value to use instead of "evaltime"
   *    - "evaltime" is the frame at which F-Curve is being evaluated
   *  - has to return a float value
 + *  - driver_orig is where we cache Python expressions, in case of COW
   */
 -float evaluate_driver(PathResolvedRNA *anim_rna, ChannelDriver *driver, const float evaltime)
 +float evaluate_driver(PathResolvedRNA *anim_rna, ChannelDriver *driver, ChannelDriver *driver_orig, const float evaltime)
  {
        DriverVar *dvar;
-       
        /* check if driver can be evaluated */
 -      if (driver->flag & DRIVER_FLAG_INVALID)
 +      if (driver_orig->flag & DRIVER_FLAG_INVALID)
                return 0.0f;
-       
        switch (driver->type) {
                case DRIVER_TYPE_AVERAGE: /* average values of driver targets */
                case DRIVER_TYPE_SUM: /* sum values of driver targets */
@@@ -161,8 -173,11 +161,8 @@@ static AdrBit2Path *adrcode_bitmaps_to_
        if ((blocktype == ID_OB) && (adrcode == OB_LAY)) {
                RET_ABP(ob_layer_bits);
        }
 -      else if ((blocktype == ID_MA) && (adrcode == MA_MODE)) {
 -              RET_ABP(ma_mode_bits);
 -      }
        // XXX TODO: add other types...
-       
        /* Normal curve */
        return NULL;
  }
@@@ -1753,9 -1768,26 +1753,9 @@@ void do_versions_ipos_to_animato(Main *
                                ipo_to_animdata(bmain, id, ob->ipo, NULL, NULL, NULL);
                                id_us_min(&ob->ipo->id);
                                ob->ipo = NULL;
 -
 -                              {
 -                                      /* If we have any empty action actuators, assume they were
 -                                       * converted IPO Actuators using the object IPO */
 -                                      bActuator *act;
 -                                      bActionActuator *aa;
 -
 -                                      for (act = ob->actuators.first; act; act = act->next) {
 -                                              /* Any actuators set to ACT_IPO at this point are actually Action Actuators that
 -                                               * need this converted IPO to finish converting the actuator. */
 -                                              if (act->type == ACT_IPO) {
 -                                                      aa = (bActionActuator *)act->data;
 -                                                      aa->act = ob->adt->action;
 -                                                      act->type = ACT_ACTION;
 -                                              }
 -                                      }
 -                              }
                        }
                }
-               
                /* check PoseChannels for constraints with local data */
                if (ob->pose) {
                        /* Verify if there's AnimData block */
@@@ -80,16 -84,23 +80,16 @@@ void BKE_lamp_init(Lamp *la
        la->coeff_lin = 0.0f;
        la->coeff_quad = 0.0f;
        la->curfalloff = curvemapping_add(1, 0.0f, 1.0f, 1.0f, 0.0f);
 -      la->sun_effect_type = 0;
 -      la->horizon_brightness = 1.0;
 -      la->spread = 1.0;
 -      la->sun_brightness = 1.0;
 -      la->sun_size = 1.0;
 -      la->backscattered_light = 1.0f;
 -      la->atm_turbidity = 2.0f;
 -      la->atm_inscattering_factor = 1.0f;
 -      la->atm_extinction_factor = 1.0f;
 -      la->atm_distance_factor = 1.0f;
 -      la->sun_intensity = 1.0f;
 -      la->skyblendtype = MA_RAMP_ADD;
 -      la->skyblendfac = 1.0f;
 -      la->sky_colorspace = BLI_XYZ_CIE;
 -      la->sky_exposure = 1.0f;
 -      la->shadow_frustum_size = 10.0f;
 +      la->cascade_max_dist = 1000.0f;
 +      la->cascade_count = 4;
 +      la->cascade_exponent = 0.8f;
 +      la->cascade_fade = 0.1f;
 +      la->contact_dist = 1.0f;
 +      la->contact_bias = 0.03f;
 +      la->contact_spread = 0.2f;
 +      la->contact_thickness = 0.5f;
 +      la->spec_fac = 1.0f;
-       
        curvemapping_initialize(la->curfalloff);
  }
  
@@@ -809,10 -810,10 +809,10 @@@ void curve_deform_verts
                                mul_m4_v3(cd.curvespace, vertexCos[a]);
                                minmax_v3v3_v3(cd.dmin, cd.dmax, vertexCos[a]);
                        }
-       
                        for (a = 0; a < numVerts; a++) {
                                /* already in 'cd.curvespace', prev for loop */
 -                              calc_curve_deform(scene, cuOb, vertexCos[a], defaxis, &cd, NULL);
 +                              calc_curve_deform(cuOb, vertexCos[a], defaxis, &cd, NULL);
                                mul_m4_v3(cd.objectspace, vertexCos[a]);
                        }
                }
@@@ -840,10 -841,10 +840,10 @@@ void curve_deform_vector(Object *cuOb, 
        copy_v3_v3(cd.dmax, orco);
  
        mul_m4_v3(cd.curvespace, vec);
-       
 -      if (calc_curve_deform(scene, cuOb, vec, target->trackflag, &cd, quat)) {
 +      if (calc_curve_deform(cuOb, vec, target->trackflag, &cd, quat)) {
                float qmat[3][3];
-               
                quat_to_mat3(qmat, quat);
                mul_m3_m3m3(mat, qmat, cd.objectspace3);
        }
@@@ -1111,10 -1023,9 +1111,10 @@@ int set_listbasepointers(Main *main, Li
        lb[INDEX_ID_OB]  = &(main->object);
        lb[INDEX_ID_LS]  = &(main->linestyle); /* referenced by scenes */
        lb[INDEX_ID_SCE] = &(main->scene);
 +      lb[INDEX_ID_WS]  = &(main->workspaces); /* before wm, so it's freed after it! */
        lb[INDEX_ID_WM]  = &(main->wm);
        lb[INDEX_ID_MSK] = &(main->mask);
-       
        lb[INDEX_ID_NULL] = NULL;
  
        return (MAX_LIBARRAY - 1);
@@@ -1409,10 -1280,10 +1409,10 @@@ void *BKE_id_new_nomain(const short typ
  static void id_copy_animdata(Main *bmain, ID *id, const bool do_action)
  {
        AnimData *adt = BKE_animdata_from_id(id);
-       
        if (adt) {
                IdAdtTemplate *iat = (IdAdtTemplate *)id;
 -              iat->adt = BKE_animdata_copy(bmain, iat->adt, do_action); /* could be set to false, need to investigate */
 +              iat->adt = BKE_animdata_copy(bmain, iat->adt, do_action, true); /* could be set to false, need to investigate */
        }
  }
  
@@@ -1015,11 -1004,11 +1015,11 @@@ void BKE_libblock_free(Main *bmain, voi
  void BKE_libblock_free_us(Main *bmain, void *idv)      /* test users */
  {
        ID *id = idv;
-       
        id_us_min(id);
  
 -      /* XXX This is a temp (2.77) hack so that we keep same behavior as in 2.76 regarding groups when deleting an object.
 -       *     Since only 'user_one' usage of objects is groups, and only 'real user' usage of objects is scenes,
 +      /* XXX This is a temp (2.77) hack so that we keep same behavior as in 2.76 regarding collections when deleting an object.
 +       *     Since only 'user_one' usage of objects is collections, and only 'real user' usage of objects is scenes,
         *     removing that 'user_one' tag when there is no more real (scene) users of an object ensures it gets
         *     fully unlinked.
         *     But only for local objects, not linked ones!
@@@ -89,11 -87,17 +89,11 @@@ void init_def_material(void
  /** Free (or release) any data used by this material (does not free the material itself). */
  void BKE_material_free(Material *ma)
  {
 -      int a;
 -
        BKE_animdata_free((ID *)ma, false);
-       
 -      for (a = 0; a < MAX_MTEX; a++) {
 -              MEM_SAFE_FREE(ma->mtex[a]);
 -      }
 -
 -      MEM_SAFE_FREE(ma->ramp_col);
 -      MEM_SAFE_FREE(ma->ramp_spec);
 +      /* Free gpu material before the ntree */
 +      GPU_material_free(&ma->gpumaterial);
-       
        /* is no lib link block, but material extension */
        if (ma->nodetree) {
                ntreeFreeTree(ma->nodetree);
@@@ -111,13 -117,52 +111,13 @@@ void BKE_material_init(Material *ma
  {
        BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(ma, id));
  
 -      ma->r = ma->g = ma->b = ma->ref = 0.8;
 +      ma->r = ma->g = ma->b = 0.8;
        ma->specr = ma->specg = ma->specb = 1.0;
 -      ma->mirr = ma->mirg = ma->mirb = 1.0;
 -      ma->spectra = 1.0;
 -      ma->amb = 1.0;
 -      ma->alpha = 1.0;
 -      ma->spec = ma->hasize = 0.5;
 -      ma->har = 50;
 -      ma->starc = ma->ringc = 4;
 -      ma->linec = 12;
 -      ma->flarec = 1;
 -      ma->flaresize = ma->subsize = 1.0;
 -      ma->flareboost = 1;
 -      ma->seed2 = 6;
 -      ma->friction = 0.5;
 -      ma->refrac = 4.0;
 -      ma->roughness = 0.5;
 -      ma->param[0] = 0.5;
 -      ma->param[1] = 0.1;
 -      ma->param[2] = 0.5;
 -      ma->param[3] = 0.1;
 -      ma->rms = 0.1;
 -      ma->darkness = 1.0;
 -
 -      ma->strand_sta = ma->strand_end = 1.0f;
 -
 -      ma->ang = 1.0;
 -      ma->ray_depth = 2;
 -      ma->ray_depth_tra = 2;
 -      ma->fresnel_mir = 0.0;
 -      ma->fresnel_tra = 0.0;
 -      ma->fresnel_tra_i = 1.25;
 -      ma->fresnel_mir_i = 1.25;
 -      ma->tx_limit = 0.0;
 -      ma->tx_falloff = 1.0;
 -      ma->shad_alpha = 1.0f;
 -      ma->vcol_alpha = 0;
 -
 -      ma->gloss_mir = ma->gloss_tra = 1.0;
 -      ma->samp_gloss_mir = ma->samp_gloss_tra = 18;
 -      ma->adapt_thresh_mir = ma->adapt_thresh_tra = 0.005;
 -      ma->dist_mir = 0.0;
 -      ma->fadeto_mir = MA_RAYMIR_FADETOSKY;
 -
 -      ma->rampfac_col = 1.0;
 -      ma->rampfac_spec = 1.0;
 +      // ma->alpha = 1.0;  /* DEPRECATED */
 +      ma->spec = 0.5;
 +
 +      ma->roughness = 0.25f;
-       
++
        ma->pr_lamp = 3;         /* two lamps, is bits */
        ma->pr_type = MA_SPHERE;
  
@@@ -410,10 -509,10 +410,10 @@@ Material *BKE_material_pop_id(Main *bma
                                material_data_index_remove_id(id, index);
                        }
  
 -                      DAG_relations_tag_update(bmain);
 +                      DEG_relations_tag_update(bmain);
                }
        }
-       
        return ret;
  }
  
@@@ -967,55 -1347,93 +967,55 @@@ void BKE_texpaint_slot_refresh_cache(Sc
                ma->paint_clone_slot = 0;
                return;
        }
-       
 -      if (use_nodes || ma->use_nodes) {
 -              bNode *node, *active_node;
 +      bNode *node, *active_node;
  
 -              if (!(ma->nodetree)) {
 -                      ma->paint_active_slot = 0;
 -                      ma->paint_clone_slot = 0;
 -                      return;
 -              }
 +      if (!(ma->nodetree)) {
 +              ma->paint_active_slot = 0;
 +              ma->paint_clone_slot = 0;
 +              return;
 +      }
  
 -              for (node = ma->nodetree->nodes.first; node; node = node->next) {
 -                      if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id)
 -                              count++;
 -              }
 +      for (node = ma->nodetree->nodes.first; node; node = node->next) {
 +              if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id)
 +                      count++;
 +      }
  
 -              if (count == 0) {
 -                      ma->paint_active_slot = 0;
 -                      ma->paint_clone_slot = 0;
 -                      return;
 -              }
 -              ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots");
 -
 -              active_node = nodeGetActiveTexture(ma->nodetree);
 -
 -              for (node = ma->nodetree->nodes.first; node; node = node->next) {
 -                      if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id) {
 -                              if (active_node == node)
 -                                      ma->paint_active_slot = index;
 -                              ma->texpaintslot[index].ima = (Image *)node->id;
 -
 -                              /* for new renderer, we need to traverse the treeback in search of a UV node */
 -                              if (use_nodes) {
 -                                      bNode *uvnode = nodetree_uv_node_recursive(node);
 -
 -                                      if (uvnode) {
 -                                              NodeShaderUVMap *storage = (NodeShaderUVMap *)uvnode->storage;
 -                                              ma->texpaintslot[index].uvname = storage->uv_map;
 -                                              /* set a value to index so UI knows that we have a valid pointer for the mesh */
 -                                              ma->texpaintslot[index].index = 0;
 -                                      }
 -                                      else {
 -                                              /* just invalidate the index here so UV map does not get displayed on the UI */
 -                                              ma->texpaintslot[index].index = -1;
 -                                      }
 -                              }
 -                              else {
 -                                      ma->texpaintslot[index].index = -1;
 -                              }
 -                              index++;
 -                      }
 -              }
 +      if (count == 0) {
 +              ma->paint_active_slot = 0;
 +              ma->paint_clone_slot = 0;
 +              return;
        }
 -      else if (is_bi) {
 -              for (mtex = ma->mtex, i = 0; i < MAX_MTEX; i++, mtex++) {
 -                      if (get_mtex_slot_valid_texpaint(*mtex)) {
 -                              count++;
 -                      }
 -              }
 +      ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots");
  
 -              if (count == 0) {
 -                      ma->paint_active_slot = 0;
 -                      ma->paint_clone_slot = 0;
 -                      return;
 -              }
 +      active_node = nodeGetActiveTexture(ma->nodetree);
  
 -              ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots");
 +      for (node = ma->nodetree->nodes.first; node; node = node->next) {
 +              if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id) {
 +                      if (active_node == node)
 +                              ma->paint_active_slot = index;
 +                      ma->texpaintslot[index].ima = (Image *)node->id;
-                       
 -              for (mtex = ma->mtex, i = 0; i < MAX_MTEX; i++, mtex++) {
 -                      if (get_mtex_slot_valid_texpaint(*mtex)) {
 -                              ma->texpaintslot[index].ima = (*mtex)->tex->ima;
 -                              ma->texpaintslot[index].uvname = (*mtex)->uvname;
 -                              ma->texpaintslot[index].index = i;
 +                      /* for new renderer, we need to traverse the treeback in search of a UV node */
 +                      bNode *uvnode = nodetree_uv_node_recursive(node);
-                       
 -                              index++;
 +                      if (uvnode) {
 +                              NodeShaderUVMap *storage = (NodeShaderUVMap *)uvnode->storage;
 +                              ma->texpaintslot[index].uvname = storage->uv_map;
 +                              /* set a value to index so UI knows that we have a valid pointer for the mesh */
 +                              ma->texpaintslot[index].valid = true;
 +                      }
 +                      else {
 +                              /* just invalidate the index here so UV map does not get displayed on the UI */
 +                              ma->texpaintslot[index].valid = false;
                        }
 +                      index++;
                }
        }
 -      else {
 -              ma->paint_active_slot = 0;
 -              ma->paint_clone_slot = 0;
 -              return;
 -      }
 -
  
        ma->tot_slots = count;
-       
-       
        if (ma->paint_active_slot >= count) {
                ma->paint_active_slot = count - 1;
        }
@@@ -107,10 -106,10 +107,10 @@@ static int customdata_compare(CustomDat
        const float thresh_sq = thresh * thresh;
        CustomDataLayer *l1, *l2;
        int i, i1 = 0, i2 = 0, tot, j;
-       
        for (i = 0; i < c1->totlayer; i++) {
                if (ELEM(c1->layers[i].type, CD_MVERT, CD_MEDGE, CD_MPOLY,
 -                       CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))
 +                       CD_MLOOPUV, CD_MLOOPCOL, CD_MDEFORMVERT))
                {
                        i1++;
                }
@@@ -436,9 -427,14 +436,9 @@@ void BKE_object_free(Object *ob
                animviz_free_motionpath(ob->mpath);
                ob->mpath = NULL;
        }
-       
 -      BKE_bproperty_free_list(&ob->prop);
 -
 -      free_sensors(&ob->sensors);
 -      free_controllers(&ob->controllers);
 -      free_actuators(&ob->actuators);
        BKE_constraints_free_ex(&ob->constraints, false);
-       
        free_partdeflect(ob->pd);
        BKE_rigidbody_free_object(ob);
        BKE_rigidbody_free_constraint(ob);
@@@ -739,11 -658,9 +739,11 @@@ void BKE_object_init(Object *ob
        ob->fluidsimSettings = NULL;
  
        BLI_listbase_clear(&ob->pc_ids);
-       
        /* Animation Visualization defaults */
        animviz_settings_init(&ob->avs);
 +
 +      ob->display.flag = OB_SHOW_SHADOW;
  }
  
  /* more general add: creates minimum required data, but without vertices etc. */
@@@ -922,12 -944,13 +922,12 @@@ ParticleSystem *BKE_object_copy_particl
        psysn->effectors = NULL;
        psysn->tree = NULL;
        psysn->bvhtree = NULL;
-       
 +      psysn->batch_cache = NULL;
        BLI_listbase_clear(&psysn->pathcachebufs);
        BLI_listbase_clear(&psysn->childcachebufs);
-       
 -      psysn->renderdata = NULL;
 -      /* XXX Never copy caches here? */
 -      psysn->pointcache = BKE_ptcache_copy_list(&psysn->ptcaches, &psys->ptcaches, flag & ~LIB_ID_COPY_CACHES);
 +      psysn->pointcache = BKE_ptcache_copy_list(&psysn->ptcaches, &psys->ptcaches, flag);
  
        /* XXX - from reading existing code this seems correct but intended usage of
         * pointcache should /w cloth should be added in 'ParticleSystem' - campbell */
@@@ -1191,11 -1123,12 +1191,11 @@@ void BKE_object_copy_data(Main *UNUSED(
        }
  
        if (ob_src->iuser) ob_dst->iuser = MEM_dupallocN(ob_src->iuser);
-       
        if (ob_src->bb) ob_dst->bb = MEM_dupallocN(ob_src->bb);
-       
 -      ob_dst->flag &= ~OB_FROMGROUP;
        BLI_listbase_clear(&ob_dst->modifiers);
-       
        for (md = ob_src->modifiers.first; md; md = md->next) {
                ModifierData *nmd = modifier_new(md->type);
                BLI_strncpy(nmd->name, md->name, sizeof(nmd->name));
        ob_dst->derivedFinal = NULL;
  
        BLI_listbase_clear(&ob_dst->gpulamp);
 +      BLI_listbase_clear(&ob_dst->drawdata);
        BLI_listbase_clear(&ob_dst->pc_ids);
  
 -      ob_dst->mpath = NULL;
 +      ob_dst->avs = ob_src->avs;
 +      ob_dst->mpath = animviz_copy_motionpath(ob_src->mpath);
  
        copy_object_lod(ob_dst, ob_src, flag_subdata);
-       
        /* Do not copy runtime curve data. */
        ob_dst->curve_cache = NULL;
  
@@@ -1393,26 -1325,26 +1393,26 @@@ void BKE_object_make_proxy(Object *ob, 
                printf("cannot make proxy\n");
                return;
        }
-       
        ob->proxy = target;
 -      ob->proxy_group = gob;
 +      ob->proxy_group = cob;
        id_lib_extern(&target->id);
-       
 -      DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
 -      DAG_id_tag_update(&target->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
 +      DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
 +      DEG_id_tag_update(&target->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
-       
        /* copy transform
 -       * - gob means this proxy comes from a group, just apply the matrix
 +       * - cob means this proxy comes from a collection, just apply the matrix
         *   so the object wont move from its dupli-transform.
         *
 -       * - no gob means this is being made from a linked object,
 +       * - no cob means this is being made from a linked object,
         *   this is closer to making a copy of the object - in-place. */
 -      if (gob) {
 +      if (cob) {
                ob->rotmode = target->rotmode;
 -              mul_m4_m4m4(ob->obmat, gob->obmat, target->obmat);
 -              if (gob->dup_group) { /* should always be true */
 +              mul_m4_m4m4(ob->obmat, cob->obmat, target->obmat);
 +              if (cob->dup_group) { /* should always be true */
                        float tvec[3];
 -                      mul_v3_mat3_m4v3(tvec, ob->obmat, gob->dup_group->dupli_ofs);
 +                      mul_v3_mat3_m4v3(tvec, ob->obmat, cob->dup_group->dupli_ofs);
                        sub_v3_v3(ob->obmat[3], tvec);
                }
                BKE_object_apply_mat4(ob, ob->obmat, false, true);
@@@ -2085,13 -2013,13 +2085,13 @@@ static void solve_parenting(Depsgraph *
        float totmat[4][4];
        float tmat[4][4];
        float locmat[4][4];
-       
        BKE_object_to_mat4(ob, locmat);
-       
        if (ob->partype & PARSLOW) copy_m4_m4(slowmat, obmat);
  
 -      BKE_object_get_parent_matrix(scene, ob, par, totmat);
 +      BKE_object_get_parent_matrix(depsgraph, scene, ob, par, totmat);
-       
        /* total */
        mul_m4_m4m4(tmat, totmat, ob->parentinv);
        mul_m4_m4m4(obmat, tmat, locmat);
@@@ -2133,23 -2061,22 +2133,23 @@@ static bool where_is_object_parslow(Obj
  }
  
  /* note, scene is the active scene while actual_scene is the scene the object resides in */
 -void BKE_object_where_is_calc_time_ex(Scene *scene, Object *ob, float ctime,
 -                                      RigidBodyWorld *rbw, float r_originmat[3][3])
 +void BKE_object_where_is_calc_time_ex(
 +        Depsgraph *depsgraph, Scene *scene, Object *ob, float ctime,
 +        RigidBodyWorld *rbw, float r_originmat[3][3])
  {
        if (ob == NULL) return;
-       
        /* execute drivers only, as animation has already been done */
 -      BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, ctime, ADT_RECALC_DRIVERS);
 +      BKE_animsys_evaluate_animdata(depsgraph, scene, &ob->id, ob->adt, ctime, ADT_RECALC_DRIVERS);
-       
        if (ob->parent) {
                Object *par = ob->parent;
                float slowmat[4][4];
-               
                /* calculate parent matrix */
 -              solve_parenting(scene, ob, par, ob->obmat, slowmat, r_originmat, true);
 +              solve_parenting(depsgraph, scene, ob, par, ob->obmat, slowmat, r_originmat, true);
-               
-               /* "slow parent" is definitely not threadsafe, and may also give bad results jumping around 
+               /* "slow parent" is definitely not threadsafe, and may also give bad results jumping around
                 * An old-fashioned hack which probably doesn't really cut it anymore
                 */
                if (ob->partype & PARSLOW) {
        /* solve constraints */
        if (ob->constraints.first && !(ob->transflag & OB_NO_CONSTRAINTS)) {
                bConstraintOb *cob;
 -              cob = BKE_constraints_make_evalob(scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
 -              BKE_constraints_solve(&ob->constraints, cob, ctime);
 +              cob = BKE_constraints_make_evalob(depsgraph, scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
 +              BKE_constraints_solve(depsgraph, &ob->constraints, cob, ctime);
                BKE_constraints_clear_evalob(cob);
        }
-       
        /* set negative scale flag in object */
        if (is_negative_m4(ob->obmat)) ob->transflag |= OB_NEG_SCALE;
        else ob->transflag &= ~OB_NEG_SCALE;
@@@ -2195,9 -2122,9 +2195,9 @@@ void BKE_object_where_is_calc_mat4(Deps
                float slowmat[4][4];
  
                Object *par = ob->parent;
-               
 -              solve_parenting(scene, ob, par, obmat, slowmat, NULL, false);
 +              solve_parenting(depsgraph, scene, ob, par, obmat, slowmat, NULL, false);
-               
                if (ob->partype & PARSLOW)
                        where_is_object_parslow(ob, obmat, slowmat);
        }
        }
  }
  
 -void BKE_object_where_is_calc_ex(Scene *scene, RigidBodyWorld *rbw, Object *ob, float r_originmat[3][3])
 +void BKE_object_where_is_calc_ex(Depsgraph *depsgraph, Scene *scene, RigidBodyWorld *rbw, Object *ob, float r_originmat[3][3])
  {
 -      BKE_object_where_is_calc_time_ex(scene, ob, BKE_scene_frame_get(scene), rbw, r_originmat);
 +      BKE_object_where_is_calc_time_ex(depsgraph, scene, ob, DEG_get_ctime(depsgraph), rbw, r_originmat);
  }
 -void BKE_object_where_is_calc(Scene *scene, Object *ob)
 +void BKE_object_where_is_calc(Depsgraph *depsgraph, Scene *scene, Object *ob)
  {
 -      BKE_object_where_is_calc_time_ex(scene, ob, BKE_scene_frame_get(scene), NULL, NULL);
 +      BKE_object_where_is_calc_time_ex(depsgraph, scene, ob, DEG_get_ctime(depsgraph), NULL, NULL);
  }
  
 -/* for calculation of the inverse parent transform, only used for editor */
 -void BKE_object_workob_calc_parent(Scene *scene, Object *ob, Object *workob)
 +/**
 + * For calculation of the inverse parent transform, only used for editor.
 + *
 + * It assumes the object parent is already in the depsgraph.
 + * Otherwise, after changing ob->parent you need to call:
 + *  DEG_relations_tag_update(bmain);
 + *  BKE_scene_graph_update_tagged(depsgraph, bmain);
 + */
 +void BKE_object_workob_calc_parent(Depsgraph *depsgraph, Scene *scene, Object *ob, Object *workob)
  {
 +      Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
        BKE_object_workob_clear(workob);
-       
        unit_m4(workob->obmat);
        unit_m4(workob->parentinv);
        unit_m4(workob->constinv);
 -      workob->parent = ob->parent;
  
 -      workob->trackflag = ob->trackflag;
 -      workob->upflag = ob->upflag;
 +      /* Since this is used while calculating parenting, at this moment ob_eval->parent is still NULL. */
 +      workob->parent = DEG_get_evaluated_object(depsgraph, ob->parent);
  
 -      workob->partype = ob->partype;
 -      workob->par1 = ob->par1;
 -      workob->par2 = ob->par2;
 -      workob->par3 = ob->par3;
 +      workob->trackflag = ob_eval->trackflag;
 +      workob->upflag = ob_eval->upflag;
-       
 -      workob->constraints.first = ob->constraints.first;
 -      workob->constraints.last = ob->constraints.last;
 +      workob->partype = ob_eval->partype;
 +      workob->par1 = ob_eval->par1;
 +      workob->par2 = ob_eval->par2;
 +      workob->par3 = ob_eval->par3;
  
 -      BLI_strncpy(workob->parsubstr, ob->parsubstr, sizeof(workob->parsubstr));
 +      workob->constraints = ob_eval->constraints;
  
 -      BKE_object_where_is_calc(scene, workob);
 +      BLI_strncpy(workob->parsubstr, ob_eval->parsubstr, sizeof(workob->parsubstr));
 +
 +      BKE_object_where_is_calc(depsgraph, scene, workob);
  }
  
 -/* see BKE_pchan_apply_mat4() for the equivalent 'pchan' function */
 -void BKE_object_apply_mat4(Object *ob, float mat[4][4], const bool use_compat, const bool use_parent)
 +/**
 + * Applies the global transformation \a mat to the \a ob using a relative parent space if supplied.
 + *
 + * \param mat the global transformation mat that the object should be set object to.
 + * \param parent the parent space in which this object will be set relative to (should probably always be parent_eval).
 + * \param use_compat true to ensure that rotations are set using the min difference between the old and new orientation.
 + */
 +void BKE_object_apply_mat4_ex(Object *ob, float mat[4][4], Object *parent, float parentinv[4][4], const bool use_compat)
  {
 +      /* see BKE_pchan_apply_mat4() for the equivalent 'pchan' function */
 +
        float rot[3][3];
  
 -      if (use_parent && ob->parent) {
 +      if (parent != NULL) {
                float rmat[4][4], diff_mat[4][4], imat[4][4], parent_mat[4][4];
  
 -              BKE_object_get_parent_matrix(NULL, ob, ob->parent, parent_mat);
 +              BKE_object_get_parent_matrix(NULL, NULL, ob, parent, parent_mat);
  
 -              mul_m4_m4m4(diff_mat, parent_mat, ob->parentinv);
 +              mul_m4_m4m4(diff_mat, parent_mat, parentinv);
                invert_m4_m4(imat, diff_mat);
                mul_m4_m4m4(rmat, imat, mat); /* get the parent relative matrix */
  
@@@ -2758,16 -2660,16 +2758,16 @@@ void BKE_object_handle_update_ex(Depsgr
                }
        }
  
 -      if (ob->recalc & OB_RECALC_DATA) {
 -              BKE_object_handle_data_update(bmain, eval_ctx, scene, ob);
 +      if (recalc_data) {
 +              BKE_object_handle_data_update(depsgraph, scene, ob);
        }
  
 -      ob->recalc &= ~OB_RECALC_ALL;
 +      ob->id.recalc &= ID_RECALC_ALL;
  
 -      object_handle_update_proxy(bmain, eval_ctx, scene, ob, do_proxy_update);
 +      object_handle_update_proxy(depsgraph, scene, ob, do_proxy_update);
  }
  
- /* WARNING: "scene" here may not be the scene object actually resides in. 
+ /* WARNING: "scene" here may not be the scene object actually resides in.
   * When dealing with background-sets, "scene" is actually the active scene.
   * e.g. "scene" <-- set 1 <-- set 2 ("ob" lives here) <-- set 3 <-- ... <-- set n
   * rigid bodies depend on their world so use BKE_object_handle_update_ex() to also pass along the corrent rigid body world
@@@ -121,13 -123,15 +121,13 @@@ static void init_context
  }
  
  /* create sub-context for recursive duplis */
 -static void copy_dupli_context(DupliContext *r_ctx, const DupliContext *ctx, Object *ob, float mat[4][4], int index, bool animated)
 +static void copy_dupli_context(DupliContext *r_ctx, const DupliContext *ctx, Object *ob, float mat[4][4], int index)
  {
        *r_ctx = *ctx;
-       
 -      r_ctx->animated |= animated; /* object animation makes all children animated */
 -
        /* XXX annoying, previously was done by passing an ID* argument, this at least is more explicit */
 -      if (ctx->gen->type == OB_DUPLIGROUP)
 -              r_ctx->group = ctx->object->dup_group;
 +      if (ctx->gen->type == OB_DUPLICOLLECTION)
 +              r_ctx->collection = ctx->object->dup_group;
  
        r_ctx->object = ob;
        if (mat)
@@@ -160,13 -156,13 +160,13 @@@ Paint *BKE_paint_get_active_from_paintm
        return NULL;
  }
  
 -Paint *BKE_paint_get_active(Scene *sce)
 +Paint *BKE_paint_get_active(Scene *sce, ViewLayer *view_layer)
  {
 -      if (sce) {
 +      if (sce && view_layer) {
                ToolSettings *ts = sce->toolsettings;
-               
 -              if (sce->basact && sce->basact->object) {
 -                      switch (sce->basact->object->mode) {
 +              if (view_layer->basact && view_layer->basact->object) {
 +                      switch (view_layer->basact->object->mode) {
                                case OB_MODE_SCULPT:
                                        return &ts->sculpt->paint;
                                case OB_MODE_VERTEX_PAINT:
@@@ -1227,10 -1392,10 +1227,10 @@@ static float psys_interpolate_value_fro
                case PART_FROM_FACE:
                case PART_FROM_VOLUME:
                {
 -                      MFace *mf = dm->getTessFaceData(dm, index, CD_MFACE);
 +                      MFace *mf = &mesh->mface[index];
                        return interpolate_particle_value(values[mf->v1], values[mf->v2], values[mf->v3], values[mf->v4], fw, mf->v4);
                }
-                       
        }
        return 0.0f;
  }
@@@ -1514,10 -1685,10 +1514,10 @@@ float psys_particle_value_from_verts(Me
        float mapfw[4];
        int mapindex;
  
 -      if (!psys_map_index_on_dm(dm, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, &mapindex, mapfw))
 +      if (!psys_map_index_on_dm(mesh, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, &mapindex, mapfw))
                return 0.0f;
-       
 -      return psys_interpolate_value_from_verts(dm, from, mapindex, mapfw, values);
 +      return psys_interpolate_value_from_verts(mesh, from, mapindex, mapfw, values);
  }
  
  ParticleSystemModifierData *psys_get_modifier(Object *ob, ParticleSystem *psys)
@@@ -1639,11 -1813,11 +1639,11 @@@ void precalc_guides(ParticleSimulationD
                return;
  
        LOOP_PARTICLES {
 -              psys_particle_on_emitter(sim->psmd, sim->psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, state.co, 0, 0, 0, 0, 0);
 +              psys_particle_on_emitter(sim->psmd, sim->psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, state.co, 0, 0, 0, 0);
-               
                mul_m4_v3(sim->ob->obmat, state.co);
                mul_mat3_m4_v3(sim->ob->obmat, state.vel);
-               
                pd_point_from_particle(sim, pa, &state, &point);
  
                for (eff = effectors->first; eff; eff = eff->next) {
@@@ -1725,11 -1899,11 +1725,11 @@@ int do_guides(Depsgraph *depsgraph, Par
                        axis_angle_to_quat(rot2, guidedir, guidevec[3] - eff->guide_loc[3]);
                        mul_qt_v3(rot2, vec_to_point);
                }
-               
                /* curve taper */
                if (cu->taperobj)
 -                      mul_v3_fl(vec_to_point, BKE_displist_calc_taper(eff->scene, cu->taperobj, (int)(data->strength * guidetime * 100.0f), 100));
 +                      mul_v3_fl(vec_to_point, BKE_displist_calc_taper(depsgraph, eff->scene, cu->taperobj, (int)(data->strength * guidetime * 100.0f), 100));
-               
                else { /* curve size*/
                        if (cu->flag & CU_PATH_RADIUS) {
                                mul_v3_fl(vec_to_point, radius);
@@@ -1922,8 -2096,8 +1922,8 @@@ static bool psys_thread_context_init_pa
  
        if (totchild && part->childtype == PART_CHILD_FACES) {
                totparent = (int)(totchild * part->parents * 0.3f);
-               
 -              if ((psys->renderdata || use_render_params) && part->child_nbr && part->ren_child_nbr)
 +              if (use_render_params && part->child_nbr && part->ren_child_nbr)
                        totparent *= (float)part->child_nbr / (float)part->ren_child_nbr;
  
                /* part->parents could still be 0 so we can't test with totparent */
@@@ -2257,11 -2430,11 +2257,11 @@@ static void psys_thread_create_path(Par
                if (pa) {
                        ListBase modifiers;
                        BLI_listbase_clear(&modifiers);
-                       
                        psys_particle_on_emitter(ctx->sim.psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset,
 -                                               par_co, NULL, NULL, NULL, par_orco, NULL);
 +                                               par_co, NULL, NULL, NULL, par_orco);
-                       
 -                      psys_apply_child_modifiers(ctx, &modifiers, cpa, &ptex, orco, ornor, hairmat, child_keys, par, par_orco);
 +                      psys_apply_child_modifiers(ctx, &modifiers, cpa, &ptex, orco, hairmat, child_keys, par, par_orco);
                }
                else
                        zero_v3(par_orco);
@@@ -2403,10 -2576,10 +2403,10 @@@ void psys_cache_paths(ParticleSimulatio
        ParticleSettings *part = psys->part;
        ParticleCacheKey *ca, **cache;
  
 -      DerivedMesh *hair_dm = (psys->part->type == PART_HAIR && psys->flag & PSYS_HAIR_DYNAMICS) ? psys->hair_out_dm : NULL;
 +      Mesh *hair_mesh = (psys->part->type == PART_HAIR && psys->flag & PSYS_HAIR_DYNAMICS) ? psys->hair_out_mesh : NULL;
-       
        ParticleKey result;
-       
        Material *ma;
        ParticleInterpolationData pind;
        ParticleTexture ptex;
  
        if ((psys->flag & PSYS_GLOBAL_HAIR) == 0) {
                if ((psys->part->flag & PART_CHILD_EFFECT) == 0)
 -                      vg_effector = psys_cache_vgroup(psmd->dm_final, psys, PSYS_VG_EFFECTOR);
 +                      vg_effector = psys_cache_vgroup(psmd->mesh_final, psys, PSYS_VG_EFFECTOR);
-               
                if (!psys->totchild)
 -                      vg_length = psys_cache_vgroup(psmd->dm_final, psys, PSYS_VG_LENGTH);
 +                      vg_length = psys_cache_vgroup(psmd->mesh_final, psys, PSYS_VG_LENGTH);
        }
  
        /* ensure we have tessfaces to be used for mapping */
@@@ -2749,85 -2934,40 +2749,85 @@@ static void psys_cache_edit_paths_iter
                                }
                        }
                        else {
 -                              if ((ekey + (pind.ekey[0] - point->keys))->flag & PEK_SELECT) {
 -                                      if ((ekey + (pind.ekey[1] - point->keys))->flag & PEK_SELECT) {
 -                                              copy_v3_v3(ca->col, sel_col);
 -                                      }
 -                                      else {
 -                                              keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time));
 -                                              interp_v3_v3v3(ca->col, sel_col, nosel_col, keytime);
 -                                      }
 +                              if ((ekey + (pind.ekey[1] - point->keys))->flag & PEK_SELECT) {
 +                                      keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time));
 +                                      interp_v3_v3v3(ca->col, iter_data->nosel_col, iter_data->sel_col, keytime);
                                }
                                else {
 -                                      if ((ekey + (pind.ekey[1] - point->keys))->flag & PEK_SELECT) {
 -                                              keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time));
 -                                              interp_v3_v3v3(ca->col, nosel_col, sel_col, keytime);
 -                                      }
 -                                      else {
 -                                              copy_v3_v3(ca->col, nosel_col);
 -                                      }
 +                                      copy_v3_v3(ca->col, iter_data->nosel_col);
                                }
                        }
 -
 -                      ca->time = t;
                }
 -              if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
 -                      /* First rotation is based on emitting face orientation.
 -                       * This is way better than having flipping rotations resulting
 -                       * from using a global axis as a rotation pole (vec_to_quat()).
 -                       * It's not an ideal solution though since it disregards the
 -                       * initial tangent, but taking that in to account will allow
 -                       * the possibility of flipping again. -jahka
 -                       */
 -                      mat3_to_quat_is_ok(cache[i]->rot, rotmat);
 +
 +              ca->time = t;
 +      }
 +      if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
 +              /* First rotation is based on emitting face orientation.
 +               * This is way better than having flipping rotations resulting
 +               * from using a global axis as a rotation pole (vec_to_quat()).
 +               * It's not an ideal solution though since it disregards the
 +               * initial tangent, but taking that in to account will allow
 +               * the possibility of flipping again. -jahka
 +               */
 +              mat3_to_quat_is_ok(cache[iter]->rot, rotmat);
 +      }
 +}
 +
 +void psys_cache_edit_paths(Depsgraph *depsgraph, Scene *scene, Object *ob, PTCacheEdit *edit, float cfra, const bool use_render_params)
 +{
 +      ParticleCacheKey **cache = edit->pathcache;
 +      ParticleEditSettings *pset = &scene->toolsettings->particle;
-       
++
 +      ParticleSystem *psys = edit->psys;
 +      ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
 +
 +      ParticleData *pa = psys ? psys->particles : NULL;
 +
 +      int segments = 1 << pset->draw_step;
 +      int totpart = edit->totpoint, recalc_set = 0;
 +
 +      segments = MAX2(segments, 4);
 +
 +      if (!cache || edit->totpoint != edit->totcached) {
 +              /* Clear out old and create new empty path cache. */
 +              psys_free_path_cache(edit->psys, edit);
 +              cache = edit->pathcache = psys_alloc_path_cache_buffers(&edit->pathcachebufs, totpart, segments + 1);
 +              /* Set flag for update (child particles check this too). */
 +              int i;
 +              PTCacheEditPoint *point;
 +              for (i = 0, point = edit->points; i < totpart; i++, point++) {
 +                      point->flag |= PEP_EDIT_RECALC;
                }
 +              recalc_set = 1;
 +      }
 +
 +      const bool use_weight = (pset->brushtype == PE_BRUSH_WEIGHT) && (psys != NULL) && (psys->particles != NULL);
 +
 +      CacheEditrPathsIterData iter_data;
 +      iter_data.object = ob;
 +      iter_data.edit = edit;
 +      iter_data.psmd = psmd;
 +      iter_data.pa = pa;
 +      iter_data.segments = segments;
 +      iter_data.use_weight = use_weight;
 +
 +      if (use_weight) {
 +              ; /* use weight painting colors now... */
 +      }
 +      else {
 +              iter_data.sel_col[0] = (float)edit->sel_col[0] / 255.0f;
 +              iter_data.sel_col[1] = (float)edit->sel_col[1] / 255.0f;
 +              iter_data.sel_col[2] = (float)edit->sel_col[2] / 255.0f;
 +              iter_data.nosel_col[0] = (float)edit->nosel_col[0] / 255.0f;
 +              iter_data.nosel_col[1] = (float)edit->nosel_col[1] / 255.0f;
 +              iter_data.nosel_col[2] = (float)edit->nosel_col[2] / 255.0f;
        }
  
 +      ParallelRangeSettings settings;
 +      BLI_parallel_range_settings_defaults(&settings);
 +      settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
 +      BLI_task_parallel_range(0, edit->totpoint, &iter_data, psys_cache_edit_paths_iter, &settings);
 +
        edit->totcached = totpart;
  
        if (psys) {
@@@ -2937,12 -3073,12 +2937,12 @@@ static void psys_face_mat(Object *ob, M
        float (*orcodata)[3];
  
        int i = (ELEM(pa->num_dmcache, DMCACHE_ISCHILD, DMCACHE_NOTFOUND)) ? pa->num : pa->num_dmcache;
 -      if (i == -1 || i >= dm->getNumTessFaces(dm)) { unit_m4(mat); return; }
 +      if (i == -1 || i >= mesh->totface) { unit_m4(mat); return; }
  
 -      mface = dm->getTessFaceData(dm, i, CD_MFACE);
 -      osface = dm->getTessFaceData(dm, i, CD_ORIGSPACE);
 +      mface = &mesh->mface[i];
 +      osface = CustomData_get(&mesh->fdata, i, CD_ORIGSPACE);
-       
 -      if (orco && (orcodata = dm->getVertDataArray(dm, CD_ORCO))) {
 +      if (orco && (orcodata = CustomData_get_layer(&mesh->vdata, CD_ORCO))) {
                copy_v3_v3(v[0], orcodata[mface->v1]);
                copy_v3_v3(v[1], orcodata[mface->v2]);
                copy_v3_v3(v[2], orcodata[mface->v3]);
@@@ -2970,9 -3106,9 +2970,9 @@@ void psys_mat_hair_to_object(Object *UN
                unit_m4(hairmat);
                return;
        }
-       
 -      psys_face_mat(0, dm, pa, hairmat, 0);
 -      psys_particle_on_dm(dm, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, vec, 0, 0, 0, 0, 0);
 +      psys_face_mat(0, mesh, pa, hairmat, 0);
 +      psys_particle_on_dm(mesh, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, vec, 0, 0, 0, 0);
        copy_v3_v3(hairmat[3], vec);
  }
  
@@@ -3096,11 -3232,8 +3096,11 @@@ void object_remove_particle_system(Mai
        else
                ob->mode &= ~OB_MODE_PARTICLE_EDIT;
  
 -      DAG_relations_tag_update(bmain);
 -      DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
 +      DEG_relations_tag_update(bmain);
 +      DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
-       
++
 +      /* Flush object mode. */
 +      DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE);
  }
  
  static void default_particle_settings(ParticleSettings *part)
@@@ -3296,11 -3427,11 +3296,11 @@@ static int get_particle_uv(Mesh *mesh, 
        MFace *mf;
        MTFace *tf;
        int i;
-       
 -      tf = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, name);
 +      tf = CustomData_get_layer_named(&mesh->fdata, CD_MTFACE, name);
  
        if (tf == NULL)
 -              tf = CustomData_get_layer(&dm->faceData, CD_MTFACE);
 +              tf = mesh->mtface;
  
        if (tf == NULL)
                return 0;
@@@ -3492,8 -3623,8 +3492,8 @@@ void psys_get_texture(ParticleSimulatio
                                        /* no break, failed to get uv's, so let's try orco's */
                                        ATTR_FALLTHROUGH;
                                case TEXCO_ORCO:
 -                                      psys_particle_on_emitter(sim->psmd, sim->psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co, 0, 0, 0, texvec, 0);
 +                                      psys_particle_on_emitter(sim->psmd, sim->psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co, 0, 0, 0, texvec);
-                                       
                                        if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) {
                                                BKE_mesh_texspace_calc(me);
                                        }
@@@ -4069,8 -4200,8 +4069,8 @@@ void psys_get_dupli_texture(ParticleSys
                                mtface += cpa->num;
                                psys_interpolate_uvs(mtface, mface->v4, cpa->fuv, uv);
                        }
-               
 -                      psys_particle_on_emitter(psmd, PART_FROM_FACE, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, loc, 0, 0, 0, orco, 0);
 +                      psys_particle_on_emitter(psmd, PART_FROM_FACE, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, loc, 0, 0, 0, orco);
                        return;
                }
                else {
@@@ -94,12 -94,12 +94,12 @@@ static void distribute_simple_children(
                for (p=0; p<psys->totpart; p++,cpa++) {
                        float length=2.0;
                        cpa->parent=p;
-                                       
                        /* create even spherical distribution inside unit sphere */
                        while (length>=1.0f) {
 -                              cpa->fuv[0]=2.0f*BLI_frand()-1.0f;
 -                              cpa->fuv[1]=2.0f*BLI_frand()-1.0f;
 -                              cpa->fuv[2]=2.0f*BLI_frand()-1.0f;
 +                              cpa->fuv[0]=2.0f*BLI_rng_get_float(rng)-1.0f;
 +                              cpa->fuv[1]=2.0f*BLI_rng_get_float(rng)-1.0f;
 +                              cpa->fuv[2]=2.0f*BLI_rng_get_float(rng)-1.0f;
                                length=len_v3(cpa->fuv);
                        }
  
@@@ -198,9 -196,9 +198,9 @@@ static void distribute_grid(Mesh *mesh
                int a, a1, a2, a0mul, a1mul, a2mul, totface;
                int amax= from==PART_FROM_FACE ? 3 : 1;
  
 -              totface=dm->getNumTessFaces(dm);
 -              mface=mface_array=dm->getTessFaceDataArray(dm,CD_MFACE);
 +              totface = mesh->totface;
 +              mface = mface_array = mesh->mface;
-               
                for (a=0; a<amax; a++) {
                        if (a==0) { a0mul=res*res; a1mul=res; a2mul=1; }
                        else if (a==1) { a0mul=res; a1mul=1; a2mul=res*res; }
@@@ -476,21 -477,19 +476,21 @@@ static void distribute_from_verts_exec(
        if (ctx->tree) {
                KDTreeNearest ptn[3];
                int w, maxw;
-               
 -              psys_particle_on_dm(ctx->dm,from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co1,0,0,0,orco1,0);
 +              psys_particle_on_dm(ctx->mesh,from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co1,0,0,0,orco1,0);
                BKE_mesh_orco_verts_transform((Mesh*)ob->data, &orco1, 1, 1);
                maxw = BLI_kdtree_find_nearest_n(ctx->tree,orco1,ptn,3);
-               
                for (w=0; w<maxw; w++) {
                        pa->verts[w]=ptn->num;
                }
        }
  #endif
-       
 -      if (rng_skip_tot > 0) /* should never be below zero */
 +      BLI_assert(rng_skip_tot > 0);  /* should never be below zero */
 +      if (rng_skip_tot > 0) {
                BLI_rng_skip(thread->rng, rng_skip_tot);
 +      }
  }
  
  static void distribute_from_faces_exec(ParticleTask *thread, ParticleData *pa, int p) {
        int rng_skip_tot= PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */
  
        MFace *mface;
-       
        pa->num = i = ctx->index[p];
 -      mface = dm->getTessFaceData(dm,i,CD_MFACE);
 +      mface = &mesh->mface[i];
-       
        switch (distr) {
                case PART_DISTR_JIT:
                        if (ctx->jitlevel == 1) {
@@@ -545,13 -542,13 +545,13 @@@ static void distribute_from_volume_exec
        int distr= ctx->distr;
        int i, intersect, tot;
        int rng_skip_tot= PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */
-       
        MFace *mface;
 -      MVert *mvert=dm->getVertDataArray(dm,CD_MVERT);
 +      MVert *mvert = mesh->mvert;
-       
        pa->num = i = ctx->index[p];
 -      mface = dm->getTessFaceData(dm,i,CD_MFACE);
 +      mface = &mesh->mface[i];
-       
        switch (distr) {
                case PART_DISTR_JIT:
                        if (ctx->jitlevel == 1) {
                        break;
        }
        pa->foffset= 0.0f;
-       
        /* experimental */
 -      tot=dm->getNumTessFaces(dm);
 +      tot = mesh->totface;
-       
 -      psys_interpolate_face(mvert,mface,0,0,pa->fuv,co,nor,0,0,0,0);
 +      psys_interpolate_face(mvert,mface,0,0,pa->fuv,co,nor,0,0,0);
-       
        normalize_v3(nor);
        negate_v3(nor);
-       
        min_d=FLT_MAX;
        intersect=0;
-       
 -      for (i=0,mface=dm->getTessFaceDataArray(dm,CD_MFACE); i<tot; i++,mface++) {
 +      for (i=0, mface=mesh->mface; i<tot; i++,mface++) {
                if (i==pa->num) continue;
-               
                v1=mvert[mface->v1].co;
                v2=mvert[mface->v2].co;
                v3=mvert[mface->v3].co;
                                break;
                }
        }
-       
 -      if (rng_skip_tot > 0) /* should never be below zero */
 +      BLI_assert(rng_skip_tot > 0); /* should never be below zero */
 +      if (rng_skip_tot > 0) {
                BLI_rng_skip(thread->rng, rng_skip_tot);
 +      }
  }
  
  static void distribute_children_exec(ParticleTask *thread, ChildParticle *cpa, int p) {
                cpa->pa[0]=cpa->pa[1]=cpa->pa[2]=cpa->pa[3]=0;
                return;
        }
-       
 -      mf= dm->getTessFaceData(dm, ctx->index[p], CD_MFACE);
 +      mf = &mesh->mface[ctx->index[p]];
-       
        randu= BLI_rng_get_float(thread->rng);
        randv= BLI_rng_get_float(thread->rng);
        rng_skip_tot -= 2;
                float maxd /*, mind,dd */, totw= 0.0f;
                int parent[10];
                float pweight[10];
-               
 -              psys_particle_on_dm(dm,cfrom,cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,co1,nor1,NULL,NULL,orco1,NULL);
 +              psys_particle_on_dm(mesh,cfrom,cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,co1,nor1,NULL,NULL,orco1);
                BKE_mesh_orco_verts_transform((Mesh*)ob->data, &orco1, 1, 1);
                maxw = BLI_kdtree_find_nearest_n(ctx->tree,orco1,ptn,3);
-               
                maxd=ptn[maxw-1].dist;
                /* mind=ptn[0].dist; */ /* UNUSED */
-               
                /* the weights here could be done better */
                for (w=0; w<maxw; w++) {
                        parent[w]=ptn[w].index;
@@@ -749,10 -743,16 +749,10 @@@ static void exec_distribute_child(TaskP
        /* RNG skipping at the beginning */
        cpa = psys->child;
        for (p = 0; p < task->begin; ++p, ++cpa) {
 -              if (task->ctx->skip) /* simplification skip */
 -                      BLI_rng_skip(task->rng, PSYS_RND_DIST_SKIP * task->ctx->skip[p]);
 -
                BLI_rng_skip(task->rng, PSYS_RND_DIST_SKIP);
        }
-               
        for (; p < task->end; ++p, ++cpa) {
 -              if (task->ctx->skip) /* simplification skip */
 -                      BLI_rng_skip(task->rng, PSYS_RND_DIST_SKIP * task->ctx->skip[p]);
 -
                distribute_children_exec(task, cpa, p);
        }
  }
@@@ -828,17 -825,16 +828,17 @@@ static int psys_thread_context_init_dis
        int jitlevel= 1, distr;
        float *element_weight=NULL,*jitter_offset=NULL, *vweight=NULL;
        float cur, maxweight=0.0, tweight, totweight, inv_totweight, co[3], nor[3], orco[3];
-       
 +      RNG *rng = NULL;
        if (ELEM(NULL, ob, psys, psys->part))
                return 0;
-       
        part=psys->part;
        totpart=psys->totpart;
        if (totpart==0)
                return 0;
-       
 -      if (!finaldm->deformedOnly && !finaldm->getTessFaceDataArray(finaldm, CD_ORIGINDEX)) {
 +      if (!final_mesh->runtime.deformed_only && !CustomData_get_layer(&final_mesh->fdata, CD_ORIGINDEX)) {
                printf("Can't create particles with the current modifier stack, disable destructive modifiers\n");
  // XXX                error("Can't paint with the current modifier stack, disable destructive modifiers");
                return 0;
  
        psys_thread_context_init(ctx, sim);
  
-       
 +      const bool use_render_params = (DEG_get_mode(sim->depsgraph) == DAG_EVAL_RENDER);
++
        /* First handle special cases */
        if (from == PART_FROM_CHILD) {
                /* Simple children */
                        return 0;
                }
        }
-       
        /* Create trees and original coordinates if needed */
        if (from == PART_FROM_CHILD) {
 -              distr=PART_DISTR_RAND;
 -              BLI_srandom(31415926 + psys->seed + psys->child_seed);
 -              dm= finaldm;
 +              distr = PART_DISTR_RAND;
 +              rng = BLI_rng_new_srandom(31415926 + psys->seed + psys->child_seed);
 +              mesh= final_mesh;
  
                /* BMESH ONLY */
 -              DM_ensure_tessface(dm);
 +              BKE_mesh_tessface_ensure(mesh);
  
                children=1;
  
        }
        else {
                distr = part->distr;
 -              BLI_srandom(31415926 + psys->seed);
 +
 +              rng = BLI_rng_new_srandom(31415926 + psys->seed);
-               
                if (psys->part->use_modifier_stack)
 -                      dm = finaldm;
 +                      mesh = final_mesh;
                else
 -                      dm= CDDM_from_mesh((Mesh*)ob->data);
 +                      BKE_id_copy_ex(
 +                                  NULL, ob->data, (ID **)&mesh,
 +                                  LIB_ID_CREATE_NO_MAIN |
 +                                  LIB_ID_CREATE_NO_USER_REFCOUNT |
 +                                  LIB_ID_CREATE_NO_DEG_TAG |
 +                                  LIB_ID_COPY_NO_PREVIEW,
 +                                  false);
  
 -              DM_ensure_tessface(dm);
 +              BKE_mesh_tessface_ensure(mesh);
  
                /* we need orco for consistent distributions */
 -              if (!CustomData_has_layer(&dm->vertData, CD_ORCO))
 -                      DM_add_vert_layer(dm, CD_ORCO, CD_ASSIGN, BKE_mesh_orco_verts_get(ob));
 +              if (!CustomData_has_layer(&mesh->vdata, CD_ORCO))
 +                      CustomData_add_layer(&mesh->vdata, CD_ORCO, CD_ASSIGN, BKE_mesh_orco_verts_get(ob), mesh->totvert);
  
                if (from == PART_FROM_VERT) {
 -                      MVert *mv= dm->getVertDataArray(dm, CD_MVERT);
 -                      float (*orcodata)[3] = dm->getVertDataArray(dm, CD_ORCO);
 -                      int totvert = dm->getNumVerts(dm);
 +                      MVert *mv = mesh->mvert;
 +                      float (*orcodata)[3] = CustomData_get_layer(&mesh->vdata, CD_ORCO);
 +                      int totvert = mesh->totvert;
  
                        tree=BLI_kdtree_new(totvert);
  
                MVert *v1, *v2, *v3, *v4;
                float totarea=0.f, co1[3], co2[3], co3[3], co4[3];
                float (*orcodata)[3];
-               
 -              orcodata= dm->getVertDataArray(dm, CD_ORCO);
 +              orcodata = CustomData_get_layer(&mesh->vdata, CD_ORCO);
  
                for (i=0; i<totelem; i++) {
 -                      MFace *mf=dm->getTessFaceData(dm,i,CD_MFACE);
 +                      MFace *mf = &mesh->mface[i];
  
                        if (orcodata) {
                                copy_v3_v3(co1, orcodata[mf->v1]);
                }
                else { /* PART_FROM_FACE / PART_FROM_VOLUME */
                        for (i=0;i<totelem; i++) {
 -                              MFace *mf=dm->getTessFaceData(dm,i,CD_MFACE);
 +                              MFace *mf = &mesh->mface[i];
                                tweight = vweight[mf->v1] + vweight[mf->v2] + vweight[mf->v3];
-                               
                                if (mf->v4) {
                                        tweight += vweight[mf->v4];
                                        tweight /= 4.0f;
@@@ -1220,9 -1202,9 +1220,9 @@@ static void distribute_particles_on_dm(
        TaskPool *task_pool;
        ParticleThreadContext ctx;
        ParticleTask *tasks;
 -      DerivedMesh *finaldm = sim->psmd->dm_final;
 +      Mesh *final_mesh = sim->psmd->mesh_final;
        int i, totpart, numtasks;
-       
        /* create a task pool for distribution tasks */
        if (!psys_thread_context_init_distribute(&ctx, sim, from))
                return;
                        BLI_task_pool_push(task_pool, exec_distribute_parent, task, false, TASK_PRIORITY_LOW);
        }
        BLI_task_pool_work_and_wait(task_pool);
-       
        BLI_task_pool_free(task_pool);
-       
 -      psys_calc_dmcache(sim->ob, finaldm, sim->psmd->dm_deformed, sim->psys);
 +      psys_calc_dmcache(sim->ob, final_mesh, sim->psmd->mesh_original, sim->psys);
-       
 -      if (ctx.dm != finaldm)
 -              ctx.dm->release(ctx.dm);
 +      if (ctx.mesh != final_mesh)
 +              BKE_id_free(NULL, ctx.mesh);
-       
        psys_tasks_free(tasks, numtasks);
-       
        psys_thread_context_free(&ctx);
  }
  
@@@ -324,9 -320,9 +324,9 @@@ void psys_calc_dmcache(Object *ob, Mes
        Mesh *me= (Mesh*)ob->data;
        bool use_modifier_stack= psys->part->use_modifier_stack;
        PARTICLE_P;
-       
        /* CACHE LOCATIONS */
 -      if (!dm_final->deformedOnly) {
 +      if (!mesh_final->runtime.deformed_only) {
                /* Will use later to speed up subsurf/derivedmesh */
                LinkNode *node, *nodedmelem, **nodearray;
                int totdmelem, totelem, i, *origindex, *origindex_poly = NULL;
@@@ -705,10 -702,10 +705,10 @@@ void psys_get_birth_coords(ParticleSimu
  
        /* get birth location from object               */
        if (use_tangents)
 -              psys_particle_on_emitter(sim->psmd, part->from,pa->num, pa->num_dmcache, pa->fuv,pa->foffset,loc,nor,utan,vtan,0,0);
 +              psys_particle_on_emitter(sim->psmd, part->from,pa->num, pa->num_dmcache, pa->fuv,pa->foffset,loc,nor,utan,vtan,0);
        else
 -              psys_particle_on_emitter(sim->psmd, part->from,pa->num, pa->num_dmcache, pa->fuv,pa->foffset,loc,nor,0,0,0,0);
 +              psys_particle_on_emitter(sim->psmd, part->from,pa->num, pa->num_dmcache, pa->fuv,pa->foffset,loc,nor,0,0,0);
-               
        /* get possible textural influence */
        psys_get_texture(sim, pa, &ptex, PAMAP_IVEL, cfra);
  
  }
  
  /* recursively evaluate emitter parent anim at cfra */
 -static void evaluate_emitter_anim(Scene *scene, Object *ob, float cfra)
 +static void evaluate_emitter_anim(struct Depsgraph *depsgraph, Scene *scene, Object *ob, float cfra)
  {
        if (ob->parent)
 -              evaluate_emitter_anim(scene, ob->parent, cfra);
 +              evaluate_emitter_anim(depsgraph, scene, ob->parent, cfra);
-       
        /* we have to force RECALC_ANIM here since where_is_objec_time only does drivers */
 -      BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, cfra, ADT_RECALC_ANIM);
 -      BKE_object_where_is_calc_time(scene, ob, cfra);
 +      BKE_animsys_evaluate_animdata(depsgraph, scene, &ob->id, ob->adt, cfra, ADT_RECALC_ANIM);
 +      BKE_object_where_is_calc_time(depsgraph, scene, ob, cfra);
  }
  
  /* sets particle to the emitter surface with initial velocity & rotation */
@@@ -1009,10 -1006,10 +1009,10 @@@ void reset_particle(ParticleSimulationD
        ParticleTexture ptex;
        int p = pa - psys->particles;
        part=psys->part;
-       
        /* get precise emitter matrix if particle is born */
        if (part->type != PART_HAIR && dtime > 0.f && pa->time < cfra && pa->time >= sim->psys->cfra) {
 -              evaluate_emitter_anim(sim->scene, sim->ob, pa->time);
 +              evaluate_emitter_anim(sim->depsgraph, sim->scene, sim->ob, pa->time);
  
                psys->flag |= PSYS_OB_ANIM_RESTORE;
        }
@@@ -1146,9 -1143,8 +1146,9 @@@ static void set_keyed_keys(ParticleSimu
        int totpart = psys->totpart, k, totkeys = psys->totkeyed;
        int keyed_flag = 0;
  
 -      ksim.scene= sim->scene;
 +      ksim.depsgraph = sim->depsgraph;
 +      ksim.scene = sim->scene;
-       
        /* no proper targets so let's clear and bail out */
        if (psys->totkeyed==0) {
                free_keyed_keys(psys);
@@@ -3042,17 -3034,16 +3042,17 @@@ static void hair_create_input_mesh(Part
        float hairmat[4][4];
        float max_length;
        float hair_radius;
-       
 -      dm = *r_dm;
 -      if (!dm) {
 -              *r_dm = dm = CDDM_new(totpoint, totedge, 0, 0, 0);
 -              DM_add_vert_layer(dm, CD_MDEFORMVERT, CD_CALLOC, NULL);
 +      mesh = *r_mesh;
 +      if (!mesh) {
 +              *r_mesh = mesh = BKE_mesh_new_nomain(totpoint, totedge, 0, 0, 0);
 +              CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, mesh->totvert);
 +              BKE_mesh_update_customdata_pointers(mesh, false);
        }
 -      mvert = CDDM_get_verts(dm);
 -      medge = CDDM_get_edges(dm);
 -      dvert = DM_get_vert_data_layer(dm, CD_MDEFORMVERT);
 +      mvert = mesh->mvert;
 +      medge = mesh->medge;
 +      dvert = mesh->dvert;
-       
        hairdata = *r_hairdata;
        if (!hairdata) {
                *r_hairdata = hairdata = MEM_mallocN(sizeof(ClothHairData) * totpoint, "hair data");
@@@ -3181,49 -3172,46 +3181,49 @@@ static void do_hair_dynamics(ParticleSi
                        totpoint += pa->totkey + 1; /* +1 for virtual root point */
                }
        }
-       
        realloc_roots = false; /* whether hair root info array has to be reallocated */
 -      if (psys->hair_in_dm) {
 -              DerivedMesh *dm = psys->hair_in_dm;
 -              if (totpoint != dm->getNumVerts(dm) || totedge != dm->getNumEdges(dm)) {
 -                      dm->release(dm);
 -                      psys->hair_in_dm = NULL;
 +      if (psys->hair_in_mesh) {
 +              Mesh *mesh = psys->hair_in_mesh;
 +              if (totpoint != mesh->totvert || totedge != mesh->totedge) {
 +                      BKE_id_free(NULL, mesh);
 +                      psys->hair_in_mesh = NULL;
                        realloc_roots = true;
                }
        }
-       
 -      if (!psys->hair_in_dm || !psys->clmd->hairdata || realloc_roots) {
 +      if (!psys->hair_in_mesh || !psys->clmd->hairdata || realloc_roots) {
                if (psys->clmd->hairdata) {
                        MEM_freeN(psys->clmd->hairdata);
                        psys->clmd->hairdata = NULL;
                }
        }
-       
 -      hair_create_input_dm(sim, totpoint, totedge, &psys->hair_in_dm, &psys->clmd->hairdata);
 +      hair_create_input_mesh(sim, totpoint, totedge, &psys->hair_in_mesh, &psys->clmd->hairdata);
-       
 -      if (psys->hair_out_dm)
 -              psys->hair_out_dm->release(psys->hair_out_dm);
 +      if (psys->hair_out_mesh)
 +              BKE_id_free(NULL, psys->hair_out_mesh);
-       
        psys->clmd->point_cache = psys->pointcache;
        /* for hair sim we replace the internal cloth effector weights temporarily
         * to use the particle settings
         */
        clmd_effweights = psys->clmd->sim_parms->effector_weights;
        psys->clmd->sim_parms->effector_weights = psys->part->effector_weights;
-       
 -      deformedVerts = MEM_mallocN(sizeof(*deformedVerts) * psys->hair_in_dm->getNumVerts(psys->hair_in_dm), "do_hair_dynamics vertexCos");
 -      psys->hair_out_dm = CDDM_copy(psys->hair_in_dm);
 -      psys->hair_out_dm->getVertCos(psys->hair_out_dm, deformedVerts);
 -
 -      clothModifier_do(psys->clmd, sim->scene, sim->ob, psys->hair_in_dm, deformedVerts);
 -
 -      CDDM_apply_vert_coords(psys->hair_out_dm, deformedVerts);
 +      BKE_id_copy_ex(
 +                  NULL, &psys->hair_in_mesh->id, (ID **)&psys->hair_out_mesh,
 +                  LIB_ID_CREATE_NO_MAIN |
 +                  LIB_ID_CREATE_NO_USER_REFCOUNT |
 +                  LIB_ID_CREATE_NO_DEG_TAG |
 +                  LIB_ID_COPY_NO_PREVIEW,
 +                  false);
 +      deformedVerts = BKE_mesh_vertexCos_get(psys->hair_out_mesh, NULL);
 +      clothModifier_do(psys->clmd, sim->depsgraph, sim->scene, sim->ob, psys->hair_in_mesh, deformedVerts);
 +      BKE_mesh_apply_vert_coords(psys->hair_out_mesh, deformedVerts);
-       
        MEM_freeN(deformedVerts);
-       
        /* restore cloth effector weights */
        psys->clmd->sim_parms->effector_weights = clmd_effweights;
  }
@@@ -3773,8 -3761,8 +3773,8 @@@ static void cached_step(ParticleSimulat
        float disp, dietime;
  
        psys_update_effectors(sim);
-       
 -      disp= psys_get_current_display_percentage(psys);
 +      disp= psys_get_current_display_percentage(psys, use_render_params);
  
        LOOP_PARTICLES {
                psys_get_texture(sim, pa, &ptex, PAMAP_SIZE, cfra);
@@@ -3768,9 -3745,9 +3768,9 @@@ void BKE_ptcache_bake(PTCacheBaker *bak
  
        scene->r.framelen = frameleno;
        CFRA = cfrao;
-       
        if (bake) { /* already on cfra unless baking */
 -              BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay);
 +              BKE_scene_graph_update_for_newframe(depsgraph, bmain);
        }
  
        /* TODO: call redraw all windows somehow */
@@@ -292,18 -286,18 +292,18 @@@ static rbCollisionShape *rigidbody_get_
                int totvert;
                int tottri;
                const MLoop *mloop;
-               
 -              dm = rigidbody_get_mesh(ob);
 +              mesh = rigidbody_get_mesh(ob);
  
                /* ensure mesh validity, then grab data */
 -              if (dm == NULL)
 +              if (mesh == NULL)
                        return NULL;
  
 -              mvert   = dm->getVertArray(dm);
 -              totvert = dm->getNumVerts(dm);
 -              looptri = dm->getLoopTriArray(dm);
 -              tottri = dm->getNumLoopTri(dm);
 -              mloop = dm->getLoopArray(dm);
 +              mvert   = mesh->mvert;
 +              totvert = mesh->totvert;
 +              looptri = BKE_mesh_runtime_looptri_ensure(mesh);
 +              tottri = mesh->runtime.looptris.len;
 +              mloop = mesh->mloop;
  
                /* sanity checking - potential case when no data will be present */
                if ((totvert == 0) || (tottri == 0)) {
@@@ -520,17 -519,17 +520,17 @@@ void BKE_rigidbody_calc_volume(Object *
                                const MLoopTri *lt = NULL;
                                int totvert, tottri = 0;
                                const MLoop *mloop = NULL;
-                               
                                /* ensure mesh validity, then grab data */
 -                              if (dm == NULL)
 +                              if (mesh == NULL)
                                        return;
-                       
 -                              mvert   = dm->getVertArray(dm);
 -                              totvert = dm->getNumVerts(dm);
 -                              lt = dm->getLoopTriArray(dm);
 -                              tottri = dm->getNumLoopTri(dm);
 -                              mloop = dm->getLoopArray(dm);
 +                              mvert   = mesh->mvert;
 +                              totvert = mesh->totvert;
 +                              lt = BKE_mesh_runtime_looptri_ensure(mesh);
 +                              tottri = mesh->runtime.looptris.len;
 +                              mloop = mesh->mloop;
-                               
                                if (totvert > 0 && tottri > 0) {
                                        BKE_mesh_calc_volume(mvert, totvert, lt, tottri, mloop, &volume, NULL);
                                }
@@@ -598,17 -602,17 +598,17 @@@ void BKE_rigidbody_calc_center_of_mass(
                                const MLoopTri *looptri;
                                int totvert, tottri;
                                const MLoop *mloop;
-                               
                                /* ensure mesh validity, then grab data */
 -                              if (dm == NULL)
 +                              if (mesh == NULL)
                                        return;
-                       
 -                              mvert   = dm->getVertArray(dm);
 -                              totvert = dm->getNumVerts(dm);
 -                              looptri = dm->getLoopTriArray(dm);
 -                              tottri = dm->getNumLoopTri(dm);
 -                              mloop = dm->getLoopArray(dm);
 +                              mvert   = mesh->mvert;
 +                              totvert = mesh->totvert;
 +                              looptri = BKE_mesh_runtime_looptri_ensure(mesh);
 +                              tottri = mesh->runtime.looptris.len;
 +                              mloop = mesh->mloop;
-                               
                                if (totvert > 0 && tottri > 0) {
                                        BKE_mesh_calc_volume(mvert, totvert, looptri, tottri, mloop, NULL, r_center);
                                }
@@@ -1385,11 -1391,10 +1385,11 @@@ static void rigidbody_update_simulation
                        }
  
                        /* update simulation object... */
 -                      rigidbody_update_sim_ob(scene, rbw, ob, rbo);
 +                      rigidbody_update_sim_ob(depsgraph, scene, rbw, ob, rbo);
                }
        }
-       
 +      FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
        /* update constraints */
        if (rbw->constraints == NULL) /* no constraints, move on */
                return;
@@@ -476,15 -487,27 +476,15 @@@ void BKE_scene_free_ex(Scene *sce, cons
                sce->r.ffcodecdata.properties = NULL;
        }
  
 -      for (srl = sce->r.layers.first; srl; srl = srl->next) {
 -              if (srl->prop != NULL) {
 -                      IDP_FreeProperty(srl->prop);
 -                      MEM_freeN(srl->prop);
 -              }
 -              BKE_freestyle_config_free(&srl->freestyleConfig);
 -      }
 -
        BLI_freelistN(&sce->markers);
        BLI_freelistN(&sce->transform_spaces);
 -      BLI_freelistN(&sce->r.layers);
        BLI_freelistN(&sce->r.views);
-       
        BKE_toolsettings_free(sce->toolsettings);
        sce->toolsettings = NULL;
-       
 -      DAG_scene_free(sce);
 -      if (sce->depsgraph)
 -              DEG_graph_free(sce->depsgraph);
 +      BKE_scene_free_depsgraph_hash(sce);
  
 -      MEM_SAFE_FREE(sce->stats);
        MEM_SAFE_FREE(sce->fps_info);
  
        BKE_sound_destroy_scene(sce);
@@@ -532,8 -529,8 +532,8 @@@ void BKE_scene_init(Scene *sce
        BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(sce, id));
  
        sce->lay = sce->layact = 1;
-       
 -      sce->r.mode = R_GAMMA | R_OSA | R_SHADOW | R_SSS | R_ENVMAP | R_RAYTRACE;
 +      sce->r.mode = R_OSA;
        sce->r.cfra = 1;
        sce->r.sfra = 1;
        sce->r.efra = 250;
  
        sce->toolsettings->selectmode = SCE_SELECT_VERTEX;
        sce->toolsettings->uv_selectmode = UV_SELECT_VERTEX;
 -      sce->toolsettings->normalsize = 0.1;
        sce->toolsettings->autokey_mode = U.autokey_mode;
  
-       
 -      sce->toolsettings->snap_node_mode = SCE_SNAP_MODE_GRID;
 -      sce->toolsettings->skgen_resolution = 100;
 -      sce->toolsettings->skgen_threshold_internal     = 0.01f;
 -      sce->toolsettings->skgen_threshold_external     = 0.01f;
 -      sce->toolsettings->skgen_angle_limit            = 45.0f;
 -      sce->toolsettings->skgen_length_ratio           = 1.3f;
 -      sce->toolsettings->skgen_length_limit           = 1.5f;
 -      sce->toolsettings->skgen_correlation_limit      = 0.98f;
 -      sce->toolsettings->skgen_symmetry_limit         = 0.1f;
 -      sce->toolsettings->skgen_postpro = SKGEN_SMOOTH;
 -      sce->toolsettings->skgen_postpro_passes = 1;
 -      sce->toolsettings->skgen_options = SKGEN_FILTER_INTERNAL | SKGEN_FILTER_EXTERNAL | SKGEN_FILTER_SMART | SKGEN_HARMONIC | SKGEN_SUB_CORRELATION | SKGEN_STICK_TO_EMBEDDING;
 -      sce->toolsettings->skgen_subdivisions[0] = SKGEN_SUB_CORRELATION;
 -      sce->toolsettings->skgen_subdivisions[1] = SKGEN_SUB_LENGTH;
 -      sce->toolsettings->skgen_subdivisions[2] = SKGEN_SUB_ANGLE;
 +      sce->toolsettings->transform_pivot_point = V3D_AROUND_CENTER_MEAN;
 +      sce->toolsettings->snap_mode = SCE_SNAP_MODE_INCREMENT;
 +      sce->toolsettings->snap_node_mode = SCE_SNAP_MODE_GRID;
 +      sce->toolsettings->snap_uv_mode = SCE_SNAP_MODE_INCREMENT;
  
        sce->toolsettings->curve_paint_settings.curve_type = CU_BEZIER;
        sce->toolsettings->curve_paint_settings.flag |= CURVE_PAINT_FLAG_CORNERS_DETECT;
@@@ -908,22 -906,50 +908,22 @@@ Object *BKE_scene_object_find_by_name(S
   */
  void BKE_scene_set_background(Main *bmain, Scene *scene)
  {
 -      Scene *sce;
 -      Base *base;
        Object *ob;
-       
 -      Group *group;
 -      GroupObject *go;
 -      int flag;
        /* check for cyclic sets, for reading old files but also for definite security (py?) */
        BKE_scene_validate_setscene(bmain, scene);
-       
 -      /* can happen when switching modes in other scenes */
 -      if (scene->obedit && !(scene->obedit->mode & OB_MODE_EDIT))
 -              scene->obedit = NULL;
 -
        /* deselect objects (for dataselect) */
        for (ob = bmain->object.first; ob; ob = ob->id.next)
 -              ob->flag &= ~(SELECT | OB_FROMGROUP);
 -
 -      /* group flags again */
 -      for (group = bmain->group.first; group; group = group->id.next) {
 -              for (go = group->gobject.first; go; go = go->next) {
 -                      if (go->ob) {
 -                              go->ob->flag |= OB_FROMGROUP;
 -                      }
 -              }
 -      }
 -
 -      /* sort baselist for scene and sets */
 -      for (sce = scene; sce; sce = sce->set)
 -              DAG_scene_relations_rebuild(bmain, sce);
 +              ob->flag &= ~SELECT;
  
        /* copy layers and flags from bases to objects */
 -      for (base = scene->base.first; base; base = base->next) {
 -              ob = base->object;
 -              ob->lay = base->lay;
 -
 -              /* group patch... */
 -              base->flag &= ~(OB_FROMGROUP);
 -              flag = ob->flag & (OB_FROMGROUP);
 -              base->flag |= flag;
 -
 -              /* not too nice... for recovering objects with lost data */
 -              //if (ob->pose == NULL) base->flag &= ~OB_POSEMODE;
 -              ob->flag = base->flag;
 +      for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
 +              for (Base *base = view_layer->object_bases.first; base; base = base->next) {
 +                      ob = base->object;
 +                      /* collection patch... */
 +                      BKE_scene_object_base_flag_sync_from_base(base);
 +              }
        }
        /* no full animation update, this to enable render code to work (render code calls own animation updates) */
  }
@@@ -943,11 -969,11 +943,11 @@@ Scene *BKE_scene_set_name(Main *bmain, 
  }
  
  /* Used by metaballs, return *all* objects (including duplis) existing in the scene (including scene's sets) */
 -int BKE_scene_base_iter_next(Main *bmain, EvaluationContext *eval_ctx, SceneBaseIter *iter,
 -                             Scene **scene, int val, Base **base, Object **ob)
 +int BKE_scene_base_iter_next(Depsgraph *depsgraph, SceneBaseIter *iter,
 +        Scene **scene, int val, Base **base, Object **ob)
  {
        bool run_again = true;
-       
        /* init */
        if (val == 0) {
                iter->phase = F_START;
                        }
                        else {
                                if (iter->phase != F_DUPLI) {
 -                                      if ( (*base)->object->transflag & OB_DUPLI) {
 -                                              /* groups cannot be duplicated for mballs yet,
 +                                      if (depsgraph && (*base)->object->transflag & OB_DUPLI) {
-                                               /* collections cannot be duplicated for mballs yet, 
-                                                * this enters eternal loop because of 
++                                              /* collections cannot be duplicated for mballs yet,
+                                                * this enters eternal loop because of
 -                                               * makeDispListMBall getting called inside of group_duplilist */
 +                                               * makeDispListMBall getting called inside of collection_duplilist */
                                                if ((*base)->object->dup_group == NULL) {
 -                                                      iter->duplilist = object_duplilist_ex(bmain, eval_ctx, (*scene), (*base)->object, false);
 +                                                      iter->duplilist = object_duplilist(depsgraph, (*scene), (*base)->object);
-                                                       
                                                        iter->dupob = iter->duplilist->first;
  
                                                        if (!iter->dupob) {
                                }
                                else if (iter->phase == F_DUPLI) {
                                        iter->phase = F_SCENE;
 -                                      (*base)->flag &= ~OB_FROMDUPLI;
 +                                      (*base)->flag_legacy &= ~OB_FROMDUPLI;
-                                       
                                        if (iter->dupli_refob) {
                                                /* Restore last object's real matrix. */
                                                copy_m4_m4(iter->dupli_refob->obmat, iter->omat);
@@@ -216,19 -187,18 +216,19 @@@ static void panel_list_copy(ListBase *n
  ARegion *BKE_area_region_copy(SpaceType *st, ARegion *ar)
  {
        ARegion *newar = MEM_dupallocN(ar);
-       
 -      Panel *pa, *newpa, *patab;
        newar->prev = newar->next = NULL;
        BLI_listbase_clear(&newar->handlers);
        BLI_listbase_clear(&newar->uiblocks);
        BLI_listbase_clear(&newar->panels_category);
        BLI_listbase_clear(&newar->panels_category_active);
        BLI_listbase_clear(&newar->ui_lists);
 -      newar->swinid = 0;
 +      newar->visible = 0;
 +      newar->manipulator_map = NULL;
        newar->regiontimer = NULL;
        newar->headerstr = NULL;
-       
 +      newar->draw_buffer = NULL;
        /* use optional regiondata callback */
        if (ar->regiondata) {
                ARegionType *art = BKE_regiontype_from_id(st, ar->regiontype);
  
        if (ar->v2d.tab_offset)
                newar->v2d.tab_offset = MEM_dupallocN(ar->v2d.tab_offset);
-       
 -      BLI_listbase_clear(&newar->panels);
 -      BLI_duplicatelist(&newar->panels, &ar->panels);
 +      panel_list_copy(&newar->panels, &ar->panels);
  
        BLI_listbase_clear(&newar->ui_previews);
        BLI_duplicatelist(&newar->ui_previews, &ar->ui_previews);
-       
 -      /* copy panel pointers */
 -      for (newpa = newar->panels.first; newpa; newpa = newpa->next) {
 -              patab = newar->panels.first;
 -              pa = ar->panels.first;
 -              while (patab) {
 -                      if (newpa->paneltab == pa) {
 -                              newpa->paneltab = patab;
 -                              break;
 -                      }
 -                      patab = patab->next;
 -                      pa = pa->next;
 -              }
 -      }
 -
        return newar;
  }
  
@@@ -435,11 -374,10 +435,11 @@@ void BKE_screen_area_free(ScrArea *sa
        for (ar = sa->regionbase.first; ar; ar = ar->next)
                BKE_area_region_free(st, ar);
  
 +      MEM_SAFE_FREE(sa->global);
        BLI_freelistN(&sa->regionbase);
-       
        BKE_spacedata_freelist(&sa->spacedata);
-       
        BLI_freelistN(&sa->actionzones);
  }
  
index b116e99,0000000..c20fe34
mode 100644,000000..100644
--- /dev/null
@@@ -1,925 -1,0 +1,925 @@@
-       
 +/*
 + * ***** 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) 2006-2007 Blender Foundation.
 + * All rights reserved.
 + *
 + * The Original Code is: all of this file.
 + *
 + * Contributor(s): none yet.
 + *
 + * ***** END GPL LICENSE BLOCK *****
 + *
 + */
 +
 +/** \file blender/blenkernel/intern/studiolight.c
 + *  \ingroup bke
 + */
 +
 +#include "BKE_studiolight.h"
 +
 +#include "BKE_appdir.h"
 +#include "BKE_icons.h"
 +
 +#include "BLI_fileops.h"
 +#include "BLI_fileops_types.h"
 +#include "BLI_listbase.h"
 +#include "BLI_math.h"
 +#include "BLI_path_util.h"
 +#include "BLI_rand.h"
 +#include "BLI_string.h"
 +#include "BLI_string_utils.h"
 +
 +#include "DNA_listBase.h"
 +
 +#include "IMB_imbuf.h"
 +#include "IMB_imbuf_types.h"
 +
 +#include "GPU_texture.h"
 +
 +#include "MEM_guardedalloc.h"
 +
 +
 +/* Statics */
 +static ListBase studiolights;
 +#define STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE 16
 +#define STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT 64
 +#define STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_WIDTH (STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT * 2)
 +
 +static const char *STUDIOLIGHT_CAMERA_FOLDER = "studiolights/camera/";
 +static const char *STUDIOLIGHT_WORLD_FOLDER = "studiolights/world/";
 +static const char *STUDIOLIGHT_MATCAP_FOLDER = "studiolights/matcap/";
 +
 +/* FUNCTIONS */
 +static void studiolight_free(struct StudioLight *sl)
 +{
 +      for (int index = 0 ; index < 6 ; index ++) {
 +              if (sl->radiance_cubemap_buffers[index] != NULL) {
 +                      IMB_freeImBuf(sl->radiance_cubemap_buffers[index]);
 +                      sl->radiance_cubemap_buffers[index] = NULL;
 +              }
 +      }
 +      if (sl->equirectangular_radiance_gputexture) {
 +              GPU_texture_free(sl->equirectangular_radiance_gputexture);
 +              sl->equirectangular_radiance_gputexture = NULL;
 +      }
-       
++
 +      if (sl->equirectangular_irradiance_gputexture) {
 +              GPU_texture_free(sl->equirectangular_irradiance_gputexture);
 +              sl->equirectangular_irradiance_gputexture = NULL;
 +      }
-       
++
 +      if (sl->equirectangular_radiance_buffer) {
 +              IMB_freeImBuf(sl->equirectangular_radiance_buffer);
 +              sl->equirectangular_radiance_buffer = NULL;
 +      }
-         ImBuf *radiance_buffer, const float normal[3], float color[3], 
++
 +      if (sl->equirectangular_irradiance_buffer) {
 +              IMB_freeImBuf(sl->equirectangular_irradiance_buffer);
 +              sl->equirectangular_irradiance_buffer = NULL;
 +      }
 +      if (sl->path_irr) {
 +              MEM_freeN(sl->path_irr);
 +              sl->path_irr = NULL;
 +      }
 +      if (sl->gpu_matcap_3components) {
 +              MEM_freeN(sl->gpu_matcap_3components);
 +              sl->gpu_matcap_3components = NULL;
 +      }
 +      MEM_freeN(sl);
 +}
 +
 +static struct StudioLight *studiolight_create(int flag)
 +{
 +      struct StudioLight *sl = MEM_callocN(sizeof(*sl), __func__);
 +      sl->path[0] = 0x00;
 +      sl->name[0] = 0x00;
 +      sl->path_irr = NULL;
 +      sl->flag = flag;
 +      sl->index = BLI_listbase_count(&studiolights);
 +      if (flag & STUDIOLIGHT_ORIENTATION_VIEWNORMAL) {
 +              sl->icon_id_matcap = BKE_icon_ensure_studio_light(sl, STUDIOLIGHT_ICON_ID_TYPE_MATCAP);
 +              sl->icon_id_matcap_flipped = BKE_icon_ensure_studio_light(sl, STUDIOLIGHT_ICON_ID_TYPE_MATCAP_FLIPPED);
 +      }
 +      else {
 +              sl->icon_id_radiance = BKE_icon_ensure_studio_light(sl, STUDIOLIGHT_ICON_ID_TYPE_RADIANCE);
 +              sl->icon_id_irradiance = BKE_icon_ensure_studio_light(sl, STUDIOLIGHT_ICON_ID_TYPE_IRRADIANCE);
 +      }
 +
 +      for (int index = 0 ; index < 6 ; index ++) {
 +              sl->radiance_cubemap_buffers[index] = NULL;
 +      }
 +      return sl;
 +}
 +
 +static void direction_to_equirectangular(float r[2], const float dir[3])
 +{
 +      r[0] = (atan2f(dir[1], dir[0]) - M_PI) / -(M_PI * 2);
 +      r[1] = (acosf(dir[2] / 1.0) - M_PI) / -M_PI;
 +}
 +
 +static void equirectangular_to_direction(float r[3], float u, float v)
 +{
 +      float phi = (-(M_PI * 2)) * u + M_PI;
 +      float theta = -M_PI * v + M_PI;
 +      float sin_theta = sinf(theta);
 +      r[0] = sin_theta * cosf(phi);
 +      r[1] = sin_theta * sinf(phi);
 +      r[2] = cosf(theta);
 +}
 +
 +static void studiolight_calculate_radiance(ImBuf *ibuf, float color[4], const float direction[3])
 +{
 +      float uv[2];
 +      direction_to_equirectangular(uv, direction);
 +      nearest_interpolation_color_wrap(ibuf, NULL, color, uv[0] * ibuf->x, uv[1] * ibuf->y);
 +}
 +
 +static void studiolight_calculate_radiance_buffer(
 +        ImBuf *ibuf, float *colbuf,
 +        const float start_x, const float add_x,
 +        const float start_y, const float add_y, const float z,
 +        const int index_x, const int index_y, const int index_z)
 +{
 +      float direction[3];
 +      float yf = start_y;
 +      float xf;
 +      float *color = colbuf;
 +
 +      for (int y = 0; y < STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; y ++, yf += add_y) {
 +              xf = start_x;
 +              for (int x = 0; x < STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; x ++, xf += add_x) {
 +                      direction[index_x] = xf;
 +                      direction[index_y] = yf;
 +                      direction[index_z] = z;
 +                      normalize_v3(direction);
 +                      studiolight_calculate_radiance(ibuf, color, direction);
 +                      color += 4;
 +              }
 +      }
 +}
 +
 +static void studiolight_load_equirectangular_image(StudioLight *sl)
 +{
 +      if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
 +              ImBuf *ibuf = NULL;
 +              ibuf = IMB_loadiffname(sl->path, 0, NULL);
 +              if (ibuf) {
 +                      IMB_float_from_rect(ibuf);
 +                      sl->equirectangular_radiance_buffer = ibuf;
 +              }
 +      }
 +      sl->flag |= STUDIOLIGHT_EXTERNAL_IMAGE_LOADED;
 +}
 +
 +static void studiolight_create_equirectangular_radiance_gputexture(StudioLight *sl)
 +{
 +      if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
 +              char error[256];
 +              BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
 +              ImBuf *ibuf = sl->equirectangular_radiance_buffer;
 +
 +              if (sl->flag & STUDIOLIGHT_ORIENTATION_VIEWNORMAL) {
 +                      sl->gpu_matcap_3components = MEM_callocN(sizeof(float[3]) * ibuf->x * ibuf->y, __func__);
 +
 +                      float *offset4 = ibuf->rect_float;
 +                      float *offset3 = sl->gpu_matcap_3components;
 +                      for (int i = 0 ; i < ibuf->x * ibuf->y; i++) {
 +                              copy_v3_v3(offset3, offset4);
 +                              offset3 += 3;
 +                              offset4 += 4;
 +                      }
 +                      sl->equirectangular_radiance_gputexture = GPU_texture_create_2D(
 +                              ibuf->x, ibuf->y, GPU_R11F_G11F_B10F, sl->gpu_matcap_3components, error);
 +              }
 +              else {
 +                      sl->equirectangular_radiance_gputexture = GPU_texture_create_2D(
 +                              ibuf->x, ibuf->y, GPU_RGBA16F, ibuf->rect_float, error);
 +                      GPUTexture *tex = sl->equirectangular_radiance_gputexture;
 +                      GPU_texture_bind(tex, 0);
 +                      GPU_texture_filter_mode(tex, true);
 +                      GPU_texture_wrap_mode(tex, true);
 +                      GPU_texture_unbind(tex);
 +              }
 +      }
 +      sl->flag |= STUDIOLIGHT_EQUIRECTANGULAR_RADIANCE_GPUTEXTURE;
 +}
 +
 +static void studiolight_create_equirectangular_irradiance_gputexture(StudioLight *sl)
 +{
 +      if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
 +              char error[256];
 +              BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_IMAGE_CALCULATED);
 +              ImBuf *ibuf = sl->equirectangular_irradiance_buffer;
 +              sl->equirectangular_irradiance_gputexture = GPU_texture_create_2D(
 +                      ibuf->x, ibuf->y, GPU_RGBA16F, ibuf->rect_float, error);
 +              GPUTexture *tex = sl->equirectangular_irradiance_gputexture;
 +              GPU_texture_bind(tex, 0);
 +              GPU_texture_filter_mode(tex, true);
 +              GPU_texture_wrap_mode(tex, true);
 +              GPU_texture_unbind(tex);
 +      }
 +      sl->flag |= STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_GPUTEXTURE;
 +}
 +
 +static void studiolight_calculate_radiance_cubemap_buffers(StudioLight *sl)
 +{
 +      if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
 +              BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
 +              ImBuf *ibuf = sl->equirectangular_radiance_buffer;
 +              if (ibuf) {
 +                      float *colbuf = MEM_mallocN(SQUARE(STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE) * sizeof(float[4]), __func__);
 +                      const float add = 1.0f / (STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE + 1);
 +                      const float start = ((1.0f / STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE) * 0.5f) - 0.5f;
 +
 +                      /* front */
 +                      studiolight_calculate_radiance_buffer(ibuf, colbuf, start, add, start, add, 0.5f, 0, 2, 1);
 +                      sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_POS] = IMB_allocFromBuffer(
 +                              NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
 +
 +                      /* back */
 +                      studiolight_calculate_radiance_buffer(ibuf, colbuf, -start, -add, start, add, -0.5f, 0, 2, 1);
 +                      sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_NEG] = IMB_allocFromBuffer(
 +                              NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
 +
 +                      /* left */
 +                      studiolight_calculate_radiance_buffer(ibuf, colbuf, -start, -add, start, add, 0.5f, 1, 2, 0);
 +                      sl->radiance_cubemap_buffers[STUDIOLIGHT_X_POS] = IMB_allocFromBuffer(
 +                              NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
 +
 +                      /* right */
 +                      studiolight_calculate_radiance_buffer(ibuf, colbuf, start, add, start, add, -0.5f, 1, 2, 0);
 +                      sl->radiance_cubemap_buffers[STUDIOLIGHT_X_NEG] = IMB_allocFromBuffer(
 +                              NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
 +
 +                      /* top */
 +                      studiolight_calculate_radiance_buffer(ibuf, colbuf, start, add, start, add, -0.5f, 0, 1, 2);
 +                      sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_NEG] = IMB_allocFromBuffer(
 +                              NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
 +
 +                      /* bottom */
 +                      studiolight_calculate_radiance_buffer(ibuf, colbuf, start, add, -start, -add, 0.5f, 0, 1, 2);
 +                      sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_POS] = IMB_allocFromBuffer(
 +                              NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
 +
 +#if 0
 +                      IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_X_POS], "/tmp/studiolight_radiance_left.png", IB_rectfloat);
 +                      IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_X_NEG], "/tmp/studiolight_radiance_right.png", IB_rectfloat);
 +                      IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_POS], "/tmp/studiolight_radiance_front.png", IB_rectfloat);
 +                      IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_NEG], "/tmp/studiolight_radiance_back.png", IB_rectfloat);
 +                      IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_POS], "/tmp/studiolight_radiance_bottom.png", IB_rectfloat);
 +                      IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_NEG], "/tmp/studiolight_radiance_top.png", IB_rectfloat);
 +#endif
 +                      MEM_freeN(colbuf);
 +              }
 +      }
 +      sl->flag |= STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED;
 +}
 +
 +BLI_INLINE void studiolight_evaluate_radiance_buffer(
 +        ImBuf *radiance_buffer, const float normal[3], float color[3], int *hits,
 +        int xoffset, int yoffset, int zoffset, float zvalue)
 +{
 +      if (radiance_buffer == NULL) {
 +              return;
 +      }
 +      float angle;
 +      float *radiance_color = radiance_buffer->rect_float;
 +      float direction[3];
 +      for (int y = 0; y < STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; y ++) {
 +              for (int x = 0; x < STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; x ++) {
 +                      // calculate light direction;
 +                      direction[zoffset] = zvalue;
 +                      direction[xoffset] = (x / (float)STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE) - 0.5f;
 +                      direction[yoffset] = (y / (float)STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE) - 0.5f;
 +                      normalize_v3(direction);
 +                      angle = fmax(0.0f, dot_v3v3(direction, normal));
 +                      madd_v3_v3fl(color, radiance_color, angle);
 +                      (*hits) ++;
 +                      radiance_color += 4;
 +              }
 +      }
 +
 +}
 +
 +static void studiolight_calculate_irradiance(StudioLight *sl, float color[3], const float normal[3])
 +{
 +      int hits = 0;
 +      copy_v3_fl(color, 0.0f);
 +
 +      /* back */
 +      studiolight_evaluate_radiance_buffer(sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_POS], normal, color, &hits, 0, 2, 1, 0.5);
 +      /* front */
 +      studiolight_evaluate_radiance_buffer(sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_NEG], normal, color, &hits, 0, 2, 1, -0.5);
 +
 +      /* left */
 +      studiolight_evaluate_radiance_buffer(sl->radiance_cubemap_buffers[STUDIOLIGHT_X_POS], normal, color, &hits, 1, 2, 0, 0.5);
 +      /* right */
 +      studiolight_evaluate_radiance_buffer(sl->radiance_cubemap_buffers[STUDIOLIGHT_X_NEG], normal, color, &hits, 1, 2, 0, -0.5);
 +
 +      /* top */
 +      studiolight_evaluate_radiance_buffer(sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_POS], normal, color, &hits, 0, 1, 2, 0.5);
 +      /* bottom */
 +      studiolight_evaluate_radiance_buffer(sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_NEG], normal, color, &hits, 0, 1, 2, -0.5);
 +
 +      if (hits) {
 +              mul_v3_fl(color, 3.0 / hits);
 +      }
 +      else {
 +              copy_v3_fl3(color, 1.0, 0.0, 1.0);
 +      }
 +}
 +
 +
 +static void studiolight_calculate_diffuse_light(StudioLight *sl)
 +{
 +      /* init light to black */
 +      copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_X_POS], 0.0f);
 +      copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_X_NEG], 0.0f);
 +      copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_Y_POS], 0.0f);
 +      copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_Y_NEG], 0.0f);
 +      copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_Z_POS], 0.0f);
 +      copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_Z_NEG], 0.0f);
 +
 +      if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
 +              const float normal_x_neg[3] = {-1.0f,  0.0f,  0.0f};
 +              const float normal_x_pos[3] = { 1.0f,  0.0f,  0.0f};
 +              const float normal_y_neg[3] = { 0.0f,  1.0f,  0.0f};
 +              const float normal_y_pos[3] = { 0.0f, -1.0f,  0.0f};
 +              const float normal_z_neg[3] = { 0.0f,  0.0f, -1.0f};
 +              const float normal_z_pos[3] = { 0.0f,  0.0f,  1.0f};
 +
 +              BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED);
 +
 +              studiolight_calculate_irradiance(sl, sl->diffuse_light[STUDIOLIGHT_X_POS], normal_x_pos);
 +              studiolight_calculate_irradiance(sl, sl->diffuse_light[STUDIOLIGHT_X_NEG], normal_x_neg);
 +              studiolight_calculate_irradiance(sl, sl->diffuse_light[STUDIOLIGHT_Y_POS], normal_y_pos);
 +              studiolight_calculate_irradiance(sl, sl->diffuse_light[STUDIOLIGHT_Y_NEG], normal_y_neg);
 +              studiolight_calculate_irradiance(sl, sl->diffuse_light[STUDIOLIGHT_Z_POS], normal_z_pos);
 +              studiolight_calculate_irradiance(sl, sl->diffuse_light[STUDIOLIGHT_Z_NEG], normal_z_neg);
 +      }
 +      sl->flag |= STUDIOLIGHT_DIFFUSE_LIGHT_CALCULATED;
 +}
 +
 +static float area_element(float x, float y )
 +{
 +      return atan2f(x * y, sqrt(x * x + y * y + 1));
 +}
 +
 +static float texel_coord_solid_angle(float a_U, float a_V, int a_Size)
 +{
 +      //scale up to [-1, 1] range (inclusive), offset by 0.5 to point to texel center.
 +      float u = (2.0f * ((float)a_U + 0.5f) / (float)a_Size ) - 1.0f;
 +      float v = (2.0f * ((float)a_V + 0.5f) / (float)a_Size ) - 1.0f;
 +
 +      float resolution_inv = 1.0f / a_Size;
 +
 +      // U and V are the -1..1 texture coordinate on the current face.
 +      // Get projected area for this texel
 +      float x0 = u - resolution_inv;
 +      float y0 = v - resolution_inv;
 +      float x1 = u + resolution_inv;
 +      float y1 = v + resolution_inv;
 +      return area_element(x0, y0) - area_element(x0, y1) - area_element(x1, y0) + area_element(x1, y1);
 +}
 +
 +BLI_INLINE void studiolight_evaluate_specular_radiance_buffer(
-               
++        ImBuf *radiance_buffer, const float normal[3], float color[3],
 +        int xoffset, int yoffset, int zoffset, float zvalue)
 +{
 +      if (radiance_buffer == NULL) {
 +              return;
 +      }
 +      float angle;
 +      float *radiance_color = radiance_buffer->rect_float;
 +      float direction[3];
 +      for (int y = 0; y < STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; y ++) {
 +              for (int x = 0; x < STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; x ++) {
 +                      // calculate light direction;
 +                      float u = (x / (float)STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE) - 0.5f;
 +                      float v = (y / (float)STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE) - 0.5f;
 +                      direction[zoffset] = zvalue;
 +                      direction[xoffset] = u;
 +                      direction[yoffset] = v;
 +                      normalize_v3(direction);
 +                      angle = fmax(0.0f, dot_v3v3(direction, normal)) * texel_coord_solid_angle(x, y, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
 +                      madd_v3_v3fl(color, radiance_color, angle);
 +                      radiance_color += 4;
 +              }
 +      }
 +
 +}
 +
 +static void studiolight_calculate_specular_irradiance(StudioLight *sl, float color[3], const float normal[3])
 +{
 +      copy_v3_fl(color, 0.0f);
 +
 +      /* back */
 +      studiolight_evaluate_specular_radiance_buffer(
 +              sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_POS], normal, color, 0, 2, 1, 0.5);
 +      /* front */
 +      studiolight_evaluate_specular_radiance_buffer(
 +              sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_NEG], normal, color, 0, 2, 1, -0.5);
 +
 +      /* left */
 +      studiolight_evaluate_specular_radiance_buffer(
 +              sl->radiance_cubemap_buffers[STUDIOLIGHT_X_POS], normal, color, 1, 2, 0, 0.5);
 +      /* right */
 +      studiolight_evaluate_specular_radiance_buffer(
 +              sl->radiance_cubemap_buffers[STUDIOLIGHT_X_NEG], normal, color, 1, 2, 0, -0.5);
 +
 +      /* top */
 +      studiolight_evaluate_specular_radiance_buffer(
 +              sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_POS], normal, color, 0, 1, 2, 0.5);
 +      /* bottom */
 +      studiolight_evaluate_specular_radiance_buffer(
 +              sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_NEG], normal, color, 0, 1, 2, -0.5);
 +
 +      mul_v3_fl(color, 1.0 / M_PI);
 +}
 +
 +static bool studiolight_load_irradiance_equirectangular_image(StudioLight *sl)
 +{
 +#if 1
 +      if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
 +              ImBuf *ibuf = NULL;
 +              ibuf = IMB_loadiffname(sl->path_irr, 0, NULL);
 +              if (ibuf) {
 +                      IMB_float_from_rect(ibuf);
 +                      sl->equirectangular_irradiance_buffer = ibuf;
 +                      sl->flag |= STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_IMAGE_CALCULATED;
 +                      return true;
 +              }
 +      }
 +#endif
 +      return false;
 +}
 +
 +static void studiolight_calculate_irradiance_equirectangular_image(StudioLight *sl)
 +{
 +      if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
 +              /* check for cached irr file */
++
 +              BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED);
 +
 +              float *colbuf = MEM_mallocN(STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_WIDTH * STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT * sizeof(float[4]), __func__);
 +              float *color = colbuf;
 +              for (int y = 0; y < STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT ; y ++) {
 +                      float yf = y / (float)STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT;
 +
 +                      for (int x = 0; x < STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_WIDTH ; x ++) {
 +                              float xf = x / (float)STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_WIDTH;
 +                              float dir[3];
 +                              equirectangular_to_direction(dir, xf, yf);
 +                              studiolight_calculate_specular_irradiance(sl, color, dir);
 +                              color[3] = 1.0f;
 +                              color += 4;
 +                      }
 +              }
 +              sl->equirectangular_irradiance_buffer = IMB_allocFromBuffer(
 +                      NULL, colbuf,
 +                      STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_WIDTH,
 +                      STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT);
 +              MEM_freeN(colbuf);
 +
 +              if (sl->flag | STUDIOLIGHT_USER_DEFINED) {
 +                      IMB_saveiff(sl->equirectangular_irradiance_buffer, sl->path_irr, IB_rectfloat);
 +              }
 +      }
 +      sl->flag |= STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_IMAGE_CALCULATED;
 +}
 +
 +static void studiolight_calculate_light_direction(StudioLight *sl)
 +{
 +      float best_light = 0.0;
 +      sl->light_direction[0] = 0.0f;
 +      sl->light_direction[1] = 0.0f;
 +      sl->light_direction[2] = -1.0f;
 +
 +      if ((sl->flag & STUDIOLIGHT_EXTERNAL_FILE) && (sl->flag & STUDIOLIGHT_ORIENTATION_WORLD)) {
 +              BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_IMAGE_CALCULATED);
 +              ImBuf *ibuf = sl->equirectangular_irradiance_buffer;
 +              if (ibuf) {
 +                      /* go over every pixel, determine light, if higher calc direction off the light */
 +                      float new_light;
 +                      float *color = ibuf->rect_float;
 +                      for (int y = 0; y < STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT; y ++) {
 +                              for (int x = 0; x < STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_WIDTH; x ++) {
 +                                      new_light = color[0] + color[1] + color[2];
 +                                      if (new_light > best_light) {
 +                                              float u = x / (float)STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_WIDTH;
 +                                              float v = y / (float)STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT;
 +                                              equirectangular_to_direction(sl->light_direction, u, v);
 +                                              SWAP(float, sl->light_direction[0], sl->light_direction[1]);
 +                                              normalize_v3(sl->light_direction);
 +                                              negate_v3(sl->light_direction);
 +                                              best_light = new_light;
 +                                      }
 +                                      color += 4;
 +                              }
 +                      }
 +              }
 +      }
 +      sl->flag |= STUDIOLIGHT_LIGHT_DIRECTION_CALCULATED;
 +}
 +
 +static void studiolight_add_files_from_datafolder(const int folder_id, const char *subfolder, int flag)
 +{
 +      StudioLight *sl;
 +      struct direntry *dir;
 +      const char *folder = BKE_appdir_folder_id(folder_id, subfolder);
 +      if (folder) {
 +              uint totfile = BLI_filelist_dir_contents(folder, &dir);
 +              int i;
 +              for (i = 0; i < totfile; i++) {
 +                      if ((dir[i].type & S_IFREG)) {
 +                              const char *filename = dir[i].relname;
 +                              const char *path = dir[i].path;
 +                              if (BLI_path_extension_check_array(filename, imb_ext_image)) {
 +                                      sl = studiolight_create(STUDIOLIGHT_EXTERNAL_FILE | flag);
 +                                      BLI_strncpy(sl->name, filename, FILE_MAXFILE);
 +                                      BLI_strncpy(sl->path, path, FILE_MAXFILE);
 +                                      sl->path_irr = BLI_string_joinN(path, ".irr");
 +                                      BLI_addtail(&studiolights, sl);
 +                              }
 +                      }
 +              }
 +              BLI_filelist_free(dir, totfile);
 +              dir = NULL;
 +      }
 +
 +}
 +
 +static int studiolight_flag_cmp_order(const StudioLight *sl)
 +{
 +      /* Internal studiolights before external studio lights */
 +      if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
 +              return 1;
 +      }
 +      return 0;
 +}
 +
 +static int studiolight_cmp(const void *a, const void *b)
 +{
 +      const StudioLight *sl1 = a;
 +      const StudioLight *sl2 = b;
 +
 +      const int flagorder1 = studiolight_flag_cmp_order(sl1);
 +      const int flagorder2 = studiolight_flag_cmp_order(sl2);
 +
 +      if (flagorder1 < flagorder2) {
 +              return -1;
 +      }
 +      else if (flagorder1 > flagorder2) {
 +              return 1;
 +      }
 +      else {
 +              return BLI_strcasecmp(sl1->name, sl2->name);
 +      }
 +}
 +
 +/* icons */
 +
 +/* Takes normalized uvs as parameter (range from 0 to 1).
 + * inner_edge and outer_edge are distances (from the center)
 + * in uv space for the alpha mask falloff. */
 +static uint alpha_circle_mask(float u, float v, float inner_edge, float outer_edge)
 +{
 +      /* Coords from center. */
 +      float co[2] = {u - 0.5f, v - 0.5f};
 +      float dist = len_v2(co);
 +      float alpha = 1.0f + (inner_edge - dist) / (outer_edge - inner_edge);
 +      uint mask = (uint)floorf(255.0f * min_ff(max_ff(alpha, 0.0f), 1.0f));
 +      return mask << 24;
 +}
 +
 +#define STUDIOLIGHT_DIAMETER 0.95f
 +
 +static uint *studiolight_radiance_preview(StudioLight *sl, int icon_size)
 +{
 +      BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
 +
 +      uint *rect = MEM_mallocN(icon_size * icon_size * sizeof(uint), __func__);
 +      float pixel_size = 1.0f / (float)icon_size;
 +
 +      int offset = 0;
 +      for (int y = 0; y < icon_size; y++) {
 +              float dy = (y + 0.5f) / (float)icon_size;
 +              dy = dy / STUDIOLIGHT_DIAMETER - (1.0f - STUDIOLIGHT_DIAMETER) / 2.0f;
 +              for (int x = 0; x < icon_size; x++) {
 +                      float dx = (x + 0.5f) / (float)icon_size;
 +                      dx = dx / STUDIOLIGHT_DIAMETER - (1.0f - STUDIOLIGHT_DIAMETER) / 2.0f;
 +
 +                      uint pixelresult = 0x0;
 +                      uint alphamask = alpha_circle_mask(dx, dy, 0.5f - pixel_size, 0.5f);
 +                      if (alphamask != 0) {
 +                              float incoming[3] = {0.0f, 0.0f, -1.0f};
 +
 +                              float normal[3];
 +                              normal[0] = dx * 2.0f - 1.0f;
 +                              normal[1] = dy * 2.0f - 1.0f;
 +                              float dist = len_v2(normal);
 +                              normal[2] = sqrtf(1.0f - SQUARE(dist));
 +
 +                              float direction[3];
 +                              reflect_v3_v3v3(direction, incoming, normal);
 +
 +                              /* We want to see horizon not poles. */
 +                              SWAP(float, direction[1], direction[2]);
 +                              direction[1] = -direction[1];
 +
 +                              float color[4];
 +                              studiolight_calculate_radiance(sl->equirectangular_radiance_buffer, color, direction);
 +
 +                              pixelresult = rgb_to_cpack(
 +                                      linearrgb_to_srgb(color[0]),
 +                                      linearrgb_to_srgb(color[1]),
 +                                      linearrgb_to_srgb(color[2])) | alphamask;
 +                      }
 +                      rect[offset++] = pixelresult;
 +              }
 +      }
 +      return rect;
 +}
 +
 +static uint *studiolight_matcap_preview(StudioLight *sl, int icon_size, bool flipped)
 +{
 +      BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
 +
 +      uint *rect = MEM_mallocN(icon_size * icon_size * sizeof(uint), __func__);
 +      float color[4];
 +      float fx, fy;
 +      float pixel_size = 1.0f / (float)icon_size;
 +      int offset = 0;
 +      ImBuf *ibuf = sl->equirectangular_radiance_buffer;
 +
 +      for (int y = 0; y < icon_size; y++) {
 +              fy = (y + 0.5f) / (float)icon_size;
 +              fy = fy / STUDIOLIGHT_DIAMETER - (1.0f - STUDIOLIGHT_DIAMETER) / 2.0f;
 +              for (int x = 0; x < icon_size; x++) {
 +                      fx = (x + 0.5f) / (float)icon_size;
 +                      fx = fx / STUDIOLIGHT_DIAMETER - (1.0f - STUDIOLIGHT_DIAMETER) / 2.0f;
 +                      if (flipped) {
 +                              fx = 1.0f - fx;
 +                      }
 +                      nearest_interpolation_color(ibuf, NULL, color, fx * ibuf->x, fy * ibuf->y);
 +
 +                      uint alphamask = alpha_circle_mask(fx, fy, 0.5f - pixel_size, 0.5f);
 +
 +                      rect[offset++] = rgb_to_cpack(
 +                              linearrgb_to_srgb(color[0]),
 +                              linearrgb_to_srgb(color[1]),
 +                              linearrgb_to_srgb(color[2])) | alphamask;
 +              }
 +      }
 +      return rect;
 +}
 +
 +static uint *studiolight_irradiance_preview(StudioLight *sl, int icon_size)
 +{
 +#if 0
 +      if (!(sl->flag & STUDIOLIGHT_EXTERNAL_FILE))
 +#endif
 +      {
 +
 +              BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_DIFFUSE_LIGHT_CALCULATED);
 +
 +              uint *rect = MEM_mallocN(icon_size * icon_size * sizeof(uint), __func__);
 +              float pixel_size = 1.0f / (float)icon_size;
 +
 +              int offset = 0;
 +              for (int y = 0; y < icon_size; y++) {
 +                      float dy = (y + 0.5f) / (float)icon_size;
 +                      dy = dy / STUDIOLIGHT_DIAMETER - (1.0f - STUDIOLIGHT_DIAMETER) / 2.0f;
 +                      for (int x = 0; x < icon_size; x++) {
 +                              float dx = (x + 0.5f) / (float)icon_size;
 +                              dx = dx / STUDIOLIGHT_DIAMETER - (1.0f - STUDIOLIGHT_DIAMETER) / 2.0f;
 +
 +                              uint pixelresult = 0x0;
 +                              uint alphamask = alpha_circle_mask(dx, dy, 0.5f - pixel_size, 0.5f);
 +                              if (alphamask != 0) {
 +                                      /* calculate normal */
 +                                      float normal[3];
 +                                      normal[0] = dx * 2.0f - 1.0f;
 +                                      normal[1] = dy * 2.0f - 1.0f;
 +                                      float dist = len_v2(normal);
 +                                      normal[2] = sqrtf(1.0f - SQUARE(dist));
 +
 +                                      float color[3];
 +                                      mul_v3_v3fl(color, sl->diffuse_light[STUDIOLIGHT_X_POS], clamp_f(normal[0], 0.0, 1.0));
 +                                      interp_v3_v3v3(color, color, sl->diffuse_light[STUDIOLIGHT_X_NEG], clamp_f(-normal[0], 0.0, 1.0));
 +                                      interp_v3_v3v3(color, color, sl->diffuse_light[STUDIOLIGHT_Z_POS], clamp_f(normal[1], 0.0, 1.0));
 +                                      interp_v3_v3v3(color, color, sl->diffuse_light[STUDIOLIGHT_Z_NEG], clamp_f(-normal[1], 0.0, 1.0));
 +                                      interp_v3_v3v3(color, color, sl->diffuse_light[STUDIOLIGHT_Y_POS], clamp_f(normal[2], 0.0, 1.0));
 +
 +                                      pixelresult = rgb_to_cpack(
 +                                              linearrgb_to_srgb(color[0]),
 +                                              linearrgb_to_srgb(color[1]),
 +                                              linearrgb_to_srgb(color[2])) | alphamask;
 +                              }
 +                              rect[offset++] = pixelresult;
 +                      }
 +              }
 +              return rect;
 +      }
 +#if 0
 +      else {
 +              BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_IMAGE_CALCULATED);
 +
 +              uint *rect = MEM_mallocN(icon_size * icon_size * sizeof(uint), __func__);
 +              int icon_center = icon_size / 2;
 +              float sphere_radius = icon_center * 0.9;
 +
 +              int offset = 0;
 +              for (int y = 0; y < icon_size; y++) {
 +                      float dy = y - icon_center;
 +                      for (int x = 0; x < icon_size; x++) {
 +                              float dx = x - icon_center;
 +                              /* calculate aliasing */
 +                              float alias = 0;
 +                              const float alias_step = 0.333;
 +                              for (float ay = dy - 0.5; ay < dy + 0.5; ay += alias_step) {
 +                                      for (float ax = dx - 0.5; ax < dx + 0.5; ax += alias_step) {
 +                                              if (sqrt(ay * ay + ax * ax) < sphere_radius) {
 +                                                      alias += alias_step * alias_step;
 +                                              }
 +                                      }
 +                              }
 +                              uint pixelresult = 0x0;
 +                              uint alias_i = clamp_i(alias * 256, 0, 255);
 +                              if (alias_i != 0) {
 +                                      /* calculate normal */
 +                                      uint alias_mask = alias_i << 24;
 +                                      float incoming[3];
 +                                      copy_v3_fl3(incoming, 0.0, 1.0, 0.0);
 +
 +                                      float normal[3];
 +                                      normal[0] = dx / sphere_radius;
 +                                      normal[2] = dy / sphere_radius;
 +                                      normal[1] = -sqrt(-(normal[0] * normal[0]) - (normal[2] * normal[2]) + 1);
 +                                      normalize_v3(normal);
 +
 +                                      float direction[3];
 +                                      reflect_v3_v3v3(direction, incoming, normal);
 +
 +                                      float color[4];
 +                                      studiolight_calculate_radiance(sl->equirectangular_irradiance_buffer, color, direction);
 +
 +                                      pixelresult = rgb_to_cpack(
 +                                              linearrgb_to_srgb(color[0]),
 +                                              linearrgb_to_srgb(color[1]),
 +                                              linearrgb_to_srgb(color[2])) | alias_mask;
 +                              }
 +                              rect[offset++] = pixelresult;
 +                      }
 +              }
 +              return rect;
 +      }
 +#endif
 +}
 +
 +/* API */
 +void BKE_studiolight_init(void)
 +{
 +      StudioLight *sl;
 +      /* go over the preset folder and add a studiolight for every image with its path */
 +      /* order studio lights by name */
 +      /* Also reserve icon space for it. */
 +      /* Add default studio light */
 +      sl = studiolight_create(STUDIOLIGHT_INTERNAL | STUDIOLIGHT_DIFFUSE_LIGHT_CALCULATED | STUDIOLIGHT_ORIENTATION_CAMERA);
 +      BLI_strncpy(sl->name, "INTERNAL_01", FILE_MAXFILE);
 +      copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_X_POS], 1.5f);
 +      copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_X_NEG], 0.0f);
 +      copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_Y_POS], 0.8f);
 +      copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_Y_NEG], 0.05f);
 +      copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_Z_POS], 0.2f);
 +      copy_v3_fl3(sl->diffuse_light[STUDIOLIGHT_Z_NEG], 0.1f, 0.0f, 0.0f);
 +      BLI_addtail(&studiolights, sl);
 +
 +      studiolight_add_files_from_datafolder(BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_CAMERA_FOLDER, STUDIOLIGHT_ORIENTATION_CAMERA);
 +      studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES,   STUDIOLIGHT_CAMERA_FOLDER, STUDIOLIGHT_ORIENTATION_CAMERA | STUDIOLIGHT_USER_DEFINED);
 +      studiolight_add_files_from_datafolder(BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_WORLD_FOLDER,  STUDIOLIGHT_ORIENTATION_WORLD);
 +      studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES,   STUDIOLIGHT_WORLD_FOLDER,  STUDIOLIGHT_ORIENTATION_WORLD | STUDIOLIGHT_USER_DEFINED);
 +      studiolight_add_files_from_datafolder(BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_MATCAP_FOLDER, STUDIOLIGHT_ORIENTATION_VIEWNORMAL);
 +      studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES,   STUDIOLIGHT_MATCAP_FOLDER, STUDIOLIGHT_ORIENTATION_VIEWNORMAL | STUDIOLIGHT_USER_DEFINED);
 +
 +      /* sort studio lights on filename. */
 +      BLI_listbase_sort(&studiolights, studiolight_cmp);
 +}
 +
 +void BKE_studiolight_free(void)
 +{
 +      struct StudioLight *sl;
 +      while ((sl = BLI_pophead(&studiolights))) {
 +              studiolight_free(sl);
 +      }
 +}
 +
 +struct StudioLight *BKE_studiolight_find_first(int flag)
 +{
 +      LISTBASE_FOREACH(StudioLight *, sl, &studiolights) {
 +              if ((sl->flag & flag)) {
 +                      return sl;
 +              }
 +      }
 +      return NULL;
 +}
 +
 +struct StudioLight *BKE_studiolight_find(const char *name, int flag)
 +{
 +      LISTBASE_FOREACH(StudioLight *, sl, &studiolights) {
 +              if (STREQLEN(sl->name, name, FILE_MAXFILE)) {
 +                      if ((sl->flag & flag)) {
 +                              return sl;
 +                      }
 +                      else {
 +                              /* flags do not match, so use default */
 +                              return BKE_studiolight_find_first(flag);
 +                      }
 +              }
 +      }
 +      /* When not found, use the default studio light */
 +      return BKE_studiolight_find_first(flag);
 +}
 +
 +struct StudioLight *BKE_studiolight_findindex(int index, int flag)
 +{
 +      LISTBASE_FOREACH(StudioLight *, sl, &studiolights) {
 +              if (sl->index == index) {
 +                      return sl;
 +              }
 +      }
 +      /* When not found, use the default studio light */
 +      return BKE_studiolight_find_first(flag);
 +}
 +
 +struct ListBase *BKE_studiolight_listbase(void)
 +{
 +      return &studiolights;
 +}
 +
 +uint *BKE_studiolight_preview(StudioLight *sl, int icon_size, int icon_id_type)
 +{
 +      switch (icon_id_type) {
 +              case STUDIOLIGHT_ICON_ID_TYPE_RADIANCE:
 +              default:
 +                      return studiolight_radiance_preview(sl, icon_size);
 +              case STUDIOLIGHT_ICON_ID_TYPE_IRRADIANCE:
 +                      return studiolight_irradiance_preview(sl, icon_size);
 +              case STUDIOLIGHT_ICON_ID_TYPE_MATCAP:
 +                      return studiolight_matcap_preview(sl, icon_size, false);
 +              case STUDIOLIGHT_ICON_ID_TYPE_MATCAP_FLIPPED:
 +                      return studiolight_matcap_preview(sl, icon_size, true);
 +      }
 +}
 +
 +void BKE_studiolight_ensure_flag(StudioLight *sl, int flag)
 +{
 +      if ((sl->flag & flag) == flag) {
 +              return;
 +      }
 +
 +      if ((flag & STUDIOLIGHT_EXTERNAL_IMAGE_LOADED)) {
 +              studiolight_load_equirectangular_image(sl);
 +      }
 +      if ((flag & STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED)) {
 +              studiolight_calculate_radiance_cubemap_buffers(sl);
 +      }
 +      if ((flag & STUDIOLIGHT_DIFFUSE_LIGHT_CALCULATED)) {
 +              studiolight_calculate_diffuse_light(sl);
 +      }
 +      if ((flag & STUDIOLIGHT_EQUIRECTANGULAR_RADIANCE_GPUTEXTURE)) {
 +              studiolight_create_equirectangular_radiance_gputexture(sl);
 +      }
 +      if ((flag & STUDIOLIGHT_LIGHT_DIRECTION_CALCULATED)) {
 +              studiolight_calculate_light_direction(sl);
 +      }
 +      if ((flag & STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_GPUTEXTURE)) {
 +              studiolight_create_equirectangular_irradiance_gputexture(sl);
 +      }
 +      if ((flag & STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_IMAGE_CALCULATED)) {
 +              if (!studiolight_load_irradiance_equirectangular_image(sl)) {
 +                      studiolight_calculate_irradiance_equirectangular_image(sl);
 +              }
 +      }
 +}
 +
 +void BKE_studiolight_refresh(void)
 +{
 +      BKE_studiolight_free();
 +      BKE_studiolight_init();
 +}
@@@ -1785,229 -1830,2402 +1785,229 @@@ static void UNUSED_FUNCTION(ccgdm_pbvh_
        }
  }
  
 -static void ccgDM_drawEdges(DerivedMesh *dm, bool drawLooseEdges, bool drawAllEdges)
 +static void ccgDM_foreachMappedFaceCenter(
 +        DerivedMesh *dm,
 +        void (*func)(void *userData, int index, const float co[3], const float no[3]),
 +        void *userData,
 +        DMForeachFlag flag)
  {
 -      GPUDrawObject *gdo;
        CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
 +      CCGSubSurf *ss = ccgdm->ss;
 +      CCGKey key;
 +      CCGFaceIterator fi;
  
 -#ifdef WITH_OPENSUBDIV
 -      if (ccgdm->useGpuBackend) {
 -              /* TODO(sergey): We currently only support all edges drawing. */
 -              if (ccgSubSurf_prepareGLMesh(ccgdm->ss, true, -1)) {
 -                      ccgSubSurf_drawGLMesh(ccgdm->ss, false, -1, -1);
 +      CCG_key_top_level(&key, ss);
 +
 +      for (ccgSubSurf_initFaceIterator(ss, &fi); !ccgFaceIterator_isStopped(&fi); ccgFaceIterator_next(&fi)) {
 +              CCGFace *f = ccgFaceIterator_getCurrent(&fi);
 +              const int index = ccgDM_getFaceMapIndex(ss, f);
 +
 +              if (index != -1) {
 +                      /* Face center data normal isn't updated atm. */
 +                      CCGElem *vd = ccgSubSurf_getFaceGridData(ss, f, 0, 0, 0);
 +                      const float *no = (flag & DM_FOREACH_USE_NORMAL) ? CCG_elem_no(&key, vd) : NULL;
 +                      func(userData, index, CCG_elem_co(&key, vd), no);
                }
 -              return;
        }
 -#endif
 -
 -      ccgdm_pbvh_update(ccgdm);
 +}
  
 -/* old debug feature for edges, unsupported for now */
 -#if 0
 -      int useAging = 0;
 +static void ccgDM_release(DerivedMesh *dm)
 +{
 +      CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
  
 -      if (!(G.f & G_BACKBUFSEL)) {
 -              CCGSubSurf *ss = ccgdm->ss;
 -              ccgSubSurf_getUseAgeCounts(ss, &useAging, NULL, NULL, NULL);
 +      if (DM_release(dm)) {
 +              /* Before freeing, need to update the displacement map */
 +              if (ccgdm->multires.modified_flags) {
 +                      /* Check that mmd still exists */
 +                      if (!ccgdm->multires.local_mmd &&
 +                          BLI_findindex(&ccgdm->multires.ob->modifiers, ccgdm->multires.mmd) < 0)
 +                      {
 +                              ccgdm->multires.mmd = NULL;
 +                      }
-                       
 -              /* it needs some way to upload this to VBO now */
 -              if (useAging) {
 -                      int ageCol = 255 - ccgSubSurf_getEdgeAge(ss, e) * 4;
 -                      glColor3ub(0, ageCol > 0 ? ageCol : 0, 0);
 +                      if (ccgdm->multires.mmd) {
 +                              if (ccgdm->multires.modified_flags & MULTIRES_COORDS_MODIFIED)
 +                                      multires_modifier_update_mdisps(dm);
 +                              if (ccgdm->multires.modified_flags & MULTIRES_HIDDEN_MODIFIED)
 +                                      multires_modifier_update_hidden(dm);
 +                      }
                }
 -      }
 -#endif
  
 -      GPU_edge_setup(dm);
 -      gdo = dm->drawObject;
 -      if (gdo->edges && gdo->points) {
 -              if (drawAllEdges && drawLooseEdges) {
 -                      GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, (gdo->totedge - gdo->totinterior) * 2);
 -              }
 -              else if (drawAllEdges) {
 -                      GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, gdo->loose_edge_offset * 2);
 +              if (ccgdm->ehash)
 +                      BLI_edgehash_free(ccgdm->ehash, NULL);
 +
 +              if (ccgdm->reverseFaceMap) MEM_freeN(ccgdm->reverseFaceMap);
 +              if (ccgdm->gridFaces) MEM_freeN(ccgdm->gridFaces);
 +              if (ccgdm->gridData) MEM_freeN(ccgdm->gridData);
 +              if (ccgdm->gridOffset) MEM_freeN(ccgdm->gridOffset);
 +              if (ccgdm->gridFlagMats) MEM_freeN(ccgdm->gridFlagMats);
 +              if (ccgdm->gridHidden) {
 +                      /* Using dm->getNumGrids(dm) accesses freed memory */
 +                      uint numGrids = ccgdm->numGrid;
 +                      for (uint i = 0; i < numGrids; i++) {
 +                              if (ccgdm->gridHidden[i]) {
 +                                      MEM_freeN(ccgdm->gridHidden[i]);
 +                              }
 +                      }
 +                      MEM_freeN(ccgdm->gridHidden);
                }
 -              else {
 -                      GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, gdo->tot_edge_drawn * 2);
 -                      GPU_buffer_draw_elements(gdo->edges, GL_LINES, gdo->loose_edge_offset * 2, gdo->tot_loose_edge_drawn * 2);
 +              if (ccgdm->freeSS) ccgSubSurf_free(ccgdm->ss);
 +              if (ccgdm->pmap) MEM_freeN(ccgdm->pmap);
 +              if (ccgdm->pmap_mem) MEM_freeN(ccgdm->pmap_mem);
 +              MEM_freeN(ccgdm->edgeFlags);
 +              MEM_freeN(ccgdm->faceFlags);
 +              if (ccgdm->useGpuBackend == false) {
 +                      MEM_freeN(ccgdm->vertMap);
 +                      MEM_freeN(ccgdm->edgeMap);
 +                      MEM_freeN(ccgdm->faceMap);
                }
 -      }
  
 -      if (gdo->edges && ccgdm->drawInteriorEdges) {
 -              GPU_buffer_draw_elements(gdo->edges, GL_LINES, gdo->interior_offset * 2, gdo->totinterior * 2);
 +              BLI_mutex_end(&ccgdm->loops_cache_lock);
 +              BLI_rw_mutex_end(&ccgdm->origindex_cache_rwlock);
 +
 +              MEM_freeN(ccgdm);
        }
 -      GPU_buffers_unbind();
  }
  
 -static void ccgDM_drawLooseEdges(DerivedMesh *dm)
 +static void *ccgDM_get_vert_data_layer(DerivedMesh *dm, int type)
  {
 -      int start;
 -      int count;
 +      if (type == CD_ORIGINDEX) {
 +              /* create origindex on demand to save memory */
 +              CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
 +              CCGSubSurf *ss = ccgdm->ss;
 +              int *origindex;
 +              int a, index, totnone, totorig;
  
 -#ifdef WITH_OPENSUBDIV
 -      CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
 -      if (ccgdm->useGpuBackend) {
 -              /* TODO(sergey): Needs implementation. */
 -              return;
 -      }
 -#endif
 +              /* Avoid re-creation if the layer exists already */
 +              BLI_rw_mutex_lock(&ccgdm->origindex_cache_rwlock, THREAD_LOCK_READ);
 +              origindex = DM_get_vert_data_layer(dm, CD_ORIGINDEX);
 +              BLI_rw_mutex_unlock(&ccgdm->origindex_cache_rwlock);
 +              if (origindex) {
 +                      return origindex;
 +              }
 +
 +              BLI_rw_mutex_lock(&ccgdm->origindex_cache_rwlock, THREAD_LOCK_WRITE);
 +              DM_add_vert_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
 +              origindex = DM_get_vert_data_layer(dm, CD_ORIGINDEX);
 +
 +              totorig = ccgSubSurf_getNumVerts(ss);
 +              totnone = dm->numVertData - totorig;
  
 -      GPU_edge_setup(dm);
 +              /* original vertices are at the end */
 +              for (a = 0; a < totnone; a++)
 +                      origindex[a] = ORIGINDEX_NONE;
  
 -      start = (dm->drawObject->loose_edge_offset * 2);
 -      count = (dm->drawObject->interior_offset - dm->drawObject->loose_edge_offset) * 2;
 +              for (index = 0; index < totorig; index++, a++) {
 +                      CCGVert *v = ccgdm->vertMap[index].vert;
 +                      origindex[a] = ccgDM_getVertMapIndex(ccgdm->ss, v);
 +              }
 +              BLI_rw_mutex_unlock(&ccgdm->origindex_cache_rwlock);
  
 -      if (count) {
 -              GPU_buffer_draw_elements(dm->drawObject->edges, GL_LINES, start, count);
 +              return origindex;
        }
  
 -      GPU_buffers_unbind();
 +      return DM_get_vert_data_layer(dm, type);
  }
  
 -static void ccgDM_NormalFast(float *a, float *b, float *c, float *d, float no[3])
 +static void *ccgDM_get_edge_data_layer(DerivedMesh *dm, int type)
  {
 -      float a_cX = c[0] - a[0], a_cY = c[1] - a[1], a_cZ = c[2] - a[2];
 -      float b_dX = d[0] - b[0], b_dY = d[1] - b[1], b_dZ = d[2] - b[2];
 +      if (type == CD_ORIGINDEX) {
 +              /* create origindex on demand to save memory */
 +              CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
 +              CCGSubSurf *ss = ccgdm->ss;
 +              int *origindex;
 +              int a, i, index, totnone, totorig, totedge;
 +              int edgeSize = ccgSubSurf_getEdgeSize(ss);
  
 -      no[0] = b_dY * a_cZ - b_dZ * a_cY;
 -      no[1] = b_dZ * a_cX - b_dX * a_cZ;
 -      no[2] = b_dX * a_cY - b_dY * a_cX;
 +              /* Avoid re-creation if the layer exists already */
 +              origindex = DM_get_edge_data_layer(dm, CD_ORIGINDEX);
 +              if (origindex) {
 +                      return origindex;
 +              }
  
 -      normalize_v3(no);
 -}
 +              DM_add_edge_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
 +              origindex = DM_get_edge_data_layer(dm, CD_ORIGINDEX);
  
 +              totedge = ccgSubSurf_getNumEdges(ss);
 +              totorig = totedge * (edgeSize - 1);
 +              totnone = dm->numEdgeData - totorig;
  
 -static void ccgDM_glNormalFast(float *a, float *b, float *c, float *d)
 -{
 -      float a_cX = c[0] - a[0], a_cY = c[1] - a[1], a_cZ = c[2] - a[2];
 -      float b_dX = d[0] - b[0], b_dY = d[1] - b[1], b_dZ = d[2] - b[2];
 -      float no[3];
 +              /* original edges are at the end */
 +              for (a = 0; a < totnone; a++)
 +                      origindex[a] = ORIGINDEX_NONE;
 +
 +              for (index = 0; index < totedge; index++) {
 +                      CCGEdge *e = ccgdm->edgeMap[index].edge;
 +                      int mapIndex = ccgDM_getEdgeMapIndex(ss, e);
 +
 +                      for (i = 0; i < edgeSize - 1; i++, a++)
 +                              origindex[a] = mapIndex;
 +              }
  
 -      no[0] = b_dY * a_cZ - b_dZ * a_cY;
 -      no[1] = b_dZ * a_cX - b_dX * a_cZ;
 -      no[2] = b_dX * a_cY - b_dY * a_cX;
 +              return origindex;
 +      }
  
 -      /* don't normalize, GL_NORMALIZE is enabled */
 -      glNormal3fv(no);
 +      return DM_get_edge_data_layer(dm, type);
  }
  
 -/* Only used by non-editmesh types */
 -static void ccgDM_buffer_copy_normal(
 -        DerivedMesh *dm, short *varray)
 +static void *ccgDM_get_tessface_data_layer(DerivedMesh *dm, int type)
  {
 -      CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
 -      CCGSubSurf *ss = ccgdm->ss;
 -      CCGKey key;
 -      const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
 -      int gridSize = ccgSubSurf_getGridSize(ss);
 -      int gridFaces = gridSize - 1;
 -      DMFlagMat *faceFlags = ccgdm->faceFlags;
 -      int i, totface = ccgSubSurf_getNumFaces(ss);
 -      int shademodel;
 -      int start = 0;
 +      if (type == CD_ORIGINDEX) {
 +              /* create origindex on demand to save memory */
 +              int *origindex;
  
 -      /* we are in sculpt mode, disable loop normals (since they won't get updated) */
 -      if (ccgdm->pbvh)
 -              lnors = NULL;
 +              /* Avoid re-creation if the layer exists already */
 +              origindex = DM_get_tessface_data_layer(dm, CD_ORIGINDEX);
 +              if (origindex) {
 +                      return origindex;
 +              }
  
 -      CCG_key_top_level(&key, ss);
 +              DM_add_tessface_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
 +              origindex = DM_get_tessface_data_layer(dm, CD_ORIGINDEX);
  
 -      for (i = 0; i < totface; i++) {
 -              CCGFace *f = ccgdm->faceMap[i].face;
 -              int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
 -              int index = GET_INT_FROM_POINTER