Logo Search packages:      
Sourcecode: yafray version File versions

blendershader.cc

#include "blendershader.h"

__BEGIN_YAFRAY
//------------------------------------------------------------------------------------------
// texture mapping

// slightly modified Blender's own functions,
// works better than previous functions which needed extra tweaks
static void tubemap(const point3d_t &p, PFLOAT &u, PFLOAT &v)
{
      u = 0;
      v = 1 - (p.z + 1)*0.5;
      PFLOAT d = p.x*p.x + p.y*p.y;
      if (d>0) {
            d = 1/sqrt(d);
            u = 0.5*(1 - (atan2(p.x*d, p.y*d) *M_1_PI));
      }
}

static void spheremap(const point3d_t &p, PFLOAT &u, PFLOAT &v)
{
      PFLOAT d = p.x*p.x + p.y*p.y + p.z*p.z;
      u = v= 0;
      if (d>0) {
            if ((p.x!=0) && (p.y!=0)) u = 0.5*(1 - atan2(p.x, p.y)*M_1_PI);
            v = acos(p.z/sqrt(d)) * M_1_PI;
      }
}

blenderMapperNode_t::blenderMapperNode_t(const shader_t *m):mapped(m)
{
      _sizex = _sizey = _sizez = 1.0;
      tex_maptype = TXM_FLAT;
      tex_coords = TXC_ORCO;
      tex_Mtx.identity();
      has_transform = false;
      _ofsx = _ofsy = _ofsz = 0.0;
      _cropminx = _cropminy = 0.0;
      _cropmaxx = _cropmaxy = 1.0;
      _xrepeat = _yrepeat = 1;
      tex_clipmode = TCL_REPEAT;
      tex_projx = TEX_PROJX;
      tex_projy = TEX_PROJY;
      tex_projz = TEX_PROJZ;
}

