=bmesh= merge from trunk at r36529
[blender.git] / source / blender / render / intern / source / shadeoutput.c
index f167122f49719a17106d91af3bc5f85a7966849c..55249847aa4b0f44800a518da3f79aea1f9f64d0 100644 (file)
@@ -1,5 +1,5 @@
-/**
-* $Id:
+/*
+* $Id$
  *
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  *
  * The Original Code is Copyright (C) 2006 Blender Foundation
  * All rights reserved.
  * ***** END GPL LICENSE BLOCK *****
  */
 
+/** \file blender/render/intern/source/shadeoutput.c
+ *  \ingroup render
+ */
+
+
 #include <stdio.h>
 #include <float.h>
 #include <math.h>
 #include <string.h>
 
-
 #include "BLI_math.h"
+#include "BLI_utildefines.h"
 
 #include "BKE_colortools.h"
 #include "BKE_material.h"
 #include "BKE_texture.h"
-#include "BKE_utildefines.h"
+
 
 #include "DNA_group_types.h"
 #include "DNA_lamp_types.h"
@@ -154,8 +159,8 @@ float mistfactor(float zcor, float *co)
 static void spothalo(struct LampRen *lar, ShadeInput *shi, float *intens)
 {
        double a, b, c, disc, nray[3], npos[3];
-       float t0, t1 = 0.0f, t2= 0.0f, t3, haint;
-       float p1[3], p2[3], ladist, maxz = 0.0f, maxy = 0.0f;
+       double t0, t1 = 0.0f, t2= 0.0f, t3;
+       float p1[3], p2[3], ladist, maxz = 0.0f, maxy = 0.0f, haint;
        int snijp, doclip=1, use_yco=0;
        int ok1=0, ok2=0;
        
@@ -202,7 +207,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]) < DBL_EPSILON ) use_yco= 1;
+               if( fabs(nray[2]) < FLT_EPSILON ) use_yco= 1;
        }
        
        /* scale z to make sure volume is normalized */ 
@@ -354,7 +359,7 @@ void renderspothalo(ShadeInput *shi, float *col, float alpha)
                lar= go->lampren;
                if(lar==NULL) continue;
                
