3 * ***** BEGIN GPL LICENSE BLOCK *****
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
20 * All rights reserved.
22 * Contributor(s): 2004-2006, Blender Foundation, full recode
24 * ***** END GPL LICENSE BLOCK *****
30 #include "BLI_arithb.h"
32 /* External modules: */
33 #include "IMB_imbuf_types.h"
34 #include "IMB_imbuf.h"
35 #include "MTC_matrixops.h"
36 #include "MTC_vectorops.h"
38 #include "DNA_camera_types.h"
39 #include "DNA_group_types.h"
40 #include "DNA_material_types.h"
41 #include "DNA_object_types.h"
42 #include "DNA_image_types.h"
43 #include "DNA_texture_types.h"
44 #include "DNA_lamp_types.h"
46 #include "BKE_image.h"
47 #include "BKE_global.h"
48 #include "BKE_texture.h"
49 #include "BKE_utildefines.h"
52 #include "render_types.h"
53 #include "renderpipeline.h"
54 #include "renderdatabase.h"
56 #include "pixelblending.h"
57 #include "rendercore.h"
59 #include "pixelshading.h"
61 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
62 /* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
63 /* only to be used here in this file, it's for speed */
64 extern struct Render R;
65 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
68 extern float hashvectf[];
70 static void render_lighting_halo(HaloRen *har, float *colf)
74 float i, inp, inpr, rco[3], dco[3], lv[3], lampdist, ld, t, *vn;
75 float ir, ig, ib, shadfac, soft, lacol[3];
79 VECCOPY(rco, har->co);
80 dco[0]=dco[1]=dco[2]= 1.0/har->rad;
84 for(go=R.lights.first; go; go= go->next) {
87 /* test for lamplayer */
88 if(lar->mode & LA_LAYER) if((lar->lay & har->lay)==0) continue;
90 /* lampdist cacluation */
91 if(lar->type==LA_SUN || lar->type==LA_HEMI) {
92 VECCOPY(lv, lar->vec);
96 lv[0]= rco[0]-lar->co[0];
97 lv[1]= rco[1]-lar->co[1];
98 lv[2]= rco[2]-lar->co[2];
99 ld= sqrt(lv[0]*lv[0]+lv[1]*lv[1]+lv[2]*lv[2]);
104 /* ld is re-used further on (texco's) */
106 if(lar->mode & LA_QUAD) {
109 t= lar->dist/(lar->dist+lar->ld1*ld);
111 t*= lar->distkw/(lar->distkw+lar->ld2*ld*ld);
116 lampdist= (lar->dist/(lar->dist+ld));
119 if(lar->mode & LA_SPHERE) {
133 if(lar->mode & LA_TEXTURE) {
136 /* Warning, This is not that nice, and possibly a bit slow,
137 however some variables were not initialized properly in, unless using shade_input_initialize(...), we need to do a memset */
138 memset(&shi, 0, sizeof(ShadeInput));
139 /* end warning! - Campbell */
141 VECCOPY(shi.co, rco);
143 do_lamp_tex(lar, lv, &shi, lacol);
146 if(lar->type==LA_SPOT) {
148 if(lar->mode & LA_SQUARE) {
149 if(lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2]>0.0) {
152 /* rotate view to lampspace */
154 MTC_Mat3MulVecfl(lar->imat, lvrot);
156 x= MAX2(fabs(lvrot[0]/lvrot[2]) , fabs(lvrot[1]/lvrot[2]));
157 /* 1.0/(sqrt(1+x*x)) is equivalent to cos(atan(x)) */
159 inpr= 1.0/(sqrt(1.0+x*x));
164 inpr= lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2];
173 if(t<lar->spotbl && lar->spotbl!=0.0) {
177 soft= (3.0*t-2.0*t*i);
180 if(lar->mode & LA_ONLYSHADOW) {
181 /* if(ma->mode & MA_SHADOW) { */
182 /* dot product positive: front side face! */
183 inp= vn[0]*lv[0] + vn[1]*lv[1] + vn[2]*lv[2];
185 /* testshadowbuf==0.0 : 100% shadow */
186 shadfac = testshadowbuf(&R, lar->shb, rco, dco, dco, inp, 0.0f);
188 shadfac*= inp*soft*lar->energy;
200 if(lar->mode & LA_ONLYSHADOW) continue;
204 /* dot product and reflectivity*/
206 inp= 1.0-fabs(vn[0]*lv[0] + vn[1]*lv[1] + vn[2]*lv[2]);
208 /* inp= cos(0.5*M_PI-acos(inp)); */
212 if(lar->type==LA_HEMI) {
220 if(i> -0.41) { /* heuristic valua! */
223 shadfac = testshadowbuf(&R, lar->shb, rco, dco, dco, inp, 0.0f);
224 if(shadfac==0.0) continue;
248 * Converts a halo z-buffer value to distance from the camera's near plane
249 * @param z The z-buffer value to convert
250 * @return a distance from the camera's near plane in blender units
252 static float haloZtoDist(int z)
259 zco = (float)z/(float)0x7FFFFF;
260 if(R.r.mode & R_ORTHO)
261 return (R.winmat[3][2] - zco*R.winmat[3][3])/(R.winmat[2][2]);
263 return (R.winmat[3][2])/(R.winmat[2][2] - R.winmat[2][3]*zco);
268 * @param col (float[4]) Store the rgb color here (with alpha)
269 * The alpha is used to blend the color to the background
270 * color_new = (1-alpha)*color_background + color
271 * @param zz The current zbuffer value at the place of this pixel
272 * @param dist Distance of the pixel from the center of the halo squared. Given in pixels
273 * @param xn The x coordinate of the pixel relaticve to the center of the halo. given in pixels
274 * @param yn The y coordinate of the pixel relaticve to the center of the halo. given in pixels
276 int shadeHaloFloat(HaloRen *har, float *col, int zz,
277 float dist, float xn, float yn, short flarec)
280 float t, zn, radist, ringf=0.0f, linef=0.0f, alpha, si, co;
283 if(R.wrld.mode & WO_MIST) {
284 if(har->type & HA_ONLYSKY) {
285 /* stars but no mist */
289 /* a bit patchy... */
290 alpha= mistfactor(-har->co[2], har->co)*har->alfa;
293 else alpha= har->alfa;
298 /* soften the halo if it intersects geometry */
299 if(har->mat->mode & MA_HALO_SOFT) {
300 float segment_length, halo_depth, distance_from_z, visible_depth, soften;
302 /* calculate halo depth */
303 segment_length= har->hasize*sasqrt(1.0f - dist/(har->rad*har->rad));
304 halo_depth= 2.0f*segment_length;
306 if(halo_depth < FLT_EPSILON)
309 /* calculate how much of this depth is visible */
310 distance_from_z = haloZtoDist(zz) - haloZtoDist(har->zs);
311 visible_depth = halo_depth;
312 if(distance_from_z < segment_length) {
313 soften= (segment_length + distance_from_z)/halo_depth;
315 /* apply softening to alpha */
323 /* not a soft halo. use the old softening code */
324 /* halo being intersected? */
325 if(har->zs> zz-har->zd) {
326 t= ((float)(zz-har->zs))/(float)har->zd;
327 alpha*= sqrt(sqrt(t));
333 /* watch it: not used nicely: flarec is set at zero in pixstruct */
334 if(flarec) har->pixels+= (int)(har->rad-radist);
340 /* per ring an antialised circle */
343 for(a= har->ringc; a>0; a--, ofs+=2) {
345 rc= hashvectf + (ofs % 768);
347 fac= fabs( rc[1]*(har->rad*fabs(rc[0]) - radist) );
355 if(har->type & HA_VECT) {
356 dist= fabs( har->cos*(yn) - har->sin*(xn) )/har->rad;
357 if(dist>1.0) dist= 1.0;
359 zn= har->sin*xn - har->cos*yn;
360 yn= har->cos*xn + har->sin*yn;
364 else dist= dist/har->radsq;
366 if(har->type & HA_FLARECIRC) {
368 dist= 0.5+fabs(dist-0.5);
375 dist= sin(dist*M_PI_2);
381 else if(har->hard<20) dist*=dist;
392 /* per starpoint an antialiased line */
395 for(a= har->linec; a>0; a--, ofs+=3) {
397 rc= hashvectf + (ofs % 768);
399 fac= fabs( (xn)*rc[0]+(yn)*rc[1]);
408 if(har->starpoints) {
411 angle= atan2(yn, xn);
412 angle*= (1.0+0.25*har->starpoints);
417 angle= (co*xn+si*yn)*(co*yn-si*xn);
421 ster= (har->rad)/(ster);
423 if(ster<1.0) dist*= sqrt(ster);
427 /* disputable optimize... (ton) */
435 /* The color is either the rgb spec-ed by the user, or extracted from */
443 do_halo_tex(har, xn, yn, col);
454 if(har->type & HA_XALPHA) col[3]= dist*dist;
459 if(har->mat->mode & MA_HALO_SHADE) {
460 /* we test for lights because of preview... */
461 if(R.lights.first) render_lighting_halo(har, col);
464 /* Next, we do the line and ring factor modifications. */
466 Material *ma= har->mat;
468 col[0]+= linef * ma->specr;
469 col[1]+= linef * ma->specg;
470 col[2]+= linef * ma->specb;
472 if(har->type & HA_XALPHA) col[3]+= linef*linef;
476 Material *ma= har->mat;
478 col[0]+= ringf * ma->mirr;
479 col[1]+= ringf * ma->mirg;
480 col[2]+= ringf * ma->mirb;
482 if(har->type & HA_XALPHA) col[3]+= ringf*ringf;
487 /* alpha requires clip, gives black dots */
494 /* ------------------------------------------------------------------------- */
496 static void fillBackgroundImage(float *collector, float fx, float fy)
504 float dx= 1.0f/(float)R.winx;
505 float dy= 1.0f/(float)R.winy;
507 image_sample(R.backbuf, fx*dx, fy*dy, dx, dy, collector);
511 /* Only view vector is important here. Result goes to colf[3] */
512 void shadeSkyView(float *colf, float *rco, float *view, float *dxyview)
514 float lo[3], zen[3], hor[3], blend, blendm;
517 /* flag indicating if we render the top hemisphere */
520 /* Some view vector stuff. */
521 if(R.wrld.skytype & WO_SKYREAL) {
523 blend= view[0]*R.grvec[0]+ view[1]*R.grvec[1]+ view[2]*R.grvec[2];
525 if(blend<0.0) skyflag= 0;
529 else if(R.wrld.skytype & WO_SKYPAPER) {
530 blend= 0.5+ 0.5*view[1];
533 /* the fraction of how far we are above the bottom of the screen */
534 blend= fabs(0.5+ view[1]);
537 hor[0]= R.wrld.horr; hor[1]= R.wrld.horg; hor[2]= R.wrld.horb;
538 zen[0]= R.wrld.zenr; zen[1]= R.wrld.zeng; zen[2]= R.wrld.zenb;
540 /* Careful: SKYTEX and SKYBLEND are NOT mutually exclusive! If */
541 /* SKYBLEND is active, the texture and color blend are added. */
542 if(R.wrld.skytype & WO_SKYTEX) {
544 if(R.wrld.skytype & WO_SKYREAL) {
546 MTC_Mat3MulVecfl(R.imat, lo);
548 SWAP(float, lo[1], lo[2]);
551 do_sky_tex(rco, lo, dxyview, hor, zen, &blend, skyflag);
554 if(blend>1.0) blend= 1.0;
557 /* No clipping, no conversion! */
558 if(R.wrld.skytype & WO_SKYBLEND) {
559 colf[0] = (blendm*hor[0] + blend*zen[0]);
560 colf[1] = (blendm*hor[1] + blend*zen[1]);
561 colf[2] = (blendm*hor[2] + blend*zen[2]);
563 /* Done when a texture was grabbed. */
571 Stuff the sky color into the collector.
573 void shadeSkyPixel(float *collector, float fx, float fy)
575 float view[3], dxyview[2];
579 1. Draw an image, if a background image was provided. Stop
580 2. get texture and color blend, and combine these.
585 /* 1. Do a backbuffer image: */
586 if(R.r.bufflag & 1) {
587 fillBackgroundImage(collector, fx, fy);
590 else if((R.wrld.skytype & (WO_SKYBLEND+WO_SKYTEX))==0) {
592 collector[0] = R.wrld.horr;
593 collector[1] = R.wrld.horg;
594 collector[2] = R.wrld.horb;
600 /* This one true because of the context of this routine */
601 if(R.wrld.skytype & WO_SKYPAPER) {
602 view[0]= -1.0f + 2.0f*(fx/(float)R.winx);
603 view[1]= -1.0f + 2.0f*(fy/(float)R.winy);
606 dxyview[0]= 1.0f/(float)R.winx;
607 dxyview[1]= 1.0f/(float)R.winy;
610 calc_view_vector(view, fx, fy);
611 fac= Normalize(view);
613 if(R.wrld.skytype & WO_SKYTEX) {
614 dxyview[0]= -R.viewdx/fac;
615 dxyview[1]= -R.viewdy/fac;
619 /* get sky color in the collector */
620 shadeSkyView(collector, NULL, view, dxyview);