// creates texture coord from surface point, returns true if texture clipped
bool blenderMapperNode_t::doMapping(const surfacePoint_t &sp, const vector3d_t &eye,
                        point3d_t &texpt) const
{
      bool outside = false;   // clipflag

      switch (tex_coords) {
            case TXC_UV: {
                  // this might seem weird, but since the texture coords are changed later on
                  // have to adapt the uv-coords here as well...
                  texpt.x = sp.u()*2.0 - 1.0;
                  texpt.y = 1.0 - sp.v()*2.0;
                  texpt.z = -0.98;  // some arbitrary(?) value, (R.lo[2] in Blender, orco?), never seems to change
                  break;
            }
            case TXC_GLOB: {
                  // coords as is without transform to object
                  texpt = sp.P();
                  break;
            }
            case TXC_ORCO: {
                  // scaled/rotated/translated to fit object size/rotation/position
                  if (sp.hasOrco())
                        texpt = sp.orco();
                        //texpt = sp.getObject()->toObject(sp.orco());
                  else
                        texpt = sp.getObject()->toObjectOrco(sp.P());
                  break;
            }
            case TXC_WIN: {
                  // Current (normalized) screen sampling coords.
                  sp.getScreenPos(texpt.x, texpt.y);
                  texpt.z = -0.98;  // some arbitrary(?) value, (R.lo[2] in Blender, orco?), never seems to change
                  break;
            }
            case TXC_NOR: {
                  // current normal
                  vector3d_t N = sp.N();
                  texpt = point3d_t(-N.x, N.z, N.y);
                  break;
            }
            case TXC_REFL: {
                  // reflection vector
                  vector3d_t neye = eye;
                  neye.normalize();
                  vector3d_t N = FACE_FORWARD(sp.Ng(), sp.N(), neye);
                  texpt = point3d_t(reflect(N, neye));
            }
      }

      // For render from blender, 'object' texture mode is also set as global,
      // but a transform is used to rotate/scale/translate the texture accordingly.
      // This is also used with reflection mapping, BUT full mtx only used with flat, otherwise translation ignored
      if (has_transform) {
            if (tex_coords==TXC_REFL) {
                  if (tex_maptype==TXM_FLAT)
                        texpt = tex_Mtx * texpt;
                  else
                        texpt = point3d_t(tex_Mtx * toVector(texpt));
            }
            else texpt = tex_Mtx * texpt;
      }

      // for projection axes swap
      float texT[3] = {texpt.x, texpt.y, texpt.z};

      // no more PROC_TEX/IMAGE_TEX flag, can determine the same from discrete()
      if (mapped->discrete()) {
            // parameters only relevant to image texture

            // projection first
            if (tex_projx) texpt.x=texT[tex_projx-1]; else texpt.x=0.0;
            if (tex_projy) texpt.y=texT[tex_projy-1]; else texpt.y=0.0;
            if (tex_projz) texpt.z=texT[tex_projz-1]; else texpt.z=0.0;

            // mapping next
            switch (tex_maptype) {
                  case TXM_FLAT: {
                        texpt.x = (texpt.x+1)*0.5;
                        texpt.y = (1-texpt.y)*0.5;
                        break;
                  }
                  case TXM_CUBE: {
                        // orient normal, Blender's cubemap() not implemented yet,
                        // needs face puno flag (needed at all? sofar everything seems to work without it)
                        vector3d_t aN;
                        if ((has_transform) || (tex_coords==TXC_GLOB)) {
                              // assume object/global mapping, cubemap_ob()
                              aN = tex_Mtx * sp.N();
                              aN.normalize();
                        }
                        else aN = sp.getObject()->toObjectRot(sp.N());  // global mapping but not used for yafray global mapping(!), cubemap_glob()
                        aN.abs();
                        if ((aN.x>=aN.y) && (aN.x>=aN.z))
                              texpt.set((texpt.y+1)*0.5, (1-texpt.z)*0.5, texpt.z);
                        else if ((aN.y>=aN.x) && (aN.y>=aN.z))
                              texpt.set((texpt.x+1)*0.5, (1-texpt.z)*0.5, texpt.z);
                        else
                              texpt.set((texpt.x+1)*0.5, (1-texpt.y)*0.5, texpt.z);
                        break;
                  }
                  case TXM_TUBE: {
                        CFLOAT u, v;
                        tubemap(texpt, u, v);
                        texpt.x = u;
                        texpt.y = v;
                        break;
                  }
                  case TXM_SPHERE: {
                        CFLOAT u, v;
                        spheremap(texpt, u, v);
                        texpt.x = u;
                        texpt.y = v;
                        break;
                  }
            }

            // repeat
            if (_xrepeat>1) {
                  texpt.x *= (PFLOAT)_xrepeat;
                  if (texpt.x>1.0) texpt.x -= int(texpt.x); else if (texpt.x<0.0) texpt.x += 1-int(texpt.x);
            }
            if (_yrepeat>1) {
                  texpt.y *= (PFLOAT)_yrepeat;
                  if (texpt.y>1.0) texpt.y -= int(texpt.y); else if (texpt.y<0.0) texpt.y += 1-int(texpt.y);
            }

            // crop
            if ((_cropminx!=0.0) || (_cropmaxx!=1.0)) texpt.x = _cropminx + texpt.x*(_cropmaxx - _cropminx);
            if ((_cropminy!=0.0) || (_cropmaxy!=1.0)) texpt.y = _cropminy + texpt.y*(_cropmaxy - _cropminy);

            // size & offset last, ofsy is negated
            // if rot90 enabled, swap u & v, and negate both size & ofs
            if (_rot90) {
                  PFLOAT tx = texpt.x;
                  texpt.x = -_sizey*(texpt.y-0.5) + _ofsy + 0.5;
                  texpt.y = -_sizex*(tx-0.5) - _ofsx + 0.5;
            }
            else {
                  texpt.x = _sizex*(texpt.x-0.5) + _ofsx + 0.5;
                  texpt.y = _sizey*(texpt.y-0.5) - _ofsy + 0.5;
            }

            // clipping
            switch (tex_clipmode) {
                  case TCL_CLIPCUBE: {
                        if ((texpt.x<0) || (texpt.x>1) || (texpt.y<0) || (texpt.y>1) || (texpt.z<-1) || (texpt.z>1))
                              outside = true;
                        else
                              outside = false;
                        break;
                  }
                  case TCL_CLIP: {
                        if ((texpt.x<0) || (texpt.x>1) || (texpt.y<0) || (texpt.y>1))
                              outside = true;
                        else
                              outside = false;
                        break;
                  }
                  case TCL_EXTEND: {
                        if (texpt.x>1) texpt.x=1; else if (texpt.x<0) texpt.x=0;
                        if (texpt.y>1) texpt.y=1; else if (texpt.y<0) texpt.y=0;
                        // no break, fall thru to TEX_REPEAT
                  }
                  case TCL_REPEAT: {
                        outside = false;
                        break;
                  }
            }

      }
      else {
            // procedural texture
            if (tex_projx) texpt.x=_sizex*(texT[tex_projx-1]+_ofsx); else texpt.x=_sizex*_ofsx;
            if (tex_projy) texpt.y=_sizey*(texT[tex_projy-1]+_ofsy); else texpt.y=_sizey*_ofsy;
            if (tex_projz) texpt.z=_sizez*(texT[tex_projz-1]+_ofsz); else texpt.z=_sizez*_ofsz;
            outside = false;  // no clipping for this type
      }

      return outside;
}

CFLOAT blenderMapperNode_t::stdoutFloat(renderState_t &state,
            const surfacePoint_t &sp, const vector3d_t &eye,
            const scene_t *scene) const
{
      point3d_t mpoint;
      if(doMapping(sp,eye,mpoint)) return 0.0;
      surfacePoint_t tempsp(sp);
      tempsp.P()=mpoint;
      return mapped->stdoutFloat(state,tempsp,eye,scene);
}

colorA_t blenderMapperNode_t::stdoutColor(renderState_t &state,
            const surfacePoint_t &sp, const vector3d_t &eye,
            const scene_t *scene) const
{
      point3d_t mpoint;
      if(doMapping(sp,eye,mpoint)) return color_t(0,0,0);
      surfacePoint_t tempsp(sp);
      tempsp.P()=mpoint;
      return mapped->stdoutColor(state,tempsp,eye,scene);
}

void blenderMapperNode_t::string2maptype(const std::string &mapname)
{
      // default "flat"
      if (mapname=="cube")
            tex_maptype = TXM_CUBE;
      else if (mapname=="tube")
            tex_maptype = TXM_TUBE;
      else if (mapname=="sphere")
            tex_maptype = TXM_SPHERE;
      else
            tex_maptype = TXM_FLAT;
}

void blenderMapperNode_t::string2texcotype(const std::string &texconame)
{
      // default "uv"
      if (texconame=="global")
            tex_coords = TXC_GLOB;
      else if (texconame=="orco")
            tex_coords = TXC_ORCO;
      else if (texconame=="window")
            tex_coords = TXC_WIN;
      else if (texconame=="normal")
            tex_coords = TXC_NOR;
      else if (texconame=="reflect")
            tex_coords = TXC_REFL;
      else
            tex_coords = TXC_UV;
}