-               if(lar->type==LA_SPOT && (lar->mode & LA_HALO) && lar->haint>0) {
+               if(lar->type==LA_SPOT && (lar->mode & LA_HALO) && (lar->buftype != LA_SHADBUF_DEEP) && lar->haint>0) {
                        
                        if(lar->mode & LA_LAYER) 
                                if(shi->vlr && (lar->lay & shi->obi->lay)==0) 
@@ -379,25 +384,6 @@ void renderspothalo(ShadeInput *shi, float *col, float alpha)
 
 /* ---------------- shaders ----------------------- */
 
-static double Normalize_d(double *n)
-{
-       double d;
-       
-       d= n[0]*n[0]+n[1]*n[1]+n[2]*n[2];
-
-       if(d>0.00000000000000001) {
-               d= sqrt(d);
-
-               n[0]/=d; 
-               n[1]/=d; 
-               n[2]/=d;
-       } else {
-               n[0]=n[1]=n[2]= 0.0;
-               d= 0.0;
-       }
-       return d;
-}
-
 /* mix of 'real' fresnel and allowing control. grad defines blending gradient */
 float fresnel_fac(float *view, float *vn, float grad, float fac)
 {
@@ -436,10 +422,10 @@ static float area_lamp_energy(float (*area)[3], float *co, float *vn)
        VECSUB(vec[2], co, area[2]);
        VECSUB(vec[3], co, area[3]);
        
-       Normalize_d(vec[0]);
-       Normalize_d(vec[1]);
-       Normalize_d(vec[2]);
-       Normalize_d(vec[3]);
+       normalize_dv3(vec[0]);
+       normalize_dv3(vec[1]);
+       normalize_dv3(vec[2]);
+       normalize_dv3(vec[3]);
 
        /* cross product */
        CROSS(cross[0], vec[0], vec[1]);
@@ -447,10 +433,10 @@ static float area_lamp_energy(float (*area)[3], float *co, float *vn)
        CROSS(cross[2], vec[2], vec[3]);
        CROSS(cross[3], vec[3], vec[0]);
 
-       Normalize_d(cross[0]);
-       Normalize_d(cross[1]);
-       Normalize_d(cross[2]);
-       Normalize_d(cross[3]);
+       normalize_dv3(cross[0]);
+       normalize_dv3(cross[1]);
+       normalize_dv3(cross[2]);
+       normalize_dv3(cross[3]);
 
        /* angles */
        rad[0]= vec[0][0]*vec[1][0]+ vec[0][1]*vec[1][1]+ vec[0][2]*vec[1][2];
@@ -721,7 +707,7 @@ static float Toon_Diff( float *n, float *l, float *v, float size, float smooth )
 /* in latter case, only last multiplication uses 'nl' */
 static float OrenNayar_Diff(float nl, float *n, float *l, float *v, float rough )
 {
-       float i, nh, nv, vh, realnl, h[3];
+       float i/*, nh*/, nv, vh, realnl, h[3];
        float a, b, t, A, B;
        float Lit_A, View_A, Lit_B[3], View_B[3];
        
@@ -730,8 +716,8 @@ static float OrenNayar_Diff(float nl, float *n, float *l, float *v, float rough
        h[2]= v[2]+l[2];
        normalize_v3(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;
+       /* 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; */
        
        nv= n[0]*v[0]+n[1]*v[1]+n[2]*v[2]; /* Dot product between surface normal and view vector */
        if(nv<=0.0f) nv= 0.0f;
@@ -873,7 +859,9 @@ void shade_color(ShadeInput *shi, ShadeResult *shr)
 
        if(ma->fresnel_tra!=0.0f) 
                shi->alpha*= fresnel_fac(shi->view, shi->vn, ma->fresnel_tra_i, ma->fresnel_tra);
-
+       
+       if (!(shi->mode & MA_TRANSP)) shi->alpha= 1.0f;
+       
        shr->diff[0]= shi->r;
        shr->diff[1]= shi->g;
        shr->diff[2]= shi->b;
@@ -1013,40 +1001,69 @@ void ambient_occlusion(ShadeInput *shi)
        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);
+               ray_ao(shi, shi->ao, shi->env);
        else
                shi->ao[0]= shi->ao[1]= shi->ao[2]= 1.0f;
 }
 
 
 /* wrld mode was checked for */
-void ambient_occlusion_to_diffuse(ShadeInput *shi, float *diff)
+static void ambient_occlusion_apply(ShadeInput *shi, ShadeResult *shr)
 {
-       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);
+       float f= R.wrld.aoenergy;
+       float tmp[3], tmpspec[3];
+
+       if(!((R.r.mode & R_RAYTRACE) || R.wrld.ao_gather_method == WO_AOGATHER_APPROX))
+               return;
+       if(f == 0.0f)
+               return;
+
+       if(R.wrld.aomix==WO_AOADD) {
+               shr->combined[0] += shi->ao[0]*shi->r*shi->refl*f;
+               shr->combined[1] += shi->ao[1]*shi->g*shi->refl*f;
+               shr->combined[2] += shi->ao[2]*shi->b*shi->refl*f;
+       }
+       else if(R.wrld.aomix==WO_AOMUL) {
+               mul_v3_v3v3(tmp, shr->combined, shi->ao);
+               mul_v3_v3v3(tmpspec, shr->spec, shi->ao);
+
+               if(f == 1.0f) {
+                       copy_v3_v3(shr->combined, tmp);
+                       copy_v3_v3(shr->spec, tmpspec);
+               }
+               else {
+                       interp_v3_v3v3(shr->combined, shr->combined, tmp, f);
+                       interp_v3_v3v3(shr->spec, shr->spec, tmpspec, f);
                }
-               else
-                       diff[0]= diff[1]= diff[2]= 0.0f;
        }
-       else
-               diff[0]= diff[1]= diff[2]= 0.0f;
+}
+
+void environment_lighting_apply(ShadeInput *shi, ShadeResult *shr)
+{
+       float f= R.wrld.ao_env_energy*shi->amb;
+
+       if(!((R.r.mode & R_RAYTRACE) || R.wrld.ao_gather_method == WO_AOGATHER_APPROX))
+               return;
+       if(f == 0.0f)
+               return;
+       
+       shr->combined[0] += shi->env[0]*shi->r*shi->refl*f;
+       shr->combined[1] += shi->env[1]*shi->g*shi->refl*f;
+       shr->combined[2] += shi->env[2]*shi->b*shi->refl*f;
+}
+
+static void indirect_lighting_apply(ShadeInput *shi, ShadeResult *shr)
+{
+       float f= R.wrld.ao_indirect_energy;
+
+       if(!((R.r.mode & R_RAYTRACE) || R.wrld.ao_gather_method == WO_AOGATHER_APPROX))
+               return;
+       if(f == 0.0f)
+               return;
+
+       shr->combined[0] += shi->indirect[0]*shi->r*shi->refl*f;
+       shr->combined[1] += shi->indirect[1]*shi->g*shi->refl*f;
+       shr->combined[2] += shi->indirect[2]*shi->b*shi->refl*f;
 }
 
 /* result written in shadfac */
@@ -1112,6 +1129,11 @@ float lamp_get_visibility(LampRen *lar, float *co, float *lv, float *dist)
                                        visifac = lar->dist/(lar->dist + dist[0]);
                                        break;
                                case LA_FALLOFF_INVSQUARE:
+                                       /* NOTE: This seems to be a hack since commit r12045 says this
+                                        * option is similar to old Quad, but with slight changes.
+                                        * Correct inv square would be (which would be old Quad):
+                                        * visifac = lar->distkw / (lar->distkw + dist[0]*dist[0]);
+                                        */
                                        visifac = lar->dist / (lar->dist + dist[0]*dist[0]);
                                        break;
                                case LA_FALLOFF_SLIDERS:
@@ -1362,6 +1384,7 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
                                        }
                                        
                                        i*= shadfac[3];
+                                       shr->shad[3] = shadfac[3]; /* store this for possible check in troublesome cases */
                                }
                        }
                }
