diff options
Diffstat (limited to 'source/blender/render/intern/source/pixelshading.c')
-rw-r--r-- | source/blender/render/intern/source/pixelshading.c | 1917 |
1 files changed, 1917 insertions, 0 deletions
diff --git a/source/blender/render/intern/source/pixelshading.c b/source/blender/render/intern/source/pixelshading.c new file mode 100644 index 00000000000..ff69b4226bf --- /dev/null +++ b/source/blender/render/intern/source/pixelshading.c @@ -0,0 +1,1917 @@ +/** + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * Shading of pixels + * + * 11-09-2000 nzc + * + * $Id$ + * + * Shading hierarchy: + * + * (externally visible) + * + * renderPixel---------- + * | renderHaloPixel-- shadeHaloFloat + * | + * | renderFacePixel-- shadeLampLusFloat + * | shadeSpotHaloPixelFloat-- spotHaloFloat + * + * + * renderSpotHaloPixel--(should call shadeSpotHaloPixelFloat, but there's numerical) + * ( issues there... need to iron that out still ) + */ + +#include <math.h> +#include "BLI_arithb.h" + +/* External modules: */ +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" +#include "MTC_matrixops.h" +#include "MTC_vectorops.h" + +#include "DNA_camera_types.h" +#include "DNA_object_types.h" +#include "DNA_mesh_types.h" +#include "DNA_image_types.h" +#include "DNA_texture_types.h" +#include "DNA_lamp_types.h" + +#include "BKE_global.h" +#include "BKE_texture.h" +#include "BKE_utildefines.h" + +#include "render.h" +#include "render_intern.h" + +#include "vanillaRenderPipe_types.h" +#include "pixelblending.h" +#include "zbuf.h" +#include "rendercore.h" /* for some shading functions... */ +#include "zbufferdatastruct.h" + +#include "shadbuf.h" +#include "shadowBuffer.h" + +#include "renderHelp.h" + +#include "gammaCorrectionTables.h" +#include "errorHandler.h" +#include "pixelshading.h" + +/* ------------------------------------------------------------------------- */ +/* maybe declare local functions here? */ +/* ------------------------------------------------------------------------- */ + +/* The collector is the communication channel with the render pipe. */ +extern RE_COLBUFTYPE collector[4]; /* used throughout as pixel colour accu */ +/* shortcol was the old collector */ +extern float holoofs, fmask[256]; +extern float Zmulx, Zmuly; /* Some kind of scale? */ + +unsigned int calcHaloZ(HaloRen *har, unsigned int zz); + +/* ------------------------------------------------------------------------- */ +/* if defined: do full error tracing and reporting here */ +/* #define RE_PIXSHADE_FULL_SAFETY */ +/* if defined: use fake (dummy) colours for filling pixels (all is purple) */ +/* #define RE_FAKE_PIXELS */ +/* if defined: use fake (dummy) colours for filling faces (all blue) */ +/* #define RE_FAKE_FACE_PIXELS */ +/* if defined: use fake (dummy) colours for filling halos (all red) */ +/* #define RE_FAKE_HALO_PIXELS */ +/* #define RE_FAKE_HALO_PIXELS_2 */ +/* if defined: use fake (dummy) colours for filling spothalos (green) */ +/* #define RE_FAKE_SPOTHALO_PIXELS */ +/* if defined: use fake (dummy) colours for shading lighting */ +/* #define RE_FAKE_LAMP_SHADE */ +/* if defined: fake colours for sky pixels */ +/* #define RE_FAKE_SKY_PIXELS */ + +/* ------------------------------------------------------------------------- */ + +unsigned int calcHaloZ(HaloRen *har, unsigned int zz) +{ + + if(har->type & HA_ONLYSKY) { + if(zz!=0x7FFFFFFF) zz= 0; + } + else { + zz= (zz>>8); + if(zz<0x800000) zz= (zz+0x7FFFFF); + else zz= (zz-0x800000); + } + return zz; +} + +/* ------------------------------------------------------------------------- */ + +void *renderPixel(float x, float y, int *obdata) +{ + void* data = NULL; +#ifdef RE_PIXSHADE_FULL_SAFETY + char fname[] = "renderPixel"; +#endif +#ifdef RE_FAKE_PIXELS + collector[0] = RE_UNITY_COLOUR_FLOAT; + collector[1] = 0; + collector[2] = RE_UNITY_COLOUR_FLOAT; + collector[3] = RE_UNITY_COLOUR_FLOAT; + return NULL; +#endif + + if (obdata[3] & RE_POLY) { + /* face pixels aren't rendered in floats yet, so we wrap it here */ + data = renderFacePixel(x, y, obdata[1]); + } + else if (obdata[3] & RE_HALO) { + data = renderHaloPixel(x, y, obdata[1]); + } + else if( obdata[1] == 0 ) { + /* for lamphalo, but doesn't seem to be called? Actually it is, and */ + /* it returns NULL pointers. */ + data = renderFacePixel(x, y, obdata[1]); + } +#ifdef RE_PIXSHADE_FULL_SAFETY + else RE_error(RE_BAD_FACE_TYPE, fname); +#endif /* RE_PIXSHADE_FULL_SAFETY */ + return data; + +} /* end of void renderPixel(float x, float y, int *obdata) */ + +/* ------------------------------------------------------------------------- */ + +void *renderFacePixel(float x, float y, int vlaknr) +/* Result goes into <collector> */ +{ +#ifdef RE_PIXSHADE_FULL_SAFETY + char fname[]= "renderFacePixelFloat"; +#endif + static VlakRen *vlr; /* static, because we don't want to recalculate vlr */ + /* when we already know it */ + static VertRen *v1, *v2, *v3; + static float t00, t01, t10, t11, dvlak, n1[3], n2[3], n3[3]; + static float s00, s01, s10, s11; + float *o1, *o2, *o3; + float u, v, l, dl, hox, hoy, detsh, fac, deler, alpha; + char *cp1, *cp2, *cp3; + +/* RE_error(RE_TRACE_COUNTER, fname); */ + +#ifdef RE_FAKE_FACE_PIXELS + collector[0] = 0; + collector[1] = 0; + collector[2] = RE_UNITY_COLOUR_FLOAT; + collector[3] = RE_UNITY_COLOUR_FLOAT; + /* try to keep the rest as clean as possible... */ + if( ((vlaknr & 0x7FFFFF) <= R.totvlak) + && ! ((R.vlaknr== -1)||(vlaknr<=0)) ) { + /* a bit superfluous to do this always, but */ + /* when this is switched on, it doesn't matter */ + vlr= RE_findOrAddVlak( (vlaknr-1) & 0x7FFFFF); + } else vlr = NULL; + return vlr; +#endif + + if(R.vlaknr== -1) { /* doet initrender */ + /* also set in the pixelrender loop */ + vlr= R.vlr= 0; + } + + if(vlaknr<=0) { /* sky */ + R.vlaknr= 0; + collector[3] = 0.0; + } + else if( (vlaknr & 0x7FFFFF) <= R.totvlak) { + + /* What follows now is a large bunch of texture coordinate mappings. */ + /* When this face is the same as the previous one, that means all */ + /* the coordinate remapping does not need to be recomputed. */ + if(vlaknr!=R.vlaknr) { + + vlr= RE_findOrAddVlak( (vlaknr-1) & 0x7FFFFF); + + R.mat= vlr->mat; + R.matren= R.mat->ren; + + if(R.matren==0) { /* tijdelijk voor debug */ + collector[3] = RE_UNITY_COLOUR_FLOAT; + collector[2] = 0.0; + collector[1] = RE_UNITY_COLOUR_FLOAT; + collector[0] = RE_UNITY_COLOUR_FLOAT; + return NULL; + } + + R.vlr= vlr; + + R.vno= vlr->n; + R.osatex= (R.matren->texco & TEXCO_OSA); + R.vlaknr= vlaknr; + + v1= vlr->v1; + dvlak= MTC_dot3Float(v1->co, vlr->n); + + if( (vlr->flag & R_SMOOTH) || (R.matren->texco & NEED_UV)) { /* uv nodig */ + if(vlaknr & 0x800000) { + v2= vlr->v3; + v3= vlr->v4; + } + else { + v2= vlr->v2; + v3= vlr->v3; + } + + if(vlr->snproj==0) { + t00= v3->co[0]-v1->co[0]; t01= v3->co[1]-v1->co[1]; + t10= v3->co[0]-v2->co[0]; t11= v3->co[1]-v2->co[1]; + } + else if(vlr->snproj==1) { + t00= v3->co[0]-v1->co[0]; t01= v3->co[2]-v1->co[2]; + t10= v3->co[0]-v2->co[0]; t11= v3->co[2]-v2->co[2]; + } + else { + t00= v3->co[1]-v1->co[1]; t01= v3->co[2]-v1->co[2]; + t10= v3->co[1]-v2->co[1]; t11= v3->co[2]-v2->co[2]; + } + + detsh= t00*t11-t10*t01; + t00/= detsh; t01/=detsh; + t10/=detsh; t11/=detsh; + + if(vlr->flag & R_SMOOTH) { /* puno's goedzetten */ + if(vlr->puno & ME_FLIPV1) MTC_cp3FloatInv(v1->n, n1); + else MTC_cp3Float(v1->n, n1); + + if(vlaknr & 0x800000) { + if(vlr->puno & ME_FLIPV3) MTC_cp3FloatInv(v2->n, n2); + else MTC_cp3Float(v2->n, n2); + + if(vlr->puno & ME_FLIPV4) MTC_cp3FloatInv(v3->n, n3); + else MTC_cp3Float(v3->n, n3); + } + else { + if(vlr->puno & ME_FLIPV2) MTC_cp3FloatInv(v2->n, n2); + else MTC_cp3Float(v2->n, n2); + + if(vlr->puno & ME_FLIPV3) MTC_cp3FloatInv(v3->n, n3); + else MTC_cp3Float(v3->n, n3); + } + } + if(R.matren->texco & TEXCO_STICKY) { + s00= v3->ho[0]/v3->ho[3] - v1->ho[0]/v1->ho[3]; + s01= v3->ho[1]/v3->ho[3] - v1->ho[1]/v1->ho[3]; + s10= v3->ho[0]/v3->ho[3] - v2->ho[0]/v2->ho[3]; + s11= v3->ho[1]/v3->ho[3] - v2->ho[1]/v2->ho[3]; + + detsh= s00*s11-s10*s01; + s00/= detsh; s01/=detsh; + s10/=detsh; s11/=detsh; + } + } + } /* end of if vlaknr*/ + + /* This trafo might be migrated to a separate function. It is used */ + /* quite often. */ + /* COXYZ nieuwe methode */ + if( (G.special1 & G_HOLO) + && (((Camera *)G.scene->camera->data)->flag & CAM_HOLO2) ) { + R.view[0]= (x+(R.xstart)+1.0+holoofs); + } + else { + R.view[0]= (x+(R.xstart)+1.0); + } + + if(R.flag & R_SEC_FIELD) { + if(R.r.mode & R_ODDFIELD) R.view[1]= (y+R.ystart+0.5)*R.ycor; + else R.view[1]= (y+R.ystart+1.5)*R.ycor; + } + else R.view[1]= (y+R.ystart+1.0)*R.ycor; + + R.view[2]= -R.viewfac; + + if(R.r.mode & R_PANORAMA) { + float panoco, panosi; + panoco = getPanovCo(); + panosi = getPanovSi(); + u= R.view[0]; v= R.view[2]; + + R.view[0]= panoco*u + panosi*v; + R.view[2]= -panosi*u + panoco*v; + } + + deler= vlr->n[0]*R.view[0] + vlr->n[1]*R.view[1] + vlr->n[2]*R.view[2]; + if (deler!=0.0) fac= R.zcor= dvlak/deler; + else fac= R.zcor= 0.0; + + R.co[0]= fac*R.view[0]; + R.co[1]= fac*R.view[1]; + R.co[2]= fac*R.view[2]; + + if(R.osatex || (R.r.mode & R_SHADOW) ) { + u= dvlak/(deler-vlr->n[0]); + v= dvlak/(deler- R.ycor*vlr->n[1]); + + O.dxco[0]= R.co[0]- (R.view[0]-1.0)*u; + O.dxco[1]= R.co[1]- (R.view[1])*u; + O.dxco[2]= R.co[2]- (R.view[2])*u; + + O.dyco[0]= R.co[0]- (R.view[0])*v; + O.dyco[1]= R.co[1]- (R.view[1]-1.0*R.ycor)*v; + O.dyco[2]= R.co[2]- (R.view[2])*v; + + } + + fac= Normalise(R.view); + R.zcor*= fac; /* voor mist */ + + if(R.osatex) { + if( (R.matren->texco & TEXCO_REFL) ) { + O.dxview= 1.0/fac; + O.dyview= R.ycor/fac; + } + } + + /* UV en TEX*/ + if( (vlr->flag & R_SMOOTH) || (R.matren->texco & NEED_UV)) { + if(vlr->snproj==0) { + u= (R.co[0]-v3->co[0])*t11-(R.co[1]-v3->co[1])*t10; + v= (R.co[1]-v3->co[1])*t00-(R.co[0]-v3->co[0])*t01; + if(R.osatex) { + O.dxuv[0]= O.dxco[0]*t11- O.dxco[1]*t10; + O.dxuv[1]= O.dxco[1]*t00- O.dxco[0]*t01; + O.dyuv[0]= O.dyco[0]*t11- O.dyco[1]*t10; + O.dyuv[1]= O.dyco[1]*t00- O.dyco[0]*t01; + } + } + else if(vlr->snproj==1) { + u= (R.co[0]-v3->co[0])*t11-(R.co[2]-v3->co[2])*t10; + v= (R.co[2]-v3->co[2])*t00-(R.co[0]-v3->co[0])*t01; + if(R.osatex) { + O.dxuv[0]= O.dxco[0]*t11- O.dxco[2]*t10; + O.dxuv[1]= O.dxco[2]*t00- O.dxco[0]*t01; + O.dyuv[0]= O.dyco[0]*t11- O.dyco[2]*t10; + O.dyuv[1]= O.dyco[2]*t00- O.dyco[0]*t01; + } + } + else { + u= (R.co[1]-v3->co[1])*t11-(R.co[2]-v3->co[2])*t10; + v= (R.co[2]-v3->co[2])*t00-(R.co[1]-v3->co[1])*t01; + if(R.osatex) { + O.dxuv[0]= O.dxco[1]*t11- O.dxco[2]*t10; + O.dxuv[1]= O.dxco[2]*t00- O.dxco[1]*t01; + O.dyuv[0]= O.dyco[1]*t11- O.dyco[2]*t10; + O.dyuv[1]= O.dyco[2]*t00- O.dyco[1]*t01; + } + } + l= 1.0+u+v; + + if(vlr->flag & R_SMOOTH) { + R.vn[0]= l*n3[0]-u*n1[0]-v*n2[0]; + R.vn[1]= l*n3[1]-u*n1[1]-v*n2[1]; + R.vn[2]= l*n3[2]-u*n1[2]-v*n2[2]; + + Normalise(R.vn); + if(R.osatex && (R.matren->texco & (TEXCO_NORM+TEXCO_REFL)) ) { + dl= O.dxuv[0]+O.dxuv[1]; + O.dxno[0]= dl*n3[0]-O.dxuv[0]*n1[0]-O.dxuv[1]*n2[0]; + O.dxno[1]= dl*n3[1]-O.dxuv[0]*n1[1]-O.dxuv[1]*n2[1]; + O.dxno[2]= dl*n3[2]-O.dxuv[0]*n1[2]-O.dxuv[1]*n2[2]; + dl= O.dyuv[0]+O.dyuv[1]; + O.dyno[0]= dl*n3[0]-O.dyuv[0]*n1[0]-O.dyuv[1]*n2[0]; + O.dyno[1]= dl*n3[1]-O.dyuv[0]*n1[1]-O.dyuv[1]*n2[1]; + O.dyno[2]= dl*n3[2]-O.dyuv[0]*n1[2]-O.dyuv[1]*n2[2]; + + } + } + else { + VECCOPY(R.vn, vlr->n); + } + + if(R.matren->mode & MA_ZINV) { /* z invert */ + /* R.vn[0]= -R.vn[0]; */ + /* R.vn[1]= -R.vn[1]; */ + } + + if(R.matren->texco & TEXCO_ORCO) { + if(v2->orco) { + o1= v1->orco; + o2= v2->orco; + o3= v3->orco; + + R.lo[0]= l*o3[0]-u*o1[0]-v*o2[0]; + R.lo[1]= l*o3[1]-u*o1[1]-v*o2[1]; + R.lo[2]= l*o3[2]-u*o1[2]-v*o2[2]; + + if(R.osatex) { + dl= O.dxuv[0]+O.dxuv[1]; + O.dxlo[0]= dl*o3[0]-O.dxuv[0]*o1[0]-O.dxuv[1]*o2[0]; + O.dxlo[1]= dl*o3[1]-O.dxuv[0]*o1[1]-O.dxuv[1]*o2[1]; + O.dxlo[2]= dl*o3[2]-O.dxuv[0]*o1[2]-O.dxuv[1]*o2[2]; + dl= O.dyuv[0]+O.dyuv[1]; + O.dylo[0]= dl*o3[0]-O.dyuv[0]*o1[0]-O.dyuv[1]*o2[0]; + O.dylo[1]= dl*o3[1]-O.dyuv[0]*o1[1]-O.dyuv[1]*o2[1]; + O.dylo[2]= dl*o3[2]-O.dyuv[0]*o1[2]-O.dyuv[1]*o2[2]; + } + } + } + + if(R.matren->texco & TEXCO_GLOB) { + VECCOPY(R.gl, R.co); + MTC_Mat4MulVecfl(R.viewinv, R.gl); + if(R.osatex) { + VECCOPY(O.dxgl, O.dxco); + MTC_Mat3MulVecfl(R.imat, O.dxco); + VECCOPY(O.dygl, O.dyco); + MTC_Mat3MulVecfl(R.imat, O.dyco); + } + } + if((R.matren->texco & TEXCO_UV) || (R.matren->mode & (MA_VERTEXCOL|MA_FACETEXTURE))) { + if(R.vlr->tface) { + float *uv1, *uv2, *uv3; + + uv1= R.vlr->tface->uv[0]; + if( (vlaknr & 0x800000) || (R.vlr->flag & R_FACE_SPLIT) ) { + uv2= R.vlr->tface->uv[2]; + uv3= R.vlr->tface->uv[3]; + } + else { + uv2= R.vlr->tface->uv[1]; + uv3= R.vlr->tface->uv[2]; + } + + R.uv[0]= -1.0 + 2.0*(l*uv3[0]-u*uv1[0]-v*uv2[0]); + R.uv[1]= -1.0 + 2.0*(l*uv3[1]-u*uv1[1]-v*uv2[1]); + + if(R.osatex) { + float duv[2]; + + dl= O.dxuv[0]+O.dxuv[1]; + duv[0]= O.dxuv[0]; + duv[1]= O.dxuv[1]; + + O.dxuv[0]= 2.0*(dl*uv3[0]-duv[0]*uv1[0]-duv[1]*uv2[0]); + O.dxuv[1]= 2.0*(dl*uv3[1]-duv[0]*uv1[1]-duv[1]*uv2[1]); + + dl= O.dyuv[0]+O.dyuv[1]; + duv[0]= O.dyuv[0]; + duv[1]= O.dyuv[1]; + + O.dyuv[0]= 2.0*(dl*uv3[0]-duv[0]*uv1[0]-duv[1]*uv2[0]); + O.dyuv[1]= 2.0*(dl*uv3[1]-duv[0]*uv1[1]-duv[1]*uv2[1]); + } + } + else { + R.uv[0]= 2.0*(u+.5); + R.uv[1]= 2.0*(v+.5); + } + } + if(R.matren->texco & TEXCO_NORM) { + R.orn[0]= R.vn[0]; + R.orn[1]= -R.vn[1]; + R.orn[2]= R.vn[2]; + } + if(R.matren->mode & MA_VERTEXCOL) { + + /* some colour calculations here */ + cp1= (char *)vlr->vcol; + if(cp1) { + if( (vlaknr & 0x800000) || (R.vlr->flag & R_FACE_SPLIT) ) { + cp2= (char *)(vlr->vcol+2); + cp3= (char *)(vlr->vcol+3); + } + else { + cp2= (char *)(vlr->vcol+1); + cp3= (char *)(vlr->vcol+2); + } + R.vcol[0]= (l*cp3[3]-u*cp1[3]-v*cp2[3])/255.0; + R.vcol[1]= (l*cp3[2]-u*cp1[2]-v*cp2[2])/255.0; + R.vcol[2]= (l*cp3[1]-u*cp1[1]-v*cp2[1])/255.0; + + } + else { + R.vcol[0]= 0.0; + R.vcol[1]= 0.0; + R.vcol[2]= 0.0; + } + } + if(R.matren->mode & MA_FACETEXTURE) { + if((R.matren->mode & MA_VERTEXCOL)==0) { + R.vcol[0]= 1.0; + R.vcol[1]= 1.0; + R.vcol[2]= 1.0; + } + /* shading here */ + if(vlr->tface) render_realtime_texture(); + } + + /* hierna klopt de u en v EN O.dxuv en O.dyuv niet meer */ + if(R.matren->texco & TEXCO_STICKY) { + if(v2->sticky) { + + /* opnieuw u en v berekenen */ + hox= x/Zmulx -1.0; + hoy= y/Zmuly -1.0; + u= (hox - v3->ho[0]/v3->ho[3])*s11 + - (hoy - v3->ho[1]/v3->ho[3])*s10; + v= (hoy - v3->ho[1]/v3->ho[3])*s00 + - (hox - v3->ho[0]/v3->ho[3])*s01; + l= 1.0+u+v; + + o1= v1->sticky; + o2= v2->sticky; + o3= v3->sticky; + + R.sticky[0]= l*o3[0]-u*o1[0]-v*o2[0]; + R.sticky[1]= l*o3[1]-u*o1[1]-v*o2[1]; + + if(R.osatex) { + O.dxuv[0]= s11/Zmulx; + O.dxuv[1]= - s01/Zmulx; + O.dyuv[0]= - s10/Zmuly; + O.dyuv[1]= s00/Zmuly; + + dl= O.dxuv[0]+O.dxuv[1]; + O.dxsticky[0]= dl*o3[0]-O.dxuv[0]*o1[0]-O.dxuv[1]*o2[0]; + O.dxsticky[1]= dl*o3[1]-O.dxuv[0]*o1[1]-O.dxuv[1]*o2[1]; + dl= O.dyuv[0]+O.dyuv[1]; + O.dysticky[0]= dl*o3[0]-O.dyuv[0]*o1[0]-O.dyuv[1]*o2[0]; + O.dysticky[1]= dl*o3[1]-O.dyuv[0]*o1[1]-O.dyuv[1]*o2[1]; + } + } + } + } + else { + VECCOPY(R.vn, vlr->n); + } + if(R.matren->texco & TEXCO_WINDOW) { + R.winco[0]= (x+(R.xstart))/(float)R.afmx; + R.winco[1]= (y+(R.ystart))/(float)R.afmy; + } + + /* After all texture coordinates are set and converted and */ + /* transformed, we need to put some colour on it: */ + shadeLampLusFloat(); + + /* MIST */ + if( (R.wrld.mode & WO_MIST) && (R.matren->mode & MA_NOMIST)==0 ){ + /* alpha returned in float? */ + alpha= mistfactor(R.co); + } + else alpha= 1.0; + + /* RAYTRACE (tijdelijk?) UITGESCHAKELD */ + + if(R.matren->alpha!=1.0 || alpha!=1.0) { + fac= alpha*(R.matren->alpha); + + collector[0] *= fac; /* This applies to transparent faces! Even */ + collector[1] *= fac; /* though it may seem to be a premul op, it */ + collector[2] *= fac; /* isn't. */ + collector[3] = fac; /* doesn't need scaling? */ + } + else { + collector[3] = 1.0; + } + } + else { + collector[0] = 1.0; + collector[1] = 1.0; + collector[2] = 0.0; + collector[3] = 1.0; + } + + /* Spothalos: do this here for covered pixels. It seems messy to place */ + /* it here, structure-wise, but it's more efficient. Also, not having it */ + /* here makes it difficult to do proper overlaying later on. */ + /* It starts off with a coordinate transform again. */ + if(R.flag & R_LAMPHALO) { + if(vlaknr<=0) { /* bereken viewvec en zet R.co op far */ + + /* this view vector stuff should get its own function */ + if( (G.special1 & G_HOLO) && + ((Camera *)G.scene->camera->data)->flag & CAM_HOLO2) { + R.view[0]= (x+(R.xstart)+1.0+holoofs); + } else { + R.view[0]= (x+(R.xstart)+1.0); + } + + if(R.flag & R_SEC_FIELD) { + if(R.r.mode & R_ODDFIELD) R.view[1]= (y+R.ystart+0.5)*R.ycor; + else R.view[1]= (y+R.ystart+1.5)*R.ycor; + } else { + R.view[1]= (y+R.ystart+1.0)*R.ycor; + } + + R.view[2]= -R.viewfac; + + if(R.r.mode & R_PANORAMA) { + float panoco, panosi; + panoco = getPanovCo(); + panosi = getPanovSi(); + u= R.view[0]; v= R.view[2]; + + R.view[0]= panoco*u + panosi*v; + R.view[2]= -panosi*u + panoco*v; + } + + R.co[2]= 0.0; + + } + + shadeSpotHaloPixelFloat(collector); +/* renderspothaloFix(collector); */ + + } + +#ifdef RE_PIXSHADE_FULL_SAFETY + if (!vlr) RE_error(RE_BAD_DATA_POINTER, fname); +#endif + + return vlr; + +} /* end of void renderFacePixelFloat(float x, float y, int vlaknr) */ + +/* ------------------------------------------------------------------------- */ +/* + - uses R.view to determine which pixel, I think? + - the spothalo is dumped quite unceremoniously on top of the col vector + This function is also (sort of) implemented in shadespothalofix, but without + all the clipping stuff. Somehow, the clipping here is _quite_ critical. + */ +void shadeSpotHaloPixelFloat(float *col) +{ + LampRen *lar; + float factor = 0.0; + int a; + float rescol[4]; + + + for(a=0; a<R.totlamp; a++) { + lar= R.la[a]; + if(lar->type==LA_SPOT && (lar->mode & LA_HALO) && lar->haint>0) { + + if(lar->org) { + lar->r= lar->org->r; + lar->g= lar->org->g; + lar->b= lar->org->b; + } + + /* determines how much spothalo we see */ + spotHaloFloat(lar, R.view, &factor); + + if(factor>0.0) { + + /* Why is alpha clipped? */ + if(factor > RE_FULL_COLOUR_FLOAT) rescol[3]= 1.0; + else rescol[3]= factor; + + /* erg vervelend: gammagecorrigeerd renderen EN addalphaADD */ + /* gaat niet goed samen */ + /* eigenlijk moet er een aparte 'optel' gamma komen */ + /* + There is a strange thing here: the spothalo seems to be + calculated in the space you would get when you go from + value space through inverse gamma! So we gamma-transform + to value-space, then integrate, blend, and gamma correct + _again_. + */ + + rescol[0] = factor * lar->r; /* Lampren rgb's are floats */ + rescol[1] = factor * lar->g; + rescol[2] = factor * lar->b; + + /* ---->add values, disregard alpha */ + /* - check for dest. alpha = 0. If so , just copy */ + /* this is a slightly different approach: I do the gamma */ + /* correction BEFORE the addition. What does the other */ + /* approach do? */ + if (col[3]< RE_EMPTY_COLOUR_FLOAT) { + col[0] = gammaCorrect(rescol[0]); + col[1] = gammaCorrect(rescol[1]); + col[2] = gammaCorrect(rescol[2]); + col[3] = rescol[3]; + } else { + col[0] += gammaCorrect(rescol[0]); + col[1] += gammaCorrect(rescol[1]); + col[2] += gammaCorrect(rescol[2]); + col[3] += rescol[3]; + } + + /* this clipping may have to go? Actually, if it's */ + /* done sooner, it may be more efficient */ + if(col[0] > RE_FULL_COLOUR_FLOAT) col[0] = 1.0; + if(col[1] > RE_FULL_COLOUR_FLOAT) col[1] = 1.0; + if(col[2] > RE_FULL_COLOUR_FLOAT) col[2] = 1.0; + if(col[3] > RE_FULL_COLOUR_FLOAT) col[3] = 1.0; + if(col[0] < RE_EMPTY_COLOUR_FLOAT) col[0] = 0.0; + if(col[1] < RE_EMPTY_COLOUR_FLOAT) col[1] = 0.0; + if(col[2] < RE_EMPTY_COLOUR_FLOAT) col[2] = 0.0; + if(col[3] < RE_EMPTY_COLOUR_FLOAT) col[3] = 0.0; + } + } + } + + if(col[0] < RE_EMPTY_COLOUR_FLOAT) col[0] = 0.0; + if(col[1] < RE_EMPTY_COLOUR_FLOAT) col[1] = 0.0; + if(col[2] < RE_EMPTY_COLOUR_FLOAT) col[2] = 0.0; + if(col[3] < RE_EMPTY_COLOUR_FLOAT) col[3] = 0.0; + +} + +/* ------------------------------------------------------------------------- */ + +void spotHaloFloat(struct LampRen *lar, float *view, float *intens) +{ + double a, b, c, disc, nray[3], npos[3]; + float t0, t1 = 0.0, t2= 0.0, t3, haint; + float p1[3], p2[3], ladist, maxz = 0.0, maxy = 0.0; + int snijp, doclip=1, use_yco=0; + int ok1=0, ok2=0; + + *intens= 0.0; + haint= lar->haint; + + VECCOPY(npos, lar->sh_invcampos); /* in initlamp berekend */ + + /* view roteren */ + VECCOPY(nray, view); + MTC_Mat3MulVecd(lar->imat, nray); + + if(R.wrld.mode & WO_MIST) { + /* een beetje patch... */ + R.zcor= -lar->co[2]; + haint *= mistfactor(lar->co); + if(haint==0.0) { + return; + } + } + + + /* maxz roteren */ + if(R.co[2]==0) doclip= 0; /* is als halo op sky */ + else { + p1[0]= R.co[0]-lar->co[0]; + p1[1]= R.co[1]-lar->co[1]; + p1[2]= R.co[2]-lar->co[2]; + + maxz= lar->imat[0][2]*p1[0]+lar->imat[1][2]*p1[1]+lar->imat[2][2]*p1[2]; + maxz*= lar->sh_zfac; + maxy= lar->imat[0][1]*p1[0]+lar->imat[1][1]*p1[1]+lar->imat[2][1]*p1[2]; + + if( fabs(nray[2]) <0.000001 ) use_yco= 1; + } + + /* z scalen zodat het volume genormaliseerd is */ + nray[2]*= lar->sh_zfac; + /* nray hoeft niet genormaliseerd */ + + ladist= lar->sh_zfac*lar->dist; + + /* oplossen */ + a = nray[0] * nray[0] + nray[1] * nray[1] - nray[2]*nray[2]; + b = nray[0] * npos[0] + nray[1] * npos[1] - nray[2]*npos[2]; + c = npos[0] * npos[0] + npos[1] * npos[1] - npos[2]*npos[2]; + + snijp= 0; + if (fabs(a) < 0.00000001) { + /* + * Only one intersection point... + */ + return; + } + else { + disc = b*b - a*c; + + if(disc==0.0) { + t1=t2= (-b)/ a; + snijp= 2; + } + else if (disc > 0.0) { + disc = sqrt(disc); + t1 = (-b + disc) / a; + t2 = (-b - disc) / a; + snijp= 2; + } + } + if(snijp==2) { + /* sorteren */ + if(t1>t2) { + a= t1; t1= t2; t2= a; + } + + /* z van snijpunten met diabolo */ + p1[2]= npos[2] + t1*nray[2]; + p2[2]= npos[2] + t2*nray[2]; + + /* beide punten evalueren */ + if(p1[2]<=0.0) ok1= 1; + if(p2[2]<=0.0 && t1!=t2) ok2= 1; + + /* minstens 1 punt met negatieve z */ + if(ok1==0 && ok2==0) return; + + /* snijpunt met -ladist, de bodem van de kegel */ + if(use_yco==0) { + t3= (-ladist-npos[2])/nray[2]; + + /* moet 1 van de snijpunten worden vervangen? */ + if(ok1) { + if(p1[2]<-ladist) t1= t3; + } + else { + ok1= 1; + t1= t3; + } + if(ok2) { + if(p2[2]<-ladist) t2= t3; + } + else { + ok2= 1; + t2= t3; + } + } + else if(ok1==0 || ok2==0) return; + + /* minstens 1 zichtbaar snijpunt */ + if(t1<0.0 && t2<0.0) return; + + if(t1<0.0) t1= 0.0; + if(t2<0.0) t2= 0.0; + + if(t1==t2) return; + + /* voor zekerheid nog eens sorteren */ + if(t1>t2) { + a= t1; t1= t2; t2= a; + } + + /* t0 berekenen: is de maximale zichtbare z (als halo door vlak */ + /* doorsneden wordt) */ + if(doclip) { + if(use_yco==0) t0= (maxz-npos[2])/nray[2]; + else t0= (maxy-npos[1])/nray[1]; + + if(t0<t1) return; + if(t0<t2) t2= t0; + } + + /* bereken punten */ + p1[0]= npos[0] + t1*nray[0]; + p1[1]= npos[1] + t1*nray[1]; + p1[2]= npos[2] + t1*nray[2]; + p2[0]= npos[0] + t2*nray[0]; + p2[1]= npos[1] + t2*nray[1]; + p2[2]= npos[2] + t2*nray[2]; + + + /* nu hebben we twee punten, hiermee maken we drie lengtes */ + + a= sqrt(p1[0]*p1[0]+p1[1]*p1[1]+p1[2]*p1[2]); + b= sqrt(p2[0]*p2[0]+p2[1]*p2[1]+p2[2]*p2[2]); + c= VecLenf(p1, p2); + + a/= ladist; + a= sqrt(a); + b/= ladist; + b= sqrt(b); + c/= ladist; + + *intens= c*( (1.0-a)+(1.0-b) ); + + /* LET OP: a,b en c NIET op 1.0 clippen, dit geeft kleine + overflowtjes op de rand (vooral bij smalle halo's) */ + if(*intens<=0.0) return; + + /* zachte gebied */ + /* vervalt omdat t0 nu ook voor p1/p2 wordt gebruikt */ + /* if(doclip && t0<t2) { */ + /* *intens *= (t0-t1)/(t2-t1); */ + /* } */ + + *intens *= haint; + + if(lar->shb && lar->shb->shadhalostep) { + /* from shadbuf.c, returns float */ + *intens *= shadow_halo(lar, p1, p2); + } + /* if(lar->mode & LA_TEXTURE) do_lamphalo_tex(lar, p1, p2, intens); */ + + } +} /* end of void spotHaloFloat(struct LampRen *, float *view, float *intens) */ + +/* ------------------------------------------------------------------------- */ + +void shadeLampLusFloat() +{ + LampRen *lar; + register Material *ma; + float i, inp, inpr, t, lv[3], lampdist, ld = 0; + float ir, ig, ib; + float isr=0,isg=0,isb=0; + float lvrot[3], *vn, *view, shadfac, soft; + int a; + float shadfacvec[3] = {1.0, 1.0, 1.0}; + + vn= R.vn; + view= R.view; + ma= R.matren; + + /* aparte lus */ + if(ma->mode & MA_ONLYSHADOW) { + shadfac= ir= 0.0; + for(a=0; a<R.totlamp; a++) { + lar= R.la[a]; + + if(lar->mode & LA_LAYER) if((lar->lay & R.vlr->lay)==0) continue; + + if(lar->shb) { + /* alleen testen binnen spotbundel */ + lv[0]= R.co[0]-lar->co[0]; + lv[1]= R.co[1]-lar->co[1]; + lv[2]= R.co[2]-lar->co[2]; + Normalise(lv); + inpr= lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2]; + if(inpr>lar->spotsi) { + + inp= vn[0]*lv[0] + vn[1]*lv[1] + vn[2]*lv[2]; + + RE_testshadowbuf(lar->shadowBufOb, lar->shb, inp, shadfacvec); +/* testshadowbuf(lar->shb, inp, shadfacvec); */ + + i= shadfacvec[0]; + + t= inpr - lar->spotsi; + if(t<lar->spotbl && lar->spotbl!=0.0) { + t/= lar->spotbl; + t*= t; + i= t*i+(1.0-t); + } + + shadfac+= i; + ir+= 1.0; + } + else { + shadfac+= 1.0; + ir+= 1.0; + } + } + } + if(ir>0.0) shadfac/= ir; + ma->alpha= (R.mat->alpha)*(1.0-shadfac); + + collector[0] = 0.0; + collector[1] = 0.0; + collector[2] = 0.0; + /* alpha is not set.... why?*/ + return; + } + + if(ma->mode & (MA_VERTEXCOLP|MA_FACETEXTURE)) { + ma->r= R.vcol[0]; + ma->g= R.vcol[1]; + ma->b= R.vcol[2]; + } + + /* mirror reflection colour */ + R.refcol[0]= R.refcol[1]= R.refcol[2]= R.refcol[3]= 0.0; + + if(ma->texco) { + + if(ma->texco & TEXCO_REFL) { + RE_calc_R_ref(); + } + + if(ma->mode & (MA_VERTEXCOLP|MA_FACETEXTURE)) { + R.mat->r= R.vcol[0]; + R.mat->g= R.vcol[1]; + R.mat->b= R.vcol[2]; + } + + do_material_tex(); + } + + if(ma->mode & MA_SHLESS) { + if( (ma->mode & (MA_VERTEXCOL+MA_VERTEXCOLP+MA_FACETEXTURE) )) { + ir= R.vcol[0]*ma->r; + ig= R.vcol[1]*ma->g; + ib= R.vcol[2]*ma->b; + } + else { + ir= ma->r; /* apparently stored as [0,1]? */ + ig= ma->g; + ib= ma->b; + } + + collector[0] = ir; /* no clipping, no alpha */ + collector[1] = ig; + collector[2] = ib; + return; + } + + if( (ma->mode & (MA_VERTEXCOL+MA_VERTEXCOLP))== MA_VERTEXCOL ) { + ir= ma->emit+R.vcol[0]; + ig= ma->emit+R.vcol[1]; + ib= ma->emit+R.vcol[2]; + } + else ir= ig= ib= ma->emit; + + for(a=0; a<R.totlamp; a++) { + lar= R.la[a]; + + /* test op lamplayer */ + if(lar->mode & LA_LAYER) if((lar->lay & R.vlr->lay)==0) continue; + + /* lampdist berekening */ + if(lar->type==LA_SUN || lar->type==LA_HEMI) { + VECCOPY(lv, lar->vec); + lampdist= 1.0; + } + else { + lv[0]= R.co[0]-lar->co[0]; + lv[1]= R.co[1]-lar->co[1]; + lv[2]= R.co[2]-lar->co[2]; + ld= sqrt(lv[0]*lv[0]+lv[1]*lv[1]+lv[2]*lv[2]); + lv[0]/= ld; + lv[1]/= ld; + lv[2]/= ld; + + /* ld wordt verderop nog gebruikt (texco's) */ + + if(lar->mode & LA_QUAD) { + t= 1.0; + if(lar->ld1>0.0) + t= lar->dist/(lar->dist+lar->ld1*ld); + if(lar->ld2>0.0) + t*= lar->distkw/(lar->distkw+lar->ld2*ld*ld); + + lampdist= t; + } + else { + lampdist= (lar->dist/(lar->dist+ld)); + } + + if(lar->mode & LA_SPHERE) { + t= lar->dist - ld; + if(t<0.0) continue; + + t/= lar->dist; + lampdist*= (t); + } + + } + + if(lar->mode & LA_TEXTURE) do_lamp_tex(lar, lv); + + if(lar->type==LA_SPOT) { + + /* hier de fie Inp() vertaagt! */ + + if(lar->mode & LA_SQUARE) { + if(lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2]>0.0) { + float x; + + /* rotate view to lampspace */ + VECCOPY(lvrot, lv); + MTC_Mat3MulVecfl(lar->imat, lvrot); + + x= MAX2(fabs(lvrot[0]/lvrot[2]) , fabs(lvrot[1]/lvrot[2])); + /* 1.0/(sqrt(1+x*x)) is equivalent to cos(atan(x)) */ + + inpr= 1.0/(sqrt(1+x*x)); + } + else inpr= 0.0; + } + else { + inpr= lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2]; + } + + t= lar->spotsi; + if(inpr<t) continue; + else { + t= inpr-t; + i= 1.0; + soft= 1.0; + if(t<lar->spotbl && lar->spotbl!=0.0) { + /* zachte gebied */ + i= t/lar->spotbl; + t= i*i; + soft= (3.0*t-2.0*t*i); + inpr*= soft; + } + if(lar->mode & LA_ONLYSHADOW && lar->shb) { + if(ma->mode & MA_SHADOW) { + /* inprodukt positief: voorzijde vlak! */ + inp= vn[0]*lv[0] + vn[1]*lv[1] + vn[2]*lv[2]; + if(inp>0.0) { + + /* testshadowbuf==0.0 : 100% schaduw */ + RE_testshadowbuf(lar->shadowBufOb, lar->shb, inp, shadfacvec); +/* testshadowbuf(lar->shb, inp, shadfacvec); */ + shadfac = 1.0 - shadfacvec[0]; + + if(shadfac>0.0) { + shadfac*= inp*soft*lar->energy; + ir -= shadfac; + ig -= shadfac; + ib -= shadfac; + + continue; + } + } + } + } + lampdist*=inpr; + } + if(lar->mode & LA_ONLYSHADOW) continue; + + if(lar->mode & LA_OSATEX) { + R.osatex= 1; /* signaal voor multitex() */ + + O.dxlv[0]= lv[0] - (R.co[0]-lar->co[0]+O.dxco[0])/ld; + O.dxlv[1]= lv[1] - (R.co[1]-lar->co[1]+O.dxco[1])/ld; + O.dxlv[2]= lv[2] - (R.co[2]-lar->co[2]+O.dxco[2])/ld; + + O.dylv[0]= lv[0] - (R.co[0]-lar->co[0]+O.dyco[0])/ld; + O.dylv[1]= lv[1] - (R.co[1]-lar->co[1]+O.dyco[1])/ld; + O.dylv[2]= lv[2] - (R.co[2]-lar->co[2]+O.dyco[2])/ld; + } + + } + + /* inprodukt en reflectivity*/ + inp=i= vn[0]*lv[0] + vn[1]*lv[1] + vn[2]*lv[2]; + if(lar->type==LA_HEMI) { + i= 0.5*i+0.5; + } + if(i>0.0) { + i*= lampdist*ma->ref; + } + + /* schaduw en spec */ + if(i> -0.41) { /* beetje willekeurig, beetje getest */ + shadfac= 1.0; + if(lar->shb) { + if(ma->mode & MA_SHADOW) { + float shadfacvec[3] = {1.0, 1.0, 1.0}; + RE_testshadowbuf(lar->shadowBufOb, lar->shb, inp, shadfacvec); +/* testshadowbuf(lar->shb, inp, shadfacvec); */ + shadfac = shadfacvec[0]; + +/* shadfac = 1.0; : no shadow */ + if(shadfac==0.0) continue; + i*= shadfac; + } + } + /* specularity */ + + if(ma->spec!=0.0) { + + if(lar->type==LA_SUN || lar->type==LA_HEMI) { + if(lar->type==LA_SUN) { + lv[2]-= 1.0; + } + else { + lv[0]+= view[0]; + lv[1]+= view[1]; + lv[2]+= view[2]; + } + + Normalise(lv); + + t= vn[0]*lv[0]+vn[1]*lv[1]+vn[2]*lv[2]; + + if(lar->type==LA_HEMI) { + t= 0.5*t+0.5; + } + /* let op: shadfac en lampdist uit onderstaande */ + + /* no more speclim */ + + t= ma->spec*RE_Spec(t, ma->har); + isr+= t*(lar->r * ma->specr); + isg+= t*(lar->g * ma->specg); + isb+= t*(lar->b * ma->specb); + } + else { + /* Does specular reflection? This would be the place */ + /* to put BRDFs. */ + t= shadfac*ma->spec*lampdist*CookTorr(vn, lv, view, ma->har); + isr+= t*(lar->r * ma->specr); + isg+= t*(lar->g * ma->specg); + isb+= t*(lar->b * ma->specb); + } + } + } + if(i>0.0) { + ir+= i*lar->r; + ig+= i*lar->g; + ib+= i*lar->b; + } + } + + /* clipping: maybe don't clip? (nzc) */ + /* yes, it shouldn't be done... unfortunately the current + * gammaCorrect implementation doesn't handle negative values + * correctly ( (-1)^2 = 1!!) (ton) + */ +/* if(ir<0.0) ir= 0.0; */ +/* if(ig<0.0) ig= 0.0; */ +/* if(ib<0.0) ib= 0.0; */ +/* if(isr<0.0) isr= 0.0; */ +/* if(isg<0.0) isg= 0.0; */ +/* if(isb<0.0) isb= 0.0; */ + /* Well, it does now. -(1^2) = -1 :) (nzc) */ + + if(ma->mode & MA_ZTRA) { /* ztra shade */ + if(ma->spectra!=0.0) { + + t = MAX3(isr, isb, isg); + t *= ma->spectra; + if(t>1.0) t= 1.0; + if(ma->mapto & MAP_ALPHA) ma->alpha= (1.0-t)*ma->alpha+t; + else ma->alpha= (1.0-t)*R.mat->alpha+t; + } + } + + if(R.refcol[0]==0.0) { + collector[0] = (ma->r * ir) + ma->ambr + isr; + collector[1] = (ma->g * ig) + ma->ambg + isg; + collector[2] = (ma->b * ib) + ma->ambb + isb; + /* clip for >0 ? */ + } + else { + collector[0] = (ma->mirr * R.refcol[1]) + + ((1.0 - (ma->mirr * R.refcol[0])) * ((ma->r * ir) + ma->ambr)) + + isr; + collector[1] = (ma->mirg*R.refcol[2]) + + ((1.0 - (ma->mirg * R.refcol[0])) * ((ma->g * ig) +ma->ambg)) + +isg; + collector[2] = (ma->mirb*R.refcol[3]) + + ((1.0 - (ma->mirb * R.refcol[0])) * ((ma->b * ib) +ma->ambb)) + +isb; + } + +#ifdef RE_FAKE_LAMP_SHADE + collector[0] = 0.5; + collector[1] = 0.5; + collector[2] = 1.0; +#endif + +} + +/* ------------------------------------------------------------------------- */ + +void* renderHaloPixel(float x, float y, int haloNr) { + HaloRen *har = NULL; + float dist = 0.0; + unsigned int zz = 0; + +#ifdef RE_FAKE_HALO_PIXELS + collector[0] = RE_UNITY_COLOUR_FLOAT; + collector[1] = 0; + collector[2] = 0; + collector[3] = RE_UNITY_COLOUR_FLOAT; + har = RE_findOrAddHalo(haloNr); /* crash prevention */ + return (void*) har; +#endif + + /* Find har to go with haloNr */ + har = RE_findOrAddHalo(haloNr); + + /* zz is a strange number... This call should effect that halo's are */ + /* never cut? Seems a bit strange to me now... */ + /* This might be the zbuffer depth */ + zz = calcHaloZ(har, 0x7FFFFFFF); + + /* distance of this point wrt. the halo center. Maybe xcor is also needed? */ + dist = ((x - har->xs) * (x - har->xs)) + + ((y - har->ys) * (y - har->ys) * R.ycor * R.ycor) ; + + collector[0] = RE_ZERO_COLOUR_FLOAT; collector[1] = RE_ZERO_COLOUR_FLOAT; + collector[2] = RE_ZERO_COLOUR_FLOAT; collector[3] = RE_ZERO_COLOUR_FLOAT; + + if (dist < har->radsq) { + shadeHaloFloat(har, collector, zz, dist, + (x - har->xs), (y - har->ys) * R.ycor, har->flarec); + /* make a second fake pixel? */ +#ifdef RE_FAKE_HALO_PIXELS_2 + collector[0] = RE_UNITY_COLOUR_FLOAT; + collector[1] = 0; + collector[2] = 0; + collector[3] = RE_UNITY_COLOUR_FLOAT; +#endif + }; /* else: this pixel is not rendered for this halo: no colour */ + + return (void*) har; + +} /* end of void* renderHaloPixel(float x, float y, int haloNr) */ + +/* ------------------------------------------------------------------------- */ + +extern float hashvectf[]; +void shadeHaloFloat(HaloRen *har, + float *col, unsigned int zz, + float dist, float xn, + float yn, short flarec) +{ + /* in col invullen */ + /* migrate: fill collector */ + float t, zn, radist, ringf=0.0, linef=0.0, alpha, si, co, colf[4]; + int a; + + if(R.wrld.mode & WO_MIST) { + if(har->type & HA_ONLYSKY) { + /* sterren geen mist */ + alpha= har->alfa; + } + else { + /* een beetje patch... */ + R.zcor= -har->co[2]; + alpha= mistfactor(har->co)*har->alfa; + } + } + else alpha= har->alfa; + + if(alpha==0.0) { + col[0] = 0.0; + col[1] = 0.0; + col[2] = 0.0; + col[3] = 0.0; + return; + } + + radist= sqrt(dist); + + /* let op: hiermee wordt gesjoemeld: flarec wordt op nul gezet in de pixstruct */ + if(flarec) har->pixels+= (int)(har->rad-radist); + + if(har->ringc) { + float *rc, fac; + int ofs; + + /* per ring een alicirc */ + ofs= har->seed; + + for(a= har->ringc; a>0; a--, ofs+=2) { + + rc= hashvectf + (ofs % 768); + + fac= fabs( rc[1]*(har->rad*fabs(rc[0]) - radist) ); + + if(fac< 1.0) { + ringf+= (1.0-fac); + } + } + } + + if(har->type & HA_VECT) { + dist= fabs( har->cos*(yn) - har->sin*(xn) )/har->rad; + if(dist>1.0) dist= 1.0; + if(har->tex) { + zn= har->sin*xn - har->cos*yn; + yn= har->cos*xn + har->sin*yn; + xn= zn; + } + } + else dist= dist/har->radsq; + + if(har->type & HA_FLARECIRC) { + + dist= 0.5+fabs(dist-0.5); + + } + + if(har->hard>=30) { + dist= sqrt(dist); + if(har->hard>=40) { + dist= sin(dist*M_PI_2); + if(har->hard>=50) { + dist= sqrt(dist); + } + } + } + else if(har->hard<20) dist*=dist; + + dist=(1.0-dist); + + if(har->linec) { + float *rc, fac; + int ofs; + + /* per starpoint een aliline */ + ofs= har->seed; + + for(a= har->linec; a>0; a--, ofs+=3) { + + rc= hashvectf + (ofs % 768); + + fac= fabs( (xn)*rc[0]+(yn)*rc[1]); + + if(fac< 1.0 ) { + linef+= (1.0-fac); + } + } + + linef*= dist; + + } + + if(har->starpoints) { + float ster, hoek; + /* rotatie */ + hoek= atan2(yn, xn); + hoek*= (1.0+0.25*har->starpoints); + + co= cos(hoek); + si= sin(hoek); + + hoek= (co*xn+si*yn)*(co*yn-si*xn); + + ster= fabs(hoek); + if(ster>1.0) { + ster= (har->rad)/(ster); + + if(ster<1.0) dist*= sqrt(ster); + } + } + + /* halo wordt doorsneden? */ + if(har->zs> zz-har->zd) { + t= ((float)(zz-har->zs))/(float)har->zd; + alpha*= sqrt(sqrt(t)); + } + + dist*= alpha; + ringf*= dist; + linef*= alpha; + + if(dist<0.003) { + col[0] = 0.0; + col[1] = 0.0; + col[2] = 0.0; + col[3] = 0.0; + return; + } + + /* The colour is either the rgb spec-ed by the user, or extracted from */ + /* the texture */ + if(har->tex) { + colf[3]= dist; + do_halo_tex(har, xn, yn, colf); + colf[0]*= colf[3]; + colf[1]*= colf[3]; + colf[2]*= colf[3]; + + } + else { + colf[0]= dist*har->r; + colf[1]= dist*har->g; + colf[2]= dist*har->b; + if(har->type & HA_XALPHA) colf[3]= dist*dist; + else colf[3]= dist; + } + + if(har->mat && har->mat->mode & MA_HALO_SHADE) { + /* we test for lights because of preview... */ + if(R.totlamp) render_lighting_halo(har, colf); + } + + /* Next, we do the line and ring factor modifications. It seems we do */ + /* uchar calculations, but it's basically doing float arith with a 255 */ + /* scale factor. */ + if(linef!=0.0) { + Material *ma= har->mat; + linef *= 255.0; + + colf[0]+= linef * ma->specr; + colf[1]+= linef * ma->specg; + colf[2]+= linef * ma->specb; + + if(har->type & HA_XALPHA) colf[3]+= linef*linef; + else colf[3]+= linef; + } + if(ringf!=0.0) { + Material *ma= har->mat; + ringf *= 255.0; + + colf[0]+= ringf * ma->mirr; + colf[1]+= ringf * ma->mirg; + colf[2]+= ringf * ma->mirb; + + if(har->type & HA_XALPHA) colf[3]+= ringf*ringf; + else colf[3]+= ringf; + } + + /* convert to [0.0; 1.0] range */ + col[0] = colf[0] / 255.0; + col[1] = colf[1] / 255.0; + col[2] = colf[2] / 255.0; + col[3] = colf[3]; + +} /* end of shadeHaloFloat() */ + +/* ------------------------------------------------------------------------- */ + +void renderSpotHaloPixel(float x, float y, float* target) +{ + float u = 0.0, v = 0.0; + +#ifdef RE_FAKE_SPOTHALO_PIXELS + target[0] = 0.0; + target[1] = 1.0; + target[2] = 0.0; + target[3] = 1.0; + return; +#endif + + /* Strange fix? otherwise done inside shadepixel. It's sort */ + /* of like telling this is a 'sky' pixel. */ + R.vlaknr = 0; + target[3] = 0.0; + + /* + Here's the viewvector setting again. + */ + if( (G.special1 & G_HOLO) && ((Camera *)G.scene->camera->data)->flag & CAM_HOLO2) { + R.view[0]= (x+(R.xstart)+1.0+holoofs); + } + else { + R.view[0]= (x+(R.xstart)+1.0); + } + + if(R.flag & R_SEC_FIELD) { + if(R.r.mode & R_ODDFIELD) R.view[1]= (y+R.ystart+0.5)*R.ycor; + else R.view[1]= (y+R.ystart+1.5)*R.ycor; + } + else R.view[1]= (y+R.ystart+1.0)*R.ycor; + + R.view[2]= -R.viewfac; + + if(R.r.mode & R_PANORAMA) { + float panoco, panosi; + panoco = getPanovCo(); + panosi = getPanovSi(); + u= R.view[0]; v= R.view[2]; + + R.view[0]= panoco*u + panosi*v; + R.view[2]= -panosi*u + panoco*v; + } + + R.co[2]= 0.0; + + /* This little function is a patch for spothalos on non-covered pixels. */ + renderspothaloFix(target); + +} /* end of void renderSpotHaloPixel(float x, float y, float colbuf[4]) */ + +/* ------------------------------------------------------------------------- */ +/* + This routine is only for sky-pixels. Therefore, no gamma needs to be done. + One strange side-effect is when you have a negative halo lamp. This suddenly + gives loads of colour. That particular case has been explicitly guarded: no + halo for negative halo spots! + + This routine uses the viewvector in R... to determine what to shade. Just + deposit the colour to be blended in col. + + I would like to add colours 'normally', so this routine would be the same + for spothalo on covered pixels, but that doesn't work. Some strange clipping + occurs... + */ +void renderspothaloFix(float *col) +{ + LampRen *lar; + float i; + int a; + + for(a=0; a<R.totlamp; a++) { + lar= R.la[a]; + if((lar->type==LA_SPOT) + && (lar->mode & LA_HALO) + && !(lar->mode & LA_NEG) + && (lar->haint>0)) { + + if(lar->org) { + lar->r= lar->org->r; + lar->g= lar->org->g; + lar->b= lar->org->b; + } + + /* returns the intensity in i */ + spotHaloFloat(lar, R.view, &i); + + if(i>0.0) { + /* Premul colours here! */ + col[0] = i * lar->r; + col[1] = i * lar->g; + col[2] = i * lar->b; + col[3] = i; + } + } + } +} + +/* ------------------------------------------------------------------------- */ +/* + + There are three different modes for blending sky behind a picture: + 1. sky = blend in sky directly + 2. premul = don't do sky, but apply alpha (so pretend the picture ends + exactly at it's boundaries) + 3. key = don't do anything + Now the stupid thing is that premul means do nothing for us, and key + we have to adjust a bit... + +*/ + +/* Sky vars. */ +enum RE_SkyAlphaBlendingType keyingType = RE_ALPHA_SKY; /* The blending type */ + +void setSkyBlendingMode(enum RE_SkyAlphaBlendingType mode) { + if ((RE_ALPHA_NODEF < mode) && (mode < RE_ALPHA_MAX) ) { + keyingType = mode; + } else { + /* error: false mode received */ + keyingType = RE_ALPHA_SKY; + } +} + +enum RE_SkyAlphaBlendingType getSkyBlendingMode() { + return keyingType; +} + +/* This one renders into collector, as always. */ +void renderSkyPixelFloat(float x, float y) +{ +#ifdef RE_FAKE_SKY_PIXELS + collector[0] = 1.0; + collector[1] = 1.0; + collector[2] = 0.0; + collector[3] = 1.0; + return; +#endif + + switch (keyingType) { + case RE_ALPHA_PREMUL: + /* Premul: don't fill, and don't change the values! */ + case RE_ALPHA_KEY: + /* + Key: Leave pixels fully coloured, but retain alpha data, so you + can composit the picture later on. + - Should operate on the stack outcome! + */ +/* collector[0] = 0.0; */ +/* collector[1] = 0.0; */ +/* collector[2] = 0.0; */ +/* collector[3] = 0.0; */ + collector[3]= 0.0; + collector[0]= R.wrld.horr; + collector[1]= R.wrld.horg; + collector[2]= R.wrld.horb; + break; + case RE_ALPHA_SKY: + /* Fill in the sky as if it were a normal face. */ + shadeSkyPixel(x, y); + break; + default: + ; /* Error: illegal alpha blending state */ + } +} + +/* + Stuff the sky colour into the collector. + */ +void shadeSkyPixel(float fx, float fy) { + + /* + The rules for sky: + 1. Draw an image, if a background image was provided. Stop + 2. get texture and colour blend, and combine these. + */ + + float fac; + + /* 1. Do a backbuffer image: */ + if(R.r.bufflag & 1) { + fillBackgroundImage(fx, fy); + return; + } else if((R.wrld.skytype & (WO_SKYBLEND+WO_SKYTEX))==0) { + /* + 2. Test for these types of sky. The old renderer always had to check for + coverage, but we don't need that anymore + - SKYBLEND or SKYTEX disabled: fill in a flat colour + - otherwise, do the appropriate mapping (tex or colour blend) + There used to be cached chars here, but they are not useful anymore + */ + collector[0] = R.wrld.horr; + collector[1] = R.wrld.horg; + collector[2] = R.wrld.horb; + collector[3] = RE_UNITY_COLOUR_FLOAT; + } else { + /* + 3. Which type(s) is(are) this (these)? This has to be done when no simple + way of determining the colour exists. + */ + + /* This one true because of the context of this routine */ +/* if(rect[3] < 254) { */ + if(R.wrld.skytype & WO_SKYPAPER) { + R.view[0]= (fx+(R.xstart))/(float)R.afmx; + R.view[1]= (fy+(R.ystart))/(float)R.afmy; + R.view[2]= 0.0; + } + else { + /* Wasn't this some pano stuff? */ + R.view[0]= (fx+(R.xstart)+1.0); + + if(R.flag & R_SEC_FIELD) { + if(R.r.mode & R_ODDFIELD) R.view[1]= (fy+R.ystart+0.5)*R.ycor; + else R.view[1]= (fy+R.ystart+1.5)*R.ycor; + } + else R.view[1]= (fy+R.ystart+1.0)*R.ycor; + + R.view[2]= -R.viewfac; + + fac= Normalise(R.view); + if(R.wrld.skytype & WO_SKYTEX) { + O.dxview= 1.0/fac; + O.dyview= R.ycor/fac; + } + } + + if(R.r.mode & R_PANORAMA) { + float panoco, panosi; + float u, v; + + panoco = getPanovCo(); + panosi = getPanovSi(); + u= R.view[0]; v= R.view[2]; + + R.view[0]= panoco*u + panosi*v; + R.view[2]= -panosi*u + panoco*v; + } + + /* get sky colour in the collector */ + shadeSkyPixelFloat(fy); + } + + +} + +/* Only line number is important here. Result goes to collector[4] */ +void shadeSkyPixelFloat(float y) +{ + + /* Why is this setting forced? Seems silly to me. It is tested in the texture unit. */ + R.wrld.skytype |= WO_ZENUP; + + /* Some view vector stuff. */ + if(R.wrld.skytype & WO_SKYREAL) { + + R.inprz= R.view[0]*R.grvec[0]+ R.view[1]*R.grvec[1]+ R.view[2]*R.grvec[2]; + + if(R.inprz<0.0) R.wrld.skytype-= WO_ZENUP; + R.inprz= fabs(R.inprz); + } + else if(R.wrld.skytype & WO_SKYPAPER) { + R.inprz= 0.5+ 0.5*R.view[1]; + } + else { + /* the fraction of how far we are above the bottom of the screen */ + R.inprz= fabs(0.5+ R.view[1]); + } + + /* Careful: SKYTEX and SKYBLEND are NOT mutually exclusive! If */ + /* SKYBLEND is active, the texture and colour blend are added. */ + if(R.wrld.skytype & WO_SKYTEX) { + VECCOPY(R.lo, R.view); + if(R.wrld.skytype & WO_SKYREAL) { + + MTC_Mat3MulVecfl(R.imat, R.lo); + + SWAP(float, R.lo[1], R.lo[2]); + + } + + R.osatex= 0; + + /* sky texture? I wonder how this manages to work... */ + /* Does this communicate with R.wrld.hor{rgb}? Yes. */ + do_sky_tex(); + /* internally, T{rgb} are used for communicating colours in the */ + /* texture pipe, externally, this particular routine uses the */ + /* R.wrld.hor{rgb} thingies. */ + + } + + /* Why are this R. members? */ + if(R.inprz>1.0) R.inprz= 1.0; + R.inprh= 1.0-R.inprz; + + /* No clipping, no conversion! */ + if(R.wrld.skytype & WO_SKYBLEND) { + collector[0] = (R.inprh*R.wrld.horr + R.inprz*R.wrld.zenr); + collector[1] = (R.inprh*R.wrld.horg + R.inprz*R.wrld.zeng); + collector[2] = (R.inprh*R.wrld.horb + R.inprz*R.wrld.zenb); + } else { + /* Done when a texture was grabbed. */ + collector[0]= R.wrld.horr; + collector[1]= R.wrld.horg; + collector[2]= R.wrld.horb; + } + + collector[3]= RE_UNITY_COLOUR_FLOAT; + /* om verkeerde optimalisatie alphaover van flares te voorkomen */ + /* ??? seems strange to me... This used to be a 1 when the colours */ + /* were chars. might need a separate flag for this... */ +} + + +/* + Render pixel (x,y) from the backbuffer into the collector + + backbuf is type Image, backbuf->ibuf is an ImBuf. ibuf->rect is the + rgba data (32 bit total), in ibuf->x by ibuf->y pixels. Copying + should be really easy. I hope I understand the way ImBuf works + correctly. (nzc) +*/ +void fillBackgroundImage(float x, float y) +{ + + int iy, ix; + unsigned int* imBufPtr; + char *colSource; + + /* This double check is bad... */ + if (!(R.backbuf->ok)) { + /* Something went sour here... bail... */ + collector[0] = 0.0; + collector[1] = 0.0; + collector[2] = 0.0; + collector[3] = 1.0; + return; + } + /* load image if not already done?*/ + if(R.backbuf->ibuf==0) { + R.backbuf->ibuf= IMB_loadiffname(R.backbuf->name, IB_rect); + if(R.backbuf->ibuf==0) { + /* load failed .... keep skipping */ + R.backbuf->ok= 0; + return; + } + } + + /* Now for the real extraction: */ + /* Get the y-coordinate of the scanline? */ + iy= (int) ((y+R.afmy+R.ystart)*R.backbuf->ibuf->y)/(2*R.afmy); + ix= (int) ((x+R.afmx+R.xstart)*R.backbuf->ibuf->x)/(2*R.afmx); + + /* correct in case of fields rendering: */ + if(R.flag & R_SEC_FIELD) { + if((R.r.mode & R_ODDFIELD)==0) { + if( iy<R.backbuf->ibuf->y) iy++; + } + else { + if( iy>0) iy--; + } + } + + /* Offset into the buffer: start of scanline y: */ + imBufPtr = R.backbuf->ibuf->rect + + (iy * R.backbuf->ibuf->x) + + ix; + + colSource = (char*) imBufPtr; + + cpCharColV2FloatColV(colSource, collector); + +} + +/* eof */ |