diff options
Diffstat (limited to 'source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.cpp')
-rw-r--r-- | source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.cpp | 404 |
1 files changed, 404 insertions, 0 deletions
diff --git a/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.cpp b/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.cpp new file mode 100644 index 00000000000..e631b9f4471 --- /dev/null +++ b/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.cpp @@ -0,0 +1,404 @@ +/* + * ***** 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) 2010 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/freestyle/intern/stroke/AdvancedStrokeShaders.cpp + * \ingroup freestyle + * \brief Fredo's stroke shaders + * \author Fredo Durand + * \date 17/12/2002 + */ + +#include "AdvancedStrokeShaders.h" +#include "StrokeIterators.h" + +#include "../system/PseudoNoise.h" +#include "../system/RandGen.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.0f; + +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; +} + +#if 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); + } + } +} +#endif + +///////////////////////////////////////// +// +// 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, ++i) { + _vertex[i] = (v)->getPoint(); + } + 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(); +} + +static 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; + } +} + +#if 0 // FIXME + +///////////////////////////////////////// +// +// 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, ++i) { + _u[i] = (v)->curvilinearAbscissa(); + } +} + +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; + } + } +} + +#endif |