svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r22668:22701
[blender.git] / source / blender / render / intern / source / shadeoutput.c
index af1f179d8d3b936e3dfb37faf1934492fe86d284..d5c8cf30b3000ec13466bd393144198012f1c701 100644 (file)
  */
 
 #include <stdio.h>
+#include <float.h>
 #include <math.h>
 #include <string.h>
 
 #include "MTC_matrixops.h"
 #include "BLI_arithb.h"
 
+#include "BKE_colortools.h"
 #include "BKE_material.h"
 #include "BKE_texture.h"
 #include "BKE_utildefines.h"
 #include "DNA_material_types.h"
 
 /* local include */
+#include "occlusion.h"
 #include "renderpipeline.h"
 #include "render_types.h"
 #include "pixelblending.h"
 #include "rendercore.h"
 #include "shadbuf.h"
+#include "sss.h"
 #include "texture.h"
 
 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
@@ -57,12 +61,14 @@ extern struct Render R;
 static ListBase *get_lights(ShadeInput *shi)
 {
        
+       if(R.r.scemode & R_PREVIEWBUTS)
+               return &R.lights;
        if(shi->light_override)
                return &shi->light_override->gobject;
-       else if(shi->mat && shi->mat->group)
+       if(shi->mat && shi->mat->group)
                return &shi->mat->group->gobject;
-       else
-               return &R.lights;
+       
+       return &R.lights;
 }
 
 #if 0
@@ -164,6 +170,9 @@ static void spothalo(struct LampRen *lar, ShadeInput *shi, float *intens)
                p1[2]= -lar->co[2];
                MTC_Mat3MulVecfl(lar->imat, p1);
                VECCOPY(npos, p1);      // npos is double!
+               
+               /* pre-scale */
+               npos[2]*= lar->sh_zfac;
        }
        else {
                VECCOPY(npos, lar->sh_invcampos);       /* in initlamp calculated */
@@ -193,7 +202,7 @@ static void spothalo(struct LampRen *lar, ShadeInput *shi, float *intens)
                maxz*= lar->sh_zfac;
                maxy= lar->imat[0][1]*p1[0]+lar->imat[1][1]*p1[1]+lar->imat[2][1]*p1[2];
 
-               if( fabs(nray[2]) <0.000001f ) use_yco= 1;
+               if( fabs(nray[2]) < DBL_EPSILON ) use_yco= 1;
        }
        
        /* scale z to make sure volume is normalized */ 
@@ -208,7 +217,7 @@ static void spothalo(struct LampRen *lar, ShadeInput *shi, float *intens)
        c = npos[0] * npos[0] + npos[1] * npos[1] - npos[2]*npos[2];
 
        snijp= 0;
