diff options
Diffstat (limited to 'source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.cpp')
-rwxr-xr-x | source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.cpp | 431 |
1 files changed, 431 insertions, 0 deletions
diff --git a/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.cpp b/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.cpp new file mode 100755 index 00000000000..05da47914f3 --- /dev/null +++ b/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.cpp @@ -0,0 +1,431 @@ + +// +// Copyright (C) : Please refer to the COPYRIGHT file distributed +// with this source distribution. +// +// 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. +// +/////////////////////////////////////////////////////////////////////////////// + +#include "AdvancedStrokeShaders.h" +#include "../system/PseudoNoise.h" +#include "../system/RandGen.h" +#include "StrokeIterators.h" + +///////////////////////////////////////// +// +// CALLIGRAPHICS SHADER +// +///////////////////////////////////////// + + +CalligraphicShader::CalligraphicShader (real iMinThickness, real iMaxThickness, + const Vec2f &iOrientation, bool clamp) + : StrokeShader() +{ + _minThickness=iMinThickness; + _maxThickness=iMaxThickness; + _orientation = iOrientation; + _orientation.normalize(); + _clamp = clamp; +} + +float ksinToto=0; + +int +CalligraphicShader::shade(Stroke &ioStroke) const +{ + Interface0DIterator v; + Functions0D::VertexOrientation2DF0D fun; + StrokeVertex* sv; + for(v=ioStroke.verticesBegin(); + !v.isEnd(); + ++v) + { + real thickness; + if (fun(v) < 0) + return -1; + Vec2f vertexOri(fun.result); + Vec2r ori2d(-vertexOri[1], vertexOri[0]); + ori2d.normalizeSafe(); + real scal = ori2d * _orientation; + sv = dynamic_cast<StrokeVertex*>(&(*v)); + if (_clamp && (scal<0)) { + scal=0.0; + sv->attribute().setColor(1,1,1); + } + else { + scal=fabs(scal); + sv->attribute().setColor(0,0,0); + } + thickness=_minThickness+scal*(_maxThickness-_minThickness); + if (thickness<0.0) + thickness=0.0; + sv->attribute().setThickness(thickness/2.0,thickness/2.0); + } + + return 0; +} + +//void +//TipRemoverShader::shade(Stroke &ioStroke) const +//{ +// +// StrokeInternal::StrokeVertexIterator v, vend; +// for(v=ioStroke.strokeVerticesBegin(), vend=ioStroke.strokeVerticesEnd(); +// v!=vend; +// ++v) +// { +// if (((*v)->curvilinearAbscissa()<_tipLength) || +// ((*v)->strokeLength()-(*v)->curvilinearAbscissa()<_tipLength)) +// { +// (*v)->attribute().setThickness(0.0, 0.0); +// (*v)->attribute().setColor(1,1,1); +// } +// } +// +//} + + + +///////////////////////////////////////// +// +// SPATIAL NOISE SHADER +// +///////////////////////////////////////// + +static const unsigned NB_VALUE_NOISE = 512; + +SpatialNoiseShader::SpatialNoiseShader (float ioamount, float ixScale, int nbOctave, + bool smooth, bool pureRandom) + : StrokeShader() +{ + _amount = ioamount; + if (ixScale==0) _xScale=0; + else _xScale=1.0/ixScale/real(NB_VALUE_NOISE); + _nbOctave=nbOctave; + _smooth=smooth; + _pureRandom=pureRandom; +} +int +SpatialNoiseShader::shade(Stroke &ioStroke) const +{ + Interface0DIterator v, v2; + v=ioStroke.verticesBegin(); + Vec2r p(v->getProjectedX(), v->getProjectedY()); + v2=v; ++v2; + Vec2r p0(v2->getProjectedX(), v2->getProjectedY()); + p0=p+2*(p-p0); + StrokeVertex* sv; + sv = dynamic_cast<StrokeVertex*>(&(*v)); + real initU = sv->strokeLength()*real(NB_VALUE_NOISE); + if (_pureRandom) initU+=RandGen::drand48()*real(NB_VALUE_NOISE); + + Functions0D::VertexOrientation2DF0D fun; + while (!v.isEnd()) + { + sv = dynamic_cast<StrokeVertex*>(&(*v)); + Vec2r p(sv->getPoint()); + if (fun(v) < 0) + return -1; + Vec2r vertexOri(fun.result); + Vec2r ori2d(vertexOri[0], vertexOri[1]); + ori2d = Vec2r(p-p0); + ori2d.normalizeSafe(); + + PseudoNoise mynoise; + real bruit; + + if (_smooth) + bruit=mynoise.turbulenceSmooth(_xScale*sv->curvilinearAbscissa()+initU, + _nbOctave); + else + bruit=mynoise.turbulenceLinear(_xScale*sv->curvilinearAbscissa()+initU, + _nbOctave); + + Vec2r noise(-ori2d[1]*_amount*bruit, + ori2d[0]*_amount*bruit); + + sv->setPoint(p[0]+noise[0], p[1]+noise[1]); + p0=p; + + ++v; + } + + return 0; +} + + + +///////////////////////////////////////// +// +// SMOOTHING SHADER +// +///////////////////////////////////////// + + +SmoothingShader::SmoothingShader (int ionbIteration, real iFactorPoint, real ifactorCurvature, real iFactorCurvatureDifference, + real iAnisoPoint, real iAnisoNormal, real iAnisoCurvature, real iCarricatureFactor) + : StrokeShader() +{ + _nbIterations=ionbIteration; + _factorCurvature=ifactorCurvature; + _factorCurvatureDifference=iFactorCurvatureDifference; + _anisoNormal=iAnisoNormal; + _anisoCurvature=iAnisoCurvature; + _carricatureFactor=iCarricatureFactor; + _factorPoint=iFactorPoint; + _anisoPoint=iAnisoPoint; +} + + + +int +SmoothingShader::shade(Stroke &ioStroke) const +{ + //cerr<<" Smoothing a stroke "<<endl; + + Smoother smoother(ioStroke); + smoother.smooth(_nbIterations, _factorPoint, _factorCurvature, _factorCurvatureDifference, + _anisoPoint, _anisoNormal, _anisoCurvature, _carricatureFactor); + return 0; +} + +// SMOOTHER +//////////////////////////// + +Smoother::Smoother(Stroke &ioStroke) +{ + _stroke=&ioStroke; + + _nbVertices=ioStroke.vertices_size(); + _vertex=new Vec2r[_nbVertices]; + _curvature=new real[_nbVertices]; + _normal=new Vec2r[_nbVertices]; + StrokeInternal::StrokeVertexIterator v, vend; + int i=0; + for(v = ioStroke.strokeVerticesBegin(), vend = ioStroke.strokeVerticesEnd(); + v != vend; + ++v) + { + _vertex[i]=(v)->getPoint(); + i++; + } + Vec2r vec_tmp(_vertex[0]-_vertex[_nbVertices-1]); + _isClosedCurve = (vec_tmp.norm() < M_EPSILON); + + _safeTest=(_nbVertices>4); +} + +void Smoother::smooth(int nbIteration, real iFactorPoint, real ifactorCurvature, real iFactorCurvatureDifference, + real iAnisoPoint, real iAnisoNormal, real iAnisoCurvature, real iCarricatureFactor) +{ + _factorCurvature=ifactorCurvature; + _factorCurvatureDifference=iFactorCurvatureDifference; + _anisoNormal=iAnisoNormal; + _anisoCurvature=iAnisoCurvature; + _carricatureFactor=iCarricatureFactor; + _factorPoint=iFactorPoint; + _anisoPoint=iAnisoPoint; + + for (int i=0; i<nbIteration; i++) + iteration (); + copyVertices(); +} + +real edgeStopping (real x, real sigma) +{ + if (sigma==0.0) return 1.0; + return exp(-x*x/(sigma*sigma)); +} + +void +Smoother::iteration () +{ + computeCurvature(); + for (int i=1; i<_nbVertices-1; i++) + { + real motionNormal=_factorCurvature*_curvature[i]* + edgeStopping(_curvature[i], _anisoNormal); + + real diffC1=_curvature[i]-_curvature[i-1]; + real diffC2=_curvature[i]-_curvature[i+1]; + real motionCurvature=edgeStopping(diffC1, _anisoCurvature)*diffC1 + + edgeStopping(diffC2, _anisoCurvature)*diffC2;//_factorCurvatureDifference; + motionCurvature*=_factorCurvatureDifference; + //motionCurvature=_factorCurvatureDifference*(diffC1+diffC2); + if (_safeTest) + _vertex[i]=Vec2r(_vertex[i]+(motionNormal+motionCurvature)*_normal[i]); + Vec2r v1(_vertex[i-1]-_vertex[i]); + Vec2r v2(_vertex[i+1]-_vertex[i]); + real d1 = v1.norm(); + real d2 = v2.norm(); + _vertex[i]=Vec2r(_vertex[i]+ + _factorPoint*edgeStopping(d2, _anisoPoint)*(_vertex[i-1]-_vertex[i]) + + _factorPoint*edgeStopping(d1, _anisoPoint)*(_vertex[i+1]-_vertex[i]) ); + } + + if (_isClosedCurve) + { + real motionNormal=_factorCurvature*_curvature[0]* + edgeStopping(_curvature[0], _anisoNormal); + + real diffC1=_curvature[0]-_curvature[_nbVertices-2]; + real diffC2=_curvature[0]-_curvature[1]; + real motionCurvature=edgeStopping(diffC1, _anisoCurvature)*diffC1 + + edgeStopping(diffC2, _anisoCurvature)*diffC2;//_factorCurvatureDifference; + motionCurvature*=_factorCurvatureDifference; + //motionCurvature=_factorCurvatureDifference*(diffC1+diffC2); + _vertex[0]=Vec2r(_vertex[0]+(motionNormal+motionCurvature)*_normal[0]); + _vertex[_nbVertices-1]=_vertex[0]; + } +} + + +void +Smoother::computeCurvature () +{ + int i; + Vec2r BA, BC, normalCurvature; + for (i = 1; i < _nbVertices - 1; i++) + { + BA=_vertex[i-1]-_vertex[i]; + BC=_vertex[i+1]-_vertex[i]; + real lba=BA.norm(), lbc=BC.norm(); + BA.normalizeSafe(); + BC.normalizeSafe(); + normalCurvature = BA + BC; + + _normal[i]=Vec2r(-(BC-BA)[1], (BC-BA)[0]); + _normal[i].normalizeSafe(); + + _curvature[i] = normalCurvature * _normal[i]; + if (lba+lbc > M_EPSILON) + _curvature[i]/=(0.5*lba+lbc); + } + _curvature[0]=_curvature[1]; + _curvature[_nbVertices-1]=_curvature[_nbVertices-2]; + Vec2r di(_vertex[1]-_vertex[0]); + _normal[0] = Vec2r(-di[1], di[0]); + _normal[0].normalizeSafe(); + di=_vertex[_nbVertices-1]-_vertex[_nbVertices-2]; + _normal[_nbVertices-1]=Vec2r(-di[1], di[0]); + _normal[_nbVertices-1].normalizeSafe(); + + if (_isClosedCurve) + { + BA=_vertex[_nbVertices-2]-_vertex[0]; + BC=_vertex[1]-_vertex[0]; + real lba=BA.norm(), lbc=BC.norm(); + BA.normalizeSafe(); + BC.normalizeSafe(); + normalCurvature = BA + BC; + + _normal[i]=Vec2r(-(BC-BA)[1], (BC-BA)[0]); + _normal[i].normalizeSafe(); + + _curvature[i] = normalCurvature * _normal[i]; + if (lba+lbc > M_EPSILON) + _curvature[i]/=(0.5*lba+lbc); + + _normal[_nbVertices-1]=_normal[0]; + _curvature[_nbVertices-1]=_curvature[0]; + } +} + +void +Smoother::copyVertices () +{ + int i=0; + StrokeInternal::StrokeVertexIterator v, vend; + for(v=_stroke->strokeVerticesBegin(), vend=_stroke->strokeVerticesEnd(); + v!=vend; + ++v) + { + const Vec2r p0((v)->getPoint()); + const Vec2r p1(_vertex[i]); + Vec2r p(p0 + _carricatureFactor * (p1 - p0)); + + (v)->setPoint(p[0], p[1]); + i++; + } + +} + + +///////////////////////////////////////// +// +// OMISSION SHADER +// +///////////////////////////////////////// + +OmissionShader::OmissionShader (real sizeWindow, real thrVari, real thrFlat, real lFlat) +{ + _sizeWindow=sizeWindow; + _thresholdVariation=thrVari; + _thresholdFlat=thrFlat; + _lengthFlat=lFlat; +} + +int +OmissionShader::shade(Stroke &ioStroke) const +{ + Omitter omi(ioStroke); + omi.omit(_sizeWindow, _thresholdVariation, _thresholdFlat, _lengthFlat); + + return 0; +} + + +// OMITTER +/////////////////////////// + +Omitter::Omitter (Stroke &ioStroke) + :Smoother (ioStroke) +{ + StrokeInternal::StrokeVertexIterator v, vend; + int i=0; + for(v=ioStroke.strokeVerticesBegin(), vend=ioStroke.strokeVerticesEnd(); + v!=vend; + ++v) + { + _u[i]=(v)->curvilinearAbscissa(); + i++; + } + +} + +void +Omitter::omit (real sizeWindow, real thrVari, real thrFlat, real lFlat) +{ + _sizeWindow=sizeWindow; + _thresholdVariation=thrVari; + _thresholdFlat=thrFlat; + _lengthFlat=lFlat; + + for (int i=1; i<_nbVertices-1; i++) + { + if (_u[i]<_lengthFlat) continue; + // is the previous segment flat? + int j=i-1; + while ((j>=0) && (_u[i]-_u[j]<_lengthFlat)) + { + if ((_normal[j] * _normal[i]) < _thresholdFlat) + ; // FIXME + j--; + } + + } +} |