void blenderMapperNode_t::string2cliptype(const std::string &clipname)
{
      // default "repeat"
      if (clipname=="extend")
            tex_clipmode = TCL_EXTEND;
      else if (clipname=="clip")
            tex_clipmode = TCL_CLIP;
      else if (clipname=="clipcube")
            tex_clipmode = TCL_CLIPCUBE;
      else
            tex_clipmode = TCL_REPEAT;
}

void blenderMapperNode_t::string2texprojection(const std::string &x_axis,
            const std::string &y_axis, const std::string &z_axis)
{
      // string find pos. corresponds to TEX_PROJ0/X/Y/Z, if not found, assume disabled (PROJ0)
      const std::string axes = "nxyz";
      if ((tex_projx = axes.find(x_axis))==-1) tex_projx = TEX_PROJ0;
      if ((tex_projy = axes.find(y_axis))==-1) tex_projy = TEX_PROJ0;
      if ((tex_projz = axes.find(z_axis))==-1) tex_projz = TEX_PROJ0;
}

using namespace std;

shader_t * blenderMapperNode_t::factory(paramMap_t &bparams,
            std::list<paramMap_t> &lparams,renderEnvironment_t &render)
{
      string _childname;
      const string *childname=&_childname;
      bparams.getParam("input",childname);
      shader_t *child=render.getShader(*childname);
      if(child==NULL)
      {
            cerr<<"Null input in blender mapper\n";
            return NULL;
      }
      blenderMapperNode_t *mapper=new blenderMapperNode_t(child);

      GFLOAT size=1, sizex=1, sizey=1, sizez=1;
      
      string _mapping="flat", _texco="orco", _clipping="extend";  // defaults
      string _projx="x", _projy="y", _projz="z";
      const string *mapping=&_mapping, *texco=&_texco, *clipping=&_clipping;  // defaults
      const string *projx=&_projx, *projy=&_projy, *projz=&_projz;

      int xrep=1, yrep=1;
      matrix4x4_t txm(1);
      GFLOAT ofsx=0, ofsy=0, ofsz=0;
      GFLOAT minx=0, miny=0, maxx=1, maxy=1;
      bool ROT90=false;

      bparams.getParam("size", size);
      bparams.getParam("sizex", sizex);
      bparams.getParam("sizey", sizey);
      bparams.getParam("sizez", sizez);
      bparams.getParam("mapping", mapping);
      bparams.getParam("texco", texco);
      bparams.getParam("clipping", clipping);
      bparams.getParam("xrepeat", xrep);
      bparams.getParam("yrepeat", yrep);
      bparams.getParam("ofsx", ofsx);
      bparams.getParam("ofsy", ofsy);
      bparams.getParam("ofsz", ofsz);
      bparams.getParam("cropmin_x", minx);
      bparams.getParam("cropmin_y", miny);
      bparams.getParam("cropmax_x", maxx);
      bparams.getParam("cropmax_y", maxy);
      bparams.getParam("proj_x", projx);
      bparams.getParam("proj_y", projy);
      bparams.getParam("proj_z", projz);
      bparams.getParam("rot90", ROT90);

      // texture matrix
      bool hasmtx = bparams.getParam("m00", txm[0][0]);
      hasmtx |= bparams.getParam("m01", txm[0][1]);
      hasmtx |= bparams.getParam("m02", txm[0][2]);
      hasmtx |= bparams.getParam("m03", txm[0][3]);
      hasmtx |= bparams.getParam("m10", txm[1][0]);
      hasmtx |= bparams.getParam("m11", txm[1][1]);
      hasmtx |= bparams.getParam("m12", txm[1][2]);
      hasmtx |= bparams.getParam("m13", txm[1][3]);
      hasmtx |= bparams.getParam("m20", txm[2][0]);
      hasmtx |= bparams.getParam("m21", txm[2][1]);
      hasmtx |= bparams.getParam("m22", txm[2][2]);
      hasmtx |= bparams.getParam("m23", txm[2][3]);
      hasmtx |= bparams.getParam("m30", txm[3][0]);
      hasmtx |= bparams.getParam("m31", txm[3][1]);
      hasmtx |= bparams.getParam("m32", txm[3][2]);
      hasmtx |= bparams.getParam("m33", txm[3][3]);

      mapper->setRot90(ROT90);
      mapper->sizeX(sizex);
      mapper->sizeY(sizey);
      mapper->sizeZ(sizez);
      mapper->ofsX(ofsx);
      mapper->ofsY(ofsy);
      mapper->ofsZ(ofsz);
      if (size!=1.0) mapper->size(size);
      mapper->string2maptype(*mapping);
      mapper->string2texcotype(*texco);
      mapper->string2cliptype(*clipping);
      mapper->string2texprojection(*projx, *projy, *projz);
      mapper->setRepeat(xrep, yrep);
      mapper->setCrop(minx, miny, maxx, maxy);
      if (hasmtx) mapper->setTransform(txm);

      return mapper;
}

