Fix T47038: Particles in Particle Edit Mode get added in completely wrong location.
[blender.git] / source / blender / render / intern / source / convertblender.c
index e9d3e294b28bedc90e293be4f7b1eccaf2789cdb..69e45fea74dbfd22f361a464a55a393c7debcdf9 100644 (file)
 #include "BLI_blenlib.h"
 #include "BLI_utildefines.h"
 #include "BLI_rand.h"
-#include "BLI_task.h"
 #include "BLI_memarena.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 "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
 
 /* ------------------------------------------------------------------------- */
 
+#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);
@@ -161,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);
                        }
                }
@@ -398,23 +378,25 @@ static void SetTSpace(const SMikkTSpaceContext *pContext, const float fvTangent[
        }
 }
 
-static void calc_vertexnormals(Render *UNUSED(re), ObjectRen *obr, bool do_tangent, bool 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);
@@ -426,11 +408,11 @@ static void calc_vertexnormals(Render *UNUSED(re), ObjectRen *obr, bool do_tange
                }
        }
 
-               /* 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);
@@ -494,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)
@@ -790,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;
@@ -955,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;
@@ -1231,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)
@@ -1273,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;
@@ -1290,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;
@@ -1333,7 +1314,6 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
        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;
@@ -1351,7 +1331,10 @@ 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) && psys->edit)
+       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 */
@@ -1377,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;
 
@@ -1407,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
@@ -1427,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;
@@ -1455,8 +1440,7 @@ 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 */
@@ -1466,7 +1450,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
 
 /* 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)) {
@@ -1516,9 +1500,9 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
                                if (ma->amb != 0.0f)
                                        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;
                        }
@@ -1573,10 +1557,10 @@ 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;
 
@@ -1585,7 +1569,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
 
                        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;
@@ -1596,10 +1580,10 @@ 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);
@@ -1627,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);
@@ -1753,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);
                                }
@@ -1819,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 {
@@ -1855,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);
                        }
                }
 
@@ -1867,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 */
@@ -1883,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);
        
@@ -1899,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;
 }
@@ -2009,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;
@@ -2022,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;
@@ -2062,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;
@@ -2083,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]; 
@@ -2108,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;
 
@@ -2137,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;
@@ -2163,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;
@@ -2188,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);
 }
 
 /* ------------------------------------------------------------------------- */
@@ -2587,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);
        }
 
 }
@@ -2675,7 +2644,7 @@ 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 nr, startvert, a, b, negative_scale;
        bool need_orco = false;
        int totmat;
 
@@ -2689,10 +2658,10 @@ static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset)
        
        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 */
@@ -2734,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;
@@ -2758,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];
@@ -2770,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_EPSILON) {
-                                                       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 ];
@@ -2966,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)
@@ -2982,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);
@@ -3099,36 +3072,21 @@ 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(__func__);
-               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);
-                       }
+               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;
@@ -3154,10 +3112,11 @@ 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;
+       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, totvert = 0;
-       bool do_autosmooth = false;
+       bool do_autosmooth = false, do_displace = false;
        bool use_original_normals = false;
        int recalc_normals = 0; /* false by default */
        int negative_scale;
@@ -3207,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) != 0;
-       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;
@@ -3301,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 */
 
@@ -3322,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)
                                {
@@ -3349,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);
@@ -3360,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);
@@ -3426,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;
 
@@ -3459,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++;
                                                                        }
                                                                }
 
@@ -3541,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);
 }
 
@@ -3680,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);
 
@@ -3734,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;
@@ -3825,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) {
@@ -3836,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;
 
@@ -3849,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;
 
                }
@@ -3930,20 +3919,44 @@ static GroupObject *add_render_lamp(Render *re, Object *ob)
        return go;
 }
 
-static bool is_object_hidden(Render *re, Object *ob)
+static bool is_object_restricted(Render *re, Object *ob)
 {
        if (re->r.scemode & R_VIEWPORT_PREVIEW)
-               return (ob->restrictflag & OB_RESTRICT_VIEW) != 0 || ELEM(ob->dt, OB_BOUNDBOX, OB_WIRE);
+               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 */
@@ -3982,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);
        }
 }
@@ -4357,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
@@ -4560,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, 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);
@@ -4579,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);
                }
 
@@ -4645,7 +4659,7 @@ 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);
+                       obi = RE_addRenderInstance(re, obr, ob, par, index, 0, NULL, ob->lay, dob);
                        if (dob) set_dupli_tex_mat(re, obi, dob, omat);
                }
                else
@@ -4674,12 +4688,12 @@ 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);
+                               obi = RE_addRenderInstance(re, obr, ob, par, index, psysindex, NULL, ob->lay, dob);
                                if (dob) set_dupli_tex_mat(re, obi, dob, omat);
                        }
                        else
@@ -4803,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 */
@@ -4843,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 */
@@ -4872,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);
                        }
                }
 
@@ -4880,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)
@@ -4934,13 +4950,6 @@ static void add_group_render_dupli_obs(Render *re, Group *group, int nolamps, in
        }
 }
 
