Fix T47038: Particles in Particle Edit Mode get added in completely wrong location.
[blender.git] / source / blender / render / intern / source / convertblender.c
index 698c46c1e8d2319fc152561b2c2531074549c712..69e45fea74dbfd22f361a464a55a393c7debcdf9 100644 (file)
 #include "BLI_utildefines.h"
 #include "BLI_rand.h"
 #include "BLI_memarena.h"
-#include "BLI_ghash.h"
-#include "BLI_linklist.h"
 #ifdef WITH_FREESTYLE
 #  include "BLI_edgehash.h"
 #endif
 
-#include "BLF_translation.h"
+#include "BLT_translation.h"
 
-#include "DNA_armature_types.h"
-#include "DNA_camera_types.h"
 #include "DNA_material_types.h"
 #include "DNA_curve_types.h"
-#include "DNA_effect_types.h"
 #include "DNA_group_types.h"
 #include "DNA_lamp_types.h"
 #include "DNA_image_types.h"
-#include "DNA_lattice_types.h"
 #include "DNA_mesh_types.h"
 #include "DNA_meshdata_types.h"
-#include "DNA_meta_types.h"
 #include "DNA_modifier_types.h"
 #include "DNA_node_types.h"
 #include "DNA_object_types.h"
-#include "DNA_object_force.h"
 #include "DNA_object_fluidsim.h"
 #include "DNA_particle_types.h"
 #include "DNA_scene_types.h"
 #include "DNA_texture_types.h"
-#include "DNA_view3d_types.h"
 
 #include "BKE_anim.h"
-#include "BKE_armature.h"
-#include "BKE_action.h"
 #include "BKE_curve.h"
 #include "BKE_customdata.h"
 #include "BKE_colortools.h"
-#include "BKE_constraint.h"
 #include "BKE_displist.h"
-#include "BKE_deform.h"
+#include "BKE_depsgraph.h"
 #include "BKE_DerivedMesh.h"
-#include "BKE_effect.h"
 #include "BKE_global.h"
-#include "BKE_group.h"
 #include "BKE_key.h"
-#include "BKE_ipo.h"
 #include "BKE_image.h"
 #include "BKE_lattice.h"
-#include "BKE_library.h"
 #include "BKE_material.h"
 #include "BKE_main.h"
 #include "BKE_mball.h"
 #include "BKE_object.h"
 #include "BKE_particle.h"
 #include "BKE_scene.h"
-#include "BKE_subsurf.h"
-#include "BKE_texture.h"
-
-#include "BKE_world.h"
 
 #include "PIL_time.h"
-#include "IMB_imbuf_types.h"
 
 #include "envmap.h"
 #include "occlusion.h"
 #include "texture.h"
 #include "volume_precache.h"
 #include "sss.h"
-#include "strand.h"
 #include "zbuf.h"
 #include "sunsky.h"
 
-#include "RE_render_ext.h"
-
 /* 10 times larger than normal epsilon, test it on default nurbs sphere with ray_transp (for quad detection) */
 /* or for checking vertex normal flips */
 #define FLT_EPSILON10 1.19209290e-06F
 #  pragma GCC diagnostic ignored "-Wdouble-promotion"
 #endif
 
-/* ------------------------------------------------------------------------- */
-
-/* Stuff for stars. This sits here because it uses gl-things. Part of
- * this code may move down to the converter.  */
-/* ------------------------------------------------------------------------- */
-/* this is a bad beast, since it is misused by the 3d view drawing as well. */
-
-static HaloRen *initstar(Render *re, ObjectRen *obr, const float vec[3], float hasize)
-{
-       HaloRen *har;
-       float hoco[4];
-       
-       projectverto(vec, re->winmat, hoco);
-       
-       har= RE_findOrAddHalo(obr, obr->tothalo++);
-       
-       /* projectvert is done in function zbufvlaggen again, because of parts */
-       copy_v3_v3(har->co, vec);
-       har->hasize= hasize;
-       
-       har->zd= 0.0;
-       har->pool = re->pool;
-       
-       return har;
-}
-
-/* there must be a 'fixed' amount of stars generated between
- *         near and far
- * all stars must by preference lie on the far and solely
- *        differ in clarity/color
- */
-
-void RE_make_stars(Render *re, Scene *scenev3d, void (*initfunc)(void),
-                   void (*vertexfunc)(float *),  void (*termfunc)(void))
-{
-       extern unsigned char hash[512];
-       ObjectRen *obr= NULL;
-       World *wrld= NULL;
-       HaloRen *har;
-       Scene *scene;
-       Object *camera;
-       Camera *cam;
-       RNG *rng;
-       double dblrand, hlfrand;
-       float vec[4], fx, fy, fz;
-       float fac, starmindist, clipend;
-       float mat[4][4], stargrid, maxrand, maxjit, force, alpha;
-       int x, y, z, sx, sy, sz, ex, ey, ez, done = FALSE;
-       unsigned int totstar= 0;
-       
-       if (initfunc) {
-               scene= scenev3d;
-               wrld= scene->world;
-       }
-       else {
-               scene= re->scene;
-               wrld= &(re->wrld);
-       }
-
-       stargrid = wrld->stardist;                      /* distance between stars */
-       maxrand = 2.0;                                          /* amount a star can be shifted (in grid units) */
-       maxjit = (wrld->starcolnoise);          /* amount a color is being shifted */
-       
-       /* size of stars */
-       force = ( wrld->starsize );
-       
-       /* minimal free space (starting at camera) */
-       starmindist= wrld->starmindist;
-       
-       if (stargrid <= 0.10f) return;
-       
-       if (re) re->flag |= R_HALO;
-       else stargrid *= 1.0f;                          /* then it draws fewer */
-       
-       if (re) invert_m4_m4(mat, re->viewmat);
-       else unit_m4(mat);
-       
-       /* BOUNDING BOX CALCULATION
-        * bbox goes from z = loc_near_var | loc_far_var,
-        * x = -z | +z,
-        * y = -z | +z
-        */
-
-       camera= re ? RE_GetCamera(re) : scene->camera;
-
-       if (camera==NULL || camera->type != OB_CAMERA)
-               return;
-
-       cam = camera->data;
-       clipend = cam->clipend;
-       
-       /* convert to grid coordinates */
-       
-       sx = ((mat[3][0] - clipend) / stargrid) - maxrand;
-       sy = ((mat[3][1] - clipend) / stargrid) - maxrand;
-       sz = ((mat[3][2] - clipend) / stargrid) - maxrand;
-       
-       ex = ((mat[3][0] + clipend) / stargrid) + maxrand;
-       ey = ((mat[3][1] + clipend) / stargrid) + maxrand;
-       ez = ((mat[3][2] + clipend) / stargrid) + maxrand;
-       
-       dblrand = maxrand * stargrid;
-       hlfrand = 2.0 * dblrand;
-       
-       if (initfunc) {
-               initfunc();
-       }
-
-       if (re) /* add render object for stars */
-               obr= RE_addRenderObject(re, NULL, NULL, 0, 0, 0);
-       
-       rng = BLI_rng_new(0);
-       
-       for (x = sx, fx = sx * stargrid; x <= ex; x++, fx += stargrid) {
-               for (y = sy, fy = sy * stargrid; y <= ey; y++, fy += stargrid) {
-                       for (z = sz, fz = sz * stargrid; z <= ez; z++, fz += stargrid) {
-
-                               BLI_rng_seed(rng, (hash[z & 0xff] << 24) + (hash[y & 0xff] << 16) + (hash[x & 0xff] << 8));
-                               vec[0] = fx + (hlfrand * BLI_rng_get_double(rng)) - dblrand;
-                               vec[1] = fy + (hlfrand * BLI_rng_get_double(rng)) - dblrand;
-                               vec[2] = fz + (hlfrand * BLI_rng_get_double(rng)) - dblrand;
-                               vec[3] = 1.0;
-                               
-                               if (vertexfunc) {
-                                       if (done & 1) vertexfunc(vec);
-                                       done++;
-                               }
-                               else {
-                                       if (re)
-                                               mul_m4_v3(re->viewmat, vec);
-                                       
-                                       /* in vec are global coordinates
-                                        * calculate distance to camera
-                                        * and using that, define the alpha
-                                        */
-                                       alpha = len_v3(vec);
-
-                                       if (alpha >= clipend) alpha = 0.0;
-                                       else if (alpha <= starmindist) alpha = 0.0;
-                                       else if (alpha <= 2.0f * starmindist) {
-                                               alpha = (alpha - starmindist) / starmindist;
-                                       }
-                                       else {
-                                               alpha -= 2.0f * starmindist;
-                                               alpha /= (clipend - 2.0f * starmindist);
-                                               alpha = 1.0f - alpha;
-                                       }
-                                       
-                                       
-                                       if (alpha != 0.0f) {
-                                               fac = force * BLI_rng_get_double(rng);
-                                               
-                                               har = initstar(re, obr, vec, fac);
-                                               
-                                               if (har) {
-                                                       har->alfa = sqrt(sqrt(alpha));
-                                                       har->add= 255;
-                                                       har->r = har->g = har->b = 1.0;
-                                                       if (maxjit) {
-                                                               har->r += ((maxjit * BLI_rng_get_double(rng)) ) - maxjit;
-                                                               har->g += ((maxjit * BLI_rng_get_double(rng)) ) - maxjit;
-                                                               har->b += ((maxjit * BLI_rng_get_double(rng)) ) - maxjit;
-                                                       }
-                                                       har->hard = 32;
-                                                       har->lay= -1;
-                                                       har->type |= HA_ONLYSKY;
-                                                       done++;
-                                               }
-                                       }
-                               }
-
-                               /* break out of the loop if generating stars takes too long */
-                               if (re && !(totstar % 1000000)) {
-                                       if (re->test_break(re->tbh)) {
-                                               x= ex + 1;
-                                               y= ey + 1;
-                                               z= ez + 1;
-                                       }
-                               }
-                               
-                               totstar++;
-                       }
-                       /* do not call blender_test_break() here, since it is used in UI as well, confusing the callback system */
-                       /* main cause is G.is_break of course, a global again... (ton) */
-               }
-       }
-       if (termfunc) termfunc();
-
-       if (obr)
-               re->tothalo += obr->tothalo;
-
-       BLI_rng_free(rng);
-}
-
-
 /* ------------------------------------------------------------------------- */
 /* tool functions/defines for ad hoc simplification and possible future 
  * cleanup      */
 /* ------------------------------------------------------------------------- */
 
-#define UVTOINDEX(u,v) (startvlak + (u) * sizev + (v))
+#define UVTOINDEX(u, v) (startvlak + (u) * sizev + (v))
 /*
  *
  * NOTE THAT U/V COORDINATES ARE SOMETIMES SWAPPED !!
@@ -349,6 +130,9 @@ void RE_make_stars(Render *re, Scene *scenev3d, void (*initfunc)(void),
 
 /* ------------------------------------------------------------------------- */
 