void blenderModulator_t::blenderModulate(colorA_t &col, colorA_t &colspec,
            colorA_t &refcol, colorA_t &colmir,CFLOAT &refcol0, CFLOAT &ref,
            CFLOAT &spec, CFLOAT &har, CFLOAT &emit, CFLOAT &alpha,
            CFLOAT &stencilTin,     renderState_t &state,const surfacePoint_t &sp,
            const vector3d_t &eye) const
{
      colorA_t texcolor=input->stdoutColor(state,sp,eye,NULL);
      if (alpha_flag & TXA_CALCALPHA) texcolor.setAlpha(max(texcolor.getRed(), max(texcolor.getGreen(), texcolor.getBlue())));
      CFLOAT Tin, Ta;
      Tin = texcolor.energy();
      if (alpha_flag & TXA_NEGALPHA) Ta=1-texcolor.getAlpha(); else Ta=texcolor.getAlpha();
      bool Talpha = ((alpha_flag & TXA_USEALPHA)!=0);

      // procedural textures are intensity only by default
      bool TEX_RGB = input->isRGB();
      if (TEX_RGB) {
            // contrast & brightness
            texcolor = _filtercolor*((texcolor-colorA_t(0.5))*_contrast + colorA_t(_brightness - 0.5));
            texcolor.clampRGB01();
      }
      else {
            Tin = (Tin-0.5)*_contrast + _brightness - 0.5;
            if (Tin<0) Tin=0; else if (Tin>1) Tin=1;
      }

      CFLOAT fact, facm, factt, facmm, facmul=0;

      if (texflag & TXF_RGBTOINT) {
            Tin = 0.35*texcolor.getRed() + 0.45*texcolor.getGreen() + 0.2*texcolor.getBlue();
            TEX_RGB = false;
      }
      if (texflag & TXF_NEGATIVE) {
            if (TEX_RGB) texcolor = colorA_t(1.0)-texcolor;
            Tin = 1.0-Tin;
      }
      if(texflag & TXF_STENCIL) {
            if (TEX_RGB) {
                  fact = Ta;
                  Ta *= stencilTin;
                  stencilTin *= fact;
            }
            else {
                  fact = Tin;
                  Tin *= stencilTin;
                  stencilTin *= fact;
            }
      }
      else {
            if (TEX_RGB) Ta *= stencilTin;
            else Tin *= stencilTin;
      }

      // color type modulation
      // _color|_csp|_cmir all switches, positive only, value not used
      if ((_color!=0) || (_csp!=0) || (_cmir!=0)) {

            if (!TEX_RGB)
                  texcolor = texture_col;
            else {
                  if (_alpha>0)
                        Tin = stencilTin; // MTEX_ALPHAMIX seems to be unused (old Blender code?)
                  else
                        Tin = Ta;
            }

            fact = Tin * colfac;
            facm = 1-fact;
            if (_mode==MUL) facm = 1-colfac;
            if (_mode==SUB) fact = -fact;

            // diffuse color modulation
            if (_color!=0) {
                  if (_mode==MIX)
                        col = fact*texcolor + facm*col;
                  else if (_mode==MUL)
                        col *= (colorA_t(facm) + fact*texcolor);
                  else
                        col += fact*texcolor;
            }

            // specular color modulation
            if (_csp!=0) {
                  if (_mode==MIX)
                        colspec = fact*texcolor + facm*colspec;
                  else if (_mode==MUL)
                        colspec *= (colorA_t(facm) + fact*texcolor);
                  else
                        colspec += fact*texcolor;
            }

            // mirror color modulation (blender, not reflection)
            if (_cmir!=0) {
                  // separate colors for mix & other modes...
                  if (_mode==MIX) {
                        refcol0 = fact + facm*refcol0;
                        refcol = fact*texcolor + facm*refcol;
                  }
                  else if (_mode==MUL)
                        colmir *= (colorA_t(facm) + fact*texcolor);
                  else
                        colmir += fact*texcolor;
            }

      }

      // intensity type modulation
      if ((_ref!=0) || (_specular!=0) || (_hard!=0) || (_alpha!=0) || (_emit!=0)) {

            if (TEX_RGB) {
                  if (Talpha) Tin = Ta;
                  else Tin = 0.35*texcolor.getRed() + 0.45*texcolor.getGreen() + 0.2*texcolor.getBlue();
            }

            fact = Tin*varfac;
            facm = 1-fact;
            if (_mode==MUL) facmul=1-varfac;
            if (_mode==SUB) fact = -fact;

            if (_ref!=0) {
                  if (_ref<0) { factt=facm;  facmm=fact; }
                  else { factt=fact;  facmm=facm; }

                  if (_mode==MIX)
                        ref = factt*def_var + facmm*ref;
                  else if (_mode==MUL)
                        ref *= (facmul+factt);
                  else {
                        ref += factt;
                        if (ref<0) ref=0;
                  }
            }

            if (_specular!=0) {
                  if (_specular<0) { factt=facm;  facmm=fact; }
                  else { factt=fact;  facmm=facm; }

                  if (_mode==MIX)
                        spec = factt*def_var + facmm*spec;
                  else if (_mode==MUL)
                        spec *= (facmul+factt);
                  else {
                        spec += factt;
                        if (spec<0) spec=0;
                  }
            }

            if (_emit!=0) {
                  if (_emit<0) { factt=facm;  facmm=fact; }
                  else { factt=fact;  facmm=facm; }

                  if (_mode==MIX)
                        emit = factt*def_var + facmm*emit;
                  else if (_mode==MUL)
                        emit *= (facmul+factt);
                  else {
                        emit += factt;
                        if (emit<0) emit=0;
                  }
            }

            if (_alpha!=0) {
                  if (_alpha<0) { factt=facm;  facmm=fact; }
                  else { factt=fact;  facmm=facm; }

                  if (_mode==MIX)
                        alpha = factt*def_var + facmm*alpha;
                  else if (_mode==MUL)
                        alpha *= (facmul+factt);
                  else {
                        alpha += factt;
                        if (alpha<0) alpha=0; else if (alpha>1) alpha=1;
                  }
            }

            if (_hard!=0) {
                  if (_hard<0) { factt=facm; facmm=fact; }
                  else { factt=fact;  facmm=facm; }

                  if (_mode==MIX)
                        har = 128.0*factt*def_var + facmm*har;
                  else if (_mode==MUL)
                        har *= (facmul+factt);
                  else {
                        har += 128.0*factt;
                        if (har<1) har=1;
                  }
            }

      }

}