-/* additional data for dupli objects outside
- * of the main dupli list
- */
-typedef struct DupliObjectExtra {
-       float omat[4][4];
-} DupliObjectExtra;
-
 static void database_init_objects(Render *re, unsigned int renderlay, int nolamps, int onlyselected, Object *actob, int timeoffset)
 {
        Base *base;
@@ -4983,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 (is_object_hidden(re, ob)) 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) {
@@ -5000,28 +5009,24 @@ static void database_init_objects(Render *re, unsigned int renderlay, int nolamp
                        if ((ob->transflag & OB_DUPLI) && (ob->type!=OB_MBALL)) {
                                DupliObject *dob;
                                ListBase *duplilist;
-                               DupliObjectExtra *duplilist_extra = NULL;
-                               int totdob, i;
+                               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);
                                duplilist = object_duplilist(re->eval_ctx, re->scene, ob);
-                               totdob = BLI_countlist(duplilist);
-                               if (totdob > 0)
-                                       duplilist_extra = MEM_mallocN(sizeof(DupliObjectExtra) * totdob, "DupliObject extra data");
-                               dupli_render_particle_set(re, ob, timeoffset, 0, 0);
-
-                               /* set dupli obmats */
-                               for (dob= duplilist->first, i = 0; dob; dob= dob->next, ++i) {
-                                       copy_m4_m4(duplilist_extra[i].omat, dob->ob->obmat);
-                                       copy_m4_m4(dob->ob->obmat, dob->mat);
-                               }
+                               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) {
-                                       DupliObjectExtra *dob_extra = &duplilist_extra[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;
@@ -5035,8 +5040,6 @@ static void database_init_objects(Render *re, unsigned int renderlay, int nolamp
                                        if (!allow_render_object(re, obd, nolamps, onlyselected, actob))
                                                continue;
 
-                                       copy_m4_m4(obd->obmat, dob->mat);
-
                                        if (allow_render_dupli_instance(re, dob, obd)) {
                                                ParticleSystem *psys;
                                                ObjectRen *obr = NULL;
@@ -5051,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, dob_extra->omat);
+                                                       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];
@@ -5078,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, dob_extra->omat);
+                                                               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];
@@ -5096,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, dob_extra->omat, timeoffset);
+                                                       init_render_object(re, obd, ob, dob, dob_extra->obmat, timeoffset);
                                                
                                                if (dob->type != OB_DUPLIGROUP) {
                                                        obd->flag |= OB_DONE;
@@ -5104,22 +5107,19 @@ static void database_init_objects(Render *re, unsigned int renderlay, int nolamp
                                                }
                                        }
                                        else
-                                               init_render_object(re, obd, ob, dob, dob_extra->omat, timeoffset);
+                                               init_render_object(re, obd, ob, dob, dob_extra->obmat, timeoffset);
                                        
                                        if (re->test_break(re->tbh)) break;
                                }
-                               
-                               /* restore obmats
-                                * NOTE: this has to happen in reverse order, since nested
-                                * dupli objects can repeatedly override the obmat
-                                */
-                               for (dob= duplilist->last, i = totdob - 1; dob; dob= dob->prev, --i) {
-                                       copy_m4_m4(dob->ob->obmat, duplilist_extra[i].omat);
+
+                               /* 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 (duplilist_extra)
-                                       MEM_freeN(duplilist_extra);
 
                                if (allow_render_object(re, ob, nolamps, onlyselected, actob))
                                        init_render_object(re, ob, NULL, NULL, NULL, timeoffset);
@@ -5169,8 +5169,7 @@ 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 */
        
        /* in localview, lamps are using normal layers, objects only local bits */
@@ -5178,8 +5177,10 @@ void RE_Database_FromScene(Render *re, Main *bmain, Scene *scene, unsigned int l
                lay &= 0xFF000000;
        
        /* applies changes fully */
-       if ((re->r.scemode & (R_NO_FRAME_UPDATE|R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))==0)
+       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) {
@@ -5187,8 +5188,7 @@ 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);
 
@@ -5211,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 */
@@ -5230,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)
@@ -5271,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))
@@ -5349,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)
@@ -5362,7 +5358,8 @@ static void database_fromscene_vectors(Render *re, Scene *scene, unsigned int la
        
        /* 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);
        }
@@ -5371,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;
@@ -5469,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;
@@ -5508,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)
@@ -5575,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];
@@ -5864,8 +5861,8 @@ 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= !ELEM5(type, RE_BAKE_LIGHT, RE_BAKE_ALL, RE_BAKE_SHADOW, RE_BAKE_AO, RE_BAKE_VERTEX_COLORS);
-       const short nolamps= ELEM5(type, RE_BAKE_NORMALS, RE_BAKE_TEXTURE, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE, RE_BAKE_VERTEX_COLORS);
+       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;
@@ -5873,9 +5870,11 @@ void RE_Database_Baking(Render *re, Main *bmain, Scene *scene, unsigned int lay,
 
        /* renderdata setup and exceptions */
        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;
@@ -5889,7 +5888,7 @@ void RE_Database_Baking(Render *re, Main *bmain, Scene *scene, unsigned int lay,
        if (type==RE_BAKE_VERTEX_COLORS)
                re->flag |=  R_NEED_VCOL;
 
-       if (!actob && ELEM6(type, RE_BAKE_LIGHT, RE_BAKE_NORMALS, RE_BAKE_TEXTURE, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE, RE_BAKE_VERTEX_COLORS)) {
+       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;
        }
@@ -5943,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);