@@ -1380,10 +1403,7 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
                        }
                        if(i_noshad>0.0f) {
                                if(passflag & (SCE_PASS_DIFFUSE|SCE_PASS_SHADOW)) {
-                                       if(ma->mode & MA_SHADOW_TRA)
-                                               add_to_diffuse(shr->diff, shi, is, i_noshad*shadfac[0]*lacol[0], i_noshad*shadfac[1]*lacol[1], i_noshad*shadfac[2]*lacol[2]);
-                                       else
-                                               add_to_diffuse(shr->diff, shi, is, i_noshad*lacol[0], i_noshad*lacol[1], i_noshad*lacol[2]);
+                                       add_to_diffuse(shr->diff, shi, is, i_noshad*lacol[0], i_noshad*lacol[1], i_noshad*lacol[2]);
                                }
                                else
                                        VECCOPY(shr->diff, shr->shad);
@@ -1465,10 +1485,10 @@ static void shade_lamp_loop_only_shadow(ShadeInput *shi, ShadeResult *shr)
                float inpr, lv[3];
                float *view, shadfac[4];
                float ir, accum, visifac, lampdist;
+               float shaded = 0.0f, lightness = 0.0f;
                
 
                view= shi->view;
-
                accum= ir= 0.0f;
                
                lights= get_lights(shi);
@@ -1484,47 +1504,99 @@ static void shade_lamp_loop_only_shadow(ShadeInput *shi, ShadeResult *shr)
                        
                        if(lar->shb || (lar->mode & LA_SHAD_RAY)) {
                                visifac= lamp_get_visibility(lar, shi->co, lv, &lampdist);
+                               ir+= 1.0f;
+
                                if(visifac <= 0.0f) {
-                                       ir+= 1.0f;
-                                       accum+= 1.0f;
+                                       if (shi->mat->shadowonly_flag == MA_SO_OLD)
+                                               accum+= 1.0f;
+
                                        continue;
                                }
                                inpr= INPR(shi->vn, lv);
                                if(inpr <= 0.0f) {
-                                       ir+= 1.0f;
-                                       accum+= 1.0f;
+                                       if (shi->mat->shadowonly_flag == MA_SO_OLD)
+                                               accum+= 1.0f;
+
                                        continue;
-                               }                               
+                               }
+
                                lamp_get_shadow(lar, shi, inpr, shadfac, shi->depth);
 
-                               ir+= 1.0f;
-                               accum+= (1.0f-visifac) + (visifac)*shadfac[3];
+                               if (shi->mat->shadowonly_flag == MA_SO_OLD) {
+                                       /* Old "Shadows Only" */
+                                       accum+= (1.0f-visifac) + (visifac)*rgb_to_grayscale(shadfac)*shadfac[3];
+                               }
+                               else {
+                                       shaded += rgb_to_grayscale(shadfac)*shadfac[3] * visifac * lar->energy;
+
+                                       if (shi->mat->shadowonly_flag == MA_SO_SHADOW) {
+                                               lightness += visifac * lar->energy;
+                                       }
+                               }
                        }
                }
