diff options
Diffstat (limited to 'source/blender/render/intern/source/shadeinput.c')
-rw-r--r-- | source/blender/render/intern/source/shadeinput.c | 1490 |
1 files changed, 1490 insertions, 0 deletions
diff --git a/source/blender/render/intern/source/shadeinput.c b/source/blender/render/intern/source/shadeinput.c new file mode 100644 index 00000000000..d79749871c3 --- /dev/null +++ b/source/blender/render/intern/source/shadeinput.c @@ -0,0 +1,1490 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2006 Blender Foundation + * All rights reserved. + * + * Contributors: Hos, Robert Wenzlaff. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/source/shadeinput.c + * \ingroup render + */ + + +#include <stdio.h> +#include <math.h> +#include <string.h> + + +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "DNA_lamp_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_material_types.h" +#include "DNA_particle_types.h" + +#include "BKE_scene.h" + +#include "BKE_node.h" + +/* local include */ +#include "raycounter.h" +#include "render_types.h" +#include "renderdatabase.h" +#include "rendercore.h" +#include "shading.h" +#include "strand.h" +#include "texture.h" +#include "volumetric.h" +#include "zbuf.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; +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +/* 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 AO + * - shade_samples_do_AO() + * - if shading happens + * - for each sample + * - shade_input_set_shade_texco() + * - shade_samples_do_shade() + * - OSA: distribute sample result with filter masking + * + */ + +/* initialize material variables in shadeinput, + * doing inverse gamma correction where applicable */ +void shade_input_init_material(ShadeInput *shi) +{ + /* note, keep this synced with render_types.h */ + memcpy(&shi->r, &shi->mat->r, 23 * sizeof(float)); + shi->har = shi->mat->har; +} + +/* 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; + + shade_input_init_material(shi); + negate_v3_v3(shi->vn, shi->vno); + negate_v3(shi->facenor); + shi->depth++; /* hack to get real shadow now */ + shade_lamp_loop(shi, &shr_t); + shi->depth--; + + /* a couple of passes */ + madd_v3_v3fl(shr->combined, shr_t.combined, fac); + if (shi->passflag & SCE_PASS_SPEC) + madd_v3_v3fl(shr->spec, shr_t.spec, fac); + if (shi->passflag & SCE_PASS_DIFFUSE) { + madd_v3_v3fl(shr->diff, shr_t.diff, fac); + madd_v3_v3fl(shr->diffshad, shr_t.diffshad, fac); + } + if (shi->passflag & SCE_PASS_SHADOW) + madd_v3_v3fl(shr->shad, shr_t.shad, fac); + + negate_v3(shi->vn); + negate_v3(shi->facenor); + } + + /* depth >= 1 when ray-shading */ + if (shi->depth == 0 || shi->volume_depth > 0) { + if (R.r.mode & R_RAYTRACE) { + if (shi->ray_mirror != 0.0f || ((shi->mode & MA_TRANSP) && (shi->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->mode & MA_TRANSP) && (shi->mode & MA_RAYTRANSP)) + if ((shi->layflag & SCE_LAY_SKY) && (R.r.alphamode == R_ADDSKY)) + shr->alpha = 1.0f; + } + + if (R.r.mode & R_RAYTRACE) { + if (R.render_volumes_inside.first) + shade_volume_inside(shi, shr); + } +} + + +/* do a shade, finish up some passes, apply mist */ +void shade_input_do_shade(ShadeInput *shi, ShadeResult *shr) +{ + bool compat = false; + float alpha; + + /* ------ main shading loop -------- */ +#ifdef RE_RAYCOUNTER + memset(&shi->raycounter, 0, sizeof(shi->raycounter)); +#endif + + if (shi->mat->nodetree && shi->mat->use_nodes) { + compat = ntreeShaderExecTree(shi->mat->nodetree, shi, shr); + } + + /* also run this when node shaders fail, due to incompatible shader nodes */ + if (compat == false) { + /* copy all relevant material vars, note, keep this synced with render_types.h */ + shade_input_init_material(shi); + + if (shi->mat->material_type == MA_TYPE_VOLUME) { + if (R.r.mode & R_RAYTRACE) { + shade_volume_outside(shi, shr); + } + } + else { /* MA_TYPE_SURFACE, MA_TYPE_WIRE */ + shade_material_loop(shi, shr); + } + } + + /* copy additional passes */ + if (shi->passflag & (SCE_PASS_VECTOR | SCE_PASS_NORMAL)) { + copy_v4_v4(shr->winspeed, shi->winspeed); + copy_v3_v3(shr->nor, shi->vn); + } + + /* MIST */ + if ((shi->passflag & SCE_PASS_MIST) || ((R.wrld.mode & WO_MIST) && (shi->mat->mode & MA_NOMIST) == 0)) { + if (R.r.mode & R_ORTHO) + shr->mist = mistfactor(-shi->co[2], shi->co); + else + shr->mist = mistfactor(len_v3(shi->co), shi->co); + } + else shr->mist = 0.0f; + + if ((R.wrld.mode & WO_MIST) && (shi->mat->mode & MA_NOMIST) == 0) { + alpha = shr->mist; + } + 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; + + if (shi->mat->material_type != MA_TYPE_VOLUME) + mul_v3_fl(shr->combined, fac); + } + else + shr->combined[3] = 1.0f; + + /* add z */ + shr->z = -shi->co[2]; + + /* RAYHITS */ +#if 0 + if (1 || shi->passflag & SCE_PASS_RAYHITS) { + shr->rayhits[0] = (float)shi->raycounter.faces.test; + shr->rayhits[1] = (float)shi->raycounter.bb.hit; + shr->rayhits[2] = 0.0; + shr->rayhits[3] = 1.0; + } +#endif + + RE_RC_MERGE(&re_rc_counter[shi->thread], &shi->raycounter); +} + +/* **************************************************************************** */ +/* 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 */ +void shade_input_set_triangle_i(ShadeInput *shi, ObjectInstanceRen *obi, VlakRen *vlr, short i1, short i2, short i3) +{ + VertRen **vpp = &vlr->v1; + + shi->vlr = vlr; + shi->obi = obi; + shi->obr = obi->obr; + + shi->v1 = vpp[i1]; + shi->v2 = vpp[i2]; + shi->v3 = vpp[i3]; + + shi->i1 = i1; + shi->i2 = i2; + shi->i3 = i3; + + /* note, shi->mat is set in node shaders */ + shi->mat = shi->mat_override ? shi->mat_override : vlr->mat; + + shi->osatex = (shi->mat->texco & TEXCO_OSA); + shi->mode = shi->mat->mode_l; /* or-ed result for all nodes */ + shi->mode2 = shi->mat->mode2_l; + + /* facenormal copy, can get flipped */ + shi->flippednor = 0; + RE_vlakren_get_normal(&R, obi, vlr, shi->facenor); + + /* calculate vertexnormals */ + if (vlr->flag & R_SMOOTH) { + copy_v3_v3(shi->n1, shi->v1->n); + copy_v3_v3(shi->n2, shi->v2->n); + copy_v3_v3(shi->n3, shi->v3->n); + + if (obi->flag & R_TRANSFORMED) { + mul_m3_v3(obi->nmat, shi->n1); normalize_v3(shi->n1); + mul_m3_v3(obi->nmat, shi->n2); normalize_v3(shi->n2); + mul_m3_v3(obi->nmat, shi->n3); normalize_v3(shi->n3); + } + } +} + +/* copy data from face to ShadeInput, scanline case */ +void shade_input_set_triangle(ShadeInput *shi, int obi, int facenr, int UNUSED(normal_flip)) +{ + if (facenr > 0) { + shi->obi = &R.objectinstance[obi]; + shi->obr = shi->obi->obr; + shi->facenr = (facenr - 1) & RE_QUAD_MASK; + if (shi->facenr < shi->obr->totvlak) { + VlakRen *vlr = RE_findOrAddVlak(shi->obr, shi->facenr); + + if (facenr & RE_QUAD_OFFS) + shade_input_set_triangle_i(shi, shi->obi, vlr, 0, 2, 3); + else + shade_input_set_triangle_i(shi, shi->obi, 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)); +} + +/* copy data from strand to shadeinput */ +void shade_input_set_strand(ShadeInput *shi, StrandRen *strand, StrandPoint *spoint) +{ + /* note, shi->mat is set in node shaders */ + shi->mat = shi->mat_override ? shi->mat_override : strand->buffer->ma; + + shi->osatex = (shi->mat->texco & TEXCO_OSA); + shi->mode = shi->mat->mode_l; /* or-ed result for all nodes */ + + /* shade_input_set_viewco equivalent */ + copy_v3_v3(shi->co, spoint->co); + copy_v3_v3(shi->view, shi->co); + normalize_v3(shi->view); + + shi->xs = (int)spoint->x; + shi->ys = (int)spoint->y; + + if (shi->osatex || (R.r.mode & R_SHADOW)) { + copy_v3_v3(shi->dxco, spoint->dtco); + copy_v3_v3(shi->dyco, spoint->dsco); + } + + /* dxview, dyview, not supported */ + + /* facenormal, simply viewco flipped */ + copy_v3_v3(shi->facenor, spoint->nor); + + /* shade_input_set_normals equivalent */ + if (shi->mat->mode & MA_TANGENT_STR) { + copy_v3_v3(shi->vn, spoint->tan); + } + else { + float cross[3]; + + cross_v3_v3v3(cross, spoint->co, spoint->tan); + cross_v3_v3v3(shi->vn, cross, spoint->tan); + normalize_v3(shi->vn); + + if (dot_v3v3(shi->vn, shi->view) < 0.0f) + negate_v3(shi->vn); + } + + copy_v3_v3(shi->vno, shi->vn); +} + +void shade_input_set_strand_texco(ShadeInput *shi, StrandRen *strand, StrandVert *svert, StrandPoint *spoint) +{ + StrandBuffer *strandbuf = strand->buffer; + ObjectRen *obr = strandbuf->obr; + StrandVert *sv; + int mode = shi->mode; /* or-ed result for all nodes */ + short texco = shi->mat->texco; + + if ((shi->mat->texco & TEXCO_REFL)) { + /* shi->dxview, shi->dyview, not supported */ + } + + if (shi->osatex && (texco & (TEXCO_NORM | TEXCO_REFL))) { + /* not supported */ + } + + if (mode & (MA_TANGENT_V | MA_NORMAP_TANG)) { + copy_v3_v3(shi->tang, spoint->tan); + copy_v3_v3(shi->nmaptang, spoint->tan); + } + + if (mode & MA_STR_SURFDIFF) { + const float *surfnor = RE_strandren_get_surfnor(obr, strand, 0); + + if (surfnor) + copy_v3_v3(shi->surfnor, surfnor); + else + copy_v3_v3(shi->surfnor, shi->vn); + + if (shi->mat->strand_surfnor > 0.0f) { + shi->surfdist = 0.0f; + for (sv = strand->vert; sv != svert; sv++) + shi->surfdist += len_v3v3(sv->co, (sv + 1)->co); + shi->surfdist += spoint->t * len_v3v3(sv->co, (sv + 1)->co); + } + } + + if (R.r.mode & R_SPEED) { + const float *speed; + + speed = RE_strandren_get_winspeed(shi->obi, strand, 0); + if (speed) + copy_v4_v4(shi->winspeed, speed); + else + shi->winspeed[0] = shi->winspeed[1] = shi->winspeed[2] = shi->winspeed[3] = 0.0f; + } + + /* shade_input_set_shade_texco equivalent */ + if (texco & NEED_UV) { + if (texco & TEXCO_ORCO) { + copy_v3_v3(shi->lo, strand->orco); + /* no shi->osatex, orco derivatives are zero */ + } + + if (texco & TEXCO_GLOB) { + mul_v3_m4v3(shi->gl, R.viewinv, shi->co); + + if (shi->osatex) { + mul_v3_mat3_m4v3(shi->dxgl, R.viewinv, shi->dxco); + mul_v3_mat3_m4v3(shi->dygl, R.viewinv, shi->dyco); + } + } + + if (texco & TEXCO_STRAND) { + shi->strandco = spoint->strandco; + + if (shi->osatex) { + shi->dxstrand = spoint->dtstrandco; + shi->dystrand = 0.0f; + } + } + + if ((texco & TEXCO_UV) || (mode & (MA_VERTEXCOL | MA_VERTEXCOLP | MA_FACETEXTURE))) { + MCol *mcol; + const float *uv; + char *name; + int i; + + shi->totuv = 0; + shi->totcol = 0; + shi->actuv = obr->actmtface; + shi->actcol = obr->actmcol; + + if (mode & (MA_VERTEXCOL | MA_VERTEXCOLP)) { + for (i = 0; (mcol = RE_strandren_get_mcol(obr, strand, i, &name, 0)); i++) { + ShadeInputCol *scol = &shi->col[i]; + const char *cp = (char *)mcol; + + shi->totcol++; + scol->name = name; + + scol->col[0] = cp[3] / 255.0f; + scol->col[1] = cp[2] / 255.0f; + scol->col[2] = cp[1] / 255.0f; + scol->col[3] = cp[0] / 255.0f; + } + + if (shi->totcol) { + shi->vcol[0] = shi->col[shi->actcol].col[0]; + shi->vcol[1] = shi->col[shi->actcol].col[1]; + shi->vcol[2] = shi->col[shi->actcol].col[2]; + shi->vcol[3] = shi->col[shi->actcol].col[3]; + } + else { + shi->vcol[0] = 0.0f; + shi->vcol[1] = 0.0f; + shi->vcol[2] = 0.0f; + shi->vcol[3] = 0.0f; + } + } + + for (i = 0; (uv = RE_strandren_get_uv(obr, strand, i, &name, 0)); i++) { + ShadeInputUV *suv = &shi->uv[i]; + + shi->totuv++; + suv->name = name; + + if (strandbuf->overrideuv == i) { + suv->uv[0] = -1.0f; + suv->uv[1] = spoint->strandco; + suv->uv[2] = 0.0f; + } + else { + suv->uv[0] = -1.0f + 2.0f * uv[0]; + suv->uv[1] = -1.0f + 2.0f * uv[1]; + suv->uv[2] = 0.0f; /* texture.c assumes there are 3 coords */ + } + + if (shi->osatex) { + suv->dxuv[0] = 0.0f; + suv->dxuv[1] = 0.0f; + suv->dyuv[0] = 0.0f; + suv->dyuv[1] = 0.0f; + } + + if ((mode & MA_FACETEXTURE) && i == obr->actmtface) { + if ((mode & (MA_VERTEXCOL | MA_VERTEXCOLP)) == 0) { + shi->vcol[0] = 1.0f; + shi->vcol[1] = 1.0f; + shi->vcol[2] = 1.0f; + shi->vcol[3] = 1.0f; + } + } + } + + if (shi->totuv == 0) { + ShadeInputUV *suv = &shi->uv[0]; + + suv->uv[0] = 0.0f; + suv->uv[1] = spoint->strandco; + suv->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; + shi->vcol[3] = 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 (texco & TEXCO_STRESS) { + /* not supported */ + } + + if (texco & TEXCO_TANGENT) { + if ((mode & MA_TANGENT_V) == 0) { + /* just prevent surprises */ + shi->tang[0] = shi->tang[1] = shi->tang[2] = 0.0f; + shi->nmaptang[0] = shi->nmaptang[1] = shi->nmaptang[2] = 0.0f; + } + } + } + + /* this only avalailable for scanline renders */ + if (shi->depth == 0) { + if (texco & TEXCO_WINDOW) { + shi->winco[0] = -1.0f + 2.0f * spoint->x / (float)R.winx; + shi->winco[1] = -1.0f + 2.0f * spoint->y / (float)R.winy; + shi->winco[2] = 0.0f; + + /* not supported */ + if (shi->osatex) { + shi->dxwin[0] = 0.0f; + shi->dywin[1] = 0.0f; + shi->dxwin[0] = 0.0f; + shi->dywin[1] = 0.0f; + } + } + } + + if (shi->do_manage) { + if (mode & (MA_VERTEXCOL | MA_VERTEXCOLP | MA_FACETEXTURE)) { + srgb_to_linearrgb_v3_v3(shi->vcol, shi->vcol); + } + } + +} + +/* from scanline pixel coordinates to 3d coordinates, requires set_triangle */ +void shade_input_calc_viewco(ShadeInput *shi, float x, float y, float z, float view[3], float dxyview[2], float co[3], float dxco[3], float dyco[3]) +{ + /* returns not normalized, so is in viewplane coords */ + calc_view_vector(view, x, y); + + if (shi->mat->material_type == MA_TYPE_WIRE) { + /* wire cannot use normal for calculating shi->co, so + * we reconstruct the coordinate less accurate */ + if (R.r.mode & R_ORTHO) + calc_renderco_ortho(co, x, y, z); + else + calc_renderco_zbuf(co, view, z); + } + else { + /* for non-wire, intersect with the triangle to get the exact coord */ + float fac, dface, v1[3]; + + copy_v3_v3(v1, shi->v1->co); + if (shi->obi->flag & R_TRANSFORMED) + mul_m4_v3(shi->obi->mat, v1); + + dface = dot_v3v3(v1, shi->facenor); + + /* 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]); + + 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]; + + /* using a*x + b*y + c*z = d equation, (a b c) is normal */ + if (shi->facenor[2] != 0.0f) + co[2] = (dface - shi->facenor[0] * co[0] - shi->facenor[1] * co[1]) / shi->facenor[2]; + else + co[2] = 0.0f; + + if (dxco && dyco) { + dxco[0] = fx; + dxco[1] = 0.0f; + if (shi->facenor[2] != 0.0f) + dxco[2] = -(shi->facenor[0] * fx) / shi->facenor[2]; + else + dxco[2] = 0.0f; + + dyco[0] = 0.0f; + dyco[1] = fy; + if (shi->facenor[2] != 0.0f) + dyco[2] = -(shi->facenor[1] * fy) / shi->facenor[2]; + else + dyco[2] = 0.0f; + + if (dxyview) { + fac = (co[2] != 0.0f) ? (1.0f / co[2]) : 0.0f; + dxyview[0] = -R.viewdx * fac; + dxyview[1] = -R.viewdy * fac; + } + } + } + else { + float div; + + div = dot_v3v3(shi->facenor, view); + if (div != 0.0f) fac = dface / div; + else fac = 0.0f; + + co[0] = fac * view[0]; + co[1] = fac * view[1]; + co[2] = fac * view[2]; + + /* pixel dx/dy for render coord */ + if (dxco && dyco) { + float u = dface / (div - R.viewdx * shi->facenor[0]); + float v = dface / (div - R.viewdy * shi->facenor[1]); + + dxco[0] = co[0] - (view[0] - R.viewdx) * u; + dxco[1] = co[1] - (view[1]) * u; + dxco[2] = co[2] - (view[2]) * u; + + dyco[0] = co[0] - (view[0]) * v; + dyco[1] = co[1] - (view[1] - R.viewdy) * v; + dyco[2] = co[2] - (view[2]) * v; + + if (dxyview) { + if (fac != 0.0f) fac = 1.0f / fac; + dxyview[0] = -R.viewdx * fac; + dxyview[1] = -R.viewdy * fac; + } + } + } + } + + /* set camera coords - for scanline, it's always 0.0,0.0,0.0 (render is in camera space) + * however for raytrace it can be different - the position of the last intersection */ + shi->camera_co[0] = shi->camera_co[1] = shi->camera_co[2] = 0.0f; + + /* cannot normalize earlier, code above needs it at viewplane level */ + normalize_v3(view); +} + +/* from scanline pixel coordinates to 3d coordinates, requires set_triangle */ +void shade_input_set_viewco(ShadeInput *shi, float x, float y, float xs, float ys, float z) +{ + float *dxyview = NULL, *dxco = NULL, *dyco = NULL; + + /* currently in use for dithering (soft shadow), node preview, irregular shad */ + shi->xs = (int)xs; + shi->ys = (int)ys; + + /* original scanline coordinate without jitter */ + shi->scanco[0] = x; + shi->scanco[1] = y; + shi->scanco[2] = z; + + /* check if we need derivatives */ + if (shi->osatex || (R.r.mode & R_SHADOW)) { + dxco = shi->dxco; + dyco = shi->dyco; + + if ((shi->mat->texco & TEXCO_REFL)) + dxyview = &shi->dxview; + } + + shade_input_calc_viewco(shi, xs, ys, z, shi->view, dxyview, shi->co, dxco, dyco); +} + +void barycentric_differentials_from_position( + const float co[3], const float v1[3], const float v2[3], const float v3[3], + const float dxco[3], const float dyco[3], const float facenor[3], const bool differentials, + float *u, float *v, float *dx_u, float *dx_v, float *dy_u, float *dy_v) +{ + /* find most stable axis to project */ + int axis1, axis2; + axis_dominant_v3(&axis1, &axis2, facenor); + + /* compute u,v and derivatives */ + float t00 = v3[axis1] - v1[axis1]; + float t01 = v3[axis2] - v1[axis2]; + float t10 = v3[axis1] - v2[axis1]; + float t11 = v3[axis2] - v2[axis2]; + + float detsh = (t00 * t11 - t10 * t01); + detsh = (detsh != 0.0f) ? 1.0f / detsh : 0.0f; + t00 *= detsh; t01 *= detsh; + t10 *= detsh; t11 *= detsh; + + *u = (v3[axis1] - co[axis1]) * t11 - (v3[axis2] - co[axis2]) * t10; + *v = (v3[axis2] - co[axis2]) * t00 - (v3[axis1] - co[axis1]) * t01; + if (differentials) { + *dx_u = dxco[axis1] * t11 - dxco[axis2] * t10; + *dx_v = dxco[axis2] * t00 - dxco[axis1] * t01; + *dy_u = dyco[axis1] * t11 - dyco[axis2] * t10; + *dy_v = dyco[axis2] * t00 - dyco[axis1] * t01; + } +} +/* 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) || (shi->passflag & SCE_PASS_UV)) { + float v1[3], v2[3], v3[3]; + + copy_v3_v3(v1, shi->v1->co); + copy_v3_v3(v2, shi->v2->co); + copy_v3_v3(v3, shi->v3->co); + + if (shi->obi->flag & R_TRANSFORMED) { + mul_m4_v3(shi->obi->mat, v1); + mul_m4_v3(shi->obi->mat, v2); + mul_m4_v3(shi->obi->mat, v3); + } + + /* exception case for wire render of edge */ + if (vlr->v2 == vlr->v3) { + float lend, lenc; + + lend = len_v3v3(v2, v1); + lenc = len_v3v3(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 { + barycentric_differentials_from_position( + shi->co, v1, v2, v3, shi->dxco, shi->dyco, shi->facenor, shi->osatex, + &shi->u, &shi->v, &shi->dx_u, &shi->dx_v, &shi->dy_u, &shi->dy_v); + + shi->u = -shi->u; + shi->v = -shi->v; + + /* 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; + + shi->flippednor = 0; + + /* test flip normals to viewing direction */ + if (!(shi->vlr->flag & R_TANGENT)) { + if (dot_v3v3(shi->facenor, shi->view) < 0.0f) { + negate_v3(shi->facenor); + shi->flippednor = 1; + } + } + + /* calculate vertexnormals */ + if (shi->vlr->flag & R_SMOOTH) { + float *n1 = shi->n1, *n2 = shi->n2, *n3 = shi->n3; + + if (shi->flippednor) { + negate_v3(n1); + negate_v3(n2); + negate_v3(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]; + + /* use unnormalized normal (closer to games) */ + copy_v3_v3(shi->nmapnorm, shi->vn); + + normalize_v3(shi->vn); + } + else { + copy_v3_v3(shi->vn, shi->facenor); + copy_v3_v3(shi->nmapnorm, shi->vn); + } + + /* used in nodes */ + copy_v3_v3(shi->vno, shi->vn); + + /* flip normals to viewing direction */ + if (!(shi->vlr->flag & R_TANGENT)) + if (dot_v3v3(shi->facenor, shi->view) < 0.0f) + shade_input_flip_normals(shi); +} + +/* XXX shi->flippednor messes up otherwise */ +void shade_input_set_vertex_normals(ShadeInput *shi) +{ + float u = shi->u, v = shi->v; + float l = 1.0f + u + v; + + /* calculate vertexnormals */ + if (shi->vlr->flag & R_SMOOTH) { + const 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]; + + /* use unnormalized normal (closer to games) */ + copy_v3_v3(shi->nmapnorm, shi->vn); + + normalize_v3(shi->vn); + } + else { + copy_v3_v3(shi->vn, shi->facenor); + copy_v3_v3(shi->nmapnorm, shi->vn); + } + + /* used in nodes */ + copy_v3_v3(shi->vno, shi->vn); +} + + +/* use by raytrace, sss, bake to flip into the right direction */ +void shade_input_flip_normals(ShadeInput *shi) +{ + negate_v3(shi->facenor); + negate_v3(shi->vn); + negate_v3(shi->vno); + negate_v3(shi->nmapnorm); + shi->flippednor = !shi->flippednor; +} + +void shade_input_set_shade_texco(ShadeInput *shi) +{ + ObjectInstanceRen *obi = shi->obi; + ObjectRen *obr = shi->obr; + 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; /* or-ed result for all nodes */ + int mode2 = shi->mode2; + short texco = shi->mat->texco; + const bool need_mikk_tangent = (mode & MA_NORMAP_TANG || R.flag & R_NEED_TANGENT); + const bool need_mikk_tangent_concrete = (mode2 & MA_TANGENT_CONCRETE) != 0; + + /* calculate dxno */ + if (shi->vlr->flag & R_SMOOTH) { + + if (shi->osatex && (texco & (TEXCO_NORM | TEXCO_REFL)) ) { + const 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]; + + } + } + + /* calc tangents */ + if (mode & (MA_TANGENT_V | MA_NORMAP_TANG) || mode2 & MA_TANGENT_CONCRETE || R.flag & R_NEED_TANGENT) { + const float *s1, *s2, *s3; + float tl, tu, tv; + + if (shi->vlr->flag & R_SMOOTH) { + tl = l; + tu = u; + tv = v; + } + else { + /* qdn: flat faces have tangents too, + * could pick either one, using average here */ + tl = 1.0f / 3.0f; + tu = -1.0f / 3.0f; + tv = -1.0f / 3.0f; + } + + shi->tang[0] = shi->tang[1] = shi->tang[2] = 0.0f; + shi->nmaptang[0] = shi->nmaptang[1] = shi->nmaptang[2] = 0.0f; + + if (mode & MA_TANGENT_V) { + s1 = RE_vertren_get_tangent(obr, v1, 0); + s2 = RE_vertren_get_tangent(obr, v2, 0); + s3 = RE_vertren_get_tangent(obr, v3, 0); + + if (s1 && s2 && s3) { + shi->tang[0] = (tl * s3[0] - tu * s1[0] - tv * s2[0]); + shi->tang[1] = (tl * s3[1] - tu * s1[1] - tv * s2[1]); + shi->tang[2] = (tl * s3[2] - tu * s1[2] - tv * s2[2]); + + if (obi->flag & R_TRANSFORMED) + mul_m3_v3(obi->nmat, shi->tang); + + normalize_v3(shi->tang); + copy_v3_v3(shi->nmaptang, shi->tang); + } + } + + if (need_mikk_tangent || need_mikk_tangent_concrete) { + int j1 = shi->i1, j2 = shi->i2, j3 = shi->i3; + float c0[3], c1[3], c2[3]; + int acttang = obr->actmtface; + + vlr_set_uv_indices(shi->vlr, &j1, &j2, &j3); + + /* cycle through all tangent in vlakren */ + for (int i = 0; i < MAX_MTFACE; i++) { + const float *tangent = RE_vlakren_get_nmap_tangent(obr, shi->vlr, i, false); + if (!tangent) + continue; + + copy_v3_v3(c0, &tangent[j1 * 4]); + copy_v3_v3(c1, &tangent[j2 * 4]); + copy_v3_v3(c2, &tangent[j3 * 4]); + + /* keeping tangents normalized at vertex level + * corresponds better to how it's done in game engines */ + if (obi->flag & R_TRANSFORMED) { + mul_mat3_m4_v3(obi->mat, c0); normalize_v3(c0); + mul_mat3_m4_v3(obi->mat, c1); normalize_v3(c1); + mul_mat3_m4_v3(obi->mat, c2); normalize_v3(c2); + } + + /* we don't normalize the interpolated TBN tangent + * corresponds better to how it's done in game engines */ + shi->tangents[i][0] = (tl * c2[0] - tu * c0[0] - tv * c1[0]); + shi->tangents[i][1] = (tl * c2[1] - tu * c0[1] - tv * c1[1]); + shi->tangents[i][2] = (tl * c2[2] - tu * c0[2] - tv * c1[2]); + + /* the sign is the same for all 3 vertices of any + * non degenerate triangle. */ + shi->tangents[i][3] = tangent[j1 * 4 + 3]; + + if (acttang == i && need_mikk_tangent) { + for (int m = 0; m < 4; m++) { + shi->nmaptang[m] = shi->tangents[i][m]; + } + } + } + } + } + + if (mode & MA_STR_SURFDIFF) { + const float *surfnor = RE_vlakren_get_surfnor(obr, shi->vlr, 0); + + if (surfnor) { + copy_v3_v3(shi->surfnor, surfnor); + if (obi->flag & R_TRANSFORMED) + mul_m3_v3(obi->nmat, shi->surfnor); + } + else + copy_v3_v3(shi->surfnor, shi->vn); + + shi->surfdist = 0.0f; + } + + if (R.r.mode & R_SPEED) { + const float *s1, *s2, *s3; + + s1 = RE_vertren_get_winspeed(obi, v1, 0); + s2 = RE_vertren_get_winspeed(obi, v2, 0); + s3 = RE_vertren_get_winspeed(obi, 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; + } + } + + /* pass option forces UV calc */ + if ((shi->passflag & SCE_PASS_UV) || (R.flag & R_NEED_VCOL)) + texco |= (NEED_UV | TEXCO_UV); + + /* texture coordinates. shi->dxuv shi->dyuv have been set */ + if (texco & NEED_UV) { + + if (texco & TEXCO_ORCO) { + if (v1->orco) { + const 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]; + } + } + + copy_v3_v3(shi->duplilo, obi->dupliorco); + } + + if (texco & TEXCO_GLOB) { + copy_v3_v3(shi->gl, shi->co); + mul_m4_v3(R.viewinv, shi->gl); + if (shi->osatex) { + copy_v3_v3(shi->dxgl, shi->dxco); + mul_mat3_m4_v3(R.viewinv, shi->dxgl); + copy_v3_v3(shi->dygl, shi->dyco); + mul_mat3_m4_v3(R.viewinv, shi->dygl); + } + } + + if (texco & TEXCO_STRAND) { + shi->strandco = (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)) || (R.flag & R_NEED_VCOL)) { + VlakRen *vlr = shi->vlr; + MTFace *tface; + MCol *mcol; + char *name; + int i, 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); + + shi->totuv = 0; + shi->totcol = 0; + shi->actuv = obr->actmtface; + shi->actcol = obr->actmcol; + + if ((mode & (MA_VERTEXCOL | MA_VERTEXCOLP)) || (R.flag & R_NEED_VCOL)) { + for (i = 0; (mcol = RE_vlakren_get_mcol(obr, vlr, i, &name, 0)); i++) { + ShadeInputCol *scol = &shi->col[i]; + const char *cp1, *cp2, *cp3; + float a[3]; + + shi->totcol++; + scol->name = name; + + cp1 = (char *)(mcol + j1); + cp2 = (char *)(mcol + j2); + cp3 = (char *)(mcol + j3); + + /* alpha values */ + a[0] = ((float)cp1[0]) / 255.f; + a[1] = ((float)cp2[0]) / 255.f; + a[2] = ((float)cp3[0]) / 255.f; + scol->col[3] = l * a[2] - u * a[0] - v * a[1]; + + /* sample premultiplied color value */ + scol->col[0] = (l * ((float)cp3[3]) * a[2] - u * ((float)cp1[3]) * a[0] - v * ((float)cp2[3]) * a[1]) / 255.f; + scol->col[1] = (l * ((float)cp3[2]) * a[2] - u * ((float)cp1[2]) * a[0] - v * ((float)cp2[2]) * a[1]) / 255.f; + scol->col[2] = (l * ((float)cp3[1]) * a[2] - u * ((float)cp1[1]) * a[0] - v * ((float)cp2[1]) * a[1]) / 255.f; + + /* if not zero alpha, restore non-multiplied color */ + if (scol->col[3]) { + mul_v3_fl(scol->col, 1.0f / scol->col[3]); + } + } + + if (shi->totcol) { + shi->vcol[0] = shi->col[shi->actcol].col[0]; + shi->vcol[1] = shi->col[shi->actcol].col[1]; + shi->vcol[2] = shi->col[shi->actcol].col[2]; + shi->vcol[3] = shi->col[shi->actcol].col[3]; + } + else { + shi->vcol[0] = 0.0f; + shi->vcol[1] = 0.0f; + shi->vcol[2] = 0.0f; + shi->vcol[3] = 1.0f; + } + } + + for (i = 0; (tface = RE_vlakren_get_tface(obr, vlr, i, &name, 0)); i++) { + ShadeInputUV *suv = &shi->uv[i]; + const float *uv1 = tface->uv[j1]; + const float *uv2 = tface->uv[j2]; + const float *uv3 = tface->uv[j3]; + + shi->totuv++; + suv->name = name; + + if ((shi->mat->mapflag & MA_MAPFLAG_UVPROJECT) && (shi->depth == 0)) { + float x = shi->xs; + float y = shi->ys; + + float s1[2] = {-1.0f + 2.0f * uv1[0], -1.0f + 2.0f * uv1[1]}; + float s2[2] = {-1.0f + 2.0f * uv2[0], -1.0f + 2.0f * uv2[1]}; + float s3[2] = {-1.0f + 2.0f * uv3[0], -1.0f + 2.0f * uv3[1]}; + + + float obwinmat[4][4], winmat[4][4], ho1[4], ho2[4], ho3[4]; + float Zmulx, Zmuly; + float hox, hoy, l_proj, dl_proj, u_proj, v_proj; + float s00, s01, s10, s11, detsh; + + /* old globals, localized now */ + Zmulx = ((float)R.winx) / 2.0f; + Zmuly = ((float)R.winy) / 2.0f; + + zbuf_make_winmat(&R, winmat); + if (shi->obi->flag & R_TRANSFORMED) + mul_m4_m4m4(obwinmat, winmat, obi->mat); + else + copy_m4_m4(obwinmat, winmat); + + zbuf_render_project(obwinmat, v1->co, ho1); + zbuf_render_project(obwinmat, v2->co, ho2); + zbuf_render_project(obwinmat, v3->co, ho3); + + s00 = ho3[0] / ho3[3] - ho1[0] / ho1[3]; + s01 = ho3[1] / ho3[3] - ho1[1] / ho1[3]; + s10 = ho3[0] / ho3[3] - ho2[0] / ho2[3]; + s11 = ho3[1] / ho3[3] - ho2[1] / ho2[3]; + + detsh = s00 * s11 - s10 * s01; + detsh = (detsh != 0.0f) ? 1.0f / detsh : 0.0f; + s00 *= detsh; s01 *= detsh; + s10 *= detsh; s11 *= detsh; + + /* recalc u and v again */ + hox = x / Zmulx - 1.0f; + hoy = y / Zmuly - 1.0f; + u_proj = (hox - ho3[0] / ho3[3]) * s11 - (hoy - ho3[1] / ho3[3]) * s10; + v_proj = (hoy - ho3[1] / ho3[3]) * s00 - (hox - ho3[0] / ho3[3]) * s01; + l_proj = 1.0f + u_proj + v_proj; + + suv->uv[0] = l_proj * s3[0] - u_proj * s1[0] - v_proj * s2[0]; + suv->uv[1] = l_proj * s3[1] - u_proj * s1[1] - v_proj * s2[1]; + suv->uv[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_proj = dxuv[0] + dxuv[1]; + suv->dxuv[0] = dl_proj * s3[0] - dxuv[0] * s1[0] - dxuv[1] * s2[0]; + suv->dxuv[1] = dl_proj * s3[1] - dxuv[0] * s1[1] - dxuv[1] * s2[1]; + dl_proj = dyuv[0] + dyuv[1]; + suv->dyuv[0] = dl_proj * s3[0] - dyuv[0] * s1[0] - dyuv[1] * s2[0]; + suv->dyuv[1] = dl_proj * s3[1] - dyuv[0] * s1[1] - dyuv[1] * s2[1]; + } + } + else { + + suv->uv[0] = -1.0f + 2.0f * (l * uv3[0] - u * uv1[0] - v * uv2[0]); + suv->uv[1] = -1.0f + 2.0f * (l * uv3[1] - u * uv1[1] - v * uv2[1]); + suv->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; + + suv->dxuv[0] = 2.0f * (dl * uv3[0] - duv[0] * uv1[0] - duv[1] * uv2[0]); + suv->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; + + suv->dyuv[0] = 2.0f * (dl * uv3[0] - duv[0] * uv1[0] - duv[1] * uv2[0]); + suv->dyuv[1] = 2.0f * (dl * uv3[1] - duv[0] * uv1[1] - duv[1] * uv2[1]); + } + + if ((mode & MA_FACETEXTURE) && i == obr->actmtface) { + if (((mode & (MA_VERTEXCOL | MA_VERTEXCOLP)) == 0) && ((R.flag & R_NEED_VCOL) == 0)) { + shi->vcol[0] = 1.0f; + shi->vcol[1] = 1.0f; + shi->vcol[2] = 1.0f; + shi->vcol[3] = 1.0f; + } + if (tface->tpage) { + render_realtime_texture(shi, tface->tpage); + } + } + } + } + + shi->dupliuv[0] = -1.0f + 2.0f * obi->dupliuv[0]; + shi->dupliuv[1] = -1.0f + 2.0f * obi->dupliuv[1]; + shi->dupliuv[2] = 0.0f; + + if (shi->totuv == 0) { + ShadeInputUV *suv = &shi->uv[0]; + + suv->uv[0] = 2.0f * (u + .5f); + suv->uv[1] = 2.0f * (v + .5f); + suv->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; + shi->vcol[3] = 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 (texco & TEXCO_STRESS) { + const float *s1, *s2, *s3; + + s1 = RE_vertren_get_stress(obr, v1, 0); + s2 = RE_vertren_get_stress(obr, v2, 0); + s3 = RE_vertren_get_stress(obr, 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; + shi->nmaptang[0] = shi->nmaptang[1] = shi->nmaptang[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; + } + } + } + /* else { + * Note! For raytracing winco is not set, + * important because thus means all shader input's need to have their variables set to zero + * else un-initialized values are used + */ + if (shi->do_manage) { + if ((mode & (MA_VERTEXCOL | MA_VERTEXCOLP | MA_FACETEXTURE)) || (R.flag & R_NEED_VCOL)) { + srgb_to_linearrgb_v3_v3(shi->vcol, shi->vcol); + } + } + +} + +/* ****************** ShadeSample ************************************** */ + +/* initialize per part, not per pixel! */ +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_MATNODE_PREVIEW) != 0; + + shi->do_manage = BKE_scene_check_color_management_enabled(R.scene); + shi->use_world_space_shading = BKE_scene_use_world_space_shading(R.scene); + + shi->lay = rl->lay; + shi->layflag = rl->layflag; + shi->passflag = rl->passflag; + shi->combinedflag = ~rl->pass_xor; + shi->mat_override = rl->mat_override; + shi->light_override = rl->light_override; +// shi->rl= rl; + /* note shi.depth==0 means first hit, not raytracing */ + +} + +/* initialize per part, not per pixel! */ +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(ShadeResult)); + } + + get_sample_layers(pa, rl, ssamp->rlpp); +} + +/* Do AO or (future) GI */ +void shade_samples_do_AO(ShadeSample *ssamp) +{ + if (!(R.r.mode & R_SHADOW)) + return; + if (!(R.r.mode & R_RAYTRACE) && !(R.wrld.ao_gather_method == WO_AOGATHER_APPROX)) + return; + + if (R.wrld.mode & (WO_AMB_OCC | WO_ENV_LIGHT | WO_INDIRECT_LIGHT)) { + ShadeInput *shi = &ssamp->shi[0]; + int sample; + + if (((shi->passflag & SCE_PASS_COMBINED) && (shi->combinedflag & (SCE_PASS_AO | SCE_PASS_ENVIRONMENT | SCE_PASS_INDIRECT))) || + (shi->passflag & (SCE_PASS_AO | SCE_PASS_ENVIRONMENT | SCE_PASS_INDIRECT))) + { + for (sample = 0; sample < ssamp->tot; shi++, sample++) + if (!(shi->mode & MA_SHLESS)) + ambient_occlusion(shi); /* stores in shi->ao[] */ + } + } +} + + +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) { + shade_input_set_triangle(shi, ps->obi, ps->facenr, 1); + + if (shi->vlr) { /* NULL happens for env material or for 'all z' */ + unsigned short curmask = ps->mask; + + /* full osa is only set for OSA renders */ + if (shi->vlr->flag & R_FULL_OSA) { + short shi_cp = 0, samp; + + for (samp = 0; samp < R.osa; samp++) { + if (curmask & (1 << samp)) { + /* zbuffer has this inverse corrected, ensures xs,ys are inside pixel */ + xs = (float)x + R.jit[samp][0] + 0.5f; + ys = (float)y + R.jit[samp][1] + 0.5f; + + if (shi_cp) + shade_input_copy_triangle(shi, shi - 1); + + shi->mask = (1 << samp); +// shi->rl= ssamp->rlpp[samp]; + shi->samplenr = R.shadowsamplenr[shi->thread]++; /* this counter is not being reset per pixel */ + shade_input_set_viewco(shi, x, y, xs, ys, (float)ps->z); + shade_input_set_uv(shi); + if (shi_cp == 0) + shade_input_set_normals(shi); + else /* XXX shi->flippednor messes up otherwise */ + shade_input_set_vertex_normals(shi); + + shi_cp = 1; + shi++; + } + } + } + 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 if (R.i.curblur) { + xs= (float)x + R.mblur_jit[R.i.curblur-1][0] + 0.5f; + ys= (float)y + R.mblur_jit[R.i.curblur-1][1] + 0.5f; + } + else { + xs = (float)x + 0.5f; + ys = (float)y + 0.5f; + } + + shi->mask = curmask; + shi->samplenr = R.shadowsamplenr[shi->thread]++; + shade_input_set_viewco(shi, x, y, xs, ys, (float)ps->z); + shade_input_set_uv(shi); + shade_input_set_normals(shi); + shi++; + } + + /* total sample amount, shi->sample is static set in initialize */ + if (shi != ssamp->shi) + ssamp->tot = (shi - 1)->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? */ + shade_samples_do_AO(ssamp); + + /* if shade (all shadepinputs have same passflag) */ + if (ssamp->shi[0].passflag & ~(SCE_PASS_Z | SCE_PASS_INDEXOB | SCE_PASS_INDEXMA)) { + + for (samp = 0; samp < ssamp->tot; samp++, shi++, shr++) { + shade_input_set_shade_texco(shi); + shade_input_do_shade(shi, shr); + } + } + else if (shi->passflag & SCE_PASS_Z) { + for (samp = 0; samp < ssamp->tot; samp++, shi++, shr++) + shr->z = -shi->co[2]; + } + + return 1; + } + return 0; +} + |