Comments
[blender.git] / source / blender / render / intern / source / shadeoutput.c
index c2e21af4ad25d90acea5fe48e201974343b53a83..427d0eeed11fa4de58f249e6051935dae4d12c99 100644 (file)
 
 #include "shading.h" /* own include */
 
+/* could enable at some point but for now there are far too many conversions */
+#ifdef __GNUC__
+#  pragma GCC diagnostic ignored "-Wdouble-promotion"
+#endif
+
 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
 /* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
 /* only to be used here in this file, it's for speed */
@@ -66,7 +71,7 @@ extern struct Render R;
 ListBase *get_lights(ShadeInput *shi)
 {
        
-       if (R.r.scemode & R_PREVIEWBUTS)
+       if (R.r.scemode & R_BUTS_PREVIEW)
                return &R.lights;
        if (shi->light_override)
                return &shi->light_override->gobject;
@@ -114,7 +119,7 @@ static void fogcolor(const float colf[3], float *rco, float *view)
                addAlphaOverFloat(colf, hor);
                
                sub_v3_v3(vec, dview);
-       }       
+       }
 }
 #endif
 
@@ -123,37 +128,52 @@ float mistfactor(float zcor, float const co[3])
 {
        float fac, hi;
        
-       fac= zcor - R.wrld.miststa;     /* zcor is calculated per pixel */
+       fac = zcor - R.wrld.miststa;    /* zcor is calculated per pixel */
 
        /* fac= -co[2]-R.wrld.miststa; */
 
-       if (fac>0.0f) {
-               if (fac< R.wrld.mistdist) {
+       if (fac > 0.0f) {
+               if (fac < R.wrld.mistdist) {
                        
-                       fac= (fac/(R.wrld.mistdist));
+                       fac = (fac / R.wrld.mistdist);
                        
-                       if (R.wrld.mistype==0) fac*= fac;
-                       else if (R.wrld.mistype==1);
-                       else fac= sqrt(fac);
+                       if (R.wrld.mistype == 0) {
+                               fac *= fac;
+                       }
+                       else if (R.wrld.mistype == 1) {
+                               /* pass */
+                       }
+                       else {
+                               fac = sqrt(fac);
+                       }
+               }
+               else {
+                       fac = 1.0f;
                }
-               else fac= 1.0f;
        }
-       else fac= 0.0f;
+       else {
+               fac = 0.0f;
+       }
        
        /* height switched off mist */
        if (R.wrld.misthi!=0.0f && fac!=0.0f) {
                /* at height misthi the mist is completely gone */
 
-               hi= R.viewinv[0][2]*co[0]+R.viewinv[1][2]*co[1]+R.viewinv[2][2]*co[2]+R.viewinv[3][2];
+               hi = R.viewinv[0][2] * co[0] +
+                    R.viewinv[1][2] * co[1] +
+                    R.viewinv[2][2] * co[2] +
+                    R.viewinv[3][2];
                
-               if (hi>R.wrld.misthi) fac= 0.0f;
+               if (hi > R.wrld.misthi) {
+                       fac = 0.0f;
+               }
                else if (hi>0.0f) {
                        hi= (R.wrld.misthi-hi)/R.wrld.misthi;
                        fac*= hi*hi;
                }
        }
 
-       return (1.0f-fac)* (1.0f-R.wrld.misi);  
+       return (1.0f-fac)* (1.0f-R.wrld.misi);
 }
 
 static void spothalo(struct LampRen *lar, ShadeInput *shi, float *intens)
@@ -161,7 +181,8 @@ static void spothalo(struct LampRen *lar, ShadeInput *shi, float *intens)
        double a, b, c, disc, nray[3], npos[3];
        double t0, t1 = 0.0f, t2= 0.0f, t3;
        float p1[3], p2[3], ladist, maxz = 0.0f, maxy = 0.0f, haint;
-       int snijp, do_clip = TRUE, use_yco = FALSE;
+       int cuts;
+       bool do_clip = true, use_yco = false;
 
        *intens= 0.0f;
        haint= lar->haint;
@@ -173,7 +194,7 @@ static void spothalo(struct LampRen *lar, ShadeInput *shi, float *intens)
                p1[1]= shi->co[1]-lar->co[1];
                p1[2]= -lar->co[2];
                mul_m3_v3(lar->imat, p1);
-               copy_v3db_v3fl(npos, p1);       // npos is double!
+               copy_v3db_v3fl(npos, p1);  /* npos is double! */
                
                /* pre-scale */
                npos[2] *= (double)lar->sh_zfac;
@@ -197,7 +218,7 @@ static void spothalo(struct LampRen *lar, ShadeInput *shi, float *intens)
 
        /* rotate maxz */
        if (shi->co[2]==0.0f) {
-               do_clip = FALSE;  /* for when halo at sky */
+               do_clip = false;  /* for when halo at sky */
        }
        else {
                p1[0]= shi->co[0]-lar->co[0];
@@ -208,12 +229,12 @@ 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 (fabsf(nray[2]) < FLT_EPSILON) {
-                       use_yco = TRUE;
+               if (fabs(nray[2]) < FLT_EPSILON) {
+                       use_yco = true;
                }
        }
        
-       /* scale z to make sure volume is normalized */ 
+       /* scale z to make sure volume is normalized */
        nray[2] *= (double)lar->sh_zfac;
        /* nray does not need normalization */
        
@@ -224,7 +245,7 @@ static void spothalo(struct LampRen *lar, ShadeInput *shi, float *intens)
        b = nray[0] * npos[0] + nray[1] * npos[1] - nray[2]*npos[2];
        c = npos[0] * npos[0] + npos[1] * npos[1] - npos[2]*npos[2];
 
-       snijp= 0;
+       cuts= 0;
        if (fabs(a) < DBL_EPSILON) {
                /*
                 * Only one intersection point...
@@ -236,16 +257,16 @@ static void spothalo(struct LampRen *lar, ShadeInput *shi, float *intens)
                
                if (disc==0.0) {
                        t1=t2= (-b)/ a;
-                       snijp= 2;
+                       cuts= 2;
                }
                else if (disc > 0.0) {
                        disc = sqrt(disc);
                        t1 = (-b + disc) / a;
                        t2 = (-b - disc) / a;
-                       snijp= 2;
+                       cuts= 2;
                }
        }
-       if (snijp==2) {
+       if (cuts==2) {
                int ok1=0, ok2=0;
 
                /* sort */
@@ -265,7 +286,7 @@ static void spothalo(struct LampRen *lar, ShadeInput *shi, float *intens)
                if (ok1==0 && ok2==0) return;
                
                /* intersction point with -ladist, the bottom of the cone */
-               if (use_yco == FALSE) {
+               if (use_yco == false) {
                        t3= ((double)(-ladist)-npos[2])/nray[2];
                                
                        /* de we have to replace one of the intersection points? */
@@ -299,8 +320,8 @@ static void spothalo(struct LampRen *lar, ShadeInput *shi, float *intens)
                
                /* calculate t0: is the maximum visible z (when halo is intersected by face) */ 
                if (do_clip) {
-                       if (use_yco == FALSE) t0 = (maxz - npos[2]) / nray[2];
-                       else t0 = (maxy - npos[1]) / nray[1];
+                       if (use_yco == false) t0 = ((double)maxz - npos[2]) / nray[2];
+                       else                  t0 = ((double)maxy - npos[1]) / nray[1];
 
                        if (t0 < t1) return;
                        if (t0 < t2) t2= t0;
@@ -371,11 +392,12 @@ void renderspothalo(ShadeInput *shi, float col[4], float alpha)
                                continue;
                        
                        spothalo(lar, shi, &i);
-                       if (i>0.0f) {
-                               col[3]+= i*alpha;                       // all premul
-                               col[0]+= i*lar->r*alpha;
-                               col[1]+= i*lar->g*alpha;
-                               col[2]+= i*lar->b*alpha;        
+                       if (i > 0.0f) {
+                               const float i_alpha = i * alpha;
+                               col[0] += i_alpha * lar->r;
+                               col[1] += i_alpha * lar->g;
+                               col[2] += i_alpha * lar->b;
+                               col[3] += i_alpha;  /* all premul */
                        }
                }
        }
@@ -452,9 +474,10 @@ static float area_lamp_energy(float (*area)[3], const float co[3], const float v
 
        /* cross product */
 #define CROSS(dest, a, b) \
-       { dest[0]= a[1] * b[2] - a[2] * b[1]; \
-         dest[1]= a[2] * b[0] - a[0] * b[2]; \
-         dest[2]= a[0] * b[1] - a[1] * b[0]; \
+       { \
+               dest[0]= a[1] * b[2] - a[2] * b[1]; \
+               dest[1]= a[2] * b[0] - a[0] * b[2]; \
+               dest[2]= a[0] * b[1] - a[1] * b[0]; \
        } (void)0
 
        CROSS(cross[0], vec[0], vec[1]);
@@ -519,7 +542,7 @@ static float area_lamp_energy_multisample(LampRen *lar, const float co[3], float
        }
        intens /= (float)lar->ray_totsamp;
        
-       return pow(intens*lar->areasize, lar->k);       // corrected for buttons size and lar->dist^2
+       return pow(intens * lar->areasize, lar->k);     /* corrected for buttons size and lar->dist^2 */
 }
 
 static float spec(float inp, int hard) 
@@ -531,7 +554,7 @@ static float spec(float inp, int hard)
        
        b1= inp*inp;
        /* avoid FPE */
-       if (b1<0.01f) b1= 0.01f;        
+       if (b1<0.01f) b1= 0.01f;
        
        if ((hard & 1)==0)  inp= 1.0f;
        if (hard & 2)  inp*= b1;
@@ -544,7 +567,7 @@ static float spec(float inp, int hard)
        b1*= b1;
 
        /* avoid FPE */
-       if (b1<0.001f) b1= 0.0f;        
+       if (b1<0.001f) b1= 0.0f;
 
        if (hard & 32) inp*= b1;
        b1*= b1;
@@ -552,7 +575,7 @@ static float spec(float inp, int hard)
        b1*= b1;
        if (hard & 128) inp*=b1;
 
-       if (b1<0.001f) b1= 0.0f;        
+       if (b1<0.001f) b1= 0.0f;
 
        if (hard & 256) {
                b1*= b1;
@@ -810,7 +833,7 @@ static float Minnaert_Diff(float nl, const float n[3], const float v[3], float d
                nv = 0.0f;
 
        if (darkness <= 1.0f)
-               i = nl * pow(maxf(nv * nl, 0.1f), (darkness - 1.0f) ); /*The Real model*/
+               i = nl * pow(max_ff(nv * nl, 0.1f), (darkness - 1.0f) ); /*The Real model*/
        else
                i = nl * pow( (1.001f - nv), (darkness  - 1.0f) ); /*Nvidia model*/
 
@@ -902,6 +925,21 @@ void shade_color(ShadeInput *shi, ShadeResult *shr)
        shr->diff[1]= shi->g;
        shr->diff[2]= shi->b;
        shr->alpha= shi->alpha;
+
+       /* modulate by the object color */
+       if ((ma->shade_flag & MA_OBCOLOR) && shi->obr->ob) {
+               float obcol[4];
+
+               copy_v4_v4(obcol, shi->obr->ob->col);
+               CLAMP(obcol[3], 0.0f, 1.0f);
+
+               shr->diff[0] *= obcol[0];
+               shr->diff[1] *= obcol[1];
+               shr->diff[2] *= obcol[2];
+               if (shi->mode & MA_TRANSP) shr->alpha *= obcol[3];
+       }
+
+       copy_v3_v3(shr->diffshad, shr->diff);
 }
 
 /* ramp for at end of shade */
@@ -932,7 +970,7 @@ static void add_to_diffuse(float *diff, ShadeInput *shi, float is, float r, floa
                
                /* MA_RAMP_IN_RESULT is exceptional */
                if (ma->rampin_col==MA_RAMP_IN_RESULT) {
-                       // normal add
+                       /* normal add */
                        diff[0] += r * shi->r;
                        diff[1] += g * shi->g;
                        diff[2] += b * shi->b;
@@ -1156,8 +1194,8 @@ float lamp_get_visibility(LampRen *lar, const float co[3], float lv[3], float *d
                float visifac= 1.0f, t;
                
                sub_v3_v3v3(lv, co, lar->co);
-               *dist= sqrtf(dot_v3v3(lv, lv));
-               t= 1.0f/dist[0];
+               *dist = len_v3(lv);
+               t = 1.0f / (*dist);
                mul_v3_fl(lv, t);
                
                /* area type has no quad or sphere option */
@@ -1191,6 +1229,7 @@ float lamp_get_visibility(LampRen *lar, const float co[3], float lv[3], float *d
                                                visifac*= lar->distkw/(lar->distkw+lar->ld2*dist[0]*dist[0]);
                                        break;
                                case LA_FALLOFF_CURVE:
+                                       /* curvemapping_initialize is called from #add_render_lamp */
                                        visifac = curvemapping_evaluateF(lar->curfalloff, 0, dist[0]/lar->dist);
                                        break;
                        }
@@ -1215,7 +1254,7 @@ float lamp_get_visibility(LampRen *lar, const float co[3], float lv[3], float *d
                                                        copy_v3_v3(lvrot, lv);
                                                        mul_m3_v3(lar->imat, lvrot);
                                                        
-                                                       x = maxf(fabsf(lvrot[0]/lvrot[2]), fabsf(lvrot[1]/lvrot[2]));
+                                                       x = max_ff(fabsf(lvrot[0]/lvrot[2]), fabsf(lvrot[1]/lvrot[2]));
                                                        /* 1.0f/(sqrt(1+x*x)) is equivalent to cos(atan(x)) */
                                                        
                                                        inpr= 1.0f/(sqrt(1.0f+x*x));
@@ -1299,7 +1338,7 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
        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 */ 
+               /* 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], nstrand[3], blend;
@@ -1345,11 +1384,13 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
        /* inp = dotproduct, is = shader result, i = lamp energy (with shadow), i_noshad = i without shadow */
        inp= dot_v3v3(vn, lv);
 
-       /* phong threshold to prevent backfacing faces having artefacts on ray shadow (terminator problem) */
+       /* phong threshold to prevent backfacing faces having artifacts on ray shadow (terminator problem) */
        /* 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 || lar->type==LA_AREA);
+                       if (lar->type == LA_HEMI || lar->type == LA_AREA) {
+                               /* pass */
+                       }
                        else if ((ma->mode & MA_RAYBIAS) && (lar->mode & LA_SHAD_RAY) && (vlr->flag & R_SMOOTH)) {
                                float thresh= shi->obr->ob->smoothresh;
                                if (inp>thresh)
@@ -1368,10 +1409,10 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
        
        /* diffuse shaders */
        if (lar->mode & LA_NO_DIFF) {
-               is= 0.0f;       // skip shaders
+               is = 0.0f;  /* skip shaders */
        }
        else if (lar->type==LA_HEMI) {
-               is= 0.5f*inp + 0.5f;
+               is = 0.5f * inp + 0.5f;
        }
        else {
                
@@ -1383,12 +1424,13 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
                else if (ma->diff_shader==MA_DIFF_TOON) is= Toon_Diff(vn, lv, view, ma->param[0], ma->param[1]);
                else if (ma->diff_shader==MA_DIFF_MINNAERT) is= Minnaert_Diff(inp, vn, view, ma->darkness);
                else if (ma->diff_shader==MA_DIFF_FRESNEL) is= Fresnel_Diff(vn, lv, view, ma->param[0], ma->param[1]);
-               else is= inp;   // Lambert
+               else is= inp;  /* Lambert */
        }
-       
+
        /* 'is' is diffuse */
-       if ((ma->shade_flag & MA_CUBIC) && is>0.0f && is<1.0f)
-               is= 3.0f*is*is - 2.0f*is*is*is; // nicer termination of shades
+       if ((ma->shade_flag & MA_CUBIC) && is > 0.0f && is < 1.0f) {
+               is= 3.0f * is * is - 2.0f * is * is * is;  /* nicer termination of shades */
+       }
 
        i= is*phongcorr;
        
@@ -1397,7 +1439,7 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
        }
        i_noshad= i;
        
-       vn= shi->vn;    // bring back original vector, we use special specular shaders for tangent
+       vn = shi->vn;  /* bring back original vector, we use special specular shaders for tangent */
        if (ma->mode & MA_TANGENT_V)
                vn= shi->tang;
        
@@ -1424,9 +1466,11 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
                                                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]);
+                                               if (!(lar->mode & LA_NO_SPEC)) {
+                                                       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;
                                        }
@@ -1463,8 +1507,10 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
                
                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) {
+                       if (!(passflag & (SCE_PASS_COMBINED | SCE_PASS_SPEC))) {
+                               /* pass */
+                       }
+                       else if (lar->type == LA_HEMI) {
                                float t;
                                /* hemi uses no spec shaders (yet) */
                                
@@ -1614,7 +1660,7 @@ static void shade_lamp_loop_only_shadow(ShadeInput *shi, ShadeResult *shr)
                }
        }
        
-       /* quite disputable this...  also note it doesn't mirror-raytrace */    
+       /* quite disputable this...  also note it doesn't mirror-raytrace */
        if ((R.wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT)) && shi->amb!=0.0f) {
                float f;
                
@@ -1660,9 +1706,19 @@ static void wrld_exposure_correct(float diff[3])
 
 void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
 {
+       /* Passes which might need to know material color.
+        *
+        * It seems to be faster to just calculate material color
+        * even if the pass doesn't really need it than trying to
+        * figure out whether color is really needed or not.
+        */
+       const int color_passes =
+               SCE_PASS_COMBINED | SCE_PASS_RGBA | SCE_PASS_DIFFUSE | SCE_PASS_SPEC |
+               SCE_PASS_REFLECT | SCE_PASS_NORMAL | SCE_PASS_REFRACT | SCE_PASS_EMIT;
+
        Material *ma= shi->mat;
        int passflag= shi->passflag;
-       
+
        memset(shr, 0, sizeof(ShadeResult));
        
        if (!(shi->mode & MA_TRANSP)) shi->alpha = 1.0f;
@@ -1677,7 +1733,7 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
        shi->refcol[0]= shi->refcol[1]= shi->refcol[2]= shi->refcol[3]= 0.0f;
        
        /* material color itself */
-       if (passflag & (SCE_PASS_COMBINED|SCE_PASS_RGBA)) {
+       if (passflag & color_passes) {
                if (ma->mode & (MA_FACETEXTURE)) {
                        shi->r= shi->vcol[0];
                        shi->g= shi->vcol[1];
@@ -1685,12 +1741,14 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
                        if (ma->mode & (MA_FACETEXTURE_ALPHA))
                                shi->alpha= shi->vcol[3];
                }
+#ifdef WITH_FREESTYLE
                else if (ma->vcol_alpha) {
                        shi->r= shi->vcol[0];
                        shi->g= shi->vcol[1];
                        shi->b= shi->vcol[2];
                        shi->alpha= shi->vcol[3];
                }
+#endif
                else if (ma->mode & (MA_VERTEXCOLP)) {
                        float neg_alpha = 1.0f - shi->vcol[3];
                        shi->r= shi->r*neg_alpha + shi->vcol[0]*shi->vcol[3];
@@ -1713,15 +1771,15 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
                                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);
+                               shi->r= pow(max_ff(shi->r, 0.0f), ma->sss_texfac);
+                               shi->g= pow(max_ff(shi->g, 0.0f), ma->sss_texfac);
+                               shi->b= pow(max_ff(shi->b, 0.0f), ma->sss_texfac);
+                               shi->alpha= pow(max_ff(shi->alpha, 0.0f), 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);
+                               shr->col[0]= pow(max_ff(shr->col[0], 0.0f), ma->sss_texfac);
+                               shr->col[1]= pow(max_ff(shr->col[1], 0.0f), ma->sss_texfac);
+                               shr->col[2]= pow(max_ff(shr->col[2], 0.0f), ma->sss_texfac);
+                               shr->col[3]= pow(max_ff(shr->col[3], 0.0f), ma->sss_texfac);
                        }
                }
        }
@@ -1734,7 +1792,7 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
                return;
        }
 
-       if ( (ma->mode & (MA_VERTEXCOL|MA_VERTEXCOLP))== MA_VERTEXCOL ) {       // vertexcolor light
+       if ( (ma->mode & (MA_VERTEXCOL|MA_VERTEXCOLP))== MA_VERTEXCOL ) {       /* vertexcolor light */
                shr->emit[0]= shi->r*(shi->emit+shi->vcol[0]*shi->vcol[3]);
                shr->emit[1]= shi->g*(shi->emit+shi->vcol[1]*shi->vcol[3]);
                shr->emit[2]= shi->b*(shi->emit+shi->vcol[2]*shi->vcol[3]);
@@ -1746,18 +1804,20 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
        }
        
        /* AO pass */
-       if (R.wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT)) {
-               if (((passflag & SCE_PASS_COMBINED) && (shi->combinedflag & (SCE_PASS_AO|SCE_PASS_ENVIRONMENT|SCE_PASS_INDIRECT))) ||
-                   (passflag & (SCE_PASS_AO|SCE_PASS_ENVIRONMENT|SCE_PASS_INDIRECT)))
-               {
-                       if (R.r.mode & R_SHADOW) {
-                               /* AO was calculated for scanline already */
-                               if (shi->depth || shi->volume_depth)
-                                       ambient_occlusion(shi);
-                               copy_v3_v3(shr->ao, shi->ao);
-                               copy_v3_v3(shr->env, shi->env); // XXX multiply
-                               copy_v3_v3(shr->indirect, shi->indirect); // XXX multiply
-                       }
+       if (((passflag & SCE_PASS_COMBINED) && (shi->combinedflag & (SCE_PASS_AO|SCE_PASS_ENVIRONMENT|SCE_PASS_INDIRECT))) ||
+           (passflag & (SCE_PASS_AO|SCE_PASS_ENVIRONMENT|SCE_PASS_INDIRECT))) {
+               if ((R.wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT)) && (R.r.mode & R_SHADOW)) {
+                       /* AO was calculated for scanline already */
+                       if (shi->depth || shi->volume_depth)
+                               ambient_occlusion(shi);
+                       copy_v3_v3(shr->ao, shi->ao);
+                       copy_v3_v3(shr->env, shi->env); /* XXX multiply */
+                       copy_v3_v3(shr->indirect, shi->indirect); /* XXX multiply */
+               }
+               else {
+                       shr->ao[0]= shr->ao[1]= shr->ao[2]= 1.0f;
+                       zero_v3(shr->env);
+                       zero_v3(shr->indirect);
                }
        }
        
@@ -1811,9 +1871,9 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
                                else {
                                        copy_v3_v3(col, shr->col);
                                        mul_v3_fl(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);
+                                       col[0]= pow(max_ff(col[0], 0.0f), 1.0f-texfac);
+                                       col[1]= pow(max_ff(col[1], 0.0f), 1.0f-texfac);
+                                       col[2]= pow(max_ff(col[2], 0.0f), 1.0f-texfac);
                                }
 
                                shr->diff[0]= sss[0]*col[0];
@@ -1828,10 +1888,12 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
                        }
                }
                
-               if (shi->combinedflag & SCE_PASS_SHADOW)        
-                       copy_v3_v3(shr->combined, shr->shad);   /* note, no ';' ! */
+               if (shi->combinedflag & SCE_PASS_SHADOW)
+                       copy_v3_v3(shr->diffshad, shr->shad);   /* note, no ';' ! */
                else
-                       copy_v3_v3(shr->combined, shr->diff);
+                       copy_v3_v3(shr->diffshad, shr->diff);
+
+               copy_v3_v3(shr->combined, shr->diffshad);
                        
                /* calculate shadow pass, we use a multiplication mask */
                /* if diff = 0,0,0 it doesn't matter what the shadow pass is, so leave it as is */
@@ -1862,7 +1924,7 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
                /* note: shi->mode! */
                if (shi->mode & MA_TRANSP && (shi->mode & (MA_ZTRANSP|MA_RAYTRANSP))) {
                        if (shi->spectra!=0.0f) {
-                               float t = MAX3(shr->spec[0], shr->spec[1], shr->spec[2]);
+                               float t = max_fff(shr->spec[0], shr->spec[1], shr->spec[2]);
                                t *= shi->spectra;
                                if (t>1.0f) t= 1.0f;
                                shi->alpha= (1.0f-t)*shi->alpha+t;
@@ -1937,3 +1999,94 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
        shr->combined[3]= shr->alpha;
 }
 
+/* used for "Lamp Data" shader node */
+static float lamp_get_data_internal(ShadeInput *shi, GroupObject *go, float col[4], float lv[3], float *dist, float shadow[4])
+{
+       LampRen *lar = go->lampren;
+       float visifac, inp;
+
+       if (!lar || lar->type == LA_YF_PHOTON
+           || ((lar->mode & LA_LAYER) && (lar->lay & shi->obi->lay) == 0)
+           || (lar->lay & shi->lay) == 0)
+               return 0.0f;
+
+       if (lar->mode & LA_TEXTURE)
+               do_lamp_tex(lar, lv, shi, col, LA_TEXTURE);
+
+       visifac = lamp_get_visibility(lar, shi->co, lv, dist);
+
+       if (visifac == 0.0f
+           || lar->type == LA_HEMI
+           || (lar->type != LA_SPOT && !(lar->mode & LA_SHAD_RAY))
+           || (R.r.scemode & R_BUTS_PREVIEW))
+               return visifac;
+
+       inp = dot_v3v3(shi->vn, lv);
+
+       if (inp > 0.0f) {
+               float shadfac[4];
+
+               shadow[0] = lar->shdwr;
+               shadow[1] = lar->shdwg;
+               shadow[2] = lar->shdwb;
+
+               if (lar->mode & LA_SHAD_TEX)
+                       do_lamp_tex(lar, lv, shi, shadow, LA_SHAD_TEX);
+
+               lamp_get_shadow(lar, shi, inp, shadfac, shi->depth);
+
+               shadow[0] = 1.0f - ((1.0f - shadfac[0] * shadfac[3]) * (1.0f - shadow[0]));
+               shadow[1] = 1.0f - ((1.0f - shadfac[1] * shadfac[3]) * (1.0f - shadow[1]));
+               shadow[2] = 1.0f - ((1.0f - shadfac[2] * shadfac[3]) * (1.0f - shadow[2]));
+       }
+
+       return visifac;
+}
+
+float RE_lamp_get_data(ShadeInput *shi, Object *lamp_obj, float col[4], float lv[3], float *dist, float shadow[4])
+{
+       col[0] = col[1] = col[2] = 0.0f;
+       col[3] = 1.0f;
+       copy_v3_v3(lv, shi->vn);
+       *dist = 1.0f;
+       shadow[0] = shadow[1] = shadow[2] = shadow[3] = 1.0f;
+
+       if (lamp_obj->type == OB_LAMP) {
+               GroupObject *go;
+               Lamp *lamp = (Lamp *)lamp_obj->data;
+
+               col[0] = lamp->r * lamp->energy;
+               col[1] = lamp->g * lamp->energy;
+               col[2] = lamp->b * lamp->energy;
+
+               if (R.r.scemode & R_BUTS_PREVIEW) {
+                       for (go = R.lights.first; go; go = go->next) {
+                               /* "Lamp.002" is main key light of material preview */
+                               if (strcmp(go->ob->id.name + 2, "Lamp.002") == 0)
+                                       return lamp_get_data_internal(shi, go, col, lv, dist, shadow);
+                       }
+                       return 0.0f;
+               }
+
+               if (shi->light_override) {
+                       for (go = shi->light_override->gobject.first; go; go = go->next) {
+                               if (go->ob == lamp_obj)
+                                       return lamp_get_data_internal(shi, go, col, lv, dist, shadow);
+                       }
+               }
+
+               if (shi->mat && shi->mat->group) {
+                       for (go = shi->mat->group->gobject.first; go; go = go->next) {
+                               if (go->ob == lamp_obj)
+                                       return lamp_get_data_internal(shi, go, col, lv, dist, shadow);
+                       }
+               }
+
+               for (go = R.lights.first; go; go = go->next) {
+                       if (go->ob == lamp_obj)
+                               return lamp_get_data_internal(shi, go, col, lv, dist, shadow);
+               }
+       }
+
+       return 0.0f;
+}