diff options
Diffstat (limited to 'source/blender/render/intern')
17 files changed, 3590 insertions, 3315 deletions
diff --git a/source/blender/render/intern/include/pixelblending.h b/source/blender/render/intern/include/pixelblending.h index 2713b2023a9..04c5a3977a3 100644 --- a/source/blender/render/intern/include/pixelblending.h +++ b/source/blender/render/intern/include/pixelblending.h @@ -62,14 +62,6 @@ void addalphaAddFloat(float *dest, float *source); */ void addalphaUnderGammaFloat(float *doel, float *bron); -/** -* Copy the colour buffer output to R.rectot, to line y. - */ -void transferColourBufferToOutput(float *buf, int y); -/** -* using default transforms for brightness, gamma, hue, saturation etc. - */ -void std_floatcol_to_charcol(float *buf, char *target); #endif /* PIXELBLENDING_EXT_H */ diff --git a/source/blender/render/intern/include/pixelshading.h b/source/blender/render/intern/include/pixelshading.h index 67b0e5bcf3c..88c93a147fc 100644 --- a/source/blender/render/intern/include/pixelshading.h +++ b/source/blender/render/intern/include/pixelshading.h @@ -53,9 +53,8 @@ void shadeHaloFloat(HaloRen *har, /** * Render the sky at pixel (x, y). */ -void renderSkyPixelFloat(float *collector, float x, float y, float *rco); -void shadeSkyPixel(float *collector, float fx, float fy, float *rco); -void shadeSkyPixelFloat(float *colf, float *rco, float *view, float *dxyview); +void shadeSkyPixel(float *collector, float fx, float fy); +void shadeSkyView(float *colf, float *rco, float *view, float *dxyview); /* ------------------------------------------------------------------------- */ diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h index 3ac56e73099..77beb446c86 100644 --- a/source/blender/render/intern/include/render_types.h +++ b/source/blender/render/intern/include/render_types.h @@ -253,9 +253,8 @@ typedef struct RadFace { int flag; } RadFace; -typedef struct VlakRen -{ - struct VertRen *v1, *v2, *v3, *v4; +typedef struct VlakRen { + struct VertRen *v1, *v2, *v3, *v4; /* keep in order for ** addressing */ unsigned int lay; float n[3]; struct Material *mat; @@ -290,8 +289,12 @@ struct MTex; * For each lamp in a scene, a LampRen is created. It determines the * properties of a lightsource. */ -typedef struct LampRen -{ + +typedef struct LampShadowSample { + float shadfac[16][4]; /* 16 = RE_MAX_OSA, 4 = rgba */ +} LampShadowSample; + +typedef struct LampRen { float xs, ys, dist; float co[3]; short type, mode; @@ -340,6 +343,10 @@ typedef struct LampRen float mat[3][3]; /* 3x3 part from lampmat x viewmat */ float area[8][3], areasize; + /* passes & node shader support: all shadow info for a pixel */ + /* struct is currently 2k long... check on alloc? */ + LampShadowSample shadsamp[BLENDER_MAX_THREADS]; + /* yafray: photonlight params */ int YF_numphotons, YF_numsearch; short YF_phdepth, YF_useqmc, YF_bufsize; diff --git a/source/blender/render/intern/include/rendercore.h b/source/blender/render/intern/include/rendercore.h index e70913fbbde..9f22480f0cb 100644 --- a/source/blender/render/intern/include/rendercore.h +++ b/source/blender/render/intern/include/rendercore.h @@ -47,17 +47,11 @@ struct HaloRen; struct ShadeInput; struct ShadeResult; struct World; +struct RenderPart; +struct RenderLayer; /* ------------------------------------------------------------------------- */ -/* to make passing on variables to shadepixel() easier */ -typedef struct ShadePixelInfo { - int thread; - int layflag, passflag; - unsigned int lay; - ShadeResult shr; -} ShadePixelInfo; - typedef struct PixStr { struct PixStr *next; @@ -79,25 +73,17 @@ typedef struct PixStrMain void calc_view_vector(float *view, float x, float y); float mistfactor(float zcor, float *co); /* dist and height, return alpha */ +void renderspothalo(struct ShadeInput *shi, float *col, float alpha); void add_halo_flare(Render *re); -void shade_input_set_coords(ShadeInput *shi, float u, float v, int i1, int i2, int i3); - -void shade_color(struct ShadeInput *shi, ShadeResult *shr); -void shade_lamp_loop(struct ShadeInput *shi, ShadeResult *shr); - -float fresnel_fac(float *view, float *vn, float fresnel, float fac); -void calc_R_ref(struct ShadeInput *shi); +void calc_renderco_zbuf(float *co, float *view, int z); +void calc_renderco_ortho(float *co, float x, float y, int z); -/* for nodes */ -void shade_material_loop(struct ShadeInput *shi, struct ShadeResult *shr); +int count_mask(unsigned short mask); void zbufshade(void); void zbufshadeDA(void); /* Delta Accum Pixel Struct */ -void *shadepixel(ShadePixelInfo *shpi, float x, float y, int z, volatile int facenr, int mask, float *rco); -int count_mask(unsigned short mask); - void zbufshade_tile(struct RenderPart *pa); void zbufshadeDA_tile(struct RenderPart *pa); diff --git a/source/blender/render/intern/include/shading.h b/source/blender/render/intern/include/shading.h new file mode 100644 index 00000000000..38ed0f73e70 --- /dev/null +++ b/source/blender/render/intern/include/shading.h @@ -0,0 +1,75 @@ +/** +* $Id: + * + * ***** BEGIN GPL 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. + * + * 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) 2006 Blender Foundation + * All rights reserved. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +struct ShadeInput; +struct ShadeResult; +struct RenderPart; +struct RenderLayer; +struct PixStr; + +/* shadeinput.c */ + + +/* needed to calculate shadow and AO for an entire pixel */ +typedef struct ShadeSample { + int tot; /* amount of shi in use, can be 1 for not FULL_OSA */ + ShadeInput shi[16]; /* RE_MAX_OSA */ + ShadeResult shr[16]; /* RE_MAX_OSA */ +} ShadeSample; + + + /* also the node shader callback */ +void shade_material_loop(struct ShadeInput *shi, struct ShadeResult *shr); + +void shade_input_set_triangle_i(struct ShadeInput *shi, struct VlakRen *vlr, short i1, short i2, short i3); +void shade_input_set_triangle(struct ShadeInput *shi, volatile int facenr, int normal_flip); +void shade_input_copy_triangle(struct ShadeInput *shi, struct ShadeInput *from); +void shade_input_set_viewco(struct ShadeInput *shi, float x, float y, float z); +void shade_input_set_uv(struct ShadeInput *shi); +void shade_input_set_normals(struct ShadeInput *shi); +void shade_input_set_shade_texco(struct ShadeInput *shi); +void shade_input_do_shade(struct ShadeInput *shi, struct ShadeResult *shr); + +void shade_sample_initialize(struct ShadeSample *ssamp, struct RenderPart *pa, struct RenderLayer *rl); +void shade_samples_do_shadow(struct ShadeSample *ssamp); +int shade_samples(struct ShadeSample *ssamp, struct PixStr *ps, int x, int y); + +void vlr_set_uv_indices(struct VlakRen *vlr, int *i1, int *i2, int *i3); + +void calc_R_ref(struct ShadeInput *shi); + + +/* shadeoutput. */ +void shade_lamp_loop(struct ShadeInput *shi, struct ShadeResult *shr); + +void shade_color(struct ShadeInput *shi, ShadeResult *shr); + +void ambient_occlusion_to_diffuse(struct ShadeInput *shi, float *diff); +void ambient_occlusion(struct ShadeInput *shi); + +float lamp_get_visibility(struct LampRen *lar, float *co, float *lv, float *dist); +void lamp_get_shadow(struct LampRen *lar, ShadeInput *shi, float inp, float *shadfac, int do_real); + +float fresnel_fac(float *view, float *vn, float fresnel, float fac); diff --git a/source/blender/render/intern/include/zbuf.h b/source/blender/render/intern/include/zbuf.h index 993ca711a18..c308ae25bce 100644 --- a/source/blender/render/intern/include/zbuf.h +++ b/source/blender/render/intern/include/zbuf.h @@ -49,7 +49,7 @@ int testclip(float *v); void set_part_zbuf_clipflag(struct RenderPart *pa); void zbuffer_shadow(struct Render *re, struct LampRen *lar, int *rectz, int size, float jitx, float jity); void zbuffer_solid(struct RenderPart *pa, unsigned int layer, short layflag); -void zbuffer_transp_shade(struct RenderPart *pa, struct RenderLayer *rl, float *pass); +unsigned short *zbuffer_transp_shade(struct RenderPart *pa, struct RenderLayer *rl, float *pass); void convert_zbuf_to_distbuf(struct RenderPart *pa, struct RenderLayer *rl); typedef struct APixstr { diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 4142c5198d1..7232e0e6e71 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -101,6 +101,7 @@ #include "renderpipeline.h" #include "radio.h" #include "shadbuf.h" +#include "shading.h" #include "texture.h" #include "zbuf.h" @@ -2323,6 +2324,9 @@ static LampRen *add_render_lamp(Render *re, Object *ob) } } + else if(la->type==LA_HEMI) { + lar->mode &= ~(LA_SHAD_RAY|LA_SHAD_BUF); + } for(c=0; c<MAX_MTEX; c++) { if(la->mtex[c] && la->mtex[c]->tex) { @@ -2353,11 +2357,18 @@ static LampRen *add_render_lamp(Render *re, Object *ob) /* yafray: shadow flag should not be cleared, only used with internal renderer */ if (re->r.renderer==R_INTERN) { + int a, b; + /* to make sure we can check ray shadow easily in the render code */ if(lar->mode & LA_SHAD_RAY) { if( (re->r.mode & R_RAYTRACE)==0) lar->mode &= ~LA_SHAD_RAY; } + /* shadfacs actually mean light, let's put them to 1 to prevent unitialized accidents */ + for(c=0; c<re->r.threads; c++) + for(a=0; a<re->r.osa; a++) + for(b=0; b<4; b++) + lar->shadsamp[c].shadfac[a][b]= 1.0f; } return lar; } @@ -2974,6 +2985,9 @@ static void set_fullsample_flag(Render *re) VlakRen *vlr; int a, trace; + if(re->osa==0) + return; + trace= re->r.mode & R_RAYTRACE; for(a=re->totvlak-1; a>=0; a--) { @@ -3147,7 +3161,12 @@ void init_render_world(Render *re) for(a=0; a<MAX_MTEX; a++) if(re->wrld.mtex[a] && re->wrld.mtex[a]->tex) re->wrld.skytype |= WO_SKYTEX; - while(re->wrld.aosamp*re->wrld.aosamp < re->osa) re->wrld.aosamp++; + /* AO samples should be OSA minimum */ + if(re->osa) + while(re->wrld.aosamp*re->wrld.aosamp < re->osa) + re->wrld.aosamp++; + if(!(re->r.mode & R_RAYTRACE)) + re->wrld.mode &= ~WO_AMB_OCC; } else { memset(&re->wrld, 0, sizeof(World)); @@ -3200,12 +3219,12 @@ void RE_Database_FromScene(Render *re, Scene *scene, int use_camera_view) } init_render_world(re); /* do first, because of ambient. also requires re->osa set correct */ - if( (re->wrld.mode & WO_AMB_OCC) && (re->r.mode & R_RAYTRACE) ) + if(re->wrld.mode & WO_AMB_OCC) init_ao_sphere(&re->wrld); /* still bad... doing all */ init_render_textures(re); - init_render_materials(re->osa, &re->wrld.ambr); + init_render_materials(re->r.mode, &re->wrld.ambr); set_node_shader_lamp_loop(shade_material_loop); for(SETLOOPER(re->scene, base)) { @@ -3871,12 +3890,12 @@ void RE_Database_Baking(Render *re, Scene *scene, int type) } init_render_world(re); /* do first, because of ambient. also requires re->osa set correct */ - if( (re->wrld.mode & WO_AMB_OCC) && (re->r.mode & R_RAYTRACE) ) + if(re->wrld.mode & WO_AMB_OCC) init_ao_sphere(&re->wrld); /* still bad... doing all */ init_render_textures(re); - init_render_materials(re->osa, &re->wrld.ambr); + init_render_materials(re->r.mode, &re->wrld.ambr); set_node_shader_lamp_loop(shade_material_loop); for(SETLOOPER(re->scene, base)) { diff --git a/source/blender/render/intern/source/initrender.c b/source/blender/render/intern/source/initrender.c index 327b04f6c81..51ed2156a5b 100644 --- a/source/blender/render/intern/source/initrender.c +++ b/source/blender/render/intern/source/initrender.c @@ -74,7 +74,6 @@ #include "rendercore.h" #include "pixelshading.h" -#include "gammaCorrectionTables.h" #include "zbuf.h" /* Own includes */ @@ -98,7 +97,7 @@ static void init_render_jit(Render *re) } -/* ****************** GAMMA, MASKS and LUTS **************** */ +/* ****************** MASKS and LUTS **************** */ static float filt_quadratic(float x) { @@ -264,7 +263,6 @@ void make_sample_tables(Render *re) /* optimization tables, only once */ if(firsttime) { - makeGammaTables(2.0); /* tables only used for adding colors */ firsttime= 0; } @@ -278,12 +276,6 @@ void make_sample_tables(Render *re) return; } - re->do_gamma= 0; - if(re->r.mode & R_GAMMA) { - if(re->r.alphamode!=R_ALPHAKEY) /* alpha corrected gamma doesnt work for key alpha */ - re->do_gamma= 1; - } - st= re->samples= MEM_callocN(sizeof(SampleTables), "sample tables"); for(a=0; a<9;a++) { diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index ef6434cf65a..a4fd1168d22 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -290,11 +290,18 @@ static char *get_pass_name(int passtype, int channel) else if(channel==1) return "AO.G"; else return "AO.B"; } - if(passtype == SCE_PASS_RAY) { - if(channel==0) return "Ray.R"; - else if(channel==1) return "Ray.G"; - else return "Ray.B"; - } + if(passtype == SCE_PASS_REFLECT) { + if(channel==0) return "Reflect.R"; + else if(channel==1) return "Reflect.G"; + else return "Reflect.B"; + } + if(passtype == SCE_PASS_REFRACT) { + if(channel==0) return "Refract.R"; + else if(channel==1) return "Refract.G"; + else return "Refract.B"; + } + if(passtype == SCE_PASS_INDEXOB) + return "IndexOB"; return "Unknown"; } @@ -434,12 +441,19 @@ static RenderResult *new_render_result(Render *re, rcti *partrct, int crop, int render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE); if(srl->passflag & SCE_PASS_SPEC) render_layer_add_pass(rr, rl, 3, SCE_PASS_SPEC); - if(srl->passflag & SCE_PASS_SHADOW) - render_layer_add_pass(rr, rl, 3, SCE_PASS_SHADOW); - if(srl->passflag & SCE_PASS_AO) - render_layer_add_pass(rr, rl, 3, SCE_PASS_AO); - if(srl->passflag & SCE_PASS_RAY) - render_layer_add_pass(rr, rl, 3, SCE_PASS_RAY); + if(re->r.mode & R_SHADOW) + if(srl->passflag & SCE_PASS_SHADOW) + render_layer_add_pass(rr, rl, 3, SCE_PASS_SHADOW); + if(re->r.mode & R_RAYTRACE) { + if(srl->passflag & SCE_PASS_AO) + render_layer_add_pass(rr, rl, 3, SCE_PASS_AO); + if(srl->passflag & SCE_PASS_REFLECT) + render_layer_add_pass(rr, rl, 3, SCE_PASS_REFLECT); + if(srl->passflag & SCE_PASS_REFRACT) + render_layer_add_pass(rr, rl, 3, SCE_PASS_REFRACT); + } + if(srl->passflag & SCE_PASS_INDEXOB) + render_layer_add_pass(rr, rl, 1, SCE_PASS_INDEXOB); } /* previewrender and envmap don't do layers, so we make a default one */ diff --git a/source/blender/render/intern/source/pixelblending.c b/source/blender/render/intern/source/pixelblending.c index 3048a151925..136709b3ed5 100644 --- a/source/blender/render/intern/source/pixelblending.c +++ b/source/blender/render/intern/source/pixelblending.c @@ -280,134 +280,7 @@ void addalphaAddFloat(float *dest, float *source) } -/* ------------------------------------------------------------------------- */ - -/* ------------------------------------------------------------------------- */ -/* Colour buffer related: */ -/* This transforms the 4 inputvalues RE_COLBUFTYPE to a new value */ -/* It expects the values R.r.postigamma, R.r.postmul and R.r.postadd. */ -/* This is the standard transformation, more elaborate tools are for later. */ -/* ------------------------------------------------------------------------- */ -void std_floatcol_to_charcol( float *buf, char *target) -{ - float col[3]; - - float dither_value; - - dither_value = ((BLI_frand()-0.5)*R.r.dither_intensity)/256.0; - - /* alpha */ - if((buf[3]+dither_value)<=0.0) target[3]= 0; - else if((buf[3]+dither_value)>1.0) target[3]= 255; - else target[3]= 255.0*(buf[3]+dither_value); - - if(R.r.postgamma==1.0) { - /* r */ - col[0]= R.r.postmul*buf[0] + R.r.postadd + dither_value; - /* g */ - col[1]= R.r.postmul*buf[1] + R.r.postadd + dither_value; - /* b */ - col[2]= R.r.postmul*buf[2] + R.r.postadd + dither_value; - } - else { - /* putting the postmul within the pow() gives an - * easier control for the user, values from 1.0-2.0 - * are relevant then - */ - - /* r */ - col[0]= pow(R.r.postmul*buf[0], R.r.postigamma) + R.r.postadd + dither_value; - /* g */ - col[1]= pow( R.r.postmul*buf[1], R.r.postigamma) + R.r.postadd + dither_value; - /* b */ - col[2]= pow(R.r.postmul*buf[2], R.r.postigamma) + R.r.postadd + dither_value; - } - - if(R.r.posthue!=0.0 || R.r.postsat!=1.0) { - float hsv[3]; - - rgb_to_hsv(col[0], col[1], col[2], hsv, hsv+1, hsv+2); - hsv[0]+= R.r.posthue; - if(hsv[0]>1.0) hsv[0]-=1.0; else if(hsv[0]<0.0) hsv[0]+= 1.0; - hsv[1]*= R.r.postsat; - if(hsv[1]>1.0) hsv[1]= 1.0; else if(hsv[1]<0.0) hsv[1]= 0.0; - hsv_to_rgb(hsv[0], hsv[1], hsv[2], col, col+1, col+2); - } - - if(col[0]<=0.0) target[0]= 0; - else if(col[0]>1.0) target[0]= 255; - else target[0]= 255.0*col[0]; - - if(col[1]<=0.0) target[1]= 0; - else if(col[1]>1.0) target[1]= 255; - else target[1]= 255.0*col[1]; - - if(col[2]<=0.0) target[2]= 0; - else if(col[2]>1.0) target[2]= 255; - else target[2]= 255.0*col[2]; -} - -/* ---------------------------------------------------------------------------- - -Colour buffer related: - -The colour buffer is a buffer of a single screen line. It contains -four fields of type RE_COLBUFTYPE per pixel. - -We can do several post-process steps. I would prefer to move them outside -the render module later on, but it's ok to leave it here for now. For the -time being, we have: -- post-process function - Does some operations with the colours. -- Multiply with some factor -- Add constant offset -- Apply extra gamma correction (seems weird...) -- key-alpha correction - Key alpha means 'un-applying' the alpha. For fully covered pixels, this - operation has no effect. - -- XXX WARNING! Added the inverse render gamma here, so this cannot be used external - without setting Osa or Gamma flags off (ton) - ----------------------------------------------------------------------------- */ -/* used external! */ -void transferColourBufferToOutput( float *buf, int y) -{ - /* Copy the contents of AColourBuffer3 to R.rectot + y * R.rectx */ - int x = 0; -// char *target = (char*) (R.rectot + (y * R.rectx)); - - /* Copy the first <R.rectx> pixels. We can do some more clipping on */ - /* the z buffer, I think. */ - while (x < R.rectx) { - - - /* invert gamma corrected additions */ - if(R.do_gamma) { - buf[0] = invGammaCorrect(buf[0]); - buf[1] = invGammaCorrect(buf[1]); - buf[2] = invGammaCorrect(buf[2]); - } - -// std_floatcol_to_charcol(buf, target); - - /* - Key-alpha mode: - Need to un-apply alpha if alpha is non-full. For full alpha, - the operation doesn't have effect. Do this after the post- - processing, so we can still use the benefits of that. - - */ - - if (R.r.alphamode == R_ALPHAKEY) { -// applyKeyAlphaCharCol(target); - } - -// target+=4; - buf+=4; - x++; - } -} +/* ---------------------------------------------------------------------------- */ /* eof pixelblending.c */ diff --git a/source/blender/render/intern/source/pixelshading.c b/source/blender/render/intern/source/pixelshading.c index bf5e34d3442..4955c65f55c 100644 --- a/source/blender/render/intern/source/pixelshading.c +++ b/source/blender/render/intern/source/pixelshading.c @@ -54,7 +54,6 @@ #include "pixelblending.h" #include "rendercore.h" #include "shadbuf.h" -#include "gammaCorrectionTables.h" #include "pixelshading.h" /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ @@ -438,42 +437,6 @@ void shadeHaloFloat(HaloRen *har, float *col, int zz, } /* ------------------------------------------------------------------------- */ -/* - - 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... - -*/ - - -/* This one renders into collector, as always. */ -void renderSkyPixelFloat(float *collector, float x, float y, float *rco) -{ - - switch (R.r.alphamode) { - case R_ALPHAPREMUL: - case R_ALPHAKEY: - /* Premul or key: don't fill, and don't change the values! */ - /* key alpha used to fill in color in 'empty' pixels, doesn't work anymore this way */ - collector[0] = 0.0; - collector[1] = 0.0; - collector[2] = 0.0; - collector[3] = 0.0; - break; - case R_ADDSKY: - /* Fill in the sky as if it were a normal face. */ - shadeSkyPixel(collector, x, y, rco); - collector[3]= 0.0; - break; - default: - ; /* Error: illegal alpha blending state */ - } -} static void fillBackgroundImage(float *collector, float fx, float fy) { @@ -490,70 +453,8 @@ static void fillBackgroundImage(float *collector, float fx, float fy) } } -/* - Stuff the sky colour into the collector. - */ -void shadeSkyPixel(float *collector, float fx, float fy, float *rco) -{ - float view[3], dxyview[2]; - - /* - 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(collector, 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] = 1.0f; - } 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(R.wrld.skytype & WO_SKYPAPER) { - view[0]= -1.0f + 2.0f*(fx/(float)R.winx); - view[1]= -1.0f + 2.0f*(fy/(float)R.winy); - view[2]= 0.0; - - dxyview[0]= 1.0f/(float)R.winx; - dxyview[1]= 1.0f/(float)R.winy; - } - else { - calc_view_vector(view, fx, fy); - fac= Normalise(view); - - if(R.wrld.skytype & WO_SKYTEX) { - dxyview[0]= -R.viewdx/fac; - dxyview[1]= -R.viewdy/fac; - } - } - - /* get sky colour in the collector */ - shadeSkyPixelFloat(collector, rco, view, dxyview); - collector[3] = 1.0f; - } -} - /* Only view vector is important here. Result goes to colf[3] */ -void shadeSkyPixelFloat(float *colf, float *rco, float *view, float *dxyview) +void shadeSkyView(float *colf, float *rco, float *view, float *dxyview) { float lo[3], zen[3], hor[3], blend, blendm; int skyflag; @@ -563,9 +464,9 @@ void shadeSkyPixelFloat(float *colf, float *rco, float *view, float *dxyview) /* Some view vector stuff. */ if(R.wrld.skytype & WO_SKYREAL) { - + blend= view[0]*R.grvec[0]+ view[1]*R.grvec[1]+ view[2]*R.grvec[2]; - + if(blend<0.0) skyflag= 0; blend= fabs(blend); @@ -577,7 +478,7 @@ void shadeSkyPixelFloat(float *colf, float *rco, float *view, float *dxyview) /* the fraction of how far we are above the bottom of the screen */ blend= fabs(0.5+ view[1]); } - + hor[0]= R.wrld.horr; hor[1]= R.wrld.horg; hor[2]= R.wrld.horb; zen[0]= R.wrld.zenr; zen[1]= R.wrld.zeng; zen[2]= R.wrld.zenb; @@ -588,16 +489,16 @@ void shadeSkyPixelFloat(float *colf, float *rco, float *view, float *dxyview) if(R.wrld.skytype & WO_SKYREAL) { MTC_Mat3MulVecfl(R.imat, lo); - + SWAP(float, lo[1], lo[2]); } do_sky_tex(rco, lo, dxyview, hor, zen, &blend, skyflag); } - + if(blend>1.0) blend= 1.0; blendm= 1.0-blend; - + /* No clipping, no conversion! */ if(R.wrld.skytype & WO_SKYBLEND) { colf[0] = (blendm*hor[0] + blend*zen[0]); @@ -611,5 +512,60 @@ void shadeSkyPixelFloat(float *colf, float *rco, float *view, float *dxyview) } } +/* + Stuff the sky colour into the collector. + */ +void shadeSkyPixel(float *collector, float fx, float fy) +{ + float view[3], dxyview[2]; + + /* + 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(collector, fx, fy); + return; + } + else if((R.wrld.skytype & (WO_SKYBLEND+WO_SKYTEX))==0) { + /* 2. solid color */ + collector[0] = R.wrld.horr; + collector[1] = R.wrld.horg; + collector[2] = R.wrld.horb; + collector[3] = 0.0f; + } + else { + /* 3. */ + + /* This one true because of the context of this routine */ + if(R.wrld.skytype & WO_SKYPAPER) { + view[0]= -1.0f + 2.0f*(fx/(float)R.winx); + view[1]= -1.0f + 2.0f*(fy/(float)R.winy); + view[2]= 0.0; + + dxyview[0]= 1.0f/(float)R.winx; + dxyview[1]= 1.0f/(float)R.winy; + } + else { + calc_view_vector(view, fx, fy); + fac= Normalise(view); + + if(R.wrld.skytype & WO_SKYTEX) { + dxyview[0]= -R.viewdx/fac; + dxyview[1]= -R.viewdy/fac; + } + } + + /* get sky colour in the collector */ + shadeSkyView(collector, NULL, view, dxyview); + collector[3] = 0.0f; + } +} + /* eof */ diff --git a/source/blender/render/intern/source/ray.c b/source/blender/render/intern/source/ray.c index 972e4a8afc8..71c116e0c9b 100644 --- a/source/blender/render/intern/source/ray.c +++ b/source/blender/render/intern/source/ray.c @@ -51,6 +51,7 @@ #include "rendercore.h" #include "pixelblending.h" #include "pixelshading.h" +#include "shading.h" #include "texture.h" #define DDA_SHADOW 0 @@ -337,32 +338,32 @@ static void d2dda(Octree *oc, short b1, short b2, short c1, short c2, char *ocfa oy2= rtf[b2][c2]; if(ox1!=ox2) { - if(ox2-ox1>0.0) { - labdax= (ox1-ocx1-1.0)/(ox1-ox2); - ldx= -1.0/(ox1-ox2); + if(ox2-ox1>0.0f) { + labdax= (ox1-ocx1-1.0f)/(ox1-ox2); + ldx= -1.0f/(ox1-ox2); dx= 1; } else { labdax= (ox1-ocx1)/(ox1-ox2); - ldx= 1.0/(ox1-ox2); + ldx= 1.0f/(ox1-ox2); dx= -1; } } else { - labdax=1.0; + labdax=1.0f; ldx=0; } if(oy1!=oy2) { - if(oy2-oy1>0.0) { - labday= (oy1-ocy1-1.0)/(oy1-oy2); - ldy= -1.0/(oy1-oy2); + if(oy2-oy1>0.0f) { + labday= (oy1-ocy1-1.0f)/(oy1-oy2); + ldy= -1.0f/(oy1-oy2); dy= 1; } else { labday= (oy1-ocy1)/(oy1-oy2); - ldy= 1.0/(oy1-oy2); + ldy= 1.0f/(oy1-oy2); dy= -1; } } else { - labday=1.0; + labday=1.0f; ldy=0; } @@ -391,7 +392,7 @@ static void d2dda(Octree *oc, short b1, short b2, short c1, short c2, char *ocfa } labda=MIN2(labdax,labday); if(labda==labdao) break; - if(labda>=1.0) break; + if(labda>=1.0f) break; } ocface[oc->ocres*ocx2+ocy2]=1; } @@ -513,8 +514,8 @@ void makeoctree(Render *re) memset(ocface, 0, 3*ocres2); for(c=0;c<3;c++) { /* octree enlarge, still needed? */ - oc->min[c]-= 0.01; - oc->max[c]+= 0.01; + oc->min[c]-= 0.01f; + oc->max[c]+= 0.01f; } t00= oc->max[0]-oc->min[0]; @@ -535,7 +536,7 @@ void makeoctree(Render *re) vlr= re->blovl[v>>8]; if(re->test_break()) break; - if(time-lasttime>1.0) { + if(time-lasttime>1.0f) { char str[32]; sprintf(str, "Filling Octree: %d", v); re->i.infostr= str; @@ -697,16 +698,16 @@ static int intersection2(VlakRen *vlr, float r0, float r1, float r2, float rx1, m2= rz1-v3->co[2]; det1= m0*x0+m1*x1+m2*x2; - if(divdet!=0.0) { + if(divdet!=0.0f) { u1= det1/divdet; - if(u1<=0.0) { + if(u1<=0.0f) { det= t00*(m1*r2-m2*r1); det+= t01*(m2*r0-m0*r2); det+= t02*(m0*r1-m1*r0); v= det/divdet; - if(v<=0.0 && (u1 + v) >= -1.0) { + if(v<=0.0f && (u1 + v) >= -1.0f) { return 1; } } @@ -719,16 +720,16 @@ static int intersection2(VlakRen *vlr, float r0, float r1, float r2, float rx1, t22= v3->co[2]-v4->co[2]; divdet= t20*x0+t21*x1+t22*x2; - if(divdet!=0.0) { + if(divdet!=0.0f) { u2= det1/divdet; - if(u2<=0.0) { + if(u2<=0.0f) { det= t20*(m1*r2-m2*r1); det+= t21*(m2*r0-m0*r2); det+= t22*(m0*r1-m1*r0); v= det/divdet; - if(v<=0.0 && (u2 + v) >= -1.0) { + if(v<=0.0f && (u2 + v) >= -1.0f) { return 2; } } @@ -845,12 +846,12 @@ static int intersection(Isect *is) m2= is->start[2]-v3->co[2]; det1= m0*x0+m1*x1+m2*x2; - if(divdet!=0.0) { + if(divdet!=0.0f) { float u; - divdet= 1.0/divdet; + divdet= 1.0f/divdet; u= det1*divdet; - if(u<0.0 && u>-1.0) { + if(u<0.0f && u>-1.0f) { float v, cros0, cros1, cros2; cros0= m1*t02-m2*t01; @@ -858,11 +859,11 @@ static int intersection(Isect *is) cros2= m0*t01-m1*t00; v= divdet*(cros0*r0 + cros1*r1 + cros2*r2); - if(v<0.0 && (u + v) > -1.0) { + if(v<0.0f && (u + v) > -1.0f) { float labda; labda= divdet*(cros0*t10 + cros1*t11 + cros2*t12); - if(labda>0.0 && labda<1.0) { + if(labda>0.0f && labda<1.0f) { is->labda= labda; is->u= u; is->v= v; ok= 1; @@ -878,23 +879,23 @@ static int intersection(Isect *is) t22= v3->co[2]-v4->co[2]; divdet= t20*x0+t21*x1+t22*x2; - if(divdet!=0.0) { + if(divdet!=0.0f) { float u; - divdet= 1.0/divdet; + divdet= 1.0f/divdet; u = det1*divdet; - if(u<0.0 && u>-1.0) { + if(u<0.0f && u>-1.0f) { float v, cros0, cros1, cros2; cros0= m1*t22-m2*t21; cros1= m2*t20-m0*t22; cros2= m0*t21-m1*t20; v= divdet*(cros0*r0 + cros1*r1 + cros2*r2); - if(v<0.0 && (u + v) > -1.0) { + if(v<0.0f && (u + v) > -1.0f) { float labda; labda= divdet*(cros0*t10 + cros1*t11 + cros2*t12); - if(labda>0.0 && labda<1.0) { + if(labda>0.0f && labda<1.0f) { ok= 2; is->labda= labda; is->u= u; is->v= v; @@ -995,7 +996,7 @@ static int testnode(Isect *is, Node *no, OcVal ocval) Isect isect; int found= 0; - is->labda= 1.0; /* needed? */ + is->labda= 1.0f; /* needed? */ isect= *is; /* copy for sorting */ vlr= no->v[0]; @@ -1097,24 +1098,24 @@ static int cliptest(float p, float q, float *u1, float *u2) { float r; - if(p<0.0) { + if(p<0.0f) { if(q<p) return 0; - else if(q<0.0) { + else if(q<0.0f) { r= q/p; if(r>*u2) return 0; else if(r>*u1) *u1=r; } } else { - if(p>0.0) { - if(q<0.0) return 0; + if(p>0.0f) { + if(q<0.0f) return 0; else if(q<p) { r= q/p; if(r<*u1) return 0; else if(r<*u2) *u2=r; } } - else if(q<0.0) return 0; + else if(q<0.0f) return 0; } return 1; } @@ -1183,8 +1184,8 @@ static int d3dda(Isect *is) } ldx= is->end[0] - is->start[0]; - u1= 0.0; - u2= 1.0; + u1= 0.0f; + u2= 1.0f; /* clip with octree cube */ if(cliptest(-ldx, is->start[0]-R.oc.min[0], &u1,&u2)) { @@ -1196,12 +1197,12 @@ static int d3dda(Isect *is) if(cliptest(-ldz, is->start[2]-R.oc.min[2], &u1,&u2)) { if(cliptest(ldz, R.oc.max[2]-is->start[2], &u1,&u2)) { c1=1; - if(u2<1.0) { + if(u2<1.0f) { is->end[0]= is->start[0]+u2*ldx; is->end[1]= is->start[1]+u2*ldy; is->end[2]= is->start[2]+u2*ldz; } - if(u1>0.0) { + if(u1>0.0f) { is->start[0]+=u1*ldx; is->start[1]+=u1*ldy; is->start[2]+=u1*ldz; @@ -1243,7 +1244,7 @@ static int d3dda(Isect *is) vec1[0]= ox1; vec1[1]= oy1; vec1[2]= oz1; vec2[0]= ox2; vec2[1]= oy2; vec2[2]= oz2; calc_ocval_ray(&ocval, (float)ocx1, (float)ocy1, (float)ocz1, vec1, vec2); - is->ddalabda= 1.0; + is->ddalabda= 1.0f; if( testnode(is, no, ocval) ) return 1; } } @@ -1258,43 +1259,43 @@ static int d3dda(Isect *is) doz= oz1-oz2; if(dox<-FLT_EPSILON) { - ldx= -1.0/dox; - labdax= (ocx1-ox1+1.0)*ldx; + ldx= -1.0f/dox; + labdax= (ocx1-ox1+1.0f)*ldx; dx= 1; } else if(dox>FLT_EPSILON) { - ldx= 1.0/dox; + ldx= 1.0f/dox; labdax= (ox1-ocx1)*ldx; dx= -1; } else { - labdax=1.0; + labdax=1.0f; ldx=0; dx= 0; } if(doy<-FLT_EPSILON) { - ldy= -1.0/doy; - labday= (ocy1-oy1+1.0)*ldy; + ldy= -1.0f/doy; + labday= (ocy1-oy1+1.0f)*ldy; dy= 1; } else if(doy>FLT_EPSILON) { - ldy= 1.0/doy; + ldy= 1.0f/doy; labday= (oy1-ocy1)*ldy; dy= -1; } else { - labday=1.0; + labday=1.0f; ldy=0; dy= 0; } if(doz<-FLT_EPSILON) { - ldz= -1.0/doz; - labdaz= (ocz1-oz1+1.0)*ldz; + ldz= -1.0f/doz; + labdaz= (ocz1-oz1+1.0f)*ldz; dz= 1; } else if(doz>FLT_EPSILON) { - ldz= 1.0/doz; + ldz= 1.0f/doz; labdaz= (oz1-ocz1)*ldz; dz= -1; } else { - labdaz=1.0; + labdaz=1.0f; ldz=0; dz= 0; } @@ -1307,7 +1308,7 @@ static int d3dda(Isect *is) vec2[2]= oz1; /* this loop has been constructed to make sure the first and last node of ray - are always included, even when ddalabda==1.0 or larger */ + are always included, even when ddalabda==1.0f or larger */ while(TRUE) { @@ -1388,7 +1389,7 @@ static int d3dda(Isect *is) ddalabda=MIN3(labdax,labday,labdaz); if(ddalabda==labdao) break; /* to make sure the last node is always checked */ - if(labdao>=1.0) break; + if(labdao>=1.0f) break; } } @@ -1421,7 +1422,7 @@ static void shade_ray(Isect *is, ShadeInput *shi, ShadeResult *shr) /* face normal, check for flip */ l= vlr->n[0]*shi->view[0]+vlr->n[1]*shi->view[1]+vlr->n[2]*shi->view[2]; - if(l<0.0) { + if(l<0.0f) { shi->facenor[0]= -vlr->n[0]; shi->facenor[1]= -vlr->n[1]; shi->facenor[2]= -vlr->n[2]; @@ -1436,34 +1437,42 @@ static void shade_ray(Isect *is, ShadeInput *shi, ShadeResult *shr) // Osa structs we leave unchanged now SWAP(int, osatex, shi->osatex); - shi->dxco[0]= shi->dxco[1]= shi->dxco[2]= 0.0; - shi->dyco[0]= shi->dyco[1]= shi->dyco[2]= 0.0; + shi->dxco[0]= shi->dxco[1]= shi->dxco[2]= 0.0f; + shi->dyco[0]= shi->dyco[1]= shi->dyco[2]= 0.0f; // but, set Osa stuff to zero where it can confuse texture code if(shi->mat->texco & (TEXCO_NORM|TEXCO_REFL) ) { - shi->dxno[0]= shi->dxno[1]= shi->dxno[2]= 0.0; - shi->dyno[0]= shi->dyno[1]= shi->dyno[2]= 0.0; + shi->dxno[0]= shi->dxno[1]= shi->dxno[2]= 0.0f; + shi->dyno[0]= shi->dyno[1]= shi->dyno[2]= 0.0f; } if(vlr->v4) { if(is->isect==2) - shade_input_set_coords(shi, is->u, is->v, 2, 1, 3); + shade_input_set_triangle_i(shi, vlr, 2, 1, 3); else - shade_input_set_coords(shi, is->u, is->v, 0, 1, 3); + shade_input_set_triangle_i(shi, vlr, 0, 1, 3); } else { - shade_input_set_coords(shi, is->u, is->v, 0, 1, 2); + shade_input_set_triangle_i(shi, vlr, 0, 1, 2); } + shi->u= is->u; + shi->v= is->v; + shade_input_set_normals(shi); + shade_input_set_shade_texco(shi); if(is->mode==DDA_SHADOW_TRA) shade_color(shi, shr); - else if(shi->mat->nodetree && shi->mat->use_nodes) { - ntreeShaderExecTree(shi->mat->nodetree, shi, shr); - shi->mat= vlr->mat; /* shi->mat is being set in nodetree */ - } - else - shade_material_loop(shi, shr); - + else { + if(shi->mat->nodetree && shi->mat->use_nodes) { + ntreeShaderExecTree(shi->mat->nodetree, shi, shr); + shi->mat= vlr->mat; /* shi->mat is being set in nodetree */ + } + else + shade_material_loop(shi, shr); + + /* raytrace likes to separate the spec color */ + VECSUB(shr->diff, shr->combined, shr->spec); + } SWAP(int, osatex, shi->osatex); // XXXXX!!!! @@ -1477,15 +1486,15 @@ static int refraction(float *refract, float *n, float *view, float index) dot= view[0]*n[0] + view[1]*n[1] + view[2]*n[2]; - if(dot>0.0) { - index = 1.0/index; - fac= 1.0 - (1.0 - dot*dot)*index*index; - if(fac<= 0.0) return 0; + if(dot>0.0f) { + index = 1.0f/index; + fac= 1.0f - (1.0f - dot*dot)*index*index; + if(fac<= 0.0f) return 0; fac= -dot*index + sqrt(fac); } else { - fac= 1.0 - (1.0 - dot*dot)*index*index; - if(fac<= 0.0) return 0; + fac= 1.0f - (1.0f - dot*dot)*index*index; + if(fac<= 0.0f) return 0; fac= -dot*index - sqrt(fac); } @@ -1501,7 +1510,7 @@ static void reflection(float *ref, float *n, float *view, float *orn) { float f1; - f1= -2.0*(n[0]*view[0]+ n[1]*view[1]+ n[2]*view[2]); + f1= -2.0f*(n[0]*view[0]+ n[1]*view[1]+ n[2]*view[2]); ref[0]= (view[0]+f1*n[0]); ref[1]= (view[1]+f1*n[1]); @@ -1510,8 +1519,8 @@ static void reflection(float *ref, float *n, float *view, float *orn) if(orn) { /* test phong normals, then we should prevent vector going to the back */ f1= ref[0]*orn[0]+ ref[1]*orn[1]+ ref[2]*orn[2]; - if(f1>0.0) { - f1+= .01; + if(f1>0.0f) { + f1+= .01f; ref[0]-= f1*orn[0]; ref[1]-= f1*orn[1]; ref[2]-= f1*orn[2]; @@ -1547,8 +1556,8 @@ static float shade_by_transmission(Isect *is, ShadeInput *shi, ShadeResult *shr) if (0 == (shi->mat->mode & (MA_RAYTRANSP|MA_ZTRA))) return -1; - if (shi->mat->tx_limit <= 0.0) { - d= 1.0; + if (shi->mat->tx_limit <= 0.0f) { + d= 1.0f; } else { /* shi.co[] calculated by shade_ray() */ @@ -1560,12 +1569,12 @@ static float shade_by_transmission(Isect *is, ShadeInput *shi, ShadeResult *shr) d= shi->mat->tx_limit; p = shi->mat->tx_falloff; - if(p < 0.0) p= 0.0; - else if (p > 10.0) p= 10.0; + if(p < 0.0f) p= 0.0f; + else if (p > 10.0f) p= 10.0f; shr->alpha *= pow(d, p); - if (shr->alpha > 1.0) - shr->alpha= 1.0; + if (shr->alpha > 1.0f) + shr->alpha= 1.0f; } return d; @@ -1588,7 +1597,7 @@ static void traceray(ShadeInput *origshi, short depth, float *start, float *vec, isec.vlrorig= vlr; if( d3dda(&isec) ) { - float d= 1.0; + float d= 1.0f; shi.mask= origshi->mask; shi.osatex= origshi->osatex; @@ -1597,6 +1606,7 @@ static void traceray(ShadeInput *origshi, short depth, float *start, float *vec, shi.xs= origshi->xs; shi.ys= origshi->ys; shi.lay= origshi->lay; + shi.passflag= origshi->passflag; shi.do_preview= 0; memset(&shr, 0, sizeof(ShadeResult)); @@ -1607,7 +1617,7 @@ static void traceray(ShadeInput *origshi, short depth, float *start, float *vec, if(depth>0) { - if(shi.mat->mode_l & (MA_RAYTRANSP|MA_ZTRA) && shr.alpha < 1.0) { + if(shi.mat->mode_l & (MA_RAYTRANSP|MA_ZTRA) && shr.alpha < 1.0f) { float nf, f, f1, refract[3], tracol[4]; tracol[0]= shi.r; @@ -1635,11 +1645,11 @@ static void traceray(ShadeInput *origshi, short depth, float *start, float *vec, else traceray(origshi, depth-1, shi.co, shi.view, tracol, shi.vlr, 0); - f= shr.alpha; f1= 1.0-f; + f= shr.alpha; f1= 1.0f-f; nf= d * shi.mat->filter; - fr= 1.0+ nf*(shi.r-1.0); - fg= 1.0+ nf*(shi.g-1.0); - fb= 1.0+ nf*(shi.b-1.0); + fr= 1.0f+ nf*(shi.r-1.0f); + fg= 1.0f+ nf*(shi.g-1.0f); + fb= 1.0f+ nf*(shi.b-1.0f); shr.diff[0]= f*shr.diff[0] + f1*fr*tracol[0]; shr.diff[1]= f*shr.diff[1] + f1*fg*tracol[1]; shr.diff[2]= f*shr.diff[2] + f1*fb*tracol[2]; @@ -1651,24 +1661,24 @@ static void traceray(ShadeInput *origshi, short depth, float *start, float *vec, col[3]= f1*tracol[3] + f; } else - col[3]= 1.0; + col[3]= 1.0f; if(shi.mat->mode_l & MA_RAYMIRROR) { f= shi.ray_mirror; - if(f!=0.0) f*= fresnel_fac(shi.view, shi.vn, shi.mat->fresnel_mir_i, shi.mat->fresnel_mir); + if(f!=0.0f) f*= fresnel_fac(shi.view, shi.vn, shi.mat->fresnel_mir_i, shi.mat->fresnel_mir); } - else f= 0.0; + else f= 0.0f; - if(f!=0.0) { + if(f!=0.0f) { float mircol[4]; reflection(ref, shi.vn, shi.view, NULL); traceray(origshi, depth-1, shi.co, ref, mircol, shi.vlr, 0); - f1= 1.0-f; + f1= 1.0f-f; /* combine */ - //color_combine(col, f*fr*(1.0-shr.spec[0]), f1, col, shr.diff); + //color_combine(col, f*fr*(1.0f-shr.spec[0]), f1, col, shr.diff); //col[0]+= shr.spec[0]; //col[1]+= shr.spec[1]; //col[2]+= shr.spec[2]; @@ -1677,9 +1687,9 @@ static void traceray(ShadeInput *origshi, short depth, float *start, float *vec, fg= shi.mirg; fb= shi.mirb; - col[0]= f*fr*(1.0-shr.spec[0])*mircol[0] + f1*shr.diff[0] + shr.spec[0]; - col[1]= f*fg*(1.0-shr.spec[1])*mircol[1] + f1*shr.diff[1] + shr.spec[1]; - col[2]= f*fb*(1.0-shr.spec[2])*mircol[2] + f1*shr.diff[2] + shr.spec[2]; + col[0]= f*fr*(1.0f-shr.spec[0])*mircol[0] + f1*shr.diff[0] + shr.spec[0]; + col[1]= f*fg*(1.0f-shr.spec[1])*mircol[1] + f1*shr.diff[1] + shr.spec[1]; + col[2]= f*fb*(1.0f-shr.spec[2])*mircol[2] + f1*shr.diff[2] + shr.spec[2]; } else { col[0]= shr.diff[0] + shr.spec[0]; @@ -1698,7 +1708,7 @@ static void traceray(ShadeInput *origshi, short depth, float *start, float *vec, VECCOPY(shi.view, vec); Normalise(shi.view); - shadeSkyPixelFloat(col, isec.start, shi.view, NULL); + shadeSkyView(col, isec.start, shi.view, NULL); } } @@ -1714,7 +1724,7 @@ static void DP_energy(float *table, float *vec, int tot, float xsize, float ysiz min= MIN2(xsize, ysize); min*= min; - result[0]= result[1]= 0.0; + result[0]= result[1]= 0.0f; for(y= -1; y<2; y++) { dy= ysize*y; @@ -1725,7 +1735,7 @@ static void DP_energy(float *table, float *vec, int tot, float xsize, float ysiz force[0]= vec[0] - fp[0]-dx; force[1]= vec[1] - fp[1]-dy; dist= force[0]*force[0] + force[1]*force[1]; - if(dist < min && dist>0.0) { + if(dist < min && dist>0.0f) { result[0]+= force[0]/dist; result[1]+= force[1]/dist; } @@ -1784,9 +1794,9 @@ void init_jitter_plane(LampRen *lar) } /* create the dithered tables (could just check lamp type!) */ - jitter_plane_offset(lar->jitter, lar->jitter+2*tot, tot, lar->area_size, lar->area_sizey, 0.5, 0.0); - jitter_plane_offset(lar->jitter, lar->jitter+4*tot, tot, lar->area_size, lar->area_sizey, 0.5, 0.5); - jitter_plane_offset(lar->jitter, lar->jitter+6*tot, tot, lar->area_size, lar->area_sizey, 0.0, 0.5); + jitter_plane_offset(lar->jitter, lar->jitter+2*tot, tot, lar->area_size, lar->area_sizey, 0.5f, 0.0f); + jitter_plane_offset(lar->jitter, lar->jitter+4*tot, tot, lar->area_size, lar->area_sizey, 0.5f, 0.5f); + jitter_plane_offset(lar->jitter, lar->jitter+6*tot, tot, lar->area_size, lar->area_sizey, 0.0f, 0.5f); } /* table around origin, -0.5*size to 0.5*size */ @@ -1824,25 +1834,36 @@ void ray_trace(ShadeInput *shi, ShadeResult *shr) float i, f, f1, fr, fg, fb, vec[3], mircol[4], tracol[4]; int do_tra, do_mir; - do_tra= ((shi->mat->mode & (MA_RAYTRANSP)) && shr->alpha!=1.0); - do_mir= ((shi->mat->mode & MA_RAYMIRROR) && shi->ray_mirror!=0.0); + do_tra= ((shi->mat->mode & (MA_RAYTRANSP)) && shr->alpha!=1.0f); + do_mir= ((shi->mat->mode & MA_RAYMIRROR) && shi->ray_mirror!=0.0f); vlr= shi->vlr; + /* raytrace likes to separate the spec color */ + VECSUB(shr->diff, shr->combined, shr->spec); + if(do_tra) { float refract[3]; + float olddiff[3]; tracol[3]= shr->alpha; refraction(refract, shi->vn, shi->view, shi->ang); traceray(shi, shi->mat->ray_depth_tra, shi->co, refract, tracol, shi->vlr, RAY_TRA|RAY_TRAFLIP); - f= shr->alpha; f1= 1.0-f; - fr= 1.0+ shi->mat->filter*(shi->r-1.0); - fg= 1.0+ shi->mat->filter*(shi->g-1.0); - fb= 1.0+ shi->mat->filter*(shi->b-1.0); - shr->diff[0]= f*shr->diff[0] + f1*fr*tracol[0]; - shr->diff[1]= f*shr->diff[1] + f1*fg*tracol[1]; - shr->diff[2]= f*shr->diff[2] + f1*fb*tracol[2]; + f= shr->alpha; f1= 1.0f-f; + fr= 1.0f+ shi->mat->filter*(shi->r-1.0f); + fg= 1.0f+ shi->mat->filter*(shi->g-1.0f); + fb= 1.0f+ shi->mat->filter*(shi->b-1.0f); + + /* for refract pass */ + VECCOPY(olddiff, shr->diff); + + shr->diff[0]= f*shr->diff[0] + fr*tracol[0]; + shr->diff[1]= f*shr->diff[1] + fr*tracol[1]; + shr->diff[2]= f*shr->diff[2] + fr*tracol[2]; + + if(shi->passflag & SCE_PASS_REFRACT) + VECSUB(shr->refr, shr->diff, olddiff); shr->alpha= tracol[3]; } @@ -1850,10 +1871,10 @@ void ray_trace(ShadeInput *shi, ShadeResult *shr) if(do_mir) { i= shi->ray_mirror*fresnel_fac(shi->view, shi->vn, shi->mat->fresnel_mir_i, shi->mat->fresnel_mir); - if(i!=0.0) { - fr= shi->mirr; - fg= shi->mirg; - fb= shi->mirb; + if(i!=0.0f) { + fr= i*shi->mirr; + fg= i*shi->mirg; + fb= i*shi->mirb; if(vlr->flag & R_SMOOTH) reflection(vec, shi->vn, shi->view, shi->facenor); @@ -1862,16 +1883,25 @@ void ray_trace(ShadeInput *shi, ShadeResult *shr) traceray(shi, shi->mat->ray_depth, shi->co, vec, mircol, shi->vlr, 0); - f= i*fr*(1.0-shr->spec[0]); f1= 1.0-i; + if(shi->passflag & SCE_PASS_REFLECT) { + /* mirror pass is not blocked out with spec */ + shr->refl[0]= fr*mircol[0] - fr*shr->diff[0]; + shr->refl[1]= fg*mircol[1] - fg*shr->diff[1]; + shr->refl[2]= fb*mircol[2] - fb*shr->diff[2]; + } + f= fr*(1.0f-shr->spec[0]); f1= 1.0f-i; shr->diff[0]= f*mircol[0] + f1*shr->diff[0]; - f= i*fg*(1.0-shr->spec[1]); f1= 1.0-i; + f= fg*(1.0f-shr->spec[1]); f1= 1.0f-i; shr->diff[1]= f*mircol[1] + f1*shr->diff[1]; - f= i*fb*(1.0-shr->spec[2]); f1= 1.0-i; + f= fb*(1.0f-shr->spec[2]); f1= 1.0f-i; shr->diff[2]= f*mircol[2] + f1*shr->diff[2]; } } + + /* put back together */ + VECADD(shr->combined, shr->diff, shr->spec); } /* color 'shadfac' passes through 'col' with alpha and filter */ @@ -1880,26 +1910,26 @@ static void addAlphaLight(float *shadfac, float *col, float alpha, float filter) { float fr, fg, fb; - fr= 1.0+ filter*(col[0]-1.0); - fg= 1.0+ filter*(col[1]-1.0); - fb= 1.0+ filter*(col[2]-1.0); + fr= 1.0f+ filter*(col[0]-1.0f); + fg= 1.0f+ filter*(col[1]-1.0f); + fb= 1.0f+ filter*(col[2]-1.0f); - shadfac[0]= alpha*col[0] + fr*(1.0-alpha)*shadfac[0]; - shadfac[1]= alpha*col[1] + fg*(1.0-alpha)*shadfac[1]; - shadfac[2]= alpha*col[2] + fb*(1.0-alpha)*shadfac[2]; + shadfac[0]= alpha*col[0] + fr*(1.0f-alpha)*shadfac[0]; + shadfac[1]= alpha*col[1] + fg*(1.0f-alpha)*shadfac[1]; + shadfac[2]= alpha*col[2] + fb*(1.0f-alpha)*shadfac[2]; - shadfac[3]= (1.0-alpha)*shadfac[3]; + shadfac[3]= (1.0f-alpha)*shadfac[3]; } static void ray_trace_shadow_tra(Isect *is, int depth, int traflag) { /* ray to lamp, find first face that intersects, check alpha properties, - if it has col[3]>0.0 continue. so exit when alpha is full */ + if it has col[3]>0.0f continue. so exit when alpha is full */ ShadeInput shi; ShadeResult shr; if( d3dda(is)) { - float d= 1.0; + float d= 1.0f; /* we got a face */ shi.mask= 1; @@ -1913,7 +1943,7 @@ static void ray_trace_shadow_tra(Isect *is, int depth, int traflag) /* mix colors based on shadfac (rgb + amount of light factor) */ addAlphaLight(is->col, shr.diff, shr.alpha, d*shi.mat->filter); - if(depth>0 && is->col[3]>0.0) { + if(depth>0 && is->col[3]>0.0f) { /* adapt isect struct */ VECCOPY(is->start, shi.co); @@ -1933,7 +1963,7 @@ int ray_trace_shadow_rad(ShadeInput *ship, ShadeResult *shr) Isect isec; ShadeInput shi; ShadeResult shr_t; - float vec[3], accum[3], div= 0.0; + float vec[3], accum[3], div= 0.0f; int a; if(only_one) { @@ -1941,7 +1971,7 @@ int ray_trace_shadow_rad(ShadeInput *ship, ShadeResult *shr) } only_one= 1; - accum[0]= accum[1]= accum[2]= 0.0; + accum[0]= accum[1]= accum[2]= 0.0f; isec.mode= DDA_MIRROR; isec.vlrorig= ship->vlr; @@ -1950,7 +1980,7 @@ int ray_trace_shadow_rad(ShadeInput *ship, ShadeResult *shr) counter+=3; counter %= 768; VECCOPY(vec, hashvectf+counter); - if(ship->vn[0]*vec[0]+ship->vn[1]*vec[1]+ship->vn[2]*vec[2]>0.0) { + if(ship->vn[0]*vec[0]+ship->vn[1]*vec[1]+ship->vn[2]*vec[2]>0.0f) { vec[0]-= vec[0]; vec[1]-= vec[1]; vec[2]-= vec[2]; @@ -1964,21 +1994,21 @@ int ray_trace_shadow_rad(ShadeInput *ship, ShadeResult *shr) float fac; shade_ray(&isec, &shi, &shr_t); fac= isec.labda*isec.labda; - fac= 1.0; + fac= 1.0f; accum[0]+= fac*(shr_t.diff[0]+shr_t.spec[0]); accum[1]+= fac*(shr_t.diff[1]+shr_t.spec[1]); accum[2]+= fac*(shr_t.diff[2]+shr_t.spec[2]); div+= fac; } - else div+= 1.0; + else div+= 1.0f; } - if(div!=0.0) { + if(div!=0.0f) { shr->diff[0]+= accum[0]/div; shr->diff[1]+= accum[1]/div; shr->diff[2]+= accum[2]/div; } - shr->alpha= 1.0; + shr->alpha= 1.0f; only_one= 0; return 1; @@ -2004,13 +2034,13 @@ static void DS_energy(float *sphere, int tot, float *vec) float *fp, fac, force[3], res[3]; int a; - res[0]= res[1]= res[2]= 0.0; + res[0]= res[1]= res[2]= 0.0f; for(a=0, fp=sphere; a<tot; a++, fp+=3) { VecSubf(force, vec, fp); fac= force[0]*force[0] + force[1]*force[1] + force[2]*force[2]; - if(fac!=0.0) { - fac= 1.0/fac; + if(fac!=0.0f) { + fac= 1.0f/fac; res[0]+= fac*force[0]; res[1]+= fac*force[1]; res[2]+= fac*force[2]; @@ -2127,7 +2157,7 @@ static float *sphere_sampler(int type, int resol, int thread, int xs, int ys) void ray_ao(ShadeInput *shi, float *shadfac) { Isect isec; - float *vec, *nrm, div, bias, sh=0; + float *vec, *nrm, div, bias, sh=0.0f; float maxdist = R.wrld.aodist; float dxyview[3]; int j= -1, tot, actual=0, skyadded=0; @@ -2137,7 +2167,7 @@ void ray_ao(ShadeInput *shi, float *shadfac) isec.mode= (R.wrld.aomode & WO_AODIST)?DDA_SHADOW_TRA:DDA_SHADOW; isec.lay= -1; - shadfac[0]= shadfac[1]= shadfac[2]= 0.0; + shadfac[0]= shadfac[1]= shadfac[2]= 0.0f; // bias prevents smoothed faces to appear flat if(shi->vlr->flag & R_SMOOTH) { @@ -2145,7 +2175,7 @@ void ray_ao(ShadeInput *shi, float *shadfac) nrm= shi->vn; } else { - bias= 0.0; + bias= 0.0f; nrm= shi->facenor; } @@ -2163,7 +2193,7 @@ void ray_ao(ShadeInput *shi, float *shadfac) while(tot--) { if ((vec[0]*nrm[0] + vec[1]*nrm[1] + vec[2]*nrm[2]) > bias) { - // only ao samples for mask + /* only ao samples for mask */ if(R.r.mode & R_OSA) { j++; if(j==R.osa) j= 0; @@ -2184,7 +2214,7 @@ void ray_ao(ShadeInput *shi, float *shadfac) /* do the trace */ if (d3dda(&isec)) { if (R.wrld.aomode & WO_AODIST) sh+= exp(-isec.labda*R.wrld.aodistfac); - else sh+= 1.0; + else sh+= 1.0f; } else if(R.wrld.aocolor!=WO_AOPLAIN) { float skycol[4]; @@ -2196,13 +2226,13 @@ void ray_ao(ShadeInput *shi, float *shadfac) Normalise(view); if(R.wrld.aocolor==WO_AOSKYCOL) { - fac= 0.5*(1.0+view[0]*R.grvec[0]+ view[1]*R.grvec[1]+ view[2]*R.grvec[2]); - shadfac[0]+= (1.0-fac)*R.wrld.horr + fac*R.wrld.zenr; - shadfac[1]+= (1.0-fac)*R.wrld.horg + fac*R.wrld.zeng; - shadfac[2]+= (1.0-fac)*R.wrld.horb + fac*R.wrld.zenb; + fac= 0.5*(1.0f+view[0]*R.grvec[0]+ view[1]*R.grvec[1]+ view[2]*R.grvec[2]); + shadfac[0]+= (1.0f-fac)*R.wrld.horr + fac*R.wrld.zenr; + shadfac[1]+= (1.0f-fac)*R.wrld.horg + fac*R.wrld.zeng; + shadfac[2]+= (1.0f-fac)*R.wrld.horb + fac*R.wrld.zenb; } else { /* WO_AOSKYTEX */ - shadeSkyPixelFloat(skycol, isec.start, view, dxyview); + shadeSkyView(skycol, isec.start, view, dxyview); shadfac[0]+= skycol[0]; shadfac[1]+= skycol[1]; shadfac[2]+= skycol[2]; @@ -2214,16 +2244,19 @@ void ray_ao(ShadeInput *shi, float *shadfac) vec+= 3; } - if(actual==0) shadfac[3]= 1.0; - else shadfac[3] = 1.0 - sh/((float)actual); + if(actual==0) sh= 1.0f; + else sh = 1.0f - sh/((float)actual); if(R.wrld.aocolor!=WO_AOPLAIN && skyadded) { - div= shadfac[3]/((float)skyadded); + div= sh/((float)skyadded); shadfac[0]*= div; // average color times distances/hits formula shadfac[1]*= div; // average color times distances/hits formula shadfac[2]*= div; // average color times distances/hits formula } + else { + shadfac[0]= shadfac[1]= shadfac[2]= sh; + } } @@ -2259,7 +2292,7 @@ void ray_shadow(ShadeInput *shi, LampRen *lar, float *shadfac) if(lar->ray_totsamp<2) { isec.vlrorig= shi->vlr; - shadfac[3]= 1.0; // 1.0=full light + shadfac[3]= 1.0f; // 1.0=full light /* set up isec vec */ VECCOPY(isec.start, shi->co); @@ -2267,27 +2300,27 @@ void ray_shadow(ShadeInput *shi, LampRen *lar, float *shadfac) if(isec.mode==DDA_SHADOW_TRA) { /* isec.col is like shadfac, so defines amount of light (0.0 is full shadow) */ - isec.col[0]= isec.col[1]= isec.col[2]= 1.0; - isec.col[3]= 1.0; + isec.col[0]= isec.col[1]= isec.col[2]= 1.0f; + isec.col[3]= 1.0f; ray_trace_shadow_tra(&isec, DEPTH_SHADOW_TRA, 0); QUATCOPY(shadfac, isec.col); //printf("shadfac %f %f %f %f\n", shadfac[0], shadfac[1], shadfac[2], shadfac[3]); } - else if( d3dda(&isec)) shadfac[3]= 0.0; + else if( d3dda(&isec)) shadfac[3]= 0.0f; } else { /* area soft shadow */ float *jitlamp; - float fac=0.0, div=0.0, vec[3]; + float fac=0.0f, div=0.0f, vec[3]; int a, j= -1, mask; if(isec.mode==DDA_SHADOW_TRA) { - shadfac[0]= shadfac[1]= shadfac[2]= shadfac[3]= 0.0; + shadfac[0]= shadfac[1]= shadfac[2]= shadfac[3]= 0.0f; } - else shadfac[3]= 1.0; // 1.0=full light + else shadfac[3]= 1.0f; // 1.0=full light - fac= 0.0; + fac= 0.0f; jitlamp= give_jitter_plane(lar, shi->thread, shi->xs, shi->ys); a= lar->ray_totsamp; @@ -2312,7 +2345,7 @@ void ray_shadow(ShadeInput *shi, LampRen *lar, float *shadfac) vec[0]= jitlamp[0]; vec[1]= jitlamp[1]; - vec[2]= 0.0; + vec[2]= 0.0f; Mat3MulVecfl(lar->mat, vec); /* set start and end, d3dda clips it */ @@ -2323,8 +2356,8 @@ void ray_shadow(ShadeInput *shi, LampRen *lar, float *shadfac) if(isec.mode==DDA_SHADOW_TRA) { /* isec.col is like shadfac, so defines amount of light (0.0 is full shadow) */ - isec.col[0]= isec.col[1]= isec.col[2]= 1.0; - isec.col[3]= 1.0; + isec.col[0]= isec.col[1]= isec.col[2]= 1.0f; + isec.col[3]= 1.0f; ray_trace_shadow_tra(&isec, DEPTH_SHADOW_TRA, 0); shadfac[0] += isec.col[0]; @@ -2332,9 +2365,9 @@ void ray_shadow(ShadeInput *shi, LampRen *lar, float *shadfac) shadfac[2] += isec.col[2]; shadfac[3] += isec.col[3]; } - else if( d3dda(&isec) ) fac+= 1.0; + else if( d3dda(&isec) ) fac+= 1.0f; - div+= 1.0; + div+= 1.0f; jitlamp+= 2; } @@ -2347,9 +2380,9 @@ void ray_shadow(ShadeInput *shi, LampRen *lar, float *shadfac) else { // sqrt makes nice umbra effect if(lar->ray_samp_type & LA_SAMP_UMBRA) - shadfac[3]= sqrt(1.0-fac/div); + shadfac[3]= sqrt(1.0f-fac/div); else - shadfac[3]= 1.0-fac/div; + shadfac[3]= 1.0f-fac/div; } } diff --git a/source/blender/render/intern/source/rendercore.c b/source/blender/render/intern/source/rendercore.c index 23777cea0f2..7416d6c7545 100644 --- a/source/blender/render/intern/source/rendercore.c +++ b/source/blender/render/intern/source/rendercore.c @@ -30,13 +30,10 @@ #include <stdio.h> #include <math.h> #include <string.h> -#include <stdlib.h> /* External modules: */ #include "MEM_guardedalloc.h" -#include "MTC_matrixops.h" - #include "BLI_arithb.h" #include "BLI_blenlib.h" #include "BLI_jitter.h" @@ -45,17 +42,12 @@ #include "BKE_utildefines.h" -#include "DNA_group_types.h" #include "DNA_image_types.h" #include "DNA_lamp_types.h" #include "DNA_material_types.h" -#include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" -#include "DNA_object_types.h" -#include "DNA_texture_types.h" #include "BKE_global.h" -#include "BKE_material.h" #include "BKE_main.h" #include "BKE_node.h" #include "BKE_texture.h" @@ -69,12 +61,10 @@ #include "renderdatabase.h" #include "pixelblending.h" #include "pixelshading.h" -#include "gammaCorrectionTables.h" #include "shadbuf.h" +#include "shading.h" #include "zbuf.h" -#include "texture.h" - #include "PIL_time.h" /* own include */ @@ -120,305 +110,36 @@ void calc_view_vector(float *view, float x, float y) view[0]= R.panoco*u + R.panosi*v; view[2]= -R.panosi*u + R.panoco*v; } - } } -#if 0 -static void fogcolor(float *colf, float *rco, float *view) +void calc_renderco_ortho(float *co, float x, float y, int z) { - float alpha, stepsize, startdist, dist, hor[4], zen[3], vec[3], dview[3]; - float div=0.0f, distfac; - - hor[0]= R.wrld.horr; hor[1]= R.wrld.horg; hor[2]= R.wrld.horb; - zen[0]= R.wrld.zenr; zen[1]= R.wrld.zeng; zen[2]= R.wrld.zenb; - - VECCOPY(vec, rco); + /* x and y 3d coordinate can be derived from pixel coord and winmat */ + float fx= 2.0f/(R.winx*R.winmat[0][0]); + float fy= 2.0f/(R.winy*R.winmat[1][1]); + float zco; - /* we loop from cur coord to mist start in steps */ - stepsize= 1.0f; + co[0]= (x - 0.5f*R.winx)*fx - R.winmat[3][0]/R.winmat[0][0]; + co[1]= (y - 0.5f*R.winy)*fy - R.winmat[3][1]/R.winmat[1][1]; - div= ABS(view[2]); - dview[0]= view[0]/(stepsize*div); - dview[1]= view[1]/(stepsize*div); - dview[2]= -stepsize; - - startdist= -rco[2] + BLI_frand(); - for(dist= startdist; dist>R.wrld.miststa; dist-= stepsize) { - - hor[0]= R.wrld.horr; hor[1]= R.wrld.horg; hor[2]= R.wrld.horb; - alpha= 1.0f; - do_sky_tex(vec, vec, NULL, hor, zen, &alpha); - - distfac= (dist-R.wrld.miststa)/R.wrld.mistdist; - - hor[3]= hor[0]*distfac*distfac; - - /* premul! */ - alpha= hor[3]; - hor[0]= hor[0]*alpha; - hor[1]= hor[1]*alpha; - hor[2]= hor[2]*alpha; - addAlphaOverFloat(colf, hor); - - VECSUB(vec, vec, dview); - } + zco= ((float)z)/2147483647.0f; + co[2]= R.winmat[3][2]/( R.winmat[2][3]*zco - R.winmat[2][2] ); } -#endif -/* zcor is distance, co the 3d coordinate in eye space, return alpha */ -float mistfactor(float zcor, float *co) +void calc_renderco_zbuf(float *co, float *view, int z) { - float fac, hi; + float fac, zco; - fac= zcor - R.wrld.miststa; /* zcor is calculated per pixel */ + /* inverse of zbuf calc: zbuf = MAXZ*hoco_z/hoco_w */ + zco= ((float)z)/2147483647.0f; + co[2]= R.winmat[3][2]/( R.winmat[2][3]*zco - R.winmat[2][2] ); - /* fac= -co[2]-R.wrld.miststa; */ - - if(fac>0.0) { - if(fac< R.wrld.mistdist) { - - fac= (fac/(R.wrld.mistdist)); - - if(R.wrld.mistype==0) fac*= fac; - else if(R.wrld.mistype==1); - else fac= sqrt(fac); - } - else fac= 1.0; - } - else fac= 0.0; - - /* height switched off mist */ - if(R.wrld.misthi!=0.0 && fac!=0.0) { - /* at height misthi the mist is completely gone */ - - hi= R.viewinv[0][2]*co[0]+R.viewinv[1][2]*co[1]+R.viewinv[2][2]*co[2]+R.viewinv[3][2]; - - if(hi>R.wrld.misthi) fac= 0.0; - else if(hi>0.0) { - hi= (R.wrld.misthi-hi)/R.wrld.misthi; - fac*= hi*hi; - } - } - - return (1.0-fac)* (1.0-R.wrld.misi); + fac= co[2]/view[2]; + co[0]= fac*view[0]; + co[1]= fac*view[1]; } -static void spothalo(struct LampRen *lar, ShadeInput *shi, 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; - - if(R.r.mode & R_ORTHO) { - /* camera pos (view vector) cannot be used... */ - /* camera position (cox,coy,0) rotate around lamp */ - p1[0]= shi->co[0]-lar->co[0]; - p1[1]= shi->co[1]-lar->co[1]; - p1[2]= -lar->co[2]; - MTC_Mat3MulVecfl(lar->imat, p1); - VECCOPY(npos, p1); // npos is double! - } - else { - VECCOPY(npos, lar->sh_invcampos); /* in initlamp calculated */ - } - - /* rotate view */ - VECCOPY(nray, shi->view); - MTC_Mat3MulVecd(lar->imat, nray); - - if(R.wrld.mode & WO_MIST) { - /* patchy... */ - haint *= mistfactor(-lar->co[2], lar->co); - if(haint==0.0) { - return; - } - } - - - /* rotate maxz */ - if(shi->co[2]==0.0) doclip= 0; /* for when halo at sky */ - else { - p1[0]= shi->co[0]-lar->co[0]; - p1[1]= shi->co[1]-lar->co[1]; - p1[2]= shi->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; - } - - /* scale z to make sure volume is normalized */ - nray[2]*= lar->sh_zfac; - /* nray does not need normalization */ - - ladist= lar->sh_zfac*lar->dist; - - /* solve */ - 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) { - /* sort */ - if(t1>t2) { - a= t1; t1= t2; t2= a; - } - - /* z of intersection points with diabolo */ - p1[2]= npos[2] + t1*nray[2]; - p2[2]= npos[2] + t2*nray[2]; - - /* evaluate both points */ - if(p1[2]<=0.0) ok1= 1; - if(p2[2]<=0.0 && t1!=t2) ok2= 1; - - /* at least 1 point with negative z */ - if(ok1==0 && ok2==0) return; - - /* intersction point with -ladist, the bottom of the cone */ - if(use_yco==0) { - t3= (-ladist-npos[2])/nray[2]; - - /* de we have to replace one of the intersection points? */ - 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; - - /* at least 1 visible interesction point */ - 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; - - /* sort again to be sure */ - if(t1>t2) { - a= t1; t1= t2; t2= a; - } - - /* calculate t0: is the maximum visible z (when halo is intersected by face) */ - 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; - } - - /* calc points */ - 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]; - - - /* now we have 2 points, make three lengths with it */ - - 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) ); - - /* WATCH IT: do not clip a,b en c at 1.0, this gives nasty little overflows - at the edges (especially with narrow halos) */ - if(*intens<=0.0) return; - - /* soft area */ - /* not needed because t0 has been used for p1/p2 as well */ - /* if(doclip && t0<t2) { */ - /* *intens *= (t0-t1)/(t2-t1); */ - /* } */ - - *intens *= haint; - - if(lar->shb && lar->shb->shadhalostep) { - *intens *= shadow_halo(lar, p1, p2); - } - - } -} - -static void renderspothalo(ShadeInput *shi, float *col, float alpha) -{ - GroupObject *go; - LampRen *lar; - float i; - - if(alpha==0.0f) return; - - for(go=R.lights.first; go; go= go->next) { - lar= go->lampren; - - if(lar->type==LA_SPOT && (lar->mode & LA_HALO) && lar->haint>0) { - if((lar->lay & shi->lay)==0) continue; - - spothalo(lar, shi, &i); - if(i>0.0) { - col[3]+= i*alpha; // all premul - col[0]+= i*lar->r*alpha; - col[1]+= i*lar->g*alpha; - col[2]+= i*lar->b*alpha; - } - } - } - /* clip alpha, is needed for unified 'alpha threshold' (vanillaRenderPipe.c) */ - if(col[3]>1.0) col[3]= 1.0; -} - - - /* also used in zbuf.c and shadbuf.c */ int count_mask(unsigned short mask) { @@ -445,7 +166,7 @@ static void halo_pixelstruct(HaloRen *har, float *rb, float dist, float xn, floa int amount, amountm, zz, flarec; amount= 0; - accol[0]=accol[1]=accol[2]=accol[3]= 0.0; + accol[0]=accol[1]=accol[2]=accol[3]= 0.0f; flarec= har->flarec; while(ps) { @@ -569,7 +290,7 @@ static void halo_tile(RenderPart *pa, float *pass, unsigned int lay) static void lamphalo_tile(RenderPart *pa, float *pass, unsigned int lay) { ShadeInput shi; - float zco, fac; + float fac; long *rd= pa->rectdaps; int x, y, *rz= pa->rectz; @@ -585,13 +306,10 @@ static void lamphalo_tile(RenderPart *pa, float *pass, unsigned int lay) int samp, totsamp= 0; while(ps) { - /* inverse of zbuf calc: zbuf = MAXZ*hoco_z/hoco_w */ - zco= ((float)ps->z)/2147483647.0f; - shi.co[2]= R.winmat[3][2]/( R.winmat[2][3]*zco - R.winmat[2][2] ); - - fac= shi.co[2]/shi.view[2]; - shi.co[0]= fac*shi.view[0]; - shi.co[1]= fac*shi.view[1]; + if(R.r.mode & R_ORTHO) + calc_renderco_ortho(shi.co, (float)x, (float)y, ps->z); + else + calc_renderco_zbuf(shi.co, shi.view, ps->z); totsamp+= samp= count_mask(ps->mask); fac= ((float)samp)/(float)R.osa; @@ -606,14 +324,12 @@ static void lamphalo_tile(RenderPart *pa, float *pass, unsigned int lay) } else { - /* inverse of zbuf calc: zbuf = MAXZ*hoco_z/hoco_w */ - zco= ((float)*rz)/2147483647.0f; - zco= shi.co[2]= R.winmat[3][2]/( R.winmat[2][3]*zco - R.winmat[2][2] ); - fac= shi.co[2]/shi.view[2]; - shi.co[0]= fac*shi.view[0]; - shi.co[1]= fac*shi.view[1]; + if(R.r.mode & R_ORTHO) + calc_renderco_ortho(shi.co, (float)x, (float)y, *rz); + else + calc_renderco_zbuf(shi.co, shi.view, *rz); - renderspothalo(&shi, pass, 1.0); + renderspothalo(&shi, pass, 1.0f); } if(rd) rd++; @@ -623,2223 +339,6 @@ static void lamphalo_tile(RenderPart *pa, float *pass, unsigned int lay) } } -/* ---------------- shaders ----------------------- */ - -static double Normalise_d(double *n) -{ - double d; - - d= n[0]*n[0]+n[1]*n[1]+n[2]*n[2]; - - if(d>0.00000000000000001) { - d= sqrt(d); - - n[0]/=d; - n[1]/=d; - n[2]/=d; - } else { - n[0]=n[1]=n[2]= 0.0; - d= 0.0; - } - return d; -} - -/* mix of 'real' fresnel and allowing control. grad defines blending gradient */ -float fresnel_fac(float *view, float *vn, float grad, float fac) -{ - float t1, t2; - - if(fac==0.0) return 1.0; - - t1= (view[0]*vn[0] + view[1]*vn[1] + view[2]*vn[2]); - if(t1>0.0) t2= 1.0+t1; - else t2= 1.0-t1; - - t2= grad + (1.0-grad)*pow(t2, fac); - - if(t2<0.0) return 0.0; - else if(t2>1.0) return 1.0; - return t2; -} - -static double saacos_d(double fac) -{ - if(fac<= -1.0f) return M_PI; - else if(fac>=1.0f) return 0.0; - else return acos(fac); -} - -/* Stoke's form factor. Need doubles here for extreme small area sizes */ -static float area_lamp_energy(float *co, float *vn, LampRen *lar) -{ - double fac; - double vec[4][3]; /* vectors of rendered co to vertices lamp */ - double cross[4][3]; /* cross products of this */ - double rad[4]; /* angles between vecs */ - - VECSUB(vec[0], co, lar->area[0]); - VECSUB(vec[1], co, lar->area[1]); - VECSUB(vec[2], co, lar->area[2]); - VECSUB(vec[3], co, lar->area[3]); - - Normalise_d(vec[0]); - Normalise_d(vec[1]); - Normalise_d(vec[2]); - Normalise_d(vec[3]); - - /* cross product */ - CROSS(cross[0], vec[0], vec[1]); - CROSS(cross[1], vec[1], vec[2]); - CROSS(cross[2], vec[2], vec[3]); - CROSS(cross[3], vec[3], vec[0]); - - Normalise_d(cross[0]); - Normalise_d(cross[1]); - Normalise_d(cross[2]); - Normalise_d(cross[3]); - - /* angles */ - rad[0]= vec[0][0]*vec[1][0]+ vec[0][1]*vec[1][1]+ vec[0][2]*vec[1][2]; - rad[1]= vec[1][0]*vec[2][0]+ vec[1][1]*vec[2][1]+ vec[1][2]*vec[2][2]; - rad[2]= vec[2][0]*vec[3][0]+ vec[2][1]*vec[3][1]+ vec[2][2]*vec[3][2]; - rad[3]= vec[3][0]*vec[0][0]+ vec[3][1]*vec[0][1]+ vec[3][2]*vec[0][2]; - - rad[0]= saacos_d(rad[0]); - rad[1]= saacos_d(rad[1]); - rad[2]= saacos_d(rad[2]); - rad[3]= saacos_d(rad[3]); - - /* Stoke formula */ - fac= rad[0]*(vn[0]*cross[0][0]+ vn[1]*cross[0][1]+ vn[2]*cross[0][2]); - fac+= rad[1]*(vn[0]*cross[1][0]+ vn[1]*cross[1][1]+ vn[2]*cross[1][2]); - fac+= rad[2]*(vn[0]*cross[2][0]+ vn[1]*cross[2][1]+ vn[2]*cross[2][2]); - fac+= rad[3]*(vn[0]*cross[3][0]+ vn[1]*cross[3][1]+ vn[2]*cross[3][2]); - - if(fac<=0.0) return 0.0; - return pow(fac*lar->areasize, lar->k); // corrected for buttons size and lar->dist^2 -} - -static float spec(float inp, int hard) -{ - float b1; - - if(inp>=1.0) return 1.0; - else if (inp<=0.0) return 0.0; - - b1= inp*inp; - /* avoid FPE */ - if(b1<0.01) b1= 0.01; - - if((hard & 1)==0) inp= 1.0; - if(hard & 2) inp*= b1; - b1*= b1; - if(hard & 4) inp*= b1; - b1*= b1; - if(hard & 8) inp*= b1; - b1*= b1; - if(hard & 16) inp*= b1; - b1*= b1; - - /* avoid FPE */ - if(b1<0.001) b1= 0.0; - - if(hard & 32) inp*= b1; - b1*= b1; - if(hard & 64) inp*=b1; - b1*= b1; - if(hard & 128) inp*=b1; - - if(b1<0.001) b1= 0.0; - - if(hard & 256) { - b1*= b1; - inp*=b1; - } - - return inp; -} - -static float Phong_Spec( float *n, float *l, float *v, int hard, int tangent ) -{ - float h[3]; - float rslt; - - h[0] = l[0] + v[0]; - h[1] = l[1] + v[1]; - h[2] = l[2] + v[2]; - Normalise(h); - - rslt = h[0]*n[0] + h[1]*n[1] + h[2]*n[2]; - if(tangent) rslt= sasqrt(1.0 - rslt*rslt); - - if( rslt > 0.0 ) rslt= spec(rslt, hard); - else rslt = 0.0; - - return rslt; -} - - -/* reduced cook torrance spec (for off-specular peak) */ -static float CookTorr_Spec(float *n, float *l, float *v, int hard, int tangent) -{ - float i, nh, nv, h[3]; - - h[0]= v[0]+l[0]; - h[1]= v[1]+l[1]; - h[2]= v[2]+l[2]; - Normalise(h); - - nh= n[0]*h[0]+n[1]*h[1]+n[2]*h[2]; - if(tangent) nh= sasqrt(1.0 - nh*nh); - else if(nh<0.0) return 0.0; - - nv= n[0]*v[0]+n[1]*v[1]+n[2]*v[2]; - if(tangent) nv= sasqrt(1.0 - nv*nv); - else if(nv<0.0) nv= 0.0; - - i= spec(nh, hard); - - i= i/(0.1+nv); - return i; -} - -/* Blinn spec */ -static float Blinn_Spec(float *n, float *l, float *v, float refrac, float spec_power, int tangent) -{ - float i, nh, nv, nl, vh, h[3]; - float a, b, c, g=0.0, p, f, ang; - - if(refrac < 1.0) return 0.0; - if(spec_power == 0.0) return 0.0; - - /* conversion from 'hardness' (1-255) to 'spec_power' (50 maps at 0.1) */ - if(spec_power<100.0) - spec_power= sqrt(1.0/spec_power); - else spec_power= 10.0/spec_power; - - h[0]= v[0]+l[0]; - h[1]= v[1]+l[1]; - h[2]= v[2]+l[2]; - Normalise(h); - - nh= n[0]*h[0]+n[1]*h[1]+n[2]*h[2]; /* Dot product between surface normal and half-way vector */ - if(tangent) nh= sasqrt(1.0f - nh*nh); - else if(nh<0.0) return 0.0; - - nv= n[0]*v[0]+n[1]*v[1]+n[2]*v[2]; /* Dot product between surface normal and view vector */ - if(tangent) nv= sasqrt(1.0f - nv*nv); - if(nv<=0.01) nv= 0.01; /* hrms... */ - - nl= n[0]*l[0]+n[1]*l[1]+n[2]*l[2]; /* Dot product between surface normal and light vector */ - if(tangent) nl= sasqrt(1.0f - nl*nl); - if(nl<=0.01) { - return 0.0; - } - - vh= v[0]*h[0]+v[1]*h[1]+v[2]*h[2]; /* Dot product between view vector and half-way vector */ - if(vh<=0.0) vh= 0.01; - - a = 1.0; - b = (2.0*nh*nv)/vh; - c = (2.0*nh*nl)/vh; - - if( a < b && a < c ) g = a; - else if( b < a && b < c ) g = b; - else if( c < a && c < b ) g = c; - - p = sqrt( (double)((refrac * refrac)+(vh*vh)-1.0) ); - f = (((p-vh)*(p-vh))/((p+vh)*(p+vh)))*(1+((((vh*(p+vh))-1.0)*((vh*(p+vh))-1.0))/(((vh*(p-vh))+1.0)*((vh*(p-vh))+1.0)))); - ang = saacos(nh); - - i= f * g * exp((double)(-(ang*ang) / (2.0*spec_power*spec_power))); - if(i<0.0) i= 0.0; - - return i; -} - -/* cartoon render spec */ -static float Toon_Spec( float *n, float *l, float *v, float size, float smooth, int tangent) -{ - float h[3]; - float ang; - float rslt; - - h[0] = l[0] + v[0]; - h[1] = l[1] + v[1]; - h[2] = l[2] + v[2]; - Normalise(h); - - rslt = h[0]*n[0] + h[1]*n[1] + h[2]*n[2]; - if(tangent) rslt = sasqrt(1.0f - rslt*rslt); - - ang = saacos( rslt ); - - if( ang < size ) rslt = 1.0; - else if( ang >= (size + smooth) || smooth == 0.0 ) rslt = 0.0; - else rslt = 1.0 - ((ang - size) / smooth); - - return rslt; -} - -/* Ward isotropic gaussian spec */ -static float WardIso_Spec( float *n, float *l, float *v, float rms, int tangent) -{ - float i, nh, nv, nl, h[3], angle, alpha; - - - /* half-way vector */ - h[0] = l[0] + v[0]; - h[1] = l[1] + v[1]; - h[2] = l[2] + v[2]; - Normalise(h); - - nh = n[0]*h[0]+n[1]*h[1]+n[2]*h[2]; /* Dot product between surface normal and half-way vector */ - if(tangent) nh = sasqrt(1.0f - nh*nh); - if(nh<=0.0) nh = 0.001f; - - nv = n[0]*v[0]+n[1]*v[1]+n[2]*v[2]; /* Dot product between surface normal and view vector */ - if(tangent) nv = sasqrt(1.0f - nv*nv); - if(nv<=0.0) nv = 0.001f; - - nl = n[0]*l[0]+n[1]*l[1]+n[2]*l[2]; /* Dot product between surface normal and light vector */ - if(tangent) nl = sasqrt(1.0f - nl*nl); - if(nl<=0.0) nl = 0.001; - - angle = tan(saacos(nh)); - alpha = MAX2(rms,0.001); - - i= nl * (1.0/(4*M_PI*alpha*alpha)) * (exp( -(angle*angle)/(alpha*alpha))/(sqrt(nv*nl))); - - return i; -} - -/* cartoon render diffuse */ -static float Toon_Diff( float *n, float *l, float *v, float size, float smooth ) -{ - float rslt, ang; - - rslt = n[0]*l[0] + n[1]*l[1] + n[2]*l[2]; - - ang = saacos( (double)(rslt) ); - - if( ang < size ) rslt = 1.0; - else if( ang >= (size + smooth) || smooth == 0.0 ) rslt = 0.0; - else rslt = 1.0 - ((ang - size) / smooth); - - return rslt; -} - -/* Oren Nayar diffuse */ - -/* 'nl' is either dot product, or return value of area light */ -/* in latter case, only last multiplication uses 'nl' */ -static float OrenNayar_Diff(float nl, float *n, float *l, float *v, float rough ) -{ - float i, nh, nv, vh, realnl, h[3]; - float a, b, t, A, B; - float Lit_A, View_A, Lit_B[3], View_B[3]; - - h[0]= v[0]+l[0]; - h[1]= v[1]+l[1]; - h[2]= v[2]+l[2]; - Normalise(h); - - nh= n[0]*h[0]+n[1]*h[1]+n[2]*h[2]; /* Dot product between surface normal and half-way vector */ - if(nh<0.0) nh = 0.0; - - nv= n[0]*v[0]+n[1]*v[1]+n[2]*v[2]; /* Dot product between surface normal and view vector */ - if(nv<=0.0) nv= 0.0; - - realnl= n[0]*l[0]+n[1]*l[1]+n[2]*l[2]; /* Dot product between surface normal and light vector */ - if(realnl<=0.0) return 0.0; - if(nl<0.0) return 0.0; /* value from area light */ - - vh= v[0]*h[0]+v[1]*h[1]+v[2]*h[2]; /* Dot product between view vector and halfway vector */ - if(vh<=0.0) vh= 0.0; - - Lit_A = saacos(realnl); - View_A = saacos( nv ); - - Lit_B[0] = l[0] - (realnl * n[0]); - Lit_B[1] = l[1] - (realnl * n[1]); - Lit_B[2] = l[2] - (realnl * n[2]); - Normalise( Lit_B ); - - View_B[0] = v[0] - (nv * n[0]); - View_B[1] = v[1] - (nv * n[1]); - View_B[2] = v[2] - (nv * n[2]); - Normalise( View_B ); - - t = Lit_B[0]*View_B[0] + Lit_B[1]*View_B[1] + Lit_B[2]*View_B[2]; - if( t < 0 ) t = 0; - - if( Lit_A > View_A ) { - a = Lit_A; - b = View_A; - } - else { - a = View_A; - b = Lit_A; - } - - A = 1 - (0.5 * ((rough * rough) / ((rough * rough) + 0.33))); - B = 0.45 * ((rough * rough) / ((rough * rough) + 0.09)); - - b*= 0.95; /* prevent tangens from shooting to inf, 'nl' can be not a dot product here. */ - /* overflow only happens with extreme size area light, and higher roughness */ - i = nl * ( A + ( B * t * sin(a) * tan(b) ) ); - - return i; -} - -/* Minnaert diffuse */ -static float Minnaert_Diff(float nl, float *n, float *v, float darkness) -{ - - float i, nv; - - /* nl = dot product between surface normal and light vector */ - if (nl <= 0.0) - return 0; - - /* nv = dot product between surface normal and view vector */ - nv = n[0]*v[0]+n[1]*v[1]+n[2]*v[2]; - if (nv < 0.0) - nv = 0; - - if (darkness <= 1) - i = nl * pow(MAX2(nv*nl, 0.1), (darkness - 1) ); /*The Real model*/ - else - i = nl * pow( (1.001 - nv), (darkness - 1) ); /*Nvidia model*/ - - return i; -} - -static float Fresnel_Diff(float *vn, float *lv, float *view, float fac_i, float fac) -{ - return fresnel_fac(lv, vn, fac_i, fac); -} - -/* --------------------------------------------- */ -/* also called from texture.c */ -void calc_R_ref(ShadeInput *shi) -{ - float i; - - /* shi->vn dot shi->view */ - i= -2*(shi->vn[0]*shi->view[0]+shi->vn[1]*shi->view[1]+shi->vn[2]*shi->view[2]); - - shi->ref[0]= (shi->view[0]+i*shi->vn[0]); - shi->ref[1]= (shi->view[1]+i*shi->vn[1]); - shi->ref[2]= (shi->view[2]+i*shi->vn[2]); - if(shi->osatex) { - if(shi->vlr->flag & R_SMOOTH) { - i= -2*( (shi->vn[0]+shi->dxno[0])*(shi->view[0]+shi->dxview) + - (shi->vn[1]+shi->dxno[1])*shi->view[1]+ (shi->vn[2]+shi->dxno[2])*shi->view[2] ); - - shi->dxref[0]= shi->ref[0]- ( shi->view[0]+shi->dxview+i*(shi->vn[0]+shi->dxno[0])); - shi->dxref[1]= shi->ref[1]- (shi->view[1]+ i*(shi->vn[1]+shi->dxno[1])); - shi->dxref[2]= shi->ref[2]- (shi->view[2]+ i*(shi->vn[2]+shi->dxno[2])); - - i= -2*( (shi->vn[0]+shi->dyno[0])*shi->view[0]+ - (shi->vn[1]+shi->dyno[1])*(shi->view[1]+shi->dyview)+ (shi->vn[2]+shi->dyno[2])*shi->view[2] ); - - shi->dyref[0]= shi->ref[0]- (shi->view[0]+ i*(shi->vn[0]+shi->dyno[0])); - shi->dyref[1]= shi->ref[1]- (shi->view[1]+shi->dyview+i*(shi->vn[1]+shi->dyno[1])); - shi->dyref[2]= shi->ref[2]- (shi->view[2]+ i*(shi->vn[2]+shi->dyno[2])); - - } - else { - - i= -2*( shi->vn[0]*(shi->view[0]+shi->dxview) + - shi->vn[1]*shi->view[1]+ shi->vn[2]*shi->view[2] ); - - shi->dxref[0]= shi->ref[0]- (shi->view[0]+shi->dxview+i*shi->vn[0]); - shi->dxref[1]= shi->ref[1]- (shi->view[1]+ i*shi->vn[1]); - shi->dxref[2]= shi->ref[2]- (shi->view[2]+ i*shi->vn[2]); - - i= -2*( shi->vn[0]*shi->view[0]+ - shi->vn[1]*(shi->view[1]+shi->dyview)+ shi->vn[2]*shi->view[2] ); - - shi->dyref[0]= shi->ref[0]- (shi->view[0]+ i*shi->vn[0]); - shi->dyref[1]= shi->ref[1]- (shi->view[1]+shi->dyview+i*shi->vn[1]); - shi->dyref[2]= shi->ref[2]- (shi->view[2]+ i*shi->vn[2]); - } - } - -} - -/* called from ray.c */ -void shade_color(ShadeInput *shi, ShadeResult *shr) -{ - Material *ma= shi->mat; - - if(ma->mode & (MA_VERTEXCOLP|MA_FACETEXTURE)) { - shi->r= shi->vcol[0]; - shi->g= shi->vcol[1]; - shi->b= shi->vcol[2]; - } - - if(ma->texco) { - if(ma->mode & (MA_VERTEXCOLP|MA_FACETEXTURE)) { - shi->r= shi->vcol[0]; - shi->g= shi->vcol[1]; - shi->b= shi->vcol[2]; - } - do_material_tex(shi); - } - - if(ma->fresnel_tra!=0.0) - shi->alpha*= fresnel_fac(shi->view, shi->vn, ma->fresnel_tra_i, ma->fresnel_tra); - - shr->diff[0]= shi->r; - shr->diff[1]= shi->g; - shr->diff[2]= shi->b; - shr->alpha= shi->alpha; -} - -/* ramp for at end of shade */ -static void ramp_diffuse_result(float *diff, ShadeInput *shi) -{ - Material *ma= shi->mat; - float col[4], fac=0; - - if(ma->ramp_col) { - if(ma->rampin_col==MA_RAMP_IN_RESULT) { - - fac= 0.3*diff[0] + 0.58*diff[1] + 0.12*diff[2]; - do_colorband(ma->ramp_col, fac, col); - - /* blending method */ - fac= col[3]*ma->rampfac_col; - - ramp_blend(ma->rampblend_col, diff, diff+1, diff+2, fac, col); - } - } -} - -/* r,g,b denote energy, ramp is used with different values to make new material color */ -static void add_to_diffuse(float *diff, ShadeInput *shi, float is, float r, float g, float b) -{ - Material *ma= shi->mat; - float col[4], colt[3], fac=0; - - if(ma->ramp_col && (ma->mode & MA_RAMP_COL)) { - - /* MA_RAMP_IN_RESULT is exceptional */ - if(ma->rampin_col==MA_RAMP_IN_RESULT) { - // normal add - diff[0] += r * shi->r; - diff[1] += g * shi->g; - diff[2] += b * shi->b; - } - else { - /* input */ - switch(ma->rampin_col) { - case MA_RAMP_IN_ENERGY: - fac= 0.3*r + 0.58*g + 0.12*b; - break; - case MA_RAMP_IN_SHADER: - fac= is; - break; - case MA_RAMP_IN_NOR: - fac= shi->view[0]*shi->vn[0] + shi->view[1]*shi->vn[1] + shi->view[2]*shi->vn[2]; - break; - } - - do_colorband(ma->ramp_col, fac, col); - - /* blending method */ - fac= col[3]*ma->rampfac_col; - colt[0]= shi->r; - colt[1]= shi->g; - colt[2]= shi->b; - - ramp_blend(ma->rampblend_col, colt, colt+1, colt+2, fac, col); - - /* output to */ - diff[0] += r * colt[0]; - diff[1] += g * colt[1]; - diff[2] += b * colt[2]; - } - } - else { - diff[0] += r * shi->r; - diff[1] += g * shi->g; - diff[2] += b * shi->b; - } -} - -static void ramp_spec_result(float *specr, float *specg, float *specb, ShadeInput *shi) -{ - Material *ma= shi->mat; - float col[4]; - float fac; - - if(ma->ramp_spec && (ma->rampin_spec==MA_RAMP_IN_RESULT)) { - fac= 0.3*(*specr) + 0.58*(*specg) + 0.12*(*specb); - do_colorband(ma->ramp_spec, fac, col); - - /* blending method */ - fac= col[3]*ma->rampfac_spec; - - ramp_blend(ma->rampblend_spec, specr, specg, specb, fac, col); - - } -} - -/* is = dot product shade, t = spec energy */ -static void do_specular_ramp(ShadeInput *shi, float is, float t, float *spec) -{ - Material *ma= shi->mat; - float col[4]; - float fac=0.0; - - spec[0]= shi->specr; - spec[1]= shi->specg; - spec[2]= shi->specb; - - /* MA_RAMP_IN_RESULT is exception */ - if(ma->ramp_spec && (ma->rampin_spec!=MA_RAMP_IN_RESULT)) { - - /* input */ - switch(ma->rampin_spec) { - case MA_RAMP_IN_ENERGY: - fac= t; - break; - case MA_RAMP_IN_SHADER: - fac= is; - break; - case MA_RAMP_IN_NOR: - fac= shi->view[0]*shi->vn[0] + shi->view[1]*shi->vn[1] + shi->view[2]*shi->vn[2]; - break; - } - - do_colorband(ma->ramp_spec, fac, col); - - /* blending method */ - fac= col[3]*ma->rampfac_spec; - - ramp_blend(ma->rampblend_spec, spec, spec+1, spec+2, fac, col); - } -} - - - -static void ambient_occlusion(ShadeInput *shi, ShadeResult *shr) -{ - float f, shadfac[4]; - - if((R.wrld.mode & WO_AMB_OCC) && (R.r.mode & R_RAYTRACE) && shi->amb!=0.0) { - ray_ao(shi, shadfac); - - if(R.wrld.aocolor==WO_AOPLAIN) { - if (R.wrld.aomix==WO_AOADDSUB) shadfac[3] = 2.0*shadfac[3]-1.0; - else if (R.wrld.aomix==WO_AOSUB) shadfac[3] = shadfac[3]-1.0; - - f= R.wrld.aoenergy*shadfac[3]*shi->amb; - shr->ao[0]+= f; - shr->ao[1]+= f; - shr->ao[2]+= f; - } - else { - if (R.wrld.aomix==WO_AOADDSUB) { - shadfac[0] = 2.0*shadfac[0]-1.0; - shadfac[1] = 2.0*shadfac[1]-1.0; - shadfac[2] = 2.0*shadfac[2]-1.0; - } - else if (R.wrld.aomix==WO_AOSUB) { - shadfac[0] = shadfac[0]-1.0; - shadfac[1] = shadfac[1]-1.0; - shadfac[2] = shadfac[2]-1.0; - } - f= R.wrld.aoenergy*shi->amb; - shr->ao[0]+= f*shadfac[0]; - shr->ao[1]+= f*shadfac[1]; - shr->ao[2]+= f*shadfac[2]; - } - } -} - -/* function returns diff, spec and optional shadow */ -/* if passrender it returns shadow color, otherwise it applies it to diffuse and spec */ -static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int passrender) -{ - Material *ma= shi->mat; - VlakRen *vlr= shi->vlr; - float lv[3], lampdist, ld= 1.0f, lacol[3], shadfac[4]; - float i, is, inp, i_noshad, *vn, *view, vnor[3], phongcorr=1.0f; - - vn= shi->vn; - view= shi->view; - - /* lampdist calculation */ - if(lar->type==LA_SUN || lar->type==LA_HEMI) { - VECCOPY(lv, lar->vec); - lampdist= 1.0; - } - else { - lv[0]= shi->co[0]-lar->co[0]; - lv[1]= shi->co[1]-lar->co[1]; - lv[2]= shi->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 is re-used further on (texco's) */ - if(lar->type==LA_AREA) { - lampdist= 1.0; - } - else { - if(lar->mode & LA_QUAD) { - float 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) { - float t= lar->dist - ld; - if(t<0.0) return; - - t/= lar->dist; - lampdist*= (t); - } - } - } - - lacol[0]= lar->r; - lacol[1]= lar->g; - lacol[2]= lar->b; - - if(lar->type==LA_SPOT) { - float t, inpr; - - if(lar->mode & LA_SQUARE) { - if(lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2]>0.0) { - float lvrot[3], 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.0f/(sqrt(1.0f+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) return; - else { - t= inpr-t; - i= 1.0; - if(t<lar->spotbl && lar->spotbl!=0.0) { - /* soft area */ - i= t/lar->spotbl; - t= i*i; - inpr*= (3.0*t-2.0*t*i); - } - lampdist*=inpr; - } - - if(lar->mode & LA_OSATEX) { - shi->osatex= 1; /* signal for multitex() */ - - shi->dxlv[0]= lv[0] - (shi->co[0]-lar->co[0]+shi->dxco[0])/ld; - shi->dxlv[1]= lv[1] - (shi->co[1]-lar->co[1]+shi->dxco[1])/ld; - shi->dxlv[2]= lv[2] - (shi->co[2]-lar->co[2]+shi->dxco[2])/ld; - - shi->dylv[0]= lv[0] - (shi->co[0]-lar->co[0]+shi->dyco[0])/ld; - shi->dylv[1]= lv[1] - (shi->co[1]-lar->co[1]+shi->dyco[1])/ld; - shi->dylv[2]= lv[2] - (shi->co[2]-lar->co[2]+shi->dyco[2])/ld; - } - - } - - if(lar->mode & LA_TEXTURE) do_lamp_tex(lar, lv, shi, lacol); - - /* dot product and reflectivity */ - /* inp = dotproduct, is = shader result, i = lamp energy (with shadow) */ - - /* tangent case; calculate fake face normal, aligned with lampvector */ - if(vlr->flag & R_TANGENT) { - float cross[3]; - Crossf(cross, lv, vn); - Crossf(vnor, cross, vn); - vnor[0]= -vnor[0];vnor[1]= -vnor[1];vnor[2]= -vnor[2]; - vn= vnor; - } - else if (ma->mode & MA_TANGENT_V) { - float cross[3]; - Crossf(cross, lv, shi->tang); - Crossf(vnor, cross, shi->tang); - vnor[0]= -vnor[0];vnor[1]= -vnor[1];vnor[2]= -vnor[2]; - vn= vnor; - } - - inp= vn[0]*lv[0] + vn[1]*lv[1] + vn[2]*lv[2]; - - /* phong threshold to prevent backfacing faces having artefacts on ray shadow (terminator problem) */ - /* this complex construction screams for a nicer implementation! (ton) */ - if(R.r.mode & R_SHADOW) { - if(ma->mode & MA_SHADOW) { - if(lar->type==LA_HEMI); - else if((ma->mode & MA_RAYBIAS) && (lar->mode & LA_SHAD_RAY) && (vlr->flag & R_SMOOTH)) { - float thresh= vlr->ob->smoothresh; - if(inp>thresh) - phongcorr= (inp-thresh)/(inp*(1.0-thresh)); - else - phongcorr= 0.0; - } - else if(ma->sbias!=0.0f && ((lar->mode & LA_SHAD_RAY) || lar->shb)) { - if(inp>ma->sbias) - phongcorr= (inp-ma->sbias)/(inp*(1.0-ma->sbias)); - else - phongcorr= 0.0; - } - } - } - - /* diffuse shaders */ - if(lar->mode & LA_NO_DIFF) { - is= 0.0; // skip shaders - } - else if(lar->type==LA_HEMI) { - is= 0.5*inp + 0.5; - } - else { - - if(lar->type==LA_AREA) { - /* single sided */ - if(lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2]>0.0) { - inp= area_lamp_energy(shi->co, vn, lar); - } - else inp= 0.0; - } - - /* diffuse shaders (oren nayer gets inp from area light) */ - if(ma->diff_shader==MA_DIFF_ORENNAYAR) is= OrenNayar_Diff(inp, vn, lv, view, ma->roughness); - else if(ma->diff_shader==MA_DIFF_TOON) is= Toon_Diff(vn, lv, view, ma->param[0], ma->param[1]); - else if(ma->diff_shader==MA_DIFF_MINNAERT) is= Minnaert_Diff(inp, vn, view, ma->darkness); - else if(ma->diff_shader==MA_DIFF_FRESNEL) is= Fresnel_Diff(vn, lv, view, ma->param[0], ma->param[1]); - else is= inp; // Lambert - } - - i= is*phongcorr; - - if(i>0.0) { - i*= lampdist*shi->refl; - } - i_noshad= i; - - vn= shi->vn; // bring back original vector, we use special specular shaders for tangent - if(ma->mode & MA_TANGENT_V) - vn= shi->tang; - - /* init transp shadow */ - shadfac[0]= shadfac[1]= shadfac[2]= shadfac[3]= 1.0; - - /* shadow and spec, (lampdist==0 outside spot) */ - if(lampdist> 0.0) { - - if(i>0.0 && (R.r.mode & R_SHADOW)) { - if(ma->mode & MA_SHADOW) { - if(lar->type==LA_HEMI); // no shadow - else { - if(lar->shb) { - if(lar->buftype==LA_SHADBUF_IRREGULAR) - shadfac[3]= ISB_getshadow(shi, lar->shb); - else - shadfac[3] = testshadowbuf(lar->shb, shi->co, shi->dxco, shi->dyco, inp); - } - else if(lar->mode & LA_SHAD_RAY) { - ray_shadow(shi, lar, shadfac); - } - - /* warning, here it skips the loop */ - if(lar->mode & LA_ONLYSHADOW) { - - shadfac[3]= i*lar->energy*(1.0-shadfac[3]); - shr->diff[0] -= shadfac[3]*shi->r; - shr->diff[1] -= shadfac[3]*shi->g; - shr->diff[2] -= shadfac[3]*shi->b; - return; - } - - if(passrender==0) - if(shadfac[3]==0.0) return; - - i*= shadfac[3]; - } - } - } - - /* in case 'no diffuse' we still do most calculus, spec can be in shadow */ - if(i>0.0 && !(lar->mode & LA_NO_DIFF)) { - if(ma->mode & MA_SHADOW_TRA) - add_to_diffuse(shr->diff, shi, is, i*shadfac[0]*lacol[0], i*shadfac[1]*lacol[1], i*shadfac[2]*lacol[2]); - else - add_to_diffuse(shr->diff, shi, is, i*lacol[0], i*lacol[1], i*lacol[2]); - } - if(passrender && i_noshad>0.0 && !(lar->mode & LA_NO_DIFF)) { - /* while passrender we store shadowless diffuse in shr->shad, so we can subtract */ - if(ma->mode & MA_SHADOW_TRA) - add_to_diffuse(shr->shad, shi, is, i_noshad*shadfac[0]*lacol[0], i_noshad*shadfac[1]*lacol[1], i_noshad*shadfac[2]*lacol[2]); - else - add_to_diffuse(shr->shad, shi, is, i_noshad*lacol[0], i_noshad*lacol[1], i_noshad*lacol[2]); - } - - /* specularity */ - if(shadfac[3]>0.0 && shi->spec!=0.0 && !(lar->mode & LA_NO_SPEC)) { - - if(lar->type==LA_HEMI) { - float t; - /* hemi uses no spec shaders (yet) */ - - 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; - } - - t= shadfac[3]*shi->spec*spec(t, shi->har); - - shr->spec[0]+= t*(lacol[0] * shi->specr); - shr->spec[1]+= t*(lacol[1] * shi->specg); - shr->spec[2]+= t*(lacol[2] * shi->specb); - } - else { - /* specular shaders */ - float specfac, t; - - if(ma->spec_shader==MA_SPEC_PHONG) - specfac= Phong_Spec(vn, lv, view, shi->har, (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V)); - else if(ma->spec_shader==MA_SPEC_COOKTORR) - specfac= CookTorr_Spec(vn, lv, view, shi->har, (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V)); - else if(ma->spec_shader==MA_SPEC_BLINN) - specfac= Blinn_Spec(vn, lv, view, ma->refrac, (float)shi->har, (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V)); - else if(ma->spec_shader==MA_SPEC_WARDISO) - specfac= WardIso_Spec( vn, lv, view, ma->rms, (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V)); - else - specfac= Toon_Spec(vn, lv, view, ma->param[2], ma->param[3], (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V)); - - /* area lamp correction */ - if(lar->type==LA_AREA) specfac*= inp; - - t= shadfac[3]*shi->spec*lampdist*specfac; - - if(ma->mode & MA_RAMP_SPEC) { - float spec[3]; - do_specular_ramp(shi, specfac, t, spec); - shr->spec[0]+= t*(lacol[0] * spec[0]); - shr->spec[1]+= t*(lacol[1] * spec[1]); - shr->spec[2]+= t*(lacol[2] * spec[2]); - } - else { - shr->spec[0]+= t*(lacol[0] * shi->specr); - shr->spec[1]+= t*(lacol[1] * shi->specg); - shr->spec[2]+= t*(lacol[2] * shi->specb); - } - } - } - } - -} - -#if 0 -static void shade_lamp_loop_pass(ShadeInput *shi, ShadeResult *shr, int passflag) -{ - Material *ma= shi->mat; - VlakRen *vlr= shi->vlr; - - memset(shr, 0, sizeof(ShadeResult)); - - /* envmap hack, always reset */ - shi->refcol[0]= shi->refcol[1]= shi->refcol[2]= shi->refcol[3]= 0.0f; - - /* material color itself */ - if(passflag & (SCE_PASS_COMBINED|SCE_PASS_RGBA)) { - if(ma->mode & (MA_VERTEXCOLP|MA_FACETEXTURE)) { - shi->r= shi->vcol[0]; - shi->g= shi->vcol[1]; - shi->b= shi->vcol[2]; - } - if(ma->texco) - do_material_tex(shi); - - shr->col[0]= shi->r; - shr->col[1]= shi->g; - shr->col[2]= shi->b; - } - - if(ma->mode & MA_SHLESS) { - shr->diff[0]= shi->r; - shr->diff[1]= shi->g; - shr->diff[2]= shi->b; - shr->alpha= shi->alpha; - return; - } - - if( (ma->mode & (MA_VERTEXCOL|MA_VERTEXCOLP))== MA_VERTEXCOL ) { // vertexcolor light - shr->diff[0]= shi->r*(shi->emit+shi->vcol[0]); - shr->diff[1]= shi->g*(shi->emit+shi->vcol[1]); - shr->diff[2]= shi->b*(shi->emit+shi->vcol[2]); - } - else { - shr->diff[0]= shi->r*shi->emit; - shr->diff[1]= shi->g*shi->emit; - shr->diff[2]= shi->b*shi->emit; - } - - /* AO pass */ - if(passflag & (SCE_PASS_COMBINED|SCE_PASS_AO)) { - ambient_occlusion(shi, shr); - } - - /* lighting pass */ - if(passflag & (SCE_PASS_COMBINED|SCE_PASS_DIFFUSE|SCE_PASS_SPEC|SCE_PASS_SHADOW)) { - GroupObject *go; - ListBase *lights; - LampRen *lar; - float diff[3]; - - /* lights */ - if(ma->group) - lights= &ma->group->gobject; - else - lights= &R.lights; - - for(go=lights->first; go; go= go->next) { - lar= go->lampren; - if(lar==NULL) continue; - - /* yafray: ignore shading by photonlights, not used in Blender */ - if (lar->type==LA_YF_PHOTON) continue; - - /* test for lamp layer */ - if(lar->mode & LA_LAYER) if((lar->lay & vlr->lay)==0) continue; - if((lar->lay & shi->lay)==0) continue; - - /* accumulates in shr->diff and shr->spec and shr->shad */ - shade_one_light(lar, shi, shr, passflag); - } - - /* calculate shadow */ - VECCOPY(diff, shr->shad); - VECSUB(shr->shad, shr->shad, shr->diff); - VECCOPY(shr->diff, diff); - } - - /* alpha in end, spec can influence it */ - if(passflag & (SCE_PASS_COMBINED|SCE_PASS_RGBA)) { - if(ma->fresnel_tra!=0.0) - shi->alpha*= fresnel_fac(shi->view, shi->vn, ma->fresnel_tra_i, ma->fresnel_tra); - - if(shi->mode & (MA_ZTRA|MA_RAYTRANSP)) { - if(shi->spectra!=0.0) { - float t = MAX3(shr->spec[0], shr->spec[1], shr->spec[2]); - t *= shi->spectra; - if(t>1.0) t= 1.0; - shi->alpha= (1.0-t)*shi->alpha+t; - } - } - shr->col[3]= shi->alpha; - } - shr->alpha= shi->alpha; - - shr->diff[0]+= shi->ambr + shi->r*shi->amb*shi->rad[0]; - shr->diff[1]+= shi->ambg + shi->g*shi->amb*shi->rad[1]; - shr->diff[2]+= shi->ambb + shi->b*shi->amb*shi->rad[2]; - - if(ma->mode & MA_RAMP_COL) ramp_diffuse_result(shr->diff, shi); - if(ma->mode & MA_RAMP_SPEC) ramp_spec_result(shr->spec, shr->spec+1, shr->spec+2, shi); - - /* refcol is for envmap only */ - if(shi->refcol[0]!=0.0) { - shr->diff[0]= shi->mirr*shi->refcol[1] + (1.0 - shi->mirr*shi->refcol[0])*shr->diff[0]; - shr->diff[1]= shi->mirg*shi->refcol[2] + (1.0 - shi->mirg*shi->refcol[0])*shr->diff[1]; - shr->diff[2]= shi->mirb*shi->refcol[3] + (1.0 - shi->mirb*shi->refcol[0])*shr->diff[2]; - } - - if(passflag & SCE_PASS_COMBINED) { - shr->combined[0]= shr->diff[0] + shr->ao[0]*shr->col[0] + shr->spec[0]; - shr->combined[1]= shr->diff[1] + shr->ao[1]*shr->col[1] + shr->spec[1]; - shr->combined[2]= shr->diff[2] + shr->ao[2]*shr->col[2] + shr->spec[2]; - shr->combined[3]= shr->alpha; - } - - if(R.r.mode & R_RAYTRACE) { - - if((ma->mode & MA_RAYMIRROR)==0) shi->ray_mirror= 0.0; - - if(shi->ray_mirror!=0.0 || ((shi->mat->mode & MA_RAYTRANSP) && shr->alpha!=1.0)) { - float diff[3]; - - VECCOPY(diff, shr->diff); - - ray_trace(shi, shr); - - VECSUB(shr->ray, shr->diff, diff); - VECCOPY(shr->diff, diff); - VECADD(shr->combined, shr->combined, shr->ray); - } - } - else { - /* doesnt look 'correct', but is better for preview, plus envmaps dont raytrace this */ - if(shi->mat->mode & MA_RAYTRANSP) shr->alpha= 1.0; - } -} -#endif - -void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr) -{ - LampRen *lar; - GroupObject *go; - Material *ma= shi->mat; - VlakRen *vlr= shi->vlr; - ListBase *lights; - - memset(shr, 0, sizeof(ShadeResult)); - - if((ma->mode & MA_RAYMIRROR)==0) shi->ray_mirror= 0.0; - - /* lights */ - if(ma->group) - lights= &ma->group->gobject; - else - lights= &R.lights; - - /* separate loop */ - if(ma->mode & MA_ONLYSHADOW) { - float i, inp, inpr, lv[3]; - float *vn, *view, shadfac[4]; - float t, ir; - - vn= shi->vn; - view= shi->view; - - if(R.r.mode & R_SHADOW) { - - shadfac[3]= ir= 0.0; - for(go=lights->first; go; go= go->next) { - lar= go->lampren; - if(lar==NULL) continue; - - /* yafray: ignore shading by photonlights, not used in Blender */ - if (lar->type==LA_YF_PHOTON) continue; - - if(lar->mode & LA_LAYER) if((lar->lay & vlr->lay)==0) continue; - if((lar->lay & shi->lay)==0) continue; - - lv[0]= shi->co[0]-lar->co[0]; - lv[1]= shi->co[1]-lar->co[1]; - lv[2]= shi->co[2]-lar->co[2]; - - if(lar->type==LA_SPOT) { - /* only test within spotbundel */ - if(lar->shb || (lar->mode & LA_SHAD_RAY)) { - - 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]; - - /* lampbuffer also returns 0.0 on backfacing normals now */ - if(inp <= 0.0f) - i= 1.0f; - else { - if(lar->shb) { - if(lar->buftype==LA_SHADBUF_IRREGULAR) - i= ISB_getshadow(shi, lar->shb); - else - i = testshadowbuf(lar->shb, shi->co, shi->dxco, shi->dyco, inp); - } - else { - float shad[4]; - ray_shadow(shi, lar, shad); - i= shad[3]; - } - } - - t= inpr - lar->spotsi; - if(t<lar->spotbl && lar->spotbl!=0.0) { - t/= lar->spotbl; - t*= t; - i= t*i+(1.0-t); - } - - shadfac[3]+= i; - ir+= 1.0; - } - else { - shadfac[3]+= 1.0; - ir+= 1.0; - } - } - } - else if(lar->mode & LA_SHAD_RAY) { - float shad[4]; - - /* single sided? */ - if( shi->facenor[0]*lv[0] + shi->facenor[1]*lv[1] + shi->facenor[2]*lv[2] > -0.01) { - ray_shadow(shi, lar, shad); - shadfac[3]+= shad[3]; - ir+= 1.0; - } - } - - } - if(ir>0.0) { - shadfac[3]/= ir; - shr->alpha= (shi->alpha)*(1.0-shadfac[3]); - } - } - - if((R.wrld.mode & WO_AMB_OCC) && (R.r.mode & R_RAYTRACE) && shi->amb!=0.0) { - float f; - - ray_ao(shi, shadfac); // shadfac==0: full light - shadfac[3]= 1.0-shadfac[3]; - - f= R.wrld.aoenergy*shadfac[3]*shi->amb; - - if(R.wrld.aomix==WO_AOADD) { - shr->alpha += f; - shr->alpha *= f; - } - else if(R.wrld.aomix==WO_AOSUB) { - shr->alpha += f; - } - else { - shr->alpha *= f; - shr->alpha += f; - } - } - - return; - } - - if(ma->mode & (MA_VERTEXCOLP|MA_FACETEXTURE)) { - shi->r= shi->vcol[0]; - shi->g= shi->vcol[1]; - shi->b= shi->vcol[2]; - } - - /* envmap hack, always reset */ - shi->refcol[0]= shi->refcol[1]= shi->refcol[2]= shi->refcol[3]= 0.0; - - if(ma->texco) { - if(ma->mode & (MA_VERTEXCOLP|MA_FACETEXTURE)) { - shi->r= shi->vcol[0]; - shi->g= shi->vcol[1]; - shi->b= shi->vcol[2]; - } - do_material_tex(shi); - } - - if(ma->mode & MA_SHLESS) { - shr->diff[0]= shi->r; - shr->diff[1]= shi->g; - shr->diff[2]= shi->b; - shr->alpha= shi->alpha; - return; - } - - if( (ma->mode & (MA_VERTEXCOL|MA_VERTEXCOLP))== MA_VERTEXCOL ) { // vertexcolor light - shr->diff[0]= shi->r*(shi->emit+shi->vcol[0]); - shr->diff[1]= shi->g*(shi->emit+shi->vcol[1]); - shr->diff[2]= shi->b*(shi->emit+shi->vcol[2]); - } - else { - shr->diff[0]= shi->r*shi->emit; - shr->diff[1]= shi->g*shi->emit; - shr->diff[2]= shi->b*shi->emit; - } - - if(R.wrld.mode & WO_AMB_OCC) { - ambient_occlusion(shi, shr); - shr->diff[0] += shi->r*shr->ao[0]; - shr->diff[1] += shi->g*shr->ao[1]; - shr->diff[2] += shi->b*shr->ao[2]; - } - - for(go=lights->first; go; go= go->next) { - lar= go->lampren; - if(lar==NULL) continue; - - /* yafray: ignore shading by photonlights, not used in Blender */ - if (lar->type==LA_YF_PHOTON) continue; - - /* test for lamp layer */ - if(lar->mode & LA_LAYER) if((lar->lay & vlr->lay)==0) continue; - if((lar->lay & shi->lay)==0) continue; - - /* accumulates in shr->diff and shr->spec, 0= no passrender */ - shade_one_light(lar, shi, shr, 0); - } - - if(ma->fresnel_tra!=0.0) - shi->alpha*= fresnel_fac(shi->view, shi->vn, ma->fresnel_tra_i, ma->fresnel_tra); - - if(shi->mode & (MA_ZTRA|MA_RAYTRANSP)) { - if(shi->spectra!=0.0) { - float t = MAX3(shr->spec[0], shr->spec[1], shr->spec[2]); - t *= shi->spectra; - if(t>1.0) t= 1.0; - shi->alpha= (1.0-t)*shi->alpha+t; - } - } - - shr->alpha= shi->alpha; - - if(shr->spec[0]<0.0f) shr->spec[0]= 0.0f; - if(shr->spec[1]<0.0f) shr->spec[1]= 0.0f; - if(shr->spec[2]<0.0f) shr->spec[2]= 0.0f; - - shr->diff[0]+= shi->r*shi->amb*shi->rad[0]; - shr->diff[0]+= shi->ambr; - if(shr->diff[0]<0.0f) shr->diff[0]= 0.0f; - - shr->diff[1]+= shi->g*shi->amb*shi->rad[1]; - shr->diff[1]+= shi->ambg; - if(shr->diff[1]<0.0f) shr->diff[1]= 0.0f; - - shr->diff[2]+= shi->b*shi->amb*shi->rad[2]; - shr->diff[2]+= shi->ambb; - if(shr->diff[2]<0.0f) shr->diff[2]= 0.0f; - - if(ma->mode & MA_RAMP_COL) ramp_diffuse_result(shr->diff, shi); - if(ma->mode & MA_RAMP_SPEC) ramp_spec_result(shr->spec, shr->spec+1, shr->spec+2, shi); - - /* refcol is for envmap only */ - if(shi->refcol[0]!=0.0) { - shr->diff[0]= shi->mirr*shi->refcol[1] + (1.0 - shi->mirr*shi->refcol[0])*shr->diff[0]; - shr->diff[1]= shi->mirg*shi->refcol[2] + (1.0 - shi->mirg*shi->refcol[0])*shr->diff[1]; - shr->diff[2]= shi->mirb*shi->refcol[3] + (1.0 - shi->mirb*shi->refcol[0])*shr->diff[2]; - } - -} - -static void vlr_set_uv_indices(VlakRen *vlr, int *i1, int *i2, int *i3) -{ - /* to prevent storing new tfaces or vcols, we check a split runtime */ - /* 4---3 4---3 */ - /* |\ 1| or |1 /| */ - /* |0\ | |/ 0| */ - /* 1---2 1---2 0 = orig face, 1 = new face */ - - /* Update vert nums to point to correct verts of original face */ - if(vlr->flag & R_DIVIDE_24) { - if(vlr->flag & R_FACE_SPLIT) { - (*i1)++; (*i2)++; (*i3)++; - } - else { - (*i3)++; - } - } - else if(vlr->flag & R_FACE_SPLIT) { - (*i2)++; (*i3)++; - } -} - -/* this function sets all coords for render (shared with raytracer) */ -/* warning; exception for ortho render is here, can be done better! */ -void shade_input_set_coords(ShadeInput *shi, float u, float v, int i1, int i2, int i3) -{ - VertRen *v1, *v2, *v3; - VlakRen *vlr= shi->vlr; - float l, dl; - int mode= shi->mode= shi->mat->mode_l; /* or-ed result for all nodes */ - short texco= shi->mat->texco; - char p1, p2, p3; - - /* for rendering of quads, the following values are used to denote vertices: - 0 1 2 scanline tria & first half quad, and ray tria - 0 2 3 scanline 2nd half quad - 0 1 3 raytracer first half quad - 2 1 3 raytracer 2nd half quad - */ - - if(i1==0) { - v1= vlr->v1; - p1= ME_FLIPV1; - } else { - v1= vlr->v3; - p1= ME_FLIPV3; - } - - if(i2==1) { - v2= vlr->v2; - p2= ME_FLIPV2; - } else { - v2= vlr->v3; - p2= ME_FLIPV3; - } - - if(i3==2) { - v3= vlr->v3; - p3= ME_FLIPV3; - } else { - v3= vlr->v4; - p3= ME_FLIPV4; - } - - /* calculate U and V, for scanline (normal u and v are -1 to 0) */ - if(u==1.0) { - if( (vlr->flag & R_SMOOTH) || (texco & NEED_UV) ) { - /* exception case for wire render of edge */ - if(vlr->v2==vlr->v3) { - float lend, lenc; - - lend= VecLenf(v2->co, v1->co); - lenc= VecLenf(shi->co, v1->co); - - if(lend==0.0f) { - u=v= 0.0f; - } - else { - u= - (1.0f - lenc/lend); - v= 0.0f; - } - - if(shi->osatex) { - shi->dxuv[0]= 0.0f; - shi->dxuv[1]= 0.0f; - shi->dyuv[0]= 0.0f; - shi->dyuv[1]= 0.0f; - } - } - else { - float detsh, t00, t10, t01, t11; - - 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= 1.0/(t00*t11-t10*t01); - t00*= detsh; t01*=detsh; - t10*=detsh; t11*=detsh; - - if(vlr->snproj==0) { - u= (shi->co[0]-v3->co[0])*t11-(shi->co[1]-v3->co[1])*t10; - v= (shi->co[1]-v3->co[1])*t00-(shi->co[0]-v3->co[0])*t01; - if(shi->osatex) { - shi->dxuv[0]= shi->dxco[0]*t11- shi->dxco[1]*t10; - shi->dxuv[1]= shi->dxco[1]*t00- shi->dxco[0]*t01; - shi->dyuv[0]= shi->dyco[0]*t11- shi->dyco[1]*t10; - shi->dyuv[1]= shi->dyco[1]*t00- shi->dyco[0]*t01; - } - } - else if(vlr->snproj==1) { - u= (shi->co[0]-v3->co[0])*t11-(shi->co[2]-v3->co[2])*t10; - v= (shi->co[2]-v3->co[2])*t00-(shi->co[0]-v3->co[0])*t01; - if(shi->osatex) { - shi->dxuv[0]= shi->dxco[0]*t11- shi->dxco[2]*t10; - shi->dxuv[1]= shi->dxco[2]*t00- shi->dxco[0]*t01; - shi->dyuv[0]= shi->dyco[0]*t11- shi->dyco[2]*t10; - shi->dyuv[1]= shi->dyco[2]*t00- shi->dyco[0]*t01; - } - } - else { - u= (shi->co[1]-v3->co[1])*t11-(shi->co[2]-v3->co[2])*t10; - v= (shi->co[2]-v3->co[2])*t00-(shi->co[1]-v3->co[1])*t01; - if(shi->osatex) { - shi->dxuv[0]= shi->dxco[1]*t11- shi->dxco[2]*t10; - shi->dxuv[1]= shi->dxco[2]*t00- shi->dxco[1]*t01; - shi->dyuv[0]= shi->dyco[1]*t11- shi->dyco[2]*t10; - shi->dyuv[1]= shi->dyco[2]*t00- shi->dyco[1]*t01; - } - } - /* u and v are in range -1 to 0, we allow a little bit extra but not too much, screws up speedvectors */ - CLAMP(u, -2.0f, 1.0f); - CLAMP(v, -2.0f, 1.0f); - } - } - } - l= 1.0+u+v; - - /* calculate punos (vertexnormals) */ - if(vlr->flag & R_SMOOTH) { - float n1[3], n2[3], n3[3]; - - if(shi->puno & p1) { - n1[0]= -v1->n[0]; n1[1]= -v1->n[1]; n1[2]= -v1->n[2]; - } else { - n1[0]= v1->n[0]; n1[1]= v1->n[1]; n1[2]= v1->n[2]; - } - if(shi->puno & p2) { - n2[0]= -v2->n[0]; n2[1]= -v2->n[1]; n2[2]= -v2->n[2]; - } else { - n2[0]= v2->n[0]; n2[1]= v2->n[1]; n2[2]= v2->n[2]; - } - - if(shi->puno & p3) { - n3[0]= -v3->n[0]; n3[1]= -v3->n[1]; n3[2]= -v3->n[2]; - } else { - n3[0]= v3->n[0]; n3[1]= v3->n[1]; n3[2]= v3->n[2]; - } - - shi->vn[0]= l*n3[0]-u*n1[0]-v*n2[0]; - shi->vn[1]= l*n3[1]-u*n1[1]-v*n2[1]; - shi->vn[2]= l*n3[2]-u*n1[2]-v*n2[2]; - - Normalise(shi->vn); - - if(shi->osatex && (texco & (TEXCO_NORM|TEXCO_REFL)) ) { - dl= shi->dxuv[0]+shi->dxuv[1]; - shi->dxno[0]= dl*n3[0]-shi->dxuv[0]*n1[0]-shi->dxuv[1]*n2[0]; - shi->dxno[1]= dl*n3[1]-shi->dxuv[0]*n1[1]-shi->dxuv[1]*n2[1]; - shi->dxno[2]= dl*n3[2]-shi->dxuv[0]*n1[2]-shi->dxuv[1]*n2[2]; - dl= shi->dyuv[0]+shi->dyuv[1]; - shi->dyno[0]= dl*n3[0]-shi->dyuv[0]*n1[0]-shi->dyuv[1]*n2[0]; - shi->dyno[1]= dl*n3[1]-shi->dyuv[0]*n1[1]-shi->dyuv[1]*n2[1]; - shi->dyno[2]= dl*n3[2]-shi->dyuv[0]*n1[2]-shi->dyuv[1]*n2[2]; - - } - - /* qdn: normalmap tangent space separated from shading */ - if (mode & (MA_TANGENT_V|MA_NORMAP_TANG)) { - float *s1, *s2, *s3; - - s1= RE_vertren_get_tangent(&R, v1, 0); - s2= RE_vertren_get_tangent(&R, v2, 0); - s3= RE_vertren_get_tangent(&R, v3, 0); - if(s1 && s2 && s3) { - shi->tang[0]= (l*s3[0] - u*s1[0] - v*s2[0]); - shi->tang[1]= (l*s3[1] - u*s1[1] - v*s2[1]); - shi->tang[2]= (l*s3[2] - u*s1[2] - v*s2[2]); - /* qdn: normalize just in case */ - Normalise(shi->tang); - } - else shi->tang[0]= shi->tang[1]= shi->tang[2]= 0.0f; - } - } - else { - VECCOPY(shi->vn, shi->facenor); - /* qdn: normalmap tangent space separated from shading */ - if (mode & (MA_TANGENT_V|MA_NORMAP_TANG)) { - /* qdn: flat faces have tangents too, - could pick either one, using average here */ - float *s1 = RE_vertren_get_tangent(&R, v1, 0); - float *s2 = RE_vertren_get_tangent(&R, v2, 0); - float *s3 = RE_vertren_get_tangent(&R, v3, 0); - if (s1 && s2 && s3) { - shi->tang[0] = (s1[0] + s2[0] + s3[0]); - shi->tang[1] = (s1[1] + s2[1] + s3[1]); - shi->tang[2] = (s1[2] + s2[2] + s3[2]); - Normalise(shi->tang); - } - } - } - - /* used in nodes */ - VECCOPY(shi->vno, shi->vn); - - if(R.r.mode & R_SPEED) { - float *s1, *s2, *s3; - - s1= RE_vertren_get_winspeed(&R, v1, 0); - s2= RE_vertren_get_winspeed(&R, v2, 0); - s3= RE_vertren_get_winspeed(&R, v3, 0); - if(s1 && s2 && s3) { - shi->winspeed[0]= (l*s3[0] - u*s1[0] - v*s2[0]); - shi->winspeed[1]= (l*s3[1] - u*s1[1] - v*s2[1]); - shi->winspeed[2]= (l*s3[2] - u*s1[2] - v*s2[2]); - shi->winspeed[3]= (l*s3[3] - u*s1[3] - v*s2[3]); - } - else { - shi->winspeed[0]= shi->winspeed[1]= shi->winspeed[2]= shi->winspeed[3]= 0.0f; - } - } - - /* texture coordinates. shi->dxuv shi->dyuv have been set */ - if(texco & NEED_UV) { - if(texco & TEXCO_ORCO) { - if(v1->orco) { - float *o1, *o2, *o3; - - o1= v1->orco; - o2= v2->orco; - o3= v3->orco; - - shi->lo[0]= l*o3[0]-u*o1[0]-v*o2[0]; - shi->lo[1]= l*o3[1]-u*o1[1]-v*o2[1]; - shi->lo[2]= l*o3[2]-u*o1[2]-v*o2[2]; - - if(shi->osatex) { - dl= shi->dxuv[0]+shi->dxuv[1]; - shi->dxlo[0]= dl*o3[0]-shi->dxuv[0]*o1[0]-shi->dxuv[1]*o2[0]; - shi->dxlo[1]= dl*o3[1]-shi->dxuv[0]*o1[1]-shi->dxuv[1]*o2[1]; - shi->dxlo[2]= dl*o3[2]-shi->dxuv[0]*o1[2]-shi->dxuv[1]*o2[2]; - dl= shi->dyuv[0]+shi->dyuv[1]; - shi->dylo[0]= dl*o3[0]-shi->dyuv[0]*o1[0]-shi->dyuv[1]*o2[0]; - shi->dylo[1]= dl*o3[1]-shi->dyuv[0]*o1[1]-shi->dyuv[1]*o2[1]; - shi->dylo[2]= dl*o3[2]-shi->dyuv[0]*o1[2]-shi->dyuv[1]*o2[2]; - } - } - } - - if(texco & TEXCO_GLOB) { - VECCOPY(shi->gl, shi->co); - MTC_Mat4MulVecfl(R.viewinv, shi->gl); - if(shi->osatex) { - VECCOPY(shi->dxgl, shi->dxco); - MTC_Mat3MulVecfl(R.imat, shi->dxco); - VECCOPY(shi->dygl, shi->dyco); - MTC_Mat3MulVecfl(R.imat, shi->dyco); - } - } - if(texco & TEXCO_STRAND) { - shi->strand= (l*v3->accum - u*v1->accum - v*v2->accum); - if(shi->osatex) { - dl= shi->dxuv[0]+shi->dxuv[1]; - shi->dxstrand= dl*v3->accum-shi->dxuv[0]*v1->accum-shi->dxuv[1]*v2->accum; - dl= shi->dyuv[0]+shi->dyuv[1]; - shi->dystrand= dl*v3->accum-shi->dyuv[0]*v1->accum-shi->dyuv[1]*v2->accum; - } - } - if((texco & TEXCO_UV) || (mode & (MA_VERTEXCOL|MA_VERTEXCOLP|MA_FACETEXTURE))) { - int j1=i1, j2=i2, j3=i3; - - /* uv and vcols are not copied on split, so set them according vlr divide flag */ - vlr_set_uv_indices(vlr, &j1, &j2, &j3); - - if(mode & (MA_VERTEXCOL|MA_VERTEXCOLP)) { - - if(vlr->vcol) { - char *cp1, *cp2, *cp3; - - cp1= (char *)(vlr->vcol+j1); - cp2= (char *)(vlr->vcol+j2); - cp3= (char *)(vlr->vcol+j3); - - shi->vcol[0]= (l*((float)cp3[3]) - u*((float)cp1[3]) - v*((float)cp2[3]))/255.0; - shi->vcol[1]= (l*((float)cp3[2]) - u*((float)cp1[2]) - v*((float)cp2[2]))/255.0; - shi->vcol[2]= (l*((float)cp3[1]) - u*((float)cp1[1]) - v*((float)cp2[1]))/255.0; - } - else { - shi->vcol[0]= 0.0; - shi->vcol[1]= 0.0; - shi->vcol[2]= 0.0; - } - } - if(vlr->tface) { - float *uv1, *uv2, *uv3; - - uv1= vlr->tface->uv[j1]; - uv2= vlr->tface->uv[j2]; - uv3= vlr->tface->uv[j3]; - - shi->uv[0]= -1.0 + 2.0*(l*uv3[0]-u*uv1[0]-v*uv2[0]); - shi->uv[1]= -1.0 + 2.0*(l*uv3[1]-u*uv1[1]-v*uv2[1]); - shi->uv[2]= 0.0; // texture.c assumes there are 3 coords - - if(shi->osatex) { - float duv[2]; - - dl= shi->dxuv[0]+shi->dxuv[1]; - duv[0]= shi->dxuv[0]; - duv[1]= shi->dxuv[1]; - - shi->dxuv[0]= 2.0*(dl*uv3[0]-duv[0]*uv1[0]-duv[1]*uv2[0]); - shi->dxuv[1]= 2.0*(dl*uv3[1]-duv[0]*uv1[1]-duv[1]*uv2[1]); - - dl= shi->dyuv[0]+shi->dyuv[1]; - duv[0]= shi->dyuv[0]; - duv[1]= shi->dyuv[1]; - - shi->dyuv[0]= 2.0*(dl*uv3[0]-duv[0]*uv1[0]-duv[1]*uv2[0]); - shi->dyuv[1]= 2.0*(dl*uv3[1]-duv[0]*uv1[1]-duv[1]*uv2[1]); - } - if(mode & MA_FACETEXTURE) { - if((mode & (MA_VERTEXCOL|MA_VERTEXCOLP))==0) { - shi->vcol[0]= 1.0; - shi->vcol[1]= 1.0; - shi->vcol[2]= 1.0; - } - if(vlr->tface) render_realtime_texture(shi); - } - } - else { - shi->uv[0]= 2.0*(u+.5); - shi->uv[1]= 2.0*(v+.5); - shi->uv[2]= 0.0; // texture.c assumes there are 3 coords - if(mode & MA_FACETEXTURE) { - /* no tface? set at 1.0 */ - shi->vcol[0]= 1.0; - shi->vcol[1]= 1.0; - shi->vcol[2]= 1.0; - } - } - } - if(texco & TEXCO_NORM) { - shi->orn[0]= -shi->vn[0]; - shi->orn[1]= -shi->vn[1]; - shi->orn[2]= -shi->vn[2]; - } - if(mode & MA_RADIO) { - float *r1, *r2, *r3; - - r1= RE_vertren_get_rad(&R, v1, 0); - r2= RE_vertren_get_rad(&R, v2, 0); - r3= RE_vertren_get_rad(&R, v3, 0); - - if(r1 && r2 && r3) { - shi->rad[0]= (l*r3[0] - u*r1[0] - v*r2[0]); - shi->rad[1]= (l*r3[1] - u*r1[1] - v*r2[1]); - shi->rad[2]= (l*r3[2] - u*r1[2] - v*r2[2]); - } - else { - shi->rad[0]= shi->rad[1]= shi->rad[2]= 0.0; - } - } - else { - shi->rad[0]= shi->rad[1]= shi->rad[2]= 0.0; - } - if(texco & TEXCO_REFL) { - /* mirror reflection colour textures (and envmap) */ - calc_R_ref(shi); /* wrong location for normal maps! XXXXXXXXXXXXXX */ - } - if(texco & TEXCO_STRESS) { - float *s1, *s2, *s3; - - s1= RE_vertren_get_stress(&R, v1, 0); - s2= RE_vertren_get_stress(&R, v2, 0); - s3= RE_vertren_get_stress(&R, v3, 0); - if(s1 && s2 && s3) { - shi->stress= l*s3[0] - u*s1[0] - v*s2[0]; - if(shi->stress<1.0f) shi->stress-= 1.0f; - else shi->stress= (shi->stress-1.0f)/shi->stress; - } - else shi->stress= 0.0f; - } - if(texco & TEXCO_TANGENT) { - if((mode & MA_TANGENT_V)==0) { - /* just prevent surprises */ - shi->tang[0]= shi->tang[1]= shi->tang[2]= 0.0f; - } - } - } - else { - shi->rad[0]= shi->rad[1]= shi->rad[2]= 0.0; - } -} - -#if 0 -/* return labda for view vector being closest to line v3-v4 */ -/* was used for wire render */ -static float isec_view_line(float *view, float *v3, float *v4) -{ - float vec[3]; - float dot0, dot1, dot2, veclen, viewlen; - float fac, div; - - vec[0]= v4[0] - v3[0]; - vec[1]= v4[1] - v3[1]; - vec[2]= v4[2] - v3[2]; - - dot0 = v3[0]*vec[0] + v3[1]*vec[1] + v3[2]*vec[2]; - dot1 = vec[0]*view[0] + vec[1]*view[1] + vec[2]*view[2]; - dot2 = v3[0]*view[0] + v3[1]*view[1] + v3[2]*view[2]; - - veclen = vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]; - viewlen = view[0]*view[0] + view[1]*view[1] + view[2]*view[2]; - - div = viewlen*veclen - dot1*dot1; - if (div==0.0) return 0.0; - - fac = dot2*veclen - dot0*dot1; - return fac/div; -} -#endif - - -/* also used as callback for nodes */ -void shade_material_loop(ShadeInput *shi, ShadeResult *shr) -{ - - shade_lamp_loop(shi, shr); /* clears shr */ - - if(shi->translucency!=0.0) { - ShadeResult shr_t; - - VECCOPY(shi->vn, shi->vno); - VecMulf(shi->vn, -1.0); - VecMulf(shi->facenor, -1.0); - shade_lamp_loop(shi, &shr_t); - - shr->diff[0]+= shi->translucency*shr_t.diff[0]; - shr->diff[1]+= shi->translucency*shr_t.diff[1]; - shr->diff[2]+= shi->translucency*shr_t.diff[2]; - VecMulf(shi->vn, -1.0); - VecMulf(shi->facenor, -1.0); - } - - /* depth >= 1 when ray-shading */ - if(shi->depth==0) { - if(R.r.mode & R_RAYTRACE) { - if(shi->ray_mirror!=0.0 || ((shi->mat->mode & MA_RAYTRANSP) && shr->alpha!=1.0)) { - ray_trace(shi, shr); - } - } - else { - /* doesnt look 'correct', but is better for preview, plus envmaps dont raytrace this */ - if(shi->mat->mode & MA_RAYTRANSP) shr->alpha= 1.0; - } - } -} - -/* x,y: window coordinate from 0 to rectx,y */ -/* return pointer to rendered face */ -/* note, facenr declared volatile due to over-eager -O2 optimizations - * on cygwin (particularly -frerun-cse-after-loop) - */ -void *shadepixel(ShadePixelInfo *shpi, float x, float y, int z, volatile int facenr, int mask, float *rco) -{ - ShadeResult *shr= &shpi->shr; - ShadeInput shi; - VlakRen *vlr=NULL; - - /* currently in use for dithering (soft shadow), node preview, irregular shad */ - shi.xs= (int)(x); - shi.ys= (int)(y); - - shi.thread= shpi->thread; - shi.do_preview= R.r.scemode & R_NODE_PREVIEW; - shi.lay= shpi->lay; - - /* mask is used to indicate amount of samples (ray shad/mir and AO) */ - shi.mask= mask; - shi.depth= 0; // means first hit, not raytracing - - if(facenr<=0) { /* sky or env */ - memset(shr, 0, sizeof(ShadeResult)); - rco[0]= rco[1]= rco[2]= 0.0f; - } - else if( (facenr & RE_QUAD_MASK) <= R.totvlak) { - VertRen *v1; - float alpha, fac, zcor; - - shi.facenr= (facenr-1) & RE_QUAD_MASK; - vlr= RE_findOrAddVlak(&R, shi.facenr); - - shi.vlr= vlr; - shi.mat= vlr->mat; - - shi.osatex= (shi.mat->texco & TEXCO_OSA); - - /* copy the face normal (needed because it gets flipped for tracing */ - VECCOPY(shi.facenor, vlr->n); - shi.puno= vlr->puno; - - v1= vlr->v1; - - /* COXYZ AND VIEW VECTOR */ - calc_view_vector(shi.view, x, y); /* returns not normalized, so is in viewplane coords */ - - /* wire cannot use normal for calculating shi.co */ - if(shi.mat->mode & MA_WIRE) { - float zco; - /* inverse of zbuf calc: zbuf = MAXZ*hoco_z/hoco_w */ - - zco= ((float)z)/2147483647.0f; - shi.co[2]= R.winmat[3][2]/( R.winmat[2][3]*zco - R.winmat[2][2] ); - - fac= zcor= shi.co[2]/shi.view[2]; - - shi.co[0]= fac*shi.view[0]; - shi.co[1]= fac*shi.view[1]; - } - else { - float dface; - - dface= v1->co[0]*shi.facenor[0]+v1->co[1]*shi.facenor[1]+v1->co[2]*shi.facenor[2]; - - /* ortho viewplane cannot intersect using view vector originating in (0,0,0) */ - if(R.r.mode & R_ORTHO) { - /* x and y 3d coordinate can be derived from pixel coord and winmat */ - float fx= 2.0/(R.winx*R.winmat[0][0]); - float fy= 2.0/(R.winy*R.winmat[1][1]); - - shi.co[0]= (x - 0.5*R.winx)*fx - R.winmat[3][0]/R.winmat[0][0]; - shi.co[1]= (y - 0.5*R.winy)*fy - R.winmat[3][1]/R.winmat[1][1]; - - /* using a*x + b*y + c*z = d equation, (a b c) is normal */ - if(shi.facenor[2]!=0.0f) - shi.co[2]= (dface - shi.facenor[0]*shi.co[0] - shi.facenor[1]*shi.co[1])/shi.facenor[2]; - else - shi.co[2]= 0.0f; - - zcor= 1.0; // only to prevent not-initialize - - if(shi.osatex || (R.r.mode & R_SHADOW) ) { - shi.dxco[0]= fx; - shi.dxco[1]= 0.0; - if(shi.facenor[2]!=0.0f) - shi.dxco[2]= (shi.facenor[0]*fx)/shi.facenor[2]; - else - shi.dxco[2]= 0.0f; - - shi.dyco[0]= 0.0; - shi.dyco[1]= fy; - if(shi.facenor[2]!=0.0f) - shi.dyco[2]= (shi.facenor[1]*fy)/shi.facenor[2]; - else - shi.dyco[2]= 0.0f; - } - } - else { - float div; - - div= shi.facenor[0]*shi.view[0] + shi.facenor[1]*shi.view[1] + shi.facenor[2]*shi.view[2]; - if (div!=0.0) fac= zcor= dface/div; - else fac= zcor= 0.0; - - shi.co[0]= fac*shi.view[0]; - shi.co[1]= fac*shi.view[1]; - shi.co[2]= fac*shi.view[2]; - - /* pixel dx/dy for render coord */ - if(shi.osatex || (R.r.mode & R_SHADOW) ) { - float u= dface/(div - R.viewdx*shi.facenor[0]); - float v= dface/(div - R.viewdy*shi.facenor[1]); - - shi.dxco[0]= shi.co[0]- (shi.view[0]-R.viewdx)*u; - shi.dxco[1]= shi.co[1]- (shi.view[1])*u; - shi.dxco[2]= shi.co[2]- (shi.view[2])*u; - - shi.dyco[0]= shi.co[0]- (shi.view[0])*v; - shi.dyco[1]= shi.co[1]- (shi.view[1]-R.viewdy)*v; - shi.dyco[2]= shi.co[2]- (shi.view[2])*v; - - } - } - } - /* rco might be used for sky texture */ - VECCOPY(rco, shi.co); - - /* cannot normalise earlier, code above needs it at viewplane level */ - fac= Normalise(shi.view); - zcor*= fac; // for mist, distance of point from camera - - if(shi.osatex) { - if( (shi.mat->texco & TEXCO_REFL) ) { - shi.dxview= -R.viewdx/fac; - shi.dyview= -R.viewdy/fac; - } - } - - /* calcuate normals, texture coords, vertex colors, etc */ - if(facenr & RE_QUAD_OFFS) - shade_input_set_coords(&shi, 1.0, 1.0, 0, 2, 3); - else - shade_input_set_coords(&shi, 1.0, 1.0, 0, 1, 2); - - /* this only avalailable for scanline */ - if(shi.mat->texco & TEXCO_WINDOW) { - shi.winco[0]= -1.0f + 2.0f*x/(float)R.winx; - shi.winco[1]= -1.0f + 2.0f*y/(float)R.winy; - shi.winco[2]= 0.0; - if(shi.osatex) { - shi.dxwin[0]= 2.0/(float)R.winx; - shi.dywin[1]= 2.0/(float)R.winy; - shi.dxwin[1]= shi.dxwin[2]= 0.0; - shi.dywin[0]= shi.dywin[2]= 0.0; - } - } - /* after this the u and v AND shi.dxuv and shi.dyuv are incorrect */ - if(shi.mat->texco & TEXCO_STICKY) { - VertRen *v2, *v3; - float *s1, *s2, *s3; - - if(facenr & RE_QUAD_OFFS) { - v2= vlr->v3; v3= vlr->v4; - } else { - v2= vlr->v2; v3= vlr->v3; - } - - s1= RE_vertren_get_sticky(&R, v1, 0); - s2= RE_vertren_get_sticky(&R, v2, 0); - s3= RE_vertren_get_sticky(&R, v3, 0); - - if(s1 && s2 && s3) { - float Zmulx, Zmuly; - float hox, hoy, l, dl, u, v; - float s00, s01, s10, s11, detsh; - - /* old globals, localized now */ - Zmulx= ((float)R.winx)/2.0; Zmuly= ((float)R.winy)/2.0; - - 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; - - /* recalc u and v again */ - 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; - - shi.sticky[0]= l*s3[0]-u*s1[0]-v*s2[0]; - shi.sticky[1]= l*s3[1]-u*s1[1]-v*s2[1]; - shi.sticky[2]= 0.0; - - if(shi.osatex) { - shi.dxuv[0]= s11/Zmulx; - shi.dxuv[1]= - s01/Zmulx; - shi.dyuv[0]= - s10/Zmuly; - shi.dyuv[1]= s00/Zmuly; - - dl= shi.dxuv[0]+shi.dxuv[1]; - shi.dxsticky[0]= dl*s3[0]-shi.dxuv[0]*s1[0]-shi.dxuv[1]*s2[0]; - shi.dxsticky[1]= dl*s3[1]-shi.dxuv[0]*s1[1]-shi.dxuv[1]*s2[1]; - dl= shi.dyuv[0]+shi.dyuv[1]; - shi.dysticky[0]= dl*s3[0]-shi.dyuv[0]*s1[0]-shi.dyuv[1]*s2[0]; - shi.dysticky[1]= dl*s3[1]-shi.dyuv[0]*s1[1]-shi.dyuv[1]*s2[1]; - } - } - } - - /* ------ main shading loop -------- */ - - if(shi.mat->nodetree && shi.mat->use_nodes) { - ntreeShaderExecTree(shi.mat->nodetree, &shi, shr); - } - else { - /* copy all relevant material vars, note, keep this synced with render_types.h */ - memcpy(&shi.r, &shi.mat->r, 23*sizeof(float)); - shi.har= shi.mat->har; - -// if(passflag) -// shade_lamp_loop_pass(&shi, shr, passflag); -// else - shade_material_loop(&shi, shr); - } - - /* after shading and composit layers */ - if(shr->spec[0]<0.0f) shr->spec[0]= 0.0f; - if(shr->spec[1]<0.0f) shr->spec[1]= 0.0f; - if(shr->spec[2]<0.0f) shr->spec[2]= 0.0f; - - if(shr->diff[0]<0.0f) shr->diff[0]= 0.0f; - if(shr->diff[1]<0.0f) shr->diff[1]= 0.0f; - if(shr->diff[2]<0.0f) shr->diff[2]= 0.0f; - -// if(passflag==0) { - VECADD(shr->combined, shr->diff, shr->spec); -// } - - /* additional passes */ - QUATCOPY(shr->winspeed, shi.winspeed); - VECCOPY(shr->nor, shi.vn); - - /* NOTE: this is not correct here, sky from raytrace gets corrected... */ - /* exposure correction */ - if(R.wrld.exp!=0.0 || R.wrld.range!=1.0) { - if((shi.mat->mode & MA_SHLESS)==0) { - shr->combined[0]= R.wrld.linfac*(1.0-exp( shr->combined[0]*R.wrld.logfac) ); - shr->combined[1]= R.wrld.linfac*(1.0-exp( shr->combined[1]*R.wrld.logfac) ); - shr->combined[2]= R.wrld.linfac*(1.0-exp( shr->combined[2]*R.wrld.logfac) ); - } - } - - /* MIST */ - if((R.wrld.mode & WO_MIST) && (shi.mat->mode & MA_NOMIST)==0 ) { - if(R.r.mode & R_ORTHO) - alpha= mistfactor(-shi.co[2], shi.co); - else - alpha= mistfactor(zcor, shi.co); - } - else alpha= 1.0; - - if(shr->alpha!=1.0 || alpha!=1.0) { - if(shi.mat->mode & MA_RAYTRANSP) { - - shr->combined[3]= shr->alpha; - if(alpha!=1.0) { - /* sky is already included in tracing, no useful alpha here, so we blend in shaded color with sky */ - float col[4], malpha; - - shadeSkyPixelFloat(col, shi.co, shi.view, NULL); - malpha= 1.0f-alpha; - shr->combined[0]= alpha*shr->combined[0] + malpha*col[0]; - shr->combined[1]= alpha*shr->combined[1] + malpha*col[1]; - shr->combined[2]= alpha*shr->combined[2] + malpha*col[2]; - } - } - else { - fac= alpha*(shr->alpha); - shr->combined[3]= fac; - - shr->combined[0]*= fac; - shr->combined[1]*= fac; - shr->combined[2]*= fac; - } - } - else shr->combined[3]= 1.0; - } - - if(R.flag & R_LAMPHALO) { - if(shpi->layflag & SCE_LAY_HALO) { - - if(facenr<=0) { /* sky or env, calc view vector and put shi.co at far */ - if(R.r.mode & R_ORTHO) { - /* x and y 3d coordinate can be derived from pixel coord and winmat */ - float fx= 2.0/(R.rectx*R.winmat[0][0]); - float fy= 2.0/(R.recty*R.winmat[1][1]); - - shi.co[0]= (x - 0.5*R.rectx)*fx - R.winmat[3][0]/R.winmat[0][0]; - shi.co[1]= (y - 0.5*R.recty)*fy - R.winmat[3][1]/R.winmat[1][1]; - } - - calc_view_vector(shi.view, x, y); - shi.co[2]= 0.0; - - renderspothalo(&shi, shr->combined, 1.0); - } - else - renderspothalo(&shi, shr->combined, shr->combined[3]); - } - } - - return vlr; -} - -static void shadepixel_sky(ShadePixelInfo *shpi, float x, float y, int z, int facenr, int mask) -{ - VlakRen *vlr; - float collector[4], rco[3]; - - /* correction back for zbuffer filling in */ - x+= 0.5f; - y+= 0.5f; - - vlr= shadepixel(shpi, x, y, z, facenr, mask, rco); - if(shpi->shr.combined[3] != 1.0) { - - /* bail out when raytrace transparency (sky included already) */ - if(vlr && (R.r.mode & R_RAYTRACE)) - if(vlr->mat->mode & MA_RAYTRANSP) return; - - if(shpi->layflag & SCE_LAY_SKY) { - renderSkyPixelFloat(collector, x, y, vlr?rco:NULL); - addAlphaOverFloat(collector, shpi->shr.combined); - QUATCOPY(shpi->shr.combined, collector); - } - } -} - -/* adds only alpha values */ -static void edge_enhance_calc(RenderPart *pa, float *rectf) -{ - /* use zbuffer to define edges, add it to the image */ - int y, x, col, *rz, *rz1, *rz2, *rz3; - int zval1, zval2, zval3; - float *rf; - - /* shift values in zbuffer 4 to the right (anti overflows), for filter we need multiplying with 12 max */ - rz= pa->rectz; - if(rz==NULL) return; - - for(y=0; y<pa->recty; y++) - for(x=0; x<pa->rectx; x++, rz++) (*rz)>>= 4; - - rz1= pa->rectz; - rz2= rz1+pa->rectx; - rz3= rz2+pa->rectx; - - rf= rectf+pa->rectx+1; - - for(y=0; y<pa->recty-2; y++) { - for(x=0; x<pa->rectx-2; x++, rz1++, rz2++, rz3++, rf++) { - - /* prevent overflow with sky z values */ - zval1= rz1[0] + 2*rz1[1] + rz1[2]; - zval2= 2*rz2[0] + 2*rz2[2]; - zval3= rz3[0] + 2*rz3[1] + rz3[2]; - - col= abs ( 4*rz2[1] - (zval1 + zval2 + zval3)/3 ); - - col >>= 5; - if(col > (1<<16)) col= (1<<16); - else col= (R.r.edgeint*col)>>8; - - if(col>0) { - float fcol; - - if(col>255) fcol= 1.0f; - else fcol= (float)col/255.0f; - - if(R.osa) - *rf+= fcol/(float)R.osa; - else - *rf= fcol; - } - } - rz1+= 2; - rz2+= 2; - rz3+= 2; - rf+= 2; - } - - /* shift back zbuf values, we might need it still */ - rz= pa->rectz; - for(y=0; y<pa->recty; y++) - for(x=0; x<pa->rectx; x++, rz++) (*rz)<<= 4; - -} - -static void edge_enhance_add(RenderPart *pa, float *rectf, float *arect) -{ - float addcol[4]; - int pix; - - for(pix= pa->rectx*pa->recty; pix>0; pix--, arect++, rectf+=4) { - if(*arect != 0.0f) { - addcol[0]= *arect * R.r.edgeR; - addcol[1]= *arect * R.r.edgeG; - addcol[2]= *arect * R.r.edgeB; - addcol[3]= *arect; - addAlphaOverFloat(rectf, addcol); - } - } -} - /* ********************* MAINLOOPS ******************** */ @@ -2865,7 +364,7 @@ static void reset_sky_speedvectors(RenderPart *pa, RenderLayer *rl) } /* osa version */ -static void add_filt_passes(RenderLayer *rl, int curmask, int rectx, int offset, ShadeResult *shr) +static void add_filt_passes(RenderLayer *rl, int curmask, int rectx, int offset, ShadeInput *shi, ShadeResult *shr) { RenderPass *rpass; @@ -2879,7 +378,7 @@ static void add_filt_passes(RenderLayer *rl, int curmask, int rectx, int offset, pixsize= 4; break; case SCE_PASS_DIFFUSE: - col= shr->diff; + col= shr->diff_raw; break; case SCE_PASS_SPEC: col= shr->spec; @@ -2890,15 +389,25 @@ static void add_filt_passes(RenderLayer *rl, int curmask, int rectx, int offset, case SCE_PASS_AO: col= shr->ao; break; - case SCE_PASS_RAY: - col= shr->ray; + case SCE_PASS_REFLECT: + col= shr->refl; + break; + case SCE_PASS_REFRACT: + col= shr->refr; break; case SCE_PASS_NORMAL: col= shr->nor; break; + case SCE_PASS_INDEXOB: + /* no filter */ + if(shi->vlr) { + fp= rpass->rect + offset; + *fp= (float)shi->vlr->ob->index; + } + break; case SCE_PASS_VECTOR: { - /* add minimum speed in pixel */ + /* add minimum speed in pixel, no filter */ fp= rpass->rect + 4*offset; if( (ABS(shr->winspeed[0]) + ABS(shr->winspeed[1]))< (ABS(fp[0]) + ABS(fp[1])) ) { fp[0]= shr->winspeed[0]; @@ -2919,7 +428,7 @@ static void add_filt_passes(RenderLayer *rl, int curmask, int rectx, int offset, } /* non-osa version */ -static void add_passes(RenderLayer *rl, int offset, ShadeResult *shr) +static void add_passes(RenderLayer *rl, int offset, ShadeInput *shi, ShadeResult *shr) { RenderPass *rpass; @@ -2933,7 +442,7 @@ static void add_passes(RenderLayer *rl, int offset, ShadeResult *shr) pixsize= 4; break; case SCE_PASS_DIFFUSE: - col= shr->diff; + col= shr->diff_raw; break; case SCE_PASS_SPEC: col= shr->spec; @@ -2944,8 +453,11 @@ static void add_passes(RenderLayer *rl, int offset, ShadeResult *shr) case SCE_PASS_AO: col= shr->ao; break; - case SCE_PASS_RAY: - col= shr->ray; + case SCE_PASS_REFLECT: + col= shr->refl; + break; + case SCE_PASS_REFRACT: + col= shr->refr; break; case SCE_PASS_NORMAL: col= shr->nor; @@ -2954,6 +466,12 @@ static void add_passes(RenderLayer *rl, int offset, ShadeResult *shr) col= shr->winspeed; pixsize= 4; break; + case SCE_PASS_INDEXOB: + if(shi->vlr) { + fp= rpass->rect + offset; + *fp= (float)shi->vlr->ob->index; + } + break; } if(col) { fp= rpass->rect + pixsize*offset; @@ -2966,11 +484,24 @@ static void add_passes(RenderLayer *rl, int offset, ShadeResult *shr) /* only do sky, is default in the solid layer (shade_tile) btw */ static void sky_tile(RenderPart *pa, float *pass) { + float col[4]; int x, y; + if(R.r.alphamode!=R_ADDSKY) + return; + for(y=pa->disprect.ymin; y<pa->disprect.ymax; y++) { - for(x=pa->disprect.xmin; x<pa->disprect.xmax; x++, pass+=4) - renderSkyPixelFloat(pass, x, y, NULL); + for(x=pa->disprect.xmin; x<pa->disprect.xmax; x++, pass+=4) { + if(pass[3]<1.0f) { + if(pass[3]==0.0f) + shadeSkyPixel(pass, x, y); + else { + shadeSkyPixel(col, x, y); + addAlphaOverFloat(col, pass); + QUATCOPY(pass, col); + } + } + } if(y&1) if(R.test_break()) break; @@ -2980,13 +511,11 @@ static void sky_tile(RenderPart *pa, float *pass) static void shadeDA_tile(RenderPart *pa, RenderLayer *rl) { RenderResult *rr= pa->result; - ShadePixelInfo shpi; - PixStr *ps; - float xs, ys; - float *fcol= shpi.shr.combined, *rf, *rectf= rl->rectf; + ShadeSample ssamp; + float *fcol, *rf, *rectf= rl->rectf; long *rd, *rectdaps= pa->rectdaps; - int zbuf, samp, curmask, face, mask, fullmask; - int b, x, y, full_osa, seed, crop=0, offs=0, od, addpassflag; + int samp; + int x, y, seed, crop=0, offs=0, od, addpassflag; if(R.test_break()) return; @@ -2996,17 +525,9 @@ static void shadeDA_tile(RenderPart *pa, RenderLayer *rl) /* we set per pixel a fixed seed, for random AO and shadow samples */ seed= pa->rectx*pa->disprect.ymin; - - fullmask= (1<<R.osa)-1; - /* fill shadepixel info struct */ - shpi.thread= pa->thread; - shpi.lay= rl->lay; - shpi.layflag= rl->layflag; - shpi.passflag= 0; - - if(rl->passflag & ~(SCE_PASS_Z|SCE_PASS_NORMAL|SCE_PASS_VECTOR|SCE_PASS_COMBINED)) - shpi.passflag= rl->passflag; + /* general shader info, passes */ + shade_sample_initialize(&ssamp, pa, rl); addpassflag= rl->passflag & ~(SCE_PASS_Z|SCE_PASS_COMBINED); /* filtered render, for now we assume only 1 filter size */ @@ -3030,70 +551,17 @@ static void shadeDA_tile(RenderPart *pa, RenderLayer *rl) for(x=pa->disprect.xmin+crop; x<pa->disprect.xmax-crop; x++, rd++, rf+=4, od++) { BLI_thread_srandom(pa->thread, seed++); - ps= (PixStr *)(*rd); - mask= 0; - - /* complex loop, because empty spots are sky, without mask */ - while(TRUE) { - - if(ps==NULL) { - face= 0; - curmask= (~mask) & fullmask; - zbuf= 0x7FFFFFFF; - } - else { - face= ps->facenr; - curmask= ps->mask; - zbuf= ps->z; - } - - /* check osa level */ - if(face<=0) full_osa= 0; - else { - VlakRen *vlr= RE_findOrAddVlak(&R, (face-1) & RE_QUAD_MASK); - full_osa= (vlr->flag & R_FULL_OSA); - } - - if(full_osa) { - for(samp=0; samp<R.osa; samp++) { - if(curmask & (1<<samp)) { - xs= (float)x + R.jit[samp][0]; - ys= (float)y + R.jit[samp][1]; - shadepixel_sky(&shpi, xs, ys, zbuf, face, (1<<samp)); - - if(R.do_gamma) { - fcol[0]= gammaCorrect(fcol[0]); - fcol[1]= gammaCorrect(fcol[1]); - fcol[2]= gammaCorrect(fcol[2]); - } - add_filt_fmask(1<<samp, fcol, rf, pa->rectx); - - if(addpassflag) - add_filt_passes(rl, 1<<samp, pa->rectx, od, &shpi.shr); - } - } - } - else if(curmask) { - b= R.samples->centmask[curmask]; - xs= (float)x+R.samples->centLut[b & 15]; - ys= (float)y+R.samples->centLut[b>>4]; - shadepixel_sky(&shpi, xs, ys, zbuf, face, curmask); - - if(R.do_gamma) { - fcol[0]= gammaCorrect(fcol[0]); - fcol[1]= gammaCorrect(fcol[1]); - fcol[2]= gammaCorrect(fcol[2]); + if(*rd) { + if(shade_samples(&ssamp, (PixStr *)(*rd), x, y)) { + for(samp=0; samp<ssamp.tot; samp++) { + + fcol= ssamp.shr[samp].combined; + add_filt_fmask(ssamp.shi[samp].mask, fcol, rf, pa->rectx); + + if(addpassflag) + add_filt_passes(rl, ssamp.shi[samp].mask, pa->rectx, od, ssamp.shi, &ssamp.shr[samp]); } - add_filt_fmask(curmask, fcol, rf, pa->rectx); - - if(addpassflag) - add_filt_passes(rl, curmask, pa->rectx, od, &shpi.shr); } - - mask |= curmask; - - if(ps==NULL) break; - else ps= ps->next; } } @@ -3107,15 +575,6 @@ static void shadeDA_tile(RenderPart *pa, RenderLayer *rl) /* disable scanline updating */ rr->renlay= NULL; - if(R.do_gamma) { - rectf= rl->rectf; - for(y= pa->rectx*pa->recty; y>0; y--, rectf+=4) { - rectf[0] = invGammaCorrect(rectf[0]); - rectf[1] = invGammaCorrect(rectf[1]); - rectf[2] = invGammaCorrect(rectf[2]); - } - } - if(R.r.mode & R_SHADOW) ISB_free(pa); } @@ -3202,6 +661,26 @@ static void make_pixelstructs(RenderPart *pa, ListBase *lb) } } +static void edge_enhance_add(RenderPart *pa, float *rectf, float *arect) +{ + float addcol[4]; + int pix; + + if(arect==NULL) + return; + + for(pix= pa->rectx*pa->recty; pix>0; pix--, arect++, rectf+=4) { + if(*arect != 0.0f) { + addcol[0]= *arect * R.r.edgeR; + addcol[1]= *arect * R.r.edgeG; + addcol[2]= *arect * R.r.edgeB; + addcol[3]= *arect; + addAlphaOverFloat(rectf, addcol); + } + } +} + + static void convert_to_key_alpha(RenderPart *pa, float *rectf) { int y; @@ -3216,6 +695,126 @@ static void convert_to_key_alpha(RenderPart *pa, float *rectf) } } +/* adds only alpha values */ +static void edge_enhance_tile(RenderPart *pa, float *rectf) +{ + /* use zbuffer to define edges, add it to the image */ + int y, x, col, *rz, *rz1, *rz2, *rz3; + int zval1, zval2, zval3; + float *rf; + + /* shift values in zbuffer 4 to the right (anti overflows), for filter we need multiplying with 12 max */ + rz= pa->rectz; + if(rz==NULL) return; + + for(y=0; y<pa->recty; y++) + for(x=0; x<pa->rectx; x++, rz++) (*rz)>>= 4; + + rz1= pa->rectz; + rz2= rz1+pa->rectx; + rz3= rz2+pa->rectx; + + rf= rectf+pa->rectx+1; + + for(y=0; y<pa->recty-2; y++) { + for(x=0; x<pa->rectx-2; x++, rz1++, rz2++, rz3++, rf++) { + + /* prevent overflow with sky z values */ + zval1= rz1[0] + 2*rz1[1] + rz1[2]; + zval2= 2*rz2[0] + 2*rz2[2]; + zval3= rz3[0] + 2*rz3[1] + rz3[2]; + + col= ( 4*rz2[1] - (zval1 + zval2 + zval3)/3 ); + if(col<0) col= -col; + + col >>= 5; + if(col > (1<<16)) col= (1<<16); + else col= (R.r.edgeint*col)>>8; + + if(col>0) { + float fcol; + + if(col>255) fcol= 1.0f; + else fcol= (float)col/255.0f; + + if(R.osa) + *rf+= fcol/(float)R.osa; + else + *rf= fcol; + } + } + rz1+= 2; + rz2+= 2; + rz3+= 2; + rf+= 2; + } + + /* shift back zbuf values, we might need it still */ + rz= pa->rectz; + for(y=0; y<pa->recty; y++) + for(x=0; x<pa->rectx; x++, rz++) (*rz)<<= 4; + +} + +static unsigned short *make_solid_mask(RenderPart *pa) +{ + long *rd= pa->rectdaps; + short *solidmask, *sp; + int x; + + if(rd==NULL) return NULL; + + sp=solidmask= MEM_mallocN(sizeof(short)*pa->rectx*pa->recty, "solidmask"); + + for(x=pa->rectx*pa->recty; x>0; x--, rd++, sp++) { + if(*rd) { + PixStr *ps= (PixStr *)*rd; + + *sp= ps->mask; + for(ps= ps->next; ps; ps= ps->next) + *sp |= ps->mask; + } + else + *sp= 0; + } + + return solidmask; +} + +static void addAlphaOverFloatMask(float *dest, float *source, unsigned short dmask, unsigned short smask) +{ + unsigned short shared= dmask & smask; + float mul= 1.0 - source[3]; + + if(shared) { /* overlapping masks */ + + /* masks differ, we make a mixture of 'add' and 'over' */ + if(shared!=dmask) { + float shared_bits= (float)count_mask(shared); /* alpha over */ + float tot_bits= (float)count_mask(smask|dmask); /* alpha add */ + + float add= (tot_bits - shared_bits)/tot_bits; /* add level */ + mul= add + (1.0f-add)*mul; + } + } + else if(dmask && smask) { + /* works for premul only, of course */ + dest[0]+= source[0]; + dest[1]+= source[1]; + dest[2]+= source[2]; + dest[3]+= source[3]; + + return; + } + + dest[0]= (mul*dest[0]) + source[0]; + dest[1]= (mul*dest[1]) + source[1]; + dest[2]= (mul*dest[2]) + source[2]; + dest[3]= (mul*dest[3]) + source[3]; +} + + +/* main call for shading Delta Accum, for OSA */ /* supposed to be fully threadable! */ void zbufshadeDA_tile(RenderPart *pa) { @@ -3236,7 +835,10 @@ void zbufshadeDA_tile(RenderPart *pa) /* initialize pixelstructs and edge buffer */ addpsmain(&psmlist); pa->rectdaps= MEM_callocN(sizeof(long)*pa->rectx*pa->recty+4, "zbufDArectd"); - if(R.r.mode & R_EDGE) edgerect= MEM_callocN(sizeof(float)*pa->rectx*pa->recty, "rectedge"); + + if(rl->layflag & SCE_LAY_EDGE) + if(R.r.mode & R_EDGE) + edgerect= MEM_callocN(sizeof(float)*pa->rectx*pa->recty, "rectedge"); /* always fill visibility */ for(pa->sample=0; pa->sample<R.osa; pa->sample++) { @@ -3245,7 +847,7 @@ void zbufshadeDA_tile(RenderPart *pa) if(rl->layflag & SCE_LAY_EDGE) if(R.r.mode & R_EDGE) - edge_enhance_calc(pa, edgerect); + edge_enhance_tile(pa, edgerect); if(R.test_break()) break; } @@ -3253,14 +855,11 @@ void zbufshadeDA_tile(RenderPart *pa) /* shades solid */ if(rl->layflag & SCE_LAY_SOLID) shadeDA_tile(pa, rl); - else if(rl->layflag & SCE_LAY_SKY) - sky_tile(pa, rl->rectf); /* lamphalo after solid, before ztra, looks nicest because ztra does own halo */ if(R.flag & R_LAMPHALO) if(rl->layflag & SCE_LAY_HALO) - if(!(rl->layflag & SCE_LAY_SOLID)) - lamphalo_tile(pa, rl->rectf, rl->lay); + lamphalo_tile(pa, rl->rectf, rl->lay); /* halo before ztra, because ztra fills in zbuffer now */ if(R.flag & R_HALO) @@ -3270,8 +869,7 @@ void zbufshadeDA_tile(RenderPart *pa) /* transp layer */ if(R.flag & R_ZTRA) { if(rl->layflag & SCE_LAY_ZTRA) { - float *fcol, *acol; - int x; + unsigned short *ztramask, *solidmask= NULL; /* 16 bits, MAX_OSA */ /* allocate, but not free here, for asynchronous display of this rect in main thread */ rl->acolrect= MEM_callocN(4*sizeof(float)*pa->rectx*pa->recty, "alpha layer"); @@ -3282,16 +880,35 @@ void zbufshadeDA_tile(RenderPart *pa) /* swap for live updates */ SWAP(float *, rl->acolrect, rl->rectf); - zbuffer_transp_shade(pa, rl, rl->rectf); + ztramask= zbuffer_transp_shade(pa, rl, rl->rectf); SWAP(float *, rl->acolrect, rl->rectf); - fcol= rl->rectf; acol= rl->acolrect; - for(x=pa->rectx*pa->recty; x>0; x--, acol+=4, fcol+=4) { - addAlphaOverFloat(fcol, acol); + /* zbuffer transp only returns ztramask if there's solid rendered */ + if(ztramask) + solidmask= make_solid_mask(pa); + + if(ztramask && solidmask) { + unsigned short *sps= solidmask, *spz= ztramask; + float *fcol= rl->rectf; float *acol= rl->acolrect; + int x; + for(x=pa->rectx*pa->recty; x>0; x--, acol+=4, fcol+=4, sps++, spz++) + addAlphaOverFloatMask(fcol, acol, *sps, *spz); + } + else { + float *fcol= rl->rectf; float *acol= rl->acolrect; + int x; + for(x=pa->rectx*pa->recty; x>0; x--, acol+=4, fcol+=4) { + addAlphaOverFloat(fcol, acol); + } } + if(solidmask) MEM_freeN(solidmask); + if(ztramask) MEM_freeN(ztramask); } } - + /* sky before edge */ + if(rl->layflag & SCE_LAY_SKY) + sky_tile(pa, rl->rectf); + /* extra layers */ if(rl->layflag & SCE_LAY_EDGE) if(R.r.mode & R_EDGE) @@ -3325,34 +942,31 @@ void zbufshadeDA_tile(RenderPart *pa) /* ------------------------------------------------------------------------ */ +/* non OSA case, full tile render */ /* supposed to be fully threadable! */ void zbufshade_tile(RenderPart *pa) { - ShadePixelInfo shpi; + ShadeSample ssamp; RenderResult *rr= pa->result; RenderLayer *rl; + PixStr ps; float *edgerect= NULL; int addpassflag; + /* fake pixel struct, to comply to osa render */ + ps.next= NULL; + ps.mask= 0xFFFF; + set_part_zbuf_clipflag(pa); /* zbuffer code clears/inits rects */ pa->rectp= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectp"); pa->rectz= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectz"); - shpi.thread= pa->thread; - for(rl= rr->layers.first; rl; rl= rl->next) { - if(R.r.mode & R_EDGE) edgerect= MEM_callocN(sizeof(float)*pa->rectx*pa->recty, "rectedge"); - - /* fill shadepixel info struct */ - shpi.lay= rl->lay; - shpi.layflag= rl->layflag; - shpi.passflag= 0; - - if(rl->passflag & ~(SCE_PASS_Z|SCE_PASS_NORMAL|SCE_PASS_VECTOR|SCE_PASS_COMBINED)) - shpi.passflag= rl->passflag; + /* general shader info, passes */ + shade_sample_initialize(&ssamp, pa, rl); addpassflag= rl->passflag & ~(SCE_PASS_Z|SCE_PASS_COMBINED); zbuffer_solid(pa, rl->lay, rl->layflag); @@ -3360,9 +974,12 @@ void zbufshade_tile(RenderPart *pa) if(!R.test_break()) { /* NOTE: this if() is not consistant */ /* edges only for solid part, ztransp doesn't support it yet anti-aliased */ - if(rl->layflag & SCE_LAY_EDGE) - if(R.r.mode & R_EDGE) - edge_enhance_calc(pa, edgerect); + if(rl->layflag & SCE_LAY_EDGE) { + if(R.r.mode & R_EDGE) { + edgerect= MEM_callocN(sizeof(float)*pa->rectx*pa->recty, "rectedge"); + edge_enhance_tile(pa, edgerect); + } + } /* initialize scanline updates for main thread */ rr->renrect.ymin= 0; @@ -3381,14 +998,20 @@ void zbufshade_tile(RenderPart *pa) for(y=pa->disprect.ymin; y<pa->disprect.ymax; y++, rr->renrect.ymax++) { for(x=pa->disprect.xmin; x<pa->disprect.xmax; x++, rz++, rp++, fcol+=4, offs++) { + /* per pixel fixed seed */ BLI_thread_srandom(pa->thread, seed++); - shadepixel_sky(&shpi, (float)x, (float)y, *rz, *rp, 0); - QUATCOPY(fcol, shpi.shr.combined); - - /* passes */ - if(addpassflag) - add_passes(rl, offs, &shpi.shr); + if(*rp) { + ps.facenr= *rp; + ps.z= *rz; + if(shade_samples(&ssamp, &ps, x, y)) { + QUATCOPY(fcol, ssamp.shr[0].combined); + + /* passes */ + if(addpassflag) + add_passes(rl, offs, ssamp.shi, ssamp.shr); + } + } } if(y&1) if(R.test_break()) break; @@ -3397,9 +1020,6 @@ void zbufshade_tile(RenderPart *pa) if(R.r.mode & R_SHADOW) ISB_free(pa); } - else if(rl->layflag & SCE_LAY_SKY) { - sky_tile(pa, rl->rectf); - } /* disable scanline updating */ rr->renlay= NULL; @@ -3408,14 +1028,13 @@ void zbufshade_tile(RenderPart *pa) /* lamphalo after solid, before ztra, looks nicest because ztra does own halo */ if(R.flag & R_LAMPHALO) if(rl->layflag & SCE_LAY_HALO) - if(!(rl->layflag & SCE_LAY_SOLID)) lamphalo_tile(pa, rl->rectf, rl->lay); + /* halo before ztra, because ztra fills in zbuffer now */ if(R.flag & R_HALO) if(rl->layflag & SCE_LAY_HALO) halo_tile(pa, rl->rectf, rl->lay); - if(R.flag & R_ZTRA) { if(rl->layflag & SCE_LAY_ZTRA) { float *fcol, *acol; @@ -3440,6 +1059,10 @@ void zbufshade_tile(RenderPart *pa) } } + /* sky before edge */ + if(rl->layflag & SCE_LAY_SKY) + sky_tile(pa, rl->rectf); + if(!R.test_break()) { if(rl->layflag & SCE_LAY_EDGE) if(R.r.mode & R_EDGE) @@ -3541,7 +1164,7 @@ static void renderflare(RenderResult *rr, float *rectf, HaloRen *har) alfa= har->alfa; visifac= R.ycor*(har->pixels); - /* all radials added / r^3 == 1.0! */ + /* all radials added / r^3 == 1.0f! */ visifac /= (har->rad*har->rad*har->rad); visifac*= visifac; @@ -3566,15 +1189,15 @@ static void renderflare(RenderResult *rr, float *rectf, HaloRen *har) fla.g= fabs(rc[1]); fla.b= fabs(rc[2]); fla.alfa= ma->flareboost*fabs(alfa*visifac*rc[3]); - fla.hard= 20.0 + fabs(70*rc[7]); + fla.hard= 20.0f + fabs(70*rc[7]); fla.tex= 0; type= (int)(fabs(3.9*rc[6])); - fla.rad= ma->subsize*sqrt(fabs(2.0*har->rad*rc[4])); + fla.rad= ma->subsize*sqrt(fabs(2.0f*har->rad*rc[4])); if(type==3) { - fla.rad*= 3.0; + fla.rad*= 3.0f; fla.rad+= R.rectx/10; } @@ -3582,7 +1205,7 @@ static void renderflare(RenderResult *rr, float *rectf, HaloRen *har) vec[0]= 1.4*rc[5]*(har->xs-R.winx/2); vec[1]= 1.4*rc[5]*(har->ys-R.winy/2); - vec[2]= 32.0*sqrt(vec[0]*vec[0] + vec[1]*vec[1] + 1.0); + vec[2]= 32.0f*sqrt(vec[0]*vec[0] + vec[1]*vec[1] + 1.0f); fla.xs= R.winx/2 + vec[0] + (1.2+rc[8])*R.rectx*vec[0]/vec[2]; fla.ys= R.winy/2 + vec[1] + (1.2+rc[8])*R.rectx*vec[1]/vec[2]; @@ -3676,7 +1299,7 @@ void RE_shade_external(Render *re, ShadeInput *shi, ShadeResult *shr) #define FTOCHAR(val) val<=0.0f?0: (val>=1.0f?255: (char)(255.0f*val)) typedef struct BakeShade { - ShadeInput shi; + ShadeSample ssamp; VlakRen *vlr; ZSpan *zspan; @@ -3691,7 +1314,8 @@ typedef struct BakeShade { static void do_bake_shade(void *handle, int x, int y, float u, float v) { BakeShade *bs= handle; - ShadeInput *shi= &bs->shi; + ShadeSample *ssamp= &bs->ssamp; + ShadeInput *shi= ssamp->shi; ShadeResult shr; VlakRen *vlr= bs->vlr; float l, *v1, *v2, *v3; @@ -3700,11 +1324,7 @@ static void do_bake_shade(void *handle, int x, int y, float u, float v) if(R.test_break()) return; - shi->xs= x; - shi->ys= y; - - /* setup render coordinates, it's a copy of shade_ray mostly, but different. - like for shadepixel, useful to restructure once. */ + /* setup render coordinates */ if(bs->quad) { v1= vlr->v1->co; v2= vlr->v3->co; @@ -3717,7 +1337,7 @@ static void do_bake_shade(void *handle, int x, int y, float u, float v) } /* renderco */ - l= 1.0-u-v; + l= 1.0f-u-v; shi->co[0]= l*v3[0]+u*v1[0]+v*v2[0]; shi->co[1]= l*v3[1]+u*v1[1]+v*v2[1]; @@ -3727,26 +1347,36 @@ static void do_bake_shade(void *handle, int x, int y, float u, float v) VECCOPY(shi->view, shi->co); Normalise(shi->view); - shi->vlr= vlr; - shi->mat= vlr->mat; - memcpy(&shi->r, &shi->mat->r, 23*sizeof(float)); // note, keep this synced with render_types.h - shi->har= shi->mat->har; - /* no face normal flip */ - VECCOPY(shi->facenor, vlr->n); shi->puno= 0; - + if(bs->quad) - shade_input_set_coords(shi, -u, -v, 0, 2, 3); + shade_input_set_triangle_i(shi, vlr, 0, 2, 3); else - shade_input_set_coords(shi, -u, -v, 0, 1, 2); + shade_input_set_triangle_i(shi, vlr, 0, 1, 2); + + shi->u= -u; + shi->v= -v; + shi->xs= x; + shi->ys= y; + + shade_input_set_normals(shi); + + /* init material vars */ + memcpy(&shi->r, &shi->mat->r, 23*sizeof(float)); // note, keep this synced with render_types.h + shi->har= shi->mat->har; if(bs->type==RE_BAKE_AO) { - shr.ao[0]= shr.ao[1]= shr.ao[2]= 0.0f; - ambient_occlusion(shi, &shr); - VECCOPY(shr.diff, shr.ao); + ambient_occlusion(shi); + ambient_occlusion_to_diffuse(shi, shr.diff); } else { + + shade_input_set_shade_texco(shi); + + if(R.r.mode & R_SHADOW) + shade_samples_do_shadow(ssamp); + if(shi->mat->nodetree && shi->mat->use_nodes) { ntreeShaderExecTree(shi->mat->nodetree, shi, &shr); shi->mat= vlr->mat; /* shi->mat is being set in nodetree */ @@ -3924,7 +1554,11 @@ int RE_bake_shade_all_selected(Render *re, int type) for(a=0; a<re->r.threads; a++) { /* set defaults in handles */ memset(&handles[a], 0, sizeof(BakeShade)); - handles[a].shi.lay= re->scene->lay; + + handles[a].ssamp.shi[0].lay= re->scene->lay; + handles[a].ssamp.shi[0].passflag= SCE_PASS_COMBINED; + handles[a].ssamp.shi[0].thread= a; + handles[a].type= type; handles[a].zspan= MEM_callocN(sizeof(ZSpan), "zspan for bake"); diff --git a/source/blender/render/intern/source/shadeinput.c b/source/blender/render/intern/source/shadeinput.c new file mode 100644 index 00000000000..9ee88167c3e --- /dev/null +++ b/source/blender/render/intern/source/shadeinput.c @@ -0,0 +1,999 @@ +/** +* $Id: + * + * ***** BEGIN GPL 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. + * + * 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) 2006 Blender Foundation + * All rights reserved. + * + * Contributors: Hos, Robert Wenzlaff. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <stdio.h> +#include <math.h> +#include <string.h> + +#include "MTC_matrixops.h" +#include "BLI_arithb.h" + +#include "DNA_group_types.h" +#include "DNA_lamp_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_material_types.h" + +#include "BKE_utildefines.h" +#include "BKE_node.h" + +/* local include */ +#include "renderpipeline.h" +#include "render_types.h" +#include "renderdatabase.h" +#include "rendercore.h" +#include "shadbuf.h" +#include "shading.h" +#include "texture.h" + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */ +/* only to be used here in this file, it's for speed */ +extern struct Render R; +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + + +#define VECADDISFAC(v1,v3,fac) {*(v1)+= *(v3)*(fac); *(v1+1)+= *(v3+1)*(fac); *(v1+2)+= *(v3+2)*(fac);} + + + +/* Shade Sample order: + +- shade_samples_fill_with_ps() + - for each sample + - shade_input_set_triangle() <- if prev sample-face is same, use shade_input_copy_triangle() + - if vlr + - shade_input_set_viewco() <- not for ray or bake + - shade_input_set_uv() <- not for ray or bake + - shade_input_set_normals() +- shade_samples() + - if shadow or AO + - shade_samples_do_shadow() + - if shading happens + - for each sample + - shade_input_set_shade_texco() + - shade_samples_do_shade() +- OSA: distribute sample result with filter masking + + */ + + +/* also used as callback for nodes */ +/* delivers a fully filled in ShadeResult, for all passes */ +void shade_material_loop(ShadeInput *shi, ShadeResult *shr) +{ + + shade_lamp_loop(shi, shr); /* clears shr */ + + if(shi->translucency!=0.0f) { + ShadeResult shr_t; + float fac= shi->translucency; + + /* gotta copy it again */ + memcpy(&shi->r, &shi->mat->r, 23*sizeof(float)); + shi->har= shi->mat->har; + + VECCOPY(shi->vn, shi->vno); + VECMUL(shi->vn, -1.0f); + VECMUL(shi->facenor, -1.0f); + shi->depth++; /* hack to get real shadow now */ + shade_lamp_loop(shi, &shr_t); + shi->depth--; + + /* a couple of passes */ + VECADDISFAC(shr->combined, shr_t.combined, fac); + if(shi->passflag & SCE_PASS_SPEC) + VECADDISFAC(shr->spec, shr_t.spec, fac); + if(shi->passflag & SCE_PASS_DIFFUSE) + VECADDISFAC(shr->diff_raw, shr_t.diff_raw, fac); + if(shi->passflag & SCE_PASS_SHADOW) + VECADDISFAC(shr->shad, shr_t.shad, fac); + + VECMUL(shi->vn, -1.0f); + VECMUL(shi->facenor, -1.0f); + } + + /* depth >= 1 when ray-shading */ + if(shi->depth==0) { + if(R.r.mode & R_RAYTRACE) { + if(shi->ray_mirror!=0.0f || ((shi->mat->mode & MA_RAYTRANSP) && shr->alpha!=1.0f)) { + + /* ray trace works on combined, but gives pass info */ + ray_trace(shi, shr); + } + } + /* disable adding of sky for raytransp */ + if(shi->mat->mode & MA_RAYTRANSP) + if(shi->layflag & SCE_LAY_SKY) + shr->alpha= 1.0f; + } +} + + +/* do a shade, finish up some passes, apply mist */ +void shade_input_do_shade(ShadeInput *shi, ShadeResult *shr) +{ + float alpha; + + /* ------ main shading loop -------- */ + + if(shi->mat->nodetree && shi->mat->use_nodes) { + ntreeShaderExecTree(shi->mat->nodetree, shi, shr); + } + else { + /* copy all relevant material vars, note, keep this synced with render_types.h */ + memcpy(&shi->r, &shi->mat->r, 23*sizeof(float)); + shi->har= shi->mat->har; + + shade_material_loop(shi, shr); + } + + /* additional passes */ + QUATCOPY(shr->winspeed, shi->winspeed); + VECCOPY(shr->nor, shi->vn); + + /* MIST */ + if((R.wrld.mode & WO_MIST) && (shi->mat->mode & MA_NOMIST)==0 ) { + if(R.r.mode & R_ORTHO) + alpha= mistfactor(-shi->co[2], shi->co); + else + alpha= mistfactor(VecLength(shi->co), shi->co); + } + else alpha= 1.0f; + + /* add mist and premul color */ + if(shr->alpha!=1.0f || alpha!=1.0f) { + float fac= alpha*(shr->alpha); + + shr->combined[3]= fac; + shr->combined[0]*= fac; + shr->combined[1]*= fac; + shr->combined[2]*= fac; + } + else shr->combined[3]= 1.0f; + +} + +/* **************************************************************************** */ +/* ShadeInput */ +/* **************************************************************************** */ + + +void vlr_set_uv_indices(VlakRen *vlr, int *i1, int *i2, int *i3) +{ + /* to prevent storing new tfaces or vcols, we check a split runtime */ + /* 4---3 4---3 */ + /* |\ 1| or |1 /| */ + /* |0\ | |/ 0| */ + /* 1---2 1---2 0 = orig face, 1 = new face */ + + /* Update vert nums to point to correct verts of original face */ + if(vlr->flag & R_DIVIDE_24) { + if(vlr->flag & R_FACE_SPLIT) { + (*i1)++; (*i2)++; (*i3)++; + } + else { + (*i3)++; + } + } + else if(vlr->flag & R_FACE_SPLIT) { + (*i2)++; (*i3)++; + } +} + + +/* copy data from face to ShadeInput, general case */ +/* indices 0 1 2 3 only. shi->puno should be set! */ +void shade_input_set_triangle_i(ShadeInput *shi, VlakRen *vlr, short i1, short i2, short i3) +{ + VertRen **vpp= &vlr->v1; + + shi->vlr= vlr; + + shi->v1= vpp[i1]; + shi->v2= vpp[i2]; + shi->v3= vpp[i3]; + + shi->i1= i1; + shi->i2= i2; + shi->i3= i3; + + shi->mat= vlr->mat; + shi->osatex= (shi->mat->texco & TEXCO_OSA); + + /* calculate vertexnormals */ + if(vlr->flag & R_SMOOTH) { + float *n1= shi->v1->n, *n2= shi->v2->n, *n3= shi->v3->n; + char p1, p2, p3; + + p1= 1<<i1; + p2= 1<<i2; + p3= 1<<i3; + + if(shi->puno & p1) { + shi->n1[0]= -n1[0]; shi->n1[1]= -n1[1]; shi->n1[2]= -n1[2]; + } else { + VECCOPY(shi->n1, n1); + } + if(shi->puno & p2) { + shi->n2[0]= -n2[0]; shi->n2[1]= -n2[1]; shi->n2[2]= -n2[2]; + } else { + VECCOPY(shi->n2, n2); + } + if(shi->puno & p3) { + shi->n3[0]= -n3[0]; shi->n3[1]= -n3[1]; shi->n3[2]= -n3[2]; + } else { + VECCOPY(shi->n3, n3); + } + } + /* facenormal copy, can get flipped */ + VECCOPY(shi->facenor, vlr->n); + +} + +/* note, facenr declared volatile due to over-eager -O2 optimizations + * on cygwin (particularly -frerun-cse-after-loop) + */ + +/* copy data from face to ShadeInput, scanline case */ +void shade_input_set_triangle(ShadeInput *shi, volatile int facenr, int normal_flip) +{ + if(facenr>0) { + shi->facenr= (facenr-1) & RE_QUAD_MASK; + if( shi->facenr < R.totvlak ) { + VlakRen *vlr= RE_findOrAddVlak(&R, shi->facenr); + + shi->puno= normal_flip?vlr->puno:0; + + if(facenr & RE_QUAD_OFFS) + shade_input_set_triangle_i(shi, vlr, 0, 2, 3); + else + shade_input_set_triangle_i(shi, vlr, 0, 1, 2); + } + else + shi->vlr= NULL; /* general signal we got sky */ + } + else + shi->vlr= NULL; /* general signal we got sky */ + +} + +/* full osa case: copy static info */ +void shade_input_copy_triangle(ShadeInput *shi, ShadeInput *from) +{ + /* not so nice, but works... warning is in RE_shader_ext.h */ + memcpy(shi, from, sizeof(struct ShadeInputCopy)); +} + + +/* scanline pixel coordinates */ +/* requires set_triangle */ +void shade_input_set_viewco(ShadeInput *shi, float x, float y, float z) +{ + float fac; + + /* currently in use for dithering (soft shadow), node preview, irregular shad */ + shi->xs= (int)(x); + shi->ys= (int)(y); + + calc_view_vector(shi->view, x, y); /* returns not normalized, so is in viewplane coords */ + + /* wire cannot use normal for calculating shi->co */ + if(shi->mat->mode & MA_WIRE) { + + if(R.r.mode & R_ORTHO) + calc_renderco_ortho(shi->co, x, y, z); + else + calc_renderco_zbuf(shi->co, shi->view, z); + } + else { + float dface, *v1= shi->v1->co; + + dface= v1[0]*shi->facenor[0]+v1[1]*shi->facenor[1]+v1[2]*shi->facenor[2]; + + /* ortho viewplane cannot intersect using view vector originating in (0,0,0) */ + if(R.r.mode & R_ORTHO) { + /* x and y 3d coordinate can be derived from pixel coord and winmat */ + float fx= 2.0f/(R.winx*R.winmat[0][0]); + float fy= 2.0f/(R.winy*R.winmat[1][1]); + + shi->co[0]= (x - 0.5f*R.winx)*fx - R.winmat[3][0]/R.winmat[0][0]; + shi->co[1]= (y - 0.5f*R.winy)*fy - R.winmat[3][1]/R.winmat[1][1]; + + /* using a*x + b*y + c*z = d equation, (a b c) is normal */ + if(shi->facenor[2]!=0.0f) + shi->co[2]= (dface - shi->facenor[0]*shi->co[0] - shi->facenor[1]*shi->co[1])/shi->facenor[2]; + else + shi->co[2]= 0.0f; + + if(shi->osatex || (R.r.mode & R_SHADOW) ) { + shi->dxco[0]= fx; + shi->dxco[1]= 0.0f; + if(shi->facenor[2]!=0.0f) + shi->dxco[2]= (shi->facenor[0]*fx)/shi->facenor[2]; + else + shi->dxco[2]= 0.0f; + + shi->dyco[0]= 0.0f; + shi->dyco[1]= fy; + if(shi->facenor[2]!=0.0f) + shi->dyco[2]= (shi->facenor[1]*fy)/shi->facenor[2]; + else + shi->dyco[2]= 0.0f; + + if( (shi->mat->texco & TEXCO_REFL) ) { + if(shi->co[2]!=0.0f) fac= 1.0f/shi->co[2]; else fac= 0.0f; + shi->dxview= -R.viewdx*fac; + shi->dyview= -R.viewdy*fac; + } + } + } + else { + float div; + + div= shi->facenor[0]*shi->view[0] + shi->facenor[1]*shi->view[1] + shi->facenor[2]*shi->view[2]; + if (div!=0.0f) fac= dface/div; + else fac= 0.0f; + + shi->co[0]= fac*shi->view[0]; + shi->co[1]= fac*shi->view[1]; + shi->co[2]= fac*shi->view[2]; + + /* pixel dx/dy for render coord */ + if(shi->osatex || (R.r.mode & R_SHADOW) ) { + float u= dface/(div - R.viewdx*shi->facenor[0]); + float v= dface/(div - R.viewdy*shi->facenor[1]); + + shi->dxco[0]= shi->co[0]- (shi->view[0]-R.viewdx)*u; + shi->dxco[1]= shi->co[1]- (shi->view[1])*u; + shi->dxco[2]= shi->co[2]- (shi->view[2])*u; + + shi->dyco[0]= shi->co[0]- (shi->view[0])*v; + shi->dyco[1]= shi->co[1]- (shi->view[1]-R.viewdy)*v; + shi->dyco[2]= shi->co[2]- (shi->view[2])*v; + + if( (shi->mat->texco & TEXCO_REFL) ) { + if(fac!=0.0f) fac= 1.0f/fac; + shi->dxview= -R.viewdx*fac; + shi->dyview= -R.viewdy*fac; + } + } + } + } + + /* cannot normalise earlier, code above needs it at viewplane level */ + Normalise(shi->view); +} + +/* calculate U and V, for scanline (silly render face u and v are in range -1 to 0) */ +void shade_input_set_uv(ShadeInput *shi) +{ + VlakRen *vlr= shi->vlr; + + if( (vlr->flag & R_SMOOTH) || (shi->mat->texco & NEED_UV) ) { + float *v1= shi->v1->co, *v2= shi->v2->co, *v3= shi->v3->co; + + /* exception case for wire render of edge */ + if(vlr->v2==vlr->v3) { + float lend, lenc; + + lend= VecLenf(v2, v1); + lenc= VecLenf(shi->co, v1); + + if(lend==0.0f) { + shi->u=shi->v= 0.0f; + } + else { + shi->u= - (1.0f - lenc/lend); + shi->v= 0.0f; + } + + if(shi->osatex) { + shi->dx_u= 0.0f; + shi->dx_v= 0.0f; + shi->dy_u= 0.0f; + shi->dy_v= 0.0f; + } + } + else { + /* most of this could become re-used for faces */ + float detsh, t00, t10, t01, t11; + + if(vlr->snproj==0) { + t00= v3[0]-v1[0]; t01= v3[1]-v1[1]; + t10= v3[0]-v2[0]; t11= v3[1]-v2[1]; + } + else if(vlr->snproj==1) { + t00= v3[0]-v1[0]; t01= v3[2]-v1[2]; + t10= v3[0]-v2[0]; t11= v3[2]-v2[2]; + } + else { + t00= v3[1]-v1[1]; t01= v3[2]-v1[2]; + t10= v3[1]-v2[1]; t11= v3[2]-v2[2]; + } + + detsh= 1.0f/(t00*t11-t10*t01); + t00*= detsh; t01*=detsh; + t10*=detsh; t11*=detsh; + + if(vlr->snproj==0) { + shi->u= (shi->co[0]-v3[0])*t11-(shi->co[1]-v3[1])*t10; + shi->v= (shi->co[1]-v3[1])*t00-(shi->co[0]-v3[0])*t01; + if(shi->osatex) { + shi->dx_u= shi->dxco[0]*t11- shi->dxco[1]*t10; + shi->dx_v= shi->dxco[1]*t00- shi->dxco[0]*t01; + shi->dy_u= shi->dyco[0]*t11- shi->dyco[1]*t10; + shi->dy_v= shi->dyco[1]*t00- shi->dyco[0]*t01; + } + } + else if(vlr->snproj==1) { + shi->u= (shi->co[0]-v3[0])*t11-(shi->co[2]-v3[2])*t10; + shi->v= (shi->co[2]-v3[2])*t00-(shi->co[0]-v3[0])*t01; + if(shi->osatex) { + shi->dx_u= shi->dxco[0]*t11- shi->dxco[2]*t10; + shi->dx_v= shi->dxco[2]*t00- shi->dxco[0]*t01; + shi->dy_u= shi->dyco[0]*t11- shi->dyco[2]*t10; + shi->dy_v= shi->dyco[2]*t00- shi->dyco[0]*t01; + } + } + else { + shi->u= (shi->co[1]-v3[1])*t11-(shi->co[2]-v3[2])*t10; + shi->v= (shi->co[2]-v3[2])*t00-(shi->co[1]-v3[1])*t01; + if(shi->osatex) { + shi->dx_u= shi->dxco[1]*t11- shi->dxco[2]*t10; + shi->dx_v= shi->dxco[2]*t00- shi->dxco[1]*t01; + shi->dy_u= shi->dyco[1]*t11- shi->dyco[2]*t10; + shi->dy_v= shi->dyco[2]*t00- shi->dyco[1]*t01; + } + } + /* u and v are in range -1 to 0, we allow a little bit extra but not too much, screws up speedvectors */ + CLAMP(shi->u, -2.0f, 1.0f); + CLAMP(shi->v, -2.0f, 1.0f); + } + } +} + +void shade_input_set_normals(ShadeInput *shi) +{ + float u= shi->u, v= shi->v; + float l= 1.0f+u+v; + + /* calculate vertexnormals */ + if(shi->vlr->flag & R_SMOOTH) { + float *n1= shi->n1, *n2= shi->n2, *n3= shi->n3; + + shi->vn[0]= l*n3[0]-u*n1[0]-v*n2[0]; + shi->vn[1]= l*n3[1]-u*n1[1]-v*n2[1]; + shi->vn[2]= l*n3[2]-u*n1[2]-v*n2[2]; + + Normalise(shi->vn); + } + else { + VECCOPY(shi->vn, shi->facenor); + } + + /* used in nodes */ + VECCOPY(shi->vno, shi->vn); + +} + +void shade_input_set_shade_texco(ShadeInput *shi) +{ + VertRen *v1= shi->v1, *v2= shi->v2, *v3= shi->v3; + float u= shi->u, v= shi->v; + float l= 1.0f+u+v, dl; + int mode= shi->mode= shi->mat->mode_l; /* or-ed result for all nodes */ + short texco= shi->mat->texco; + + /* calculate dxno and tangents */ + if(shi->vlr->flag & R_SMOOTH) { + + if(shi->osatex && (texco & (TEXCO_NORM|TEXCO_REFL)) ) { + float *n1= shi->n1, *n2= shi->n2, *n3= shi->n3; + + dl= shi->dx_u+shi->dx_v; + shi->dxno[0]= dl*n3[0]-shi->dx_u*n1[0]-shi->dx_v*n2[0]; + shi->dxno[1]= dl*n3[1]-shi->dx_u*n1[1]-shi->dx_v*n2[1]; + shi->dxno[2]= dl*n3[2]-shi->dx_u*n1[2]-shi->dx_v*n2[2]; + dl= shi->dy_u+shi->dy_v; + shi->dyno[0]= dl*n3[0]-shi->dy_u*n1[0]-shi->dy_v*n2[0]; + shi->dyno[1]= dl*n3[1]-shi->dy_u*n1[1]-shi->dy_v*n2[1]; + shi->dyno[2]= dl*n3[2]-shi->dy_u*n1[2]-shi->dy_v*n2[2]; + + } + + /* qdn: normalmap tangent space */ + if (mode & (MA_TANGENT_V|MA_NORMAP_TANG)) { + float *s1, *s2, *s3; + + s1= RE_vertren_get_tangent(&R, v1, 0); + s2= RE_vertren_get_tangent(&R, v2, 0); + s3= RE_vertren_get_tangent(&R, v3, 0); + if(s1 && s2 && s3) { + shi->tang[0]= (l*s3[0] - u*s1[0] - v*s2[0]); + shi->tang[1]= (l*s3[1] - u*s1[1] - v*s2[1]); + shi->tang[2]= (l*s3[2] - u*s1[2] - v*s2[2]); + /* qdn: normalize just in case */ + Normalise(shi->tang); + } + else shi->tang[0]= shi->tang[1]= shi->tang[2]= 0.0f; + } + } + else { + /* qdn: normalmap tangent space */ + if (mode & (MA_TANGENT_V|MA_NORMAP_TANG)) { + /* qdn: flat faces have tangents too, + could pick either one, using average here */ + float *s1 = RE_vertren_get_tangent(&R, v1, 0); + float *s2 = RE_vertren_get_tangent(&R, v2, 0); + float *s3 = RE_vertren_get_tangent(&R, v3, 0); + if (s1 && s2 && s3) { + shi->tang[0] = (s1[0] + s2[0] + s3[0]); + shi->tang[1] = (s1[1] + s2[1] + s3[1]); + shi->tang[2] = (s1[2] + s2[2] + s3[2]); + Normalise(shi->tang); + } + } + } + + if(R.r.mode & R_SPEED) { + float *s1, *s2, *s3; + + s1= RE_vertren_get_winspeed(&R, v1, 0); + s2= RE_vertren_get_winspeed(&R, v2, 0); + s3= RE_vertren_get_winspeed(&R, v3, 0); + if(s1 && s2 && s3) { + shi->winspeed[0]= (l*s3[0] - u*s1[0] - v*s2[0]); + shi->winspeed[1]= (l*s3[1] - u*s1[1] - v*s2[1]); + shi->winspeed[2]= (l*s3[2] - u*s1[2] - v*s2[2]); + shi->winspeed[3]= (l*s3[3] - u*s1[3] - v*s2[3]); + } + else { + shi->winspeed[0]= shi->winspeed[1]= shi->winspeed[2]= shi->winspeed[3]= 0.0f; + } + } + + /* texture coordinates. shi->dxuv shi->dyuv have been set */ + if(texco & NEED_UV) { + + if(texco & TEXCO_ORCO) { + if(v1->orco) { + float *o1, *o2, *o3; + + o1= v1->orco; + o2= v2->orco; + o3= v3->orco; + + shi->lo[0]= l*o3[0]-u*o1[0]-v*o2[0]; + shi->lo[1]= l*o3[1]-u*o1[1]-v*o2[1]; + shi->lo[2]= l*o3[2]-u*o1[2]-v*o2[2]; + + if(shi->osatex) { + dl= shi->dx_u+shi->dx_v; + shi->dxlo[0]= dl*o3[0]-shi->dx_u*o1[0]-shi->dx_v*o2[0]; + shi->dxlo[1]= dl*o3[1]-shi->dx_u*o1[1]-shi->dx_v*o2[1]; + shi->dxlo[2]= dl*o3[2]-shi->dx_u*o1[2]-shi->dx_v*o2[2]; + dl= shi->dy_u+shi->dy_v; + shi->dylo[0]= dl*o3[0]-shi->dy_u*o1[0]-shi->dy_v*o2[0]; + shi->dylo[1]= dl*o3[1]-shi->dy_u*o1[1]-shi->dy_v*o2[1]; + shi->dylo[2]= dl*o3[2]-shi->dy_u*o1[2]-shi->dy_v*o2[2]; + } + } + } + + if(texco & TEXCO_GLOB) { + VECCOPY(shi->gl, shi->co); + MTC_Mat4MulVecfl(R.viewinv, shi->gl); + if(shi->osatex) { + VECCOPY(shi->dxgl, shi->dxco); + MTC_Mat3MulVecfl(R.imat, shi->dxco); + VECCOPY(shi->dygl, shi->dyco); + MTC_Mat3MulVecfl(R.imat, shi->dyco); + } + } + + if(texco & TEXCO_STRAND) { + shi->strand= (l*v3->accum - u*v1->accum - v*v2->accum); + if(shi->osatex) { + dl= shi->dx_u+shi->dx_v; + shi->dxstrand= dl*v3->accum-shi->dx_u*v1->accum-shi->dx_v*v2->accum; + dl= shi->dy_u+shi->dy_v; + shi->dystrand= dl*v3->accum-shi->dy_u*v1->accum-shi->dy_v*v2->accum; + } + } + + if((texco & TEXCO_UV) || (mode & (MA_VERTEXCOL|MA_VERTEXCOLP|MA_FACETEXTURE))) { + VlakRen *vlr= shi->vlr; + int j1=shi->i1, j2=shi->i2, j3=shi->i3; + + /* uv and vcols are not copied on split, so set them according vlr divide flag */ + vlr_set_uv_indices(vlr, &j1, &j2, &j3); + + if(mode & (MA_VERTEXCOL|MA_VERTEXCOLP)) { + + if(vlr->vcol) { + char *cp1, *cp2, *cp3; + + cp1= (char *)(vlr->vcol+j1); + cp2= (char *)(vlr->vcol+j2); + cp3= (char *)(vlr->vcol+j3); + + shi->vcol[0]= (l*((float)cp3[3]) - u*((float)cp1[3]) - v*((float)cp2[3]))/255.0f; + shi->vcol[1]= (l*((float)cp3[2]) - u*((float)cp1[2]) - v*((float)cp2[2]))/255.0f; + shi->vcol[2]= (l*((float)cp3[1]) - u*((float)cp1[1]) - v*((float)cp2[1]))/255.0f; + } + else { + shi->vcol[0]= 0.0f; + shi->vcol[1]= 0.0f; + shi->vcol[2]= 0.0f; + } + } + if(vlr->tface) { + float *uv1, *uv2, *uv3; + + uv1= vlr->tface->uv[j1]; + uv2= vlr->tface->uv[j2]; + uv3= vlr->tface->uv[j3]; + + shi->uv[0]= -1.0f + 2.0f*(l*uv3[0]-u*uv1[0]-v*uv2[0]); + shi->uv[1]= -1.0f + 2.0f*(l*uv3[1]-u*uv1[1]-v*uv2[1]); + shi->uv[2]= 0.0f; // texture.c assumes there are 3 coords + + if(shi->osatex) { + float duv[2]; + + dl= shi->dx_u+shi->dx_v; + duv[0]= shi->dx_u; + duv[1]= shi->dx_v; + + shi->dxuv[0]= 2.0f*(dl*uv3[0]-duv[0]*uv1[0]-duv[1]*uv2[0]); + shi->dxuv[1]= 2.0f*(dl*uv3[1]-duv[0]*uv1[1]-duv[1]*uv2[1]); + + dl= shi->dy_u+shi->dy_v; + duv[0]= shi->dy_u; + duv[1]= shi->dy_v; + + shi->dyuv[0]= 2.0f*(dl*uv3[0]-duv[0]*uv1[0]-duv[1]*uv2[0]); + shi->dyuv[1]= 2.0f*(dl*uv3[1]-duv[0]*uv1[1]-duv[1]*uv2[1]); + } + if(mode & MA_FACETEXTURE) { + if((mode & (MA_VERTEXCOL|MA_VERTEXCOLP))==0) { + shi->vcol[0]= 1.0f; + shi->vcol[1]= 1.0f; + shi->vcol[2]= 1.0f; + } + if(vlr->tface) render_realtime_texture(shi); + } + } + else { + shi->uv[0]= 2.0f*(u+.5f); + shi->uv[1]= 2.0f*(v+.5f); + shi->uv[2]= 0.0f; // texture.c assumes there are 3 coords + if(mode & MA_FACETEXTURE) { + /* no tface? set at 1.0f */ + shi->vcol[0]= 1.0f; + shi->vcol[1]= 1.0f; + shi->vcol[2]= 1.0f; + } + } + } + + if(texco & TEXCO_NORM) { + shi->orn[0]= -shi->vn[0]; + shi->orn[1]= -shi->vn[1]; + shi->orn[2]= -shi->vn[2]; + } + + if(mode & MA_RADIO) { + float *r1, *r2, *r3; + + r1= RE_vertren_get_rad(&R, v1, 0); + r2= RE_vertren_get_rad(&R, v2, 0); + r3= RE_vertren_get_rad(&R, v3, 0); + + if(r1 && r2 && r3) { + shi->rad[0]= (l*r3[0] - u*r1[0] - v*r2[0]); + shi->rad[1]= (l*r3[1] - u*r1[1] - v*r2[1]); + shi->rad[2]= (l*r3[2] - u*r1[2] - v*r2[2]); + } + else { + shi->rad[0]= shi->rad[1]= shi->rad[2]= 0.0f; + } + } + else { + shi->rad[0]= shi->rad[1]= shi->rad[2]= 0.0f; + } + + if(texco & TEXCO_REFL) { + /* mirror reflection colour textures (and envmap) */ + calc_R_ref(shi); /* wrong location for normal maps! XXXXXXXXXXXXXX */ + } + + if(texco & TEXCO_STRESS) { + float *s1, *s2, *s3; + + s1= RE_vertren_get_stress(&R, v1, 0); + s2= RE_vertren_get_stress(&R, v2, 0); + s3= RE_vertren_get_stress(&R, v3, 0); + if(s1 && s2 && s3) { + shi->stress= l*s3[0] - u*s1[0] - v*s2[0]; + if(shi->stress<1.0f) shi->stress-= 1.0f; + else shi->stress= (shi->stress-1.0f)/shi->stress; + } + else shi->stress= 0.0f; + } + + if(texco & TEXCO_TANGENT) { + if((mode & MA_TANGENT_V)==0) { + /* just prevent surprises */ + shi->tang[0]= shi->tang[1]= shi->tang[2]= 0.0f; + } + } + } + else { + shi->rad[0]= shi->rad[1]= shi->rad[2]= 0.0f; + } + + /* this only avalailable for scanline renders */ + if(shi->depth==0) { + float x= shi->xs; + float y= shi->ys; + + if(texco & TEXCO_WINDOW) { + shi->winco[0]= -1.0f + 2.0f*x/(float)R.winx; + shi->winco[1]= -1.0f + 2.0f*y/(float)R.winy; + shi->winco[2]= 0.0f; + if(shi->osatex) { + shi->dxwin[0]= 2.0f/(float)R.winx; + shi->dywin[1]= 2.0f/(float)R.winy; + shi->dxwin[1]= shi->dxwin[2]= 0.0f; + shi->dywin[0]= shi->dywin[2]= 0.0f; + } + } + + if(texco & TEXCO_STICKY) { + float *s1, *s2, *s3; + + s1= RE_vertren_get_sticky(&R, v1, 0); + s2= RE_vertren_get_sticky(&R, v2, 0); + s3= RE_vertren_get_sticky(&R, v3, 0); + + if(s1 && s2 && s3) { + float Zmulx, Zmuly; + float hox, hoy, l, dl, u, v; + float s00, s01, s10, s11, detsh; + + /* old globals, localized now */ + Zmulx= ((float)R.winx)/2.0f; Zmuly= ((float)R.winy)/2.0f; + + 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; + + /* recalc u and v again */ + hox= x/Zmulx -1.0f; + hoy= y/Zmuly -1.0f; + 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.0f+u+v; + + shi->sticky[0]= l*s3[0]-u*s1[0]-v*s2[0]; + shi->sticky[1]= l*s3[1]-u*s1[1]-v*s2[1]; + shi->sticky[2]= 0.0f; + + if(shi->osatex) { + float dxuv[2], dyuv[2]; + dxuv[0]= s11/Zmulx; + dxuv[1]= - s01/Zmulx; + dyuv[0]= - s10/Zmuly; + dyuv[1]= s00/Zmuly; + + dl= dxuv[0] + dxuv[1]; + shi->dxsticky[0]= dl*s3[0] - dxuv[0]*s1[0] - dxuv[1]*s2[0]; + shi->dxsticky[1]= dl*s3[1] - dxuv[0]*s1[1] - dxuv[1]*s2[1]; + dl= dyuv[0] + dyuv[1]; + shi->dysticky[0]= dl*s3[0] - dyuv[0]*s1[0] - dyuv[1]*s2[0]; + shi->dysticky[1]= dl*s3[1] - dyuv[0]*s1[1] - dyuv[1]*s2[1]; + } + } + } + } +} + +/* ****************** ShadeSample ************************************** */ + + + +static void shade_input_initialize(ShadeInput *shi, RenderPart *pa, RenderLayer *rl, int sample) +{ + + memset(shi, 0, sizeof(ShadeInput)); + + shi->sample= sample; + shi->thread= pa->thread; + shi->do_preview= R.r.scemode & R_NODE_PREVIEW; + shi->lay= rl->lay; + shi->layflag= rl->layflag; + shi->passflag= rl->passflag; + + /* note shi.depth==0 means first hit, not raytracing */ +} + +void shade_sample_initialize(ShadeSample *ssamp, RenderPart *pa, RenderLayer *rl) +{ + int a, tot; + + tot= R.osa==0?1:R.osa; + + for(a=0; a<tot; a++) { + shade_input_initialize(&ssamp->shi[a], pa, rl, a); + memset(&ssamp->shr[a], 0, sizeof(RenderResult)); + } +} + +/* for all lamps, for all samples, do shadow */ +/* renderdata mode was checked for */ +void shade_samples_do_shadow(ShadeSample *ssamp) +{ + GroupObject *go; + LampRen *lar; + ShadeInput *shi; + int sample; + + if(ssamp->shi[0].passflag & (SCE_PASS_COMBINED|SCE_PASS_DIFFUSE|SCE_PASS_SPEC|SCE_PASS_SHADOW)) { + for(go=R.lights.first; go; go= go->next) { + lar= go->lampren; + + /* if there's shadow */ + if(lar->shb || (lar->mode & LA_SHAD_RAY)) { + + for(sample=0, shi= ssamp->shi; sample<ssamp->tot; shi++, sample++) { + float visifac, lv[3], lampdist, inpr; + + /* three tests to quickly reject */ + if(!(shi->mat->mode & MA_SHADOW) || (shi->mat->mode & MA_SHLESS)) + continue; + + visifac= lamp_get_visibility(lar, shi->co, lv, &lampdist); + if(visifac==0.0f) + continue; + + inpr= INPR(shi->vn, lv); + + /* tangential faces always look at lamp */ + if( (shi->mat->mode & MA_TANGENT_V) || (shi->vlr->flag & R_TANGENT) ) + inpr= 1.0f - inpr*inpr; + else if(inpr <= 0.0f) + continue; + + /* now we're going (1 = do it real) */ + lamp_get_shadow(lar, shi, inpr, lar->shadsamp[shi->thread].shadfac[sample], 1); + } + } + } + } + + /* do the AO */ + if(R.wrld.mode & WO_AMB_OCC) + if(ssamp->shi[0].passflag & (SCE_PASS_COMBINED|SCE_PASS_DIFFUSE|SCE_PASS_AO)) + for(sample=0, shi= ssamp->shi; sample<ssamp->tot; shi++, sample++) + if(!(shi->mat->mode & MA_SHLESS)) + if(shi->mat->mode & MA_SHADOW) + ambient_occlusion(shi); /* stores in shi->ao[] */ + +} + +static void shade_samples_fill_with_ps(ShadeSample *ssamp, PixStr *ps, int x, int y) +{ + ShadeInput *shi; + float xs, ys; + + ssamp->tot= 0; + + for(shi= ssamp->shi; ps; ps= ps->next, shi++) { + shade_input_set_triangle(shi, ps->facenr, 1); + + /* officially should always be true... we have no sky info */ + if(shi->vlr) { + unsigned short curmask= ps->mask; + + /* full osa is only set for OSA renders */ + if(shi->vlr->flag & R_FULL_OSA) { + short shi_inc= 0, samp; + + for(samp=0; samp<R.osa; samp++) { + if(curmask & (1<<samp)) { + xs= (float)x + R.jit[samp][0] + 0.5f; /* zbuffer has this inverse corrected, ensures xs,ys are inside pixel */ + ys= (float)y + R.jit[samp][1] + 0.5f; + + if(shi_inc) { + shade_input_copy_triangle(shi+1, shi); + shi++; + } + shi->mask= (1<<samp); + shade_input_set_viewco(shi, xs, ys, (float)ps->z); + shade_input_set_uv(shi); + shade_input_set_normals(shi); + + shi_inc= 1; + } + } + } + else { + if(R.osa) { + short b= R.samples->centmask[curmask]; + xs= (float)x + R.samples->centLut[b & 15] + 0.5f; + ys= (float)y + R.samples->centLut[b>>4] + 0.5f; + } + else { + xs= (float)x + 0.5f; + ys= (float)y + 0.5f; + } + shi->mask= curmask; + shade_input_set_viewco(shi, xs, ys, (float)ps->z); + shade_input_set_uv(shi); + shade_input_set_normals(shi); + } + + /* total sample amount, shi->sample is static set in initialize */ + ssamp->tot= shi->sample+1; + } + } +} + +/* shades samples, returns true if anything happened */ +int shade_samples(ShadeSample *ssamp, PixStr *ps, int x, int y) +{ + shade_samples_fill_with_ps(ssamp, ps, x, y); + + if(ssamp->tot) { + ShadeInput *shi= ssamp->shi; + ShadeResult *shr= ssamp->shr; + int samp; + + /* if shadow or AO? */ + if(R.r.mode & R_SHADOW) + shade_samples_do_shadow(ssamp); + + /* if shade (all shadepinputs have same passflag) */ + if(ssamp->shi[0].passflag & ~(SCE_PASS_Z|SCE_PASS_INDEXOB)) { + + for(samp=0; samp<ssamp->tot; samp++, shi++, shr++) { + shade_input_set_shade_texco(shi); + shade_input_do_shade(shi, shr); + } + } + + return 1; + } + return 0; +} + diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c new file mode 100644 index 00000000000..e62291497ce --- /dev/null +++ b/source/blender/render/intern/source/shadeoutput.c @@ -0,0 +1,1558 @@ +/** +* $Id: + * + * ***** BEGIN GPL 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. + * + * 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) 2006 Blender Foundation + * All rights reserved. + * + * Contributors: Hos, Robert Wenzlaff. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <stdio.h> +#include <math.h> +#include <string.h> + +#include "MTC_matrixops.h" +#include "BLI_arithb.h" + +#include "BKE_material.h" +#include "BKE_texture.h" +#include "BKE_utildefines.h" + +#include "DNA_group_types.h" +#include "DNA_lamp_types.h" +#include "DNA_material_types.h" + +/* local include */ +#include "renderpipeline.h" +#include "render_types.h" +#include "pixelblending.h" +#include "rendercore.h" +#include "shadbuf.h" +#include "texture.h" + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */ +/* only to be used here in this file, it's for speed */ +extern struct Render R; +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + + +#if 0 +static void fogcolor(float *colf, float *rco, float *view) +{ + float alpha, stepsize, startdist, dist, hor[4], zen[3], vec[3], dview[3]; + float div=0.0f, distfac; + + hor[0]= R.wrld.horr; hor[1]= R.wrld.horg; hor[2]= R.wrld.horb; + zen[0]= R.wrld.zenr; zen[1]= R.wrld.zeng; zen[2]= R.wrld.zenb; + + VECCOPY(vec, rco); + + /* we loop from cur coord to mist start in steps */ + stepsize= 1.0f; + + div= ABS(view[2]); + dview[0]= view[0]/(stepsize*div); + dview[1]= view[1]/(stepsize*div); + dview[2]= -stepsize; + + startdist= -rco[2] + BLI_frand(); + for(dist= startdist; dist>R.wrld.miststa; dist-= stepsize) { + + hor[0]= R.wrld.horr; hor[1]= R.wrld.horg; hor[2]= R.wrld.horb; + alpha= 1.0f; + do_sky_tex(vec, vec, NULL, hor, zen, &alpha); + + distfac= (dist-R.wrld.miststa)/R.wrld.mistdist; + + hor[3]= hor[0]*distfac*distfac; + + /* premul! */ + alpha= hor[3]; + hor[0]= hor[0]*alpha; + hor[1]= hor[1]*alpha; + hor[2]= hor[2]*alpha; + addAlphaOverFloat(colf, hor); + + VECSUB(vec, vec, dview); + } +} +#endif + +/* zcor is distance, co the 3d coordinate in eye space, return alpha */ +float mistfactor(float zcor, float *co) +{ + float fac, hi; + + fac= zcor - R.wrld.miststa; /* zcor is calculated per pixel */ + + /* fac= -co[2]-R.wrld.miststa; */ + + if(fac>0.0f) { + if(fac< R.wrld.mistdist) { + + fac= (fac/(R.wrld.mistdist)); + + if(R.wrld.mistype==0) fac*= fac; + else if(R.wrld.mistype==1); + else fac= sqrt(fac); + } + else fac= 1.0f; + } + else fac= 0.0f; + + /* height switched off mist */ + if(R.wrld.misthi!=0.0f && fac!=0.0f) { + /* at height misthi the mist is completely gone */ + + hi= R.viewinv[0][2]*co[0]+R.viewinv[1][2]*co[1]+R.viewinv[2][2]*co[2]+R.viewinv[3][2]; + + if(hi>R.wrld.misthi) fac= 0.0f; + else if(hi>0.0f) { + hi= (R.wrld.misthi-hi)/R.wrld.misthi; + fac*= hi*hi; + } + } + + return (1.0f-fac)* (1.0f-R.wrld.misi); +} + +static void spothalo(struct LampRen *lar, ShadeInput *shi, float *intens) +{ + double a, b, c, disc, nray[3], npos[3]; + float t0, t1 = 0.0f, t2= 0.0f, t3, haint; + float p1[3], p2[3], ladist, maxz = 0.0f, maxy = 0.0f; + int snijp, doclip=1, use_yco=0; + int ok1=0, ok2=0; + + *intens= 0.0f; + haint= lar->haint; + + if(R.r.mode & R_ORTHO) { + /* camera pos (view vector) cannot be used... */ + /* camera position (cox,coy,0) rotate around lamp */ + p1[0]= shi->co[0]-lar->co[0]; + p1[1]= shi->co[1]-lar->co[1]; + p1[2]= -lar->co[2]; + MTC_Mat3MulVecfl(lar->imat, p1); + VECCOPY(npos, p1); // npos is double! + } + else { + VECCOPY(npos, lar->sh_invcampos); /* in initlamp calculated */ + } + + /* rotate view */ + VECCOPY(nray, shi->view); + MTC_Mat3MulVecd(lar->imat, nray); + + if(R.wrld.mode & WO_MIST) { + /* patchy... */ + haint *= mistfactor(-lar->co[2], lar->co); + if(haint==0.0f) { + return; + } + } + + + /* rotate maxz */ + if(shi->co[2]==0.0f) doclip= 0; /* for when halo at sky */ + else { + p1[0]= shi->co[0]-lar->co[0]; + p1[1]= shi->co[1]-lar->co[1]; + p1[2]= shi->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.000001f ) use_yco= 1; + } + + /* scale z to make sure volume is normalized */ + nray[2]*= lar->sh_zfac; + /* nray does not need normalization */ + + ladist= lar->sh_zfac*lar->dist; + + /* solve */ + 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) { + /* sort */ + if(t1>t2) { + a= t1; t1= t2; t2= a; + } + + /* z of intersection points with diabolo */ + p1[2]= npos[2] + t1*nray[2]; + p2[2]= npos[2] + t2*nray[2]; + + /* evaluate both points */ + if(p1[2]<=0.0f) ok1= 1; + if(p2[2]<=0.0f && t1!=t2) ok2= 1; + + /* at least 1 point with negative z */ + if(ok1==0 && ok2==0) return; + + /* intersction point with -ladist, the bottom of the cone */ + if(use_yco==0) { + t3= (-ladist-npos[2])/nray[2]; + + /* de we have to replace one of the intersection points? */ + 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; + + /* at least 1 visible interesction point */ + if(t1<0.0f && t2<0.0f) return; + + if(t1<0.0f) t1= 0.0f; + if(t2<0.0f) t2= 0.0f; + + if(t1==t2) return; + + /* sort again to be sure */ + if(t1>t2) { + a= t1; t1= t2; t2= a; + } + + /* calculate t0: is the maximum visible z (when halo is intersected by face) */ + 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; + } + + /* calc points */ + 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]; + + + /* now we have 2 points, make three lengths with it */ + + 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) ); + + /* WATCH IT: do not clip a,b en c at 1.0, this gives nasty little overflows + at the edges (especially with narrow halos) */ + if(*intens<=0.0f) return; + + /* soft area */ + /* not needed because t0 has been used for p1/p2 as well */ + /* if(doclip && t0<t2) { */ + /* *intens *= (t0-t1)/(t2-t1); */ + /* } */ + + *intens *= haint; + + if(lar->shb && lar->shb->shadhalostep) { + *intens *= shadow_halo(lar, p1, p2); + } + + } +} + +void renderspothalo(ShadeInput *shi, float *col, float alpha) +{ + GroupObject *go; + LampRen *lar; + float i; + + if(alpha==0.0f) return; + + for(go=R.lights.first; go; go= go->next) { + lar= go->lampren; + + if(lar->type==LA_SPOT && (lar->mode & LA_HALO) && lar->haint>0) { + if((lar->lay & shi->lay)==0) continue; + + spothalo(lar, shi, &i); + if(i>0.0f) { + col[3]+= i*alpha; // all premul + col[0]+= i*lar->r*alpha; + col[1]+= i*lar->g*alpha; + col[2]+= i*lar->b*alpha; + } + } + } + /* clip alpha, is needed for unified 'alpha threshold' (vanillaRenderPipe.c) */ + if(col[3]>1.0f) col[3]= 1.0f; +} + + + +/* ---------------- shaders ----------------------- */ + +static double Normalise_d(double *n) +{ + double d; + + d= n[0]*n[0]+n[1]*n[1]+n[2]*n[2]; + + if(d>0.00000000000000001) { + d= sqrt(d); + + n[0]/=d; + n[1]/=d; + n[2]/=d; + } else { + n[0]=n[1]=n[2]= 0.0; + d= 0.0; + } + return d; +} + +/* mix of 'real' fresnel and allowing control. grad defines blending gradient */ +float fresnel_fac(float *view, float *vn, float grad, float fac) +{ + float t1, t2; + + if(fac==0.0f) return 1.0f; + + t1= (view[0]*vn[0] + view[1]*vn[1] + view[2]*vn[2]); + if(t1>0.0f) t2= 1.0f+t1; + else t2= 1.0f-t1; + + t2= grad + (1.0f-grad)*pow(t2, fac); + + if(t2<0.0f) return 0.0f; + else if(t2>1.0f) return 1.0f; + return t2; +} + +static double saacos_d(double fac) +{ + if(fac<= -1.0f) return M_PI; + else if(fac>=1.0f) return 0.0; + else return acos(fac); +} + +/* Stoke's form factor. Need doubles here for extreme small area sizes */ +static float area_lamp_energy(float *co, float *vn, LampRen *lar) +{ + double fac; + double vec[4][3]; /* vectors of rendered co to vertices lamp */ + double cross[4][3]; /* cross products of this */ + double rad[4]; /* angles between vecs */ + + VECSUB(vec[0], co, lar->area[0]); + VECSUB(vec[1], co, lar->area[1]); + VECSUB(vec[2], co, lar->area[2]); + VECSUB(vec[3], co, lar->area[3]); + + Normalise_d(vec[0]); + Normalise_d(vec[1]); + Normalise_d(vec[2]); + Normalise_d(vec[3]); + + /* cross product */ + CROSS(cross[0], vec[0], vec[1]); + CROSS(cross[1], vec[1], vec[2]); + CROSS(cross[2], vec[2], vec[3]); + CROSS(cross[3], vec[3], vec[0]); + + Normalise_d(cross[0]); + Normalise_d(cross[1]); + Normalise_d(cross[2]); + Normalise_d(cross[3]); + + /* angles */ + rad[0]= vec[0][0]*vec[1][0]+ vec[0][1]*vec[1][1]+ vec[0][2]*vec[1][2]; + rad[1]= vec[1][0]*vec[2][0]+ vec[1][1]*vec[2][1]+ vec[1][2]*vec[2][2]; + rad[2]= vec[2][0]*vec[3][0]+ vec[2][1]*vec[3][1]+ vec[2][2]*vec[3][2]; + rad[3]= vec[3][0]*vec[0][0]+ vec[3][1]*vec[0][1]+ vec[3][2]*vec[0][2]; + + rad[0]= saacos_d(rad[0]); + rad[1]= saacos_d(rad[1]); + rad[2]= saacos_d(rad[2]); + rad[3]= saacos_d(rad[3]); + + /* Stoke formula */ + fac= rad[0]*(vn[0]*cross[0][0]+ vn[1]*cross[0][1]+ vn[2]*cross[0][2]); + fac+= rad[1]*(vn[0]*cross[1][0]+ vn[1]*cross[1][1]+ vn[2]*cross[1][2]); + fac+= rad[2]*(vn[0]*cross[2][0]+ vn[1]*cross[2][1]+ vn[2]*cross[2][2]); + fac+= rad[3]*(vn[0]*cross[3][0]+ vn[1]*cross[3][1]+ vn[2]*cross[3][2]); + + if(fac<=0.0) return 0.0; + return pow(fac*lar->areasize, lar->k); // corrected for buttons size and lar->dist^2 +} + +static float spec(float inp, int hard) +{ + float b1; + + if(inp>=1.0f) return 1.0f; + else if (inp<=0.0f) return 0.0f; + + b1= inp*inp; + /* avoid FPE */ + if(b1<0.01f) b1= 0.01f; + + if((hard & 1)==0) inp= 1.0f; + if(hard & 2) inp*= b1; + b1*= b1; + if(hard & 4) inp*= b1; + b1*= b1; + if(hard & 8) inp*= b1; + b1*= b1; + if(hard & 16) inp*= b1; + b1*= b1; + + /* avoid FPE */ + if(b1<0.001f) b1= 0.0f; + + if(hard & 32) inp*= b1; + b1*= b1; + if(hard & 64) inp*=b1; + b1*= b1; + if(hard & 128) inp*=b1; + + if(b1<0.001f) b1= 0.0f; + + if(hard & 256) { + b1*= b1; + inp*=b1; + } + + return inp; +} + +static float Phong_Spec( float *n, float *l, float *v, int hard, int tangent ) +{ + float h[3]; + float rslt; + + h[0] = l[0] + v[0]; + h[1] = l[1] + v[1]; + h[2] = l[2] + v[2]; + Normalise(h); + + rslt = h[0]*n[0] + h[1]*n[1] + h[2]*n[2]; + if(tangent) rslt= sasqrt(1.0f - rslt*rslt); + + if( rslt > 0.0f ) rslt= spec(rslt, hard); + else rslt = 0.0f; + + return rslt; +} + + +/* reduced cook torrance spec (for off-specular peak) */ +static float CookTorr_Spec(float *n, float *l, float *v, int hard, int tangent) +{ + float i, nh, nv, h[3]; + + h[0]= v[0]+l[0]; + h[1]= v[1]+l[1]; + h[2]= v[2]+l[2]; + Normalise(h); + + nh= n[0]*h[0]+n[1]*h[1]+n[2]*h[2]; + if(tangent) nh= sasqrt(1.0f - nh*nh); + else if(nh<0.0f) return 0.0f; + + nv= n[0]*v[0]+n[1]*v[1]+n[2]*v[2]; + if(tangent) nv= sasqrt(1.0f - nv*nv); + else if(nv<0.0f) nv= 0.0f; + + i= spec(nh, hard); + + i= i/(0.1+nv); + return i; +} + +/* Blinn spec */ +static float Blinn_Spec(float *n, float *l, float *v, float refrac, float spec_power, int tangent) +{ + float i, nh, nv, nl, vh, h[3]; + float a, b, c, g=0.0f, p, f, ang; + + if(refrac < 1.0f) return 0.0f; + if(spec_power == 0.0f) return 0.0f; + + /* conversion from 'hardness' (1-255) to 'spec_power' (50 maps at 0.1) */ + if(spec_power<100.0f) + spec_power= sqrt(1.0f/spec_power); + else spec_power= 10.0f/spec_power; + + h[0]= v[0]+l[0]; + h[1]= v[1]+l[1]; + h[2]= v[2]+l[2]; + Normalise(h); + + nh= n[0]*h[0]+n[1]*h[1]+n[2]*h[2]; /* Dot product between surface normal and half-way vector */ + if(tangent) nh= sasqrt(1.0f - nh*nh); + else if(nh<0.0f) return 0.0f; + + nv= n[0]*v[0]+n[1]*v[1]+n[2]*v[2]; /* Dot product between surface normal and view vector */ + if(tangent) nv= sasqrt(1.0f - nv*nv); + if(nv<=0.01f) nv= 0.01f; /* hrms... */ + + nl= n[0]*l[0]+n[1]*l[1]+n[2]*l[2]; /* Dot product between surface normal and light vector */ + if(tangent) nl= sasqrt(1.0f - nl*nl); + if(nl<=0.01f) { + return 0.0f; + } + + vh= v[0]*h[0]+v[1]*h[1]+v[2]*h[2]; /* Dot product between view vector and half-way vector */ + if(vh<=0.0f) vh= 0.01f; + + a = 1.0f; + b = (2.0f*nh*nv)/vh; + c = (2.0f*nh*nl)/vh; + + if( a < b && a < c ) g = a; + else if( b < a && b < c ) g = b; + else if( c < a && c < b ) g = c; + + p = sqrt( (double)((refrac * refrac)+(vh*vh)-1.0f) ); + 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)))); + ang = saacos(nh); + + i= f * g * exp((double)(-(ang*ang) / (2.0f*spec_power*spec_power))); + if(i<0.0f) i= 0.0f; + + return i; +} + +/* cartoon render spec */ +static float Toon_Spec( float *n, float *l, float *v, float size, float smooth, int tangent) +{ + float h[3]; + float ang; + float rslt; + + h[0] = l[0] + v[0]; + h[1] = l[1] + v[1]; + h[2] = l[2] + v[2]; + Normalise(h); + + rslt = h[0]*n[0] + h[1]*n[1] + h[2]*n[2]; + if(tangent) rslt = sasqrt(1.0f - rslt*rslt); + + ang = saacos( rslt ); + + if( ang < size ) rslt = 1.0f; + else if( ang >= (size + smooth) || smooth == 0.0f ) rslt = 0.0f; + else rslt = 1.0f - ((ang - size) / smooth); + + return rslt; +} + +/* Ward isotropic gaussian spec */ +static float WardIso_Spec( float *n, float *l, float *v, float rms, int tangent) +{ + float i, nh, nv, nl, h[3], angle, alpha; + + + /* half-way vector */ + h[0] = l[0] + v[0]; + h[1] = l[1] + v[1]; + h[2] = l[2] + v[2]; + Normalise(h); + + nh = n[0]*h[0]+n[1]*h[1]+n[2]*h[2]; /* Dot product between surface normal and half-way vector */ + if(tangent) nh = sasqrt(1.0f - nh*nh); + if(nh<=0.0f) nh = 0.001f; + + nv = n[0]*v[0]+n[1]*v[1]+n[2]*v[2]; /* Dot product between surface normal and view vector */ + if(tangent) nv = sasqrt(1.0f - nv*nv); + if(nv<=0.0f) nv = 0.001f; + + nl = n[0]*l[0]+n[1]*l[1]+n[2]*l[2]; /* Dot product between surface normal and light vector */ + if(tangent) nl = sasqrt(1.0f - nl*nl); + if(nl<=0.0f) nl = 0.001f; + + angle = tan(saacos(nh)); + alpha = MAX2(rms, 0.001f); + + i= nl * (1.0f/(4.0f*M_PI*alpha*alpha)) * (exp( -(angle*angle)/(alpha*alpha))/(sqrt(nv*nl))); + + return i; +} + +/* cartoon render diffuse */ +static float Toon_Diff( float *n, float *l, float *v, float size, float smooth ) +{ + float rslt, ang; + + rslt = n[0]*l[0] + n[1]*l[1] + n[2]*l[2]; + + ang = saacos( (double)(rslt) ); + + if( ang < size ) rslt = 1.0f; + else if( ang >= (size + smooth) || smooth == 0.0f ) rslt = 0.0f; + else rslt = 1.0f - ((ang - size) / smooth); + + return rslt; +} + +/* Oren Nayar diffuse */ + +/* 'nl' is either dot product, or return value of area light */ +/* in latter case, only last multiplication uses 'nl' */ +static float OrenNayar_Diff(float nl, float *n, float *l, float *v, float rough ) +{ + float i, nh, nv, vh, realnl, h[3]; + float a, b, t, A, B; + float Lit_A, View_A, Lit_B[3], View_B[3]; + + h[0]= v[0]+l[0]; + h[1]= v[1]+l[1]; + h[2]= v[2]+l[2]; + Normalise(h); + + nh= n[0]*h[0]+n[1]*h[1]+n[2]*h[2]; /* Dot product between surface normal and half-way vector */ + if(nh<0.0f) nh = 0.0f; + + nv= n[0]*v[0]+n[1]*v[1]+n[2]*v[2]; /* Dot product between surface normal and view vector */ + if(nv<=0.0f) nv= 0.0f; + + realnl= n[0]*l[0]+n[1]*l[1]+n[2]*l[2]; /* Dot product between surface normal and light vector */ + if(realnl<=0.0f) return 0.0f; + if(nl<0.0f) return 0.0f; /* value from area light */ + + vh= v[0]*h[0]+v[1]*h[1]+v[2]*h[2]; /* Dot product between view vector and halfway vector */ + if(vh<=0.0f) vh= 0.0f; + + Lit_A = saacos(realnl); + View_A = saacos( nv ); + + Lit_B[0] = l[0] - (realnl * n[0]); + Lit_B[1] = l[1] - (realnl * n[1]); + Lit_B[2] = l[2] - (realnl * n[2]); + Normalise( Lit_B ); + + View_B[0] = v[0] - (nv * n[0]); + View_B[1] = v[1] - (nv * n[1]); + View_B[2] = v[2] - (nv * n[2]); + Normalise( View_B ); + + t = Lit_B[0]*View_B[0] + Lit_B[1]*View_B[1] + Lit_B[2]*View_B[2]; + if( t < 0 ) t = 0; + + if( Lit_A > View_A ) { + a = Lit_A; + b = View_A; + } + else { + a = View_A; + b = Lit_A; + } + + A = 1.0f - (0.5f * ((rough * rough) / ((rough * rough) + 0.33f))); + B = 0.45f * ((rough * rough) / ((rough * rough) + 0.09f)); + + b*= 0.95f; /* prevent tangens from shooting to inf, 'nl' can be not a dot product here. */ + /* overflow only happens with extreme size area light, and higher roughness */ + i = nl * ( A + ( B * t * sin(a) * tan(b) ) ); + + return i; +} + +/* Minnaert diffuse */ +static float Minnaert_Diff(float nl, float *n, float *v, float darkness) +{ + + float i, nv; + + /* nl = dot product between surface normal and light vector */ + if (nl <= 0.0f) + return 0.0f; + + /* nv = dot product between surface normal and view vector */ + nv = n[0]*v[0]+n[1]*v[1]+n[2]*v[2]; + if (nv < 0.0f) + nv = 0.0f; + + if (darkness <= 1.0f) + i = nl * pow(MAX2(nv*nl, 0.1f), (darkness - 1.0f) ); /*The Real model*/ + else + i = nl * pow( (1.001f - nv), (darkness - 1.0f) ); /*Nvidia model*/ + + return i; +} + +static float Fresnel_Diff(float *vn, float *lv, float *view, float fac_i, float fac) +{ + return fresnel_fac(lv, vn, fac_i, fac); +} + +/* --------------------------------------------- */ +/* also called from texture.c */ +void calc_R_ref(ShadeInput *shi) +{ + float i; + + /* shi->vn dot shi->view */ + i= -2*(shi->vn[0]*shi->view[0]+shi->vn[1]*shi->view[1]+shi->vn[2]*shi->view[2]); + + shi->ref[0]= (shi->view[0]+i*shi->vn[0]); + shi->ref[1]= (shi->view[1]+i*shi->vn[1]); + shi->ref[2]= (shi->view[2]+i*shi->vn[2]); + if(shi->osatex) { + if(shi->vlr->flag & R_SMOOTH) { + i= -2*( (shi->vn[0]+shi->dxno[0])*(shi->view[0]+shi->dxview) + + (shi->vn[1]+shi->dxno[1])*shi->view[1]+ (shi->vn[2]+shi->dxno[2])*shi->view[2] ); + + shi->dxref[0]= shi->ref[0]- ( shi->view[0]+shi->dxview+i*(shi->vn[0]+shi->dxno[0])); + shi->dxref[1]= shi->ref[1]- (shi->view[1]+ i*(shi->vn[1]+shi->dxno[1])); + shi->dxref[2]= shi->ref[2]- (shi->view[2]+ i*(shi->vn[2]+shi->dxno[2])); + + i= -2*( (shi->vn[0]+shi->dyno[0])*shi->view[0]+ + (shi->vn[1]+shi->dyno[1])*(shi->view[1]+shi->dyview)+ (shi->vn[2]+shi->dyno[2])*shi->view[2] ); + + shi->dyref[0]= shi->ref[0]- (shi->view[0]+ i*(shi->vn[0]+shi->dyno[0])); + shi->dyref[1]= shi->ref[1]- (shi->view[1]+shi->dyview+i*(shi->vn[1]+shi->dyno[1])); + shi->dyref[2]= shi->ref[2]- (shi->view[2]+ i*(shi->vn[2]+shi->dyno[2])); + + } + else { + + i= -2*( shi->vn[0]*(shi->view[0]+shi->dxview) + + shi->vn[1]*shi->view[1]+ shi->vn[2]*shi->view[2] ); + + shi->dxref[0]= shi->ref[0]- (shi->view[0]+shi->dxview+i*shi->vn[0]); + shi->dxref[1]= shi->ref[1]- (shi->view[1]+ i*shi->vn[1]); + shi->dxref[2]= shi->ref[2]- (shi->view[2]+ i*shi->vn[2]); + + i= -2*( shi->vn[0]*shi->view[0]+ + shi->vn[1]*(shi->view[1]+shi->dyview)+ shi->vn[2]*shi->view[2] ); + + shi->dyref[0]= shi->ref[0]- (shi->view[0]+ i*shi->vn[0]); + shi->dyref[1]= shi->ref[1]- (shi->view[1]+shi->dyview+i*shi->vn[1]); + shi->dyref[2]= shi->ref[2]- (shi->view[2]+ i*shi->vn[2]); + } + } + +} + +/* called from ray.c */ +void shade_color(ShadeInput *shi, ShadeResult *shr) +{ + Material *ma= shi->mat; + + if(ma->mode & (MA_VERTEXCOLP|MA_FACETEXTURE)) { + shi->r= shi->vcol[0]; + shi->g= shi->vcol[1]; + shi->b= shi->vcol[2]; + } + + if(ma->texco) { + if(ma->mode & (MA_VERTEXCOLP|MA_FACETEXTURE)) { + shi->r= shi->vcol[0]; + shi->g= shi->vcol[1]; + shi->b= shi->vcol[2]; + } + do_material_tex(shi); + } + + if(ma->fresnel_tra!=0.0f) + shi->alpha*= fresnel_fac(shi->view, shi->vn, ma->fresnel_tra_i, ma->fresnel_tra); + + shr->diff[0]= shi->r; + shr->diff[1]= shi->g; + shr->diff[2]= shi->b; + shr->alpha= shi->alpha; +} + +/* ramp for at end of shade */ +static void ramp_diffuse_result(float *diff, ShadeInput *shi) +{ + Material *ma= shi->mat; + float col[4], fac=0; + + if(ma->ramp_col) { + if(ma->rampin_col==MA_RAMP_IN_RESULT) { + + fac= 0.3*diff[0] + 0.58*diff[1] + 0.12*diff[2]; + do_colorband(ma->ramp_col, fac, col); + + /* blending method */ + fac= col[3]*ma->rampfac_col; + + ramp_blend(ma->rampblend_col, diff, diff+1, diff+2, fac, col); + } + } +} + +/* r,g,b denote energy, ramp is used with different values to make new material color */ +static void add_to_diffuse(float *diff, ShadeInput *shi, float is, float r, float g, float b) +{ + Material *ma= shi->mat; + float col[4], colt[3], fac=0; + + if(ma->ramp_col && (ma->mode & MA_RAMP_COL)) { + + /* MA_RAMP_IN_RESULT is exceptional */ + if(ma->rampin_col==MA_RAMP_IN_RESULT) { + // normal add + diff[0] += r * shi->r; + diff[1] += g * shi->g; + diff[2] += b * shi->b; + } + else { + /* input */ + switch(ma->rampin_col) { + case MA_RAMP_IN_ENERGY: + fac= 0.3*r + 0.58*g + 0.12*b; + break; + case MA_RAMP_IN_SHADER: + fac= is; + break; + case MA_RAMP_IN_NOR: + fac= shi->view[0]*shi->vn[0] + shi->view[1]*shi->vn[1] + shi->view[2]*shi->vn[2]; + break; + } + + do_colorband(ma->ramp_col, fac, col); + + /* blending method */ + fac= col[3]*ma->rampfac_col; + colt[0]= shi->r; + colt[1]= shi->g; + colt[2]= shi->b; + + ramp_blend(ma->rampblend_col, colt, colt+1, colt+2, fac, col); + + /* output to */ + diff[0] += r * colt[0]; + diff[1] += g * colt[1]; + diff[2] += b * colt[2]; + } + } + else { + diff[0] += r * shi->r; + diff[1] += g * shi->g; + diff[2] += b * shi->b; + } +} + +static void ramp_spec_result(float *specr, float *specg, float *specb, ShadeInput *shi) +{ + Material *ma= shi->mat; + float col[4]; + float fac; + + if(ma->ramp_spec && (ma->rampin_spec==MA_RAMP_IN_RESULT)) { + fac= 0.3*(*specr) + 0.58*(*specg) + 0.12*(*specb); + do_colorband(ma->ramp_spec, fac, col); + + /* blending method */ + fac= col[3]*ma->rampfac_spec; + + ramp_blend(ma->rampblend_spec, specr, specg, specb, fac, col); + + } +} + +/* is = dot product shade, t = spec energy */ +static void do_specular_ramp(ShadeInput *shi, float is, float t, float *spec) +{ + Material *ma= shi->mat; + float col[4]; + float fac=0.0f; + + spec[0]= shi->specr; + spec[1]= shi->specg; + spec[2]= shi->specb; + + /* MA_RAMP_IN_RESULT is exception */ + if(ma->ramp_spec && (ma->rampin_spec!=MA_RAMP_IN_RESULT)) { + + /* input */ + switch(ma->rampin_spec) { + case MA_RAMP_IN_ENERGY: + fac= t; + break; + case MA_RAMP_IN_SHADER: + fac= is; + break; + case MA_RAMP_IN_NOR: + fac= shi->view[0]*shi->vn[0] + shi->view[1]*shi->vn[1] + shi->view[2]*shi->vn[2]; + break; + } + + do_colorband(ma->ramp_spec, fac, col); + + /* blending method */ + fac= col[3]*ma->rampfac_spec; + + ramp_blend(ma->rampblend_spec, spec, spec+1, spec+2, fac, col); + } +} + +/* pure AO, check for raytrace and world should have been done */ +void ambient_occlusion(ShadeInput *shi) +{ + + if((R.r.mode & R_RAYTRACE) && shi->mat->amb!=0.0f) + ray_ao(shi, shi->ao); + else + shi->ao[0]= shi->ao[1]= shi->ao[2]= 1.0f; +} + + +/* wrld mode was checked for */ +void ambient_occlusion_to_diffuse(ShadeInput *shi, float *diff) +{ + + if((R.r.mode & R_RAYTRACE) && shi->mat->amb!=0.0f) { + float f= R.wrld.aoenergy*shi->mat->amb; + + if (R.wrld.aomix==WO_AOADDSUB) { + diff[0] = 2.0f*shi->ao[0]-1.0f; + diff[1] = 2.0f*shi->ao[1]-1.0f; + diff[2] = 2.0f*shi->ao[2]-1.0f; + } + else if (R.wrld.aomix==WO_AOSUB) { + diff[0] = shi->ao[0]-1.0f; + diff[1] = shi->ao[1]-1.0f; + diff[2] = shi->ao[2]-1.0f; + } + else { + VECCOPY(diff, shi->ao); + } + + VECMUL(diff, f); + } + else + diff[0]= diff[1]= diff[2]= 0.0f; +} + +/* result written in shadfac */ +void lamp_get_shadow(LampRen *lar, ShadeInput *shi, float inp, float *shadfac, int do_real) +{ + + if(do_real) { + + shadfac[0]= shadfac[1]= shadfac[2]= shadfac[3]= 1.0f; + + if(lar->shb) { + if(lar->buftype==LA_SHADBUF_IRREGULAR) + shadfac[3]= ISB_getshadow(shi, lar->shb); + else + shadfac[3] = testshadowbuf(lar->shb, shi->co, shi->dxco, shi->dyco, inp); + } + else if(lar->mode & LA_SHAD_RAY) { + ray_shadow(shi, lar, shadfac); + } + } + else { + float *fp= lar->shadsamp[shi->thread].shadfac[shi->sample]; + QUATCOPY(shadfac, fp); + } +} + +/* lampdistance and spot angle, writes in lv and dist */ +float lamp_get_visibility(LampRen *lar, float *co, float *lv, float *dist) +{ + if(lar->type==LA_SUN || lar->type==LA_HEMI) { + *dist= 1.0f; + VECCOPY(lv, lar->vec); + return 1.0f; + } + else { + float visifac, t; + + VECSUB(lv, co, lar->co); + *dist= sqrt( INPR(lv, lv)); + t= 1.0f/dist[0]; + VECMUL(lv, t); + + /* area type has no quad or sphere option */ + if(lar->type==LA_AREA) { + /* area is single sided */ + if(INPR(lv, lar->vec) > 0.0f) + visifac= 1.0f; + else + visifac= 0.0f; + } + else { + if(lar->mode & LA_QUAD) { + if(lar->ld1>0.0f) + visifac= lar->dist/(lar->dist+lar->ld1*dist[0]); + if(lar->ld2>0.0f) + visifac*= lar->distkw/(lar->distkw+lar->ld2*dist[0]*dist[0]); + } + else { + visifac= (lar->dist/(lar->dist+dist[0])); + } + + if(lar->mode & LA_SPHERE) { + float t= lar->dist - dist[0]; + if(t<=0.0f) + visifac= 0.0f; + else + visifac*= t/lar->dist; + } + + if(visifac > 0.0f) { + if(lar->type==LA_SPOT) { + float inpr; + + if(lar->mode & LA_SQUARE) { + if(lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2]>0.0f) { + float lvrot[3], 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.0f/(sqrt(1+x*x)) is equivalent to cos(atan(x)) */ + + inpr= 1.0f/(sqrt(1.0f+x*x)); + } + else inpr= 0.0f; + } + else { + inpr= lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2]; + } + + t= lar->spotsi; + if(inpr<=t) + visifac= 0.0f; + else { + t= inpr-t; + if(t<lar->spotbl && lar->spotbl!=0.0f) { + /* soft area */ + float i= t/lar->spotbl; + t= i*i; + inpr*= (3.0f*t-2.0f*t*i); + } + visifac*= inpr; + } + } + } + } + return visifac; + } +} + +/* function returns diff, spec and raw diff */ +static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int passflag) +{ + Material *ma= shi->mat; + VlakRen *vlr= shi->vlr; + float lv[3], lampdist, lacol[3], shadfac[4]; + float i, is, i_noshad, inp, *vn, *view, vnor[3], phongcorr=1.0f; + float visifac; + + vn= shi->vn; + view= shi->view; + + /* lampdist, spot angle, area side, ... */ + visifac= lamp_get_visibility(lar, shi->co, lv, &lampdist); + if(visifac==0.0f) + return; + + if(lar->type==LA_SPOT) { + if(lar->mode & LA_OSATEX) { + shi->osatex= 1; /* signal for multitex() */ + + shi->dxlv[0]= lv[0] - (shi->co[0]-lar->co[0]+shi->dxco[0])/lampdist; + shi->dxlv[1]= lv[1] - (shi->co[1]-lar->co[1]+shi->dxco[1])/lampdist; + shi->dxlv[2]= lv[2] - (shi->co[2]-lar->co[2]+shi->dxco[2])/lampdist; + + shi->dylv[0]= lv[0] - (shi->co[0]-lar->co[0]+shi->dyco[0])/lampdist; + shi->dylv[1]= lv[1] - (shi->co[1]-lar->co[1]+shi->dyco[1])/lampdist; + shi->dylv[2]= lv[2] - (shi->co[2]-lar->co[2]+shi->dyco[2])/lampdist; + } + } + + /* lamp color texture */ + lacol[0]= lar->r; + lacol[1]= lar->g; + lacol[2]= lar->b; + + if(lar->mode & LA_TEXTURE) do_lamp_tex(lar, lv, shi, lacol); + + /* tangent case; calculate fake face normal, aligned with lampvector */ + if(vlr->flag & R_TANGENT) { + float cross[3]; + Crossf(cross, lv, vn); + Crossf(vnor, cross, vn); + vnor[0]= -vnor[0];vnor[1]= -vnor[1];vnor[2]= -vnor[2]; + vn= vnor; + } + else if (ma->mode & MA_TANGENT_V) { + float cross[3]; + Crossf(cross, lv, shi->tang); + Crossf(vnor, cross, shi->tang); + vnor[0]= -vnor[0];vnor[1]= -vnor[1];vnor[2]= -vnor[2]; + vn= vnor; + } + + /* dot product and reflectivity */ + /* inp = dotproduct, is = shader result, i = lamp energy (with shadow), i_noshad = i without shadow */ + inp= vn[0]*lv[0] + vn[1]*lv[1] + vn[2]*lv[2]; + + /* phong threshold to prevent backfacing faces having artefacts on ray shadow (terminator problem) */ + /* this complex construction screams for a nicer implementation! (ton) */ + if(R.r.mode & R_SHADOW) { + if(ma->mode & MA_SHADOW) { + if(lar->type==LA_HEMI); + else if((ma->mode & MA_RAYBIAS) && (lar->mode & LA_SHAD_RAY) && (vlr->flag & R_SMOOTH)) { + float thresh= vlr->ob->smoothresh; + if(inp>thresh) + phongcorr= (inp-thresh)/(inp*(1.0f-thresh)); + else + phongcorr= 0.0f; + } + else if(ma->sbias!=0.0f && ((lar->mode & LA_SHAD_RAY) || lar->shb)) { + if(inp>ma->sbias) + phongcorr= (inp-ma->sbias)/(inp*(1.0f-ma->sbias)); + else + phongcorr= 0.0f; + } + } + } + + /* diffuse shaders */ + if(lar->mode & LA_NO_DIFF) { + is= 0.0f; // skip shaders + } + else if(lar->type==LA_HEMI) { + is= 0.5f*inp + 0.5f; + } + else { + + if(lar->type==LA_AREA) + inp= area_lamp_energy(shi->co, vn, lar); + + /* diffuse shaders (oren nayer gets inp from area light) */ + if(ma->diff_shader==MA_DIFF_ORENNAYAR) is= OrenNayar_Diff(inp, vn, lv, view, ma->roughness); + else if(ma->diff_shader==MA_DIFF_TOON) is= Toon_Diff(vn, lv, view, ma->param[0], ma->param[1]); + else if(ma->diff_shader==MA_DIFF_MINNAERT) is= Minnaert_Diff(inp, vn, view, ma->darkness); + else if(ma->diff_shader==MA_DIFF_FRESNEL) is= Fresnel_Diff(vn, lv, view, ma->param[0], ma->param[1]); + else is= inp; // Lambert + } + + /* i is diffuse */ + i= is*phongcorr; + + if(i>0.0f) { + i*= visifac*shi->refl; + } + i_noshad= i; + + vn= shi->vn; // bring back original vector, we use special specular shaders for tangent + if(ma->mode & MA_TANGENT_V) + vn= shi->tang; + + /* init transp shadow */ + shadfac[0]= shadfac[1]= shadfac[2]= shadfac[3]= 1.0f; + + /* shadow and spec, (visifac==0 outside spot) */ + if(visifac> 0.0f) { + + if(i>0.0f && (R.r.mode & R_SHADOW)) { + if(ma->mode & MA_SHADOW) { + if(lar->shb || (lar->mode & LA_SHAD_RAY)) { + + lamp_get_shadow(lar, shi, inp, shadfac, shi->depth); + + /* warning, here it skips the loop */ + if(lar->mode & LA_ONLYSHADOW) { + + shadfac[3]= i*lar->energy*(1.0f-shadfac[3]); + shr->diff[0] -= shadfac[3]*shi->r; + shr->diff[1] -= shadfac[3]*shi->g; + shr->diff[2] -= shadfac[3]*shi->b; + return; + } + + if(!(passflag & (SCE_PASS_DIFFUSE|SCE_PASS_SHADOW))) + if(shadfac[3]==0.0f) return; + + i*= shadfac[3]; + } + } + } + + /* in case 'no diffuse' we still do most calculus, spec can be in shadow */ + if(!(lar->mode & LA_NO_DIFF)) { + if(i>0.0f) { + if(ma->mode & MA_SHADOW_TRA) + add_to_diffuse(shr->diff, shi, is, i*shadfac[0]*lacol[0], i*shadfac[1]*lacol[1], i*shadfac[2]*lacol[2]); + else + add_to_diffuse(shr->diff, shi, is, i*lacol[0], i*lacol[1], i*lacol[2]); + } + if(i_noshad>0.0f && (passflag & (SCE_PASS_DIFFUSE|SCE_PASS_SHADOW))) { + if(ma->mode & MA_SHADOW_TRA) + add_to_diffuse(shr->diff_raw, shi, is, i_noshad*shadfac[0]*lacol[0], i_noshad*shadfac[1]*lacol[1], i_noshad*shadfac[2]*lacol[2]); + else + add_to_diffuse(shr->diff_raw, shi, is, i_noshad*lacol[0], i_noshad*lacol[1], i_noshad*lacol[2]); + } + } + + /* specularity */ + if(shadfac[3]>0.0f && shi->spec!=0.0f && !(lar->mode & LA_NO_SPEC)) { + + if(!(passflag & (SCE_PASS_COMBINED|SCE_PASS_SPEC))); + else if(lar->type==LA_HEMI) { + float t; + /* hemi uses no spec shaders (yet) */ + + 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; + } + + t= shadfac[3]*shi->spec*spec(t, shi->har); + + shr->spec[0]+= t*(lacol[0] * shi->specr); + shr->spec[1]+= t*(lacol[1] * shi->specg); + shr->spec[2]+= t*(lacol[2] * shi->specb); + } + else { + /* specular shaders */ + float specfac, t; + + if(ma->spec_shader==MA_SPEC_PHONG) + specfac= Phong_Spec(vn, lv, view, shi->har, (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V)); + else if(ma->spec_shader==MA_SPEC_COOKTORR) + specfac= CookTorr_Spec(vn, lv, view, shi->har, (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V)); + else if(ma->spec_shader==MA_SPEC_BLINN) + specfac= Blinn_Spec(vn, lv, view, ma->refrac, (float)shi->har, (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V)); + else if(ma->spec_shader==MA_SPEC_WARDISO) + specfac= WardIso_Spec( vn, lv, view, ma->rms, (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V)); + else + specfac= Toon_Spec(vn, lv, view, ma->param[2], ma->param[3], (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V)); + + /* area lamp correction */ + if(lar->type==LA_AREA) specfac*= inp; + + t= shadfac[3]*shi->spec*visifac*specfac; + + if(ma->mode & MA_RAMP_SPEC) { + float spec[3]; + do_specular_ramp(shi, specfac, t, spec); + shr->spec[0]+= t*(lacol[0] * spec[0]); + shr->spec[1]+= t*(lacol[1] * spec[1]); + shr->spec[2]+= t*(lacol[2] * spec[2]); + } + else { + shr->spec[0]+= t*(lacol[0] * shi->specr); + shr->spec[1]+= t*(lacol[1] * shi->specg); + shr->spec[2]+= t*(lacol[2] * shi->specb); + } + } + } + } +} + +static void shade_lamp_loop_only_shadow(ShadeInput *shi, ShadeResult *shr) +{ + + if(R.r.mode & R_SHADOW) { + ListBase *lights; + LampRen *lar; + GroupObject *go; + float inpr, lv[3]; + float *vn, *view, shadfac[4]; + float ir, accum, visifac, lampdist; + + vn= shi->vn; + view= shi->view; + + /* lights */ + if(shi->mat->group) + lights= &shi->mat->group->gobject; + else + lights= &R.lights; + + accum= ir= 0.0f; + + for(go=lights->first; go; go= go->next) { + lar= go->lampren; + if(lar==NULL) continue; + + /* yafray: ignore shading by photonlights, not used in Blender */ + if (lar->type==LA_YF_PHOTON) continue; + + if(lar->mode & LA_LAYER) if((lar->lay & shi->vlr->lay)==0) continue; + if((lar->lay & shi->lay)==0) continue; + + if(lar->shb || (lar->mode & LA_SHAD_RAY)) { + visifac= lamp_get_visibility(lar, shi->co, lv, &lampdist); + if(visifac < 0.0f) + continue; + + inpr= INPR(shi->vn, lv); + if(inpr <= 0.0f) + continue; + + lamp_get_shadow(lar, shi, inpr, shadfac, shi->depth); + ir+= 1.0f; + accum+= shadfac[3]; + } + } + if(ir>0.0f) { + accum/= ir; + shr->alpha= (shi->alpha)*(1.0f-accum); + } + } + + if((R.wrld.mode & WO_AMB_OCC) && shi->amb!=0.0f) { + float f; + + f= shi->ao[0]; + + /* quite disputable this... also note it doesn't mirror-raytrace */ + if(R.wrld.aomix==WO_AOADD) { + shr->alpha += f; + shr->alpha *= f; + } + else if(R.wrld.aomix==WO_AOSUB) { + shr->alpha += f; + } + else { + shr->alpha *= f; + shr->alpha += f; + } + } +} + +void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr) +{ + Material *ma= shi->mat; + VlakRen *vlr= shi->vlr; + int passflag= shi->passflag; + + memset(shr, 0, sizeof(ShadeResult)); + + /* separate loop */ + if(ma->mode & MA_ONLYSHADOW) { + shade_lamp_loop_only_shadow(shi, shr); + return; + } + + /* envmap hack, always reset */ + shi->refcol[0]= shi->refcol[1]= shi->refcol[2]= shi->refcol[3]= 0.0f; + + /* material color itself */ + if(passflag & (SCE_PASS_COMBINED|SCE_PASS_RGBA)) { + if(ma->mode & (MA_VERTEXCOLP|MA_FACETEXTURE)) { + shi->r= shi->vcol[0]; + shi->g= shi->vcol[1]; + shi->b= shi->vcol[2]; + } + if(ma->texco) + do_material_tex(shi); + + shr->col[0]= shi->r*shi->alpha; + shr->col[1]= shi->g*shi->alpha; + shr->col[2]= shi->b*shi->alpha; + shr->col[3]= shi->alpha; + } + + if(ma->mode & MA_SHLESS) { + shr->combined[0]= shi->r; + shr->combined[1]= shi->g; + shr->combined[2]= shi->b; + shr->alpha= shi->alpha; + return; + } + + if( (ma->mode & (MA_VERTEXCOL|MA_VERTEXCOLP))== MA_VERTEXCOL ) { // vertexcolor light + shr->diff[0]= shi->r*(shi->emit+shi->vcol[0]); + shr->diff[1]= shi->g*(shi->emit+shi->vcol[1]); + shr->diff[2]= shi->b*(shi->emit+shi->vcol[2]); + } + else { + shr->diff[0]= shi->r*shi->emit; + shr->diff[1]= shi->g*shi->emit; + shr->diff[2]= shi->b*shi->emit; + } + + /* AO pass */ + if(R.wrld.mode & WO_AMB_OCC) { + if(passflag & (SCE_PASS_COMBINED|SCE_PASS_AO)) { + /* AO was calculated for scanline already */ + if(shi->depth) + ambient_occlusion(shi); + VECCOPY(shr->ao, shi->ao); + } + } + + /* lighting pass */ + if(passflag & (SCE_PASS_COMBINED|SCE_PASS_DIFFUSE|SCE_PASS_SPEC|SCE_PASS_SHADOW)) { + GroupObject *go; + ListBase *lights; + LampRen *lar; + + /* lights */ + if(ma->group) + lights= &ma->group->gobject; + else + lights= &R.lights; + + for(go=lights->first; go; go= go->next) { + lar= go->lampren; + if(lar==NULL) continue; + + /* yafray: ignore shading by photonlights, not used in Blender */ + if (lar->type==LA_YF_PHOTON) continue; + + /* test for lamp layer */ + if(lar->mode & LA_LAYER) if((lar->lay & vlr->lay)==0) continue; + if((lar->lay & shi->lay)==0) continue; + + /* accumulates in shr->diff and shr->spec and shr->diff_raw (diffuse without shadow!) */ + shade_one_light(lar, shi, shr, passflag); + } + + /* calculate shadow pass, we use a multiplication mask */ + if(passflag & SCE_PASS_SHADOW) { + if(shr->diff_raw[0]!=0.0f) shr->shad[0]= shr->diff[0]/shr->diff_raw[0]; + if(shr->diff_raw[1]!=0.0f) shr->shad[1]= shr->diff[1]/shr->diff_raw[1]; + if(shr->diff_raw[2]!=0.0f) shr->shad[2]= shr->diff[2]/shr->diff_raw[2]; + } + + /* exposure correction */ + if(R.wrld.exp!=0.0f || R.wrld.range!=1.0f) { + shr->diff[0]= R.wrld.linfac*(1.0f-exp( shr->diff[0]*R.wrld.logfac) ); + shr->diff[1]= R.wrld.linfac*(1.0f-exp( shr->diff[1]*R.wrld.logfac) ); + shr->diff[2]= R.wrld.linfac*(1.0f-exp( shr->diff[2]*R.wrld.logfac) ); + + shr->spec[0]= R.wrld.linfac*(1.0f-exp( shr->spec[0]*R.wrld.logfac) ); + shr->spec[1]= R.wrld.linfac*(1.0f-exp( shr->spec[1]*R.wrld.logfac) ); + shr->spec[2]= R.wrld.linfac*(1.0f-exp( shr->spec[2]*R.wrld.logfac) ); + } + } + + /* alpha in end, spec can influence it */ + if(passflag & (SCE_PASS_COMBINED|SCE_PASS_RGBA)) { + if(ma->fresnel_tra!=0.0f) + shi->alpha*= fresnel_fac(shi->view, shi->vn, ma->fresnel_tra_i, ma->fresnel_tra); + + if(shi->mode & (MA_ZTRA|MA_RAYTRANSP)) { + if(shi->spectra!=0.0f) { + float t = MAX3(shr->spec[0], shr->spec[1], shr->spec[2]); + t *= shi->spectra; + if(t>1.0f) t= 1.0f; + shi->alpha= (1.0f-t)*shi->alpha+t; + } + } + } + shr->alpha= shi->alpha; + + /* now stuff everything in shr->diff: ambient, AO, radio, ramps, exposure */ + shr->diff[0]+= shi->ambr + shi->r*shi->amb*shi->rad[0]; + shr->diff[1]+= shi->ambg + shi->g*shi->amb*shi->rad[1]; + shr->diff[2]+= shi->ambb + shi->b*shi->amb*shi->rad[2]; + + if(R.wrld.mode & WO_AMB_OCC) { + float aodiff[3]; + ambient_occlusion_to_diffuse(shi, aodiff); + + shr->diff[0] += shi->r*aodiff[0]; + shr->diff[1] += shi->g*aodiff[1]; + shr->diff[2] += shi->b*aodiff[2]; + } + + if(ma->mode & MA_RAMP_COL) ramp_diffuse_result(shr->diff, shi); + if(ma->mode & MA_RAMP_SPEC) ramp_spec_result(shr->spec, shr->spec+1, shr->spec+2, shi); + + /* refcol is for envmap only */ + if(shi->refcol[0]!=0.0f) { + float olddiff[3]; + + VECCOPY(olddiff, shr->diff); + + shr->diff[0]= shi->mirr*shi->refcol[1] + (1.0f - shi->mirr*shi->refcol[0])*shr->diff[0]; + shr->diff[1]= shi->mirg*shi->refcol[2] + (1.0f - shi->mirg*shi->refcol[0])*shr->diff[1]; + shr->diff[2]= shi->mirb*shi->refcol[3] + (1.0f - shi->mirb*shi->refcol[0])*shr->diff[2]; + + if(passflag & SCE_PASS_REFLECT) + VECSUB(shr->refl, shr->diff, olddiff); + } + + /* XXX SOLVE */ + if(passflag & SCE_PASS_COMBINED) { + shr->combined[0]= shr->diff[0]+ shr->spec[0]; + shr->combined[1]= shr->diff[1]+ shr->spec[1]; + shr->combined[2]= shr->diff[2]+ shr->spec[2]; + shr->combined[3]= shr->alpha; + } +} + + diff --git a/source/blender/render/intern/source/texture.c b/source/blender/render/intern/source/texture.c index acf2b797704..ed434ac5370 100644 --- a/source/blender/render/intern/source/texture.c +++ b/source/blender/render/intern/source/texture.c @@ -59,10 +59,11 @@ #include "BKE_key.h" #include "BKE_ipo.h" +#include "envmap.h" #include "renderpipeline.h" #include "render_types.h" #include "rendercore.h" -#include "envmap.h" +#include "shading.h" #include "texture.h" /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/source/blender/render/intern/source/zbuf.c b/source/blender/render/intern/source/zbuf.c index 43119960cce..1b30cbf6037 100644 --- a/source/blender/render/intern/source/zbuf.c +++ b/source/blender/render/intern/source/zbuf.c @@ -66,6 +66,7 @@ #include "renderdatabase.h" #include "rendercore.h" #include "shadbuf.h" +#include "shading.h" /* own includes */ #include "zbuf.h" @@ -2533,14 +2534,14 @@ static void copyto_abufz(RenderPart *pa, int *arectz, int sample) * Do accumulation z buffering. */ -static void zbuffer_abuf(RenderPart *pa, APixstr *APixbuf, ListBase *apsmbase, unsigned int lay) +static int zbuffer_abuf(RenderPart *pa, APixstr *APixbuf, ListBase *apsmbase, unsigned int lay) { ZSpan zspan; Material *ma=NULL; VlakRen *vlr=NULL; VertRen *v1, *v2, *v3, *v4; float vec[3], hoco[4], mul, zval, fval; - int v, zvlnr, zsample, dofill= 0; + int v, zvlnr= 0, zsample, dofill= 0; char *clipflag= pa->clipflag; zbuf_alloc_span(&zspan, pa->rectx, pa->recty); @@ -2579,6 +2580,9 @@ static void zbuffer_abuf(RenderPart *pa, APixstr *APixbuf, ListBase *apsmbase, u zspan.zofsx -= 0.5f; zspan.zofsy -= 0.5f; + /* we use this to test if nothing was filled in */ + zvlnr= 0; + for(v=0; v<R.totvlak; v++) { if((v & 255)==0) vlr= R.blovl[v>>8]; @@ -2644,11 +2648,13 @@ static void zbuffer_abuf(RenderPart *pa, APixstr *APixbuf, ListBase *apsmbase, u if(R.osa==0) break; if(R.test_break()) break; + if(zvlnr==0) break; } MEM_freeN(zspan.arectz); zbuf_free_span(&zspan); - + + return zvlnr; } /* different rules for speed in transparent pass... */ @@ -2685,51 +2691,119 @@ static void add_transp_speed(RenderLayer *rl, int offset, float *speed, float al } } + break; } } } -static void add_transp_passes(RenderLayer *rl, int offset, ShadeResult *shr, float weight) +/* ONLY OSA! merge all shaderesult samples to one */ +/* target should have been cleared */ +static void merge_transp_passes(RenderLayer *rl, ShadeResult *shr) { RenderPass *rpass; + float weight= 1.0f/((float)R.osa); + int delta= sizeof(ShadeResult)/4; for(rpass= rl->passes.first; rpass; rpass= rpass->next) { - float *fp, *col= NULL; - int a, pixsize= 3; + float *col= NULL; + int pixsize= 0; switch(rpass->passtype) { case SCE_PASS_RGBA: - if(shr) col= shr->col; + col= shr->col; pixsize= 4; break; + case SCE_PASS_VECTOR: + col= shr->winspeed; + pixsize= 4; + break; + case SCE_PASS_DIFFUSE: + col= shr->diff; + break; + case SCE_PASS_SPEC: + col= shr->spec; + break; + case SCE_PASS_SHADOW: + col= shr->shad; + break; + case SCE_PASS_AO: + col= shr->ao; + break; + case SCE_PASS_REFLECT: + col= shr->refl; + break; + case SCE_PASS_REFRACT: + col= shr->refr; + break; + case SCE_PASS_NORMAL: + col= shr->nor; + break; + } + if(col) { + float *fp= col+delta; + int samp; + + for(samp= 1; samp<R.osa; samp++, fp+=delta) { + col[0]+= fp[0]; + col[1]+= fp[1]; + col[2]+= fp[2]; + if(pixsize) col[3]+= fp[3]; + } + col[0]*= weight; + col[1]*= weight; + col[2]*= weight; + if(pixsize) col[3]*= weight; + } + } + +} + +static void add_transp_passes(RenderLayer *rl, int offset, ShadeResult *shr, float alpha) +{ + RenderPass *rpass; + + for(rpass= rl->passes.first; rpass; rpass= rpass->next) { + float *fp, *col= NULL; + + switch(rpass->passtype) { + case SCE_PASS_RGBA: + fp= rpass->rect + 4*offset; + addAlphaOverFloat(fp, shr->col); + break; case SCE_PASS_DIFFUSE: - if(shr) col= shr->diff; + col= shr->diff; break; case SCE_PASS_SPEC: - if(shr) col= shr->spec; + col= shr->spec; break; case SCE_PASS_SHADOW: - if(shr) col= shr->shad; + col= shr->shad; break; case SCE_PASS_AO: - if(shr) col= shr->ao; + col= shr->ao; + break; + case SCE_PASS_REFLECT: + col= shr->refl; break; - case SCE_PASS_RAY: - if(shr) col= shr->ray; + case SCE_PASS_REFRACT: + col= shr->refr; break; case SCE_PASS_NORMAL: - if(shr) col= shr->nor; + col= shr->nor; break; } if(col) { - fp= rpass->rect + pixsize*offset; - for(a=0; a<pixsize; a++) - fp[a]+= weight*col[a]; + + fp= rpass->rect + 3*offset; + fp[0]= alpha*col[0] + (1.0f-alpha)*fp[0]; + fp[1]= alpha*col[1] + (1.0f-alpha)*fp[1]; + fp[2]= alpha*col[2] + (1.0f-alpha)*fp[2]; } } } + static int vergzvlak(const void *a1, const void *a2) { const int *x1=a1, *x2=a2; @@ -2742,112 +2816,183 @@ static int vergzvlak(const void *a1, const void *a2) /** * Shade this face at this location in SCS. */ -static void shadetrapixel(ShadePixelInfo *shpi, float x, float y, int z, int facenr, int mask) + +static void shade_tra_samples_fill(ShadeSample *ssamp, int x, int y, int z, int facenr, int curmask) { - float rco[3]; + ShadeInput *shi= ssamp->shi; + float xs, ys; - if(facenr<0) - return; - else if( (facenr & RE_QUAD_MASK) > R.totvlak) { - printf("error in shadetrapixel nr: %d\n", (facenr & RE_QUAD_MASK)); - return; - } - /* correction back for zbuffer filling in */ - x+= 0.5f; - y+= 0.5f; - - if(R.osa) { - VlakRen *vlr= RE_findOrAddVlak(&R, (facenr-1) & RE_QUAD_MASK); - float accumcol[4]={0,0,0,0}, tot=0.0; - int a; - - if(vlr->flag & R_FULL_OSA) { - for(a=0; a<R.osa; a++) { - if(mask & (1<<a)) { - shadepixel(shpi, x+R.jit[a][0], y+R.jit[a][1], z, facenr, 1<<a, rco); - accumcol[0]+= shpi->shr.combined[0]; - accumcol[1]+= shpi->shr.combined[1]; - accumcol[2]+= shpi->shr.combined[2]; - accumcol[3]+= shpi->shr.combined[3]; - tot+= 1.0; + ssamp->tot= 0; + + shade_input_set_triangle(shi, facenr, 1); + + /* officially should always be true... we have no sky info */ + if(shi->vlr) { + + /* full osa is only set for OSA renders */ + if(shi->vlr->flag & R_FULL_OSA) { + short shi_inc= 0, samp; + + for(samp=0; samp<R.osa; samp++) { + if(curmask & (1<<samp)) { + xs= (float)x + R.jit[samp][0] + 0.5f; /* zbuffer has this inverse corrected, ensures xs,ys are inside pixel */ + ys= (float)y + R.jit[samp][1] + 0.5f; + + if(shi_inc) { + shade_input_copy_triangle(shi+1, shi); + shi++; + } + shi->mask= (1<<samp); + shade_input_set_viewco(shi, xs, ys, (float)z); + shade_input_set_uv(shi); + shade_input_set_normals(shi); + + shi_inc= 1; } } - tot= 1.0/tot; - shpi->shr.combined[0]= accumcol[0]*tot; - shpi->shr.combined[1]= accumcol[1]*tot; - shpi->shr.combined[2]= accumcol[2]*tot; - shpi->shr.combined[3]= accumcol[3]*tot; } else { - int b= R.samples->centmask[mask]; - x= x+R.samples->centLut[b & 15]; - y= y+R.samples->centLut[b>>4]; - shadepixel(shpi, x, y, z, facenr, mask, rco); + if(R.osa) { + short b= R.samples->centmask[curmask]; + xs= (float)x + R.samples->centLut[b & 15] + 0.5f; + ys= (float)y + R.samples->centLut[b>>4] + 0.5f; + } + else { + xs= (float)x + 0.5f; + ys= (float)y + 0.5f; + } + shi->mask= curmask; + shade_input_set_viewco(shi, xs, ys, (float)z); + shade_input_set_uv(shi); + shade_input_set_normals(shi); } + + /* total sample amount, shi->sample is static set in initialize */ + ssamp->tot= shi->sample+1; } - else { - shadepixel(shpi, x, y, z, facenr, mask, rco); +} + +static int shade_tra_samples(ShadeSample *ssamp, int x, int y, int z, int facenr, int mask) +{ + shade_tra_samples_fill(ssamp, x, y, z, facenr, mask); + + if(ssamp->tot) { + ShadeInput *shi= ssamp->shi; + ShadeResult *shr= ssamp->shr; + int samp; + + /* if shadow or AO? */ + if(R.r.mode & R_SHADOW) + shade_samples_do_shadow(ssamp); + + /* if shade (all shadepinputs have same passflag) */ + if(shi->passflag & ~(SCE_PASS_Z|SCE_PASS_INDEXOB)) { + for(samp=0; samp<ssamp->tot; samp++, shi++, shr++) { + shade_input_set_shade_texco(shi); + shade_input_do_shade(shi, shr); + + /* include lamphalos for ztra, since halo layer was added already */ + if(R.flag & R_LAMPHALO) + if(shi->layflag & SCE_LAY_HALO) + renderspothalo(shi, shr->combined, shr->combined[3]); + } + } + return 1; } + return 0; +} + +static void addvecmul(float *v1, float *v2, float fac) +{ + v1[0]= v1[0]+fac*v2[0]; + v1[1]= v1[1]+fac*v2[1]; + v1[2]= v1[2]+fac*v2[2]; } -static int addtosamp_shr(ShadeResult *samp_shr, ShadeResult *shr, int mask, int addpassflag) +static int addtosamp_shr(ShadeResult *samp_shr, ShadeSample *ssamp, int addpassflag) { - int a, retval = R.osa; + int a, sample, retval = R.osa; - for(a=0; a < R.osa; a++) { - if(mask & (1<<a)) { - addAlphaUnderFloat(samp_shr->combined, shr->combined); - - if(addpassflag & SCE_PASS_VECTOR) { - QUATCOPY(samp_shr->winspeed, shr->winspeed); - } - else if(addpassflag & SCE_PASS_NORMAL) { - VECCOPY(samp_shr->nor, shr->nor); + for(a=0; a < R.osa; a++, samp_shr++) { + ShadeInput *shi= ssamp->shi; + ShadeResult *shr= ssamp->shr; + + for(sample=0; sample<ssamp->tot; sample++, shi++, shr++) { + + if(shi->mask & (1<<a)) { + float fac= (1.0f - samp_shr->combined[3])*shr->combined[3]; + + addAlphaUnderFloat(samp_shr->combined, shr->combined); + + if(addpassflag & SCE_PASS_VECTOR) { + QUATCOPY(samp_shr->winspeed, shr->winspeed); + } + /* optim... */ + if(addpassflag & ~(SCE_PASS_VECTOR)) { + + if(addpassflag & SCE_PASS_RGBA) + addAlphaUnderFloat(samp_shr->col, shr->col); + + if(addpassflag & SCE_PASS_NORMAL) + addvecmul(samp_shr->nor, shr->nor, fac); + + if(addpassflag & SCE_PASS_DIFFUSE) + addvecmul(samp_shr->diff, shr->diff, fac); + + if(addpassflag & SCE_PASS_SPEC) + addvecmul(samp_shr->spec, shr->spec, fac); + + if(addpassflag & SCE_PASS_SHADOW) + addvecmul(samp_shr->shad, shr->shad, fac); + + if(addpassflag & SCE_PASS_AO) + addvecmul(samp_shr->ao, shr->ao, fac); + + if(addpassflag & SCE_PASS_REFLECT) + addvecmul(samp_shr->refl, shr->refl, fac); + + if(addpassflag & SCE_PASS_REFRACT) + addvecmul(samp_shr->refr, shr->refr, fac); + } } } - if(samp_shr->combined[3]>0.999) retval--; - samp_shr++; + if(samp_shr->combined[3]>0.999f) retval--; } return retval; } #define MAX_ZROW 2000 /* main render call to fill in pass the full transparent layer */ - -void zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pass) +/* returns a mask, only if a) transp rendered and b) solid was rendered */ +unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pass) { RenderResult *rr= pa->result; - ShadePixelInfo shpi; + ShadeSample ssamp; APixstr *APixbuf; /* Zbuffer: linked list of face samples */ APixstr *ap, *aprect, *apn; ListBase apsmbase={NULL, NULL}; - ShadeResult samp_shr[16]; - float fac, sampalpha, *passrect= pass; + ShadeResult samp_shr[16]; /* MAX_OSA */ + float sampalpha, *passrect= pass; long *rdrect; int x, y, crop=0, a, zrow[MAX_ZROW][3], totface; - int sval, addpassflag, offs= 0, od, addzbuf; - + int addpassflag, offs= 0, od, addzbuf; + unsigned short *ztramask= NULL; + /* looks nicer for calling code */ if(R.test_break()) - return; + return NULL; APixbuf= MEM_callocN(pa->rectx*pa->recty*sizeof(APixstr), "APixbuf"); - if(R.osa>16) { - printf("abufsetrow: osa too large\n"); + if(R.osa>16) { /* MAX_OSA */ + printf("zbuffer_transp_shade: osa too large\n"); G.afbreek= 1; - return; + return NULL; } - /* fill shadepixel info struct */ - shpi.thread= pa->thread; - shpi.lay= rl->lay; - shpi.layflag= rl->layflag; - shpi.passflag= 0; - - if(rl->passflag & ~(SCE_PASS_Z|SCE_PASS_NORMAL|SCE_PASS_VECTOR|SCE_PASS_COMBINED)) - shpi.passflag= rl->passflag; + /* general shader info, passes */ + shade_sample_initialize(&ssamp, pa, rl); addpassflag= rl->passflag & ~(SCE_PASS_Z|SCE_PASS_COMBINED); addzbuf= rl->passflag & SCE_PASS_Z; @@ -2857,14 +3002,23 @@ void zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pass) sampalpha= 1.0f; /* fill the Apixbuf */ - zbuffer_abuf(pa, APixbuf, &apsmbase, rl->lay); + if(0 == zbuffer_abuf(pa, APixbuf, &apsmbase, rl->lay)) { + /* nothing filled in */ + MEM_freeN(APixbuf); + freepsA(&apsmbase); + return NULL; + } aprect= APixbuf; rdrect= pa->rectdaps; /* irregular shadowb buffer creation */ if(R.r.mode & R_SHADOW) ISB_create(pa, APixbuf); - + + /* masks, to have correct alpha combine */ + if(R.osa && (rl->layflag & SCE_LAY_SOLID)) + ztramask= MEM_callocN(pa->rectx*pa->recty*sizeof(short), "ztramask"); + /* filtered render, for now we assume only 1 filter size */ if(pa->crop) { crop= 1; @@ -2911,86 +3065,68 @@ void zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pass) apn= apn->next; } - if(totface==1) { - - shadetrapixel(&shpi, (float)x, (float)y, zrow[0][0], zrow[0][1], zrow[0][2]); - - if(R.osa) { - add_filt_fmask(zrow[0][2], shpi.shr.combined, pass, rr->rectx); - } - else { - QUATCOPY(pass, shpi.shr.combined); + if(totface==2) { + if(zrow[0][0] < zrow[1][0]) { + a= zrow[0][0]; zrow[0][0]= zrow[1][0]; zrow[1][0]= a; + a= zrow[0][1]; zrow[0][1]= zrow[1][1]; zrow[1][1]= a; + a= zrow[0][2]; zrow[0][2]= zrow[1][2]; zrow[1][2]= a; } - if(addpassflag) - add_transp_passes(rl, od, &shpi.shr, 1.0f); - - if(addpassflag & SCE_PASS_VECTOR) - add_transp_speed(rl, od, shpi.shr.winspeed, pass[3], rdrect); - - if(addzbuf) - if(pa->rectz[od]>zrow[0][0]) - pa->rectz[od]= zrow[0][0]; } - else { - - if(totface==2) { - if(zrow[0][0] < zrow[1][0]) { - a= zrow[0][0]; zrow[0][0]= zrow[1][0]; zrow[1][0]= a; - a= zrow[0][1]; zrow[0][1]= zrow[1][1]; zrow[1][1]= a; - a= zrow[0][2]; zrow[0][2]= zrow[1][2]; zrow[1][2]= a; - } + else if(totface>2) { + qsort(zrow, totface, sizeof(int)*3, vergzvlak); + } + + if(addzbuf) + if(pa->rectz[od]>zrow[totface-1][0]) + pa->rectz[od]= zrow[totface-1][0]; + + if(R.osa==0) { + while(totface>0) { + totface--; - } - else { /* totface>2 */ - qsort(zrow, totface, sizeof(int)*3, vergzvlak); - } - - if(addzbuf) - if(pa->rectz[od]>zrow[totface-1][0]) - pa->rectz[od]= zrow[totface-1][0]; - - if(R.osa==0) { - while(totface>0) { - totface--; - - shadetrapixel(&shpi, (float)x, (float)y, zrow[totface][0], zrow[totface][1], zrow[totface][2]); - addAlphaUnderFloat(pass, shpi.shr.combined); + if(shade_tra_samples(&ssamp, x, y, zrow[totface][0], zrow[totface][1], zrow[totface][2])) { if(addpassflag) - add_transp_passes(rl, od, &shpi.shr, 1.0f); + add_transp_passes(rl, od, ssamp.shr, (1.0f-pass[3])*ssamp.shr[0].combined[3]); + addAlphaUnderFloat(pass, ssamp.shr[0].combined); if(pass[3]>=0.999) break; } - if(addpassflag & SCE_PASS_VECTOR) - add_transp_speed(rl, od, shpi.shr.winspeed, pass[3], rdrect); } - else { - /* for each mask-sample we alpha-under colors. then in end it's added using filter */ - memset(samp_shr, 0, sizeof(ShadeResult)*R.osa); + if(addpassflag & SCE_PASS_VECTOR) + add_transp_speed(rl, od, ssamp.shr[0].winspeed, pass[3], rdrect); + } + else { + short filled, *sp= ztramask+od; + + /* for each mask-sample we alpha-under colors. then in end it's added using filter */ + memset(samp_shr, 0, sizeof(ShadeResult)*R.osa); - while(totface>0) { - totface--; - - shadetrapixel(&shpi, (float)x, (float)y, zrow[totface][0], zrow[totface][1], zrow[totface][2]); - sval= addtosamp_shr(samp_shr, &shpi.shr, zrow[totface][2], addpassflag); - - if(sval==0) break; - } - - for(a=0; a<R.osa; a++) { - add_filt_fmask(1<<a, samp_shr[a].combined, pass, rr->rectx); - - if(addpassflag) - add_transp_passes(rl, od, samp_shr+a, sampalpha); - } + while(totface>0) { + totface--; - if(addpassflag & SCE_PASS_VECTOR) { - fac= 0.0f; - for(a=0; a<R.osa; a++) - fac+= samp_shr[a].combined[3]; - add_transp_speed(rl, od, samp_shr[0].winspeed, fac*sampalpha, rdrect); + if(shade_tra_samples(&ssamp, x, y, zrow[totface][0], zrow[totface][1], zrow[totface][2])) { + filled= addtosamp_shr(samp_shr, &ssamp, addpassflag); + + if(ztramask) + *sp |= zrow[totface][2]; + if(filled==0) + break; } } + + for(a=0; a<R.osa; a++) { + add_filt_fmask(1<<a, samp_shr[a].combined, pass, rr->rectx); + } + + if(addpassflag) { + /* merge all in one, and then add */ + merge_transp_passes(rl, samp_shr); + add_transp_passes(rl, od, samp_shr, pass[3]); + + if(addpassflag & SCE_PASS_VECTOR) + add_transp_speed(rl, od, samp_shr[0].winspeed, pass[3], rdrect); + } } } } @@ -3009,6 +3145,7 @@ void zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pass) if(R.r.mode & R_SHADOW) ISB_free(pa); + return ztramask; } /* *************** */ |