Blender  V2.59
shadeoutput.c
Go to the documentation of this file.
00001 /*
00002 * $Id: shadeoutput.c 37667 2011-06-20 15:17:02Z campbellbarton $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2006 Blender Foundation
00021  * All rights reserved.
00022  *
00023  * Contributors: Hos, Robert Wenzlaff.
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00033 #include <stdio.h>
00034 #include <float.h>
00035 #include <math.h>
00036 #include <string.h>
00037 
00038 #include "BLI_math.h"
00039 #include "BLI_utildefines.h"
00040 
00041 #include "BKE_colortools.h"
00042 #include "BKE_material.h"
00043 #include "BKE_texture.h"
00044 
00045 
00046 #include "DNA_group_types.h"
00047 #include "DNA_lamp_types.h"
00048 #include "DNA_material_types.h"
00049 
00050 /* local include */
00051 #include "occlusion.h"
00052 #include "renderpipeline.h"
00053 #include "render_types.h"
00054 #include "pixelblending.h"
00055 #include "rendercore.h"
00056 #include "shadbuf.h"
00057 #include "sss.h"
00058 #include "texture.h"
00059 
00060 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
00061 /* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
00062 /* only to be used here in this file, it's for speed */
00063 extern struct Render R;
00064 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
00065 
00066 ListBase *get_lights(ShadeInput *shi)
00067 {
00068         
00069         if(R.r.scemode & R_PREVIEWBUTS)
00070                 return &R.lights;
00071         if(shi->light_override)
00072                 return &shi->light_override->gobject;
00073         if(shi->mat && shi->mat->group)
00074                 return &shi->mat->group->gobject;
00075         
00076         return &R.lights;
00077 }
00078 
00079 #if 0
00080 static void fogcolor(float *colf, float *rco, float *view)
00081 {
00082         float alpha, stepsize, startdist, dist, hor[4], zen[3], vec[3], dview[3];
00083         float div=0.0f, distfac;
00084         
00085         hor[0]= R.wrld.horr; hor[1]= R.wrld.horg; hor[2]= R.wrld.horb;
00086         zen[0]= R.wrld.zenr; zen[1]= R.wrld.zeng; zen[2]= R.wrld.zenb;
00087         
00088         VECCOPY(vec, rco);
00089         
00090         /* we loop from cur coord to mist start in steps */
00091         stepsize= 1.0f;
00092         
00093         div= ABS(view[2]);
00094         dview[0]= view[0]/(stepsize*div);
00095         dview[1]= view[1]/(stepsize*div);
00096         dview[2]= -stepsize;
00097 
00098         startdist= -rco[2] + BLI_frand();
00099         for(dist= startdist; dist>R.wrld.miststa; dist-= stepsize) {
00100                 
00101                 hor[0]= R.wrld.horr; hor[1]= R.wrld.horg; hor[2]= R.wrld.horb;
00102                 alpha= 1.0f;
00103                 do_sky_tex(vec, vec, NULL, hor, zen, &alpha);
00104                 
00105                 distfac= (dist-R.wrld.miststa)/R.wrld.mistdist;
00106                 
00107                 hor[3]= hor[0]*distfac*distfac;
00108                 
00109                 /* premul! */
00110                 alpha= hor[3];
00111                 hor[0]= hor[0]*alpha;
00112                 hor[1]= hor[1]*alpha;
00113                 hor[2]= hor[2]*alpha;
00114                 addAlphaOverFloat(colf, hor);
00115                 
00116                 VECSUB(vec, vec, dview);
00117         }       
00118 }
00119 #endif
00120 
00121 /* zcor is distance, co the 3d coordinate in eye space, return alpha */
00122 float mistfactor(float zcor, float *co) 
00123 {
00124         float fac, hi;
00125         
00126         fac= zcor - R.wrld.miststa;     /* zcor is calculated per pixel */
00127 
00128         /* fac= -co[2]-R.wrld.miststa; */
00129 
00130         if(fac>0.0f) {
00131                 if(fac< R.wrld.mistdist) {
00132                         
00133                         fac= (fac/(R.wrld.mistdist));
00134                         
00135                         if(R.wrld.mistype==0) fac*= fac;
00136                         else if(R.wrld.mistype==1);
00137                         else fac= sqrt(fac);
00138                 }
00139                 else fac= 1.0f;
00140         }
00141         else fac= 0.0f;
00142         
00143         /* height switched off mist */
00144         if(R.wrld.misthi!=0.0f && fac!=0.0f) {
00145                 /* at height misthi the mist is completely gone */
00146 
00147                 hi= R.viewinv[0][2]*co[0]+R.viewinv[1][2]*co[1]+R.viewinv[2][2]*co[2]+R.viewinv[3][2];
00148                 
00149                 if(hi>R.wrld.misthi) fac= 0.0f;
00150                 else if(hi>0.0f) {
00151                         hi= (R.wrld.misthi-hi)/R.wrld.misthi;
00152                         fac*= hi*hi;
00153                 }
00154         }
00155 
00156         return (1.0f-fac)* (1.0f-R.wrld.misi);  
00157 }
00158 
00159 static void spothalo(struct LampRen *lar, ShadeInput *shi, float *intens)
00160 {
00161         double a, b, c, disc, nray[3], npos[3];
00162         double t0, t1 = 0.0f, t2= 0.0f, t3;
00163         float p1[3], p2[3], ladist, maxz = 0.0f, maxy = 0.0f, haint;
00164         int snijp, doclip=1, use_yco=0;
00165         int ok1=0, ok2=0;
00166         
00167         *intens= 0.0f;
00168         haint= lar->haint;
00169         
00170         if(R.r.mode & R_ORTHO) {
00171                 /* camera pos (view vector) cannot be used... */
00172                 /* camera position (cox,coy,0) rotate around lamp */
00173                 p1[0]= shi->co[0]-lar->co[0];
00174                 p1[1]= shi->co[1]-lar->co[1];
00175                 p1[2]= -lar->co[2];
00176                 mul_m3_v3(lar->imat, p1);
00177                 VECCOPY(npos, p1);      // npos is double!
00178                 
00179                 /* pre-scale */
00180                 npos[2]*= lar->sh_zfac;
00181         }
00182         else {
00183                 VECCOPY(npos, lar->sh_invcampos);       /* in initlamp calculated */
00184         }
00185         
00186         /* rotate view */
00187         VECCOPY(nray, shi->view);
00188         mul_m3_v3_double(lar->imat, nray);
00189         
00190         if(R.wrld.mode & WO_MIST) {
00191                 /* patchy... */
00192                 haint *= mistfactor(-lar->co[2], lar->co);
00193                 if(haint==0.0f) {
00194                         return;
00195                 }
00196         }
00197 
00198 
00199         /* rotate maxz */
00200         if(shi->co[2]==0.0f) doclip= 0; /* for when halo at sky */
00201         else {
00202                 p1[0]= shi->co[0]-lar->co[0];
00203                 p1[1]= shi->co[1]-lar->co[1];
00204                 p1[2]= shi->co[2]-lar->co[2];
00205         
00206                 maxz= lar->imat[0][2]*p1[0]+lar->imat[1][2]*p1[1]+lar->imat[2][2]*p1[2];
00207                 maxz*= lar->sh_zfac;
00208                 maxy= lar->imat[0][1]*p1[0]+lar->imat[1][1]*p1[1]+lar->imat[2][1]*p1[2];
00209 
00210                 if( fabs(nray[2]) < FLT_EPSILON ) use_yco= 1;
00211         }
00212         
00213         /* scale z to make sure volume is normalized */ 
00214         nray[2]*= lar->sh_zfac;
00215         /* nray does not need normalization */
00216         
00217         ladist= lar->sh_zfac*lar->dist;
00218         
00219         /* solve */
00220         a = nray[0] * nray[0] + nray[1] * nray[1] - nray[2]*nray[2];
00221         b = nray[0] * npos[0] + nray[1] * npos[1] - nray[2]*npos[2];
00222         c = npos[0] * npos[0] + npos[1] * npos[1] - npos[2]*npos[2];
00223 
00224         snijp= 0;
00225         if (fabs(a) < DBL_EPSILON) {
00226                 /*
00227                  * Only one intersection point...
00228                  */
00229                 return;
00230         }
00231         else {
00232                 disc = b*b - a*c;
00233                 
00234                 if(disc==0.0) {
00235                         t1=t2= (-b)/ a;
00236                         snijp= 2;
00237                 }
00238                 else if (disc > 0.0) {
00239                         disc = sqrt(disc);
00240                         t1 = (-b + disc) / a;
00241                         t2 = (-b - disc) / a;
00242                         snijp= 2;
00243                 }
00244         }
00245         if(snijp==2) {
00246                 /* sort */
00247                 if(t1>t2) {
00248                         a= t1; t1= t2; t2= a;
00249                 }
00250 
00251                 /* z of intersection points with diabolo */
00252                 p1[2]= npos[2] + t1*nray[2];
00253                 p2[2]= npos[2] + t2*nray[2];
00254 
00255                 /* evaluate both points */
00256                 if(p1[2]<=0.0f) ok1= 1;
00257                 if(p2[2]<=0.0f && t1!=t2) ok2= 1;
00258                 
00259                 /* at least 1 point with negative z */
00260                 if(ok1==0 && ok2==0) return;
00261                 
00262                 /* intersction point with -ladist, the bottom of the cone */
00263                 if(use_yco==0) {
00264                         t3= (-ladist-npos[2])/nray[2];
00265                                 
00266                         /* de we have to replace one of the intersection points? */
00267                         if(ok1) {
00268                                 if(p1[2]<-ladist) t1= t3;
00269                         }
00270                         else {
00271                                 ok1= 1;
00272                                 t1= t3;
00273                         }
00274                         if(ok2) {
00275                                 if(p2[2]<-ladist) t2= t3;
00276                         }
00277                         else {
00278                                 ok2= 1;
00279                                 t2= t3;
00280                         }
00281                 }
00282                 else if(ok1==0 || ok2==0) return;
00283                 
00284                 /* at least 1 visible interesction point */
00285                 if(t1<0.0f && t2<0.0f) return;
00286                 
00287                 if(t1<0.0f) t1= 0.0f;
00288                 if(t2<0.0f) t2= 0.0f;
00289                 
00290                 if(t1==t2) return;
00291                 
00292                 /* sort again to be sure */
00293                 if(t1>t2) {
00294                         a= t1; t1= t2; t2= a;
00295                 }
00296                 
00297                 /* calculate t0: is the maximum visible z (when halo is intersected by face) */ 
00298                 if(doclip) {
00299                         if(use_yco==0) t0= (maxz-npos[2])/nray[2];
00300                         else t0= (maxy-npos[1])/nray[1];
00301 
00302                         if(t0<t1) return;
00303                         if(t0<t2) t2= t0;
00304                 }
00305 
00306                 /* calc points */
00307                 p1[0]= npos[0] + t1*nray[0];
00308                 p1[1]= npos[1] + t1*nray[1];
00309                 p1[2]= npos[2] + t1*nray[2];
00310                 p2[0]= npos[0] + t2*nray[0];
00311                 p2[1]= npos[1] + t2*nray[1];
00312                 p2[2]= npos[2] + t2*nray[2];
00313                 
00314                         
00315                 /* now we have 2 points, make three lengths with it */
00316                 
00317                 a= sqrt(p1[0]*p1[0]+p1[1]*p1[1]+p1[2]*p1[2]);
00318                 b= sqrt(p2[0]*p2[0]+p2[1]*p2[1]+p2[2]*p2[2]);
00319                 c= len_v3v3(p1, p2);
00320                 
00321                 a/= ladist;
00322                 a= sqrt(a);
00323                 b/= ladist; 
00324                 b= sqrt(b);
00325                 c/= ladist;
00326                 
00327                 *intens= c*( (1.0-a)+(1.0-b) );
00328 
00329                 /* WATCH IT: do not clip a,b en c at 1.0, this gives nasty little overflows
00330                         at the edges (especially with narrow halos) */
00331                 if(*intens<=0.0f) return;
00332 
00333                 /* soft area */
00334                 /* not needed because t0 has been used for p1/p2 as well */
00335                 /* if(doclip && t0<t2) { */
00336                 /*      *intens *= (t0-t1)/(t2-t1); */
00337                 /* } */
00338                 
00339                 *intens *= haint;
00340                 
00341                 if(lar->shb && lar->shb->shadhalostep) {
00342                         *intens *= shadow_halo(lar, p1, p2);
00343                 }
00344                 
00345         }
00346 }
00347 
00348 void renderspothalo(ShadeInput *shi, float *col, float alpha)
00349 {
00350         ListBase *lights;
00351         GroupObject *go;
00352         LampRen *lar;
00353         float i;
00354         
00355         if(alpha==0.0f) return;
00356         
00357         lights= get_lights(shi);
00358         for(go=lights->first; go; go= go->next) {
00359                 lar= go->lampren;
00360                 if(lar==NULL) continue;
00361                 
00362                 if(lar->type==LA_SPOT && (lar->mode & LA_HALO) && (lar->buftype != LA_SHADBUF_DEEP) && lar->haint>0) {
00363                         
00364                         if(lar->mode & LA_LAYER) 
00365                                 if(shi->vlr && (lar->lay & shi->obi->lay)==0) 
00366                                         continue;
00367                         if((lar->lay & shi->lay)==0) 
00368                                 continue;
00369                         
00370                         spothalo(lar, shi, &i);
00371                         if(i>0.0f) {
00372                                 col[3]+= i*alpha;                       // all premul
00373                                 col[0]+= i*lar->r*alpha;
00374                                 col[1]+= i*lar->g*alpha;
00375                                 col[2]+= i*lar->b*alpha;        
00376                         }
00377                 }
00378         }
00379         /* clip alpha, is needed for unified 'alpha threshold' (vanillaRenderPipe.c) */
00380         if(col[3]>1.0f) col[3]= 1.0f;
00381 }
00382 
00383 
00384 
00385 /* ---------------- shaders ----------------------- */
00386 
00387 static double Normalize_d(double *n)
00388 {
00389         double d;
00390         
00391         d= n[0]*n[0]+n[1]*n[1]+n[2]*n[2];
00392 
00393         if(d>0.00000000000000001) {
00394                 d= sqrt(d);
00395 
00396                 n[0]/=d; 
00397                 n[1]/=d; 
00398                 n[2]/=d;
00399         } else {
00400                 n[0]=n[1]=n[2]= 0.0;
00401                 d= 0.0;
00402         }
00403         return d;
00404 }
00405 
00406 /* mix of 'real' fresnel and allowing control. grad defines blending gradient */
00407 float fresnel_fac(float *view, float *vn, float grad, float fac)
00408 {
00409         float t1, t2;
00410         
00411         if(fac==0.0f) return 1.0f;
00412         
00413         t1= (view[0]*vn[0] + view[1]*vn[1] + view[2]*vn[2]);
00414         if(t1>0.0f)  t2= 1.0f+t1;
00415         else t2= 1.0f-t1;
00416         
00417         t2= grad + (1.0f-grad)*pow(t2, fac);
00418         
00419         if(t2<0.0f) return 0.0f;
00420         else if(t2>1.0f) return 1.0f;
00421         return t2;
00422 }
00423 
00424 static double saacos_d(double fac)
00425 {
00426         if(fac<= -1.0f) return M_PI;
00427         else if(fac>=1.0f) return 0.0;
00428         else return acos(fac);
00429 }
00430 
00431 /* Stoke's form factor. Need doubles here for extreme small area sizes */
00432 static float area_lamp_energy(float (*area)[3], float *co, float *vn)
00433 {
00434         double fac;
00435         double vec[4][3];       /* vectors of rendered co to vertices lamp */
00436         double cross[4][3];     /* cross products of this */
00437         double rad[4];          /* angles between vecs */
00438 
00439         VECSUB(vec[0], co, area[0]);
00440         VECSUB(vec[1], co, area[1]);
00441         VECSUB(vec[2], co, area[2]);
00442         VECSUB(vec[3], co, area[3]);
00443         
00444         Normalize_d(vec[0]);
00445         Normalize_d(vec[1]);
00446         Normalize_d(vec[2]);
00447         Normalize_d(vec[3]);
00448 
00449         /* cross product */
00450         CROSS(cross[0], vec[0], vec[1]);
00451         CROSS(cross[1], vec[1], vec[2]);
00452         CROSS(cross[2], vec[2], vec[3]);
00453         CROSS(cross[3], vec[3], vec[0]);
00454 
00455         Normalize_d(cross[0]);
00456         Normalize_d(cross[1]);
00457         Normalize_d(cross[2]);
00458         Normalize_d(cross[3]);
00459 
00460         /* angles */
00461         rad[0]= vec[0][0]*vec[1][0]+ vec[0][1]*vec[1][1]+ vec[0][2]*vec[1][2];
00462         rad[1]= vec[1][0]*vec[2][0]+ vec[1][1]*vec[2][1]+ vec[1][2]*vec[2][2];
00463         rad[2]= vec[2][0]*vec[3][0]+ vec[2][1]*vec[3][1]+ vec[2][2]*vec[3][2];
00464         rad[3]= vec[3][0]*vec[0][0]+ vec[3][1]*vec[0][1]+ vec[3][2]*vec[0][2];
00465 
00466         rad[0]= saacos_d(rad[0]);
00467         rad[1]= saacos_d(rad[1]);
00468         rad[2]= saacos_d(rad[2]);
00469         rad[3]= saacos_d(rad[3]);
00470 
00471         /* Stoke formula */
00472         fac=  rad[0]*(vn[0]*cross[0][0]+ vn[1]*cross[0][1]+ vn[2]*cross[0][2]);
00473         fac+= rad[1]*(vn[0]*cross[1][0]+ vn[1]*cross[1][1]+ vn[2]*cross[1][2]);
00474         fac+= rad[2]*(vn[0]*cross[2][0]+ vn[1]*cross[2][1]+ vn[2]*cross[2][2]);
00475         fac+= rad[3]*(vn[0]*cross[3][0]+ vn[1]*cross[3][1]+ vn[2]*cross[3][2]);
00476 
00477         if(fac<=0.0) return 0.0;
00478         return fac;
00479 }
00480 
00481 static float area_lamp_energy_multisample(LampRen *lar, float *co, float *vn)
00482 {
00483         /* corner vectors are moved around according lamp jitter */
00484         float *jitlamp= lar->jitter, vec[3];
00485         float area[4][3], intens= 0.0f;
00486         int a= lar->ray_totsamp;
00487 
00488         /* test if co is behind lamp */
00489         VECSUB(vec, co, lar->co);
00490         if(INPR(vec, lar->vec) < 0.0f)
00491                 return 0.0f;
00492 
00493         while(a--) {
00494                 vec[0]= jitlamp[0];
00495                 vec[1]= jitlamp[1];
00496                 vec[2]= 0.0f;
00497                 mul_m3_v3(lar->mat, vec);
00498                 
00499                 VECADD(area[0], lar->area[0], vec);
00500                 VECADD(area[1], lar->area[1], vec);
00501                 VECADD(area[2], lar->area[2], vec);
00502                 VECADD(area[3], lar->area[3], vec);
00503                 
00504                 intens+= area_lamp_energy(area, co, vn);
00505                 
00506                 jitlamp+= 2;
00507         }
00508         intens /= (float)lar->ray_totsamp;
00509         
00510         return pow(intens*lar->areasize, lar->k);       // corrected for buttons size and lar->dist^2
00511 }
00512 
00513 static float spec(float inp, int hard)  
00514 {
00515         float b1;
00516         
00517         if(inp>=1.0f) return 1.0f;
00518         else if (inp<=0.0f) return 0.0f;
00519         
00520         b1= inp*inp;
00521         /* avoid FPE */
00522         if(b1<0.01f) b1= 0.01f; 
00523         
00524         if((hard & 1)==0)  inp= 1.0f;
00525         if(hard & 2)  inp*= b1;
00526         b1*= b1;
00527         if(hard & 4)  inp*= b1;
00528         b1*= b1;
00529         if(hard & 8)  inp*= b1;
00530         b1*= b1;
00531         if(hard & 16) inp*= b1;
00532         b1*= b1;
00533 
00534         /* avoid FPE */
00535         if(b1<0.001f) b1= 0.0f; 
00536 
00537         if(hard & 32) inp*= b1;
00538         b1*= b1;
00539         if(hard & 64) inp*=b1;
00540         b1*= b1;
00541         if(hard & 128) inp*=b1;
00542 
00543         if(b1<0.001f) b1= 0.0f; 
00544 
00545         if(hard & 256) {
00546                 b1*= b1;
00547                 inp*=b1;
00548         }
00549 
00550         return inp;
00551 }
00552 
00553 static float Phong_Spec( float *n, float *l, float *v, int hard, int tangent )
00554 {
00555         float h[3];
00556         float rslt;
00557         
00558         h[0] = l[0] + v[0];
00559         h[1] = l[1] + v[1];
00560         h[2] = l[2] + v[2];
00561         normalize_v3(h);
00562         
00563         rslt = h[0]*n[0] + h[1]*n[1] + h[2]*n[2];
00564         if(tangent) rslt= sasqrt(1.0f - rslt*rslt);
00565                 
00566         if( rslt > 0.0f ) rslt= spec(rslt, hard);
00567         else rslt = 0.0f;
00568         
00569         return rslt;
00570 }
00571 
00572 
00573 /* reduced cook torrance spec (for off-specular peak) */
00574 static float CookTorr_Spec(float *n, float *l, float *v, int hard, int tangent)
00575 {
00576         float i, nh, nv, h[3];
00577 
00578         h[0]= v[0]+l[0];
00579         h[1]= v[1]+l[1];
00580         h[2]= v[2]+l[2];
00581         normalize_v3(h);
00582 
00583         nh= n[0]*h[0]+n[1]*h[1]+n[2]*h[2];
00584         if(tangent) nh= sasqrt(1.0f - nh*nh);
00585         else if(nh<0.0f) return 0.0f;
00586         
00587         nv= n[0]*v[0]+n[1]*v[1]+n[2]*v[2];
00588         if(tangent) nv= sasqrt(1.0f - nv*nv);
00589         else if(nv<0.0f) nv= 0.0f;
00590 
00591         i= spec(nh, hard);
00592 
00593         i= i/(0.1+nv);
00594         return i;
00595 }
00596 
00597 /* Blinn spec */
00598 static float Blinn_Spec(float *n, float *l, float *v, float refrac, float spec_power, int tangent)
00599 {
00600         float i, nh, nv, nl, vh, h[3];
00601         float a, b, c, g=0.0f, p, f, ang;
00602 
00603         if(refrac < 1.0f) return 0.0f;
00604         if(spec_power == 0.0f) return 0.0f;
00605         
00606         /* conversion from 'hardness' (1-255) to 'spec_power' (50 maps at 0.1) */
00607         if(spec_power<100.0f)
00608                 spec_power= sqrt(1.0f/spec_power);
00609         else spec_power= 10.0f/spec_power;
00610         
00611         h[0]= v[0]+l[0];
00612         h[1]= v[1]+l[1];
00613         h[2]= v[2]+l[2];
00614         normalize_v3(h);
00615 
00616         nh= n[0]*h[0]+n[1]*h[1]+n[2]*h[2]; /* Dot product between surface normal and half-way vector */
00617         if(tangent) nh= sasqrt(1.0f - nh*nh);
00618         else if(nh<0.0f) return 0.0f;
00619 
00620         nv= n[0]*v[0]+n[1]*v[1]+n[2]*v[2]; /* Dot product between surface normal and view vector */
00621         if(tangent) nv= sasqrt(1.0f - nv*nv);
00622         if(nv<=0.01f) nv= 0.01f;                                /* hrms... */
00623 
00624         nl= n[0]*l[0]+n[1]*l[1]+n[2]*l[2]; /* Dot product between surface normal and light vector */
00625         if(tangent) nl= sasqrt(1.0f - nl*nl);
00626         if(nl<=0.01f) {
00627                 return 0.0f;
00628         }
00629 
00630         vh= v[0]*h[0]+v[1]*h[1]+v[2]*h[2]; /* Dot product between view vector and half-way vector */
00631         if(vh<=0.0f) vh= 0.01f;
00632 
00633         a = 1.0f;
00634         b = (2.0f*nh*nv)/vh;
00635         c = (2.0f*nh*nl)/vh;
00636 
00637         if( a < b && a < c ) g = a;
00638         else if( b < a && b < c ) g = b;
00639         else if( c < a && c < b ) g = c;
00640 
00641         p = sqrt( (double)((refrac * refrac)+(vh*vh)-1.0f) );
00642         f = (((p-vh)*(p-vh))/((p+vh)*(p+vh)))*(1+((((vh*(p+vh))-1.0f)*((vh*(p+vh))-1.0f))/(((vh*(p-vh))+1.0f)*((vh*(p-vh))+1.0f))));
00643         ang = saacos(nh);
00644 
00645         i= f * g * exp((double)(-(ang*ang) / (2.0f*spec_power*spec_power)));
00646         if(i<0.0f) i= 0.0f;
00647         
00648         return i;
00649 }
00650 
00651 /* cartoon render spec */
00652 static float Toon_Spec( float *n, float *l, float *v, float size, float smooth, int tangent)
00653 {
00654         float h[3];
00655         float ang;
00656         float rslt;
00657         
00658         h[0] = l[0] + v[0];
00659         h[1] = l[1] + v[1];
00660         h[2] = l[2] + v[2];
00661         normalize_v3(h);
00662         
00663         rslt = h[0]*n[0] + h[1]*n[1] + h[2]*n[2];
00664         if(tangent) rslt = sasqrt(1.0f - rslt*rslt);
00665         
00666         ang = saacos( rslt ); 
00667         
00668         if( ang < size ) rslt = 1.0f;
00669         else if( ang >= (size + smooth) || smooth == 0.0f ) rslt = 0.0f;
00670         else rslt = 1.0f - ((ang - size) / smooth);
00671         
00672         return rslt;
00673 }
00674 
00675 /* Ward isotropic gaussian spec */
00676 static float WardIso_Spec( float *n, float *l, float *v, float rms, int tangent)
00677 {
00678         float i, nh, nv, nl, h[3], angle, alpha;
00679 
00680 
00681         /* half-way vector */
00682         h[0] = l[0] + v[0];
00683         h[1] = l[1] + v[1];
00684         h[2] = l[2] + v[2];
00685         normalize_v3(h);
00686 
00687         nh = n[0]*h[0]+n[1]*h[1]+n[2]*h[2]; /* Dot product between surface normal and half-way vector */
00688         if(tangent) nh = sasqrt(1.0f - nh*nh);
00689         if(nh<=0.0f) nh = 0.001f;
00690         
00691         nv = n[0]*v[0]+n[1]*v[1]+n[2]*v[2]; /* Dot product between surface normal and view vector */
00692         if(tangent) nv = sasqrt(1.0f - nv*nv);
00693         if(nv<=0.0f) nv = 0.001f;
00694 
00695         nl = n[0]*l[0]+n[1]*l[1]+n[2]*l[2]; /* Dot product between surface normal and light vector */
00696         if(tangent) nl = sasqrt(1.0f - nl*nl);
00697         if(nl<=0.0f) nl = 0.001f;
00698 
00699         angle = tan(saacos(nh));
00700         alpha = MAX2(rms, 0.001f);
00701 
00702         i= nl * (1.0f/(4.0f*M_PI*alpha*alpha)) * (exp( -(angle*angle)/(alpha*alpha))/(sqrt(nv*nl)));
00703 
00704         return i;
00705 }
00706 
00707 /* cartoon render diffuse */
00708 static float Toon_Diff( float *n, float *l, float *UNUSED(v), float size, float smooth )
00709 {
00710         float rslt, ang;
00711 
00712         rslt = n[0]*l[0] + n[1]*l[1] + n[2]*l[2];
00713 
00714         ang = saacos( (double)(rslt) );
00715 
00716         if( ang < size ) rslt = 1.0f;
00717         else if( ang >= (size + smooth) || smooth == 0.0f ) rslt = 0.0f;
00718         else rslt = 1.0f - ((ang - size) / smooth);
00719 
00720         return rslt;
00721 }
00722 
00723 /* Oren Nayar diffuse */
00724 
00725 /* 'nl' is either dot product, or return value of area light */
00726 /* in latter case, only last multiplication uses 'nl' */
00727 static float OrenNayar_Diff(float nl, float *n, float *l, float *v, float rough )
00728 {
00729         float i/*, nh*/, nv, vh, realnl, h[3];
00730         float a, b, t, A, B;
00731         float Lit_A, View_A, Lit_B[3], View_B[3];
00732         
00733         h[0]= v[0]+l[0];
00734         h[1]= v[1]+l[1];
00735         h[2]= v[2]+l[2];
00736         normalize_v3(h);
00737         
00738         /* nh= n[0]*h[0]+n[1]*h[1]+n[2]*h[2]; */ /* Dot product between surface normal and half-way vector */
00739         /* if(nh<0.0f) nh = 0.0f; */
00740         
00741         nv= n[0]*v[0]+n[1]*v[1]+n[2]*v[2]; /* Dot product between surface normal and view vector */
00742         if(nv<=0.0f) nv= 0.0f;
00743         
00744         realnl= n[0]*l[0]+n[1]*l[1]+n[2]*l[2]; /* Dot product between surface normal and light vector */
00745         if(realnl<=0.0f) return 0.0f;
00746         if(nl<0.0f) return 0.0f;                /* value from area light */
00747         
00748         vh= v[0]*h[0]+v[1]*h[1]+v[2]*h[2]; /* Dot product between view vector and halfway vector */
00749         if(vh<=0.0f) vh= 0.0f;
00750         
00751         Lit_A = saacos(realnl);
00752         View_A = saacos( nv );
00753         
00754         Lit_B[0] = l[0] - (realnl * n[0]);
00755         Lit_B[1] = l[1] - (realnl * n[1]);
00756         Lit_B[2] = l[2] - (realnl * n[2]);
00757         normalize_v3( Lit_B );
00758         
00759         View_B[0] = v[0] - (nv * n[0]);
00760         View_B[1] = v[1] - (nv * n[1]);
00761         View_B[2] = v[2] - (nv * n[2]);
00762         normalize_v3( View_B );
00763         
00764         t = Lit_B[0]*View_B[0] + Lit_B[1]*View_B[1] + Lit_B[2]*View_B[2];
00765         if( t < 0 ) t = 0;
00766         
00767         if( Lit_A > View_A ) {
00768                 a = Lit_A;
00769                 b = View_A;
00770         }
00771         else {
00772                 a = View_A;
00773                 b = Lit_A;
00774         }
00775         
00776         A = 1.0f - (0.5f * ((rough * rough) / ((rough * rough) + 0.33f)));
00777         B = 0.45f * ((rough * rough) / ((rough * rough) + 0.09f));
00778         
00779         b*= 0.95f;      /* prevent tangens from shooting to inf, 'nl' can be not a dot product here. */
00780                                 /* overflow only happens with extreme size area light, and higher roughness */
00781         i = nl * ( A + ( B * t * sin(a) * tan(b) ) );
00782         
00783         return i;
00784 }
00785 
00786 /* Minnaert diffuse */
00787 static float Minnaert_Diff(float nl, float *n, float *v, float darkness)
00788 {
00789 
00790         float i, nv;
00791 
00792         /* nl = dot product between surface normal and light vector */
00793         if (nl <= 0.0f)
00794                 return 0.0f;
00795 
00796         /* nv = dot product between surface normal and view vector */
00797         nv = n[0]*v[0]+n[1]*v[1]+n[2]*v[2];
00798         if (nv < 0.0f)
00799                 nv = 0.0f;
00800 
00801         if (darkness <= 1.0f)
00802                 i = nl * pow(MAX2(nv*nl, 0.1f), (darkness - 1.0f) ); /*The Real model*/
00803         else
00804                 i = nl * pow( (1.001f - nv), (darkness  - 1.0f) ); /*Nvidia model*/
00805 
00806         return i;
00807 }
00808 
00809 static float Fresnel_Diff(float *vn, float *lv, float *UNUSED(view), float fac_i, float fac)
00810 {
00811         return fresnel_fac(lv, vn, fac_i, fac);
00812 }
00813 
00814 /* --------------------------------------------- */
00815 /* also called from texture.c */
00816 void calc_R_ref(ShadeInput *shi)
00817 {
00818         float i;
00819 
00820         /* shi->vn dot shi->view */
00821         i= -2*(shi->vn[0]*shi->view[0]+shi->vn[1]*shi->view[1]+shi->vn[2]*shi->view[2]);
00822 
00823         shi->ref[0]= (shi->view[0]+i*shi->vn[0]);
00824         shi->ref[1]= (shi->view[1]+i*shi->vn[1]);
00825         shi->ref[2]= (shi->view[2]+i*shi->vn[2]);
00826         if(shi->osatex) {
00827                 if(shi->vlr->flag & R_SMOOTH) {
00828                         i= -2*( (shi->vn[0]+shi->dxno[0])*(shi->view[0]+shi->dxview) +
00829                                 (shi->vn[1]+shi->dxno[1])*shi->view[1]+ (shi->vn[2]+shi->dxno[2])*shi->view[2] );
00830 
00831                         shi->dxref[0]= shi->ref[0]- ( shi->view[0]+shi->dxview+i*(shi->vn[0]+shi->dxno[0]));
00832                         shi->dxref[1]= shi->ref[1]- (shi->view[1]+ i*(shi->vn[1]+shi->dxno[1]));
00833                         shi->dxref[2]= shi->ref[2]- (shi->view[2]+ i*(shi->vn[2]+shi->dxno[2]));
00834 
00835                         i= -2*( (shi->vn[0]+shi->dyno[0])*shi->view[0]+
00836                                 (shi->vn[1]+shi->dyno[1])*(shi->view[1]+shi->dyview)+ (shi->vn[2]+shi->dyno[2])*shi->view[2] );
00837 
00838                         shi->dyref[0]= shi->ref[0]- (shi->view[0]+ i*(shi->vn[0]+shi->dyno[0]));
00839                         shi->dyref[1]= shi->ref[1]- (shi->view[1]+shi->dyview+i*(shi->vn[1]+shi->dyno[1]));
00840                         shi->dyref[2]= shi->ref[2]- (shi->view[2]+ i*(shi->vn[2]+shi->dyno[2]));
00841 
00842                 }
00843                 else {
00844 
00845                         i= -2*( shi->vn[0]*(shi->view[0]+shi->dxview) +
00846                                 shi->vn[1]*shi->view[1]+ shi->vn[2]*shi->view[2] );
00847 
00848                         shi->dxref[0]= shi->ref[0]- (shi->view[0]+shi->dxview+i*shi->vn[0]);
00849                         shi->dxref[1]= shi->ref[1]- (shi->view[1]+ i*shi->vn[1]);
00850                         shi->dxref[2]= shi->ref[2]- (shi->view[2]+ i*shi->vn[2]);
00851 
00852                         i= -2*( shi->vn[0]*shi->view[0]+
00853                                 shi->vn[1]*(shi->view[1]+shi->dyview)+ shi->vn[2]*shi->view[2] );
00854 
00855                         shi->dyref[0]= shi->ref[0]- (shi->view[0]+ i*shi->vn[0]);
00856                         shi->dyref[1]= shi->ref[1]- (shi->view[1]+shi->dyview+i*shi->vn[1]);
00857                         shi->dyref[2]= shi->ref[2]- (shi->view[2]+ i*shi->vn[2]);
00858                 }
00859         }
00860 
00861 }
00862 
00863 /* called from ray.c */
00864 void shade_color(ShadeInput *shi, ShadeResult *shr)
00865 {
00866         Material *ma= shi->mat;
00867 
00868         if(ma->mode & (MA_VERTEXCOLP|MA_FACETEXTURE)) {
00869                 shi->r= shi->vcol[0];
00870                 shi->g= shi->vcol[1];
00871                 shi->b= shi->vcol[2];
00872                 if(ma->mode & (MA_FACETEXTURE_ALPHA))
00873                         shi->alpha= shi->vcol[3];
00874         }
00875         
00876         if(ma->texco)
00877                 do_material_tex(shi);
00878 
00879         if(ma->fresnel_tra!=0.0f) 
00880                 shi->alpha*= fresnel_fac(shi->view, shi->vn, ma->fresnel_tra_i, ma->fresnel_tra);
00881         
00882         if (!(shi->mode & MA_TRANSP)) shi->alpha= 1.0f;
00883         
00884         shr->diff[0]= shi->r;
00885         shr->diff[1]= shi->g;
00886         shr->diff[2]= shi->b;
00887         shr->alpha= shi->alpha;
00888 }
00889 
00890 /* ramp for at end of shade */
00891 static void ramp_diffuse_result(float *diff, ShadeInput *shi)
00892 {
00893         Material *ma= shi->mat;
00894         float col[4], fac=0;
00895 
00896         if(ma->ramp_col) {
00897                 if(ma->rampin_col==MA_RAMP_IN_RESULT) {
00898                         
00899                         fac= 0.3*diff[0] + 0.58*diff[1] + 0.12*diff[2];
00900                         do_colorband(ma->ramp_col, fac, col);
00901                         
00902                         /* blending method */
00903                         fac= col[3]*ma->rampfac_col;
00904                         
00905                         ramp_blend(ma->rampblend_col, diff, diff+1, diff+2, fac, col);
00906                 }
00907         }
00908 }
00909 
00910 /* r,g,b denote energy, ramp is used with different values to make new material color */
00911 static void add_to_diffuse(float *diff, ShadeInput *shi, float is, float r, float g, float b)
00912 {
00913         Material *ma= shi->mat;
00914         float col[4], colt[3], fac=0;
00915         
00916         if(ma->ramp_col && (ma->mode & MA_RAMP_COL)) {
00917                 
00918                 /* MA_RAMP_IN_RESULT is exceptional */
00919                 if(ma->rampin_col==MA_RAMP_IN_RESULT) {
00920                         // normal add
00921                         diff[0] += r * shi->r;
00922                         diff[1] += g * shi->g;
00923                         diff[2] += b * shi->b;
00924                 }
00925                 else {
00926                         /* input */
00927                         switch(ma->rampin_col) {
00928                         case MA_RAMP_IN_ENERGY:
00929                                 fac= 0.3*r + 0.58*g + 0.12*b;
00930                                 break;
00931                         case MA_RAMP_IN_SHADER:
00932                                 fac= is;
00933                                 break;
00934                         case MA_RAMP_IN_NOR:
00935                                 fac= shi->view[0]*shi->vn[0] + shi->view[1]*shi->vn[1] + shi->view[2]*shi->vn[2];
00936                                 break;
00937                         }
00938         
00939                         do_colorband(ma->ramp_col, fac, col);
00940                         
00941                         /* blending method */
00942                         fac= col[3]*ma->rampfac_col;
00943                         colt[0]= shi->r;
00944                         colt[1]= shi->g;
00945                         colt[2]= shi->b;
00946 
00947                         ramp_blend(ma->rampblend_col, colt, colt+1, colt+2, fac, col);
00948 
00949                         /* output to */
00950                         diff[0] += r * colt[0];
00951                         diff[1] += g * colt[1];
00952                         diff[2] += b * colt[2];
00953                 }
00954         }
00955         else {
00956                 diff[0] += r * shi->r;
00957                 diff[1] += g * shi->g;
00958                 diff[2] += b * shi->b;
00959         }
00960 }
00961 
00962 static void ramp_spec_result(float *specr, float *specg, float *specb, ShadeInput *shi)
00963 {
00964         Material *ma= shi->mat;
00965         float col[4];
00966         float fac;
00967         
00968         if(ma->ramp_spec && (ma->rampin_spec==MA_RAMP_IN_RESULT)) {
00969                 fac= 0.3*(*specr) + 0.58*(*specg) + 0.12*(*specb);
00970                 do_colorband(ma->ramp_spec, fac, col);
00971                 
00972                 /* blending method */
00973                 fac= col[3]*ma->rampfac_spec;
00974                 
00975                 ramp_blend(ma->rampblend_spec, specr, specg, specb, fac, col);
00976                 
00977         }
00978 }
00979 
00980 /* is = dot product shade, t = spec energy */
00981 static void do_specular_ramp(ShadeInput *shi, float is, float t, float *spec)
00982 {
00983         Material *ma= shi->mat;
00984         float col[4];
00985         float fac=0.0f;
00986         
00987         spec[0]= shi->specr;
00988         spec[1]= shi->specg;
00989         spec[2]= shi->specb;
00990 
00991         /* MA_RAMP_IN_RESULT is exception */
00992         if(ma->ramp_spec && (ma->rampin_spec!=MA_RAMP_IN_RESULT)) {
00993                 
00994                 /* input */
00995                 switch(ma->rampin_spec) {
00996                 case MA_RAMP_IN_ENERGY:
00997                         fac= t;
00998                         break;
00999                 case MA_RAMP_IN_SHADER:
01000                         fac= is;
01001                         break;
01002                 case MA_RAMP_IN_NOR:
01003                         fac= shi->view[0]*shi->vn[0] + shi->view[1]*shi->vn[1] + shi->view[2]*shi->vn[2];
01004                         break;
01005                 }
01006                 
01007                 do_colorband(ma->ramp_spec, fac, col);
01008                 
01009                 /* blending method */
01010                 fac= col[3]*ma->rampfac_spec;
01011                 
01012                 ramp_blend(ma->rampblend_spec, spec, spec+1, spec+2, fac, col);
01013         }
01014 }
01015 
01016 /* pure AO, check for raytrace and world should have been done */
01017 /* preprocess, textures were not done, don't use shi->amb for that reason */
01018 void ambient_occlusion(ShadeInput *shi)
01019 {
01020         if((R.wrld.ao_gather_method == WO_AOGATHER_APPROX) && shi->mat->amb!=0.0f)
01021                 sample_occ(&R, shi);
01022         else if((R.r.mode & R_RAYTRACE) && shi->mat->amb!=0.0f)
01023                 ray_ao(shi, shi->ao, shi->env);
01024         else
01025                 shi->ao[0]= shi->ao[1]= shi->ao[2]= 1.0f;
01026 }
01027 
01028 
01029 /* wrld mode was checked for */
01030 static void ambient_occlusion_apply(ShadeInput *shi, ShadeResult *shr)
01031 {
01032         float f= R.wrld.aoenergy;
01033         float tmp[3], tmpspec[3];
01034 
01035         if(!((R.r.mode & R_RAYTRACE) || R.wrld.ao_gather_method == WO_AOGATHER_APPROX))
01036                 return;
01037         if(f == 0.0f)
01038                 return;
01039 
01040         if(R.wrld.aomix==WO_AOADD) {
01041                 shr->combined[0] += shi->ao[0]*shi->r*shi->refl*f;
01042                 shr->combined[1] += shi->ao[1]*shi->g*shi->refl*f;
01043                 shr->combined[2] += shi->ao[2]*shi->b*shi->refl*f;
01044         }
01045         else if(R.wrld.aomix==WO_AOMUL) {
01046                 mul_v3_v3v3(tmp, shr->combined, shi->ao);
01047                 mul_v3_v3v3(tmpspec, shr->spec, shi->ao);
01048 
01049                 if(f == 1.0f) {
01050                         copy_v3_v3(shr->combined, tmp);
01051                         copy_v3_v3(shr->spec, tmpspec);
01052                 }
01053                 else {
01054                         interp_v3_v3v3(shr->combined, shr->combined, tmp, f);
01055                         interp_v3_v3v3(shr->spec, shr->spec, tmpspec, f);
01056                 }
01057         }
01058 }
01059 
01060 void environment_lighting_apply(ShadeInput *shi, ShadeResult *shr)
01061 {
01062         float f= R.wrld.ao_env_energy*shi->amb;
01063 
01064         if(!((R.r.mode & R_RAYTRACE) || R.wrld.ao_gather_method == WO_AOGATHER_APPROX))
01065                 return;
01066         if(f == 0.0f)
01067                 return;
01068         
01069         shr->combined[0] += shi->env[0]*shi->r*shi->refl*f;
01070         shr->combined[1] += shi->env[1]*shi->g*shi->refl*f;
01071         shr->combined[2] += shi->env[2]*shi->b*shi->refl*f;
01072 }
01073 
01074 static void indirect_lighting_apply(ShadeInput *shi, ShadeResult *shr)
01075 {
01076         float f= R.wrld.ao_indirect_energy;
01077 
01078         if(!((R.r.mode & R_RAYTRACE) || R.wrld.ao_gather_method == WO_AOGATHER_APPROX))
01079                 return;
01080         if(f == 0.0f)
01081                 return;
01082 
01083         shr->combined[0] += shi->indirect[0]*shi->r*shi->refl*f;
01084         shr->combined[1] += shi->indirect[1]*shi->g*shi->refl*f;
01085         shr->combined[2] += shi->indirect[2]*shi->b*shi->refl*f;
01086 }
01087 
01088 /* result written in shadfac */
01089 void lamp_get_shadow(LampRen *lar, ShadeInput *shi, float inp, float *shadfac, int do_real)
01090 {
01091         LampShadowSubSample *lss= &(lar->shadsamp[shi->thread].s[shi->sample]);
01092         
01093         if(do_real || lss->samplenr!=shi->samplenr) {
01094                 
01095                 shadfac[0]= shadfac[1]= shadfac[2]= shadfac[3]= 1.0f;
01096                 
01097                 if(lar->shb) {
01098                         if(lar->buftype==LA_SHADBUF_IRREGULAR)
01099                                 shadfac[3]= ISB_getshadow(shi, lar->shb);
01100                         else
01101                                 shadfac[3] = testshadowbuf(&R, lar->shb, shi->co, shi->dxco, shi->dyco, inp, shi->mat->lbias);
01102                 }
01103                 else if(lar->mode & LA_SHAD_RAY) {
01104                         ray_shadow(shi, lar, shadfac);
01105                 }
01106                 
01107                 if(shi->depth==0) {
01108                         QUATCOPY(lss->shadfac, shadfac);
01109                         lss->samplenr= shi->samplenr;
01110                 }
01111         }
01112         else {
01113                 QUATCOPY(shadfac, lss->shadfac);
01114         }
01115 }
01116 
01117 /* lampdistance and spot angle, writes in lv and dist */
01118 float lamp_get_visibility(LampRen *lar, float *co, float *lv, float *dist)
01119 {
01120         if(lar->type==LA_SUN || lar->type==LA_HEMI) {
01121                 *dist= 1.0f;
01122                 VECCOPY(lv, lar->vec);
01123                 return 1.0f;
01124         }
01125         else {
01126                 float visifac= 1.0f, t;
01127                 
01128                 VECSUB(lv, co, lar->co);
01129                 *dist= sqrt( INPR(lv, lv));
01130                 t= 1.0f/dist[0];
01131                 VECMUL(lv, t);
01132                 
01133                 /* area type has no quad or sphere option */
01134                 if(lar->type==LA_AREA) {
01135                         /* area is single sided */
01136                         //if(INPR(lv, lar->vec) > 0.0f)
01137                         //      visifac= 1.0f;
01138                         //else
01139                         //      visifac= 0.0f;
01140                 }
01141                 else {
01142                         switch(lar->falloff_type)
01143                         {
01144                                 case LA_FALLOFF_CONSTANT:
01145                                         visifac = 1.0f;
01146                                         break;
01147                                 case LA_FALLOFF_INVLINEAR:
01148                                         visifac = lar->dist/(lar->dist + dist[0]);
01149                                         break;
01150                                 case LA_FALLOFF_INVSQUARE:
01151                                         /* NOTE: This seems to be a hack since commit r12045 says this
01152                                          * option is similar to old Quad, but with slight changes.
01153                                          * Correct inv square would be (which would be old Quad):
01154                                          * visifac = lar->distkw / (lar->distkw + dist[0]*dist[0]);
01155                                          */
01156                                         visifac = lar->dist / (lar->dist + dist[0]*dist[0]);
01157                                         break;
01158                                 case LA_FALLOFF_SLIDERS:
01159                                         if(lar->ld1>0.0f)
01160                                                 visifac= lar->dist/(lar->dist+lar->ld1*dist[0]);
01161                                         if(lar->ld2>0.0f)
01162                                                 visifac*= lar->distkw/(lar->distkw+lar->ld2*dist[0]*dist[0]);
01163                                         break;
01164                                 case LA_FALLOFF_CURVE:
01165                                         visifac = curvemapping_evaluateF(lar->curfalloff, 0, dist[0]/lar->dist);
01166                                         break;
01167                         }
01168                         
01169                         if(lar->mode & LA_SPHERE) {
01170                                 float t= lar->dist - dist[0];
01171                                 if(t<=0.0f) 
01172                                         visifac= 0.0f;
01173                                 else
01174                                         visifac*= t/lar->dist;
01175                         }
01176                         
01177                         if(visifac > 0.0f) {
01178                                 if(lar->type==LA_SPOT) {
01179                                         float inpr;
01180                                         
01181                                         if(lar->mode & LA_SQUARE) {
01182                                                 if(lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2]>0.0f) {
01183                                                         float lvrot[3], x;
01184                                                         
01185                                                         /* rotate view to lampspace */
01186                                                         VECCOPY(lvrot, lv);
01187                                                         mul_m3_v3(lar->imat, lvrot);
01188                                                         
01189                                                         x= MAX2(fabs(lvrot[0]/lvrot[2]) , fabs(lvrot[1]/lvrot[2]));
01190                                                         /* 1.0f/(sqrt(1+x*x)) is equivalent to cos(atan(x)) */
01191                                                         
01192                                                         inpr= 1.0f/(sqrt(1.0f+x*x));
01193                                                 }
01194                                                 else inpr= 0.0f;
01195                                         }
01196                                         else {
01197                                                 inpr= lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2];
01198                                         }
01199                                         
01200                                         t= lar->spotsi;
01201                                         if(inpr<=t) 
01202                                                 visifac= 0.0f;
01203                                         else {
01204                                                 t= inpr-t;
01205                                                 if(t<lar->spotbl && lar->spotbl!=0.0f) {
01206                                                         /* soft area */
01207                                                         float i= t/lar->spotbl;
01208                                                         t= i*i;
01209                                                         inpr*= (3.0f*t-2.0f*t*i);
01210                                                 }
01211                                                 visifac*= inpr;
01212                                         }
01213                                 }
01214                         }
01215                 }
01216                 if (visifac <= 0.001) visifac = 0.0f;
01217                 return visifac;
01218         }
01219 }
01220 
01221 /* function returns raw diff, spec and full shadowed diff in the 'shad' pass */
01222 static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int passflag)
01223 {
01224         Material *ma= shi->mat;
01225         VlakRen *vlr= shi->vlr;
01226         float lv[3], lampdist, lacol[3], shadfac[4], lashdw[3];
01227         float i, is, i_noshad, inp, *vn, *view, vnor[3], phongcorr=1.0f;
01228         float visifac;
01229         
01230         vn= shi->vn;
01231         view= shi->view;
01232         
01233         
01234         if (lar->energy == 0.0) return;
01235         /* only shadow lamps shouldn't affect shadow-less materials at all */
01236         if ((lar->mode & LA_ONLYSHADOW) && (!(ma->mode & MA_SHADOW) || !(R.r.mode & R_SHADOW)))
01237                 return;
01238         /* optimisation, don't render fully black lamps */
01239         if (!(lar->mode & LA_TEXTURE) && (lar->r + lar->g + lar->b == 0.0f))
01240                 return;
01241         
01242         /* lampdist, spot angle, area side, ... */
01243         visifac= lamp_get_visibility(lar, shi->co, lv, &lampdist);
01244         if(visifac==0.0f)
01245                 return;
01246         
01247         if(lar->type==LA_SPOT) {
01248                 if(lar->mode & LA_OSATEX) {
01249                         shi->osatex= 1; /* signal for multitex() */
01250                         
01251                         shi->dxlv[0]= lv[0] - (shi->co[0]-lar->co[0]+shi->dxco[0])/lampdist;
01252                         shi->dxlv[1]= lv[1] - (shi->co[1]-lar->co[1]+shi->dxco[1])/lampdist;
01253                         shi->dxlv[2]= lv[2] - (shi->co[2]-lar->co[2]+shi->dxco[2])/lampdist;
01254                         
01255                         shi->dylv[0]= lv[0] - (shi->co[0]-lar->co[0]+shi->dyco[0])/lampdist;
01256                         shi->dylv[1]= lv[1] - (shi->co[1]-lar->co[1]+shi->dyco[1])/lampdist;
01257                         shi->dylv[2]= lv[2] - (shi->co[2]-lar->co[2]+shi->dyco[2])/lampdist;
01258                 }
01259         }
01260         
01261         /* lamp color texture */
01262         lacol[0]= lar->r;
01263         lacol[1]= lar->g;
01264         lacol[2]= lar->b;
01265         
01266         lashdw[0]= lar->shdwr;
01267         lashdw[1]= lar->shdwg;
01268         lashdw[2]= lar->shdwb;
01269         
01270         if(lar->mode & LA_TEXTURE)      do_lamp_tex(lar, lv, shi, lacol, LA_TEXTURE);
01271         if(lar->mode & LA_SHAD_TEX)     do_lamp_tex(lar, lv, shi, lashdw, LA_SHAD_TEX);
01272 
01273                 /* tangent case; calculate fake face normal, aligned with lampvector */ 
01274                 /* note, vnor==vn is used as tangent trigger for buffer shadow */
01275         if(vlr->flag & R_TANGENT) {
01276                 float cross[3], nstrand[3], blend;
01277 
01278                 if(ma->mode & MA_STR_SURFDIFF) {
01279                         cross_v3_v3v3(cross, shi->surfnor, vn);
01280                         cross_v3_v3v3(nstrand, vn, cross);
01281 
01282                         blend= INPR(nstrand, shi->surfnor);
01283                         blend= 1.0f - blend;
01284                         CLAMP(blend, 0.0f, 1.0f);
01285 
01286                         interp_v3_v3v3(vnor, nstrand, shi->surfnor, blend);
01287                         normalize_v3(vnor);
01288                 }
01289                 else {
01290                         cross_v3_v3v3(cross, lv, vn);
01291                         cross_v3_v3v3(vnor, cross, vn);
01292                         normalize_v3(vnor);
01293                 }
01294 
01295                 if(ma->strand_surfnor > 0.0f) {
01296                         if(ma->strand_surfnor > shi->surfdist) {
01297                                 blend= (ma->strand_surfnor - shi->surfdist)/ma->strand_surfnor;
01298                                 interp_v3_v3v3(vnor, vnor, shi->surfnor, blend);
01299                                 normalize_v3(vnor);
01300                         }
01301                 }
01302 
01303                 vnor[0]= -vnor[0];vnor[1]= -vnor[1];vnor[2]= -vnor[2];
01304                 vn= vnor;
01305         }
01306         else if (ma->mode & MA_TANGENT_V) {
01307                 float cross[3];
01308                 cross_v3_v3v3(cross, lv, shi->tang);
01309                 cross_v3_v3v3(vnor, cross, shi->tang);
01310                 normalize_v3(vnor);
01311                 vnor[0]= -vnor[0];vnor[1]= -vnor[1];vnor[2]= -vnor[2];
01312                 vn= vnor;
01313         }
01314         
01315         /* dot product and reflectivity */
01316         /* inp = dotproduct, is = shader result, i = lamp energy (with shadow), i_noshad = i without shadow */
01317         inp= vn[0]*lv[0] + vn[1]*lv[1] + vn[2]*lv[2];
01318         
01319         /* phong threshold to prevent backfacing faces having artefacts on ray shadow (terminator problem) */
01320         /* this complex construction screams for a nicer implementation! (ton) */
01321         if(R.r.mode & R_SHADOW) {
01322                 if(ma->mode & MA_SHADOW) {
01323                         if(lar->type==LA_HEMI || lar->type==LA_AREA);
01324                         else if((ma->mode & MA_RAYBIAS) && (lar->mode & LA_SHAD_RAY) && (vlr->flag & R_SMOOTH)) {
01325                                 float thresh= shi->obr->ob->smoothresh;
01326                                 if(inp>thresh)
01327                                         phongcorr= (inp-thresh)/(inp*(1.0f-thresh));
01328                                 else
01329                                         phongcorr= 0.0f;
01330                         }
01331                         else if(ma->sbias!=0.0f && ((lar->mode & LA_SHAD_RAY) || lar->shb)) {
01332                                 if(inp>ma->sbias)
01333                                         phongcorr= (inp-ma->sbias)/(inp*(1.0f-ma->sbias));
01334                                 else
01335                                         phongcorr= 0.0f;
01336                         }
01337                 }
01338         }
01339         
01340         /* diffuse shaders */
01341         if(lar->mode & LA_NO_DIFF) {
01342                 is= 0.0f;       // skip shaders
01343         }
01344         else if(lar->type==LA_HEMI) {
01345                 is= 0.5f*inp + 0.5f;
01346         }
01347         else {
01348                 
01349                 if(lar->type==LA_AREA)
01350                         inp= area_lamp_energy_multisample(lar, shi->co, vn);
01351                 
01352                 /* diffuse shaders (oren nayer gets inp from area light) */
01353                 if(ma->diff_shader==MA_DIFF_ORENNAYAR) is= OrenNayar_Diff(inp, vn, lv, view, ma->roughness);
01354                 else if(ma->diff_shader==MA_DIFF_TOON) is= Toon_Diff(vn, lv, view, ma->param[0], ma->param[1]);
01355                 else if(ma->diff_shader==MA_DIFF_MINNAERT) is= Minnaert_Diff(inp, vn, view, ma->darkness);
01356                 else if(ma->diff_shader==MA_DIFF_FRESNEL) is= Fresnel_Diff(vn, lv, view, ma->param[0], ma->param[1]);
01357                 else is= inp;   // Lambert
01358         }
01359         
01360         /* 'is' is diffuse */
01361         if((ma->shade_flag & MA_CUBIC) && is>0.0f && is<1.0f)
01362                 is= 3.0*is*is - 2.0*is*is*is;   // nicer termination of shades
01363 
01364         i= is*phongcorr;
01365         
01366         if(i>0.0f) {
01367                 i*= visifac*shi->refl;
01368         }
01369         i_noshad= i;
01370         
01371         vn= shi->vn;    // bring back original vector, we use special specular shaders for tangent
01372         if(ma->mode & MA_TANGENT_V)
01373                 vn= shi->tang;
01374         
01375         /* init transp shadow */
01376         shadfac[0]= shadfac[1]= shadfac[2]= shadfac[3]= 1.0f;
01377         
01378         /* shadow and spec, (visifac==0 outside spot) */
01379         if(visifac> 0.0f) {
01380                 
01381                 if((R.r.mode & R_SHADOW)) {
01382                         if(ma->mode & MA_SHADOW) {
01383                                 if(lar->shb || (lar->mode & LA_SHAD_RAY)) {
01384                                         
01385                                         if(vn==vnor)    /* tangent trigger */
01386                                                 lamp_get_shadow(lar, shi, INPR(shi->vn, lv), shadfac, shi->depth);
01387                                         else
01388                                                 lamp_get_shadow(lar, shi, inp, shadfac, shi->depth);
01389                                                 
01390                                         /* warning, here it skips the loop */
01391                                         if((lar->mode & LA_ONLYSHADOW) && i>0.0) {
01392                                                 
01393                                                 shadfac[3]= i*lar->energy*(1.0f-shadfac[3]);
01394                                                 shr->shad[0] -= shadfac[3]*shi->r*(1.0f-lashdw[0]);
01395                                                 shr->shad[1] -= shadfac[3]*shi->g*(1.0f-lashdw[1]);
01396                                                 shr->shad[2] -= shadfac[3]*shi->b*(1.0f-lashdw[2]);
01397                                                 
01398                                                 shr->spec[0] -= shadfac[3]*shi->specr*(1.0f-lashdw[0]);
01399                                                 shr->spec[1] -= shadfac[3]*shi->specg*(1.0f-lashdw[1]);
01400                                                 shr->spec[2] -= shadfac[3]*shi->specb*(1.0f-lashdw[2]);
01401                                                 
01402                                                 return;
01403                                         }
01404                                         
01405                                         i*= shadfac[3];
01406                                         shr->shad[3] = shadfac[3]; /* store this for possible check in troublesome cases */
01407                                 }
01408                         }
01409                 }
01410                 
01411                 /* in case 'no diffuse' we still do most calculus, spec can be in shadow.*/
01412                 if(!(lar->mode & LA_NO_DIFF)) {
01413                         if(i>0.0f) {
01414                                 if(ma->mode & MA_SHADOW_TRA)
01415                                         add_to_diffuse(shr->shad, shi, is, i*shadfac[0]*lacol[0], i*shadfac[1]*lacol[1], i*shadfac[2]*lacol[2]);
01416                                 else
01417                                         add_to_diffuse(shr->shad, shi, is, i*lacol[0], i*lacol[1], i*lacol[2]);
01418                         }
01419                         /* add light for colored shadow */
01420                         if (i_noshad>i && !(lashdw[0]==0 && lashdw[1]==0 && lashdw[2]==0)) {
01421                                 add_to_diffuse(shr->shad, shi, is, lashdw[0]*(i_noshad-i)*lacol[0], lashdw[1]*(i_noshad-i)*lacol[1], lashdw[2]*(i_noshad-i)*lacol[2]);
01422                         }
01423                         if(i_noshad>0.0f) {
01424                                 if(passflag & (SCE_PASS_DIFFUSE|SCE_PASS_SHADOW)) {
01425                                         add_to_diffuse(shr->diff, shi, is, i_noshad*lacol[0], i_noshad*lacol[1], i_noshad*lacol[2]);
01426                                 }
01427                                 else
01428                                         VECCOPY(shr->diff, shr->shad);
01429                         }
01430                 }
01431                 
01432                 /* specularity */
01433                 shadfac[3]*= phongcorr; /* note, shadfac not allowed to be stored nonlocal */
01434                 
01435                 if(shadfac[3]>0.0f && shi->spec!=0.0f && !(lar->mode & LA_NO_SPEC) && !(lar->mode & LA_ONLYSHADOW)) {
01436                         
01437                         if(!(passflag & (SCE_PASS_COMBINED|SCE_PASS_SPEC)));
01438                         else if(lar->type==LA_HEMI) {
01439                                 float t;
01440                                 /* hemi uses no spec shaders (yet) */
01441                                 
01442                                 lv[0]+= view[0];
01443                                 lv[1]+= view[1];
01444                                 lv[2]+= view[2];
01445                                 
01446                                 normalize_v3(lv);
01447                                 
01448                                 t= vn[0]*lv[0]+vn[1]*lv[1]+vn[2]*lv[2];
01449                                 
01450                                 if(lar->type==LA_HEMI) {
01451                                         t= 0.5*t+0.5;
01452                                 }
01453                                 
01454                                 t= shadfac[3]*shi->spec*spec(t, shi->har);
01455                                 
01456                                 shr->spec[0]+= t*(lacol[0] * shi->specr);
01457                                 shr->spec[1]+= t*(lacol[1] * shi->specg);
01458                                 shr->spec[2]+= t*(lacol[2] * shi->specb);
01459                         }
01460                         else {
01461                                 /* specular shaders */
01462                                 float specfac, t;
01463                                 
01464                                 if(ma->spec_shader==MA_SPEC_PHONG) 
01465                                         specfac= Phong_Spec(vn, lv, view, shi->har, (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V));
01466                                 else if(ma->spec_shader==MA_SPEC_COOKTORR) 
01467                                         specfac= CookTorr_Spec(vn, lv, view, shi->har, (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V));
01468                                 else if(ma->spec_shader==MA_SPEC_BLINN) 
01469                                         specfac= Blinn_Spec(vn, lv, view, ma->refrac, (float)shi->har, (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V));
01470                                 else if(ma->spec_shader==MA_SPEC_WARDISO)
01471                                         specfac= WardIso_Spec( vn, lv, view, ma->rms, (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V));
01472                                 else 
01473                                         specfac= Toon_Spec(vn, lv, view, ma->param[2], ma->param[3], (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V));
01474                                 
01475                                 /* area lamp correction */
01476                                 if(lar->type==LA_AREA) specfac*= inp;
01477                                 
01478                                 t= shadfac[3]*shi->spec*visifac*specfac;
01479                                 
01480                                 if(ma->mode & MA_RAMP_SPEC) {
01481                                         float spec[3];
01482                                         do_specular_ramp(shi, specfac, t, spec);
01483                                         shr->spec[0]+= t*(lacol[0] * spec[0]);
01484                                         shr->spec[1]+= t*(lacol[1] * spec[1]);
01485                                         shr->spec[2]+= t*(lacol[2] * spec[2]);
01486                                 }
01487                                 else {
01488                                         shr->spec[0]+= t*(lacol[0] * shi->specr);
01489                                         shr->spec[1]+= t*(lacol[1] * shi->specg);
01490                                         shr->spec[2]+= t*(lacol[2] * shi->specb);
01491                                 }
01492                         }
01493                 }
01494         }
01495 }
01496 
01497 static void shade_lamp_loop_only_shadow(ShadeInput *shi, ShadeResult *shr)
01498 {
01499         
01500         if(R.r.mode & R_SHADOW) {
01501                 ListBase *lights;
01502                 LampRen *lar;
01503                 GroupObject *go;
01504                 float inpr, lv[3];
01505                 float *view, shadfac[4];
01506                 float ir, accum, visifac, lampdist;
01507                 float shaded = 0.0f, lightness = 0.0f;
01508                 
01509 
01510                 view= shi->view;
01511                 accum= ir= 0.0f;
01512                 
01513                 lights= get_lights(shi);
01514                 for(go=lights->first; go; go= go->next) {
01515                         lar= go->lampren;
01516                         if(lar==NULL) continue;
01517                         
01518                         /* yafray: ignore shading by photonlights, not used in Blender */
01519                         if (lar->type==LA_YF_PHOTON) continue;
01520                         
01521                         if(lar->mode & LA_LAYER) if((lar->lay & shi->obi->lay)==0) continue;
01522                         if((lar->lay & shi->lay)==0) continue;
01523                         
01524                         if(lar->shb || (lar->mode & LA_SHAD_RAY)) {
01525                                 visifac= lamp_get_visibility(lar, shi->co, lv, &lampdist);
01526                                 ir+= 1.0f;
01527 
01528                                 if(visifac <= 0.0f) {
01529                                         if (shi->mat->shadowonly_flag == MA_SO_OLD)
01530                                                 accum+= 1.0f;
01531 
01532                                         continue;
01533                                 }
01534                                 inpr= INPR(shi->vn, lv);
01535                                 if(inpr <= 0.0f) {
01536                                         if (shi->mat->shadowonly_flag == MA_SO_OLD)
01537                                                 accum+= 1.0f;
01538 
01539                                         continue;
01540                                 }
01541 
01542                                 lamp_get_shadow(lar, shi, inpr, shadfac, shi->depth);
01543 
01544                                 if (shi->mat->shadowonly_flag == MA_SO_OLD) {
01545                                         /* Old "Shadows Only" */
01546                                         accum+= (1.0f-visifac) + (visifac)*rgb_to_grayscale(shadfac)*shadfac[3];
01547                                 }
01548                                 else {
01549                                         shaded += rgb_to_grayscale(shadfac)*shadfac[3] * visifac * lar->energy;
01550 
01551                                         if (shi->mat->shadowonly_flag == MA_SO_SHADOW) {
01552                                                 lightness += visifac * lar->energy;
01553                                         }
01554                                 }
01555                         }
01556                 }
01557 
01558                 /* Apply shadows as alpha */
01559                 if(ir>0.0f) {
01560                         if (shi->mat->shadowonly_flag == MA_SO_OLD) {
01561                                 accum = 1.0f - accum/ir;
01562                         }
01563                         else {
01564                                 if (shi->mat->shadowonly_flag == MA_SO_SHADOW) {
01565                                         if (lightness > 0.0f) {
01566                                                 /* Get shadow value from between 0.0f and non-shadowed lightness */
01567                                                 accum = (lightness - shaded) / (lightness);
01568                                         }
01569                                         else {
01570                                                 accum = 0.0f;
01571                                         }
01572                                 }
01573                                 else { /* shadowonly_flag == MA_SO_SHADED */
01574                                         /* Use shaded value */
01575                                         accum = 1.0f - shaded;
01576                         }}
01577 
01578                         shr->alpha= (shi->alpha)*(accum);
01579                         if (shr->alpha<0.0f) shr->alpha=0.0f;
01580                 }
01581                 else {
01582                         /* If "fully shaded", use full alpha even on areas that have no lights */
01583                         if (shi->mat->shadowonly_flag == MA_SO_SHADED) shr->alpha=shi->alpha;
01584                         else shr->alpha= 0.f;
01585                 }
01586         }
01587         
01588         /* quite disputable this...  also note it doesn't mirror-raytrace */    
01589         if((R.wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT)) && shi->amb!=0.0f) {
01590                 float f;
01591                 
01592                 if(R.wrld.mode & WO_AMB_OCC) {
01593                         f= R.wrld.aoenergy*shi->amb;
01594                         
01595                         if(R.wrld.aomix==WO_AOADD) {
01596                                 if (shi->mat->shadowonly_flag == MA_SO_OLD) {
01597                                         f= f*(1.0f - rgb_to_grayscale(shi->ao));
01598                                         shr->alpha= (shr->alpha + f)*f;
01599                                 }
01600                                 else {
01601                                         shr->alpha -= f*rgb_to_grayscale(shi->ao);
01602                                         if (shr->alpha<0.0f) shr->alpha=0.0f;
01603                                 }
01604                         }
01605                         else /* AO Multiply */
01606                                 shr->alpha= (1.0f - f)*shr->alpha + f*(1.0f - (1.0f - shr->alpha)*rgb_to_grayscale(shi->ao));
01607                 }
01608 
01609                 if(R.wrld.mode & WO_ENV_LIGHT) {
01610                         if (shi->mat->shadowonly_flag == MA_SO_OLD) {
01611                                 f= R.wrld.ao_env_energy*shi->amb*(1.0f - rgb_to_grayscale(shi->env));
01612                                 shr->alpha= (shr->alpha + f)*f;
01613                         }
01614                         else {
01615                                 f= R.wrld.ao_env_energy*shi->amb;
01616                                 shr->alpha -= f*rgb_to_grayscale(shi->env);
01617                                 if (shr->alpha<0.0f) shr->alpha=0.0f;
01618                         }
01619                 }
01620         }
01621 }
01622 
01623 /* let's map negative light as if it mirrors positive light, otherwise negative values disappear */
01624 static void wrld_exposure_correct(float *diff)
01625 {
01626         
01627         diff[0]= R.wrld.linfac*(1.0f-exp( diff[0]*R.wrld.logfac) );
01628         diff[1]= R.wrld.linfac*(1.0f-exp( diff[1]*R.wrld.logfac) );
01629         diff[2]= R.wrld.linfac*(1.0f-exp( diff[2]*R.wrld.logfac) );
01630 }
01631 
01632 void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
01633 {
01634         Material *ma= shi->mat;
01635         int passflag= shi->passflag;
01636         
01637         memset(shr, 0, sizeof(ShadeResult));
01638         
01639         if(!(shi->mode & MA_TRANSP)) shi->alpha = 1.0f;
01640         
01641         /* separate loop */
01642         if(ma->mode & MA_ONLYSHADOW) {
01643                 shade_lamp_loop_only_shadow(shi, shr);
01644                 return;
01645         }
01646         
01647         /* envmap hack, always reset */
01648         shi->refcol[0]= shi->refcol[1]= shi->refcol[2]= shi->refcol[3]= 0.0f;
01649         
01650         /* material color itself */
01651         if(passflag & (SCE_PASS_COMBINED|SCE_PASS_RGBA)) {
01652                 if(ma->mode & (MA_VERTEXCOLP|MA_FACETEXTURE)) {
01653                         shi->r= shi->vcol[0];
01654                         shi->g= shi->vcol[1];
01655                         shi->b= shi->vcol[2];
01656                         if(ma->mode & (MA_FACETEXTURE_ALPHA))
01657                                 shi->alpha= (shi->mode & MA_TRANSP) ? shi->vcol[3] : 1.0f;
01658                 }
01659                 if(ma->texco){
01660                         do_material_tex(shi);
01661                         if (!(shi->mode & MA_TRANSP)) shi->alpha = 1.0f;
01662                 }
01663                 
01664                 shr->col[0]= shi->r*shi->alpha;
01665                 shr->col[1]= shi->g*shi->alpha;
01666                 shr->col[2]= shi->b*shi->alpha;
01667                 shr->col[3]= shi->alpha;
01668 
01669                 if((ma->sss_flag & MA_DIFF_SSS) && !sss_pass_done(&R, ma)) {
01670                         if(ma->sss_texfac == 0.0f) {
01671                                 shi->r= shi->g= shi->b= shi->alpha= 1.0f;
01672                                 shr->col[0]= shr->col[1]= shr->col[2]= shr->col[3]= 1.0f;
01673                         }
01674                         else {
01675                                 shi->r= pow(shi->r, ma->sss_texfac);
01676                                 shi->g= pow(shi->g, ma->sss_texfac);
01677                                 shi->b= pow(shi->b, ma->sss_texfac);
01678                                 shi->alpha= pow(shi->alpha, ma->sss_texfac);
01679                                 
01680                                 shr->col[0]= pow(shr->col[0], ma->sss_texfac);
01681                                 shr->col[1]= pow(shr->col[1], ma->sss_texfac);
01682                                 shr->col[2]= pow(shr->col[2], ma->sss_texfac);
01683                                 shr->col[3]= pow(shr->col[3], ma->sss_texfac);
01684                         }
01685                 }
01686         }
01687         
01688         if(ma->mode & MA_SHLESS) {
01689                 shr->combined[0]= shi->r;
01690                 shr->combined[1]= shi->g;
01691                 shr->combined[2]= shi->b;
01692                 shr->alpha= shi->alpha;
01693                 return;
01694         }
01695 
01696         if( (ma->mode & (MA_VERTEXCOL|MA_VERTEXCOLP))== MA_VERTEXCOL ) {        // vertexcolor light
01697                 shr->emit[0]= shi->r*(shi->emit+shi->vcol[0]);
01698                 shr->emit[1]= shi->g*(shi->emit+shi->vcol[1]);
01699                 shr->emit[2]= shi->b*(shi->emit+shi->vcol[2]);
01700         }
01701         else {
01702                 shr->emit[0]= shi->r*shi->emit;
01703                 shr->emit[1]= shi->g*shi->emit;
01704                 shr->emit[2]= shi->b*shi->emit;
01705         }
01706         
01707         /* AO pass */
01708         if(R.wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT)) {
01709                 if(((passflag & SCE_PASS_COMBINED) && (shi->combinedflag & (SCE_PASS_AO|SCE_PASS_ENVIRONMENT|SCE_PASS_INDIRECT)))
01710                         || (passflag & (SCE_PASS_AO|SCE_PASS_ENVIRONMENT|SCE_PASS_INDIRECT))) {
01711                         if(R.r.mode & R_SHADOW) {
01712                                 /* AO was calculated for scanline already */
01713                                 if(shi->depth || shi->volume_depth)
01714                                         ambient_occlusion(shi);
01715                                 VECCOPY(shr->ao, shi->ao);
01716                                 VECCOPY(shr->env, shi->env); // XXX multiply
01717                                 VECCOPY(shr->indirect, shi->indirect); // XXX multiply
01718                         }
01719                 }
01720         }
01721         
01722         /* lighting pass */
01723         if(passflag & (SCE_PASS_COMBINED|SCE_PASS_DIFFUSE|SCE_PASS_SPEC|SCE_PASS_SHADOW)) {
01724                 GroupObject *go;
01725                 ListBase *lights;
01726                 LampRen *lar;
01727                 
01728                 lights= get_lights(shi);
01729                 for(go=lights->first; go; go= go->next) {
01730                         lar= go->lampren;
01731                         if(lar==NULL) continue;
01732                         
01733                         /* yafray: ignore shading by photonlights, not used in Blender */
01734                         if (lar->type==LA_YF_PHOTON) continue;
01735                         
01736                         /* test for lamp layer */
01737                         if(lar->mode & LA_LAYER) if((lar->lay & shi->obi->lay)==0) continue;
01738                         if((lar->lay & shi->lay)==0) continue;
01739                         
01740                         /* accumulates in shr->diff and shr->spec and shr->shad (diffuse with shadow!) */
01741                         shade_one_light(lar, shi, shr, passflag);
01742                 }
01743 
01744                 /*this check is to prevent only shadow lamps from producing negative
01745                   colors.*/
01746                 if (shr->spec[0] < 0) shr->spec[0] = 0;
01747                 if (shr->spec[1] < 0) shr->spec[1] = 0;
01748                 if (shr->spec[2] < 0) shr->spec[2] = 0;
01749 
01750                 if (shr->shad[0] < 0) shr->shad[0] = 0;
01751                 if (shr->shad[1] < 0) shr->shad[1] = 0;
01752                 if (shr->shad[2] < 0) shr->shad[2] = 0;
01753                                                 
01754                 if(ma->sss_flag & MA_DIFF_SSS) {
01755                         float sss[3], col[3], invalpha, texfac= ma->sss_texfac;
01756 
01757                         /* this will return false in the preprocess stage */
01758                         if(sample_sss(&R, ma, shi->co, sss)) {
01759                                 invalpha= (shr->col[3] > FLT_EPSILON)? 1.0f/shr->col[3]: 1.0f;
01760 
01761                                 if(texfac==0.0f) {
01762                                         VECCOPY(col, shr->col);
01763                                         mul_v3_fl(col, invalpha);
01764                                 }
01765                                 else if(texfac==1.0f) {
01766                                         col[0]= col[1]= col[2]= 1.0f;
01767                                         mul_v3_fl(col, invalpha);
01768                                 }
01769                                 else {
01770                                         VECCOPY(col, shr->col);
01771                                         mul_v3_fl(col, invalpha);
01772                                         col[0]= pow(col[0], 1.0f-texfac);
01773                                         col[1]= pow(col[1], 1.0f-texfac);
01774                                         col[2]= pow(col[2], 1.0f-texfac);
01775                                 }
01776 
01777                                 shr->diff[0]= sss[0]*col[0];
01778                                 shr->diff[1]= sss[1]*col[1];
01779                                 shr->diff[2]= sss[2]*col[2];
01780 
01781                                 if(shi->combinedflag & SCE_PASS_SHADOW) {
01782                                         shr->shad[0]= shr->diff[0];
01783                                         shr->shad[1]= shr->diff[1];
01784                                         shr->shad[2]= shr->diff[2];
01785                                 }
01786                         }
01787                 }
01788                 
01789                 if(shi->combinedflag & SCE_PASS_SHADOW) 
01790                         VECCOPY(shr->combined, shr->shad)       /* note, no ';' ! */
01791                 else
01792                         VECCOPY(shr->combined, shr->diff);
01793                         
01794                 /* calculate shadow pass, we use a multiplication mask */
01795                 /* if diff = 0,0,0 it doesn't matter what the shadow pass is, so leave it as is */
01796                 if(passflag & SCE_PASS_SHADOW && !(shr->diff[0]==0.0f && shr->diff[1]==0.0f && shr->diff[2]==0.0f)) {
01797                         if(shr->diff[0]!=0.0f) shr->shad[0]= shr->shad[0]/shr->diff[0];
01798                         /* can't determine proper shadow from shad/diff (0/0), so use shadow intensity */
01799                         else if(shr->shad[0]==0.0f) shr->shad[0]= shr->shad[3];
01800 
01801                         if(shr->diff[1]!=0.0f) shr->shad[1]= shr->shad[1]/shr->diff[1];
01802                         else if(shr->shad[1]==0.0f) shr->shad[1]= shr->shad[3];
01803 
01804                         if(shr->diff[2]!=0.0f) shr->shad[2]= shr->shad[2]/shr->diff[2];
01805                         else if(shr->shad[2]==0.0f) shr->shad[2]= shr->shad[3];
01806                 }
01807                 
01808                 /* exposure correction */
01809                 if((R.wrld.exp!=0.0f || R.wrld.range!=1.0f) && !R.sss_points) {
01810                         wrld_exposure_correct(shr->combined);   /* has no spec! */
01811                         wrld_exposure_correct(shr->spec);
01812                 }
01813         }
01814         
01815         /* alpha in end, spec can influence it */
01816         if(passflag & (SCE_PASS_COMBINED)) {
01817                 if((ma->fresnel_tra!=0.0f) && (shi->mode & MA_TRANSP))
01818                         shi->alpha*= fresnel_fac(shi->view, shi->vn, ma->fresnel_tra_i, ma->fresnel_tra);
01819                         
01820                 /* note: shi->mode! */
01821                 if(shi->mode & MA_TRANSP && (shi->mode & (MA_ZTRANSP|MA_RAYTRANSP))) {
01822                         if(shi->spectra!=0.0f) {
01823                                 float t = MAX3(shr->spec[0], shr->spec[1], shr->spec[2]);
01824                                 t *= shi->spectra;
01825                                 if(t>1.0f) t= 1.0f;
01826                                 shi->alpha= (1.0f-t)*shi->alpha+t;
01827                         }
01828                 }
01829         }
01830         shr->alpha= shi->alpha;
01831         
01832         /* from now stuff everything in shr->combined: ambient, AO, radio, ramps, exposure */
01833         if(!(ma->sss_flag & MA_DIFF_SSS) || !sss_pass_done(&R, ma)) {
01834                 if(R.r.mode & R_SHADOW) {
01835                         /* add AO in combined? */
01836                         if(R.wrld.mode & WO_AMB_OCC)
01837                                 if(shi->combinedflag & SCE_PASS_AO)
01838                                         ambient_occlusion_apply(shi, shr);
01839 
01840                         if(R.wrld.mode & WO_ENV_LIGHT)
01841                                 if(shi->combinedflag & SCE_PASS_ENVIRONMENT)
01842                                         environment_lighting_apply(shi, shr);
01843 
01844                         if(R.wrld.mode & WO_INDIRECT_LIGHT)
01845                                 if(shi->combinedflag & SCE_PASS_INDIRECT)
01846                                         indirect_lighting_apply(shi, shr);
01847                 }
01848                 
01849                 shr->combined[0]+= shi->ambr;
01850                 shr->combined[1]+= shi->ambg;
01851                 shr->combined[2]+= shi->ambb;
01852                 
01853                 if(ma->mode & MA_RAMP_COL) ramp_diffuse_result(shr->combined, shi);
01854         }
01855 
01856         if(ma->mode & MA_RAMP_SPEC) ramp_spec_result(shr->spec, shr->spec+1, shr->spec+2, shi);
01857         
01858         /* refcol is for envmap only */
01859         if(shi->refcol[0]!=0.0f) {
01860                 float result[3];
01861                 
01862                 result[0]= shi->mirr*shi->refcol[1] + (1.0f - shi->mirr*shi->refcol[0])*shr->combined[0];
01863                 result[1]= shi->mirg*shi->refcol[2] + (1.0f - shi->mirg*shi->refcol[0])*shr->combined[1];
01864                 result[2]= shi->mirb*shi->refcol[3] + (1.0f - shi->mirb*shi->refcol[0])*shr->combined[2];
01865                 
01866                 if(passflag & SCE_PASS_REFLECT)
01867                         VECSUB(shr->refl, result, shr->combined);
01868                 
01869                 if(shi->combinedflag & SCE_PASS_REFLECT)
01870                         VECCOPY(shr->combined, result);
01871                         
01872         }
01873         
01874         /* and add emit and spec */
01875         if(shi->combinedflag & SCE_PASS_EMIT)
01876                 VECADD(shr->combined, shr->combined, shr->emit);
01877         if(shi->combinedflag & SCE_PASS_SPEC)
01878                 VECADD(shr->combined, shr->combined, shr->spec);
01879         
01880         /* modulate by the object color */
01881         if((ma->shade_flag & MA_OBCOLOR) && shi->obr->ob) {
01882                 if(!(ma->sss_flag & MA_DIFF_SSS) || !sss_pass_done(&R, ma)) {
01883                         float obcol[4];
01884 
01885                         QUATCOPY(obcol, shi->obr->ob->col);
01886                         CLAMP(obcol[3], 0.0f, 1.0f);
01887 
01888                         shr->combined[0] *= obcol[0];
01889                         shr->combined[1] *= obcol[1];
01890                         shr->combined[2] *= obcol[2];
01891                         if (shi->mode & MA_TRANSP) shr->alpha *= obcol[3];
01892                 }
01893         }
01894 
01895         shr->combined[3]= shr->alpha;
01896 }
01897