+
+               /* Apply shadows as alpha */
                if(ir>0.0f) {
-                       accum/= ir;
-                       shr->alpha= (shi->mat->alpha)*(1.0f-accum);
+                       if (shi->mat->shadowonly_flag == MA_SO_OLD) {
+                               accum = 1.0f - accum/ir;
+                       }
+                       else {
+                               if (shi->mat->shadowonly_flag == MA_SO_SHADOW) {
+                                       if (lightness > 0.0f) {
+                                               /* Get shadow value from between 0.0f and non-shadowed lightness */
+                                               accum = (lightness - shaded) / (lightness);
+                                       }
+                                       else {
+                                               accum = 0.0f;
+                                       }
+                               }
+                               else { /* shadowonly_flag == MA_SO_SHADED */
+                                       /* Use shaded value */
+                                       accum = 1.0f - shaded;
+                       }}
+
+                       shr->alpha= (shi->alpha)*(accum);
+                       if (shr->alpha<0.0f) shr->alpha=0.0f;
+               }
+               else {
+                       /* If "fully shaded", use full alpha even on areas that have no lights */
+                       if (shi->mat->shadowonly_flag == MA_SO_SHADED) shr->alpha=shi->alpha;
+                       else shr->alpha= 0.f;
                }
-               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) {
+       if((R.wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT)) && shi->amb!=0.0f) {
                float f;
                
-               f= 1.0f - shi->ao[0];
-               f= R.wrld.aoenergy*f*shi->amb;
-               
-               if(R.wrld.aomix==WO_AOADD) {
-                       shr->alpha += f;
-                       shr->alpha *= f;
-               }
-               else if(R.wrld.aomix==WO_AOSUB) {
-                       shr->alpha += f;
+               if(R.wrld.mode & WO_AMB_OCC) {
+                       f= R.wrld.aoenergy*shi->amb;
+                       
+                       if(R.wrld.aomix==WO_AOADD) {
+                               if (shi->mat->shadowonly_flag == MA_SO_OLD) {
+                                       f= f*(1.0f - rgb_to_grayscale(shi->ao));
+                                       shr->alpha= (shr->alpha + f)*f;
+                               }
+                               else {
+                                       shr->alpha -= f*rgb_to_grayscale(shi->ao);
+                                       if (shr->alpha<0.0f) shr->alpha=0.0f;
+                               }
+                       }
+                       else /* AO Multiply */
+                               shr->alpha= (1.0f - f)*shr->alpha + f*(1.0f - (1.0f - shr->alpha)*rgb_to_grayscale(shi->ao));
                }
-               else {
-                       shr->alpha *= f;
-                       shr->alpha += f;
+
+               if(R.wrld.mode & WO_ENV_LIGHT) {
+                       if (shi->mat->shadowonly_flag == MA_SO_OLD) {
+                               f= R.wrld.ao_env_energy*shi->amb*(1.0f - rgb_to_grayscale(shi->env));
+                               shr->alpha= (shr->alpha + f)*f;
+                       }
+                       else {
+                               f= R.wrld.ao_env_energy*shi->amb;
+                               shr->alpha -= f*rgb_to_grayscale(shi->env);
+                               if (shr->alpha<0.0f) shr->alpha=0.0f;
+                       }
                }
        }
 }
@@ -1545,6 +1617,8 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
        
        memset(shr, 0, sizeof(ShadeResult));
        
+       if(!(shi->mode & MA_TRANSP)) shi->alpha = 1.0f;
+       
        /* separate loop */
        if(ma->mode & MA_ONLYSHADOW) {
                shade_lamp_loop_only_shadow(shi, shr);
@@ -1561,10 +1635,12 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
                        shi->g= shi->vcol[1];
                        shi->b= shi->vcol[2];
                        if(ma->mode & (MA_FACETEXTURE_ALPHA))
-                               shi->alpha= shi->vcol[3];
+                               shi->alpha= (shi->mode & MA_TRANSP) ? shi->vcol[3] : 1.0f;
                }
-               if(ma->texco)
+               if(ma->texco){
                        do_material_tex(shi);
+                       if (!(shi->mode & MA_TRANSP)) shi->alpha = 1.0f;
+               }
                
                shr->col[0]= shi->r*shi->alpha;
                shr->col[1]= shi->g*shi->alpha;
@@ -1599,25 +1675,28 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
        }
 
        if( (ma->mode & (MA_VERTEXCOL|MA_VERTEXCOLP))== MA_VERTEXCOL ) {        // vertexcolor light
-               shr->diff[0]= shi->r*(shi->emit+shi->vcol[0]);
-               shr->diff[1]= shi->g*(shi->emit+shi->vcol[1]);
-               shr->diff[2]= shi->b*(shi->emit+shi->vcol[2]);
+               shr->emit[0]= shi->r*(shi->emit+shi->vcol[0]);
+               shr->emit[1]= shi->g*(shi->emit+shi->vcol[1]);
+               shr->emit[2]= shi->b*(shi->emit+shi->vcol[2]);
        }
        else {
-               shr->diff[0]= shi->r*shi->emit;
-               shr->diff[1]= shi->g*shi->emit;
-               shr->diff[2]= shi->b*shi->emit;
+               shr->emit[0]= shi->r*shi->emit;
+               shr->emit[1]= shi->g*shi->emit;
+               shr->emit[2]= shi->b*shi->emit;
        }