void blenderModulator_t::blenderModulate(colorA_t &col, CFLOAT &ref, 
            CFLOAT &emit,CFLOAT &alpha,   CFLOAT &stencilTin, renderState_t &state,
            const surfacePoint_t &sp,     const vector3d_t &eye) const
{
      colorA_t texcolor=input->stdoutColor(state,sp,eye,NULL);
      if (alpha_flag & TXA_CALCALPHA) texcolor.setAlpha(max(texcolor.getRed(), max(texcolor.getGreen(), texcolor.getBlue())));
      CFLOAT Tin, Ta;
      Tin = texcolor.energy();
      if (alpha_flag & TXA_NEGALPHA) Ta=1-texcolor.getAlpha(); else Ta=texcolor.getAlpha();
      bool Talpha = ((alpha_flag & TXA_USEALPHA)!=0);

      // procedural textures are intensity only by default
      bool TEX_RGB = input->isRGB();
      if (TEX_RGB) {
            // contrast & brightness
            texcolor = _filtercolor*((texcolor-colorA_t(0.5))*_contrast + colorA_t(_brightness - 0.5));
            texcolor.clampRGB01();
      }
      else {
            Tin = (Tin-0.5)*_contrast + _brightness - 0.5;
            if (Tin<0) Tin=0; else if (Tin>1) Tin=1;
      }

      CFLOAT fact, facm, factt, facmm, facmul=0;

      if (texflag & TXF_RGBTOINT) {
            Tin = 0.35*texcolor.getRed() + 0.45*texcolor.getGreen() + 0.2*texcolor.getBlue();
            TEX_RGB = false;
      }
      if (texflag & TXF_NEGATIVE) {
            if (TEX_RGB) texcolor = colorA_t(1.0)-texcolor;
            Tin = 1.0-Tin;
      }
      if(texflag & TXF_STENCIL) {
            if (TEX_RGB) {
                  fact = Ta;
                  Ta *= stencilTin;
                  stencilTin *= fact;
            }
            else {
                  fact = Tin;
                  Tin *= stencilTin;
                  stencilTin *= fact;
            }
      }
      else {
            if (TEX_RGB) Ta *= stencilTin;
            else Tin *= stencilTin;
      }

      // color type modulation
      // _color|_csp|_cmir all switches, positive only, value not used
      if (_color!=0) 
      {
            if (!TEX_RGB)
                  texcolor = texture_col;
            else {
                  if (_alpha>0)
                        Tin = stencilTin; // MTEX_ALPHAMIX seems to be unused (old Blender code?)
                  else
                        Tin = Ta;
            }

            fact = Tin * colfac;
            facm = 1-fact;
            if (_mode==MUL) facm = 1-colfac;
            if (_mode==SUB) fact = -fact;

            // diffuse color modulation
            if (_color!=0) {
                  if (_mode==MIX)
                        col = fact*texcolor + facm*col;
                  else if (_mode==MUL)
                        col *= (colorA_t(facm) + fact*texcolor);
                  else
                        col += fact*texcolor;
            }

      }

      // intensity type modulation
      if ((_ref!=0) || (_emit!=0) || (_alpha!=0)) 
      {

            if (TEX_RGB) {
                  if (Talpha) Tin = Ta;
                  else Tin = 0.35*texcolor.getRed() + 0.45*texcolor.getGreen() + 0.2*texcolor.getBlue();
            }

            fact = Tin*varfac;
            facm = 1-fact;
            if (_mode==MUL) facmul=1-varfac;
            if (_mode==SUB) fact = -fact;

            if (_ref!=0) {
                  if (_ref<0) { factt=facm;  facmm=fact; }
                  else { factt=fact;  facmm=facm; }

                  if (_mode==MIX)
                        ref = factt*def_var + facmm*ref;
                  else if (_mode==MUL)
                        ref *= (facmul+factt);
                  else {
                        ref += factt;
                        if (ref<0) ref=0;
                  }
            }


            if (_emit!=0) {
                  if (_emit<0) { factt=facm;  facmm=fact; }
                  else { factt=fact;  facmm=facm; }

                  if (_mode==MIX)
                        emit = factt*def_var + facmm*emit;
                  else if (_mode==MUL)
                        emit *= (facmul+factt);
                  else {
                        emit += factt;
                        if (emit<0) emit=0;
                  }
            }

            if (_alpha!=0) {
                  if (_alpha<0) { factt=facm;  facmm=fact; }
                  else { factt=fact;  facmm=facm; }

                  if (_mode==MIX)
                        alpha = factt*def_var + facmm*alpha;
                  else if (_mode==MUL)
                        alpha *= (facmul+factt);
                  else {
                        alpha += factt;
                        if (alpha<0) alpha=0; else if (alpha>1) alpha=1;
                  }
            }
      }
}


