=bmesh= merge from trunk at r36529
[blender.git] / source / blender / render / intern / source / shadeoutput.c
index 130cda9f1072874db5a5daeef2adaf8f125b4052..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 "MTC_matrixops.h"
-#include "BLI_arithb.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"
 extern struct Render R;
 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
 
-static ListBase *get_lights(ShadeInput *shi)
+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
@@ -152,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;
        
@@ -166,7 +173,7 @@ static void spothalo(struct LampRen *lar, ShadeInput *shi, float *intens)
                p1[0]= shi->co[0]-lar->co[0];
                p1[1]= shi->co[1]-lar->co[1];
                p1[2]= -lar->co[2];
-               MTC_Mat3MulVecfl(lar->imat, p1);
+               mul_m3_v3(lar->imat, p1);
                VECCOPY(npos, p1);      // npos is double!
                
                /* pre-scale */
@@ -178,7 +185,7 @@ static void spothalo(struct LampRen *lar, ShadeInput *shi, float *intens)
        
        /* rotate view */
        VECCOPY(nray, shi->view);
-       MTC_Mat3MulVecd(lar->imat, nray);
+       mul_m3_v3_double(lar->imat, nray);
        
        if(R.wrld.mode & WO_MIST) {
                /* patchy... */
@@ -200,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 */ 
@@ -309,7 +316,7 @@ static void spothalo(struct LampRen *lar, ShadeInput *shi, float *intens)
                
                a= sqrt(p1[0]*p1[0]+p1[1]*p1[1]+p1[2]*p1[2]);
                b= sqrt(p2[0]*p2[0]+p2[1]*p2[1]+p2[2]*p2[2]);
-               c= VecLenf(p1, p2);
+               c= len_v3v3(p1, p2);
                
                a/= ladist;
                a= sqrt(a);
@@ -352,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) 
@@ -377,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)
 {
@@ -434,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]);
@@ -445,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];
@@ -487,7 +475,7 @@ static float area_lamp_energy_multisample(LampRen *lar, float *co, float *vn)
                vec[0]= jitlamp[0];
                vec[1]= jitlamp[1];
                vec[2]= 0.0f;
-               Mat3MulVecfl(lar->mat, vec);
+               mul_m3_v3(lar->mat, vec);
                
                VECADD(area[0], lar->area[0], vec);
                VECADD(area[1], lar->area[1], vec);
@@ -551,7 +539,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];
-       Normalize(h);
+       normalize_v3(h);
        
        rslt = h[0]*n[0] + h[1]*n[1] + h[2]*n[2];
        if(tangent) rslt= sasqrt(1.0f - rslt*rslt);
@@ -571,7 +559,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];
-       Normalize(h);
+       normalize_v3(h);
 
        nh= n[0]*h[0]+n[1]*h[1]+n[2]*h[2];
        if(tangent) nh= sasqrt(1.0f - nh*nh);
@@ -604,7 +592,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];
-       Normalize(h);
+       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(tangent) nh= sasqrt(1.0f - nh*nh);
@@ -651,7 +639,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];
-       Normalize(h);
+       normalize_v3(h);
        
        rslt = h[0]*n[0] + h[1]*n[1] + h[2]*n[2];
        if(tangent) rslt = sasqrt(1.0f - rslt*rslt);
@@ -675,7 +663,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];
-       Normalize(h);
+       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(tangent) nh = sasqrt(1.0f - nh*nh);
@@ -719,17 +707,17 @@ 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];
        
        h[0]= v[0]+l[0];
        h[1]= v[1]+l[1];
        h[2]= v[2]+l[2];
-       Normalize(h);
+       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;
@@ -747,12 +735,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]);
-       Normalize( Lit_B );
+       normalize_v3( 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]);
-       Normalize( View_B );
+       normalize_v3( 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;
@@ -871,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;
@@ -1011,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 */
@@ -1110,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:
@@ -1141,7 +1165,7 @@ float lamp_get_visibility(LampRen *lar, float *co, float *lv, float *dist)
                                                        
                                                        /* rotate view to lampspace */
                                                        VECCOPY(lvrot, lv);
-                                                       MTC_Mat3MulVecfl(lar->imat, lvrot);
+                                                       mul_m3_v3(lar->imat, lvrot);
                                                        
                                                        x= MAX2(fabs(lvrot[0]/lvrot[2]) , fabs(lvrot[1]/lvrot[2]));
                                                        /* 1.0f/(sqrt(1+x*x)) is equivalent to cos(atan(x)) */
@@ -1233,27 +1257,27 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
                float cross[3], nstrand[3], blend;
 
                if(ma->mode & MA_STR_SURFDIFF) {
-                       Crossf(cross, shi->surfnor, vn);
-                       Crossf(nstrand, vn, cross);
+                       cross_v3_v3v3(cross, shi->surfnor, vn);
+                       cross_v3_v3v3(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);
+                       interp_v3_v3v3(vnor, nstrand, shi->surfnor, blend);
+                       normalize_v3(vnor);
                }
                else {
-                       Crossf(cross, lv, vn);
-                       Crossf(vnor, cross, vn);
-                       Normalize(vnor);
+                       cross_v3_v3v3(cross, lv, vn);
+                       cross_v3_v3v3(vnor, cross, vn);
+                       normalize_v3(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);
+                               interp_v3_v3v3(vnor, vnor, shi->surfnor, blend);
+                               normalize_v3(vnor);
                        }
                }
 
@@ -1262,9 +1286,9 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
        }
        else if (ma->mode & MA_TANGENT_V) {
                float cross[3];
-               Crossf(cross, lv, shi->tang);
-               Crossf(vnor, cross, shi->tang);
-               Normalize(vnor);
+               cross_v3_v3v3(cross, lv, shi->tang);
+               cross_v3_v3v3(vnor, cross, shi->tang);
+               normalize_v3(vnor);
                vnor[0]= -vnor[0];vnor[1]= -vnor[1];vnor[2]= -vnor[2];
                vn= vnor;
        }
@@ -1360,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 */
                                }
                        }
                }
@@ -1378,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);
@@ -1402,7 +1424,7 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
                                lv[1]+= view[1];
                                lv[2]+= view[2];
                                
-                               Normalize(lv);
+                               normalize_v3(lv);
                                
                                t= vn[0]*lv[0]+vn[1]*lv[1]+vn[2]*lv[2];
                                
@@ -1463,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);
@@ -1482,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;
+                       }
                }
        }
 }
@@ -1543,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);
@@ -1559,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;
@@ -1597,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
+                       }
                }
        }
        
@@ -1660,15 +1741,15 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
 
                                if(texfac==0.0f) {
                                        VECCOPY(col, shr->col);
-                                       VecMulf(col, invalpha);
+                                       mul_v3_fl(col, invalpha);
                                }
                                else if(texfac==1.0f) {
                                        col[0]= col[1]= col[2]= 1.0f;
-                                       VecMulf(col, invalpha);
+                                       mul_v3_fl(col, invalpha);
                                }
                                else {
                                        VECCOPY(col, shr->col);
-                                       VecMulf(col, invalpha);
+                                       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);
@@ -1692,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 */
@@ -1707,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_ZTRA|MA_RAYTRANSP)) {
+               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;
@@ -1724,27 +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;
-
-               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);
        }
@@ -1767,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)) {
@@ -1782,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];
                }
        }