+#define CD_MASK_RENDER_INTERNAL \
+    (CD_MASK_BAREMESH | CD_MASK_MFACE | CD_MASK_MTFACE | CD_MASK_MCOL)
+
 static void split_v_renderfaces(ObjectRen *obr, int startvlak, int UNUSED(startvert), int UNUSED(usize), int vsize, int uIndex, int UNUSED(cyclu), int cyclv)
 {
        int vLen = vsize-1+(!!cyclv);
@@ -356,29 +140,30 @@ static void split_v_renderfaces(ObjectRen *obr, int startvlak, int UNUSED(startv
 
        for (v=0; v<vLen; v++) {
                VlakRen *vlr = RE_findOrAddVlak(obr, startvlak + vLen*uIndex + v);
+               VlakRen *vlr_other;
                VertRen *vert = RE_vertren_copy(obr, vlr->v2);
 
                if (cyclv) {
                        vlr->v2 = vert;
 
-                       if (v==vLen-1) {
-                               VlakRen *vlr = RE_findOrAddVlak(obr, startvlak + vLen*uIndex + 0);
-                               vlr->v1 = vert;
+                       if (v == vLen - 1) {
+                               vlr_other = RE_findOrAddVlak(obr, startvlak + vLen*uIndex + 0);
+                               vlr_other->v1 = vert;
                        }
                        else {
-                               VlakRen *vlr = RE_findOrAddVlak(obr, startvlak + vLen*uIndex + v+1);
-                               vlr->v1 = vert;
+                               vlr_other = RE_findOrAddVlak(obr, startvlak + vLen*uIndex + v+1);
+                               vlr_other->v1 = vert;
                        }
                }
                else {
                        vlr->v2 = vert;
 
-                       if (v<vLen-1) {
-                               VlakRen *vlr = RE_findOrAddVlak(obr, startvlak + vLen*uIndex + v+1);
-                               vlr->v1 = vert;
+                       if (v < vLen - 1) {
+                               vlr_other = RE_findOrAddVlak(obr, startvlak + vLen*uIndex + v+1);
+                               vlr_other->v1 = vert;
                        }
 
-                       if (v==0) {
+                       if (v == 0) {
                                vlr->v1 = RE_vertren_copy(obr, vlr->v1);
                        }
                }
@@ -593,23 +378,25 @@ static void SetTSpace(const SMikkTSpaceContext *pContext, const float fvTangent[
        }
 }
 
-static void calc_vertexnormals(Render *UNUSED(re), ObjectRen *obr, int do_tangent, int do_nmap_tangent)
+static void calc_vertexnormals(Render *UNUSED(re), ObjectRen *obr, bool do_vertex_normal, bool do_tangent, bool do_nmap_tangent)
 {
        int a;
 
-               /* clear all vertex normals */
-       for (a=0; a<obr->totvert; a++) {
-               VertRen *ver= RE_findOrAddVert(obr, a);
-               ver->n[0]=ver->n[1]=ver->n[2]= 0.0f;
+       /* clear all vertex normals */
+       if (do_vertex_normal) {
+               for (a=0; a<obr->totvert; a++) {
+                       VertRen *ver= RE_findOrAddVert(obr, a);
+                       ver->n[0]=ver->n[1]=ver->n[2]= 0.0f;
+               }
        }
 
-               /* calculate cos of angles and point-masses, use as weight factor to
-                * add face normal to vertex */
+       /* calculate cos of angles and point-masses, use as weight factor to
+        * add face normal to vertex */
        for (a=0; a<obr->totvlak; a++) {
                VlakRen *vlr= RE_findOrAddVlak(obr, a);
-               if (vlr->flag & ME_SMOOTH) {
+               if (do_vertex_normal && vlr->flag & ME_SMOOTH) {
                        float *n4= (vlr->v4)? vlr->v4->n: NULL;
-                       float *c4= (vlr->v4)? vlr->v4->co: NULL;
+                       const float *c4= (vlr->v4)? vlr->v4->co: NULL;
 
                        accumulate_vertex_normals(vlr->v1->n, vlr->v2->n, vlr->v3->n, n4,
                                vlr->n, vlr->v1->co, vlr->v2->co, vlr->v3->co, c4);
@@ -621,11 +408,11 @@ static void calc_vertexnormals(Render *UNUSED(re), ObjectRen *obr, int do_tangen
                }
        }
 
-               /* do solid faces */
+       /* do solid faces */
        for (a=0; a<obr->totvlak; a++) {
                VlakRen *vlr= RE_findOrAddVlak(obr, a);
 
-               if ((vlr->flag & ME_SMOOTH)==0) {
+               if (do_vertex_normal && (vlr->flag & ME_SMOOTH)==0) {
                        if (is_zero_v3(vlr->v1->n)) copy_v3_v3(vlr->v1->n, vlr->n);
                        if (is_zero_v3(vlr->v2->n)) copy_v3_v3(vlr->v2->n, vlr->n);
                        if (is_zero_v3(vlr->v3->n)) copy_v3_v3(vlr->v3->n, vlr->n);
@@ -651,7 +438,7 @@ static void calc_vertexnormals(Render *UNUSED(re), ObjectRen *obr, int do_tangen
        }
 
        /* normal mapping tangent with mikktspace */
-       if (do_nmap_tangent != FALSE) {
+       if (do_nmap_tangent != false) {
                SRenderMeshToTangent mesh2tangent;
                SMikkTSpaceContext sContext;
                SMikkTSpaceInterface sInterface;
@@ -689,163 +476,163 @@ typedef struct ASface {
        VertRen *nver[4];
 } ASface;
 
-static void as_addvert(ASvert *asv, VertRen *v1, VlakRen *vlr)
+static int as_addvert(ASvert *asv, VertRen *v1, VlakRen *vlr)
 {
        ASface *asf;
-       int a;
-       
-       if (v1 == NULL) return;
-       
-       if (asv->faces.first==NULL) {
-               asf= MEM_callocN(sizeof(ASface), "asface");
-               BLI_addtail(&asv->faces, asf);
-       }
-       
-       asf= asv->faces.last;
-       for (a=0; a<4; a++) {
-               if (asf->vlr[a]==NULL) {
-                       asf->vlr[a]= vlr;
-                       asv->totface++;
-                       break;
+       int a = -1;
+
+       if (v1 == NULL)
+               return a;
+
+       asf = asv->faces.last;
+       if (asf) {
+               for (a = 0; a < 4 && asf->vlr[a]; a++) {
                }
        }
-       
+       else {
+               a = 4;
+       }
+
        /* new face struct */
-       if (a==4) {
-               asf= MEM_callocN(sizeof(ASface), "asface");
+       if (a == 4) {
+               a = 0;
+               asf = MEM_callocN(sizeof(ASface), "asface");
                BLI_addtail(&asv->faces, asf);
-               asf->vlr[0]= vlr;
-               asv->totface++;
        }
+
+       asf->vlr[a] = vlr;
+       asv->totface++;
+
+       return a;
 }
 
-static int as_testvertex(VlakRen *vlr, VertRen *UNUSED(ver), ASvert *asv, float thresh)
+static VertRen *as_findvertex_lnor(VlakRen *vlr, VertRen *ver, ASvert *asv, const float lnor[3])
 {
-       /* return 1: vertex needs a copy */
+       /* return when new vertex already was made, or existing one is OK */
        ASface *asf;
-       float inp;
        int a;
-       
-       if (vlr == NULL) return 0;
-       
-       asf= asv->faces.first;
-       while (asf) {
-               for (a=0; a<4; a++) {
-                       if (asf->vlr[a] && asf->vlr[a]!=vlr) {
-                               inp = fabsf(dot_v3v3(vlr->n, asf->vlr[a]->n));
-                               if (inp < thresh) return 1;
-                       }
-               }
-               asf= asf->next;
+
+       /* First face, we can use existing vert and assign it current lnor! */
+       if (asv->totface == 1) {
+               copy_v3_v3(ver->n, lnor);
+               return ver;
        }
-       
-       return 0;
-}
 
-static VertRen *as_findvertex(VlakRen *vlr, VertRen *UNUSED(ver), ASvert *asv, float thresh)
-{
-       /* return when new vertex already was made */
-       ASface *asf;
-       float inp;
-       int a;
-       
-       asf= asv->faces.first;
+       /* In case existing ver has same normal as current lnor, we can simply use it! */
+       if (equals_v3v3(lnor, ver->n)) {
+               return ver;
+       }
+
+       asf = asv->faces.first;
        while (asf) {
-               for (a=0; a<4; a++) {
-                       if (asf->vlr[a] && asf->vlr[a]!=vlr) {
+               for (a = 0; a < 4; a++) {
+                       if (asf->vlr[a] && asf->vlr[a] != vlr) {
                                /* this face already made a copy for this vertex! */
                                if (asf->nver[a]) {
-                                       inp = fabsf(dot_v3v3(vlr->n, asf->vlr[a]->n));
-                                       if (inp >= thresh) {
+                                       if (equals_v3v3(lnor, asf->nver[a]->n)) {
                                                return asf->nver[a];
                                        }
                                }
                        }
                }
-               asf= asf->next;
+               asf = asf->next;
        }
-       
+
        return NULL;
 }
 
+static void as_addvert_lnor(ObjectRen *obr, ASvert *asv, VertRen *ver, VlakRen *vlr, const short _lnor[3])
+{
+       VertRen *v1;
+       ASface *asf;
+       int asf_idx;
+       float lnor[3];
+
+       normal_short_to_float_v3(lnor, _lnor);
+
+       asf_idx = as_addvert(asv, ver, vlr);
+       if (asf_idx < 0) {
+               return;
+       }
+       asf = asv->faces.last;
+
+       /* already made a new vertex within threshold? */
+       v1 = as_findvertex_lnor(vlr, ver, asv, lnor);
+       if (v1 == NULL) {
+               /* make a new vertex */
+               v1 = RE_vertren_copy(obr, ver);
+               copy_v3_v3(v1->n, lnor);
+       }
+       if (v1 != ver) {
+               asf->nver[asf_idx] = v1;
+               if (vlr->v1 == ver) vlr->v1 = v1;
+               if (vlr->v2 == ver) vlr->v2 = v1;
+               if (vlr->v3 == ver) vlr->v3 = v1;
+               if (vlr->v4 == ver) vlr->v4 = v1;
+       }
+}
+
 /* note; autosmooth happens in object space still, after applying autosmooth we rotate */
 /* note2; actually, when original mesh and displist are equal sized, face normals are from original mesh */
-static void autosmooth(Render *UNUSED(re), ObjectRen *obr, float mat[4][4], int degr)
+static void autosmooth(Render *UNUSED(re), ObjectRen *obr, float mat[4][4], short (*lnors)[4][3])
 {
-       ASvert *asv, *asverts;
-       ASface *asf;
-       VertRen *ver, *v1;
+       ASvert *asverts;
+       VertRen *ver;
        VlakRen *vlr;
-       float thresh;
-       int a, b, totvert;
-       
-       if (obr->totvert==0) return;
-       asverts= MEM_callocN(sizeof(ASvert)*obr->totvert, "all smooth verts");
-       
-       thresh= cosf(DEG2RADF((0.5f + (float)degr)));
-       
-       /* step zero: give faces normals of original mesh, if this is provided */
-       
-       
-       /* step one: construct listbase of all vertices and pointers to faces */
-       for (a=0; a<obr->totvlak; a++) {
-               vlr= RE_findOrAddVlak(obr, a);
-               /* skip wire faces */
-               if (vlr->v2 != vlr->v3) {
-                       as_addvert(asverts+vlr->v1->index, vlr->v1, vlr);
-                       as_addvert(asverts+vlr->v2->index, vlr->v2, vlr);
-                       as_addvert(asverts+vlr->v3->index, vlr->v3, vlr);
-                       if (vlr->v4)
-                               as_addvert(asverts+vlr->v4->index, vlr->v4, vlr);
-               }
+       int a, totvert;
+
+       float rot[3][3];
+
+       /* Note: For normals, we only want rotation, not scaling component.
+        *       Negative scales (aka mirroring) give wrong results, see T44102. */
+       if (lnors) {
+               float mat3[3][3], size[3];
+
+               copy_m3_m4(mat3, mat);
+               mat3_to_rot_size(rot, size, mat3);
        }
-       
-       totvert= obr->totvert;
-       /* we now test all vertices, when faces have a normal too much different: they get a new vertex */
-       for (a=0, asv=asverts; a<totvert; a++, asv++) {
-               if (asv->totface > 1) {
-                       ver= RE_findOrAddVert(obr, a);
 
-                       asf= asv->faces.first;
-                       while (asf) {
-                               for (b=0; b<4; b++) {
-                               
-                                       /* is there a reason to make a new vertex? */
-                                       vlr= asf->vlr[b];
-                                       if ( as_testvertex(vlr, ver, asv, thresh) ) {
-                                               
-                                               /* already made a new vertex within threshold? */
-                                               v1= as_findvertex(vlr, ver, asv, thresh);
-                                               if (v1==NULL) {
-                                                       /* make a new vertex */
-                                                       v1= RE_vertren_copy(obr, ver);
-                                               }
-                                               asf->nver[b]= v1;
-                                               if (vlr->v1==ver) vlr->v1= v1;
-                                               if (vlr->v2==ver) vlr->v2= v1;
-                                               if (vlr->v3==ver) vlr->v3= v1;
-                                               if (vlr->v4==ver) vlr->v4= v1;
-                                       }
-                               }
-                               asf= asf->next;
+       if (obr->totvert == 0)
+               return;
+
+       totvert = obr->totvert;
+       asverts = MEM_callocN(sizeof(ASvert) * totvert, "all smooth verts");
+
+       if (lnors) {
+               /* We construct listbase of all vertices and pointers to faces, and add new verts when needed
+                * (i.e. when existing ones do not share the same (loop)normal).
+                */
+               for (a = 0; a < obr->totvlak; a++, lnors++) {
+                       vlr = RE_findOrAddVlak(obr, a);
+                       /* skip wire faces */
+                       if (vlr->v2 != vlr->v3) {
+                               as_addvert_lnor(obr, asverts+vlr->v1->index, vlr->v1, vlr, (const short*)lnors[0][0]);
+                               as_addvert_lnor(obr, asverts+vlr->v2->index, vlr->v2, vlr, (const short*)lnors[0][1]);
+                               as_addvert_lnor(obr, asverts+vlr->v3->index, vlr->v3, vlr, (const short*)lnors[0][2]);
+                               if (vlr->v4)
+                                       as_addvert_lnor(obr, asverts+vlr->v4->index, vlr->v4, vlr, (const short*)lnors[0][3]);
                        }
                }
        }
-       
+
        /* free */
-       for (a=0; a<totvert; a++) {
+       for (a = 0; a < totvert; a++) {
                BLI_freelistN(&asverts[a].faces);
        }
        MEM_freeN(asverts);
-       
+
        /* rotate vertices and calculate normal of faces */
-       for (a=0; a<obr->totvert; a++) {
-               ver= RE_findOrAddVert(obr, a);
+       for (a = 0; a < obr->totvert; a++) {
+               ver = RE_findOrAddVert(obr, a);
                mul_m4_v3(mat, ver->co);
+               if (lnors) {
+                       mul_m3_v3(rot, ver->n);
+                       negate_v3(ver->n);
+               }
        }
-       for (a=0; a<obr->totvlak; a++) {
-               vlr= RE_findOrAddVlak(obr, a);
-               
+       for (a = 0; a < obr->totvlak; a++) {
+               vlr = RE_findOrAddVlak(obr, a);
+
                /* skip wire faces */
                if (vlr->v2 != vlr->v3) {
                        if (vlr->v4)
@@ -860,28 +647,13 @@ static void autosmooth(Render *UNUSED(re), ObjectRen *obr, float mat[4][4], int
 /* Orco hash and Materials                                                   */
 /* ------------------------------------------------------------------------- */
 
-static float *get_object_orco(Render *re, Object *ob)
+static float *get_object_orco(Render *re, void *ob)
 {
-       float *orco;
-
-       if (!re->orco_hash)
-               re->orco_hash = BLI_ghash_ptr_new("get_object_orco gh");
-
-       orco = BLI_ghash_lookup(re->orco_hash, ob);
-
-       if (!orco) {
-               if (ELEM(ob->type, OB_CURVE, OB_FONT)) {
-                       orco = BKE_curve_make_orco(re->scene, ob, NULL);
-               }
-               else if (ob->type==OB_SURF) {
-                       orco = BKE_curve_surf_make_orco(ob);
-               }
-
-               if (orco)
-                       BLI_ghash_insert(re->orco_hash, ob, orco);
+       if (!re->orco_hash) {
+               return NULL;
        }
 
-       return orco;
+       return BLI_ghash_lookup(re->orco_hash, ob);
 }
 
 static void set_object_orco(Render *re, void *ob, float *orco)
@@ -1000,7 +772,7 @@ static void static_particle_strand(Render *re, ObjectRen *obr, Material *ma, Par
        w= vec[2]*re->winmat[2][3] + re->winmat[3][3];
        dx= re->winx*cross[0]*re->winmat[0][0];
        dy= re->winy*cross[1]*re->winmat[1][1];
-       w= sqrt(dx*dx + dy*dy)/w;
+       w = sqrtf(dx * dx + dy * dy) / w;
        
        if (w!=0.0f) {
                float fac;
@@ -1165,7 +937,7 @@ static void static_particle_strand(Render *re, ObjectRen *obr, Material *ma, Par
                        w= vec[2]*re->winmat[2][3] + re->winmat[3][3];
                        dx= re->winx*dvec[0]*re->winmat[0][0]/w;
                        dy= re->winy*dvec[1]*re->winmat[1][1]/w;
-                       w= sqrt(dx*dx + dy*dy);
+                       w = sqrtf(dx * dx + dy * dy);
                        if (dot_v3v3(anor, nor)<sd->adapt_angle && w>sd->adapt_pix) {
                                vlr= RE_findOrAddVlak(obr, obr->totvlak++);
                                vlr->flag= flag;
@@ -1441,8 +1213,7 @@ static void particle_normal_ren(short ren_as, ParticleSettings *part, Render *re
                        sd->time = 0.0f;
                        sd->size = hasize;
 
-                       copy_v3_v3(vel, state->vel);
-                       mul_mat3_m4_v3(re->viewmat, vel);
+                       mul_v3_mat3_m4v3(vel, re->viewmat, state->vel);
                        normalize_v3(vel);
 
                        if (part->draw & PART_DRAW_VEL_LENGTH)
@@ -1483,7 +1254,7 @@ static void get_particle_uvco_mcol(short from, DerivedMesh *dm, float *fuv, int
        /* get uvco */
        if (sd->uvco && ELEM(from, PART_FROM_FACE, PART_FROM_VOLUME)) {
                for (i=0; i<sd->totuv; i++) {
-                       if (num != DMCACHE_NOTFOUND) {
+                       if (!ELEM(num, DMCACHE_NOTFOUND, DMCACHE_ISCHILD)) {
                                MFace *mface = dm->getTessFaceData(dm, num, CD_MFACE);
                                MTFace *mtface = (MTFace*)CustomData_get_layer_n(&dm->faceData, CD_MTFACE, i);
                                mtface += num;
@@ -1500,7 +1271,7 @@ static void get_particle_uvco_mcol(short from, DerivedMesh *dm, float *fuv, int
        /* get mcol */
        if (sd->mcol && ELEM(from, PART_FROM_FACE, PART_FROM_VOLUME)) {
                for (i=0; i<sd->totcol; i++) {
-                       if (num != DMCACHE_NOTFOUND) {
+                       if (!ELEM(num, DMCACHE_NOTFOUND, DMCACHE_ISCHILD)) {
                                MFace *mface = dm->getTessFaceData(dm, num, CD_MFACE);
                                MCol *mc = (MCol*)CustomData_get_layer_n(&dm->faceData, CD_MCOL, i);
                                mc += num * 4;
@@ -1538,11 +1309,11 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
        float pa_time, pa_birthtime, pa_dietime;
        float random, simplify[2], pa_co[3];
        const float cfra= BKE_scene_frame_get(re->scene);
-       int i, a, k, max_k=0, totpart, do_simplify = FALSE, do_surfacecache = FALSE, use_duplimat = FALSE;
+       int i, a, k, max_k=0, totpart;
+       bool do_simplify = false, do_surfacecache = false, use_duplimat = false;
        int totchild=0, step_nbr;
        int seed, path_nbr=0, orco1=0, num;
        int totface;
-       char **uv_name = NULL;
 
        const int *index_mf_to_mpoly = NULL;
        const int *index_mp_to_orig = NULL;
@@ -1560,6 +1331,12 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
        if (part->ren_as==PART_DRAW_OB || part->ren_as==PART_DRAW_GR || part->ren_as==PART_DRAW_NOT)
                return 1;
 
+       if ((re->r.scemode & R_VIEWPORT_PREVIEW) && (ob->mode & OB_MODE_PARTICLE_EDIT))
+               return 0;
+
+       if (part->ren_as == PART_DRAW_BB && part->bb_ob == NULL && RE_GetCamera(re) == NULL)
+               return 0;
+
 /* 2. start initializing things */
 
        /* last possibility to bail out! */
@@ -1583,11 +1360,13 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
 
        if (re->r.scemode & R_VIEWPORT_PREVIEW) { /* preview render */
                totchild = (int)((float)totchild * (float)part->disp / 100.0f);
-               step_nbr = part->draw_step;
+               step_nbr = 1 << part->draw_step;
        }
        else {
-               step_nbr = part->ren_step;
+               step_nbr = 1 << part->ren_step;
        }
+       if (ELEM(part->kink, PART_KINK_SPIRAL))
+               step_nbr += part->kink_extra_steps;
 
        psys->flag |= PSYS_DRAWING;
 
@@ -1613,16 +1392,16 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
 
        re->flag |= R_HALO;
 
-       RE_set_customdata_names(obr, &psmd->dm->faceData);
-       sd.totuv = CustomData_number_of_layers(&psmd->dm->faceData, CD_MTFACE);
-       sd.totcol = CustomData_number_of_layers(&psmd->dm->faceData, CD_MCOL);
+       RE_set_customdata_names(obr, &psmd->dm_final->faceData);
+       sd.totuv = CustomData_number_of_layers(&psmd->dm_final->faceData, CD_MTFACE);
+       sd.totcol = CustomData_number_of_layers(&psmd->dm_final->faceData, CD_MCOL);
 
        if (ma->texco & TEXCO_UV && sd.totuv) {
                sd.uvco = MEM_callocN(sd.totuv * 2 * sizeof(float), "particle_uvs");
 
                if (ma->strand_uvname[0]) {
-                       sd.override_uv = CustomData_get_named_layer_index(&psmd->dm->faceData, CD_MTFACE, ma->strand_uvname);
-                       sd.override_uv -= CustomData_get_layer_index(&psmd->dm->faceData, CD_MTFACE);
+                       sd.override_uv = CustomData_get_named_layer_index(&psmd->dm_final->faceData, CD_MTFACE, ma->strand_uvname);
+                       sd.override_uv -= CustomData_get_layer_index(&psmd->dm_final->faceData, CD_MTFACE);
                }
        }
        else
@@ -1633,15 +1412,15 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
 
 /* 2.2 setup billboards */
        if (part->ren_as == PART_DRAW_BB) {
-               int first_uv = CustomData_get_layer_index(&psmd->dm->faceData, CD_MTFACE);
+               int first_uv = CustomData_get_layer_index(&psmd->dm_final->faceData, CD_MTFACE);
 
-               bb.uv[0] = CustomData_get_named_layer_index(&psmd->dm->faceData, CD_MTFACE, psys->bb_uvname[0]);
+               bb.uv[0] = CustomData_get_named_layer_index(&psmd->dm_final->faceData, CD_MTFACE, psys->bb_uvname[0]);
                if (bb.uv[0] < 0)
-                       bb.uv[0] = CustomData_get_active_layer_index(&psmd->dm->faceData, CD_MTFACE);
+                       bb.uv[0] = CustomData_get_active_layer_index(&psmd->dm_final->faceData, CD_MTFACE);
 
-               bb.uv[1] = CustomData_get_named_layer_index(&psmd->dm->faceData, CD_MTFACE, psys->bb_uvname[1]);
+               bb.uv[1] = CustomData_get_named_layer_index(&psmd->dm_final->faceData, CD_MTFACE, psys->bb_uvname[1]);
 
-               bb.uv[2] = CustomData_get_named_layer_index(&psmd->dm->faceData, CD_MTFACE, psys->bb_uvname[2]);
+               bb.uv[2] = CustomData_get_named_layer_index(&psmd->dm_final->faceData, CD_MTFACE, psys->bb_uvname[2]);
 
                if (first_uv >= 0) {
                        bb.uv[0] -= first_uv;
@@ -1661,23 +1440,25 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
 /* 2.5 setup matrices */
        mul_m4_m4m4(mat, re->viewmat, ob->obmat);
        invert_m4_m4(ob->imat, mat);    /* need to be that way, for imat texture */
-       copy_m3_m4(nmat, ob->imat);
-       transpose_m3(nmat);
+       transpose_m3_m4(nmat, ob->imat);
 
        if (psys->flag & PSYS_USE_IMAT) {
                /* psys->imat is the original emitter's inverse matrix, ob->obmat is the duplicated object's matrix */
                mul_m4_m4m4(duplimat, ob->obmat, psys->imat);
-               use_duplimat = TRUE;
+               use_duplimat = true;
        }
 
 /* 2.6 setup strand rendering */
        if (part->ren_as == PART_DRAW_PATH && psys->pathcache) {
-               path_nbr=(int)pow(2.0, (double) step_nbr);
+               path_nbr = step_nbr;
 
                if (path_nbr) {
                        if (!ELEM(ma->material_type, MA_TYPE_HALO, MA_TYPE_WIRE)) {
-                               sd.orco = MEM_mallocN(3*sizeof(float)*(totpart+totchild), "particle orcos");
-                               set_object_orco(re, psys, sd.orco);
+                               sd.orco = get_object_orco(re, psys);
+                               if (!sd.orco) {
+                                       sd.orco = MEM_mallocN(3*sizeof(float)*(totpart+totchild), "particle orcos");
+                                       set_object_orco(re, psys, sd.orco);
+                               }
                        }
                }
 
@@ -1714,14 +1495,14 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
                        svert= strandbuf->vert;
 
                        if (re->r.mode & R_SPEED)
-                               do_surfacecache = TRUE;
+                               do_surfacecache = true;
                        else if ((re->wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT)) && (re->wrld.ao_gather_method == WO_AOGATHER_APPROX))
                                if (ma->amb != 0.0f)
-                                       do_surfacecache = TRUE;
+                                       do_surfacecache = true;
 
-                       totface= psmd->dm->getNumTessFaces(psmd->dm);
-                       index_mf_to_mpoly = psmd->dm->getTessFaceDataArray(psmd->dm, CD_ORIGINDEX);
-                       index_mp_to_orig = psmd->dm->getPolyDataArray(psmd->dm, CD_ORIGINDEX);
+                       totface= psmd->dm_final->getNumTessFaces(psmd->dm_final);
+                       index_mf_to_mpoly = psmd->dm_final->getTessFaceDataArray(psmd->dm_final, CD_ORIGINDEX);
+                       index_mp_to_orig = psmd->dm_final->getPolyDataArray(psmd->dm_final, CD_ORIGINDEX);
                        if (index_mf_to_mpoly == NULL) {
                                index_mp_to_orig = NULL;
                        }
@@ -1776,19 +1557,19 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
                        num= pa->num_dmcache;
 
                        if (num == DMCACHE_NOTFOUND)
-                               if (pa->num < psmd->dm->getNumTessFaces(psmd->dm))
+                               if (pa->num < psmd->dm_final->getNumTessFaces(psmd->dm_final))
                                        num= pa->num;
 
-                       get_particle_uvco_mcol(part->from, psmd->dm, pa->fuv, num, &sd);
+                       get_particle_uvco_mcol(part->from, psmd->dm_final, pa->fuv, num, &sd);
 
                        pa_size = pa->size;
 
-                       r_tilt = 2.0f*(PSYS_FRAND(a) - 0.5f);
-                       r_length = PSYS_FRAND(a+1);
+                       r_tilt = 2.0f*(psys_frand(psys, a) - 0.5f);
+                       r_length = psys_frand(psys, a+1);
 
                        if (path_nbr) {
                                cache = psys->pathcache[a];
-                               max_k = (int)cache->steps;
+                               max_k = (int)cache->segments;
                        }
 
                        if (totchild && (part->draw&PART_DRAW_PARENT)==0) continue;
@@ -1799,17 +1580,17 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
                        if (path_nbr) {
                                cache = psys->childcache[a-totpart];
 
-                               if (cache->steps < 0)
+                               if (cache->segments < 0)
                                        continue;
 
-                               max_k = (int)cache->steps;
+                               max_k = (int)cache->segments;
                        }
                        
                        pa_time = psys_get_child_time(psys, cpa, cfra, &pa_birthtime, &pa_dietime);
                        pa_size = psys_get_child_size(psys, cpa, cfra, &pa_time);
 
-                       r_tilt = 2.0f*(PSYS_FRAND(a + 21) - 0.5f);
-                       r_length = PSYS_FRAND(a + 22);
+                       r_tilt = 2.0f*(psys_frand(psys, a + 21) - 0.5f);
+                       r_length = psys_frand(psys, a + 22);
 
                        num = cpa->num;
 
@@ -1830,17 +1611,17 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
 
                        /* get uvco & mcol */
                        if (part->childtype==PART_CHILD_FACES) {
-                               get_particle_uvco_mcol(PART_FROM_FACE, psmd->dm, cpa->fuv, cpa->num, &sd);
+                               get_particle_uvco_mcol(PART_FROM_FACE, psmd->dm_final, cpa->fuv, cpa->num, &sd);
                        }
                        else {
                                ParticleData *parent = psys->particles + cpa->parent;
                                num = parent->num_dmcache;
 
                                if (num == DMCACHE_NOTFOUND)
-                                       if (parent->num < psmd->dm->getNumTessFaces(psmd->dm))
+                                       if (parent->num < psmd->dm_final->getNumTessFaces(psmd->dm_final))
                                                num = parent->num;
 
-                               get_particle_uvco_mcol(part->from, psmd->dm, parent->fuv, num, &sd);
+                               get_particle_uvco_mcol(part->from, psmd->dm_final, parent->fuv, num, &sd);
                        }
 
                        do_simplify = psys_render_simplify_params(psys, cpa, simplify);
@@ -1848,9 +1629,11 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
                        if (strandbuf) {
                                int orignum = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, cpa->num) : cpa->num;
 
-                               if (orignum > sbound - strandbuf->bound) {
-                                       sbound= strandbuf->bound + orignum;
-                                       sbound->start= sbound->end= obr->totstrand;
+                               if ((orignum > sbound - strandbuf->bound) &&
+                                   (orignum < strandbuf->totbound))
+                               {
+                                       sbound = &strandbuf->bound[orignum];
+                                       sbound->start = sbound->end = obr->totstrand;
                                }
                        }
                }
@@ -1954,14 +1737,14 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
                                                sub_v3_v3v3(loc0, loc1, loc);
                                                add_v3_v3v3(loc0, loc1, loc0);
 
-                                               particle_curve(re, obr, psmd->dm, ma, &sd, loc1, loc0, seed, pa_co);
+                                               particle_curve(re, obr, psmd->dm_final, ma, &sd, loc1, loc0, seed, pa_co);
                                        }
 
                                        sd.first = 0;
                                        sd.time = time;
 
                                        if (k)
-                                               particle_curve(re, obr, psmd->dm, ma, &sd, loc, loc1, seed, pa_co);
+                                               particle_curve(re, obr, psmd->dm_final, ma, &sd, loc, loc1, seed, pa_co);
 
                                        copy_v3_v3(loc1, loc);
                                }
@@ -2020,7 +1803,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
                                        pa_co[0] = (part->draw & PART_ABS_PATH_TIME) ? (ct-pa_birthtime)/(pa_dietime-pa_birthtime) : ct;
                                        pa_co[1] = (float)i/(float)(trail_count-1);
 
-                                       particle_normal_ren(part->ren_as, part, re, obr, psmd->dm, ma, &sd, &bb, &state, seed, hasize, pa_co);
+                                       particle_normal_ren(part->ren_as, part, re, obr, psmd->dm_final, ma, &sd, &bb, &state, seed, hasize, pa_co);
                                }
                        }
                        else {
@@ -2056,7 +1839,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
                                        bb.lifetime = pa_dietime-pa_birthtime;
                                }
 
-                               particle_normal_ren(part->ren_as, part, re, obr, psmd->dm, ma, &sd, &bb, &state, seed, hasize, pa_co);
+                               particle_normal_ren(part->ren_as, part, re, obr, psmd->dm_final, ma, &sd, &bb, &state, seed, hasize, pa_co);
                        }
                }
 
@@ -2068,7 +1851,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
        }
 
        if (do_surfacecache)
-               strandbuf->surface= cache_strand_surface(re, obr, psmd->dm, mat, timeoffset);
+               strandbuf->surface= cache_strand_surface(re, obr, psmd->dm_final, mat, timeoffset);
 
 /* 4. clean up */
 #if 0  /* XXX old animation system */
@@ -2084,9 +1867,6 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
        if (sd.mcol)
                MEM_freeN(sd.mcol);
 
-       if (uv_name)
-               MEM_freeN(uv_name);
-
        if (states)
                MEM_freeN(states);
        
@@ -2100,7 +1880,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
        }
 
        if (path_nbr && (ma->mode_l & MA_TANGENT_STR)==0)
-               calc_vertexnormals(re, obr, 0, 0);
+               calc_vertexnormals(re, obr, 1, 0, 0);
 
        return 1;
 }
@@ -2210,7 +1990,7 @@ static short test_for_displace(Render *re, Object *ob)
        return 0;
 }
 
-static void displace_render_vert(Render *re, ObjectRen *obr, ShadeInput *shi, VertRen *vr, int vindex, float *scale, float mat[4][4], float imat[3][3])
+static void displace_render_vert(Render *re, ObjectRen *obr, ShadeInput *shi, VertRen *vr, int vindex, float *scale)
 {
        MTFace *tface;
        short texco= shi->mat->texco;
@@ -2223,15 +2003,6 @@ static void displace_render_vert(Render *re, ObjectRen *obr, ShadeInput *shi, Ve
        /* vertex normal is used for textures type 'col' and 'var' */
        copy_v3_v3(shi->vn, vr->n);
 
-       if (mat)
-               mul_m4_v3(mat, shi->co);
-
-       if (imat) {
-               shi->vn[0] = dot_v3v3(imat[0], vr->n);
-               shi->vn[1] = dot_v3v3(imat[1], vr->n);
-               shi->vn[2] = dot_v3v3(imat[2], vr->n);
-       }
-
        if (texco & TEXCO_UV) {
                shi->totuv= 0;
                shi->actuv= obr->actmtface;
@@ -2263,7 +2034,7 @@ static void displace_render_vert(Render *re, ObjectRen *obr, ShadeInput *shi, Ve
                /* not (yet?) */
        }
        if (texco & TEXCO_STRESS) {
-               float *s= RE_vertren_get_stress(obr, vr, 0);
+               const float *s= RE_vertren_get_stress(obr, vr, 0);
 
                if (s) {
                        shi->stress= *s;
@@ -2284,9 +2055,6 @@ static void displace_render_vert(Render *re, ObjectRen *obr, ShadeInput *shi, Ve
        displace[0]= shi->displace[0] * scale[0];
        displace[1]= shi->displace[1] * scale[1];
        displace[2]= shi->displace[2] * scale[2];
-       
-       if (mat)
-               mul_m3_v3(imat, displace);
 
        /* 0.5 could become button once?  */
        vr->co[0] += displace[0]; 
@@ -2309,7 +2077,7 @@ static void displace_render_vert(Render *re, ObjectRen *obr, ShadeInput *shi, Ve
        return;
 }
 
-static void displace_render_face(Render *re, ObjectRen *obr, VlakRen *vlr, float *scale, float mat[4][4], float imat[3][3])
+static void displace_render_face(Render *re, ObjectRen *obr, VlakRen *vlr, float *scale)
 {
        ShadeInput shi;
 
@@ -2338,17 +2106,17 @@ static void displace_render_face(Render *re, ObjectRen *obr, VlakRen *vlr, float
 
        /* Displace the verts, flag is set when done */
        if (!vlr->v1->flag)
-               displace_render_vert(re, obr, &shi, vlr->v1, 0,  scale, mat, imat);
+               displace_render_vert(re, obr, &shi, vlr->v1, 0,  scale);
        
        if (!vlr->v2->flag)
-               displace_render_vert(re, obr, &shi, vlr->v2, 1, scale, mat, imat);
+               displace_render_vert(re, obr, &shi, vlr->v2, 1, scale);
 
        if (!vlr->v3->flag)
-               displace_render_vert(re, obr, &shi, vlr->v3, 2, scale, mat, imat);
+               displace_render_vert(re, obr, &shi, vlr->v3, 2, scale);
 
        if (vlr->v4) {
                if (!vlr->v4->flag)
-                       displace_render_vert(re, obr, &shi, vlr->v4, 3, scale, mat, imat);
+                       displace_render_vert(re, obr, &shi, vlr->v4, 3, scale);
 
                /*      closest in displace value.  This will help smooth edges.   */ 
                if (fabsf(vlr->v1->accum - vlr->v3->accum) > fabsf(vlr->v2->accum - vlr->v4->accum)) vlr->flag |=  R_DIVIDE_24;
@@ -2364,7 +2132,7 @@ static void displace_render_face(Render *re, ObjectRen *obr, VlakRen *vlr, float
        }
 }
 
-static void do_displacement(Render *re, ObjectRen *obr, float mat[4][4], float imat[3][3])
+static void displace(Render *re, ObjectRen *obr)
 {
        VertRen *vr;
        VlakRen *vlr;
@@ -2389,11 +2157,11 @@ static void do_displacement(Render *re, ObjectRen *obr, float mat[4][4], float i
 
        for (i=0; i<obr->totvlak; i++) {
                vlr=RE_findOrAddVlak(obr, i);
-               displace_render_face(re, obr, vlr, scale, mat, imat);
+               displace_render_face(re, obr, vlr, scale);
        }
        
        /* Recalc vertex normals */
-       calc_vertexnormals(re, obr, 0, 0);
+       calc_vertexnormals(re, obr, 1, 0, 0);
 }
 
 /* ------------------------------------------------------------------------- */
@@ -2426,7 +2194,7 @@ static void init_render_mball(Render *re, ObjectRen *obr)
                need_orco= 1;
        }
 
-       BKE_displist_make_mball_forRender(re->scene, ob, &dispbase);
+       BKE_displist_make_mball_forRender(re->eval_ctx, re->scene, ob, &dispbase);
        dl= dispbase.first;
        if (dl == NULL) return;
 
@@ -2788,7 +2556,7 @@ static void init_render_dm(DerivedMesh *dm, Render *re, ObjectRen *obr,
                }
 
                /* Normals */
-               calc_vertexnormals(re, obr, 0, 0);
+               calc_vertexnormals(re, obr, 1, 0, 0);
        }
 
 }
@@ -2802,7 +2570,8 @@ static void init_render_surf(Render *re, ObjectRen *obr, int timeoffset)
        DispList *dl;
        Material **matar;
        float *orco=NULL, mat[4][4];
-       int a, totmat, need_orco=0;
+       int a, totmat;
+       bool need_orco = false;
        DerivedMesh *dm= NULL;
 
        cu= ob->data;
@@ -2829,9 +2598,12 @@ static void init_render_surf(Render *re, ObjectRen *obr, int timeoffset)
 
        if (dm) {
                if (need_orco) {
-                       orco= BKE_displist_make_orco(re->scene, ob, dm, 1, 1);
-                       if (orco) {
-                               set_object_orco(re, ob, orco);
+                       orco = get_object_orco(re, ob);
+                       if (!orco) {
+                               orco= BKE_displist_make_orco(re->scene, ob, dm, true, true);
+                               if (orco) {
+                                       set_object_orco(re, ob, orco);
+                               }
                        }
                }
 
@@ -2840,7 +2612,11 @@ static void init_render_surf(Render *re, ObjectRen *obr, int timeoffset)
        }
        else {
                if (need_orco) {
-                       orco= get_object_orco(re, ob);
+                       orco = get_object_orco(re, ob);
+                       if (!orco) {
+                               orco = BKE_curve_surf_make_orco(ob);
+                               set_object_orco(re, ob, orco);
+                       }
                }
 
                /* walk along displaylist and create rendervertices/-faces */
@@ -2868,23 +2644,24 @@ static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset)
        Material **matar;
        float *data, *fp, *orco=NULL;
        float n[3], mat[4][4], nmat[4][4];
-       int nr, startvert, a, b;
-       int need_orco=0, totmat;
+       int nr, startvert, a, b, negative_scale;
+       bool need_orco = false;
+       int totmat;
 
        cu= ob->data;
        if (ob->type==OB_FONT && cu->str==NULL) return;
        else if (ob->type==OB_CURVE && cu->nurb.first==NULL) return;
 
-       BKE_displist_make_curveTypes_forRender(re->scene, ob, &disp, &dm, 0, 1);
+       BKE_displist_make_curveTypes_forRender(re->scene, ob, &disp, &dm, false, true);
        dl= disp.first;
        if (dl==NULL) return;
        
        mul_m4_m4m4(mat, re->viewmat, ob->obmat);
        invert_m4_m4(ob->imat, mat);
+       negative_scale = is_negative_m4(mat);
 
        /* local object -> world space transform for normals */
-       copy_m4_m4(nmat, mat);
-       transpose_m4(nmat);
+       transpose_m4_m4(nmat, mat);
        invert_m4(nmat);
 
        /* material array */
@@ -2900,9 +2677,12 @@ static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset)
 
        if (dm) {
                if (need_orco) {
-                       orco= BKE_displist_make_orco(re->scene, ob, dm, 1, 1);
-                       if (orco) {
-                               set_object_orco(re, ob, orco);
+                       orco = get_object_orco(re, ob);
+                       if (!orco) {
+                               orco = BKE_displist_make_orco(re->scene, ob, dm, true, true);
+                               if (orco) {
+                                       set_object_orco(re, ob, orco);
+                               }
                        }
                }
 
@@ -2912,6 +2692,10 @@ static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset)
        else {
                if (need_orco) {
                        orco = get_object_orco(re, ob);
+                       if (!orco) {
+                               orco = BKE_curve_make_orco(re->scene, ob, NULL);
+                               set_object_orco(re, ob, orco);
+                       }
                }
 
                while (dl) {
@@ -2919,7 +2703,7 @@ static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset)
                                /* pass */
                        }
                        else if (dl->type==DL_INDEX3) {
-                               int *index;
+                               const int *index;
 
                                startvert= obr->totvert;
                                data= dl->verts;
@@ -2943,7 +2727,7 @@ static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset)
                                        zero_v3(n);
                                        index= dl->index;
                                        for (a=0; a<dl->parts; a++, index+=3) {
-                                               int v1 = index[0], v2 = index[1], v3 = index[2];
+                                               int v1 = index[0], v2 = index[2], v3 = index[1];
                                                float *co1 = &dl->verts[v1 * 3],
                                                      *co2 = &dl->verts[v2 * 3],
                                                      *co3 = &dl->verts[v3 * 3];
@@ -2955,9 +2739,13 @@ static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset)
                                                vlr->v4= NULL;
 
                                                /* to prevent float accuracy issues, we calculate normal in local object space (not world) */
-                                               if (area_tri_v3(co3, co2, co1)>FLT_EPSILON10) {
-                                                       normal_tri_v3(tmp, co3, co2, co1);
-                                                       add_v3_v3(n, tmp);
+                                               if (normal_tri_v3(tmp, co1, co2, co3) > FLT_EPSILON) {
+                                                       if (negative_scale == false) {
+                                                               add_v3_v3(n, tmp);
+                                                       }
+                                                       else {
+                                                               sub_v3_v3(n, tmp);
+                                                       }
                                                }
 
                                                vlr->mat= matar[ dl->col ];
@@ -3010,6 +2798,19 @@ static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset)
                                                }
                                        }
 
+                                       if (dl->flag & DL_CYCL_V && orco) {
+                                               fp = dl->verts;
+                                               nr = dl->nr;
+                                               while (nr--) {
+                                                       ver = RE_findOrAddVert(obr, obr->totvert++);
+                                                       copy_v3_v3(ver->co, fp);
+                                                       mul_m4_v3(mat, ver->co);
+                                                       ver->orco = orco;
+                                                       fp += 3;
+                                                       orco += 3;
+                                               }
+                                       }
+
                                        if (dl->bevelSplitFlag || timeoffset==0) {
                                                const int startvlak= obr->totvlak;
 
@@ -3023,6 +2824,11 @@ static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset)
                                                        p3+= startvert;
                                                        p4+= startvert;
 
+                                                       if (dl->flag & DL_CYCL_V && orco && a == dl->parts - 1) {
+                                                               p3 = p1 + dl->nr;
+                                                               p4 = p2 + dl->nr;
+                                                       }
+
                                                        for (; b<dl->nr; b++) {
                                                                vlr= RE_findOrAddVlak(obr, obr->totvlak++);
                                                                /* important 1 offset in order is kept [#24913] */
@@ -3133,8 +2939,7 @@ static struct edgesort *make_mesh_edge_lookup(DerivedMesh *dm, int *totedgesort)
 
        /* make sorted table with edges and face indices in it */
        for (a= totface, mf= mface; a>0; a--, mf++) {
-               if (mf->v4) totedge+=4;
-               else if (mf->v3) totedge+=3;
+               totedge += mf->v4 ? 4 : 3;
        }
 
        if (totedge==0)
@@ -3149,8 +2954,9 @@ static struct edgesort *make_mesh_edge_lookup(DerivedMesh *dm, int *totedgesort)
                        to_edgesort(ed++, 2, 3, mf->v3, mf->v4, a);
                        to_edgesort(ed++, 3, 0, mf->v4, mf->v1, a);
                }
-               else if (mf->v3)
+               else {
                        to_edgesort(ed++, 2, 3, mf->v3, mf->v1, a);
+               }
        }
 
        qsort(edsort, totedge, sizeof(struct edgesort), vergedgesort);
@@ -3266,42 +3072,27 @@ static void add_volume(Render *re, ObjectRen *obr, Material *ma)
 }
 
 #ifdef WITH_FREESTYLE
-static EdgeHash *make_freestyle_edge_mark_hash(Mesh *me, DerivedMesh *dm)
+static EdgeHash *make_freestyle_edge_mark_hash(DerivedMesh *dm)
 {
        EdgeHash *edge_hash= NULL;
        FreestyleEdge *fed;
        MEdge *medge;
        int totedge, a;
-       int *index;
 
        medge = dm->getEdgeArray(dm);
        totedge = dm->getNumEdges(dm);
-       index = dm->getEdgeDataArray(dm, CD_ORIGINDEX);
-       fed = CustomData_get_layer(&me->edata, CD_FREESTYLE_EDGE);
+       fed = dm->getEdgeDataArray(dm, CD_FREESTYLE_EDGE);
        if (fed) {
-               edge_hash = BLI_edgehash_new();
-               if (!index) {
-                       if (me->totedge == totedge) {
-                               for (a = 0; a < me->totedge; a++) {
-                                       if (fed[a].flag & FREESTYLE_EDGE_MARK) {
-                                               BLI_edgehash_insert(edge_hash, medge[a].v1, medge[a].v2, medge + a);
-                                       }
-                               }
-                       }
-               }
-               else {
-                       for (a = 0; a < totedge; a++) {
-                               if (index[a] == ORIGINDEX_NONE)
-                                       continue;
-                               if (fed[index[a]].flag & FREESTYLE_EDGE_MARK)
-                                       BLI_edgehash_insert(edge_hash, medge[a].v1, medge[a].v2, medge+a);
-                       }
+               edge_hash = BLI_edgehash_new(__func__);
+               for (a = 0; a < totedge; a++) {
+                       if (fed[a].flag & FREESTYLE_EDGE_MARK)
+                               BLI_edgehash_insert(edge_hash, medge[a].v1, medge[a].v2, medge+a);
                }
        }
        return edge_hash;
 }
 
-static int has_freestyle_edge_mark(EdgeHash *edge_hash, int v1, int v2)
+static bool has_freestyle_edge_mark(EdgeHash *edge_hash, int v1, int v2)
 {
        MEdge *medge= BLI_edgehash_lookup(edge_hash, v1, v2);
        return (!medge) ? 0 : 1;
@@ -3321,10 +3112,12 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
        CustomDataMask mask;
        float xn, yn, zn,  imat[3][3], mat[4][4];  //nor[3],
        float *orco = NULL;
-       int need_orco=0, need_stress=0, need_nmap_tangent=0, need_tangent=0, need_origindex=0;
+       short (*loop_nors)[4][3] = NULL;
+       bool need_orco = false, need_stress = false, need_nmap_tangent = false, need_tangent = false, need_origindex = false;
        int a, a1, ok, vertofs;
-       int end, do_autosmooth = FALSE, totvert = 0;
-       int use_original_normals = FALSE;
+       int end, totvert = 0;
+       bool do_autosmooth = false, do_displace = false;
+       bool use_original_normals = false;
        int recalc_normals = 0; /* false by default */
        int negative_scale;
 #ifdef WITH_FREESTYLE
@@ -3373,19 +3166,20 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
                }
                need_nmap_tangent= 1;
        }
-       
-       /* origindex currently only used when baking to vertex colors */
-       if (re->flag & R_BAKING && re->r.bake_flag & R_BAKE_VCOL)
-               need_origindex= 1;
 
-       /* check autosmooth and displacement, we then have to skip only-verts optimize */
-       do_autosmooth |= (me->flag & ME_AUTOSMOOTH);
-       if (do_autosmooth)
-               timeoffset= 0;
-       if (test_for_displace(re, ob ) )
-               timeoffset= 0;
-       
-       mask= CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL;
+       /* check autosmooth and displacement, we then have to skip only-verts optimize
+        * Note: not sure what we want to give higher priority, currently do_displace
+        *       takes precedence over do_autosmooth.
+        */
+       do_displace = test_for_displace(re, ob);
+       do_autosmooth = ((me->flag & ME_AUTOSMOOTH) != 0) && !do_displace;
+       if (do_autosmooth || do_displace)
+               timeoffset = 0;
+
+       /* origindex currently used when using autosmooth, or baking to vertex colors. */
+       need_origindex = (do_autosmooth || ((re->flag & R_BAKING) && (re->r.bake_flag & R_BAKE_VCOL)));
+
+       mask = CD_MASK_RENDER_INTERNAL;
        if (!timeoffset)
                if (need_orco)
                        mask |= CD_MASK_ORCO;
@@ -3401,10 +3195,13 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
        if (dm==NULL) return;   /* in case duplicated object fails? */
 
        if (mask & CD_MASK_ORCO) {
-               orco= dm->getVertDataArray(dm, CD_ORCO);
-               if (orco) {
-                       orco= MEM_dupallocN(orco);
-                       set_object_orco(re, ob, orco);
+               orco = get_object_orco(re, ob);
+               if (!orco) {
+                       orco= dm->getVertDataArray(dm, CD_ORCO);
+                       if (orco) {
+                               orco= MEM_dupallocN(orco);
+                               set_object_orco(re, ob, orco);
+                       }
                }
        }
 
@@ -3413,7 +3210,7 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
 
        /* attempt to autsmooth on original mesh, only without subsurf */
        if (do_autosmooth && me->totvert==totvert && me->totface==dm->getNumTessFaces(dm))
-               use_original_normals= TRUE;
+               use_original_normals= true;
        
        ma= give_render_material(re, ob, 1);
 
@@ -3437,7 +3234,7 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
                for (a=0; a<totvert; a++, mvert++) {
                        ver= RE_findOrAddVert(obr, obr->totvert++);
                        copy_v3_v3(ver->co, mvert->co);
-                       if (do_autosmooth == FALSE) {   /* autosmooth on original unrotated data to prevent differences between frames */
+                       if (do_autosmooth == false) {   /* autosmooth on original unrotated data to prevent differences between frames */
                                normal_short_to_float_v3(ver->n, mvert->no);
                                mul_m4_v3(mat, ver->co);
                                mul_transposed_m3_v3(imat, ver->n);
@@ -3464,19 +3261,26 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
                }
                
                if (!timeoffset) {
+                       short (*lnp)[4][3] = NULL;
 #ifdef WITH_FREESTYLE
                        EdgeHash *edge_hash;
 
                        /* create a hash table of Freestyle edge marks */
-                       edge_hash = make_freestyle_edge_mark_hash(me, dm);
+                       edge_hash = make_freestyle_edge_mark_hash(dm);
 #endif
 
                        /* store customdata names, because DerivedMesh is freed */
                        RE_set_customdata_names(obr, &dm->faceData);
 
                        /* add tangent layer if we need one */
-                       if (need_nmap_tangent!=0 && CustomData_get_layer_index(&dm->faceData, CD_TANGENT) == -1)
-                               DM_add_tangent_layer(dm);
+                       if (need_nmap_tangent!=0 && CustomData_get_layer_index(&dm->faceData, CD_TANGENT) == -1) {
+                               bool generate_data = false;
+                               if (CustomData_get_layer_index(&dm->loopData, CD_TANGENT) == -1) {
+                                       dm->calcLoopTangents(dm);
+                                       generate_data = true;
+                               }
+                               DM_generate_tangent_tessface_data(dm, generate_data);
+                       }
                        
                        /* still to do for keys: the correct local texture coordinate */
 
@@ -3485,12 +3289,13 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
                        for (a1=0; (a1<ob->totcol || (a1==0 && ob->totcol==0)); a1++) {
 
                                ma= give_render_material(re, ob, a1+1);
-                               
+
                                /* test for 100% transparent */
                                ok = 1;
                                if ((ma->alpha == 0.0f) &&
                                    (ma->spectra == 0.0f) &&
-                                   (ma->filter == 0.0f) &&
+                                   /* No need to test filter here, it's only active with MA_RAYTRANSP and we check against it below. */
+                                   /* (ma->filter == 0.0f) && */
                                    (ma->mode & MA_TRANSP) &&
                                    (ma->mode & (MA_RAYTRANSP | MA_RAYMIRROR)) == 0)
                                {
@@ -3512,6 +3317,11 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
                                if (ok) {
                                        end= dm->getNumTessFaces(dm);
                                        mface= dm->getTessFaceArray(dm);
+                                       if (!loop_nors && do_autosmooth &&
+                                           (dm->getTessFaceDataArray(dm, CD_TESSLOOPNORMAL) != NULL))
+                                       {
+                                               lnp = loop_nors = MEM_mallocN(sizeof(*loop_nors) * end, __func__);
+                                       }
 #ifdef WITH_FREESTYLE
                                        index_mf_to_mpoly= dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
                                        index_mp_to_orig= dm->getPolyDataArray(dm, CD_ORIGINDEX);
@@ -3523,13 +3333,13 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
                                                
                                                if ( mface->mat_nr==a1 ) {
                                                        float len;
-                                                       int reverse_verts = (negative_scale != 0 && do_autosmooth == FALSE);
+                                                       bool reverse_verts = (negative_scale != 0 && do_autosmooth == false);
                                                        int rev_tab[] = {reverse_verts==0 ? 0 : 2, 1, reverse_verts==0 ? 2 : 0, 3};
                                                        v1= reverse_verts==0 ? mface->v1 : mface->v3;
                                                        v2= mface->v2;
                                                        v3= reverse_verts==0 ? mface->v3 : mface->v1;
                                                        v4= mface->v4;
-                                                       flag= mface->flag & ME_SMOOTH;
+                                                       flag = do_autosmooth ? ME_SMOOTH : mface->flag & ME_SMOOTH;
 
                                                        vlr= RE_findOrAddVlak(obr, obr->totvlak++);
                                                        vlr->v1= RE_findOrAddVert(obr, vertofs+v1);
@@ -3589,7 +3399,7 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
                                                                CustomDataLayer *layer;
                                                                MTFace *mtface, *mtf;
                                                                MCol *mcol, *mc;
-                                                               int index, mtfn= 0, mcn= 0, mtng=0, vindex;
+                                                               int index, mtfn= 0, mcn= 0, mtng=0, mln = 0, vindex;
                                                                char *name;
                                                                int nr_verts = v4!=0 ? 4 : 3;
 
@@ -3622,6 +3432,21 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
                                                                                                normalize_v3(ftang+vindex*4);
                                                                                        }
                                                                                }
+                                                                               mtng++;
+                                                                       }
+                                                                       else if (layer->type == CD_TESSLOOPNORMAL && mln < 1) {
+                                                                               if (loop_nors) {
+                                                                                       const short (*lnors)[4][3] = (const short (*)[4][3])layer->data;
+                                                                                       for (vindex = 0; vindex < 4; vindex++) {
+                                                                                               //print_v3("lnors[a][rev_tab[vindex]]", lnors[a][rev_tab[vindex]]);
+                                                                                               copy_v3_v3_short((short *)lnp[0][vindex], lnors[a][rev_tab[vindex]]);
+                                                                                               /* If we copy loop normals, we are doing autosmooth, so we are still
+                                                                                                * in object space, no need to multiply with mat!
+                                                                                                */
+                                                                                       }
+                                                                                       lnp++;
+                                                                               }
+                                                                               mln++;
                                                                        }
                                                                }
 
@@ -3704,24 +3529,22 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
                if (need_stress)
                        calc_edge_stress(re, obr, me);
 
-               if (test_for_displace(re, ob ) ) {
-                       recalc_normals= 1;
-                       calc_vertexnormals(re, obr, 0, 0);
-                       if (do_autosmooth)
-                               do_displacement(re, obr, mat, imat);
-                       else
-                               do_displacement(re, obr, NULL, NULL);
+               if (do_displace) {
+                       calc_vertexnormals(re, obr, 1, 0, 0);
+                       displace(re, obr);
+                       recalc_normals = 0;  /* Already computed by displace! */
                }
-
-               if (do_autosmooth) {
-                       recalc_normals= 1;
-                       autosmooth(re, obr, mat, me->smoothresh);
+               else if (do_autosmooth) {
+                       recalc_normals = (loop_nors == NULL);  /* Should never happen, but better be safe than sorry. */
+                       autosmooth(re, obr, mat, loop_nors);
                }
 
                if (recalc_normals!=0 || need_tangent!=0)
-                       calc_vertexnormals(re, obr, need_tangent, need_nmap_tangent);
+                       calc_vertexnormals(re, obr, recalc_normals, need_tangent, need_nmap_tangent);
        }
 
+       MEM_SAFE_FREE(loop_nors);
+
        dm->release(dm);
 }
 
@@ -3843,6 +3666,7 @@ static GroupObject *add_render_lamp(Render *re, Object *ob)
        mul_m4_m4m4(mat, re->viewmat, ob->obmat);
        invert_m4_m4(ob->imat, mat);
 
+       copy_m4_m4(lar->lampmat, ob->obmat);
        copy_m3_m4(lar->mat, mat);
        copy_m3_m4(lar->imat, ob->imat);
 
@@ -3897,8 +3721,8 @@ static GroupObject *add_render_lamp(Render *re, Object *ob)
        
        /* Annoying, lamp UI does this, but the UI might not have been used? - add here too.
         * make sure this matches buttons_shading.c's logic */
-       if (ELEM4(la->type, LA_AREA, LA_SPOT, LA_SUN, LA_LOCAL) && (la->mode & LA_SHAD_RAY))
-               if (ELEM3(la->type, LA_SPOT, LA_SUN, LA_LOCAL))
+       if (ELEM(la->type, LA_AREA, LA_SPOT, LA_SUN, LA_LOCAL) && (la->mode & LA_SHAD_RAY))
+               if (ELEM(la->type, LA_SPOT, LA_SUN, LA_LOCAL))
                        if (la->ray_samp_method == LA_SAMP_CONSTANT) la->ray_samp_method = LA_SAMP_HALTON;
        
        lar->ray_samp_method= la->ray_samp_method;
@@ -3963,9 +3787,9 @@ static GroupObject *add_render_lamp(Render *re, Object *ob)
        
        lar->spotsi= la->spotsize;
        if (lar->mode & LA_HALO) {
-               if (lar->spotsi>170.0f) lar->spotsi= 170.0f;
+               if (lar->spotsi > DEG2RADF(170.0f)) lar->spotsi = DEG2RADF(170.0f);
        }
-       lar->spotsi= cosf( (float)M_PI*lar->spotsi/360.0f );
+       lar->spotsi= cosf(lar->spotsi * 0.5f);
        lar->spotbl= (1.0f-lar->spotsi)*la->spotblend;
 
        memcpy(lar->mtex, la->mtex, MAX_MTEX*sizeof(void *));
@@ -3988,8 +3812,8 @@ static GroupObject *add_render_lamp(Render *re, Object *ob)
                normalize_v3(lar->imat[1]);
                normalize_v3(lar->imat[2]);
 
-               xn= saacos(lar->spotsi);
-               xn= sin(xn)/cos(xn);
+               xn = saacos(lar->spotsi);
+               xn = sinf(xn) / cosf(xn);
                lar->spottexfac= 1.0f/(xn);
 
                if (lar->mode & LA_ONLYSHADOW) {
@@ -3999,7 +3823,9 @@ static GroupObject *add_render_lamp(Render *re, Object *ob)
        }
 
        /* set flag for spothalo en initvars */
-       if (la->type==LA_SPOT && (la->mode & LA_HALO) && (la->buftype != LA_SHADBUF_DEEP)) {
+       if ((la->type == LA_SPOT) && (la->mode & LA_HALO) &&
+           (!(la->mode & LA_SHAD_BUF) || la->buftype != LA_SHADBUF_DEEP))
+       {
                if (la->haint>0.0f) {
                        re->flag |= R_LAMPHALO;
 
@@ -4012,13 +3838,13 @@ static GroupObject *add_render_lamp(Render *re, Object *ob)
                        /* z factor, for a normalized volume */
                        angle= saacos(lar->spotsi);
                        xn= lar->spotsi;
-                       yn= sin(angle);
+                       yn = sinf(angle);
                        lar->sh_zfac= yn/xn;
                        /* pre-scale */
                        lar->sh_invcampos[2]*= lar->sh_zfac;
 
                        /* halfway shadow buffer doesn't work for volumetric effects */
-                       if (lar->buftype == LA_SHADBUF_HALFWAY)
+                       if (ELEM(lar->buftype, LA_SHADBUF_HALFWAY, LA_SHADBUF_DEEP))
                                lar->buftype = LA_SHADBUF_REGULAR;
 
                }
@@ -4093,19 +3919,51 @@ static GroupObject *add_render_lamp(Render *re, Object *ob)
        return go;
 }
 
+static bool is_object_restricted(Render *re, Object *ob)
+{
+       if (re->r.scemode & R_VIEWPORT_PREVIEW)
+               return (ob->restrictflag & OB_RESTRICT_VIEW) != 0;
+       else
+               return (ob->restrictflag & OB_RESTRICT_RENDER) != 0;
+}
+
+static bool is_object_hidden(Render *re, Object *ob)
+{
+       if (is_object_restricted(re, ob))
+               return true;
+       
+       if (re->r.scemode & R_VIEWPORT_PREVIEW) {
+               /* Mesh deform cages and so on mess up the preview. To avoid the problem,
+                * viewport doesn't show mesh object if its draw type is bounding box or wireframe.
+                * Unless it's an active smoke domain!
+                */
+               ModifierData *md = NULL;
+
+               if ((md = modifiers_findByType(ob, eModifierType_Smoke)) &&
+                   (modifier_isEnabled(re->scene, md, eModifierMode_Realtime)))
+               {
+                       return false;
+               }
+               return ELEM(ob->dt, OB_BOUNDBOX, OB_WIRE);
+       }
+       else {
+               return false;
+       }
+}
+
 /* layflag: allows material group to ignore layerflag */
 static void add_lightgroup(Render *re, Group *group, int exclusive)
 {
        GroupObject *go, *gol;
        
-       group->id.flag &= ~LIB_DOIT;
+       group->id.tag &= ~LIB_TAG_DOIT;
 
        /* it's a bit too many loops in loops... but will survive */
        /* note that 'exclusive' will remove it from the global list */
        for (go= group->gobject.first; go; go= go->next) {
                go->lampren= NULL;
 
-               if (go->ob->restrictflag & OB_RESTRICT_RENDER)
+               if (is_object_hidden(re, go->ob))
                        continue;
                
                if (go->ob->lay & re->lay) {
@@ -4137,12 +3995,12 @@ static void set_material_lightgroups(Render *re)
                return;
        
        for (group= re->main->group.first; group; group=group->id.next)
-               group->id.flag |= LIB_DOIT;
+               group->id.tag |= LIB_TAG_DOIT;
        
        /* it's a bit too many loops in loops... but will survive */
        /* hola! materials not in use...? */
        for (ma= re->main->mat.first; ma; ma=ma->id.next) {
-               if (ma->group && (ma->group->id.flag & LIB_DOIT))
+               if (ma->group && (ma->group->id.tag & LIB_TAG_DOIT))
                        add_lightgroup(re, ma->group, ma->mode & MA_GROUP_NOLAY);
        }
 }
@@ -4512,7 +4370,7 @@ static void finalize_render_object(Render *re, ObjectRen *obr, int timeoffset)
                 * I will look at means to have autosmooth enabled for all object types
                 * and have it as general postprocess, like displace */
                if (ob->type!=OB_MESH && test_for_displace(re, ob))
-                       do_displacement(re, obr, NULL, NULL);
+                       displace(re, obr);
        
                if (!timeoffset) {
                        /* phong normal interpolation can cause error in tracing
@@ -4677,7 +4535,7 @@ static ObjectRen *find_dupligroup_dupli(Render *re, Object *ob, int psysindex)
        return NULL;
 }
 
-static void set_dupli_tex_mat(Render *re, ObjectInstanceRen *obi, DupliObject *dob)
+static void set_dupli_tex_mat(Render *re, ObjectInstanceRen *obi, DupliObject *dob, float omat[4][4])
 {
        /* For duplis we need to have a matrix that transform the coordinate back
         * to it's original position, without the dupli transforms. We also check
@@ -4715,8 +4573,7 @@ static void set_dupli_tex_mat(Render *re, ObjectInstanceRen *obi, DupliObject *d
 
                obi->duplitexmat= BLI_memarena_alloc(re->memArena, sizeof(float)*4*4);
                invert_m4_m4(imat, dob->mat);
-               mul_serie_m4(obi->duplitexmat, re->viewmat, dob->omat, imat, re->viewinv,
-                            NULL, NULL, NULL, NULL);
+               mul_m4_series(obi->duplitexmat, re->viewmat, omat, imat, re->viewinv);
        }
 
        copy_v3_v3(obi->dupliorco, dob->orco);
@@ -4734,10 +4591,12 @@ static void init_render_object_data(Render *re, ObjectRen *obr, int timeoffset)
                        /* the emitter mesh wasn't rendered so the modifier stack wasn't
                         * evaluated with render settings */
                        DerivedMesh *dm;
+                       const CustomDataMask mask = CD_MASK_RENDER_INTERNAL;
+
                        if (re->r.scemode & R_VIEWPORT_PREVIEW)
-                               dm = mesh_create_derived_view(re->scene, ob, CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL);
+                               dm = mesh_create_derived_view(re->scene, ob, mask);
                        else
-                               dm = mesh_create_derived_render(re->scene, ob,  CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL);
+                               dm = mesh_create_derived_render(re->scene, ob, mask);
                        dm->release(dm);
                }
 
@@ -4765,7 +4624,7 @@ static void init_render_object_data(Render *re, ObjectRen *obr, int timeoffset)
        re->totstrand += obr->totstrand;
 }
 
-static void add_render_object(Render *re, Object *ob, Object *par, DupliObject *dob, int timeoffset)
+static void add_render_object(Render *re, Object *ob, Object *par, DupliObject *dob, float omat[4][4], int timeoffset)
 {
        ObjectRen *obr;
        ObjectInstanceRen *obi;
@@ -4800,8 +4659,8 @@ static void add_render_object(Render *re, Object *ob, Object *par, DupliObject *
 
                /* only add instance for objects that have not been used for dupli */
                if (!(ob->transflag & OB_RENDER_DUPLI)) {
-                       obi= RE_addRenderInstance(re, obr, ob, par, index, 0, NULL, ob->lay);
-                       if (dob) set_dupli_tex_mat(re, obi, dob);
+                       obi = RE_addRenderInstance(re, obr, ob, par, index, 0, NULL, ob->lay, dob);
+                       if (dob) set_dupli_tex_mat(re, obi, dob, omat);
                }
                else
                        find_dupli_instances(re, obr, dob);
@@ -4829,13 +4688,13 @@ static void add_render_object(Render *re, Object *ob, Object *par, DupliObject *
                                psys->flag |= PSYS_USE_IMAT;
                        init_render_object_data(re, obr, timeoffset);
                        if (!(re->r.scemode & R_VIEWPORT_PREVIEW))
-                               psys_render_restore(ob, psys);
+                               psys_render_restore(re->scene, ob, psys);
                        psys->flag &= ~PSYS_USE_IMAT;
 
                        /* only add instance for objects that have not been used for dupli */
                        if (!(ob->transflag & OB_RENDER_DUPLI)) {
-                               obi= RE_addRenderInstance(re, obr, ob, par, index, psysindex, NULL, ob->lay);
-                               if (dob) set_dupli_tex_mat(re, obi, dob);
+                               obi = RE_addRenderInstance(re, obr, ob, par, index, psysindex, NULL, ob->lay, dob);
+                               if (dob) set_dupli_tex_mat(re, obi, dob, omat);
                        }
                        else
                                find_dupli_instances(re, obr, dob);
@@ -4845,7 +4704,7 @@ static void add_render_object(Render *re, Object *ob, Object *par, DupliObject *
 
 /* par = pointer to duplicator parent, needed for object lookup table */
 /* index = when duplicater copies same object (particle), the counter */
-static void init_render_object(Render *re, Object *ob, Object *par, DupliObject *dob, int timeoffset)
+static void init_render_object(Render *re, Object *ob, Object *par, DupliObject *dob, float omat[4][4], int timeoffset)
 {
        static double lasttime= 0.0;
        double time;
@@ -4854,7 +4713,7 @@ static void init_render_object(Render *re, Object *ob, Object *par, DupliObject
        if (ob->type==OB_LAMP)
                add_render_lamp(re, ob);
        else if (render_object_type(ob->type))
-               add_render_object(re, ob, par, dob, timeoffset);
+               add_render_object(re, ob, par, dob, omat, timeoffset);
        else {
                mul_m4_m4m4(mat, re->viewmat, ob->obmat);
                invert_m4_m4(ob->imat, mat);
@@ -4941,7 +4800,7 @@ void RE_Database_Free(Render *re)
        free_strand_surface(re);
        
        re->totvlak=re->totvert=re->totstrand=re->totlamp=re->tothalo= 0;
-       re->i.convertdone = FALSE;
+       re->i.convertdone = false;
 
        re->bakebuf= NULL;
 
@@ -4958,12 +4817,14 @@ void RE_Database_Free(Render *re)
 
 static int allow_render_object(Render *re, Object *ob, int nolamps, int onlyselected, Object *actob)
 {
-       /* override not showing object when duplis are used with particles */
-       if (ob->transflag & OB_DUPLIPARTS) {
-               /* pass */  /* let particle system(s) handle showing vs. not showing */
-       }
-       else if ((ob->transflag & OB_DUPLI) && !(ob->transflag & OB_DUPLIFRAMES)) {
+       if (is_object_hidden(re, ob))
                return 0;
+
+       /* Only handle dupli-hiding here if there is no particle systems. Else, let those handle show/noshow. */
+       if (!ob->particlesystem.first) {
+               if ((ob->transflag & OB_DUPLI) && !(ob->transflag & OB_DUPLIFRAMES)) {
+                       return 0;
+               }
        }
        
        /* don't add non-basic meta objects, ends up having renderobjects with no geometry */
@@ -4998,7 +4859,7 @@ static int allow_render_dupli_instance(Render *UNUSED(re), DupliObject *dob, Obj
        }
 
        for (psys=obd->particlesystem.first; psys; psys=psys->next)
-               if (!ELEM5(psys->part->ren_as, PART_DRAW_BB, PART_DRAW_LINE, PART_DRAW_PATH, PART_DRAW_OB, PART_DRAW_GR))
+               if (!ELEM(psys->part->ren_as, PART_DRAW_BB, PART_DRAW_LINE, PART_DRAW_PATH, PART_DRAW_OB, PART_DRAW_GR))
                        return 0;
 
        /* don't allow lamp, animated duplis, or radio render */
@@ -5027,7 +4888,7 @@ static void dupli_render_particle_set(Render *re, Object *ob, int timeoffset, in
                                if (enable)
                                        psys_render_set(ob, psys, re->viewmat, re->winmat, re->winx, re->winy, timeoffset);
                                else
-                                       psys_render_restore(ob, psys);
+                                       psys_render_restore(re->scene, ob, psys);
                        }
                }
 
@@ -5035,7 +4896,7 @@ static void dupli_render_particle_set(Render *re, Object *ob, int timeoffset, in
                        /* this is to make sure we get render level duplis in groups:
                         * the derivedmesh must be created before init_render_mesh,
                         * since object_duplilist does dupliparticles before that */
-                       dm = mesh_create_derived_render(re->scene, ob, CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL);
+                       dm = mesh_create_derived_render(re->scene, ob, CD_MASK_RENDER_INTERNAL);
                        dm->release(dm);
 
                        for (psys=ob->particlesystem.first; psys; psys=psys->next)
@@ -5078,7 +4939,7 @@ static void add_group_render_dupli_obs(Render *re, Group *group, int nolamps, in
                if (ob->flag & OB_DONE) {
                        if (ob->transflag & OB_RENDER_DUPLI) {
                                if (allow_render_object(re, ob, nolamps, onlyselected, actob)) {
-                                       init_render_object(re, ob, NULL, NULL, timeoffset);
+                                       init_render_object(re, ob, NULL, NULL, NULL, timeoffset);
                                        ob->transflag &= ~OB_RENDER_DUPLI;
 
                                        if (ob->dup_group)
@@ -5096,13 +4957,12 @@ static void database_init_objects(Render *re, unsigned int renderlay, int nolamp
        Group *group;
        ObjectInstanceRen *obi;
        Scene *sce_iter;
-       float mat[4][4];
        int lay, vectorlay;
 
        /* for duplis we need the Object texture mapping to work as if
         * untransformed, set_dupli_tex_mat sets the matrix to allow that
         * NULL is just for init */
-       set_dupli_tex_mat(NULL, NULL, NULL);
+       set_dupli_tex_mat(NULL, NULL, NULL, NULL);
 
        /* loop over all objects rather then using SETLOOPER because we may
         * reference an mtex-mapped object which isn't rendered or is an
@@ -5111,6 +4971,8 @@ static void database_init_objects(Render *re, unsigned int renderlay, int nolamp
         * 'imat' / 'imat_ren' on all and unlikely to be a performance hit
         * See bug: [#28744] - campbell */
        for (ob= re->main->object.first; ob; ob= ob->id.next) {
+               float mat[4][4];
+               
                /* imat objects has to be done here, since displace can have texture using Object map-input */
                mul_m4_m4m4(mat, re->viewmat, ob->obmat);
                invert_m4_m4(ob->imat_ren, mat);
@@ -5130,7 +4992,7 @@ static void database_init_objects(Render *re, unsigned int renderlay, int nolamp
                lay= (timeoffset)? renderlay & vectorlay: renderlay;
 
                /* if the object has been restricted from rendering in the outliner, ignore it */
-               if (ob->restrictflag & OB_RESTRICT_RENDER) continue;
+               if (is_object_restricted(re, ob)) continue;
 
                /* OB_DONE means the object itself got duplicated, so was already converted */
                if (ob->flag & OB_DONE) {
@@ -5138,7 +5000,7 @@ static void database_init_objects(Render *re, unsigned int renderlay, int nolamp
                         * it still needs to create the ObjectRen containing the data */
                        if (ob->transflag & OB_RENDER_DUPLI) {
                                if (allow_render_object(re, ob, nolamps, onlyselected, actob)) {
-                                       init_render_object(re, ob, NULL, NULL, timeoffset);
+                                       init_render_object(re, ob, NULL, NULL, NULL, timeoffset);
                                        ob->transflag &= ~OB_RENDER_DUPLI;
                                }
                        }
@@ -5146,24 +5008,30 @@ static void database_init_objects(Render *re, unsigned int renderlay, int nolamp
                else if ((base->lay & lay) || (ob->type==OB_LAMP && (base->lay & re->lay)) ) {
                        if ((ob->transflag & OB_DUPLI) && (ob->type!=OB_MBALL)) {
                                DupliObject *dob;
-                               ListBase *lb;
+                               ListBase *duplilist;
+                               DupliApplyData *duplilist_apply_data = NULL;
+                               int i;
 
                                /* create list of duplis generated by this object, particle
                                 * system need to have render settings set for dupli particles */
                                dupli_render_particle_set(re, ob, timeoffset, 0, 1);
-                               lb= object_duplilist(re->scene, ob, TRUE);
-                               dupli_render_particle_set(re, ob, timeoffset, 0, 0);
-
-                               for (dob= lb->first; dob; dob= dob->next) {
+                               duplilist = object_duplilist(re->eval_ctx, re->scene, ob);
+                               duplilist_apply_data = duplilist_apply(ob, NULL, duplilist);
+                               /* postpone 'dupli_render_particle_set', since RE_addRenderInstance reads
+                                * index values from 'dob->persistent_id[0]', referencing 'psys->child' which
+                                * may be smaller once the particle system is restored, see: T45563. */
+
+                               for (dob= duplilist->first, i = 0; dob; dob= dob->next, ++i) {
+                                       DupliExtraData *dob_extra = &duplilist_apply_data->extra[i];
                                        Object *obd= dob->ob;
-                                       
+
                                        copy_m4_m4(obd->obmat, dob->mat);
 
                                        /* group duplis need to set ob matrices correct, for deform. so no_draw is part handled */
                                        if (!(obd->transflag & OB_RENDER_DUPLI) && dob->no_draw)
                                                continue;
 
-                                       if (obd->restrictflag & OB_RESTRICT_RENDER)
+                                       if (is_object_hidden(re, obd))
                                                continue;
 
                                        if (obd->type==OB_MBALL)
@@ -5186,10 +5054,10 @@ static void database_init_objects(Render *re, unsigned int renderlay, int nolamp
                                                if (dob->type != OB_DUPLIGROUP || (obr=find_dupligroup_dupli(re, obd, 0))) {
                                                        mul_m4_m4m4(mat, re->viewmat, dob->mat);
                                                                                                                /* ob = particle system, use that layer */
-                                                       obi= RE_addRenderInstance(re, NULL, obd, ob, dob->persistent_id[0], 0, mat, ob->lay); 
+                                                       obi = RE_addRenderInstance(re, NULL, obd, ob, dob->persistent_id[0], 0, mat, ob->lay, dob);
 
                                                        /* fill in instance variables for texturing */
-                                                       set_dupli_tex_mat(re, obi, dob);
+                                                       set_dupli_tex_mat(re, obi, dob, dob_extra->obmat);
                                                        if (dob->type != OB_DUPLIGROUP) {
                                                                copy_v3_v3(obi->dupliorco, dob->orco);
                                                                obi->dupliuv[0]= dob->uv[0];
@@ -5213,9 +5081,9 @@ static void database_init_objects(Render *re, unsigned int renderlay, int nolamp
                                                        if (dob->type != OB_DUPLIGROUP || (obr=find_dupligroup_dupli(re, obd, psysindex))) {
                                                                if (obi == NULL)
                                                                        mul_m4_m4m4(mat, re->viewmat, dob->mat);
-                                                               obi= RE_addRenderInstance(re, NULL, obd, ob, dob->persistent_id[0], psysindex++, mat, obd->lay);
+                                                               obi = RE_addRenderInstance(re, NULL, obd, ob, dob->persistent_id[0], psysindex++, mat, obd->lay, dob);
 
-                                                               set_dupli_tex_mat(re, obi, dob);
+                                                               set_dupli_tex_mat(re, obi, dob, dob_extra->obmat);
                                                                if (dob->type != OB_DUPLIGROUP) {
                                                                        copy_v3_v3(obi->dupliorco, dob->orco);
                                                                        obi->dupliuv[0]= dob->uv[0];
@@ -5231,7 +5099,7 @@ static void database_init_objects(Render *re, unsigned int renderlay, int nolamp
 
                                                if (obi==NULL)
                                                        /* can't instance, just create the object */
-                                                       init_render_object(re, obd, ob, dob, timeoffset);
+                                                       init_render_object(re, obd, ob, dob, dob_extra->obmat, timeoffset);
                                                
                                                if (dob->type != OB_DUPLIGROUP) {
                                                        obd->flag |= OB_DONE;
@@ -5239,17 +5107,25 @@ static void database_init_objects(Render *re, unsigned int renderlay, int nolamp
                                                }
                                        }
                                        else
-                                               init_render_object(re, obd, ob, dob, timeoffset);
+                                               init_render_object(re, obd, ob, dob, dob_extra->obmat, timeoffset);
                                        
                                        if (re->test_break(re->tbh)) break;
                                }
-                               free_object_duplilist(lb);
+
+                               /* restore particle system */
+                               dupli_render_particle_set(re, ob, timeoffset, 0, false);
+
+                               if (duplilist_apply_data) {
+                                       duplilist_restore(duplilist, duplilist_apply_data);
+                                       duplilist_free_apply_data(duplilist_apply_data);
+                               }
+                               free_object_duplilist(duplilist);
 
                                if (allow_render_object(re, ob, nolamps, onlyselected, actob))
-                                       init_render_object(re, ob, NULL, NULL, timeoffset);
+                                       init_render_object(re, ob, NULL, NULL, NULL, timeoffset);
                        }
                        else if (allow_render_object(re, ob, nolamps, onlyselected, actob))
-                               init_render_object(re, ob, NULL, NULL, timeoffset);
+                               init_render_object(re, ob, NULL, NULL, NULL, timeoffset);
                }
 
                if (re->test_break(re->tbh)) break;
@@ -5293,17 +5169,18 @@ void RE_Database_FromScene(Render *re, Main *bmain, Scene *scene, unsigned int l
        re->totvlak=re->totvert=re->totstrand=re->totlamp=re->tothalo= 0;
        re->lights.first= re->lights.last= NULL;
        re->lampren.first= re->lampren.last= NULL;
-       
-       slurph_opt= 0;
-       re->i.partsdone = FALSE;        /* signal now in use for previewrender */
+
+       re->i.partsdone = false;        /* signal now in use for previewrender */
        
        /* in localview, lamps are using normal layers, objects only local bits */
        if (re->lay & 0xFF000000)
                lay &= 0xFF000000;
        
        /* applies changes fully */
-       if ((re->r.scemode & (R_NO_FRAME_UPDATE|R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))==0)
-               BKE_scene_update_for_newframe(re->main, re->scene, lay);
+       if ((re->r.scemode & (R_NO_FRAME_UPDATE|R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))==0) {
+               BKE_scene_update_for_newframe(re->eval_ctx, re->main, re->scene, lay);
+               render_update_anim_renderdata(re, &re->scene->r);
+       }
        
        /* if no camera, viewmat should have been set! */
        if (use_camera_view && camera) {
@@ -5311,11 +5188,12 @@ void RE_Database_FromScene(Render *re, Main *bmain, Scene *scene, unsigned int l
                 * above call to BKE_scene_update_for_newframe, fixes bug. [#22702].
                 * following calls don't depend on 'RE_SetCamera' */
                RE_SetCamera(re, camera);
-
-               normalize_m4_m4(mat, camera->obmat);
+               RE_GetCameraModelMatrix(re, camera, mat);
                invert_m4(mat);
                RE_SetView(re, mat);
-               camera->recalc= OB_RECALC_OB; /* force correct matrix for scaled cameras */
+
+               /* force correct matrix for scaled cameras */
+               DAG_id_tag_update_ex(re->main, &camera->id, OB_RECALC_OB);
        }
        
        /* store for incremental render, viewmat rotates dbase */
@@ -5333,7 +5211,7 @@ void RE_Database_FromScene(Render *re, Main *bmain, Scene *scene, unsigned int l
        /* still bad... doing all */
        init_render_textures(re);
        copy_v3_v3(amb, &re->wrld.ambr);
-       init_render_materials(re->main, re->r.mode, amb);
+       init_render_materials(re->main, re->r.mode, amb, (re->r.scemode & R_BUTS_PREVIEW) == 0);
        set_node_shader_lamp_loop(shade_material_loop);
 
        /* MAKE RENDER DATA */
@@ -5352,8 +5230,6 @@ void RE_Database_FromScene(Render *re, Main *bmain, Scene *scene, unsigned int l
                re->i.totlamp= re->totlamp;
                re->stats_draw(re->sdh, &re->i);
        }
-
-       slurph_opt= 1;
 }
 
 void RE_Database_Preprocess(Render *re)
@@ -5361,15 +5237,7 @@ void RE_Database_Preprocess(Render *re)
        if (!re->test_break(re->tbh)) {
                int tothalo;
 
-               /* don't sort stars */
                tothalo= re->tothalo;
-               if (!re->test_break(re->tbh)) {
-                       if (re->wrld.mode & WO_STARS) {
-                               re->i.infostr = IFACE_("Creating Starfield");
-                               re->stats_draw(re->sdh, &re->i);
-                               RE_make_stars(re, NULL, NULL, NULL, NULL);
-                       }
-               }
                sort_halos(re, tothalo);
                
                init_camera_inside_volumes(re);
@@ -5401,7 +5269,7 @@ void RE_Database_Preprocess(Render *re)
                }
                
                if (!re->test_break(re->tbh))
-                       project_renderdata(re, projectverto, re->r.mode & R_PANORAMA, 0, 1);
+                       project_renderdata(re, projectverto, (re->r.mode & R_PANORAMA) != 0, 0, 1);
                
                /* Occlusion */
                if ((re->wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT)) && !re->test_break(re->tbh))
@@ -5418,7 +5286,7 @@ void RE_Database_Preprocess(Render *re)
                                volume_precache(re);
        }
        
-       re->i.convertdone = TRUE;
+       re->i.convertdone = true;
 
        if (re->test_break(re->tbh))
                RE_Database_Free(re);
@@ -5446,6 +5314,8 @@ void RE_DataBase_IncrementalView(Render *re, float viewmat[4][4], int restore)
        copy_m4_m4(re->viewmat, viewmat);
        invert_m4_m4(re->viewinv, re->viewmat);
        
+       init_camera_inside_volumes(re);
+
        env_rotate_scene(re, tmat, !restore);
 
        /* SSS points distribution depends on view */
@@ -5477,8 +5347,6 @@ static void database_fromscene_vectors(Render *re, Scene *scene, unsigned int la
        re->totvlak=re->totvert=re->totstrand=re->totlamp=re->tothalo= 0;
        re->i.totface=re->i.totvert=re->i.totstrand=re->i.totlamp=re->i.tothalo= 0;
        re->lights.first= re->lights.last= NULL;
-
-       slurph_opt= 0;
        
        /* in localview, lamps are using normal layers, objects only local bits */
        if (re->lay & 0xFF000000)
@@ -5486,11 +5354,12 @@ static void database_fromscene_vectors(Render *re, Scene *scene, unsigned int la
        
        /* applies changes fully */
        scene->r.cfra += timeoffset;
-       BKE_scene_update_for_newframe(re->main, re->scene, lay);
+       BKE_scene_update_for_newframe(re->eval_ctx, re->main, re->scene, lay);
        
        /* if no camera, viewmat should have been set! */
        if (camera) {
-               normalize_m4_m4(mat, camera->obmat);
+               RE_GetCameraModelMatrix(re, camera, mat);
+               normalize_m4(mat);
                invert_m4(mat);
                RE_SetView(re, mat);
        }
@@ -5499,7 +5368,7 @@ static void database_fromscene_vectors(Render *re, Scene *scene, unsigned int la
        database_init_objects(re, lay, 0, 0, NULL, timeoffset);
        
        if (!re->test_break(re->tbh))
-               project_renderdata(re, projectverto, re->r.mode & R_PANORAMA, 0, 1);
+               project_renderdata(re, projectverto, (re->r.mode & R_PANORAMA) != 0, 0, 1);
 
        /* do this in end, particles for example need cfra */
        scene->r.cfra -= timeoffset;
@@ -5597,7 +5466,7 @@ static float *calculate_strandsurface_speedvectors(Render *re, ObjectInstanceRen
 {
        if (mesh->co && mesh->prevco && mesh->nextco) {
                float winsq= (float)re->winx*(float)re->winy; /* int's can wrap on large images */
-               float winroot= sqrt(winsq);
+               float winroot= sqrtf(winsq);
                float (*winspeed)[4];
                float ho[4], prevho[4], nextho[4], winmat[4][4], vec[2];
                int a;
@@ -5636,7 +5505,7 @@ static void calculate_speedvectors(Render *re, ObjectInstanceRen *obi, float *ve
        StrandSurface *mesh= NULL;
        float *speed, (*winspeed)[4]=NULL, ho[4], winmat[4][4];
        float *co1, *co2, *co3, *co4, w[4];
-       float winsq= (float)re->winx*(float)re->winy, winroot= sqrt(winsq);  /* int's can wrap on large images */
+       float winsq = (float)re->winx * (float)re->winy, winroot = sqrtf(winsq);  /* int's can wrap on large images */
        int a, *face, *index;
 
        if (obi->flag & R_TRANSFORMED)
@@ -5703,7 +5572,7 @@ static int load_fluidsimspeedvectors(Render *re, ObjectInstanceRen *obi, float *
        VertRen *ver= NULL;
        float *speed, div, zco[2], avgvel[4] = {0.0, 0.0, 0.0, 0.0};
        float zmulx= re->winx/2, zmuly= re->winy/2, len;
-       float winsq= (float)re->winx*(float)re->winy, winroot= sqrt(winsq); /* int's can wrap on large images */
+       float winsq = (float)re->winx * (float)re->winy, winroot= sqrtf(winsq); /* int's can wrap on large images */
        int a, j;
        float hoco[4], ho[4], fsvec[4], camco[4];
        float mat[4][4], winmat[4][4];
@@ -5871,7 +5740,7 @@ void RE_Database_FromScene_Vectors(Render *re, Main *bmain, Scene *sce, unsigned
        /* free dbase and make the future one */
        strandsurface= re->strandsurface;
        memset(&re->strandsurface, 0, sizeof(ListBase));
-       re->i.convertdone = TRUE;
+       re->i.convertdone = true;
        RE_Database_Free(re);
        re->strandsurface= strandsurface;
        
@@ -5887,7 +5756,7 @@ void RE_Database_FromScene_Vectors(Render *re, Main *bmain, Scene *sce, unsigned
        /* free dbase and make the real one */
        strandsurface= re->strandsurface;
        memset(&re->strandsurface, 0, sizeof(ListBase));
-       re->i.convertdone = TRUE;
+       re->i.convertdone = true;
        RE_Database_Free(re);
        re->strandsurface= strandsurface;
        
@@ -5982,7 +5851,9 @@ void RE_Database_FromScene_Vectors(Render *re, Main *bmain, Scene *sce, unsigned
  * RE_BAKE_NORMALS:for baking, no lamps and only selected objects
  * RE_BAKE_AO:     for baking, no lamps, but all objects
  * RE_BAKE_TEXTURE:for baking, no lamps, only selected objects
+ * RE_BAKE_VERTEX_COLORS:for baking, no lamps, only selected objects
  * RE_BAKE_DISPLACEMENT:for baking, no lamps, only selected objects
+ * RE_BAKE_DERIVATIVE:for baking, no lamps, only selected objects
  * RE_BAKE_SHADOW: for baking, only shadows, but all objects
  */
 void RE_Database_Baking(Render *re, Main *bmain, Scene *scene, unsigned int lay, const int type, Object *actob)
@@ -5990,16 +5861,20 @@ void RE_Database_Baking(Render *re, Main *bmain, Scene *scene, unsigned int lay,
        Object *camera;
        float mat[4][4];
        float amb[3];
-       const short onlyselected= !ELEM4(type, RE_BAKE_LIGHT, RE_BAKE_ALL, RE_BAKE_SHADOW, RE_BAKE_AO);
-       const short nolamps= ELEM3(type, RE_BAKE_NORMALS, RE_BAKE_TEXTURE, RE_BAKE_DISPLACEMENT);
+       const short onlyselected= !ELEM(type, RE_BAKE_LIGHT, RE_BAKE_ALL, RE_BAKE_SHADOW, RE_BAKE_AO, RE_BAKE_VERTEX_COLORS);
+       const short nolamps= ELEM(type, RE_BAKE_NORMALS, RE_BAKE_TEXTURE, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE, RE_BAKE_VERTEX_COLORS);
 
        re->main= bmain;
        re->scene= scene;
        re->lay= lay;
 
        /* renderdata setup and exceptions */
-       re->r= scene->r;
-       
+       BLI_freelistN(&re->r.layers);
+       BLI_freelistN(&re->r.views);
+       re->r = scene->r;
+       BLI_duplicatelist(&re->r.layers, &scene->r.layers);
+       BLI_duplicatelist(&re->r.views, &scene->r.views);
+
        RE_init_threadcount(re);
        
        re->flag |= R_BAKING;
@@ -6009,8 +5884,11 @@ void RE_Database_Baking(Render *re, Main *bmain, Scene *scene, unsigned int lay,
 
        if (type==RE_BAKE_NORMALS && re->r.bake_normal_space==R_BAKE_SPACE_TANGENT)
                re->flag |= R_NEED_TANGENT;
-       
-       if (!actob && ELEM4(type, RE_BAKE_LIGHT, RE_BAKE_NORMALS, RE_BAKE_TEXTURE, RE_BAKE_DISPLACEMENT)) {
+
+       if (type==RE_BAKE_VERTEX_COLORS)
+               re->flag |=  R_NEED_VCOL;
+
+       if (!actob && ELEM(type, RE_BAKE_LIGHT, RE_BAKE_NORMALS, RE_BAKE_TEXTURE, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE, RE_BAKE_VERTEX_COLORS)) {
                re->r.mode &= ~R_SHADOW;
                re->r.mode &= ~R_RAYTRACE;
        }
@@ -6064,7 +5942,7 @@ void RE_Database_Baking(Render *re, Main *bmain, Scene *scene, unsigned int lay,
        init_render_textures(re);
        
        copy_v3_v3(amb, &re->wrld.ambr);
-       init_render_materials(re->main, re->r.mode, amb);
+       init_render_materials(re->main, re->r.mode, amb, true);
        
        set_node_shader_lamp_loop(shade_material_loop);