void blenderModulator_t::modulate(colorA_t &T,colorA_t &R,
            renderState_t &state,const surfacePoint_t &sp,
            const vector3d_t &eye) const
{
      colorA_t texcolor=input->stdoutColor(state,sp,eye,NULL);

      if(_mode==MIX)
      {
            if (_transmision>0)     T = mix(texcolor, T, _transmision);
            if (_reflection>0)            R = mix(texcolor, R, _reflection);
            return;
      }
      if(_mode==MUL)
      {
            if (_transmision>0)     T *= mix(texcolor, colorA_t(1.0), _transmision);
            if (_reflection>0)            R *= mix(texcolor, colorA_t(1.0), _reflection);
            return;
      }
      if(_mode==ADD)
      {
            if (_transmision>0)     T += (texcolor * _transmision);
            if (_reflection>0)            R += (texcolor * _reflection);
            return;
      }
      if(_mode==SUB)
      {
            if (_transmision>0)     T += (texcolor * -_transmision);
            if (_reflection>0)            R += (texcolor * -_reflection);
            return;
      }
}

void blenderModulator_t::blenderDisplace(renderState_t &state,surfacePoint_t &sp,
            const vector3d_t &eye, PFLOAT res) const
{
      if(_displace==0.0) return;
      point3d_t texpt=sp.P();
      point3d_t old=sp.P();
      bool orco=sp.hasOrco();

      sp.hasOrco(false);
      float ou=0,ov=0;
      if(sp.hasUV())
      {
            ou=sp.u();
            ov=sp.v();
      }
      vector3d_t NU=sp.NU()*res, NV=sp.NV()*res;
      PFLOAT diru=0, dirv=0;

      sp.P() = texpt-NU;
      if(sp.hasUV()) {sp.u()=ou-sp.dudNU()*res;sp.v()=ov-sp.dvdNU()*res;}
      diru = input->stdoutFloat(state,sp,eye,NULL);
      sp.P() = texpt+NU;
      if(sp.hasUV()) {sp.u()=ou+sp.dudNU()*res;sp.v()=ov+sp.dvdNU()*res;}
      diru -= input->stdoutFloat(state,sp,eye,NULL);
      diru *= _displace/res;

      sp.P() = texpt-NV;
      if(sp.hasUV()) {sp.u()=ou-sp.dudNV()*res;sp.v()=ov-sp.dvdNV()*res;}
      dirv = input->stdoutFloat(state,sp,eye,NULL);
      sp.P() = texpt+NV;
      if(sp.hasUV()) {sp.u()=ou+sp.dudNV()*res;sp.v()=ov+sp.dvdNV()*res;}
      dirv -= input->stdoutFloat(state,sp,eye,NULL);
      dirv *= _displace/res;

      PFLOAT nless=1.0;
      nless -= ((fabs(diru)>fabs(dirv))? fabs(diru) : fabs(dirv));
      if (nless<0.0) nless=0;
      sp.N() = sp.N()*nless + sp.NU()*diru + sp.NV()*dirv;
      sp.N().normalize();
      if(sp.hasUV())
      {
            sp.u()=ou;
            sp.v()=ov;
      }
      sp.P() =old;
      sp.hasOrco(orco);
}

color_t blenderShader_t::fromRadiosity(renderState_t &state, const surfacePoint_t &sp,
                                                                                                            const energy_t &ene, const vector3d_t &eye) const
{
      if ((FACE_FORWARD(sp.Ng(),sp.N(),eye) * ene.dir)<0) return color_t(0.0);

      colorA_t col = scolor;
      if (sp.hasVertexCol()) {
            if (mat_mode & MAT_VCOL_PAINT) col = sp.vertex_col();
      }

      CFLOAT ref=edif,em=emit;
      if (!mods.empty())
      {
            CFLOAT al=alpha, stt=1;
            for(vector<blenderModulator_t>::const_iterator ite=mods.begin();ite!=mods.end();++ite)
            {
                  (*ite).blenderModulate(col, ref, em, al, stt, state, sp, eye);
            }
      }
      return ref*ene.color*(color_t)col+em*(color_t)col;
}


color_t blenderShader_t::fromLight(renderState_t &state, const surfacePoint_t &sp,
                                                                                                      const energy_t &energy, const vector3d_t &eye) const
{
      if (mat_mode & MAT_SHADELESS) return color_t(0.0);
      vector3d_t edir=eye;
      edir.normalize();
      vector3d_t N = FACE_FORWARD(sp.Ng(),sp.N(), edir);
      CFLOAT inte = N*energy.dir;
      if (inte<0) return color_t(0.0);

      colorA_t col=scolor, spcol=speccol, refc(0.0), cm=mircol;
      if (sp.hasVertexCol()) {
            if (mat_mode & MAT_VCOL_PAINT) col = sp.vertex_col();
      }

      CFLOAT refc0=0, ref=edif, spa=specam, h=hard, al=alpha, em=emit;
      if (!mods.empty())
      {
            CFLOAT stt=1;
            for(vector<blenderModulator_t>::const_iterator ite=mods.begin();ite!=mods.end();++ite)
            {
                  (*ite).blenderModulate(/**/col, /**/spcol, refc,/**/ cm, /**/refc0, 
                                                                                     /**/ref, /**/spa,/**/ h, em,/**/ al, stt, state, sp, eye);
            }
      }

      edir = reflect(N,edir);
      CFLOAT refle = edir*energy.dir;
      if (refle<0) refle=0;
      else refle = pow((CFLOAT)refle, h);

      // both cmir and alpha modulation are separated in a fromLight() and fromWorld() part
      // diffuse cmir part and positive alpha part here
      if (refc0==0)
            return al*(ref*inte*(colorA_t)energy.color*col + spa*spcol*refle*(colorA_t)energy.color);
      return al*((colorA_t(1.0)-cm*refc0)*(ref*inte*(colorA_t)energy.color*col) + spa*spcol*refle*(colorA_t)energy.color);
}