-       if (fabs(a) < 0.00000001) {
+       if (fabs(a) < DBL_EPSILON) {
                /*
                 * Only one intersection point...
                 */
@@ -333,19 +342,26 @@ static void spothalo(struct LampRen *lar, ShadeInput *shi, float *intens)
 
 void renderspothalo(ShadeInput *shi, float *col, float alpha)
 {
-       ListBase *lights= get_lights(shi);
+       ListBase *lights;
        GroupObject *go;
        LampRen *lar;
        float i;
        
        if(alpha==0.0f) return;
        
+       lights= get_lights(shi);
        for(go=lights->first; go; go= go->next) {
                lar= go->lampren;
+               if(lar==NULL) continue;
                
                if(lar->type==LA_SPOT && (lar->mode & LA_HALO) && lar->haint>0) {
-                       if((lar->lay & shi->lay)==0) continue;
-
+                       
+                       if(lar->mode & LA_LAYER) 
+                               if(shi->vlr && (lar->lay & shi->obi->lay)==0) 
+                                       continue;
+                       if((lar->lay & shi->lay)==0) 
+                               continue;
+                       
                        spothalo(lar, shi, &i);
                        if(i>0.0f) {
                                col[3]+= i*alpha;                       // all premul
@@ -363,7 +379,7 @@ void renderspothalo(ShadeInput *shi, float *col, float alpha)
 
 /* ---------------- shaders ----------------------- */
 
-static double Normalise_d(double *n)
+static double Normalize_d(double *n)
 {
        double d;
        
@@ -408,22 +424,22 @@ static double saacos_d(double fac)
 }
 
 /* Stoke's form factor. Need doubles here for extreme small area sizes */
-static float area_lamp_energy(float *co, float *vn, LampRen *lar)
+static float area_lamp_energy(float (*area)[3], float *co, float *vn)
 {
        double fac;
        double vec[4][3];       /* vectors of rendered co to vertices lamp */
        double cross[4][3];     /* cross products of this */
        double rad[4];          /* angles between vecs */
 
-       VECSUB(vec[0], co, lar->area[0]);
-       VECSUB(vec[1], co, lar->area[1]);
-       VECSUB(vec[2], co, lar->area[2]);
-       VECSUB(vec[3], co, lar->area[3]);
+       VECSUB(vec[0], co, area[0]);
+       VECSUB(vec[1], co, area[1]);
+       VECSUB(vec[2], co, area[2]);
+       VECSUB(vec[3], co, area[3]);
        
-       Normalise_d(vec[0]);
-       Normalise_d(vec[1]);
-       Normalise_d(vec[2]);
-       Normalise_d(vec[3]);
+       Normalize_d(vec[0]);
+       Normalize_d(vec[1]);
+       Normalize_d(vec[2]);
+       Normalize_d(vec[3]);
 
        /* cross product */
        CROSS(cross[0], vec[0], vec[1]);
@@ -431,10 +447,10 @@ static float area_lamp_energy(float *co, float *vn, LampRen *lar)
        CROSS(cross[2], vec[2], vec[3]);
        CROSS(cross[3], vec[3], vec[0]);
 
-       Normalise_d(cross[0]);
-       Normalise_d(cross[1]);
-       Normalise_d(cross[2]);
-       Normalise_d(cross[3]);
+       Normalize_d(cross[0]);
+       Normalize_d(cross[1]);
+       Normalize_d(cross[2]);
+       Normalize_d(cross[3]);
 
        /* angles */
        rad[0]= vec[0][0]*vec[1][0]+ vec[0][1]*vec[1][1]+ vec[0][2]*vec[1][2];
@@ -454,7 +470,39 @@ static float area_lamp_energy(float *co, float *vn, LampRen *lar)
        fac+= rad[3]*(vn[0]*cross[3][0]+ vn[1]*cross[3][1]+ vn[2]*cross[3][2]);
 
        if(fac<=0.0) return 0.0;
-       return pow(fac*lar->areasize, lar->k);  // corrected for buttons size and lar->dist^2
+       return fac;
+}
+
+static float area_lamp_energy_multisample(LampRen *lar, float *co, float *vn)
+{
+       /* corner vectors are moved around according lamp jitter */
+       float *jitlamp= lar->jitter, vec[3];
+       float area[4][3], intens= 0.0f;
+       int a= lar->ray_totsamp;
+
+       /* test if co is behind lamp */
+       VECSUB(vec, co, lar->co);
+       if(INPR(vec, lar->vec) < 0.0f)
+               return 0.0f;
+
+       while(a--) {
+               vec[0]= jitlamp[0];
+               vec[1]= jitlamp[1];
+               vec[2]= 0.0f;
+               Mat3MulVecfl(lar->mat, vec);
+               
+               VECADD(area[0], lar->area[0], vec);
+               VECADD(area[1], lar->area[1], vec);
+               VECADD(area[2], lar->area[2], vec);
+               VECADD(area[3], lar->area[3], vec);
+               
+               intens+= area_lamp_energy(area, co, vn);
+               
+               jitlamp+= 2;
+       }
+       intens /= (float)lar->ray_totsamp;
+       
+       return pow(intens*lar->areasize, lar->k);       // corrected for buttons size and lar->dist^2
 }
 
 static float spec(float inp, int hard) 
@@ -505,7 +553,7 @@ static float Phong_Spec( float *n, float *l, float *v, int hard, int tangent )
        h[0] = l[0] + v[0];
        h[1] = l[1] + v[1];
        h[2] = l[2] + v[2];
-       Normalise(h);
+       Normalize(h);
        
        rslt = h[0]*n[0] + h[1]*n[1] + h[2]*n[2];
        if(tangent) rslt= sasqrt(1.0f - rslt*rslt);
@@ -525,7 +573,7 @@ static float CookTorr_Spec(float *n, float *l, float *v, int hard, int tangent)
        h[0]= v[0]+l[0];
        h[1]= v[1]+l[1];
        h[2]= v[2]+l[2];
-       Normalise(h);
+       Normalize(h);
 
        nh= n[0]*h[0]+n[1]*h[1]+n[2]*h[2];
        if(tangent) nh= sasqrt(1.0f - nh*nh);
@@ -558,7 +606,7 @@ static float Blinn_Spec(float *n, float *l, float *v, float refrac, float spec_p
        h[0]= v[0]+l[0];
        h[1]= v[1]+l[1];
        h[2]= v[2]+l[2];
-       Normalise(h);
+       Normalize(h);
 
        nh= n[0]*h[0]+n[1]*h[1]+n[2]*h[2]; /* Dot product between surface normal and half-way vector */
        if(tangent) nh= sasqrt(1.0f - nh*nh);
@@ -605,7 +653,7 @@ static float Toon_Spec( float *n, float *l, float *v, float size, float smooth,
        h[0] = l[0] + v[0];
        h[1] = l[1] + v[1];
        h[2] = l[2] + v[2];
-       Normalise(h);
+       Normalize(h);
        
        rslt = h[0]*n[0] + h[1]*n[1] + h[2]*n[2];
        if(tangent) rslt = sasqrt(1.0f - rslt*rslt);
@@ -629,7 +677,7 @@ static float WardIso_Spec( float *n, float *l, float *v, float rms, int tangent)
        h[0] = l[0] + v[0];
        h[1] = l[1] + v[1];
        h[2] = l[2] + v[2];
-       Normalise(h);
+       Normalize(h);
 
        nh = n[0]*h[0]+n[1]*h[1]+n[2]*h[2]; /* Dot product between surface normal and half-way vector */
        if(tangent) nh = sasqrt(1.0f - nh*nh);
@@ -680,7 +728,7 @@ static float OrenNayar_Diff(float nl, float *n, float *l, float *v, float rough
        h[0]= v[0]+l[0];
        h[1]= v[1]+l[1];
        h[2]= v[2]+l[2];
-       Normalise(h);
+       Normalize(h);
        
        nh= n[0]*h[0]+n[1]*h[1]+n[2]*h[2]; /* Dot product between surface normal and half-way vector */
        if(nh<0.0f) nh = 0.0f;
@@ -701,12 +749,12 @@ static float OrenNayar_Diff(float nl, float *n, float *l, float *v, float rough
        Lit_B[0] = l[0] - (realnl * n[0]);
        Lit_B[1] = l[1] - (realnl * n[1]);
        Lit_B[2] = l[2] - (realnl * n[2]);
-       Normalise( Lit_B );
+       Normalize( Lit_B );
        
        View_B[0] = v[0] - (nv * n[0]);
        View_B[1] = v[1] - (nv * n[1]);
        View_B[2] = v[2] - (nv * n[2]);
-       Normalise( View_B );
+       Normalize( View_B );
        
        t = Lit_B[0]*View_B[0] + Lit_B[1]*View_B[1] + Lit_B[2]*View_B[2];
        if( t < 0 ) t = 0;
@@ -816,16 +864,12 @@ void shade_color(ShadeInput *shi, ShadeResult *shr)
                shi->r= shi->vcol[0];
                shi->g= shi->vcol[1];
                shi->b= shi->vcol[2];
+               if(ma->mode & (MA_FACETEXTURE_ALPHA))
+                       shi->alpha= shi->vcol[3];
        }
        
-       if(ma->texco) {
-               if(ma->mode & (MA_VERTEXCOLP|MA_FACETEXTURE)) {
-                       shi->r= shi->vcol[0];
-                       shi->g= shi->vcol[1];
-                       shi->b= shi->vcol[2];
-               }
+       if(ma->texco)
                do_material_tex(shi);
-       }
 
        if(ma->fresnel_tra!=0.0f) 
                shi->alpha*= fresnel_fac(shi->view, shi->vn, ma->fresnel_tra_i, ma->fresnel_tra);
@@ -963,10 +1007,12 @@ static void do_specular_ramp(ShadeInput *shi, float is, float t, float *spec)
 }
 
 /* pure AO, check for raytrace and world should have been done */
+/* preprocess, textures were not done, don't use shi->amb for that reason */
 void ambient_occlusion(ShadeInput *shi)
 {
-       
-       if((R.r.mode & R_RAYTRACE) && shi->mat->amb!=0.0f)
+       if((R.wrld.ao_gather_method == WO_AOGATHER_APPROX) && shi->mat->amb!=0.0f)
+               sample_occ(&R, shi);
+       else if((R.r.mode & R_RAYTRACE) && shi->mat->amb!=0.0f)
                ray_ao(shi, shi->ao);
        else
                shi->ao[0]= shi->ao[1]= shi->ao[2]= 1.0f;
@@ -976,25 +1022,28 @@ void ambient_occlusion(ShadeInput *shi)
 /* wrld mode was checked for */
 void ambient_occlusion_to_diffuse(ShadeInput *shi, float *diff)
 {
-       
-       if((R.r.mode & R_RAYTRACE) && shi->mat->amb!=0.0f) {
-               float f= R.wrld.aoenergy*shi->mat->amb;
-
-               if (R.wrld.aomix==WO_AOADDSUB) {
-                       diff[0] = 2.0f*shi->ao[0]-1.0f;
-                       diff[1] = 2.0f*shi->ao[1]-1.0f;
-                       diff[2] = 2.0f*shi->ao[2]-1.0f;
-               }
-               else if (R.wrld.aomix==WO_AOSUB) {
-                       diff[0] = shi->ao[0]-1.0f;
-                       diff[1] = shi->ao[1]-1.0f;
-                       diff[2] = shi->ao[2]-1.0f;
-               }
-               else {
-                       VECCOPY(diff, shi->ao);
+       if((R.r.mode & R_RAYTRACE) || R.wrld.ao_gather_method == WO_AOGATHER_APPROX) {
+               if(shi->amb!=0.0f) {
+                       float f= R.wrld.aoenergy*shi->amb;
+
+                       if (R.wrld.aomix==WO_AOADDSUB) {
+                               diff[0] = 2.0f*shi->ao[0]-1.0f;
+                               diff[1] = 2.0f*shi->ao[1]-1.0f;
+                               diff[2] = 2.0f*shi->ao[2]-1.0f;
+                       }
+                       else if (R.wrld.aomix==WO_AOSUB) {
+                               diff[0] = shi->ao[0]-1.0f;
+                               diff[1] = shi->ao[1]-1.0f;
+                               diff[2] = shi->ao[2]-1.0f;
+                       }
+                       else {
+                               VECCOPY(diff, shi->ao);
+                       }
+                       
+                       VECMUL(diff, f);
                }
-               
-               VECMUL(diff, f);
+               else
+                       diff[0]= diff[1]= diff[2]= 0.0f;
        }
        else
                diff[0]= diff[1]= diff[2]= 0.0f;
@@ -1013,14 +1062,16 @@ void lamp_get_shadow(LampRen *lar, ShadeInput *shi, float inp, float *shadfac, i
                        if(lar->buftype==LA_SHADBUF_IRREGULAR)
                                shadfac[3]= ISB_getshadow(shi, lar->shb);
                        else
-                               shadfac[3] = testshadowbuf(lar->shb, shi->co, shi->dxco, shi->dyco, inp);
+                               shadfac[3] = testshadowbuf(&R, lar->shb, shi->co, shi->dxco, shi->dyco, inp, shi->mat->lbias);
                }
                else if(lar->mode & LA_SHAD_RAY) {
                        ray_shadow(shi, lar, shadfac);
                }
                
-               QUATCOPY(lss->shadfac, shadfac);
-               lss->samplenr= shi->samplenr;
+               if(shi->depth==0) {
+                       QUATCOPY(lss->shadfac, shadfac);
+                       lss->samplenr= shi->samplenr;
+               }
        }
        else {
                QUATCOPY(shadfac, lss->shadfac);
@@ -1046,20 +1097,32 @@ float lamp_get_visibility(LampRen *lar, float *co, float *lv, float *dist)
                /* area type has no quad or sphere option */
                if(lar->type==LA_AREA) {
                        /* area is single sided */
-                       if(INPR(lv, lar->vec) > 0.0f)
-                               visifac= 1.0f;
-                       else
-                               visifac= 0.0f;
+                       //if(INPR(lv, lar->vec) > 0.0f)
+                       //      visifac= 1.0f;
+                       //else
+                       //      visifac= 0.0f;
                }
                else {
-                       if(lar->mode & LA_QUAD) {
-                               if(lar->ld1>0.0f)
-                                       visifac= lar->dist/(lar->dist+lar->ld1*dist[0]);
-                               if(lar->ld2>0.0f)
-                                       visifac*= lar->distkw/(lar->distkw+lar->ld2*dist[0]*dist[0]);
-                       }
-                       else {
-                               visifac= (lar->dist/(lar->dist+dist[0]));
+                       switch(lar->falloff_type)
+                       {
+                               case LA_FALLOFF_CONSTANT:
+                                       visifac = 1.0f;
+                                       break;
+                               case LA_FALLOFF_INVLINEAR:
+                                       visifac = lar->dist/(lar->dist + dist[0]);
+                                       break;
+                               case LA_FALLOFF_INVSQUARE:
+                                       visifac = lar->dist / (lar->dist + dist[0]*dist[0]);
+                                       break;
+                               case LA_FALLOFF_SLIDERS:
+                                       if(lar->ld1>0.0f)
+                                               visifac= lar->dist/(lar->dist+lar->ld1*dist[0]);
+                                       if(lar->ld2>0.0f)
+                                               visifac*= lar->distkw/(lar->distkw+lar->ld2*dist[0]*dist[0]);
+                                       break;
+                               case LA_FALLOFF_CURVE:
+                                       visifac = curvemapping_evaluateF(lar->curfalloff, 0, dist[0]/lar->dist);
+                                       break;
                        }
                        
                        if(lar->mode & LA_SPHERE) {
@@ -1109,6 +1172,7 @@ float lamp_get_visibility(LampRen *lar, float *co, float *lv, float *dist)
                                }
                        }
                }
+               if (visifac <= 0.001) visifac = 0.0f;
                return visifac;
        }
 }
@@ -1118,13 +1182,22 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
 {
        Material *ma= shi->mat;
        VlakRen *vlr= shi->vlr;
-       float lv[3], lampdist, lacol[3], shadfac[4];
+       float lv[3], lampdist, lacol[3], shadfac[4], lashdw[3];
        float i, is, i_noshad, inp, *vn, *view, vnor[3], phongcorr=1.0f;
        float visifac;
        
        vn= shi->vn;
        view= shi->view;
        
+       
+       if (lar->energy == 0.0) return;
+       /* only shadow lamps shouldn't affect shadow-less materials at all */
+       if ((lar->mode & LA_ONLYSHADOW) && (!(ma->mode & MA_SHADOW) || !(R.r.mode & R_SHADOW)))
+               return;
+       /* optimisation, don't render fully black lamps */
+       if (!(lar->mode & LA_TEXTURE) && (lar->r + lar->g + lar->b == 0.0f))
+               return;
+       
        /* lampdist, spot angle, area side, ... */
        visifac= lamp_get_visibility(lar, shi->co, lv, &lampdist);
        if(visifac==0.0f)
@@ -1149,14 +1222,43 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
        lacol[1]= lar->g;
        lacol[2]= lar->b;
        
-       if(lar->mode & LA_TEXTURE)  do_lamp_tex(lar, lv, shi, lacol);
+       lashdw[0]= lar->shdwr;
+       lashdw[1]= lar->shdwg;
+       lashdw[2]= lar->shdwb;
        
-       /* tangent case; calculate fake face normal, aligned with lampvector */ 
-       /* note, vnor==vn is used as tangent trigger for buffer shadow */
+       if(lar->mode & LA_TEXTURE)      do_lamp_tex(lar, lv, shi, lacol, LA_TEXTURE);
+       if(lar->mode & LA_SHAD_TEX)     do_lamp_tex(lar, lv, shi, lashdw, LA_SHAD_TEX);
+
+               /* tangent case; calculate fake face normal, aligned with lampvector */ 
+               /* note, vnor==vn is used as tangent trigger for buffer shadow */
        if(vlr->flag & R_TANGENT) {
-               float cross[3];
-               Crossf(cross, lv, vn);
-               Crossf(vnor, cross, vn);
+               float cross[3], nstrand[3], blend;
+
+               if(ma->mode & MA_STR_SURFDIFF) {
+                       Crossf(cross, shi->surfnor, vn);
+                       Crossf(nstrand, vn, cross);
+
+                       blend= INPR(nstrand, shi->surfnor);
+                       blend= 1.0f - blend;
+                       CLAMP(blend, 0.0f, 1.0f);
+
+                       VecLerpf(vnor, nstrand, shi->surfnor, blend);
+                       Normalize(vnor);
+               }
+               else {
+                       Crossf(cross, lv, vn);
+                       Crossf(vnor, cross, vn);
+                       Normalize(vnor);
+               }
+
+               if(ma->strand_surfnor > 0.0f) {
+                       if(ma->strand_surfnor > shi->surfdist) {
+                               blend= (ma->strand_surfnor - shi->surfdist)/ma->strand_surfnor;
+                               VecLerpf(vnor, vnor, shi->surfnor, blend);
+                               Normalize(vnor);
+                       }
+               }
+
                vnor[0]= -vnor[0];vnor[1]= -vnor[1];vnor[2]= -vnor[2];
                vn= vnor;
        }
@@ -1164,6 +1266,7 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
                float cross[3];
                Crossf(cross, lv, shi->tang);
                Crossf(vnor, cross, shi->tang);
+               Normalize(vnor);
                vnor[0]= -vnor[0];vnor[1]= -vnor[1];vnor[2]= -vnor[2];
                vn= vnor;
        }
@@ -1176,9 +1279,9 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
        /* this complex construction screams for a nicer implementation! (ton) */
        if(R.r.mode & R_SHADOW) {
                if(ma->mode & MA_SHADOW) {
-                       if(lar->type==LA_HEMI);
+                       if(lar->type==LA_HEMI || lar->type==LA_AREA);
                        else if((ma->mode & MA_RAYBIAS) && (lar->mode & LA_SHAD_RAY) && (vlr->flag & R_SMOOTH)) {
-                               float thresh= vlr->ob->smoothresh;
+                               float thresh= shi->obr->ob->smoothresh;
                                if(inp>thresh)
                                        phongcorr= (inp-thresh)/(inp*(1.0f-thresh));
                                else
@@ -1203,7 +1306,7 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
        else {
                
                if(lar->type==LA_AREA)
-                       inp= area_lamp_energy(shi->co, vn, lar);
+                       inp= area_lamp_energy_multisample(lar, shi->co, vn);
                
                /* diffuse shaders (oren nayer gets inp from area light) */
                if(ma->diff_shader==MA_DIFF_ORENNAYAR) is= OrenNayar_Diff(inp, vn, lv, view, ma->roughness);
@@ -1213,7 +1316,10 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
                else is= inp;   // Lambert
        }
        
-       /* i is diffuse */
+       /* 'is' is diffuse */
+       if((ma->shade_flag & MA_CUBIC) && is>0.0f && is<1.0f)
+               is= 3.0*is*is - 2.0*is*is*is;   // nicer termination of shades
+
        i= is*phongcorr;
        
        if(i>0.0f) {
@@ -1231,7 +1337,7 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
        /* shadow and spec, (visifac==0 outside spot) */
        if(visifac> 0.0f) {
                
-               if(i>0.0f && (R.r.mode & R_SHADOW)) {
+               if((R.r.mode & R_SHADOW)) {
                        if(ma->mode & MA_SHADOW) {
                                if(lar->shb || (lar->mode & LA_SHAD_RAY)) {
                                        
@@ -1241,12 +1347,17 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
                                                lamp_get_shadow(lar, shi, inp, shadfac, shi->depth);
                                                
                                        /* warning, here it skips the loop */
-                                       if(lar->mode & LA_ONLYSHADOW) {
+                                       if((lar->mode & LA_ONLYSHADOW) && i>0.0) {
                                                
                                                shadfac[3]= i*lar->energy*(1.0f-shadfac[3]);
-                                               shr->shad[0] -= shadfac[3]*shi->r;
-                                               shr->shad[1] -= shadfac[3]*shi->g;
-                                               shr->shad[2] -= shadfac[3]*shi->b;
+                                               shr->shad[0] -= shadfac[3]*shi->r*(1.0f-lashdw[0]);
+                                               shr->shad[1] -= shadfac[3]*shi->g*(1.0f-lashdw[1]);
+                                               shr->shad[2] -= shadfac[3]*shi->b*(1.0f-lashdw[2]);
+                                               
+                                               shr->spec[0] -= shadfac[3]*shi->specr*(1.0f-lashdw[0]);
+                                               shr->spec[1] -= shadfac[3]*shi->specg*(1.0f-lashdw[1]);
+                                               shr->spec[2] -= shadfac[3]*shi->specb*(1.0f-lashdw[2]);
+                                               
                                                return;
                                        }
                                        
@@ -1255,7 +1366,7 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
                        }
                }
                
-               /* in case 'no diffuse' we still do most calculus, spec can be in shadow */
+               /* in case 'no diffuse' we still do most calculus, spec can be in shadow.*/
                if(!(lar->mode & LA_NO_DIFF)) {
                        if(i>0.0f) {
                                if(ma->mode & MA_SHADOW_TRA)
@@ -1263,6 +1374,10 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
                                else
                                        add_to_diffuse(shr->shad, shi, is, i*lacol[0], i*lacol[1], i*lacol[2]);
                        }
+                       /* add light for colored shadow */
+                       if (i_noshad>i && !(lashdw[0]==0 && lashdw[1]==0 && lashdw[2]==0)) {
+                               add_to_diffuse(shr->shad, shi, is, lashdw[0]*(i_noshad-i)*lacol[0], lashdw[1]*(i_noshad-i)*lacol[1], lashdw[2]*(i_noshad-i)*lacol[2]);
+                       }
                        if(i_noshad>0.0f) {
                                if(passflag & (SCE_PASS_DIFFUSE|SCE_PASS_SHADOW)) {
                                        if(ma->mode & MA_SHADOW_TRA)
@@ -1276,7 +1391,9 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
                }
                
                /* specularity */
-               if(shadfac[3]>0.0f && shi->spec!=0.0f && !(lar->mode & LA_NO_SPEC)) {
+               shadfac[3]*= phongcorr; /* note, shadfac not allowed to be stored nonlocal */
+               
+               if(shadfac[3]>0.0f && shi->spec!=0.0f && !(lar->mode & LA_NO_SPEC) && !(lar->mode & LA_ONLYSHADOW)) {
                        
                        if(!(passflag & (SCE_PASS_COMBINED|SCE_PASS_SPEC)));
                        else if(lar->type==LA_HEMI) {
@@ -1287,7 +1404,7 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
                                lv[1]+= view[1];
                                lv[2]+= view[2];
                                
-                               Normalise(lv);
+                               Normalize(lv);
                                
                                t= vn[0]*lv[0]+vn[1]*lv[1]+vn[2]*lv[2];
                                
@@ -1342,18 +1459,19 @@ static void shade_lamp_loop_only_shadow(ShadeInput *shi, ShadeResult *shr)
 {
        
        if(R.r.mode & R_SHADOW) {
-               ListBase *lights= get_lights(shi);
+               ListBase *lights;
                LampRen *lar;
                GroupObject *go;
                float inpr, lv[3];
-               float *vn, *view, shadfac[4];
+               float *view, shadfac[4];
                float ir, accum, visifac, lampdist;
                
-               vn= shi->vn;
+
                view= shi->view;
 
                accum= ir= 0.0f;
                
+               lights= get_lights(shi);
                for(go=lights->first; go; go= go->next) {
                        lar= go->lampren;
                        if(lar==NULL) continue;
@@ -1361,35 +1479,42 @@ static void shade_lamp_loop_only_shadow(ShadeInput *shi, ShadeResult *shr)
                        /* yafray: ignore shading by photonlights, not used in Blender */
                        if (lar->type==LA_YF_PHOTON) continue;
                        
-                       if(lar->mode & LA_LAYER) if((lar->lay & shi->vlr->lay)==0) continue;
+                       if(lar->mode & LA_LAYER) if((lar->lay & shi->obi->lay)==0) continue;
                        if((lar->lay & shi->lay)==0) continue;
                        
                        if(lar->shb || (lar->mode & LA_SHAD_RAY)) {
                                visifac= lamp_get_visibility(lar, shi->co, lv, &lampdist);
-                               if(visifac < 0.0f)
+                               if(visifac <= 0.0f) {
+                                       ir+= 1.0f;
+                                       accum+= 1.0f;
                                        continue;
-                               
+                               }
                                inpr= INPR(shi->vn, lv);
-                               if(inpr <= 0.0f)
+                               if(inpr <= 0.0f) {
+                                       ir+= 1.0f;
+                                       accum+= 1.0f;
                                        continue;
-                               
+                               }                               
                                lamp_get_shadow(lar, shi, inpr, shadfac, shi->depth);
+
                                ir+= 1.0f;
-                               accum+= shadfac[3];
+                               accum+= (1.0f-visifac) + (visifac)*shadfac[3];
                        }
                }
                if(ir>0.0f) {
                        accum/= ir;
-                       shr->alpha= (shi->alpha)*(1.0f-accum);
+                       shr->alpha= (shi->mat->alpha)*(1.0f-accum);
                }
+               else shr->alpha= shi->mat->alpha;
        }
        
+       /* quite disputable this...  also note it doesn't mirror-raytrace */    
        if((R.wrld.mode & WO_AMB_OCC) && shi->amb!=0.0f) {
                float f;
                
-               f= shi->ao[0];
+               f= 1.0f - shi->ao[0];
+               f= R.wrld.aoenergy*f*shi->amb;
                
-               /* quite disputable this...  also note it doesn't mirror-raytrace */
                if(R.wrld.aomix==WO_AOADD) {
                        shr->alpha += f;
                        shr->alpha *= f;
@@ -1404,8 +1529,10 @@ static void shade_lamp_loop_only_shadow(ShadeInput *shi, ShadeResult *shr)
        }
 }
 
+/* let's map negative light as if it mirrors positive light, otherwise negative values disappear */
 static void wrld_exposure_correct(float *diff)
 {
+       
        diff[0]= R.wrld.linfac*(1.0f-exp( diff[0]*R.wrld.logfac) );
        diff[1]= R.wrld.linfac*(1.0f-exp( diff[1]*R.wrld.logfac) );
        diff[2]= R.wrld.linfac*(1.0f-exp( diff[2]*R.wrld.logfac) );
@@ -1414,7 +1541,6 @@ static void wrld_exposure_correct(float *diff)
 void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
 {
        Material *ma= shi->mat;
-       VlakRen *vlr= shi->vlr;
        int passflag= shi->passflag;
        
        memset(shr, 0, sizeof(ShadeResult));
@@ -1434,6 +1560,8 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
                        shi->r= shi->vcol[0];
                        shi->g= shi->vcol[1];
                        shi->b= shi->vcol[2];
+                       if(ma->mode & (MA_FACETEXTURE_ALPHA))
+                               shi->alpha= shi->vcol[3];
                }
                if(ma->texco)
                        do_material_tex(shi);
@@ -1442,6 +1570,24 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
                shr->col[1]= shi->g*shi->alpha;
                shr->col[2]= shi->b*shi->alpha;
                shr->col[3]= shi->alpha;
+
+               if((ma->sss_flag & MA_DIFF_SSS) && !sss_pass_done(&R, ma)) {
+                       if(ma->sss_texfac == 0.0f) {
+                               shi->r= shi->g= shi->b= shi->alpha= 1.0f;
+                               shr->col[0]= shr->col[1]= shr->col[2]= shr->col[3]= 1.0f;
+                       }
+                       else {
+                               shi->r= pow(shi->r, ma->sss_texfac);
+                               shi->g= pow(shi->g, ma->sss_texfac);
+                               shi->b= pow(shi->b, ma->sss_texfac);
+                               shi->alpha= pow(shi->alpha, ma->sss_texfac);
+                               
+                               shr->col[0]= pow(shr->col[0], ma->sss_texfac);
+                               shr->col[1]= pow(shr->col[1], ma->sss_texfac);
+                               shr->col[2]= pow(shr->col[2], ma->sss_texfac);
+                               shr->col[3]= pow(shr->col[3], ma->sss_texfac);
+                       }
+               }
        }
        
        if(ma->mode & MA_SHLESS) {
@@ -1466,7 +1612,8 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
        
        /* AO pass */
        if(R.wrld.mode & WO_AMB_OCC) {
-               if(passflag & (SCE_PASS_COMBINED|SCE_PASS_AO)) {
+               if(((passflag & SCE_PASS_COMBINED) && (shi->combinedflag & SCE_PASS_AO))
+                       || (passflag & SCE_PASS_AO)) {
                        /* AO was calculated for scanline already */
                        if(shi->depth)
                                ambient_occlusion(shi);
@@ -1477,9 +1624,10 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
        /* lighting pass */
        if(passflag & (SCE_PASS_COMBINED|SCE_PASS_DIFFUSE|SCE_PASS_SPEC|SCE_PASS_SHADOW)) {
                GroupObject *go;
-               ListBase *lights= get_lights(shi);
+               ListBase *lights;
                LampRen *lar;
                
+               lights= get_lights(shi);
                for(go=lights->first; go; go= go->next) {
                        lar= go->lampren;
                        if(lar==NULL) continue;
@@ -1488,12 +1636,57 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
                        if (lar->type==LA_YF_PHOTON) continue;
                        
                        /* test for lamp layer */
-                       if(lar->mode & LA_LAYER) if((lar->lay & vlr->lay)==0) continue;
+                       if(lar->mode & LA_LAYER) if((lar->lay & shi->obi->lay)==0) continue;
                        if((lar->lay & shi->lay)==0) continue;
-
+                       
                        /* accumulates in shr->diff and shr->spec and shr->shad (diffuse with shadow!) */
                        shade_one_light(lar, shi, shr, passflag);
                }
+
+               /*this check is to prevent only shadow lamps from producing negative
+                 colors.*/
+               if (shr->spec[0] < 0) shr->spec[0] = 0;
+               if (shr->spec[1] < 0) shr->spec[1] = 0;
+               if (shr->spec[2] < 0) shr->spec[2] = 0;
+
+               if (shr->shad[0] < 0) shr->shad[0] = 0;
+               if (shr->shad[1] < 0) shr->shad[1] = 0;
+               if (shr->shad[2] < 0) shr->shad[2] = 0;
+                                               
+               if(ma->sss_flag & MA_DIFF_SSS) {
+                       float sss[3], col[3], invalpha, texfac= ma->sss_texfac;
+
+                       /* this will return false in the preprocess stage */
+                       if(sample_sss(&R, ma, shi->co, sss)) {
+                               invalpha= (shr->col[3] > FLT_EPSILON)? 1.0f/shr->col[3]: 1.0f;
+
+                               if(texfac==0.0f) {
+                                       VECCOPY(col, shr->col);
+                                       VecMulf(col, invalpha);
+                               }
+                               else if(texfac==1.0f) {
+                                       col[0]= col[1]= col[2]= 1.0f;
+                                       VecMulf(col, invalpha);
+                               }
+                               else {
+                                       VECCOPY(col, shr->col);
+                                       VecMulf(col, invalpha);
+                                       col[0]= pow(col[0], 1.0f-texfac);
+                                       col[1]= pow(col[1], 1.0f-texfac);
+                                       col[2]= pow(col[2], 1.0f-texfac);
+                               }
+
+                               shr->diff[0]= sss[0]*col[0];
+                               shr->diff[1]= sss[1]*col[1];
+                               shr->diff[2]= sss[2]*col[2];
+
+                               if(shi->combinedflag & SCE_PASS_SHADOW) {
+                                       shr->shad[0]= shr->diff[0];
+                                       shr->shad[1]= shr->diff[1];
+                                       shr->shad[2]= shr->diff[2];
+                               }
+                       }
+               }
                
                if(shi->combinedflag & SCE_PASS_SHADOW) 
                        VECCOPY(shr->combined, shr->shad)       /* note, no ';' ! */
@@ -1508,7 +1701,7 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
                }
                
                /* exposure correction */
-               if(R.wrld.exp!=0.0f || R.wrld.range!=1.0f) {
+               if((R.wrld.exp!=0.0f || R.wrld.range!=1.0f) && !R.sss_points) {
                        wrld_exposure_correct(shr->combined);   /* has no spec! */
                        wrld_exposure_correct(shr->spec);
                }
@@ -1520,7 +1713,7 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
                        shi->alpha*= fresnel_fac(shi->view, shi->vn, ma->fresnel_tra_i, ma->fresnel_tra);
                        
                /* note: shi->mode! */
-               if(shi->mode & (MA_ZTRA|MA_RAYTRANSP)) {
+               if(shi->mode & MA_TRANSP) {
                        if(shi->spectra!=0.0f) {
                                float t = MAX3(shr->spec[0], shr->spec[1], shr->spec[2]);
                                t *= shi->spectra;
@@ -1532,23 +1725,33 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
        shr->alpha= shi->alpha;
        
        /* from now stuff everything in shr->combined: ambient, AO, radio, ramps, exposure */
-       shr->combined[0]+= shi->ambr + shi->r*shi->amb*shi->rad[0];
-       shr->combined[1]+= shi->ambg + shi->g*shi->amb*shi->rad[1];
-       shr->combined[2]+= shi->ambb + shi->b*shi->amb*shi->rad[2];
-       
-       /* add AO in combined? */
-       if(R.wrld.mode & WO_AMB_OCC) {
-               if(shi->combinedflag & SCE_PASS_AO) {
-                       float aodiff[3];
-                       ambient_occlusion_to_diffuse(shi, aodiff);
-                       
-                       shr->combined[0] += shi->r*aodiff[0];
-                       shr->combined[1] += shi->g*aodiff[1];
-                       shr->combined[2] += shi->b*aodiff[2];
+       if(!(ma->sss_flag & MA_DIFF_SSS) || !sss_pass_done(&R, ma)) {
+               shr->combined[0]+= shi->ambr;
+               shr->combined[1]+= shi->ambg;
+               shr->combined[2]+= shi->ambb;
+
+               /* removed
+               if(shi->combinedflag & SCE_PASS_RADIO) {
+                       shr->combined[0]+= shi->r*shi->amb*shi->rad[0];
+                       shr->combined[1]+= shi->g*shi->amb*shi->rad[1];
+                       shr->combined[2]+= shi->b*shi->amb*shi->rad[2];
+               }*/
+               
+               /* add AO in combined? */
+               if(R.wrld.mode & WO_AMB_OCC) {
+                       if(shi->combinedflag & SCE_PASS_AO) {
+                               float aodiff[3];
+                               ambient_occlusion_to_diffuse(shi, aodiff);
+                               
+                               shr->combined[0] += shi->r*aodiff[0];
+                               shr->combined[1] += shi->g*aodiff[1];
+                               shr->combined[2] += shi->b*aodiff[2];
+                       }
                }
+               
+               if(ma->mode & MA_RAMP_COL) ramp_diffuse_result(shr->combined, shi);
        }
-       
-       if(ma->mode & MA_RAMP_COL) ramp_diffuse_result(shr->combined, shi);
+
        if(ma->mode & MA_RAMP_SPEC) ramp_spec_result(shr->spec, shr->spec+1, shr->spec+2, shi);
        
        /* refcol is for envmap only */
@@ -1571,7 +1774,21 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
        if(shi->combinedflag & SCE_PASS_SPEC)
                VECADD(shr->combined, shr->combined, shr->spec);
 
+       /* modulate by the object color */
+       if((ma->shade_flag & MA_OBCOLOR) && shi->obr->ob) {
+               if(!(ma->sss_flag & MA_DIFF_SSS) || !sss_pass_done(&R, ma)) {
+                       float obcol[4];
+
+                       QUATCOPY(obcol, shi->obr->ob->col);
+                       CLAMP(obcol[3], 0.0f, 1.0f);
+
+                       shr->combined[0] *= obcol[0];
+                       shr->combined[1] *= obcol[1];
+                       shr->combined[2] *= obcol[2];
+                       shr->alpha *= obcol[3];
+               }
+       }
+
        shr->combined[3]= shr->alpha;
 }
 
-