-       VECCOPY(shr->shad, shr->diff);
        
        /* AO pass */
-       if(R.wrld.mode & WO_AMB_OCC) {
-               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);
-                       VECCOPY(shr->ao, shi->ao);
+       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);
+                               VECCOPY(shr->ao, shi->ao);
+                               VECCOPY(shr->env, shi->env); // XXX multiply
+                               VECCOPY(shr->indirect, shi->indirect); // XXX multiply
+                       }
                }
        }
        
@@ -1694,10 +1773,17 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
                        VECCOPY(shr->combined, shr->diff);
                        
                /* calculate shadow pass, we use a multiplication mask */
-               if(passflag & SCE_PASS_SHADOW) {
+               /* if diff = 0,0,0 it doesn't matter what the shadow pass is, so leave it as is */
+               if(passflag & SCE_PASS_SHADOW && !(shr->diff[0]==0.0f && shr->diff[1]==0.0f && shr->diff[2]==0.0f)) {
                        if(shr->diff[0]!=0.0f) shr->shad[0]= shr->shad[0]/shr->diff[0];
+                       /* can't determine proper shadow from shad/diff (0/0), so use shadow intensity */
+                       else if(shr->shad[0]==0.0f) shr->shad[0]= shr->shad[3];
+
                        if(shr->diff[1]!=0.0f) shr->shad[1]= shr->shad[1]/shr->diff[1];
+                       else if(shr->shad[1]==0.0f) shr->shad[1]= shr->shad[3];
+
                        if(shr->diff[2]!=0.0f) shr->shad[2]= shr->shad[2]/shr->diff[2];
+                       else if(shr->shad[2]==0.0f) shr->shad[2]= shr->shad[3];
                }
                
                /* exposure correction */
@@ -1709,11 +1795,11 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
        
        /* alpha in end, spec can influence it */
        if(passflag & (SCE_PASS_COMBINED)) {
-               if(ma->fresnel_tra!=0.0f) 
+               if((ma->fresnel_tra!=0.0f) && (shi->mode & MA_TRANSP))
                        shi->alpha*= fresnel_fac(shi->view, shi->vn, ma->fresnel_tra_i, ma->fresnel_tra);
                        
                /* note: shi->mode! */
-               if(shi->mode & MA_TRANSP) {
+               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]);
                                t *= shi->spectra;
@@ -1726,32 +1812,24 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
        
        /* from now stuff everything in shr->combined: ambient, AO, radio, ramps, exposure */
        if(!(ma->sss_flag & MA_DIFF_SSS) || !sss_pass_done(&R, ma)) {
+               if(R.r.mode & R_SHADOW) {
+                       /* add AO in combined? */
+                       if(R.wrld.mode & WO_AMB_OCC)
+                               if(shi->combinedflag & SCE_PASS_AO)
+                                       ambient_occlusion_apply(shi, shr);
+
+                       if(R.wrld.mode & WO_ENV_LIGHT)
+                               if(shi->combinedflag & SCE_PASS_ENVIRONMENT)
+                                       environment_lighting_apply(shi, shr);
+
+                       if(R.wrld.mode & WO_INDIRECT_LIGHT)
+                               if(shi->combinedflag & SCE_PASS_INDIRECT)
+                                       indirect_lighting_apply(shi, shr);
+               }
+               
                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 (shr->combined[0] < 0.f) shr->combined[0]= 0.f;
-                               if (shr->combined[1] < 0.f) shr->combined[1]= 0.f;
-                               if (shr->combined[2] < 0.f) shr->combined[2]= 0.f;
-                       }
-               }
                
                if(ma->mode & MA_RAMP_COL) ramp_diffuse_result(shr->combined, shi);
        }
@@ -1774,10 +1852,12 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
                        
        }
        
-       /* and add spec */
+       /* and add emit and spec */
+       if(shi->combinedflag & SCE_PASS_EMIT)
+               VECADD(shr->combined, shr->combined, shr->emit);
        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)) {
@@ -1789,7 +1869,7 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
                        shr->combined[0] *= obcol[0];
                        shr->combined[1] *= obcol[1];
                        shr->combined[2] *= obcol[2];
-                       shr->alpha *= obcol[3];
+                       if (shi->mode & MA_TRANSP) shr->alpha *= obcol[3];
                }
        }