color_t blenderShader_t::fromWorld(renderState_t &state, const surfacePoint_t &sp,
                                                                                                const scene_t &s, const vector3d_t &eye) const
{
      const void *oldorigin=state.skipelement;
      state.skipelement=sp.getOrigin();

      colorA_t Rresul(0.0), Tresul(0.0);
      vector3d_t edir = eye;
      edir.normalize();

      if (!(eref.null() && erefr.null())) {

            CFLOAT fKr, fKt;
            vector3d_t N = FACE_FORWARD(sp.Ng(), sp.N(), edir);
            vector3d_t Ng = FACE_FORWARD(sp.Ng(), sp.Ng(), edir);
            CFLOAT &cont = state.contribution;
            CFLOAT oldcont = cont;

            if ((N*eye)<0) N=Ng;

            if (use_fastf)
                  fast_fresnel(edir, N, fastf_IOR, fKr, fKt);
            else
                  fresnel(edir, N, IOR, fKr, fKt);

            // fresnel color interpolation
            colorA_t cur_rfLcol = eref + fKr*(eref2 - eref);
            colorA_t cur_rfRcol = erefr2 + fKt*(erefr - erefr2);

            if (!cur_rfLcol.null())
            {
                  if(((sp.Ng()*eye)>0) || (state.raylevel<1))
                  {
                        vector3d_t ref = reflect(N, edir);

                        PFLOAT offset = ref*Ng;
                        if (offset<=0.05)
                        {
                              ref = ref + Ng*(0.05-offset);
                              ref.normalize();
                        }

                        CFLOAT nr = minR+fKr;
                        if (nr>1.0) nr=1.0;
                        if ((nr*cont)>0.01)
                        {
                              cont *= nr;
                              colorA_t nref = cur_rfLcol * nr;
                              Rresul = nref*(colorA_t)s.raytrace(state, sp.P(), ref);
                              cont = oldcont;
                        }
                  }
            }
            if (!cur_rfRcol.null())
            {
                  vector3d_t ref;
                  ref = refract(sp.N(), edir, IOR);
                  if(ref.null() && tir) ref=reflect(N,edir);
                  if (!ref.null())
                  {
                        CFLOAT nt = (1.0<fKt) ? 1.0 : fKt;
                        if ((nt*cont)>0.01)
                        {
                              cont *= nt;
                              colorA_t nrefr = cur_rfRcol*nt;
                              Tresul = nrefr*(colorA_t)s.raytrace(state, sp.P(), ref);
                              cont = oldcont;
                        }
                  }
            }
      }

      // for alpha modulation, the color visible through this object
      colorA_t alphacol(0.0);
      if (mat_mode & MAT_ZTRANSP) {
            // no raytrace(), must be independent of raylevel
            surfacePoint_t tsp;
            if (s.firstHit(state, tsp, sp.P(), -edir, true)) alphacol = s.light(state, tsp, sp.P(), true);
      }

      // blendermodulate still needed for emit/cmir
      colorA_t col=scolor, refc(0.0), cm=mircol;
      if (sp.hasVertexCol()) {
            if (mat_mode & MAT_VCOL_PAINT) col = sp.vertex_col();
      }
      CFLOAT refc0=0, al=alpha, em=emit;
      if (!mods.empty())
      {
            colorA_t spcol=speccol;
            CFLOAT ref=edif, spa=specam, h=hard, stt=1;
            for(vector<blenderModulator_t>::const_iterator ite=mods.begin();ite!=mods.end();++ite)
            {
                  (*ite).modulate(Tresul, Rresul, state, sp, eye);
                  (*ite).blenderModulate(/**/col, spcol, /**/refc, /**/cm,/**/ refc0, ref, spa, h,/**/ em, al, stt, state, sp, eye);
            }
      }

      // emit, as well as 'ambient' part of cmir and negated alpha modulation here
      colorA_t rc;
      if (mat_mode & MAT_SHADELESS)
            rc = col + (Tresul+Rresul) + (1-al)*alphacol;
      else
            rc = col*em + (Tresul+Rresul) + (1-al)*alphacol;
      if (refc0!=0) rc += cm*refc;
      if (sp.hasVertexCol()) {
            // vcol_paint has priority over vcol_light
            if ((mat_mode & (MAT_VCOL_LIGHT | MAT_VCOL_PAINT))==MAT_VCOL_LIGHT) rc += col*(colorA_t)sp.vertex_col();
      }
      state.skipelement=oldorigin;
      return rc;
}


const color_t blenderShader_t::getDiffuse(renderState_t &state, const surfacePoint_t &sp, const vector3d_t &eye) const
{
      colorA_t col=scolor;
      if (sp.hasVertexCol()) {
            if (mat_mode & MAT_VCOL_PAINT) col = sp.vertex_col();
      }

      CFLOAT ref=edif;
      if (!mods.empty())
      {
            CFLOAT al=alpha, em=emit, stt=1;
            for(vector<blenderModulator_t>::const_iterator ite=mods.begin();ite!=mods.end();++ite)
            {
                  (*ite).blenderModulate(col, ref, em, al, stt, state, sp, eye);
            }
      }
      return col*ref;
}

void blenderShader_t::displace(renderState_t &state,surfacePoint_t &sp, const vector3d_t &eye, PFLOAT res) const
{
      if (!mods.empty())
      {
            for(vector<blenderModulator_t>::const_iterator ite=mods.begin();ite!=mods.end();++ite)
            {
                  (*ite).blenderDisplace(state, sp, eye, res*state.traveled);
            }
      }
}

shader_t * blenderShader_t::factory(paramMap_t &bparams,std::list<paramMap_t> &lmod,
                                renderEnvironment_t &render)
{
      color_t color(0.0), specular(0.0), mirror(0.0),
                              reflected(0.0), transmitted(0.0);
      CFLOAT difref=1, specam=0, hard=1, alpha=1, emit=0, ior=1, minref=0;
      bool fast_fresnel=false,tir=false;
      // new fresnel angle dependent colors
      color_t reflected2(0.0), transmitted2(0.0);
      string _matmodes;
      const string *matmodes = &_matmodes;

      bparams.getParam("color", color);
      bparams.getParam("specular_color", specular);
      bparams.getParam("mirror_color", mirror);
      bparams.getParam("diffuse_reflect", difref);
      bparams.getParam("specular_amount", specam);
      bparams.getParam("hard", hard);
      bparams.getParam("alpha", alpha);
      bparams.getParam("emit", emit);

      bparams.getParam("reflected", reflected);
      bparams.getParam("transmitted", transmitted);
      bparams.getParam("IOR", ior);
      bparams.getParam("min_refle", minref);
      bparams.getParam("fast_fresnel", fast_fresnel);
      bparams.getParam("tir", tir);
      bparams.getParam("matmodes", matmodes);

      // if not specified, make second fresnel color = first fresnel color
      if (!bparams.getParam("reflected2", reflected2)) reflected2 = reflected;
      if (!bparams.getParam("transmitted2", transmitted2)) transmitted2 = transmitted;

      blenderShader_t *ns = new blenderShader_t(color, specular, mirror, difref, specam, hard, alpha, emit,
                                                                                                                                    reflected, transmitted, reflected2, transmitted2,
                                                                                                                                    minref, ior, fast_fresnel,tir);
      ns->setMode(*matmodes);

      for(list<paramMap_t>::iterator i=lmod.begin();i!=lmod.end();++i)
      {
            CFLOAT      displace=0, trans=0, refle=0;
            int color=0,  csp=0, cmir=0, ref=0,
                        specular=0, hard=0, alpha=0, emit=0;
            CFLOAT colfac, varfac, def_var;
            color_t texcol(1.0, 0.0, 1.0);      //blender default purple
            color_t filtercol(1.0, 1.0, 1.0);   // texture filter color
            CFLOAT bri=1, con=1;    // texture brightness & contrast

            string _mode="mix";
            string _aflag=""; // alpha flag, can contain calc_alpha, use_alpha and/or neg_alpha
            string _texflag = "";
            string _shname;
            const string *mode=&_mode;
            const string *aflag=&_aflag;  // alpha flag, can contain calc_alpha, use_alpha and/or neg_alpha
            const string *texflag = &_texflag;
            const string *shname= &_shname;
            
            paramMap_t &params=*i;

            params.getParam("input",shname);
            shader_t *input=render.getShader(*shname);
            if(input==NULL)
            {
                  cerr << "Undefined block : " << *shname << endl;
                  continue;
            }

            params.getParam("color", color);
            params.getParam("normal", displace);
            params.getParam("colspec", csp);
            params.getParam("colmir", cmir);
            params.getParam("difref", ref);
            params.getParam("specular", specular);
            params.getParam("hard", hard);
            params.getParam("alpha", alpha);
            params.getParam("emit", emit);

            params.getParam("transmission", trans);
            params.getParam("reflection", refle);

            params.getParam("mode", mode);

            // string with possible multiple keywords: stencil/negative/no_rgb
            params.getParam("texflag", texflag);

            // the variation parameters
            params.getParam("colfac", colfac);
            params.getParam("def_var", def_var);
            params.getParam("varfac", varfac);

            // blender texture color
            params.getParam("texcol", texcol);

            params.getParam("filtercolor", filtercol);
            params.getParam("contrast", con);
            params.getParam("brightness", bri);

            params.getParam("alpha_flag", aflag);

            blenderModulator_t modu(input);

            if (*mode=="mix") modu.mode(MIX);
            if (*mode=="mul") modu.mode(MUL);
            if (*mode=="add") modu.mode(ADD);
            if (*mode=="sub") modu.mode(SUB);

            modu.color(color);
            modu.displace(displace);
            modu.colspec(csp);
            modu.cmir(cmir);
            modu.difref(ref);
            modu.specular(specular);
            modu.hard(hard);
            modu.alpha(alpha);
            modu.emit(emit);

            modu.transmision(trans);
            modu.reflection(refle);

            modu.setColFac(colfac);
            modu.setDVar(def_var);
            modu.setVarFac(varfac);
            modu.setTexFlag(*texflag);
            modu.setTexCol(texcol);

            modu.setFilterCol(filtercol);
            modu.setContrast(con);
            modu.setBrightness(bri);

            modu.setAlphaFlag(*aflag);

            ns->addModulator(modu);

            params.checkUnused("modulator");
      }
      return ns;
}


extern "C"
{

YAFRAYPLUGIN_EXPORT void registerPlugin(renderEnvironment_t &render)
{
      render.registerFactory("blendermapper",blenderMapperNode_t::factory);
      render.registerFactory("blendershader",blenderShader_t::factory);
      std::cout<<"Registered blendershaders\n";
}

}
__END_YAFRAY


Generated by  Doxygen 1.6.0   Back to index