Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaxime Curioni <maxime.curioni@gmail.com>2008-05-08 23:16:40 +0400
committerMaxime Curioni <maxime.curioni@gmail.com>2008-05-08 23:16:40 +0400
commit64e4a3ec9aed6c8abe095e2cd1fe1552f7cde51c (patch)
tree6c77358bd447b6c2d215324ef48fc12d1f5ae5ca /source/blender/freestyle/intern/stroke
parentcf2e1e2857cfc5b3c2848c7fc6c9d919ac72fabb (diff)
parent106974a9d2d5caa5188322507980e3d57d2e3517 (diff)
soc-2008-mxcurioni: merged changes to revision 14747, cosmetic changes for source/blender/freestyle
Diffstat (limited to 'source/blender/freestyle/intern/stroke')
-rwxr-xr-xsource/blender/freestyle/intern/stroke/AdvancedFunctions0D.cpp85
-rwxr-xr-xsource/blender/freestyle/intern/stroke/AdvancedFunctions0D.h209
-rwxr-xr-xsource/blender/freestyle/intern/stroke/AdvancedFunctions1D.cpp108
-rwxr-xr-xsource/blender/freestyle/intern/stroke/AdvancedFunctions1D.h286
-rwxr-xr-xsource/blender/freestyle/intern/stroke/AdvancedPredicates1D.h81
-rwxr-xr-xsource/blender/freestyle/intern/stroke/AdvancedStrokeShaders.cpp423
-rwxr-xr-xsource/blender/freestyle/intern/stroke/AdvancedStrokeShaders.h222
-rwxr-xr-xsource/blender/freestyle/intern/stroke/BasicStrokeShaders.cpp1100
-rwxr-xr-xsource/blender/freestyle/intern/stroke/BasicStrokeShaders.h791
-rwxr-xr-xsource/blender/freestyle/intern/stroke/Canvas.cpp427
-rwxr-xr-xsource/blender/freestyle/intern/stroke/Canvas.h198
-rwxr-xr-xsource/blender/freestyle/intern/stroke/Chain.cpp126
-rwxr-xr-xsource/blender/freestyle/intern/stroke/Chain.h82
-rwxr-xr-xsource/blender/freestyle/intern/stroke/ChainingIterators.cpp147
-rwxr-xr-xsource/blender/freestyle/intern/stroke/ChainingIterators.h364
-rwxr-xr-xsource/blender/freestyle/intern/stroke/ContextFunctions.cpp60
-rwxr-xr-xsource/blender/freestyle/intern/stroke/ContextFunctions.h124
-rwxr-xr-xsource/blender/freestyle/intern/stroke/Curve.cpp818
-rwxr-xr-xsource/blender/freestyle/intern/stroke/Curve.h463
-rwxr-xr-xsource/blender/freestyle/intern/stroke/CurveAdvancedIterators.h378
-rwxr-xr-xsource/blender/freestyle/intern/stroke/CurveIterators.h295
-rwxr-xr-xsource/blender/freestyle/intern/stroke/Modifiers.h71
-rwxr-xr-xsource/blender/freestyle/intern/stroke/Module.h72
-rwxr-xr-xsource/blender/freestyle/intern/stroke/Operators.cpp862
-rwxr-xr-xsource/blender/freestyle/intern/stroke/Operators.h311
-rwxr-xr-xsource/blender/freestyle/intern/stroke/PSStrokeRenderer.cpp89
-rwxr-xr-xsource/blender/freestyle/intern/stroke/PSStrokeRenderer.h63
-rwxr-xr-xsource/blender/freestyle/intern/stroke/Predicates0D.h160
-rwxr-xr-xsource/blender/freestyle/intern/stroke/Predicates1D.h438
-rwxr-xr-xsource/blender/freestyle/intern/stroke/QInformationMap.h58
-rwxr-xr-xsource/blender/freestyle/intern/stroke/Stroke.cpp949
-rwxr-xr-xsource/blender/freestyle/intern/stroke/Stroke.h584
-rwxr-xr-xsource/blender/freestyle/intern/stroke/StrokeAdvancedIterators.h142
-rwxr-xr-xsource/blender/freestyle/intern/stroke/StrokeIO.cpp55
-rwxr-xr-xsource/blender/freestyle/intern/stroke/StrokeIO.h47
-rwxr-xr-xsource/blender/freestyle/intern/stroke/StrokeIterators.h227
-rwxr-xr-xsource/blender/freestyle/intern/stroke/StrokeLayer.cpp55
-rwxr-xr-xsource/blender/freestyle/intern/stroke/StrokeLayer.h75
-rwxr-xr-xsource/blender/freestyle/intern/stroke/StrokeRenderer.cpp146
-rwxr-xr-xsource/blender/freestyle/intern/stroke/StrokeRenderer.h140
-rwxr-xr-xsource/blender/freestyle/intern/stroke/StrokeRep.cpp820
-rwxr-xr-xsource/blender/freestyle/intern/stroke/StrokeRep.h138
-rwxr-xr-xsource/blender/freestyle/intern/stroke/StrokeShader.h119
-rwxr-xr-xsource/blender/freestyle/intern/stroke/StrokeTesselator.cpp88
-rwxr-xr-xsource/blender/freestyle/intern/stroke/StrokeTesselator.h67
-rwxr-xr-xsource/blender/freestyle/intern/stroke/StyleModule.h144
-rwxr-xr-xsource/blender/freestyle/intern/stroke/TextStrokeRenderer.cpp73
-rwxr-xr-xsource/blender/freestyle/intern/stroke/TextStrokeRenderer.h68
-rwxr-xr-xsource/blender/freestyle/intern/stroke/src.pri54
-rwxr-xr-xsource/blender/freestyle/intern/stroke/stroke.pro89
50 files changed, 12991 insertions, 0 deletions
diff --git a/source/blender/freestyle/intern/stroke/AdvancedFunctions0D.cpp b/source/blender/freestyle/intern/stroke/AdvancedFunctions0D.cpp
new file mode 100755
index 00000000000..c22e183eccb
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/AdvancedFunctions0D.cpp
@@ -0,0 +1,85 @@
+
+//
+// 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 "../view_map/Functions0D.h"
+# include "AdvancedFunctions0D.h"
+# include "../view_map/SteerableViewMap.h"
+# include "Canvas.h"
+
+namespace Functions0D {
+
+ double DensityF0D::operator()(Interface0DIterator& iter) {
+ Canvas* canvas = Canvas::getInstance();
+ int bound = _filter.getBound();
+ if( (iter->getProjectedX()-bound < 0) || (iter->getProjectedX()+bound>canvas->width())
+ || (iter->getProjectedY()-bound < 0) || (iter->getProjectedY()+bound>canvas->height()))
+ return 0.0;
+ RGBImage image;
+ canvas->readColorPixels((int)iter->getProjectedX() - bound,
+ (int)iter->getProjectedY() - bound,
+ _filter.maskSize(),
+ _filter.maskSize(),
+ image);
+ return _filter.getSmoothedPixel<RGBImage>(&image, (int)iter->getProjectedX(),
+ (int)iter->getProjectedY());
+ }
+
+
+ double LocalAverageDepthF0D::operator()(Interface0DIterator& iter) {
+ Canvas * iViewer = Canvas::getInstance();
+ int bound = _filter.getBound();
+
+ if( (iter->getProjectedX()-bound < 0) || (iter->getProjectedX()+bound>iViewer->width())
+ || (iter->getProjectedY()-bound < 0) || (iter->getProjectedY()+bound>iViewer->height()))
+ return 0.0;
+ GrayImage image ;
+ iViewer->readDepthPixels((int)iter->getProjectedX()-bound,(int)iter->getProjectedY()-bound,_filter.maskSize(),_filter.maskSize(),image);
+ return _filter.getSmoothedPixel(&image, (int)iter->getProjectedX(), (int)iter->getProjectedY());
+ }
+
+ float ReadMapPixelF0D::operator()(Interface0DIterator& iter) {
+ Canvas * canvas = Canvas::getInstance();
+ return canvas->readMapPixel(_mapName, _level, (int)iter->getProjectedX(), (int)iter->getProjectedY());
+ }
+
+ float ReadSteerableViewMapPixelF0D::operator()(Interface0DIterator& iter) {
+ SteerableViewMap *svm = Canvas::getInstance()->getSteerableViewMap();
+ float v = svm->readSteerableViewMapPixel(_orientation, _level,(int)iter->getProjectedX(), (int)iter->getProjectedY());
+ return v;
+ }
+
+ float ReadCompleteViewMapPixelF0D::operator()(Interface0DIterator& iter) {
+ SteerableViewMap *svm = Canvas::getInstance()->getSteerableViewMap();
+ float v = svm->readCompleteViewMapPixel(_level,(int)iter->getProjectedX(), (int)iter->getProjectedY());
+ return v;
+ }
+
+ float GetViewMapGradientNormF0D::operator()(Interface0DIterator& iter){
+ SteerableViewMap *svm = Canvas::getInstance()->getSteerableViewMap();
+ float pxy = svm->readCompleteViewMapPixel(_level,(int)iter->getProjectedX(), (int)iter->getProjectedY());
+ float gx = svm->readCompleteViewMapPixel(_level,(int)iter->getProjectedX()+_step, (int)iter->getProjectedY())
+ - pxy;
+ float gy = svm->readCompleteViewMapPixel(_level,(int)iter->getProjectedX(), (int)iter->getProjectedY()+_step)
+ - pxy;
+ float f = Vec2f(gx,gy).norm();
+ return f;
+ }
+} // end of namespace Functions0D
diff --git a/source/blender/freestyle/intern/stroke/AdvancedFunctions0D.h b/source/blender/freestyle/intern/stroke/AdvancedFunctions0D.h
new file mode 100755
index 00000000000..d92575cf110
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/AdvancedFunctions0D.h
@@ -0,0 +1,209 @@
+//
+// Filename : AdvancedFunctions0D.h
+// Author(s) : Stephane Grabli
+// Emmanuel Turquin
+// Purpose : Functions taking 0D input
+// Date of creation : 01/07/2003
+//
+///////////////////////////////////////////////////////////////////////////////
+
+
+//
+// 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef ADVANCED_FUNCTIONS0D_HPP
+# define ADVANCED_FUNCTIONS0D_HPP
+
+
+# include "../image/Image.h"
+# include "../image/GaussianFilter.h"
+# include "../view_map/Functions0D.h"
+
+//
+// Functions definitions
+//
+///////////////////////////////////////////////////////////
+
+namespace Functions0D {
+
+ // DensityF0D
+ /*! Returns the density of the (result) image evaluated at an Interface0D.
+ * This density is evaluated using a pixels square window around the
+ * evaluation point and integrating these values using
+ * a gaussian.
+ */
+ class LIB_STROKE_EXPORT DensityF0D : public UnaryFunction0D<double>
+ {
+ public:
+ /*! Builds the functor from the gaussian sigma value.
+ * \param sigma
+ * sigma indicates the x value for which the gaussian
+ * function is 0.5. It leads to the window size
+ * value. (the larger, the smoother)
+ */
+ DensityF0D(double sigma = 2) : UnaryFunction0D<double>() {
+ _filter.SetSigma((float)sigma);
+ }
+ /*! Returns the string "DensityF0D"*/
+ string getName() const {
+ return "DensityF0D";
+ }
+ /*! The () operator. */
+ double operator()(Interface0DIterator& iter);
+
+ private:
+
+ GaussianFilter _filter;
+ };
+
+ // LocalAverageDepthF0D
+ /*! Returns the average depth around a point.
+ * The result is obtained by querying the
+ * depth buffer on a window around that point.
+ */
+ class LIB_STROKE_EXPORT LocalAverageDepthF0D : public UnaryFunction0D<double>
+ {
+ private:
+ GaussianFilter _filter;
+ public:
+ /*! Builds the functor from the size of the mask that
+ * will be used.
+ */
+ LocalAverageDepthF0D(real maskSize=5.f) : UnaryFunction0D<double>() {
+ _filter.SetSigma((float)maskSize/2.f);
+ }
+ /*! Returns the string "LocalAverageDepthF0D"*/
+ string getName() const {
+ return "LocalAverageDepthF0D";
+ }
+ /*! the () operator.*/
+ double operator()(Interface0DIterator& iter);
+ };
+
+ // ReadMapPixel
+ /*! Reads a pixel in a map.
+ */
+ class LIB_STROKE_EXPORT ReadMapPixelF0D : public UnaryFunction0D<float>
+ {
+ private:
+ const char * _mapName;
+ int _level;
+ public:
+ /*! Builds the functor from name of the
+ * Map that must be read.
+ * \param iMapName
+ * The name of the map.
+ * \param level
+ * The level of the pyramid from which
+ * the pixel must be read.
+ */
+ ReadMapPixelF0D(const char *iMapName, int level) : UnaryFunction0D<float>() {
+ _mapName = iMapName;
+ _level = level;
+ }
+ /*! Returns the string "ReadMapPixelF0D"*/
+ string getName() const {
+ return "ReadMapPixelF0D";
+ }
+ /*! the () operator.*/
+ float operator()(Interface0DIterator& iter);
+ };
+
+ // ReadSteerableViewMapPixel
+ /*! Reads a pixel in one of the level of one of the steerable viewmaps.
+ */
+ class LIB_STROKE_EXPORT ReadSteerableViewMapPixelF0D : public UnaryFunction0D<float>
+ {
+ private:
+ unsigned _orientation;
+ int _level;
+ public:
+ /*! Builds the functor
+ * \param nOrientation
+ * The integer belonging to [0,4] indicating the orientation (E,NE,N,NW)
+ * we are interested in.
+ * \param level
+ * The level of the pyramid from which
+ * the pixel must be read.
+ */
+ ReadSteerableViewMapPixelF0D(unsigned nOrientation, int level) : UnaryFunction0D<float>() {
+ _orientation = nOrientation;
+ _level = level;
+ }
+ /*! Returns the string "ReadSteerableViewMapPixelF0D"*/
+ string getName() const {
+ return "ReadSteerableViewMapPixelF0D";
+ }
+ /*! the () operator.*/
+ float operator()(Interface0DIterator& iter);
+ };
+
+ // ReadCompleteViewMapPixel
+ /*! Reads a pixel in one of the level of the complete viewmap.
+ */
+ class LIB_STROKE_EXPORT ReadCompleteViewMapPixelF0D : public UnaryFunction0D<float>
+ {
+ private:
+ int _level;
+ public:
+ /*! Builds the functor
+ * \param level
+ * The level of the pyramid from which
+ * the pixel must be read.
+ */
+ ReadCompleteViewMapPixelF0D(int level) : UnaryFunction0D<float>() {
+ _level = level;
+ }
+ /*! Returns the string "ReadCompleteViewMapPixelF0D"*/
+ string getName() const {
+ return "ReadCompleteViewMapPixelF0D";
+ }
+ /*! the () operator.*/
+ float operator()(Interface0DIterator& iter);
+ };
+
+ // GetViewMapGradientNormF0D
+ /*! Returns the norm of the gradient of the global viewmap density image.
+ */
+ class LIB_STROKE_EXPORT GetViewMapGradientNormF0D: public UnaryFunction0D< float>
+ {
+ private:
+ int _level;
+ float _step;
+ public:
+ /*! Builds the functor
+ * \param level
+ * The level of the pyramid from which
+ * the pixel must be read.
+ */
+ GetViewMapGradientNormF0D(int level) : UnaryFunction0D<float>() {
+ _level = level;
+ _step = (float)pow(2.0,_level);
+ }
+ /*! Returns the string "GetOccludeeF0D"*/
+ string getName() const {
+ return "GetViewMapGradientNormF0D";
+ }
+ /*! the () operator.*/
+ float operator()(Interface0DIterator& iter);
+ };
+} // end of namespace Functions0D
+
+#endif // ADVANCED_FUNCTIONS0D_HPP
diff --git a/source/blender/freestyle/intern/stroke/AdvancedFunctions1D.cpp b/source/blender/freestyle/intern/stroke/AdvancedFunctions1D.cpp
new file mode 100755
index 00000000000..cf2982606e0
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/AdvancedFunctions1D.cpp
@@ -0,0 +1,108 @@
+
+//
+// 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 "AdvancedFunctions1D.h"
+# include "../view_map/SteerableViewMap.h"
+# include "Canvas.h"
+
+// FIXME
+namespace Functions1D {
+
+ real GetSteerableViewMapDensityF1D::operator()(Interface1D& inter) {
+ SteerableViewMap * svm = Canvas::getInstance()->getSteerableViewMap();
+ Interface0DIterator it = inter.pointsBegin(_sampling);
+ Interface0DIterator itnext = it;++itnext;
+ FEdge *fe;
+ unsigned nSVM;
+ vector<float> values;
+ while(!itnext.isEnd()){
+ Interface0D& i0D = (*it);
+ Interface0D& i0Dnext = (*itnext);
+ fe = i0D.getFEdge(i0Dnext);
+ if(fe == 0){
+ cerr << "GetSteerableViewMapDensityF1D warning: no FEdge between " << i0D.getId() << " and " << i0Dnext.getId() << endl;
+ // compute the direction between these two ???
+ Vec2f dir = i0Dnext.getPoint2D()-i0D.getPoint2D();
+ nSVM = svm->getSVMNumber(dir);
+ }else{
+ nSVM = svm->getSVMNumber(fe->getId().getFirst());
+ }
+ Vec2r m((i0D.getProjectedX()+i0Dnext.getProjectedX())/2.0,
+ (i0D.getProjectedY()+i0Dnext.getProjectedY())/2.0);
+ values.push_back(svm->readSteerableViewMapPixel(nSVM,_level,(int)m[0],(int)m[1]));
+ ++it;++itnext;
+ }
+ float res, res_tmp;
+ vector<float>::iterator v = values.begin(), vend=values.end();
+ unsigned size = 1;
+ switch(_integration) {
+ case MIN:
+ res = *v;++v;
+ for (; v!=vend; ++v) {
+ res_tmp = *v;
+ if (res_tmp < res)
+ res = res_tmp;
+ }
+ break;
+ case MAX:
+ res = *v;++v;
+ for (; v!=vend; ++v) {
+ res_tmp = *v;
+ if (res_tmp > res)
+ res = res_tmp;
+ }
+ break;
+ case FIRST:
+ res = *v;
+ break;
+ case LAST:
+ --vend;
+ res = *vend;
+ break;
+ case MEAN:
+ default:
+ res = *v;++v;
+ for (; v!=vend; ++v, ++size)
+ res += *v;
+ res /= (size ? size : 1);
+ break;
+ }
+ return res;
+ }
+
+ double GetDirectionalViewMapDensityF1D::operator()(Interface1D& inter) {
+ unsigned size;
+ double res = integrate(_fun, inter.pointsBegin(_sampling), inter.pointsEnd(_sampling), _integration);
+ return res;
+ }
+
+ double GetCompleteViewMapDensityF1D::operator()(Interface1D& inter) {
+ unsigned size;
+ Id id = inter.getId();
+ double res = integrate(_fun, inter.pointsBegin(_sampling), inter.pointsEnd(_sampling), _integration);
+ return res;
+ }
+
+ real GetViewMapGradientNormF1D::operator()(Interface1D& inter){
+ return integrate(_func, inter.pointsBegin(_sampling), inter.pointsEnd(_sampling), _integration);
+ }
+}
+
diff --git a/source/blender/freestyle/intern/stroke/AdvancedFunctions1D.h b/source/blender/freestyle/intern/stroke/AdvancedFunctions1D.h
new file mode 100755
index 00000000000..65b0eec36fd
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/AdvancedFunctions1D.h
@@ -0,0 +1,286 @@
+//
+// Filename : AdvancedFunctions1D.h
+// Author(s) : Stephane Grabli, Emmanuel Turquin
+// Purpose : Functions taking 1D input
+// Date of creation : 01/07/2003
+//
+///////////////////////////////////////////////////////////////////////////////
+
+
+//
+// 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef ADVANCED_FUNCTIONS1D_HPP
+# define ADVANCED_FUNCTIONS1D_HPP
+
+
+# include "AdvancedFunctions0D.h"
+# include "../view_map/Functions1D.h"
+
+//
+// Functions definitions
+//
+///////////////////////////////////////////////////////////
+
+namespace Functions1D {
+
+ // DensityF1D
+ /*! Returns the density evaluated for an Interface1D.
+ * The density is evaluated for a set of points along
+ * the Interface1D (using the DensityF0D functor)
+ * with a user-defined sampling and
+ * then integrated into a single value using
+ * a user-defined integration method.
+ */
+ class DensityF1D : public UnaryFunction1D<double>
+ {
+ private:
+ float _sampling;
+ public:
+ /*! Builds the functor.
+ * \param sigma
+ * Thesigma used in DensityF0D and determining
+ * the window size used in each density query.
+ * \param iType
+ * The integration method used to compute
+ * a single value from a set of values.
+ * \param sampling
+ * The resolution used to sample the chain: the corresponding 0D function
+ * is evaluated at each sample point and the result is obtained by
+ * combining the resulting values into a single one, following the
+ * method specified by iType.
+ */
+ DensityF1D(double sigma = 2, IntegrationType iType = MEAN, float sampling=2.f) : UnaryFunction1D<double>(iType), _fun(sigma) {
+ _sampling = sampling;
+ }
+ /*! Destructor */
+ virtual ~DensityF1D(){}
+
+ /*! Returns the string "DensityF1D"*/
+ string getName() const {
+ return "DensityF1D";
+ }
+ /*! the () operator.*/
+ double operator()(Interface1D& inter) {
+ return integrate(_fun, inter.pointsBegin(_sampling), inter.pointsEnd(_sampling), _integration);
+ }
+ private:
+ Functions0D::DensityF0D _fun;
+ };
+
+ // LocalAverageDepthF1D
+ /*! Returns the average depth evaluated for an Interface1D.
+ * The average depth is evaluated for a set of points along
+ * the Interface1D (using the LocalAverageDepthF0D functor)
+ * with a user-defined sampling and
+ * then integrated into a single value using
+ * a user-defined integration method.
+ */
+ class LocalAverageDepthF1D : public UnaryFunction1D<double>
+ {
+ public:
+ /*! Builds the functor.
+ * \param sigma
+ * The sigma used in DensityF0D and determining
+ * the window size used in each density query.
+ * \param iType
+ * The integration method used to compute
+ * a single value from a set of values.
+ */
+ LocalAverageDepthF1D(real sigma, IntegrationType iType = MEAN)
+ : UnaryFunction1D<double>(iType), _fun(sigma){
+ }
+ /*! Returns the string "LocalAverageDepthF1D"*/
+ string getName() const {
+ return "LocalAverageDepthF1D";
+ }
+ /*! the () operator.*/
+ double operator()(Interface1D& inter) {
+ return integrate(_fun, inter.verticesBegin(), inter.verticesEnd(), _integration);
+ }
+ private:
+ Functions0D::LocalAverageDepthF0D _fun;
+ };
+
+ // GetCompleteViewMapDensity
+ /*! Returns the density evaluated for an Interface1D in the
+ * complete viewmap image.
+ * The density is evaluated for a set of points along
+ * the Interface1D (using the ReadCompleteViewMapPixelF0D functor)
+ * and then integrated into a single value using
+ * a user-defined integration method.
+ */
+ class LIB_STROKE_EXPORT GetCompleteViewMapDensityF1D : public UnaryFunction1D<double>
+ {
+ public:
+ /*! Builds the functor.
+ * \param level
+ * The level of the pyramid from which
+ * the pixel must be read.
+ * \param iType
+ * The integration method used to compute
+ * a single value from a set of values.
+ * \param sampling
+ * The resolution used to sample the chain: the corresponding 0D function
+ * is evaluated at each sample point and the result is obtained by
+ * combining the resulting values into a single one, following the
+ * method specified by iType.
+ */
+ GetCompleteViewMapDensityF1D(unsigned level, IntegrationType iType = MEAN, float sampling=2.f)
+ : UnaryFunction1D<double>(iType), _fun(level){_sampling = sampling;}
+ /*! Returns the string "GetCompleteViewMapDensityF1D"*/
+ string getName() const {
+ return "GetCompleteViewMapDensityF1D";
+ }
+ /*! the () operator.*/
+ double operator()(Interface1D& inter);
+
+ private:
+ Functions0D::ReadCompleteViewMapPixelF0D _fun;
+ float _sampling;
+ };
+
+ // GetDirectionalViewMapDensity
+ /*! Returns the density evaluated for an Interface1D in of the
+ * steerable viewmaps image.
+ * The direction telling which Directional map to choose
+ * is explicitely specified by the user.
+ * The density is evaluated for a set of points along
+ * the Interface1D (using the ReadSteerableViewMapPixelF0D functor)
+ * and then integrated into a single value using
+ * a user-defined integration method.
+ */
+ class LIB_STROKE_EXPORT GetDirectionalViewMapDensityF1D : public UnaryFunction1D<double>
+ {
+ public:
+ /*! Builds the functor.
+ * \param iOrientation
+ * The number of the directional map
+ * we must work with.
+ * \param level
+ * The level of the pyramid from which
+ * the pixel must be read.
+ * \param iType
+ * The integration method used to compute
+ * a single value from a set of values.
+ * \param sampling
+ * The resolution used to sample the chain: the corresponding 0D function
+ * is evaluated at each sample point and the result is obtained by
+ * combining the resulting values into a single one, following the
+ * method specified by iType.
+ */
+ GetDirectionalViewMapDensityF1D(unsigned iOrientation, unsigned level, IntegrationType iType = MEAN, float sampling=2.f)
+ : UnaryFunction1D<double>(iType), _fun(iOrientation,level){_sampling = sampling;}
+ /*! Returns the string "GetDirectionalViewMapDensityF1D"*/
+ string getName() const {
+ return "GetDirectionalViewMapDensityF1D";
+ }
+ /*! the () operator.*/
+ double operator()(Interface1D& inter);
+
+ private:
+ Functions0D::ReadSteerableViewMapPixelF0D _fun;
+ float _sampling;
+ };
+
+ // GetSteerableViewMapDensityF1D
+ /*! Returns the density of the viewmap
+ * for a given Interface1D. The density of each
+ * FEdge is evaluated in the proper steerable
+ * ViewMap depending on its oorientation.
+ */
+ class LIB_STROKE_EXPORT GetSteerableViewMapDensityF1D : public UnaryFunction1D<real>
+ {
+ private:
+ int _level;
+ float _sampling;
+ public:
+ /*! Builds the functor from the level
+ * of the pyramid from which the pixel must be read.
+ * \param level
+ * The level of the pyramid from which
+ * the pixel must be read.
+ * \param iType
+ * The integration method used to compute
+ * a single value from a set of values.
+ * \param sampling
+ * The resolution used to sample the chain: the corresponding 0D function
+ * is evaluated at each sample point and the result is obtained by
+ * combining the resulting values into a single one, following the
+ * method specified by iType.
+ */
+ GetSteerableViewMapDensityF1D(int level,IntegrationType iType = MEAN, float sampling=2.f) : UnaryFunction1D<real>(iType) {
+ _level = level;
+ _sampling = sampling;
+ }
+ /*! Destructor */
+ virtual ~GetSteerableViewMapDensityF1D(){}
+
+ /*! Returns the string "GetSteerableViewMapDensityF1D"*/
+ string getName() const {
+ return "GetSteerableViewMapDensityF1D";
+ }
+ /*! the () operator.*/
+ real operator()(Interface1D& inter);
+ };
+
+ // GetViewMapGradientNormF1D
+ /*! Returns the density of the viewmap
+ * for a given Interface1D. The density of each
+ * FEdge is evaluated in the proper steerable
+ * ViewMap depending on its oorientation.
+ */
+ class LIB_STROKE_EXPORT GetViewMapGradientNormF1D : public UnaryFunction1D<real>
+ {
+ private:
+ int _level;
+ float _sampling;
+ Functions0D::GetViewMapGradientNormF0D _func;
+ public:
+ /*! Builds the functor from the level
+ * of the pyramid from which the pixel must be read.
+ * \param level
+ * The level of the pyramid from which
+ * the pixel must be read.
+ * \param iType
+ * The integration method used to compute
+ * a single value from a set of values.
+ * \param sampling
+ * The resolution used to sample the chain: the corresponding 0D function
+ * is evaluated at each sample point and the result is obtained by
+ * combining the resulting values into a single one, following the
+ * method specified by iType.
+ */
+ GetViewMapGradientNormF1D(int level,IntegrationType iType = MEAN, float sampling=2.f)
+ : UnaryFunction1D<real>(iType), _func(level) {
+ _level = level;
+ _sampling = sampling;
+ }
+
+ /*! Returns the string "GetSteerableViewMapDensityF1D"*/
+ string getName() const {
+ return "GetViewMapGradientNormF1D";
+ }
+ /*! the () operator.*/
+ real operator()(Interface1D& inter);
+ };
+} // end of namespace Functions1D
+
+#endif // ADVANCED_FUNCTIONS1D_HPP
diff --git a/source/blender/freestyle/intern/stroke/AdvancedPredicates1D.h b/source/blender/freestyle/intern/stroke/AdvancedPredicates1D.h
new file mode 100755
index 00000000000..f348f8593e5
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/AdvancedPredicates1D.h
@@ -0,0 +1,81 @@
+//
+// Filename : AdvancedPredicates1D.h
+// Author(s) : Stephane Grabli
+// Purpose : Class gathering stroke creation algorithms
+// Date of creation : 01/07/2003
+//
+///////////////////////////////////////////////////////////////////////////////
+
+
+//
+// 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef ADVANCED_PREDICATES1D_H
+# define ADVANCED_PREDICATES1D_H
+
+# include <string>
+# include "../view_map/Interface1D.h"
+# include "AdvancedFunctions1D.h"
+# include "Predicates1D.h"
+
+//
+// Predicates definitions
+//
+///////////////////////////////////////////////////////////
+
+namespace Predicates1D {
+
+ // DensityLowerThanUP1D
+ /*! Returns true if the density evaluated for the
+ * Interface1D is less than a user-defined density value.
+ */
+ class DensityLowerThanUP1D : public UnaryPredicate1D
+ {
+ public:
+ /*! Builds the functor.
+ * \param threshold
+ * The value of the threshold density.
+ * Any Interface1D having a density lower than
+ * this threshold will match.
+ * \param sigma
+ * The sigma value defining the density evaluation window size
+ * used in the DensityF0D functor.
+ */
+ DensityLowerThanUP1D(double threshold, double sigma = 2) {
+ _threshold = threshold;
+ _sigma = sigma;
+ }
+ /*! Returns the string "DensityLowerThanUP1D"*/
+ string getName() const {
+ return "DensityLowerThanUP1D";
+ }
+ /*! The () operator. */
+ bool operator()(Interface1D& inter) {
+ Functions1D::DensityF1D fun(_sigma);
+ return (fun(inter) < _threshold);
+ }
+ private:
+ double _sigma;
+ double _threshold;
+ };
+
+} // end of namespace Predicates1D
+
+#endif // ADVANCED_PREDICATES1D_H
diff --git a/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.cpp b/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.cpp
new file mode 100755
index 00000000000..b1c5317c5f1
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.cpp
@@ -0,0 +1,423 @@
+
+//
+// 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 "../system/PseudoNoise.h"
+#include "../system/RandGen.h"
+#include "AdvancedStrokeShaders.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;
+
+void
+CalligraphicShader::shade(Stroke &ioStroke) const
+{
+ Interface0DIterator v;
+ Functions0D::VertexOrientation2DF0D fun;
+ StrokeVertex* sv;
+ for(v=ioStroke.verticesBegin();
+ !v.isEnd();
+ ++v)
+ {
+ real thickness;
+ Vec2f vertexOri(fun(v));
+ 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);
+ }
+
+}
+
+//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;
+}
+void
+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());
+ Vec2r vertexOri(fun(v));
+ 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;
+ }
+
+}
+
+
+
+/////////////////////////////////////////
+//
+// 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;
+}
+
+
+
+void
+SmoothingShader::shade(Stroke &ioStroke) const
+{
+ //cerr<<" Smoothing a stroke "<<endl;
+
+ Smoother smoother(ioStroke);
+ smoother.smooth(_nbIterations, _factorPoint, _factorCurvature, _factorCurvatureDifference,
+ _anisoPoint, _anisoNormal, _anisoCurvature, _carricatureFactor);
+}
+
+// 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;
+}
+
+void
+OmissionShader::shade(Stroke &ioStroke) const
+{
+ Omitter omi(ioStroke);
+ omi.omit(_sizeWindow, _thresholdVariation, _thresholdFlat, _lengthFlat);
+
+}
+
+
+// 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--;
+ }
+
+ }
+}
diff --git a/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.h b/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.h
new file mode 100755
index 00000000000..b624ccd3e6b
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.h
@@ -0,0 +1,222 @@
+//
+// Filename : AdvancedStrokeShaders.h
+// Author : Fredo Durand
+// Purpose : Fredo's stroke shaders
+// Date of creation : 17/12/2002
+//
+///////////////////////////////////////////////////////////////////////////////
+
+
+//
+// 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef ADVANCEDSTROKESHADERS_H
+# define ADVANCEDSTROKESHADERS_H
+
+# include "BasicStrokeShaders.h"
+
+/*! [ Thickness Shader ].
+ * Assigns thicknesses to the stroke vertices
+ * so that the stroke looks like made with a calligraphic tool.
+ * i.e. The stroke will be the thickest in a main direction,
+ * the thinest in the direction perpendicular to this one,
+ * and an interpolation inbetween.
+ */
+class LIB_STROKE_EXPORT CalligraphicShader : public StrokeShader
+{
+
+public:
+ /*! Builds the shader.
+ * \param iMinThickness
+ * The minimum thickness in the direction perpandicular
+ * to the main direction.
+ * \param iMaxThickness
+ * The maximum thickness in the main direction.
+ * \param iOrientation
+ * The 2D vector giving the main direction.
+ * \param clamp
+ * Tells ???
+ */
+ CalligraphicShader (real iMinThickness, real iMaxThickness,
+ const Vec2f &iOrientation, bool clamp);
+ /*! Destructor. */
+ virtual ~CalligraphicShader () {}
+ /*! The shading method */
+ virtual void shade(Stroke &ioStroke) const;
+protected:
+ real _maxThickness;
+ real _minThickness;
+ Vec2f _orientation;
+ bool _clamp;
+};
+
+/*! [ Geometry Shader ].
+ * Spatial Noise stroke shader.
+ * Moves the vertices to make the stroke more noisy.
+ * @see \htmlonly <a href=noise/noise.html>noise/noise.html</a> \endhtmlonly
+ */
+class LIB_STROKE_EXPORT SpatialNoiseShader : public StrokeShader
+{
+public:
+ /*! Builds the shader.
+ * \param iAmount
+ * The amplitude of the noise.
+ * \param ixScale
+ * The noise frequency
+ * \param nbOctave
+ * The number of octaves
+ * \param smooth
+ * If you want the noise to be smooth
+ * \param pureRandom
+ * If you don't want any coherence
+ */
+ SpatialNoiseShader (float iAmount, float ixScale, int nbOctave, bool smooth, bool pureRandom);
+ /*! Destructor. */
+ virtual ~SpatialNoiseShader () {}
+ /*! The shading method. */
+ virtual void shade(Stroke &ioStroke) const;
+
+protected:
+
+ float _amount;
+ float _xScale;
+ int _nbOctave;
+ bool _smooth;
+ bool _pureRandom;
+};
+
+/*! [ Geometry Shader ].
+ * Smoothes the stroke.
+ * (Moves the vertices to make the stroke smoother).
+ * Uses curvature flow to converge towards a curve of constant
+ * curvature. The diffusion method we use is anisotropic
+ * to prevent the diffusion accross corners.
+ * @see \htmlonly <a href=/smoothing/smoothing.html>smoothing/smoothing.html</a> endhtmlonly
+ */
+class LIB_STROKE_EXPORT SmoothingShader : public StrokeShader
+{
+public:
+ /*! Builds the shader.
+ * \param iNbIteration
+ * The number of iterations. (400)
+ * \param iFactorPoint
+ * 0
+ * \param ifactorCurvature
+ * 0
+ * \param iFactorCurvatureDifference
+ * 0.2
+ * \param iAnisoPoint
+ * 0
+ * \param iAnisNormal
+ * 0
+ * \param iAnisoCurvature
+ * 0
+ * \param icarricatureFactor
+ * 1
+ */
+ SmoothingShader (int iNbIteration, real iFactorPoint, real ifactorCurvature, real iFactorCurvatureDifference,
+ real iAnisoPoint, real iAnisoNormal, real iAnisoCurvature, real icarricatureFactor);
+ /*! Destructor. */
+ virtual ~SmoothingShader () {}
+
+ /*! The shading method. */
+ virtual void shade(Stroke &ioStroke) const;
+
+protected:
+
+ int _nbIterations;
+ real _factorPoint;
+ real _factorCurvature;
+ real _factorCurvatureDifference;
+ real _anisoPoint;
+ real _anisoNormal;
+ real _anisoCurvature;
+ real _carricatureFactor;
+};
+
+class LIB_STROKE_EXPORT Smoother
+{
+public:
+ Smoother (Stroke &ioStroke);
+
+ virtual ~Smoother () {}
+
+ void smooth (int nbIterations, real iFactorPoint, real ifactorCurvature, real iFactorCurvatureDifference,
+ real iAnisoPoint, real iAnisoNormal, real iAnisoCurvature, real icarricatureFactor);
+ void computeCurvature ();
+
+protected:
+ real _factorPoint;
+ real _factorCurvature;
+ real _factorCurvatureDifference;
+ real _anisoPoint;
+ real _anisoNormal;
+ real _anisoCurvature;
+ real _carricatureFactor;
+
+ void iteration();
+ void copyVertices ();
+
+ Stroke *_stroke;
+ int _nbVertices;
+ Vec2r *_vertex;
+ Vec2r *_normal;
+ real *_curvature;
+ bool *_isFixedVertex;
+
+ bool _isClosedCurve;
+ bool _safeTest;
+};
+
+class LIB_STROKE_EXPORT Omitter : public Smoother
+{
+public:
+ Omitter (Stroke &ioStroke);
+ virtual ~Omitter () {}
+
+ void omit (real sizeWindow, real thrVari, real thrFlat, real lFlat);
+protected:
+ real *_u;
+
+ real _sizeWindow;
+ real _thresholdVariation;
+ real _thresholdFlat;
+ real _lengthFlat;
+};
+
+/*! Omission shader
+ */
+class LIB_STROKE_EXPORT OmissionShader : public StrokeShader
+{
+public:
+ OmissionShader (real sizeWindow, real thrVari, real thrFlat, real lFlat);
+ virtual ~OmissionShader () {}
+
+ virtual void shade(Stroke &ioStroke) const;
+
+protected:
+
+ real _sizeWindow;
+ real _thresholdVariation;
+ real _thresholdFlat;
+ real _lengthFlat;
+};
+
+#endif // ADVANCEDSTROKESHADERS_H
diff --git a/source/blender/freestyle/intern/stroke/BasicStrokeShaders.cpp b/source/blender/freestyle/intern/stroke/BasicStrokeShaders.cpp
new file mode 100755
index 00000000000..c3827ae3e36
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/BasicStrokeShaders.cpp
@@ -0,0 +1,1100 @@
+
+//
+// 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 <fstream>
+#include <qimage.h>
+#include "BasicStrokeShaders.h"
+#include "../system/PseudoNoise.h"
+#include "../system/RandGen.h"
+#include "../view_map/Functions0D.h"
+#include "../view_map/Functions1D.h"
+#include "AdvancedFunctions0D.h"
+#include "AdvancedFunctions1D.h"
+#include "StrokeIterators.h"
+#include "../system/StringUtils.h"
+#include "StrokeRenderer.h"
+#include "StrokeIO.h"
+#include <QString>
+
+// Internal function
+void convert(const QImage& iImage, float **oArray, unsigned &oSize) {
+ oSize = iImage.width();
+ *oArray = new float[oSize];
+ for(unsigned i=0; i<oSize; ++i) {
+ QRgb rgb = iImage.pixel(i,0);
+ (*oArray)[i] = ((float)qBlue(rgb))/255.f;
+ }
+}
+
+namespace StrokeShaders {
+
+ //
+ // Thickness modifiers
+ //
+ //////////////////////////////////////////////////////////
+
+ void ConstantThicknessShader::shade(Stroke& stroke) const
+ {
+ StrokeInternal::StrokeVertexIterator v, vend;
+ int i=0;
+ int size = stroke.strokeVerticesSize();
+ for(v=stroke.strokeVerticesBegin(), vend=stroke.strokeVerticesEnd();
+ v!=vend;
+ ++v)
+ {
+ if((1 == i) || (size-2 == i))
+ v->attribute().setThickness(_thickness/4.0,_thickness/4.0);
+ if((0 == i) || (size-1 == i))
+ v->attribute().setThickness(0,0);
+
+ v->attribute().setThickness(_thickness/2.0, _thickness/2.0);
+ }
+ }
+
+ void ConstantExternThicknessShader::shade(Stroke& stroke) const
+ {
+ StrokeInternal::StrokeVertexIterator v, vend;
+ int i=0;
+ int size = stroke.strokeVerticesSize();
+ for(v=stroke.strokeVerticesBegin(), vend=stroke.strokeVerticesEnd();
+ v!=vend;
+ ++v)
+ {
+ if((1 == i) || (size-2 == i))
+ v->attribute().setThickness(_thickness/2.0,0);
+ if((0 == i) || (size-1 == i))
+ v->attribute().setThickness(0,0);
+
+ v->attribute().setThickness(_thickness, 0);
+ }
+ }
+
+ void IncreasingThicknessShader::shade(Stroke& stroke) const
+ {
+
+ int n=stroke.strokeVerticesSize()-1;
+ StrokeInternal::StrokeVertexIterator v, vend;
+ int i=0;
+ for(v=stroke.strokeVerticesBegin(), vend=stroke.strokeVerticesEnd();
+ v!=vend;
+
+ ++v)
+ {
+ float t;
+ if(i < (float)n/2.f)
+ t = (1.0-(float)i/(float)n)*_ThicknessMin + (float)i/(float)n*_ThicknessMax;
+ else
+ t = (1.0-(float)i/(float)n)*_ThicknessMax + (float)i/(float)n*_ThicknessMin;
+ v->attribute().setThickness(t/2.0, t/2.0);
+ ++i;
+ }
+ }
+
+ void ConstrainedIncreasingThicknessShader::shade(Stroke& stroke) const
+ {
+ float slength = stroke.getLength2D();
+ float maxT = min(_ratio*slength,_ThicknessMax);
+ int n=stroke.strokeVerticesSize()-1;
+ StrokeInternal::StrokeVertexIterator v, vend;
+ int i=0;
+ for(v=stroke.strokeVerticesBegin(), vend=stroke.strokeVerticesEnd();
+ v!=vend;
+
+ ++v)
+ {
+ float t;
+ if(i < (float)n/2.f)
+ t = (1.0-(float)i/(float)n)*_ThicknessMin + (float)i/(float)n*maxT;
+ else
+ t = (1.0-(float)i/(float)n)*maxT + (float)i/(float)n*_ThicknessMin;
+ v->attribute().setThickness(t/2.0, t/2.0);
+ if(i == n-1)
+ v->attribute().setThickness(_ThicknessMin/2.0, _ThicknessMin/2.0);
+ ++i;
+ }
+ }
+
+
+ void LengthDependingThicknessShader::shade(Stroke& stroke) const
+ {
+ float step = (_maxThickness-_minThickness)/3.f;
+ float l = stroke.getLength2D();
+ float thickness;
+ if(l>300.f)
+ thickness = _minThickness+3.f*step;
+ else if((l< 300.f) && (l>100.f))
+ thickness = _minThickness+2.f*step;
+ else if((l<100.f) && (l>50.f))
+ thickness = _minThickness+1.f*step;
+ else if(l< 50.f)
+ thickness = _minThickness;
+
+ StrokeInternal::StrokeVertexIterator v, vend;
+ int i=0;
+ int size = stroke.strokeVerticesSize();
+ for(v=stroke.strokeVerticesBegin(), vend=stroke.strokeVerticesEnd();
+ v!=vend;
+ ++v)
+ {
+ if((1 == i) || (size-2 == i))
+ v->attribute().setThickness(thickness/4.0,thickness/4.0);
+ if((0 == i) || (size-1 == i))
+ v->attribute().setThickness(0,0);
+
+ v->attribute().setThickness(thickness/2.0, thickness/2.0);
+ }
+ }
+
+
+ ThicknessVariationPatternShader::ThicknessVariationPatternShader(const string pattern_name,
+ float iMinThickness,
+ float iMaxThickness,
+ bool stretch)
+ : StrokeShader() {
+ _stretch = stretch;
+ _minThickness = iMinThickness;
+ _maxThickness = iMaxThickness;
+ QImage image;
+ vector<string> pathnames;
+ StringUtils::getPathName(TextureManager::Options::getPatternsPath(),
+ pattern_name,
+ pathnames);
+ for (vector<string>::const_iterator j = pathnames.begin(); j != pathnames.end(); j++) {
+ ifstream ifs(j->c_str());
+ if (ifs.is_open()) {
+ image.load(j->c_str());
+ break;
+ }
+ }
+ if (image.isNull())
+ cerr << "Error: cannot find pattern \"" << pattern_name
+ << "\" - check the path in the Options" << endl;
+ else
+ convert(image, &_aThickness, _size);
+ }
+
+ void ThicknessVariationPatternShader::shade(Stroke& stroke) const
+ {
+ StrokeInternal::StrokeVertexIterator v, vend;
+ float *array = 0;
+ int size;
+ array = _aThickness;
+ size = _size;
+ // }
+ int vert_size = stroke.strokeVerticesSize();
+ int sig = 0;
+ unsigned index;
+ const float* originalThickness;
+ for(v=stroke.strokeVerticesBegin(), vend=stroke.strokeVerticesEnd();
+ v!=vend;
+ ++v)
+ {
+ originalThickness = v->attribute().getThickness();
+ if (_stretch) {
+ float tmp = v->u()*(_size-1);
+ index = (unsigned)floor(tmp);
+ if((tmp-index) > (index+1-tmp))
+ ++index;
+ }
+ else
+ index = (unsigned)floor(v->curvilinearAbscissa());
+ index %= _size;
+ float thicknessR = array[index]*originalThickness[0];
+ float thicknessL = array[index]*originalThickness[1];
+ if(thicknessR+thicknessL < _minThickness)
+ {
+ thicknessL = _minThickness/2.f;
+ thicknessR = _minThickness/2.f;
+ }
+ if(thicknessR+thicknessL > _maxThickness)
+ {
+ thicknessL = _maxThickness/2.f;
+ thicknessR = _maxThickness/2.f;
+ }
+ if((sig==0) || (sig==vert_size-1))
+ v->attribute().setThickness(1, 1);
+ else
+ v->attribute().setThickness(thicknessR, thicknessL);
+ ++sig;
+ }
+ }
+
+
+ static const unsigned NB_VALUE_NOISE = 512;
+ ThicknessNoiseShader::ThicknessNoiseShader()
+ :StrokeShader()
+ {_amplitude=1.f;_scale=1.f/2.f/(float)NB_VALUE_NOISE;}
+
+ ThicknessNoiseShader::ThicknessNoiseShader(float iAmplitude, float iPeriod)
+ :StrokeShader()
+ {_amplitude=iAmplitude;_scale=1.f/iPeriod/(float)NB_VALUE_NOISE;}
+
+
+ void ThicknessNoiseShader::shade(Stroke& stroke) const
+ {
+ StrokeInternal::StrokeVertexIterator v=stroke.strokeVerticesBegin(), vend=stroke.strokeVerticesEnd();
+ real initU1=v->strokeLength()*real(NB_VALUE_NOISE)+RandGen::drand48()*real(NB_VALUE_NOISE);
+ real initU2=v->strokeLength()*real(NB_VALUE_NOISE)+RandGen::drand48()*real(NB_VALUE_NOISE);
+
+ real bruit, bruit2;
+ PseudoNoise mynoise, mynoise2;
+ for(;
+ v!=vend;
+ ++v)
+ {
+
+ bruit=mynoise.turbulenceSmooth(_scale*v->curvilinearAbscissa()+initU1,
+ 2); //2 : nbOctaves
+ bruit2=mynoise2.turbulenceSmooth(_scale*v->curvilinearAbscissa()+initU2,
+ 2); //2 : nbOctaves
+ const float *originalThickness = v->attribute().getThickness();
+ float r = bruit*_amplitude+originalThickness[0];
+ float l = bruit2*_amplitude+originalThickness[1];
+ v->attribute().setThickness(r,l);
+ }
+
+ }
+
+ //
+ // Color shaders
+ //
+ ///////////////////////////////////////////////////////////////////////////////
+
+ void ConstantColorShader::shade(Stroke& stroke) const
+ {
+ StrokeInternal::StrokeVertexIterator v, vend;
+ for(v=stroke.strokeVerticesBegin(), vend=stroke.strokeVerticesEnd();
+ v!=vend;
+ ++v)
+ {
+ v->attribute().setColor(_color[0], _color[1], _color[2]);
+ v->attribute().setAlpha(_color[3]);
+ }
+ }
+
+ void IncreasingColorShader::shade(Stroke& stroke) const
+ {
+ StrokeInternal::StrokeVertexIterator v, vend;
+ int n=stroke.strokeVerticesSize()-1;
+ int yo=0;
+ float newcolor[4];
+ for(v=stroke.strokeVerticesBegin(), vend=stroke.strokeVerticesEnd();
+ v!=vend;
+
+ ++v)
+ {
+ for(int i=0; i<4; ++i)
+ {
+ newcolor[i] = (1.0-(float)yo/(float)n)*_colorMin[i] + (float)yo/(float)n*_colorMax[i];
+ }
+ v->attribute().setColor(newcolor[0], newcolor[1], newcolor[2]);
+ v->attribute().setAlpha(newcolor[3]);
+ ++yo;
+ }
+ }
+
+ ColorVariationPatternShader::ColorVariationPatternShader(const string pattern_name,
+ bool stretch)
+ : StrokeShader() {
+ _stretch = stretch;
+ QImage image;
+ vector<string> pathnames;
+ StringUtils::getPathName(TextureManager::Options::getPatternsPath(),
+ pattern_name,
+ pathnames);
+ for (vector<string>::const_iterator j = pathnames.begin(); j != pathnames.end(); j++) {
+ ifstream ifs(j->c_str());
+ if (ifs.is_open()) {
+ image.load(j->c_str());
+ break;
+ }
+ }
+ if (image.isNull())
+ cerr << "Error: cannot find pattern \"" << pattern_name
+ << "\" - check the path in the Options" << endl;
+ else
+ convert(image, &_aVariation, _size);
+ }
+
+ void ColorVariationPatternShader::shade(Stroke& stroke) const
+ {
+ StrokeInternal::StrokeVertexIterator v, vend;
+ unsigned index;
+ for(v=stroke.strokeVerticesBegin(), vend=stroke.strokeVerticesEnd();
+ v!=vend;
+ ++v)
+ {
+ const float *originalColor = v->attribute().getColor();
+ if (_stretch) {
+ float tmp = v->u()*(_size-1);
+ index = (unsigned)floor(tmp);
+ if((tmp-index) > (index+1-tmp))
+ ++index;
+ }
+ else
+ index = (unsigned)floor(v->curvilinearAbscissa());
+ index %= _size;
+ float r = _aVariation[index]*originalColor[0];
+ float g = _aVariation[index]*originalColor[1];
+ float b = _aVariation[index]*originalColor[2];
+ v->attribute().setColor(r,g,b);
+ }
+ }
+
+ void MaterialColorShader::shade(Stroke& stroke) const
+ {
+ Interface0DIterator v, vend;
+ Functions0D::MaterialF0D fun;
+ StrokeVertex *sv;
+ for(v=stroke.verticesBegin(), vend=stroke.verticesEnd();
+ v!=vend;
+ ++v)
+ {
+ const float *diffuse = fun(v).diffuse();
+ sv = dynamic_cast<StrokeVertex*>(&(*v));
+ sv->attribute().setColor(diffuse[0]*_coefficient, diffuse[1]*_coefficient, diffuse[2]*_coefficient);
+ sv->attribute().setAlpha(diffuse[3]);
+ }
+ }
+
+
+ void CalligraphicColorShader::shade(Stroke& stroke) const
+ {
+ Interface0DIterator v;
+ Functions0D::VertexOrientation2DF0D fun;
+ StrokeVertex* sv;
+ for(v=stroke.verticesBegin();
+ !v.isEnd();
+ ++v)
+ {
+ Vec2f vertexOri(fun(v));
+ Vec2d ori2d(-vertexOri[1], vertexOri[0]);
+ ori2d.normalizeSafe();
+ real scal = ori2d * _orientation;
+ sv = dynamic_cast<StrokeVertex*>(&(*v));
+ if ((scal<0))
+ sv->attribute().setColor(0,0,0);
+ else
+ sv->attribute().setColor(1,1,1);
+ }
+ }
+
+
+ ColorNoiseShader::ColorNoiseShader()
+ :StrokeShader()
+ {_amplitude=1.f;_scale=1.f/2.f/(float)NB_VALUE_NOISE;}
+
+ ColorNoiseShader::ColorNoiseShader(float iAmplitude, float iPeriod)
+ :StrokeShader()
+ {_amplitude=iAmplitude;_scale=1.f/iPeriod/(float)NB_VALUE_NOISE;}
+
+
+ void ColorNoiseShader::shade(Stroke& stroke) const
+ {
+ StrokeInternal::StrokeVertexIterator v=stroke.strokeVerticesBegin(), vend=stroke.strokeVerticesEnd();
+ real initU=v->strokeLength()*real(NB_VALUE_NOISE)+RandGen::drand48()*real(NB_VALUE_NOISE);
+
+ real bruit;
+ PseudoNoise mynoise;
+ for(;
+ v!=vend;
+ ++v)
+ {
+
+ bruit=mynoise.turbulenceSmooth(_scale*v->curvilinearAbscissa()+initU,
+ 2); //2 : nbOctaves
+ const float *originalColor = v->attribute().getColor();
+ float r = bruit*_amplitude+originalColor[0];
+ float g = bruit*_amplitude+originalColor[1];
+ float b = bruit*_amplitude+originalColor[2];
+ v->attribute().setColor(r,g,b);
+ }
+
+ }
+
+
+ //
+ // Texture Shaders
+ //
+ ///////////////////////////////////////////////////////////////////////////////
+
+ void TextureAssignerShader::shade(Stroke& stroke) const
+ {
+ // getBrushTextureIndex(TEXTURES_DIR "/brushes/charcoalAlpha.bmp", Stroke::HUMID_MEDIUM);
+ // getBrushTextureIndex(TEXTURES_DIR "/brushes/washbrushAlpha.bmp", Stroke::HUMID_MEDIUM);
+ // getBrushTextureIndex(TEXTURES_DIR "/brushes/oil.bmp", Stroke::HUMID_MEDIUM);
+ // getBrushTextureIndex(TEXTURES_DIR "/brushes/oilnoblend.bmp", Stroke::HUMID_MEDIUM);
+ // getBrushTextureIndex(TEXTURES_DIR "/brushes/charcoalAlpha.bmp", Stroke::DRY_MEDIUM);
+ // getBrushTextureIndex(TEXTURES_DIR "/brushes/washbrushAlpha.bmp", Stroke::DRY_MEDIUM);
+ // getBrushTextureIndex(TEXTURES_DIR "/brushes/opaqueDryBrushAlpha.bmp", Stroke::OPAQUE_MEDIUM);
+ // getBrushTextureIndex(TEXTURES_DIR "/brushes/opaqueBrushAlpha.bmp", Stroke::OPAQUE_MEDIUM);
+
+ TextureManager * instance = TextureManager::getInstance();
+ if(!instance)
+ return;
+ string pathname;
+ Stroke::MediumType mediumType;
+ bool hasTips = false;
+ switch(_textureId)
+ {
+ case 0:
+ //pathname = TextureManager::Options::getBrushesPath() + "/charcoalAlpha.bmp";
+ pathname = "/charcoalAlpha.bmp";
+ mediumType = Stroke::HUMID_MEDIUM;
+ hasTips = false;
+ break;
+ case 1:
+ pathname = "/washbrushAlpha.bmp";
+ mediumType = Stroke::HUMID_MEDIUM;
+ hasTips = true;
+ break;
+ case 2:
+ pathname = "/oil.bmp";
+ mediumType = Stroke::HUMID_MEDIUM;
+ hasTips = true;
+ break;
+ case 3:
+ pathname = "/oilnoblend.bmp";
+ mediumType = Stroke::HUMID_MEDIUM;
+ hasTips = true;
+ break;
+ case 4:
+ pathname = "/charcoalAlpha.bmp";
+ mediumType = Stroke::DRY_MEDIUM;
+ hasTips = false;
+ break;
+ case 5:
+ mediumType = Stroke::DRY_MEDIUM;
+ hasTips = true;
+ break;
+ case 6:
+ pathname = "/opaqueDryBrushAlpha.bmp";
+ mediumType = Stroke::OPAQUE_MEDIUM;
+ hasTips = true;
+ break;
+ case 7:
+ pathname = "/opaqueBrushAlpha.bmp";
+ mediumType = Stroke::OPAQUE_MEDIUM;
+ hasTips = true;
+ break;
+ default:
+ pathname = "/smoothAlpha.bmp";
+ mediumType = Stroke::OPAQUE_MEDIUM;
+ hasTips = false;
+ break;
+ }
+ unsigned int texId = instance->getBrushTextureIndex(pathname, mediumType);
+ stroke.SetMediumType(mediumType);
+ stroke.SetTips(hasTips);
+ stroke.SetTextureId(texId);
+ }
+
+ // FIXME
+ void StrokeTextureShader::shade(Stroke& stroke) const
+ {
+ TextureManager * instance = TextureManager::getInstance();
+ if(!instance)
+ return;
+ string pathname = TextureManager::Options::getBrushesPath() + "/" + _texturePath;
+ unsigned int texId = instance->getBrushTextureIndex(pathname, _mediumType);
+ stroke.SetMediumType(_mediumType);
+ stroke.SetTips(_tips);
+ stroke.SetTextureId(texId);
+ }
+
+ //
+ // Geometry Shaders
+ //
+ ///////////////////////////////////////////////////////////////////////////////
+
+ void BackboneStretcherShader::shade(Stroke& stroke) const
+ {
+ float l=stroke.getLength2D();
+ if(l <= 50)
+ return;
+
+ StrokeInternal::StrokeVertexIterator v0=stroke.strokeVerticesBegin();
+ StrokeInternal::StrokeVertexIterator v1=v0;++v1;
+ StrokeInternal::StrokeVertexIterator vn=stroke.strokeVerticesEnd();--vn;
+ StrokeInternal::StrokeVertexIterator vn_1=vn;--vn_1;
+
+
+ Vec2d first((v0)->x(), (v0)->y());
+ Vec2d last((vn)->x(), (vn)->y());
+
+ Vec2d d1(first-Vec2d((v1)->x(), (v1)->y()));
+ d1.normalize();
+ Vec2d dn(last-Vec2d((vn_1)->x(), (vn_1)->y()));
+ dn.normalize();
+
+ Vec2d newFirst(first+_amount*d1);
+ (v0)->SetPoint(newFirst[0], newFirst[1]);
+ Vec2d newLast(last+_amount*dn);
+ (vn)->SetPoint(newLast[0], newLast[1]);
+ }
+
+ void SamplingShader::shade(Stroke& stroke) const
+ {
+ stroke.Resample(_sampling);
+ }
+
+ void ExternalContourStretcherShader::shade(Stroke& stroke) const
+ {
+ float l=stroke.getLength2D();
+ Interface0DIterator it=stroke.verticesBegin();
+ Functions0D::Normal2DF0D fun;
+ StrokeVertex* sv;
+ while (!it.isEnd())
+ {
+ Vec2f n(fun(it));
+ sv = dynamic_cast<StrokeVertex*>(&(*it));
+ Vec2d newPoint(sv->x()+_amount*n.x(), sv->y()+_amount*n.y());
+ sv->SetPoint(newPoint[0], newPoint[1]);
+ ++it;
+ }
+ }
+
+ void BSplineShader::shade(Stroke& stroke) const
+ {
+ if(stroke.strokeVerticesSize() < 4)
+ return;
+
+ // Find the new vertices
+ vector<Vec2d> newVertices;
+ double t=0.f;
+ float _sampling = 5.f;
+
+ StrokeInternal::StrokeVertexIterator p0,p1,p2,p3, end;
+ p0 = stroke.strokeVerticesBegin();
+ p1 = p0;
+ p2 = p1;
+ p3 = p2;
+ end = stroke.strokeVerticesEnd();
+ double a[4],b[4];
+ int n=0;
+ while(p1 != end)
+ {
+ // if(p1 == end)
+ // p1 = p0;
+ if(p2 == end)
+ p2 = p1;
+ if(p3 == end)
+ p3 = p2;
+ // compute new matrix
+ a[0] = (-(p0)->x()+3*(p1)->x()-3*(p2)->x()+(p3)->x())/6.0;
+ a[1] = (3*(p0)->x()-6*(p1)->x()+3*(p2)->x())/6.0;
+ a[2] = (-3*(p0)->x()+3*(p2)->x())/6.0;
+ a[3] = ((p0)->x()+4*(p1)->x()+(p2)->x())/6.0;
+
+ b[0] = (-(p0)->y()+3*(p1)->y()-3*(p2)->y()+(p3)->y())/6.0;
+ b[1] = (3*(p0)->y()-6*(p1)->y()+3*(p2)->y())/6.0;
+ b[2] = (-3*(p0)->y()+3*(p2)->y())/6.0;
+ b[3] = ((p0)->y()+4*(p1)->y()+(p2)->y())/6.0;
+
+
+ // draw the spline depending on resolution:
+ Vec2d p1p2((p2)->x()-(p1)->x(), (p2)->y()-(p1)->y());
+ double norm = p1p2.norm();
+ //t = _sampling/norm;
+ t=0;
+ while(t<1)
+ {
+ newVertices.push_back(Vec2d((a[3] + t*(a[2] + t*(a[1] + t*a[0]))),
+ (b[3] + t*(b[2] + t*(b[1] + t*b[0])))));
+ t = t + _sampling/norm;
+ }
+ if(n > 2)
+ {
+ ++p0;
+ ++p1;
+ ++p2;
+ ++p3;
+ }
+ else
+ {
+ if(n==0)
+ ++p3;
+ if(n==1)
+ {++p2;++p3;}
+ if(n==2)
+ {++p1;++p2;++p3;}
+ ++n;
+ }
+ }
+ //last point:
+ newVertices.push_back(Vec2d((p0)->x(), (p0)->y()));
+
+ int originalSize = newVertices.size();
+ _sampling = stroke.ComputeSampling(originalSize);
+
+ // Resample and set x,y coordinates
+ stroke.Resample(_sampling);
+ int newsize = stroke.strokeVerticesSize();
+
+ int nExtraVertex=0;
+ if(newsize < originalSize)
+ cerr << "Warning: unsufficient resampling" << endl;
+ else
+ {
+ nExtraVertex = newsize - originalSize;
+ }
+
+ // assigns the new coordinates:
+ vector<Vec2d>::iterator p,pend;
+ p=newVertices.begin();pend=newVertices.end();
+ vector<Vec2d>::iterator last = p;
+ n=0;
+ StrokeInternal::StrokeVertexIterator it=stroke.strokeVerticesBegin(), itend=stroke.strokeVerticesEnd();
+ it=stroke.strokeVerticesBegin();
+ for(;
+ ((it!=itend) && (p!=pend));
+ ++it)
+ {
+ it->SetX(p->x());
+ it->SetY(p->y());
+ last = p;
+ ++p;
+ ++n;
+ }
+ // nExtraVertex should stay unassigned
+ for(int i=0; i< nExtraVertex; ++i)
+ {
+ it->SetX(last->x());
+ it->SetY(last->y());
+ if(it.isEnd())
+ cerr << "Warning: Problem encountered while creating B-spline" << endl;
+ ++it;
+ ++n;
+ }
+ }
+
+ //!! Bezier curve stroke shader
+ void BezierCurveShader::shade(Stroke& stroke) const
+ {
+ if(stroke.strokeVerticesSize() < 4)
+ return;
+
+ // Build the Bezier curve from this set of data points:
+ vector<Vec2d> data;
+ StrokeInternal::StrokeVertexIterator v=stroke.strokeVerticesBegin(), vend=stroke.strokeVerticesEnd();
+ data.push_back(Vec2d(v->x(), v->y()));//first one
+ StrokeInternal::StrokeVertexIterator previous = v;++v;
+ for(;
+ v!=vend;
+ ++v)
+ {
+ if(!((fabs(v->x() -(previous)->x())<M_EPSILON) && ((fabs(v->y() - (previous)->y())<M_EPSILON))))
+ data.push_back(Vec2d(v->x(), v->y()));
+ previous = v;
+ }
+
+ // Vec2d tmp;bool equal=false;
+ // if(data.front() == data.back())
+ // {
+ // tmp = data.back();
+ // data.pop_back();
+ // equal=true;
+ // }
+ // here we build the bezier curve
+ BezierCurve bcurve(data, _error);
+
+ // bad performances are here !!! // FIXME
+ vector<Vec2d> CurveVertices;
+ vector<BezierCurveSegment*>& bsegments = bcurve.segments();
+ vector<BezierCurveSegment*>::iterator s=bsegments.begin(),send=bsegments.end();
+ vector<Vec2d>& segmentsVertices = (*s)->vertices();
+ vector<Vec2d>::iterator p,pend;
+ // first point
+ CurveVertices.push_back(segmentsVertices[0]);
+ for(;
+ s!=send;
+ ++s)
+ {
+ segmentsVertices = (*s)->vertices();
+ p=segmentsVertices.begin(); pend=segmentsVertices.end();
+ ++p;
+ for(;
+ p!=pend;
+ ++p)
+ {
+ CurveVertices.push_back((*p));
+ }
+ }
+
+ //if(equal)
+ // if(data.back() == data.front())
+ // {
+ // vector<Vec2d>::iterator d=data.begin(), dend=data.end();
+ // cout << "ending point = starting point" << endl;
+ // cout << "---------------DATA----------" << endl;
+ // for(;
+ // d!=dend;
+ // ++d)
+ // {
+ // cout << d->x() << "-" << d->y() << endl;
+ // }
+ // cout << "--------------BEZIER RESULT----------" << endl;
+ // d=CurveVertices.begin(), dend=CurveVertices.end();
+ // for(;d!=dend;++d)
+ // {
+ // cout << d->x() << "-" << d->y() << endl;
+ // }
+ // }
+
+ // Resample the Stroke depending on the number of
+ // vertices of the bezier curve:
+ int originalSize = CurveVertices.size();
+ //float sampling = stroke.ComputeSampling(originalSize);
+ //stroke.Resample(sampling);
+ stroke.Resample(originalSize);
+ int newsize = stroke.strokeVerticesSize();
+ int nExtraVertex=0;
+ if(newsize < originalSize)
+ cerr << "Warning: unsufficient resampling" << endl;
+ else
+ {
+ //cout << "Oversampling" << endl;
+ nExtraVertex = newsize - originalSize;
+ if(nExtraVertex != 0)
+ cout << "Bezier Shader : Stroke " << stroke.getId() << " have not been resampled" << endl;
+ }
+
+ // assigns the new coordinates:
+ p=CurveVertices.begin();pend=CurveVertices.end();
+ vector<Vec2d>::iterator last = p;
+ int n=0;
+ StrokeInternal::StrokeVertexIterator it=stroke.strokeVerticesBegin(), itend=stroke.strokeVerticesEnd();
+ // while(p!=pend)
+ // {
+ // ++n;
+ // ++p;
+ // }
+ it=stroke.strokeVerticesBegin();
+ for(;
+ ((it!=itend) && (p!=pend));
+ ++it)
+ {
+ it->SetX(p->x());
+ it->SetY(p->y());
+ // double x = p->x();
+ // double y = p->y();
+ // cout << "x = " << x << "-" << "y = " << y << endl;
+ last = p;
+ ++p;
+ ++n;
+ }
+
+ // Deal with extra vertices:
+ if(nExtraVertex == 0)
+ return;
+
+ // nExtraVertex should stay unassigned
+ vector<StrokeAttribute> attributes;
+ vector<StrokeVertex*> verticesToRemove;
+ for(int i=0; i< nExtraVertex; ++i)
+ {
+ verticesToRemove.push_back(&(*it));
+ if(it.isEnd())
+ cout << "fucked up" << endl;
+ ++it;
+ ++n;
+ }
+ it=stroke.strokeVerticesBegin();
+ for(;
+ it!=itend;
+ ++it)
+ {
+ attributes.push_back(it->attribute());
+ }
+
+ for(vector<StrokeVertex*>::iterator vr=verticesToRemove.begin(), vrend=verticesToRemove.end();
+ vr!=vrend;
+ ++vr)
+ {
+ stroke.RemoveVertex(*vr);
+ }
+ it=stroke.strokeVerticesBegin();
+ itend=stroke.strokeVerticesEnd();
+ vector<StrokeAttribute>::iterator a=attributes.begin(), aend=attributes.end();
+ int index = 0;
+ int index1 = (int)floor((float)originalSize/2.0);
+ int index2 = index1+nExtraVertex;
+ for(;
+ (it!=itend) && (a!=aend);
+ ++it)
+ {
+ (it)->SetAttribute(*a);
+ if((index <= index1)||(index>index2))
+ ++a;
+ ++index;
+ }
+ }
+
+ void InflateShader::shade(Stroke& stroke) const
+ {
+ // we're computing the curvature variance of the stroke.(Combo 5)
+ // If it's too high, forget about it
+ Functions1D::Curvature2DAngleF1D fun;
+ if(fun(stroke) > _curvatureThreshold)
+ return;
+
+ Functions0D::VertexOrientation2DF0D ori_fun;
+ Functions0D::Curvature2DAngleF0D curv_fun;
+ Functions1D::Normal2DF1D norm_fun;
+ Interface0DIterator it=stroke.verticesBegin();
+ StrokeVertex* sv;
+ while (!it.isEnd())
+ {
+ Vec2f ntmp = ori_fun(it);
+ Vec2f n(ntmp.y(), -ntmp.x());
+ Vec2f strokeN(norm_fun(stroke));
+ if(n*strokeN < 0)
+ {
+ n[0] = -n[0];
+ n[1] = -n[1];
+ }
+ sv = dynamic_cast<StrokeVertex*>(&(*it));
+ float u=sv->u();
+ float t = 4.f*(0.25f - (u-0.5)*(u-0.5));
+ float curvature_coeff = (M_PI-curv_fun(it))/M_PI;
+ Vec2d newPoint(sv->x()+curvature_coeff*t*_amount*n.x(), sv->y()+curvature_coeff*t*_amount*n.y());
+ sv->SetPoint(newPoint[0], newPoint[1]);
+ ++it;
+ }
+ }
+
+ class CurvePiece
+ {
+ public:
+ StrokeInternal::StrokeVertexIterator _begin;
+ StrokeInternal::StrokeVertexIterator _last;
+ Vec2d A;
+ Vec2d B;
+ int size;
+ float _error;
+
+ CurvePiece(StrokeInternal::StrokeVertexIterator b, StrokeInternal::StrokeVertexIterator l, int iSize)
+ {
+ _begin = b;
+ _last = l;
+ A = Vec2d((_begin)->x(),(_begin)->y());
+ B = Vec2d((_last)->x(),(_last)->y());
+ size = iSize;
+ }
+
+ float error()
+ {
+ float maxE = 0.f;
+ for(StrokeInternal::StrokeVertexIterator it=_begin;
+ it!=_last;
+ ++it)
+ {
+ Vec2d P(it->x(), it->y());
+ float d = GeomUtils::distPointSegment(P,A,B);
+ if(d > maxE)
+ maxE = d;
+ }
+ _error = maxE;
+ return maxE;
+ }
+ //! Subdivides the curve into two pieces.
+ // The first piece is this same object (modified)
+ // the second piece is returned by the method
+ CurvePiece * subdivide()
+ {
+ StrokeInternal::StrokeVertexIterator it=_begin;
+ int actualSize = 1;
+ for(int i=0; i<size/2; ++i)
+ {
+ ++it;
+ ++actualSize;
+ }
+ CurvePiece * second = new CurvePiece(it, _last, size-actualSize+1);
+ size = actualSize;
+ _last = it;
+ B = Vec2d((_last)->x(), (_last)->y());
+ return second;
+ }
+ };
+
+ void PolygonalizationShader::shade(Stroke& stroke) const
+ {
+ vector<CurvePiece*> _pieces;
+ vector<CurvePiece*> _results;
+ vector<CurvePiece*>::iterator cp,cpend;
+
+ // Compute first approx:
+ StrokeInternal::StrokeVertexIterator a=stroke.strokeVerticesBegin();
+ StrokeInternal::StrokeVertexIterator b=stroke.strokeVerticesEnd();--b;
+ int size = stroke.strokeVerticesSize();
+
+ CurvePiece * piece = new CurvePiece(a,b,size);
+ _pieces.push_back(piece);
+
+ while(!_pieces.empty())
+ {
+ piece = _pieces.back();_pieces.pop_back();
+ if(piece->error() > _error)
+ {
+ CurvePiece * second = piece->subdivide();
+ _pieces.push_back(second);
+ _pieces.push_back(piece);
+ }
+ else
+ {
+ _results.push_back(piece);
+ }
+ }
+
+ // actually modify the geometry for each piece:
+ for(cp=_results.begin(), cpend=_results.end();
+ cp!=cpend;
+ ++cp)
+ {
+ a = (*cp)->_begin;
+ b = (*cp)->_last;
+ Vec2d u = (*cp)->B-(*cp)->A;
+ Vec2d n(u[1], -u[0]);n.normalize();
+ //Vec2d n(0,0);
+ float offset = ((*cp)->_error);
+ StrokeInternal::StrokeVertexIterator v,vlast;
+ for(v=a;
+ v!=b;
+ ++v)
+ {
+ v->SetPoint((*cp)->A.x()+v->u()*u.x()+n.x()*offset, (*cp)->A.y()+v->u()*u.y()+n.y()*offset);
+ }
+ // u.normalize();
+ // (*a)->SetPoint((*a)->x()-u.x()*10, (*a)->y()-u.y()*10);
+ }
+
+ // delete stuff
+ for(cp=_results.begin(), cpend=_results.end();
+ cp!=cpend;
+ ++cp)
+ {
+ delete (*cp);
+ }
+ _results.clear();
+ }
+
+ void GuidingLinesShader::shade(Stroke& stroke) const
+ {
+ Functions1D::Normal2DF1D norm_fun;
+ StrokeInternal::StrokeVertexIterator a=stroke.strokeVerticesBegin();
+ StrokeInternal::StrokeVertexIterator b=stroke.strokeVerticesEnd();--b;
+ int size = stroke.strokeVerticesSize();
+ CurvePiece piece(a,b,size);
+
+ Vec2d u = piece.B-piece.A;
+ Vec2f n(u[1], -u[0]);n.normalize();
+ Vec2f strokeN(norm_fun(stroke));
+ if(n*strokeN < 0)
+ {
+ n[0] = -n[0];
+ n[1] = -n[1];
+ }
+ float offset = (piece.error())/2.f*_offset;
+ StrokeInternal::StrokeVertexIterator v=a,vend=stroke.strokeVerticesEnd();
+ for(;
+ v!=vend;
+ ++v)
+ {
+ v->SetPoint(piece.A.x()+v->u()*u.x()+n.x()*offset, piece.A.y()+v->u()*u.y()+n.y()*offset);
+ }
+ }
+
+ /////////////////////////////////////////
+ //
+ // Tip Remover
+ //
+ /////////////////////////////////////////
+
+
+ TipRemoverShader::TipRemoverShader(real tipLength)
+ : StrokeShader()
+ {
+ _tipLength = tipLength;
+ }
+
+ void
+ TipRemoverShader::shade(Stroke& stroke) const
+ {
+ int originalSize = stroke.strokeVerticesSize();
+
+ if(originalSize<4)
+ return;
+
+ StrokeInternal::StrokeVertexIterator v, vend;
+ vector<StrokeVertex*> verticesToRemove;
+ vector<StrokeAttribute> oldAttributes;
+ v=stroke.strokeVerticesBegin(); vend=stroke.strokeVerticesEnd();
+ for(;
+ v!=vend;
+ ++v)
+ {
+ if ((v->curvilinearAbscissa()<_tipLength) ||
+ (v->strokeLength()-v->curvilinearAbscissa()<_tipLength))
+ {
+ verticesToRemove.push_back(&(*v));
+ }
+ oldAttributes.push_back(v->attribute());
+ }
+
+ if(originalSize-verticesToRemove.size() < 2)
+ return;
+
+ vector<StrokeVertex*>::iterator sv=verticesToRemove.begin(), svend=verticesToRemove.end();
+ for(;
+ sv!=svend;
+ ++sv)
+ {
+ stroke.RemoveVertex((*sv));
+ }
+
+ // Resample so that our new stroke have the same
+ // number of vertices than before
+ stroke.Resample(originalSize);
+
+ if(stroke.strokeVerticesSize() != originalSize)
+ cerr << "Warning: resampling problem" << endl;
+
+ // assign old attributes to new stroke vertices:
+ v=stroke.strokeVerticesBegin(); vend=stroke.strokeVerticesEnd();
+ vector<StrokeAttribute>::iterator a=oldAttributes.begin(), aend=oldAttributes.end();
+ //cout << "-----------------------------------------------" << endl;
+ for(;(v!=vend)&&(a!=aend);++v,++a)
+ {
+ v->SetAttribute(*a);
+ //cout << "thickness = " << (*a).getThickness()[0] << "-" << (*a).getThickness()[1] << endl;
+ }
+ // we're done!
+ }
+
+ void streamShader::shade(Stroke& stroke) const{
+ cout << stroke << endl;
+ }
+ void fstreamShader::shade(Stroke& stroke) const{
+ _stream << stroke << endl;
+ }
+
+} // end of namespace StrokeShaders
+
diff --git a/source/blender/freestyle/intern/stroke/BasicStrokeShaders.h b/source/blender/freestyle/intern/stroke/BasicStrokeShaders.h
new file mode 100755
index 00000000000..f68971a3966
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/BasicStrokeShaders.h
@@ -0,0 +1,791 @@
+//
+// Filename : BasicStrokeShaders.h
+// Author : Stephane Grabli
+// Purpose : Class gathering basic stroke shaders
+// Date of creation : 17/12/2002
+//
+///////////////////////////////////////////////////////////////////////////////
+
+
+//
+// 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef BASIC_STROKE_SHADERS_H
+# define BASIC_STROKE_SHADERS_H
+
+# include "Stroke.h"
+# include "../geometry/Geom.h"
+# include "../geometry/Bezier.h"
+# include "StrokeShader.h"
+# include <fstream>
+
+using namespace std;
+using namespace Geometry;
+
+namespace StrokeShaders {
+
+ //
+ // Thickness modifiers
+ //
+ //////////////////////////////////////////////////////
+ /*! [ Thickness Shader ].
+ * Assigns an absolute constant thickness to every
+ * vertices of the Stroke.
+ */
+ class LIB_STROKE_EXPORT ConstantThicknessShader : public StrokeShader
+ {
+ public:
+ /*! Builds the shader.
+ * \param thickness
+ * The thickness that must be assigned
+ * to the stroke.
+ */
+ ConstantThicknessShader(float thickness) : StrokeShader() {
+ _thickness = thickness;
+ }
+ /*! Destructor. */
+ virtual ~ConstantThicknessShader() {}
+ /*! Returns the string "ConstantThicknessShader".*/
+ virtual string getName() const {
+ return "ConstantThicknessShader";
+ }
+ /*! The shading method. */
+ virtual void shade(Stroke& stroke) const;
+
+ private:
+ float _thickness;
+ };
+
+ /* [ Thickness Shader ].
+ * Assigns an absolute constant external thickness to every
+ * vertices of the Stroke. The external thickness of a point
+ * is its thickness from the point to the strip border
+ * in the direction pointing outside the object the
+ * Stroke delimitates.
+ */
+ class LIB_STROKE_EXPORT ConstantExternThicknessShader : public StrokeShader
+ {
+ public:
+
+ ConstantExternThicknessShader(float thickness) : StrokeShader() {
+ _thickness = thickness;
+ }
+
+ virtual ~ConstantExternThicknessShader() {}
+
+ virtual string getName() const {
+ return "ConstantExternThicknessShader";
+ }
+
+ virtual void shade(Stroke& stroke) const;
+
+ private:
+
+ float _thickness;
+ };
+
+ /*! [ Thickness Shader ].
+ * Assigns thicknesses values such as the thickness
+ * increases from a thickness value A to a thickness value B
+ * between the first vertex to the midpoint vertex and
+ * then decreases from B to a A between this midpoint vertex
+ * and the last vertex.
+ * The thickness is linearly interpolated from A to B.
+ */
+ class LIB_STROKE_EXPORT IncreasingThicknessShader : public StrokeShader
+ {
+ public:
+ /*! Builds the shader.
+ * \param iThicknessMin
+ * The first thickness value.
+ * \param iThicknessMax
+ * The second thickness value.
+ */
+ IncreasingThicknessShader(float iThicknessMin, float iThicknessMax)
+ : StrokeShader()
+ {
+ _ThicknessMin = iThicknessMin;
+ _ThicknessMax = iThicknessMax;
+ }
+ /*! Destructor.*/
+ virtual ~IncreasingThicknessShader() {}
+ /*! The shading method. */
+ virtual void shade(Stroke& stroke) const;
+
+ private:
+
+ float _ThicknessMin;
+ float _ThicknessMax;
+ };
+
+ /*! [ Thickness shader ].
+ * Same as previous but
+ * here we allow the user to control the ratio thickness/length so that
+ * we don't get fat short lines
+ */
+ class LIB_STROKE_EXPORT ConstrainedIncreasingThicknessShader : public StrokeShader
+ {
+ private:
+ float _ThicknessMin;
+ float _ThicknessMax;
+ float _ratio;
+ public:
+ /*! Builds the shader.
+ * \param iThicknessMin
+ * The first thickness value.
+ * \param iThicknessMax
+ * The second thickness value.
+ * \param iRatio
+ * The ration thickness/length we don't want to
+ * exceed.
+ */
+ ConstrainedIncreasingThicknessShader(float iThicknessMin, float iThicknessMax, float iRatio)
+ : StrokeShader()
+ {
+ _ThicknessMin = iThicknessMin;
+ _ThicknessMax = iThicknessMax;
+ _ratio = iRatio;
+ }
+ /*! Destructor.*/
+ virtual ~ConstrainedIncreasingThicknessShader() {}
+ /*! The shading method. */
+ virtual void shade(Stroke& stroke) const;
+ };
+
+ /* [ Thickness Shader ].
+ * Modifys the thickness in a relative way
+ * depending on its length.
+ */
+ class LIB_STROKE_EXPORT LengthDependingThicknessShader : public StrokeShader
+ {
+ private:
+ float _minThickness;
+ float _maxThickness;
+ // We divide the strokes in 4 categories:
+ // l > 300
+ // 100 < l < 300
+ // 50 < l < 100
+ // l < 50
+ public:
+ LengthDependingThicknessShader(float iMinThickness, float iMaxThickness)
+ : StrokeShader()
+ {
+ _minThickness = iMinThickness;
+ _maxThickness = iMaxThickness;
+ }
+ virtual ~LengthDependingThicknessShader() {}
+
+ virtual void shade(Stroke& stroke) const;
+ };
+
+ /*! [ Thickness Shader ].
+ * Applys a pattern (texture) to vary thickness.
+ * The new thicknesses are the result of the multiplication
+ * of the pattern and the original thickness
+ */
+ class LIB_STROKE_EXPORT ThicknessVariationPatternShader : public StrokeShader
+ {
+ public:
+
+ /*! Builds the shader.
+ * \param pattern_name
+ * The texture file name.
+ * \param iMinThickness
+ * The minimum thickness we don't want to exceed.
+ * \param iMaxThickness
+ * The maximum thickness we don't want to exceed.
+ * \param stretch
+ * Tells whether the pattern texture must
+ * be stretched or repeted to fit the stroke.
+ */
+ ThicknessVariationPatternShader(const string pattern_name,
+ float iMinThickness = 1.f,
+ float iMaxThickness = 5.f,
+ bool stretch = true);
+ /*! Destructor.*/
+ virtual ~ThicknessVariationPatternShader()
+ {
+ if(0 != _aThickness)
+ {
+ delete [] _aThickness;
+ _aThickness = 0;
+ }
+ }
+ /*! The shading method. */
+ virtual void shade(Stroke& stroke) const;
+
+ private:
+
+ float* _aThickness; // array of thickness values, in % of the max (i.e comprised between 0 and 1)
+ unsigned _size;
+ float _minThickness;
+ float _maxThickness;
+ bool _stretch;
+ };
+
+ /*! [ Thickness Shader ].
+ * Adds some noise to the stroke thickness.
+ * \see \htmlonly <a href=noise/noise.html>noise/noise.html</a>\endhtmlonly
+ */
+ class LIB_STROKE_EXPORT ThicknessNoiseShader : public StrokeShader
+ {
+ private:
+ float _amplitude;
+ float _scale;
+ public:
+ ThicknessNoiseShader();
+ /*! Builds a Thickness Noise Shader
+ * \param iAmplitude
+ * The amplitude of the noise signal
+ * \param iPeriod
+ * The period of the noise signal
+ */
+ ThicknessNoiseShader(float iAmplitude, float iPeriod);
+ /*! The shading method. */
+ virtual void shade(Stroke& stroke) const;
+ };
+
+
+ //
+ // Color shaders
+ //
+ /////////////////////////////////////////////////////////
+ /*! [ Color Shader ].
+ * Assigns a constant color to every vertices of the Stroke.
+ */
+ class LIB_STROKE_EXPORT ConstantColorShader : public StrokeShader
+ {
+ public:
+ /*! Builds the shader from a user-specified color.
+ * \param iR
+ * The red component
+ * \param iG
+ * The green component
+ * \param iB
+ * The blue component
+ * \param iAlpha
+ * The alpha value
+ */
+ ConstantColorShader(float iR, float iG, float iB, float iAlpha=1.f)
+ : StrokeShader()
+ {
+ _color[0] = iR;
+ _color[1] = iG;
+ _color[2] = iB;
+ _color[3] = iAlpha;
+ }
+
+ virtual string getName() const {
+ return "ConstantColorShader";
+ }
+ /*! The shading method. */
+ virtual void shade(Stroke& stroke) const;
+
+ private:
+
+ float _color[4];
+ };
+
+ /*! [ Color Shader ].
+ * Assigns a varying color to the stroke.
+ * The user specifies 2 colors A and B. The stroke
+ * color will change linearly from A to B between the
+ * first and the last vertex.
+ */
+ class LIB_STROKE_EXPORT IncreasingColorShader : public StrokeShader
+ {
+ private:
+ float _colorMin[4];
+ float _colorMax[4];
+ public:
+ /*! Builds the shader from 2 user-specified colors.
+ * \param iRm
+ * The first color red component
+ * \param iGm
+ * The first color green component
+ * \param iBm
+ * The first color blue component
+ * \param iAlpham
+ * The first color alpha value
+ * \param iRM
+ * The second color red component
+ * \param iGM
+ * The second color green component
+ * \param iBM
+ * The second color blue component
+ * \param iAlphaM
+ * The second color alpha value
+ */
+ IncreasingColorShader(float iRm, float iGm, float iBm, float iAlpham,
+ float iRM, float iGM, float iBM, float iAlphaM)
+ : StrokeShader()
+ {
+ _colorMin[0] = iRm;
+ _colorMin[1] = iGm;
+ _colorMin[2] = iBm;
+ _colorMin[3] = iAlpham;
+
+ _colorMax[0] = iRM;
+ _colorMax[1] = iGM;
+ _colorMax[2] = iBM;
+ _colorMax[3] = iAlphaM;
+ }
+ /*! The shading method. */
+ virtual void shade(Stroke& stroke) const;
+ };
+
+ /*! [ Color Shader ].
+ * Applys a pattern to vary original color.
+ * The new color is the result of the multiplication
+ * of the pattern and the original color
+ */
+ class LIB_STROKE_EXPORT ColorVariationPatternShader : public StrokeShader
+ {
+ public:
+ /*! Builds the shader from the pattern texture file name.
+ * \param pattern_name
+ * The file name of the texture file to use as pattern
+ * \param stretch
+ * Tells whether the texture must be strecthed or repeted
+ * to fit the stroke.
+ */
+ ColorVariationPatternShader(const string pattern_name, bool stretch = true);
+ /*! Destructor */
+ virtual ~ColorVariationPatternShader()
+ {
+ if(0 != _aVariation)
+ {
+ delete [] _aVariation;
+ _aVariation = 0;
+ }
+ }
+ /*! The shading method. */
+ virtual void shade(Stroke& stroke) const;
+
+ private:
+
+ float* _aVariation; // array of coef values, in % of the max (i.e comprised between 0 and 1)
+ unsigned _size;
+ bool _stretch;
+ };
+
+ /* [ Color Shader ].
+ * Assigns a color to the stroke depending
+ * on the material of the shape to which ot belongs
+ * to. (Disney shader)
+ */
+ class LIB_STROKE_EXPORT MaterialColorShader : public StrokeShader
+ {
+ private:
+ float _coefficient;
+ public:
+ MaterialColorShader(float coeff=1.f)
+ : StrokeShader()
+ {_coefficient=coeff;}
+
+ virtual void shade(Stroke& stroke) const;
+ };
+
+ class LIB_STROKE_EXPORT CalligraphicColorShader : public StrokeShader
+ {
+ private:
+ int _textureId;
+ Vec2d _orientation;
+ public:
+ CalligraphicColorShader(
+ const Vec2d &iOrientation)
+ : StrokeShader()
+ {
+ _orientation=iOrientation;
+ _orientation.normalize();
+ }
+ virtual void shade(Stroke& stroke) const;
+
+ };
+
+ /*! [ Color Shader ].
+ * Shader to add noise to the stroke colors.
+ */
+ class LIB_STROKE_EXPORT ColorNoiseShader : public StrokeShader
+ {
+ private:
+ float _amplitude;
+ float _scale;
+
+ public:
+ ColorNoiseShader();
+ /*! Builds a Color Noise Shader
+ * \param iAmplitude
+ * The amplitude of the noise signal
+ * \param iPeriod
+ * The period of the noise signal
+ */
+ ColorNoiseShader(float iAmplitude, float iPeriod);
+ /*! The shading method. */
+ virtual void shade(Stroke& stroke) const;
+ };
+
+ //
+ // Texture Shaders
+ //
+ ///////////////////////////////////////////////////////////////////////////////
+ /*! [ Texture Shader ].
+ * Assigns a texture to the stroke in order to simulate
+ * its marks system. This shader takes as input an integer value
+ * telling which texture and blending mode to use among a set of
+ * predefined textures.
+ * Here are the different presets:
+ * 0) -> /brushes/charcoalAlpha.bmp, HUMID_MEDIUM
+ * 1) -> /brushes/washbrushAlpha.bmp, HUMID_MEDIUM
+ * 2) -> /brushes/oil.bmp, HUMID_MEDIUM
+ * 3) -> /brushes/oilnoblend.bmp, HUMID_MEDIUM
+ * 4) -> /brushes/charcoalAlpha.bmp, DRY_MEDIUM
+ * 5) -> /brushes/washbrushAlpha.bmp, DRY_MEDIUM
+ * 6) -> /brushes/opaqueDryBrushAlpha.bmp, OPAQUE_MEDIUM
+ * 7) -> /brushes/opaqueBrushAlpha.bmp, Stroke::OPAQUE_MEDIUM
+ * Any other value will lead to the following preset:
+ * default) -> /brushes/smoothAlpha.bmp, OPAQUE_MEDIUM.
+ */
+ class LIB_STROKE_EXPORT TextureAssignerShader : public StrokeShader // FIXME
+ {
+ private:
+ int _textureId;
+ public:
+ /*! Builds the shader.
+ * \param id
+ * The number of the preset to use.
+ */
+ TextureAssignerShader(int id)
+ : StrokeShader()
+ {
+ _textureId = id;
+ }
+ /*! The shading method */
+ virtual void shade(Stroke& stroke) const;
+
+ };
+ /*! [ Texture Shader ].
+ * Assigns a texture and a blending mode to the stroke
+ * in order to simulate its marks system.
+ */
+ class LIB_STROKE_EXPORT StrokeTextureShader : public StrokeShader
+ {
+ private:
+ string _texturePath;
+ Stroke::MediumType _mediumType;
+ bool _tips; // 0 or 1
+
+ public:
+ /*! Builds the shader from the texture file name and the blending mode to use.
+ * \param textureFile
+ * The the texture file name.
+ * \attention The textures must be placed in the $FREESTYLE_DIR/data/textures/brushes
+ * directory.
+ * \param mediumType
+ * The medium type and therefore, the blending mode that must
+ * be used for the rendering of this stroke.
+ * \param iTips
+ * Tells whether the texture includes tips or not.
+ * If it is the case, the texture image must respect the following
+ * format:
+ * \verbatim
+ * __________
+ * | |
+ * | A |
+ * |__________|
+ * | | |
+ * | B | C |
+ * |_____|____|
+ *
+ * \endverbatim
+ * - A : The stroke's corpus texture
+ * - B : The stroke's left extremity texture
+ * - C : The stroke's right extremity texture
+ */
+ StrokeTextureShader(const string textureFile, Stroke::MediumType mediumType = Stroke::OPAQUE_MEDIUM, bool iTips = false)
+ : StrokeShader()
+ {
+ _texturePath = textureFile;
+ _mediumType = mediumType;
+ _tips = iTips;
+ }
+ /*! The shading method */
+ virtual void shade(Stroke& stroke) const;
+
+ };
+
+
+ //
+ // Geometry Shaders
+ //
+ ///////////////////////////////////////////////////////////////////////////////
+ /*! [ Geometry Shader ].
+ * Stretches the stroke at its two extremities and following the
+ * respective directions: v(1)v(0) and v(n-1)v(n).
+ */
+ class LIB_STROKE_EXPORT BackboneStretcherShader : public StrokeShader
+ {
+ private:
+ float _amount;
+ public:
+ /*! Builds the shader.
+ * \param iAmount
+ * The stretching amount value.
+ */
+ BackboneStretcherShader(float iAmount=2.f)
+ : StrokeShader()
+ {
+ _amount = iAmount;
+ }
+ /*! The shading method */
+ virtual void shade(Stroke& stroke) const;
+ };
+
+ /*! [ Geometry Shader. ]
+ * Resamples the stroke.
+ * @see Stroke::Resample(float).
+ */
+ class LIB_STROKE_EXPORT SamplingShader: public StrokeShader
+ {
+ private:
+ float _sampling;
+ public:
+ /*! Builds the shader.
+ * \param sampling
+ * The sampling to use for the
+ * stroke resampling
+ */
+ SamplingShader(float sampling)
+ : StrokeShader()
+ {
+ _sampling = sampling;
+ }
+ /*! The shading method */
+ virtual void shade(Stroke& stroke) const;
+ };
+
+
+ class LIB_STROKE_EXPORT ExternalContourStretcherShader : public StrokeShader
+ {
+ private:
+ float _amount;
+ public:
+ ExternalContourStretcherShader(float iAmount=2.f)
+ : StrokeShader()
+ {
+ _amount = iAmount;
+ }
+
+ virtual void shade(Stroke& stroke) const;
+ };
+
+ // B-Spline stroke shader
+ class LIB_STROKE_EXPORT BSplineShader: public StrokeShader
+ {
+ public:
+ BSplineShader()
+ : StrokeShader()
+ {}
+
+ virtual void shade(Stroke& stroke) const;
+ };
+
+
+ // Bezier curve stroke shader
+ /*! [ Geometry Shader ].
+ * Transforms the stroke backbone geometry
+ * so that it corresponds to a Bezier Curve
+ * approximation of the original backbone geometry.
+ * @see \htmlonly <a href=bezier/bezier.html>bezier/bezier.html</a> \endhtmlonly
+ */
+ class LIB_STROKE_EXPORT BezierCurveShader : public StrokeShader
+ {
+ private:
+ float _error;
+ public:
+ /*! Builds the shader.
+ * \param error
+ * The error we're allowing for the approximation.
+ * This error is the max distance allowed between
+ * the new curve and the original geometry.
+ */
+ BezierCurveShader(float error = 4.0)
+ : StrokeShader()
+ {_error=error;}
+
+ /*! The shading method */
+ virtual void shade(Stroke& stroke) const;
+ };
+
+ /* Shader to inflate the curves. It keeps the extreme
+ * points positions and moves the other ones along
+ * the 2D normal. The displacement value is proportional
+ * to the 2d curvature at the considered point (the higher
+ * the curvature, the smaller the displacement) and to a value
+ * specified by the user.
+ */
+ class LIB_STROKE_EXPORT InflateShader : public StrokeShader
+ {
+ private:
+ float _amount;
+ float _curvatureThreshold;
+ public:
+ /*! Builds an inflate shader
+ * \param iAmount
+ * A multiplicative coefficient that
+ * acts on the amount and direction of displacement
+ * \param iThreshold
+ * The curves having a 2d curvature > iThreshold
+ * at one of their points is not inflated
+ */
+ InflateShader(float iAmount,float iThreshold)
+ : StrokeShader()
+ {
+ _amount = iAmount;
+ _curvatureThreshold = iThreshold;
+ }
+ /*! The shading method */
+ virtual void shade(Stroke& stroke) const;
+ };
+
+ /*! [ Geometry Shader ].
+ * Shader to modify the Stroke geometry so that
+ * it looks more "polygonal".
+ * The basic idea is to start from the
+ * minimal stroke approximation consisting in
+ * a line joining the first vertex to the last one and
+ * to subdivide using the original stroke vertices
+ * until a certain error is reached.
+ */
+ class LIB_STROKE_EXPORT PolygonalizationShader : public StrokeShader
+ {
+ private:
+ float _error;
+ public:
+ /*! Builds the shader.
+ * \param iError
+ * The error we want our polygonal approximation
+ * to have with respect to the original geometry.
+ * The smaller, the closer the new stroke to
+ * the orinal one.
+ * This error corresponds to the maximum distance
+ * between the new stroke and the old one.
+ */
+ PolygonalizationShader(float iError) : StrokeShader()
+ {_error = iError;}
+ /*! The shading method */
+ virtual void shade(Stroke& stroke) const;
+ };
+
+
+ /*! [ Geometry Shader ].
+ * Shader to modify the Stroke geometry so that
+ * it corresponds to its main direction line.
+ * This shader must be used together with the
+ * splitting operator using the curvature criterion.
+ * Indeed, the precision of the approximation
+ * will depend on the size of the stroke's pieces.
+ * The bigger the pieces, the rougher the approximation.
+ */
+ class LIB_STROKE_EXPORT GuidingLinesShader : public StrokeShader
+ {
+ private:
+ float _offset;
+ public:
+ /*! Builds a Guiding Lines shader
+ * \param iOffset
+ * The line that replaces the stroke
+ * is initially in the middle
+ * of the initial stroke "bbox".
+ * iOffset is the value of the displacement
+ * which is applied to this line along its
+ * normal.
+ */
+ GuidingLinesShader(float iOffset) : StrokeShader()
+ {_offset = iOffset;}
+ /*! The shading method */
+ virtual void shade(Stroke& stroke) const;
+ };
+
+ /*! [ Geometry Shader ].
+ * Removes the stroke's extremities.
+ */
+ class LIB_STROKE_EXPORT TipRemoverShader : public StrokeShader
+ {
+ public:
+ /*! Builds the shader.
+ * \param tipLength
+ * The length of the piece of stroke
+ * we want to remove at each extremity.
+ */
+ TipRemoverShader (real tipLength);
+ /*! Destructor. */
+ virtual ~TipRemoverShader () {}
+ /*! The shading method */
+ virtual void shade(Stroke &stroke) const;
+
+ protected:
+
+ real _tipLength;
+ };
+
+ /*! [ output Shader ].
+ * streams the Stroke
+ */
+ class LIB_STROKE_EXPORT streamShader : public StrokeShader
+ {
+ public:
+ /*! Destructor. */
+ virtual ~streamShader() {}
+ /*! Returns the string "streamShader".*/
+ virtual string getName() const {
+ return "streamShader";
+ }
+ /*! The shading method. */
+ virtual void shade(Stroke& stroke) const;
+ };
+
+ /*! [ output Shader ].
+ * streams the Stroke in a file
+ */
+ class LIB_STROKE_EXPORT fstreamShader : public StrokeShader
+ {
+ protected:
+ mutable ofstream _stream;
+ public:
+ /*! Builds the shader from the output file name */
+ fstreamShader(const char *iFileName) : StrokeShader(){
+ _stream .open(iFileName);
+ if(!_stream.is_open()){
+ cout << "couldn't open file " << iFileName << endl;
+ }
+ }
+ /*! Destructor. */
+ virtual ~fstreamShader() {_stream.close();}
+ /*! Returns the string "fstreamShader".*/
+ virtual string getName() const {
+ return "fstreamShader";
+ }
+ /*! The shading method. */
+ virtual void shade(Stroke& stroke) const;
+ };
+} // end of namespace StrokeShaders
+
+#endif // BASIC_STROKE_SHADERS_H
diff --git a/source/blender/freestyle/intern/stroke/Canvas.cpp b/source/blender/freestyle/intern/stroke/Canvas.cpp
new file mode 100755
index 00000000000..ecb76c4a015
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/Canvas.cpp
@@ -0,0 +1,427 @@
+
+//
+// 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 <vector>
+#include "../system/FreestyleConfig.h"
+#include "StrokeRenderer.h"
+#include "../system/TimeStamp.h"
+#include "../system/PseudoNoise.h"
+#include "Canvas.h"
+#include <qimage.h>
+#include <QString>
+#include "../image/Image.h"
+#include "../image/GaussianFilter.h"
+#include "../image/ImagePyramid.h"
+#include "../view_map/SteerableViewMap.h"
+#include "StyleModule.h"
+
+using namespace std;
+
+LIB_STROKE_EXPORT
+Canvas * Canvas::_pInstance = 0;
+
+LIB_STROKE_EXPORT
+const char * Canvas::_MapsPath = 0;
+
+using namespace std;
+
+Canvas::Canvas()
+{
+ _SelectedFEdge = 0;
+ _pInstance = this;
+ PseudoNoise::init(42);
+ _paperTextureIndex = 0;
+ _Renderer = 0;
+ _drawPaper = true;
+ _current_sm = NULL;
+ _steerableViewMap = new SteerableViewMap(NB_STEERABLE_VIEWMAP-1);
+}
+
+Canvas::Canvas(const Canvas& iBrother)
+{
+ _SelectedFEdge = iBrother._SelectedFEdge;
+ _pInstance = this;
+ PseudoNoise::init(42);
+ _paperTextureIndex = iBrother._paperTextureIndex;
+ _Renderer = iBrother._Renderer;
+ _drawPaper = iBrother._drawPaper;
+ _current_sm = iBrother._current_sm;
+ _steerableViewMap = new SteerableViewMap(*(iBrother._steerableViewMap));
+
+}
+
+Canvas::~Canvas()
+{
+ _pInstance = 0;
+
+ Clear();
+ if(_Renderer)
+ {
+ delete _Renderer;
+ _Renderer = 0;
+ }
+ // FIXME: think about an easy control
+ // for the maps memory management...
+ if(!_maps.empty()){
+ for(mapsMap::iterator m=_maps.begin(), mend=_maps.end();
+ m!=mend;
+ ++m){
+ delete ((*m).second);
+ }
+ _maps.clear();
+ }
+ if(_steerableViewMap)
+ delete _steerableViewMap;
+}
+
+void Canvas::preDraw() {}
+
+void Canvas::Draw()
+{
+ if(_StyleModules.empty())
+ return;
+ preDraw();
+ TimeStamp *timestamp = TimeStamp::instance();
+
+ for(unsigned i = 0; i < _StyleModules.size(); i++) {
+ _current_sm = _StyleModules[i];
+ if (!_StyleModules[i]->getModified())
+ {
+ if (_StyleModules[i]->getDrawable() && _Layers[i])
+ _Layers[i]->Render(_Renderer);
+ continue;
+ }
+ if (i < _Layers.size() && _Layers[i])
+ delete _Layers[i];
+
+ _Layers[i] = _StyleModules[i]->execute();
+
+ if (_StyleModules[i]->getDrawable() && _Layers[i])
+ _Layers[i]->Render(_Renderer);
+
+ timestamp->increment();
+ }
+ postDraw();
+}
+
+void Canvas::postDraw()
+{
+ update();
+}
+
+
+void Canvas::Clear()
+{
+ if(!_Layers.empty()) {
+ for (deque<StrokeLayer*>::iterator sl=_Layers.begin(), slend=_Layers.end();
+ sl != slend;
+ ++sl)
+ if (*sl)
+ delete (*sl);
+ _Layers.clear();
+ }
+
+ if(!_StyleModules.empty()) {
+ for (deque<StyleModule*>::iterator s=_StyleModules.begin(), send=_StyleModules.end();
+ s != send;
+ ++s)
+ if (*s)
+ delete (*s);
+ _StyleModules.clear();
+ }
+ if(_steerableViewMap)
+ _steerableViewMap->Reset();
+}
+
+void Canvas::Erase()
+{
+ if(!_Layers.empty())
+ {
+ for (deque<StrokeLayer*>::iterator sl=_Layers.begin(), slend=_Layers.end();
+ sl != slend;
+ ++sl)
+ if (*sl)
+ (*sl)->clear();
+ }
+ if(_steerableViewMap)
+ _steerableViewMap->Reset();
+ update();
+}
+
+void Canvas::InsertStyleModule(unsigned index, StyleModule *iStyleModule) {
+ unsigned size = _StyleModules.size();
+ StrokeLayer* layer = new StrokeLayer();
+ if((_StyleModules.empty()) || (index == size)) {
+ _StyleModules.push_back(iStyleModule);
+ _Layers.push_back(layer);
+ return;
+ }
+ _StyleModules.insert(_StyleModules.begin() + index, iStyleModule);
+ _Layers.insert(_Layers.begin()+index, layer);
+}
+
+void Canvas::RemoveStyleModule(unsigned index)
+{
+ unsigned i=0;
+ if (!_StyleModules.empty())
+ {
+ for(deque<StyleModule*>::iterator s=_StyleModules.begin(), send=_StyleModules.end();
+ s!=send;
+ ++s)
+ {
+ if(i == index)
+ {
+ // remove shader
+ if (*s)
+ delete *s;
+ _StyleModules.erase(s);
+ break;
+ }
+ ++i;
+ }
+ }
+ i=0;
+ if(!_Layers.empty())
+ {
+ for(deque<StrokeLayer*>::iterator sl=_Layers.begin(), slend=_Layers.end();
+ sl!=slend;
+ ++sl)
+ {
+ if(i == index)
+ {
+ // remove layer
+ if (*sl)
+ delete *sl;
+ _Layers.erase(sl);
+ break;
+ }
+ ++i;
+ }
+ }
+}
+
+
+void Canvas::SwapStyleModules(unsigned i1, unsigned i2)
+{
+ StyleModule* tmp;
+ tmp = _StyleModules[i1];
+ _StyleModules[i1] = _StyleModules[i2];
+ _StyleModules[i2] = tmp;
+
+ StrokeLayer* tmp2;
+ tmp2 = _Layers[i1];
+ _Layers[i1] = _Layers[i2];
+ _Layers[i2] = tmp2;
+}
+
+void Canvas::ReplaceStyleModule(unsigned index, StyleModule *iStyleModule)
+{
+ unsigned i=0;
+ for(deque<StyleModule*>::iterator s=_StyleModules.begin(), send=_StyleModules.end();
+ s != send;
+ ++s)
+ {
+ if(i == index)
+ {
+ if (*s)
+ delete *s;
+ *s = iStyleModule;
+ break;
+ }
+ ++i;
+ }
+}
+
+void Canvas::SetVisible(unsigned index, bool iVisible) {
+ _StyleModules[index]->setDisplayed(iVisible);
+}
+
+void Canvas::setModified(unsigned index, bool iMod)
+{
+ _StyleModules[index]->setModified(iMod);
+}
+
+void Canvas::resetModified(bool iMod/* =false */)
+{
+ unsigned size = _StyleModules.size();
+ for(unsigned i = 0; i < size; ++i)
+ setModified(i,iMod);
+}
+
+void Canvas::causalStyleModules(vector<unsigned>& vec, unsigned index) {
+ unsigned size = _StyleModules.size();
+
+ for(unsigned i = index; i < size; ++i)
+ if (_StyleModules[i]->getCausal())
+ vec.push_back(i);
+}
+
+void Canvas::changePaperTexture(bool increment)
+{
+ if(increment)
+ _paperTextureIndex = (_paperTextureIndex+1) % TextureManager::getPaperTexturesNumber();
+ else
+ {
+ _paperTextureIndex--;
+ if(_paperTextureIndex < 0)
+ _paperTextureIndex = TextureManager::getPaperTexturesNumber() - 1;
+ }
+}
+
+void Canvas::Render(const StrokeRenderer *iRenderer)
+{
+ for (unsigned i = 0; i < _StyleModules.size(); i++) {
+ if(!_StyleModules[i]->getDisplayed() || !_Layers[i])
+ continue;
+ _Layers[i]->Render(iRenderer);
+ }
+}
+
+void Canvas::RenderBasic(const StrokeRenderer *iRenderer)
+
+{
+ for (unsigned i = 0; i < _StyleModules.size(); i++) {
+ if(!_StyleModules[i]->getDisplayed() || !_Layers[i])
+ continue;
+ _Layers[i]->RenderBasic(iRenderer);
+ }
+}
+
+void Canvas::loadMap(const char *iFileName, const char *iMapName, unsigned int iNbLevels, float iSigma){
+ // check whether this map was already loaded:
+ if(!_maps.empty()){
+ mapsMap::iterator m = _maps.find(iMapName);
+ if(m!=_maps.end()){
+ // lazy check for size changes
+ ImagePyramid * pyramid = (*m).second;
+ if((pyramid->width() != width()) || (pyramid->height() != height())){
+ delete pyramid;
+ }else{
+ return;
+ }
+ }
+ }
+ string filePath;
+ if(_MapsPath){
+ filePath = _MapsPath;
+ filePath += iFileName;
+ }else{
+ filePath = iFileName;
+ }
+ QImage * qimg;
+ QImage newMap(filePath.c_str());
+ if(newMap.isNull()){
+ cout << "Could not load image file " << filePath << endl;
+ return;
+ }
+ qimg = &newMap;
+
+ //resize
+ QImage scaledImg;
+ if((newMap.width()!=width()) || (newMap.height()!=height())){
+ scaledImg = newMap.scaled(width(), height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+ qimg = &scaledImg;
+ }
+
+ // deal with color image
+ // if(newMap->depth() != 8){
+ // int w = newMap->width();
+ // int h = newMap->height();
+ // QImage *tmp = new QImage(w, h, 8);
+ // for(unsigned y=0;y<h;++y){
+ // for(unsigned x=0;x<w;++x){
+ // int c = qGray(newMap->pixel(x,y));
+ // tmp->setPixel(x,y,c);
+ // }
+ // }
+ // delete newMap;
+ // newMap = tmp;
+ // }
+
+ unsigned x,y;
+ int w = qimg->width();
+ int h = qimg->height();
+ GrayImage tmp(w,h);
+ for(y=0; y<h;++y){
+ for(x=0;x<w;++x){
+ float c = qGray(qimg->pixel(x,y));// /255.f;
+ tmp.setPixel(x,y,c);
+ }
+ }
+
+ // GrayImage blur(w,h);
+ // GaussianFilter gf(4.f);
+ // //int bound = gf.getBound();
+ // for(y=0; y<h;++y){
+ // for(x=0;x<w;++x){
+ // int c = gf.getSmoothedPixel<GrayImage>(&tmp, x,y);
+ // blur.setPixel(x,y,c);
+ // }
+ // }
+
+ GaussianPyramid *pyramid = new GaussianPyramid(tmp, iNbLevels, iSigma);
+ int ow = pyramid->width(0);
+ int oh = pyramid->height(0);
+ QString base(iMapName);
+ for(unsigned i=0; i<pyramid->getNumberOfLevels(); ++i){
+ // save each image:
+ // w = pyramid.width(i);
+ // h = pyramid.height(i);
+ QImage qtmp(ow, oh, QImage::Format_RGB32);
+ //int k = (1<<i);
+ for(y=0;y<oh;++y){
+ for(x=0;x<ow;++x){
+ int c = pyramid->pixel(x,y,i);//255*pyramid->pixel(x,y,i);
+ qtmp.setPixel(x,y,qRgb(c,c,c));
+ }
+ }
+ qtmp.save(base+QString::number(i)+".bmp", "BMP");
+ }
+ // QImage *qtmp = new QImage(w, h, 32);
+ // for(y=0;y<h;++y){
+ // for(x=0;x<w;++x){
+ // int c = (int)blur.pixel(x,y);
+ // qtmp->setPixel(x,y,qRgb(c,c,c));
+ // }
+ // }
+ // delete newMap;
+ // newMap = qtmp;
+ //
+ _maps[iMapName] = pyramid;
+ // newMap->save("toto.bmp", "BMP");
+}
+
+float Canvas::readMapPixel(const char *iMapName, int level, int x, int y){
+ if(_maps.empty()){
+ cout << "readMapPixel warning: no map was loaded "<< endl;
+ return -1;
+ }
+ mapsMap::iterator m = _maps.find(iMapName);
+ if(m==_maps.end()){
+ cout << "readMapPixel warning: no map was loaded with the name " << iMapName << endl;
+ return -1;
+ }
+ ImagePyramid *pyramid = (*m).second;
+ if((x<0) || (x>=pyramid->width()) || (y<0) || (y>=pyramid->height()))
+ return 0;
+
+ return pyramid->pixel(x,height()-1-y,level);
+}
diff --git a/source/blender/freestyle/intern/stroke/Canvas.h b/source/blender/freestyle/intern/stroke/Canvas.h
new file mode 100755
index 00000000000..cae50162933
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/Canvas.h
@@ -0,0 +1,198 @@
+//
+// Filename : Canvas.h
+// Author(s) : Stephane Grabli
+// Purpose : Class to define a canvas designed to draw style modules
+// Date of creation : 20/10/2002
+//
+///////////////////////////////////////////////////////////////////////////////
+
+
+//
+// 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef CANVAS_H
+# define CANVAS_H
+
+# include <deque>
+# include <vector>
+# include <map>
+# include "../system/FreestyleConfig.h"
+# include "StrokeLayer.h"
+# include "../geometry/BBox.h"
+# include "../geometry/Geom.h"
+
+using namespace Geometry;
+
+struct ltstr
+{
+ bool operator()(const char* s1, const char* s2) const
+ {
+ return strcmp(s1, s2) < 0;
+ }
+};
+
+class InformationMap;
+class StrokeRenderer;
+class ViewMap;
+class ViewEdge;
+class FEdge;
+class RGBImage;
+class GrayImage;
+class QImage;
+class ImagePyramid;
+class SteerableViewMap;
+class StyleModule;
+
+/*! Class to define the canvas on which strokes are drawn.
+ * It's used to store state information about the drawing.
+ */
+class LIB_STROKE_EXPORT Canvas
+{
+public:
+ /*! Returns a pointer on the Canvas instance */
+ static Canvas * getInstance() {return _pInstance;}
+ typedef std::map<const char*, ImagePyramid*, ltstr> mapsMap ;
+ static const int NB_STEERABLE_VIEWMAP = 5;
+protected:
+ static Canvas *_pInstance;
+ std::deque<StrokeLayer*> _Layers;
+ std::deque<StyleModule*> _StyleModules;
+ FEdge *_SelectedFEdge;
+ int _paperTextureIndex;
+ bool _drawPaper;
+ StrokeRenderer *_Renderer;
+ StyleModule* _current_sm;
+ mapsMap _maps;
+ static const char * _MapsPath;
+ SteerableViewMap *_steerableViewMap;
+
+public:
+ /* Builds the Canvas */
+ Canvas();
+ /* Copy constructor */
+ Canvas(const Canvas& iBrother);
+ /* Destructor */
+ virtual ~Canvas();
+
+ /* operations that need to be done before a draw */
+ virtual void preDraw();
+
+ /* Draw the canvas using the current shader */
+ virtual void Draw();
+
+ /* operations that need to be done after a draw */
+ virtual void postDraw();
+
+ /* Renders the created strokes */
+ virtual void Render(const StrokeRenderer *iRenderer);
+ /* Basic Renders the created strokes */
+ virtual void RenderBasic(const StrokeRenderer *iRenderer);
+ /* Renders a stroke */
+ virtual void RenderStroke(Stroke *iStroke) = 0;
+
+ /* init the canvas */
+ virtual void init() = 0;
+
+ /* Clears the Canvas (shaders stack, layers stack...)*/
+ void Clear();
+
+ /* Erases the layers */
+ virtual void Erase();
+
+ /* Reads a pixel area from the canvas */
+ virtual void readColorPixels(int x, int y,int w, int h, RGBImage& oImage) const = 0;
+ /* Reads a depth pixel area from the canvas */
+ virtual void readDepthPixels(int x, int y,int w, int h, GrayImage& oImage) const = 0;
+
+ /* update the canvas (display) */
+ virtual void update() = 0;
+
+ /* checks whether the canvas is empty or not */
+ bool isEmpty() const {return (_Layers.empty());}
+
+ /* Maps management */
+ /*! Loads an image map. The map will be scaled
+ * (without preserving the ratio in order
+ * to fit the actual canvas size.)
+ * The image must be a gray values image...
+ * \param iFileName
+ * The name of the image file
+ * \param iMapName
+ * The name that will be used to access
+ * this image
+ * \param iNbLevels
+ * The number of levels in the map pyramid. (default = 4).
+ * If iNbLevels == 0, the complete pyramid is built.
+ */
+ void loadMap(const char *iFileName, const char *iMapName, unsigned iNbLevels=4, float iSigma = 1.f);
+
+ /*! Reads a pixel value in a map.
+ * Returns a value between 0 and 1.
+ * \param iMapName
+ * The name of the map
+ * \param level
+ * The level of the pyramid from which the pixel must
+ * be read.
+ * \param x
+ * The abscissa of the desired pixel specified in level0 coordinate
+ * system. The origin is the lower left corner.
+ * \param y
+ * The ordinate of the desired pixel specified in level0 coordinate
+ * system. The origin is the lower left corner.
+ */
+ float readMapPixel(const char *iMapName, int level, int x, int y);
+
+ /*! Sets the steerable viewmap */
+ void loadSteerableViewMap(SteerableViewMap * iSVM) {_steerableViewMap = iSVM;}
+
+ /*! Returns the steerable VM */
+ SteerableViewMap * getSteerableViewMap() {return _steerableViewMap;}
+
+ /*! accessors */
+ inline const FEdge * selectedFEdge() const {return _SelectedFEdge;}
+ inline FEdge * selectedFEdge() {return _SelectedFEdge;}
+ virtual int width() const = 0;
+ virtual int height() const = 0;
+ inline int currentPaperTextureIndex() const {return _paperTextureIndex;}
+ virtual BBox<Vec3r> scene3DBBox() const = 0;
+ inline const StrokeRenderer * renderer() const {return _Renderer;}
+ inline StyleModule* getCurrentStyleModule() { return _current_sm; }
+ virtual bool getRecordFlag() const {return false;}
+
+ /*! modifiers */
+ inline void SetSelectedFEdge(FEdge *iFEdge) {_SelectedFEdge = iFEdge;}
+ /*! inserts a shader at pos index+1 */
+ void InsertStyleModule(unsigned index, StyleModule *iStyleModule);
+ void RemoveStyleModule(unsigned index);
+ void SwapStyleModules(unsigned i1, unsigned i2);
+ void ReplaceStyleModule(unsigned index, StyleModule *iStyleModule);
+ void SetVisible(unsigned index, bool iVisible) ;
+ //inline void SetDensityMap(InformationMap<RGBImage>* iMap) {_DensityMap = iMap;}
+ inline void AddLayer(StrokeLayer *iLayer) {_Layers.push_back(iLayer);}
+ inline void SetCurrentPaperTextureIndex(int i) {_paperTextureIndex = i;}
+ void changePaperTexture(bool increment=true) ;
+ /*! enables/disables paper texture */
+ inline void togglePaperTexture() {_drawPaper = !_drawPaper;}
+ void resetModified(bool iMod=false);
+ void causalStyleModules(std::vector<unsigned>& vec, unsigned index = 0);
+ void setModified(unsigned index, bool b);
+};
+
+#endif // CANVAS_H
diff --git a/source/blender/freestyle/intern/stroke/Chain.cpp b/source/blender/freestyle/intern/stroke/Chain.cpp
new file mode 100755
index 00000000000..3776cd58a03
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/Chain.cpp
@@ -0,0 +1,126 @@
+
+//
+// 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 "Chain.h"
+#include "../view_map/ViewMapIterators.h"
+#include "../view_map/ViewMapAdvancedIterators.h"
+
+void Chain::push_viewedge_back(ViewEdge *iViewEdge, bool orientation)
+{
+ ViewEdge::vertex_iterator v;
+ ViewEdge::vertex_iterator vend;
+ ViewEdge::vertex_iterator vfirst;
+ Vec3r previous, current;
+ if(true == orientation)
+ {
+ v=iViewEdge->vertices_begin();
+ vfirst = v;
+ vend=iViewEdge->vertices_end();
+ }
+ else
+ {
+ v=iViewEdge->vertices_last();
+ vfirst = v;
+ vend=iViewEdge->vertices_end();
+ }
+
+ if(!_Vertices.empty())
+ {
+ previous = _Vertices.back()->point2d();
+ if(orientation)
+ ++v;
+ else
+ --v;
+ }
+ else
+ previous = (*v)->point2d();
+ do{
+ current = (*v)->point2d();
+ Curve::push_vertex_back(*v);
+ //_Length += (current-previous).norm();
+ previous = current;
+ if(orientation)
+ ++v;
+ else
+ --v;
+ }while((v!=vend) && (v!=vfirst));
+
+ if(v==vfirst)
+ {
+ //Add last one:
+ current = (*v)->point2d();
+ Curve::push_vertex_back(*v);
+ //_Length += (current-previous).norm();
+ }
+}
+
+void Chain::push_viewedge_front(ViewEdge *iViewEdge, bool orientation)
+{
+ orientation = !orientation;
+ ViewEdge::vertex_iterator v;
+ ViewEdge::vertex_iterator vend;
+ ViewEdge::vertex_iterator vfirst;
+ Vec3r previous, current;
+ if(true == orientation)
+ {
+ v=iViewEdge->vertices_begin();
+ vfirst = v;
+ vend=iViewEdge->vertices_end();
+ }
+ else
+ {
+ v=iViewEdge->vertices_last();
+ vfirst = v;
+ vend=iViewEdge->vertices_end();
+ }
+
+ if(!_Vertices.empty())
+ {
+ previous = _Vertices.front()->point2d();
+ if(orientation)
+ ++v;
+ else
+ --v;
+ }
+ else
+ previous = (*v)->point2d();
+ do{
+ current = (*v)->point2d();
+ Curve::push_vertex_front((*v));
+ //_Length += (current-previous).norm();
+ previous = current;
+ if(orientation)
+ ++v;
+ else
+ --v;
+ }while((v!=vend) && (v!=vfirst));
+
+ if(v==vfirst)
+ {
+ //Add last one:
+ current = (*v)->point2d();
+ Curve::push_vertex_front(*v);
+ //_Length += (current-previous).norm();
+ }
+}
+
+
+
diff --git a/source/blender/freestyle/intern/stroke/Chain.h b/source/blender/freestyle/intern/stroke/Chain.h
new file mode 100755
index 00000000000..042437a4154
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/Chain.h
@@ -0,0 +1,82 @@
+//
+// Filename : Chain.h
+// Author(s) : Stephane Grabli
+// Purpose : Class to define a chain of viewedges.
+// Date of creation : 09/01/2003
+//
+///////////////////////////////////////////////////////////////////////////////
+
+
+//
+// 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef CHAIN_H
+# define CHAIN_H
+
+# include "../view_map/ViewMap.h"
+# include "Curve.h"
+/*! Class to represent a 1D elements issued
+ * from the chaining process.
+ * A Chain is the last step before the Stroke and
+ * is used in the Splitting and Creation processes.
+ */
+class Chain : public Curve
+{
+protected:
+ // tmp
+ Id * _splittingId;
+public:
+ /*! Defult constructor. */
+ Chain() : Curve() {_splittingId=0;}
+ /*! Builds a chain from its Id. */
+ Chain(const Id& id) : Curve(id) {_splittingId=0;}
+ /*! Copy Constructor */
+ Chain(const Chain& iBrother) : Curve(iBrother) {_splittingId=iBrother._splittingId;}
+ /*! Destructor. */
+ virtual ~Chain() {
+ // only the last splitted deletes this id
+ if(_splittingId){
+ if(*_splittingId == _Id)
+ delete _splittingId;
+ }
+ }
+
+ /*! Adds a ViewEdge at the end of the chain
+ * \param iViewEdge
+ * The ViewEdge that must be added.
+ * \param orientation
+ * The orientation with which this ViewEdge
+ * must be processed.
+ */
+ void push_viewedge_back(ViewEdge *iViewEdge, bool orientation) ;
+ /*! Adds a ViewEdge at the beginning of the chain
+ * \param iViewEdge
+ * The ViewEdge that must be added.
+ * \param orientation
+ * The orientation with which this ViewEdge
+ * must be processed.
+ */
+ void push_viewedge_front(ViewEdge *iViewEdge, bool orientation) ;
+
+ inline void setSplittingId(Id * sid){_splittingId = sid;}
+ inline Id* getSplittingId() {return _splittingId;}
+};
+
+#endif // CHAIN_H
diff --git a/source/blender/freestyle/intern/stroke/ChainingIterators.cpp b/source/blender/freestyle/intern/stroke/ChainingIterators.cpp
new file mode 100755
index 00000000000..206b6eb7364
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/ChainingIterators.cpp
@@ -0,0 +1,147 @@
+
+//
+// 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 "ChainingIterators.h"
+#include "../system/TimeStamp.h"
+
+ViewEdge* AdjacencyIterator::operator*() {
+ return (*_internalIterator).first;
+}
+bool AdjacencyIterator::isIncoming() const{
+ return (*_internalIterator).second;
+}
+
+void AdjacencyIterator::increment(){
+ ++_internalIterator;
+ while((!_internalIterator.isEnd()) && (!isValid((*_internalIterator).first)))
+ ++_internalIterator;
+}
+
+bool AdjacencyIterator::isValid(ViewEdge* edge){
+ if(_restrictToSelection)
+ if(edge->getTimeStamp() != TimeStamp::instance()->getTimeStamp())
+ return false;
+ if(_restrictToUnvisited)
+ if(edge->getChainingTimeStamp() > TimeStamp::instance()->getTimeStamp())
+ return false;
+ return true;
+}
+
+void ChainingIterator::increment() {
+ _increment = true;
+ ViewVertex * vertex = getVertex();
+ if(!vertex){
+ _edge = 0;
+ return;
+ }
+ AdjacencyIterator it = AdjacencyIterator(vertex, _restrictToSelection, _restrictToUnvisited);
+ if(it.isEnd())
+ _edge = 0;
+ else
+ _edge = traverse(it);
+ if(_edge == 0)
+ return;
+ if(_edge->A() == vertex)
+ _orientation = true;
+ else
+ _orientation = false;
+}
+
+void ChainingIterator::decrement() {
+ _increment = false;
+ ViewVertex * vertex = getVertex();
+ if(!vertex){
+ _edge = 0;
+ return;
+ }
+ AdjacencyIterator it = AdjacencyIterator(vertex, _restrictToSelection, _restrictToUnvisited);
+ if(it.isEnd())
+ _edge = 0;
+ else
+ _edge = traverse(it);
+ if(_edge == 0)
+ return;
+ if(_edge->B() == vertex)
+ _orientation = true;
+ else
+ _orientation = false;
+}
+
+//
+// ChainSilhouetteIterators
+//
+///////////////////////////////////////////////////////////
+
+ViewEdge * ChainSilhouetteIterator::traverse(const AdjacencyIterator& ait){
+ AdjacencyIterator it(ait);
+ ViewVertex* nextVertex = getVertex();
+ // we can't get a NULL nextVertex here, it was intercepted
+ // before
+ if(nextVertex->getNature() & Nature::T_VERTEX){
+ TVertex * tvertex = (TVertex*)nextVertex;
+ ViewEdge *mate = (tvertex)->mate(getCurrentEdge());
+ while(!it.isEnd()){
+ ViewEdge *ve = *it;
+ if(ve == mate)
+ return ve;
+ ++it;
+ }
+ return 0;
+ }
+ if(nextVertex->getNature() & Nature::NON_T_VERTEX){
+ NonTVertex * nontvertex = (NonTVertex*)nextVertex;
+ ViewEdge * newEdge(0);
+ // we'll try to chain the edges by keeping the same nature...
+ // the preseance order is : SILHOUETTE, BORDER, CREASE, SUGGESTIVE, VALLEY, RIDGE
+ Nature::EdgeNature natures[6] = {Nature::SILHOUETTE, Nature::BORDER, Nature::CREASE, Nature::SUGGESTIVE_CONTOUR, Nature::VALLEY, Nature::RIDGE};
+ for(unsigned i=0; i<6; ++i){
+ if(getCurrentEdge()->getNature() & natures[i]){
+ int n = 0;
+ while(!it.isEnd()){
+ ViewEdge *ve = *it;
+ if(ve->getNature() & natures[i]){
+ ++n;
+ newEdge = ve;
+ }
+ ++it;
+ }
+ if(n == 1){
+ return newEdge;
+ }else{
+ return 0;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+ViewEdge * ChainPredicateIterator::traverse(const AdjacencyIterator& ait){
+ AdjacencyIterator it(ait);
+ // Iterates over next edges to see if one of them
+ // respects the predicate:
+ while(!it.isEnd()) {
+ ViewEdge *ve = *it;
+ if(((*_unary_predicate)(*ve)) && ((*_binary_predicate)(*(getCurrentEdge()),*(ve))))
+ return ve;
+ ++it;
+ }
+ return 0;
+}
diff --git a/source/blender/freestyle/intern/stroke/ChainingIterators.h b/source/blender/freestyle/intern/stroke/ChainingIterators.h
new file mode 100755
index 00000000000..1e946855dce
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/ChainingIterators.h
@@ -0,0 +1,364 @@
+//
+// Filename : ChainingIterators
+// Author : Stephane Grabli
+// Purpose : Chaining iterators
+// Date of creation : 01/07/2003
+//
+///////////////////////////////////////////////////////////////////////////////
+
+//
+// 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+#ifndef CHAININGITERATORS_H
+# define CHAININGITERATORS_H
+
+# include <iostream>
+# include "../view_map/ViewMap.h"
+# include "../view_map/ViewMapIterators.h"
+# include "../view_map/ViewMapAdvancedIterators.h"
+# include "Predicates1D.h"
+
+//using namespace ViewEdgeInternal;
+
+//
+// Adjacency iterator used in the chaining process
+//
+///////////////////////////////////////////////////////////
+class LIB_STROKE_EXPORT AdjacencyIterator{
+protected:
+ ViewVertexInternal::orientedViewEdgeIterator _internalIterator;
+ bool _restrictToSelection;
+ bool _restrictToUnvisited;
+public:
+ AdjacencyIterator(){
+ _restrictToSelection = true;
+ _restrictToUnvisited = true;
+ }
+ AdjacencyIterator(ViewVertex *iVertex, bool iRestrictToSelection = true, bool iRestrictToUnvisited = true){
+ _restrictToSelection = iRestrictToSelection;
+ _restrictToUnvisited = iRestrictToUnvisited;
+ _internalIterator = iVertex->edgesBegin();
+ while((!_internalIterator.isEnd()) && (!isValid((*_internalIterator).first)))
+ ++_internalIterator;
+ }
+ AdjacencyIterator(const AdjacencyIterator& iBrother){
+ _internalIterator = iBrother._internalIterator;
+ _restrictToSelection = iBrother._restrictToSelection;
+ _restrictToUnvisited = iBrother._restrictToUnvisited;
+ }
+ AdjacencyIterator& operator=(const AdjacencyIterator& iBrother) {
+ _internalIterator = iBrother._internalIterator;
+ _restrictToSelection = iBrother._restrictToSelection;
+ _restrictToUnvisited = iBrother._restrictToUnvisited;
+ return *this;
+ }
+ virtual ~AdjacencyIterator(){
+ }
+
+ inline bool isEnd(){
+ return _internalIterator.isEnd();
+ }
+ inline bool isBegin(){
+ return _internalIterator.isBegin();
+ }
+ /*! Returns true if the current ViewEdge is is coming
+ * towards the iteration vertex. False otherwise.
+ */
+ bool isIncoming() const ;
+
+ /*! Returns a *pointer* to the pointed ViewEdge. */
+ virtual ViewEdge* operator*() ;
+ virtual ViewEdge* operator->() {return operator*();}
+ virtual AdjacencyIterator& operator++() {
+ increment();
+ return *this;
+ }
+ virtual AdjacencyIterator operator++(int) {
+ AdjacencyIterator tmp(*this);
+ increment();
+ return tmp;
+ }
+ void increment();
+
+protected:
+ bool isValid(ViewEdge* edge);
+};
+
+//
+// Base class for Chaining Iterators
+//
+///////////////////////////////////////////////////////////
+
+/*! Base class for chaining iterators.
+ * This class is designed to be overloaded
+ * in order to describe chaining rules.
+ * It makes the works of chaining rules description
+ * easier.
+ * The two main methods that need to overloaded are
+ * traverse() and init().
+ * traverse() tells which ViewEdge to follow, among the adjacent ones.
+ * If you specify restriction rules (such as "Chain only
+ * ViewEdges of the selection"), they will be included
+ * in the adjacency iterator. (i.e, the adjacent iterator
+ * will only stop on "valid" edges).
+ */
+class LIB_STROKE_EXPORT ChainingIterator : public ViewEdgeInternal::ViewEdgeIterator{
+protected:
+ bool _restrictToSelection;
+ bool _restrictToUnvisited;
+ bool _increment; //true if we're currently incrementing, false when decrementing
+
+public:
+ /*! Builds a Chaining Iterator from the first ViewEdge used for iteration
+ * and its orientation.
+ * \param iRestrictToSelection
+ * Indicates whether to force the chaining to stay within
+ * the set of selected ViewEdges or not.
+ * \param iRestrictToUnvisited
+ * Indicates whether a ViewEdge that has already been chained
+ * must be ignored ot not.
+ * \param begin
+ * The ViewEdge from which to start the chain.
+ * \param orientation
+ * The direction to follow to explore the graph. If true,
+ * the direction indicated by the first ViewEdge is used.
+ */
+ ChainingIterator(bool iRestrictToSelection = true, bool iRestrictToUnvisited = true, ViewEdge* begin = 0, bool orientation = true)
+ : ViewEdgeIterator(begin, orientation) {
+ _restrictToSelection = iRestrictToSelection;
+ _restrictToUnvisited = iRestrictToUnvisited;
+ _increment = true;
+ }
+
+ /*! Copy constructor */
+ ChainingIterator(const ChainingIterator& brother)
+ : ViewEdgeIterator(brother) {
+ _restrictToSelection = brother._restrictToSelection;
+ _restrictToUnvisited = brother._restrictToUnvisited;
+ _increment = brother._increment;
+ }
+
+ /*! Returns the string "ChainingIterator" */
+ virtual string getExactTypeName() const {
+ return "ChainingIterator";
+ }
+
+ /*! Inits the iterator context.
+ * This method is called each time
+ * a new chain is started.
+ * It can be used to reset some
+ * history information that you
+ * might want to keep.
+ */
+ virtual void init(){}
+
+ /*! This method iterates over the potential next
+ * ViewEdges and returns the one that will be
+ * followed next.
+ * returns the next ViewEdge to follow or
+ * 0 when the end of the chain is reached.
+ * \param it
+ * The iterator over the ViewEdges adjacent to
+ * the end vertex of the current ViewEdge.
+ * The Adjacency iterator reflects the restriction
+ * rules by only iterating over the valid ViewEdges.
+ */
+ virtual ViewEdge * traverse(const AdjacencyIterator &it){
+ cerr << "Warning: the traverse method was not defined" << endl;
+ return 0;
+ }
+
+ /* accessors */
+ /*! Returns true if the orientation of the current ViewEdge
+ * corresponds to its natural orientation
+ */
+ //inline bool getOrientation() const {}
+ /*! Returns the vertex which is the next crossing */
+ inline ViewVertex * getVertex() {
+ if(_increment){
+ if(_orientation){
+ return _edge->B();
+ }else{
+ return _edge->A();
+ }
+ }else{
+ if(_orientation){
+ return _edge->A();
+ }else{
+ return _edge->B();
+ }
+ }
+ }
+
+ /*! Returns true if the current iteration is an incrementation */
+ inline bool isIncrementing() const{
+ return _increment;
+ }
+
+ /* increments.*/
+ virtual void increment() ;
+ virtual void decrement() ;
+};
+
+//
+// Chaining iterators definitions
+//
+///////////////////////////////////////////////////////////
+
+/*! A ViewEdge Iterator used to follow ViewEdges the most naturally.
+ * For example, it will follow visible ViewEdges of same nature.
+ * As soon, as the nature or the visibility changes, the iteration
+ * stops (by setting the pointed ViewEdge to 0).
+ * In the case of an iteration over a set of ViewEdge that are both
+ * Silhouette and Crease, there will be a precedence of the silhouette
+ * over the crease criterion.
+ */
+class LIB_STROKE_EXPORT ChainSilhouetteIterator : public ChainingIterator
+{
+public:
+ /*! Builds a ChainSilhouetteIterator from the first ViewEdge used for iteration
+ * and its orientation.
+ * \param iRestrictToSelection
+ * Indicates whether to force the chaining to stay within
+ * the set of selected ViewEdges or not.
+ * \param begin
+ * The ViewEdge from where to start the iteration.
+ * \param orientation
+ * If true, we'll look for the next ViewEdge among the
+ * ViewEdges that surround the ending ViewVertex of begin.
+ * If false, we'll search over the ViewEdges surrounding
+ * the ending ViewVertex of begin.
+ */
+ ChainSilhouetteIterator(bool iRestrictToSelection = true, ViewEdge* begin = NULL, bool orientation = true)
+ : ChainingIterator(iRestrictToSelection, true, begin, orientation) {}
+
+ /*! Copy constructor */
+ ChainSilhouetteIterator(const ChainSilhouetteIterator& brother)
+ : ChainingIterator(brother) {}
+
+ /*! Returns the string "ChainSilhouetteIterator" */
+ virtual string getExactTypeName() const {
+ return "ChainSilhouetteIterator";
+ }
+
+ /*! This method iterates over the potential next
+ * ViewEdges and returns the one that will be
+ * followed next.
+ * When reaching the end of a chain, 0 is returned.
+ */
+ virtual ViewEdge * traverse(const AdjacencyIterator& it);
+
+};
+
+//
+// ChainPredicateIterator
+//
+///////////////////////////////////////////////////////////
+
+/*! A "generic" user-controlled ViewEdge iterator. This iterator
+ * is in particular built from a unary predicate and a binary predicate.
+ * First, the unary predicate is evaluated for all potential next ViewEdges
+ * in order to only keep the ones respecting a certain constraint.
+ * Then, the binary predicate is evaluated on the current ViewEdge
+ * together with each ViewEdge of the previous selection. The first
+ * ViewEdge respecting both the unary predicate and the binary predicate
+ * is kept as the next one. If none of the potential next ViewEdge respects
+ * these 2 predicates, 0 is returned.
+ */
+class LIB_STROKE_EXPORT ChainPredicateIterator : public ChainingIterator
+{
+protected:
+ BinaryPredicate1D *_binary_predicate; // the caller is responsible for the deletion of this object
+ UnaryPredicate1D *_unary_predicate; // the caller is responsible for the deletion of this object
+public:
+
+ /*! Builds a ChainPredicateIterator from a starting ViewEdge and its orientation.
+ * \param iRestrictToSelection
+ * Indicates whether to force the chaining to stay within
+ * the set of selected ViewEdges or not.
+ * \param iRestrictToUnvisited
+ * Indicates whether a ViewEdge that has already been chained
+ * must be ignored ot not.
+ * \param begin
+ * The ViewEdge from where to start the iteration.
+ * \param orientation
+ * If true, we'll look for the next ViewEdge among the
+ * ViewEdges that surround the ending ViewVertex of begin.
+ * If false, we'll search over the ViewEdges surrounding
+ * the ending ViewVertex of begin.
+ */
+ ChainPredicateIterator(bool iRestrictToSelection = true, bool iRestrictToUnvisited = true, ViewEdge* begin = NULL, bool orientation = true)
+ : ChainingIterator(iRestrictToSelection, iRestrictToUnvisited, begin, orientation) {
+ _binary_predicate = 0;
+ _unary_predicate = 0;
+ }
+
+ /*! Builds a ChainPredicateIterator from a unary predicate, a binary predicate, a starting ViewEdge and its orientation.
+ * \param iRestrictToSelection
+ * Indicates whether to force the chaining to stay within
+ * the set of selected ViewEdges or not.
+ * \param iRestrictToUnvisited
+ * Indicates whether a ViewEdge that has already been chained
+ * must be ignored ot not.
+ * \param upred
+ * The unary predicate that the next ViewEdge must satisfy.
+ * \param bpred
+ * The binary predicate that the next ViewEdge must satisfy
+ * together with the actual pointed ViewEdge.
+ * \param begin
+ * The ViewEdge from where to start the iteration.
+ * \param orientation
+ * If true, we'll look for the next ViewEdge among the
+ * ViewEdges that surround the ending ViewVertex of begin.
+ * If false, we'll search over the ViewEdges surrounding
+ * the ending ViewVertex of begin.
+ */
+ ChainPredicateIterator(UnaryPredicate1D& upred, BinaryPredicate1D& bpred, bool iRestrictToSelection = true, bool iRestrictToUnvisited = true, ViewEdge* begin = NULL, bool orientation = true)
+ : ChainingIterator(iRestrictToSelection, iRestrictToUnvisited, begin, orientation) {
+ _unary_predicate = &upred;
+ _binary_predicate = &bpred;
+ }
+
+ /*! Copy constructor */
+ ChainPredicateIterator(const ChainPredicateIterator& brother)
+ : ChainingIterator(brother){
+ _unary_predicate = brother._unary_predicate;
+ _binary_predicate = brother._binary_predicate;
+ }
+
+ /*! Destructor. */
+ virtual ~ChainPredicateIterator(){
+ _unary_predicate = 0;
+ _binary_predicate = 0;
+ }
+
+ /*! Returns the string "ChainPredicateIterator" */
+ virtual string getExactTypeName() const {
+ return "ChainPredicateIterator";
+ }
+
+ /*! This method iterates over the potential next
+ * ViewEdges and returns the one that will be
+ * followed next.
+ * When reaching the end of a chain, 0 is returned.
+ */
+ virtual ViewEdge * traverse(const AdjacencyIterator &it);
+};
+
+#endif // CHAININGITERATORS_H
diff --git a/source/blender/freestyle/intern/stroke/ContextFunctions.cpp b/source/blender/freestyle/intern/stroke/ContextFunctions.cpp
new file mode 100755
index 00000000000..b55da1fb0f8
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/ContextFunctions.cpp
@@ -0,0 +1,60 @@
+
+//
+// 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 "ContextFunctions.h"
+#include "../view_map/SteerableViewMap.h"
+#include "../system/TimeStamp.h"
+namespace ContextFunctions {
+
+ unsigned GetTimeStampCF(){
+ return TimeStamp::instance()->getTimeStamp();
+ }
+
+ unsigned GetCanvasWidthCF(){
+ return Canvas::getInstance()->width();
+ }
+
+ unsigned GetCanvasHeightCF(){
+ return Canvas::getInstance()->height();
+ }
+ void LoadMapCF(const char *iFileName, const char *iMapName, unsigned iNbLevels, float iSigma ){
+ return Canvas::getInstance()->loadMap(iFileName, iMapName, iNbLevels,iSigma);
+ }
+
+ float ReadMapPixelCF(const char *iMapName, int level, unsigned x, unsigned y){
+ Canvas * canvas = Canvas::getInstance();
+ return canvas->readMapPixel(iMapName, level, x,y);
+ }
+
+ float ReadCompleteViewMapPixelCF(int level, unsigned x, unsigned y){
+ SteerableViewMap *svm = Canvas::getInstance()->getSteerableViewMap();
+ return svm->readCompleteViewMapPixel(level,x,y);
+ }
+
+ float ReadDirectionalViewMapPixelCF(int iOrientation, int level, unsigned x, unsigned y){
+ SteerableViewMap *svm = Canvas::getInstance()->getSteerableViewMap();
+ return svm->readSteerableViewMapPixel(iOrientation, level,x,y);
+ }
+
+ FEdge * GetSelectedFEdgeCF(){
+ return Canvas::getInstance()->selectedFEdge();
+ }
+}
diff --git a/source/blender/freestyle/intern/stroke/ContextFunctions.h b/source/blender/freestyle/intern/stroke/ContextFunctions.h
new file mode 100755
index 00000000000..37c98656fa7
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/ContextFunctions.h
@@ -0,0 +1,124 @@
+//
+// Filename : AdvancedFunctions0D.h
+// Author(s) : Stephane Grabli
+// Purpose : Functions related to context queries
+// Date of creation : 20/12/2003
+//
+///////////////////////////////////////////////////////////////////////////////
+
+
+//
+// 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef CONTEXT_FUNCTIONS_HPP
+# define CONTEXT_FUNCTIONS_HPP
+
+# include "Canvas.h"
+# include "../image/Image.h"
+# include "../image/GaussianFilter.h"
+
+/*! \file ContextFunctions.h
+ * Interface to access the context related
+ * information.
+ */
+//
+// Context Functions definitions
+//
+///////////////////////////////////////////////////////////
+/*! namespace containing all the Context related functions */
+namespace ContextFunctions {
+
+ // GetTimeStamp
+ LIB_STROKE_EXPORT
+ /*! Returns the system time stamp */
+ unsigned GetTimeStampCF();
+
+ // GetCanvasWidth
+ /*! Returns the canvas width */
+ LIB_STROKE_EXPORT
+ unsigned GetCanvasWidthCF();
+
+ // GetCanvasHeight
+ /*! Returns the canvas width */
+ LIB_STROKE_EXPORT
+ unsigned GetCanvasHeightCF();
+
+ // Load map
+ /*! Loads an image map for further reading */
+ LIB_STROKE_EXPORT
+ void LoadMapCF(const char *iFileName, const char *iMapName, unsigned iNbLevels=4, float iSigma=1.f);
+
+ // ReadMapPixel
+ /*! Reads a pixel in a user-defined map
+ * \return the floating value stored for that pixel
+ * \param iMapName
+ * The name of the map
+ * \param level
+ * The level of the pyramid in which we wish to read the pixel
+ * \param x
+ * The x-coordinate of the pixel we wish to read. The origin is
+ * in the lower-left corner.
+ * \param y
+ * The y-coordinate of the pixel we wish to read. The origin is
+ * in the lower-left corner.
+ */
+ LIB_STROKE_EXPORT
+ float ReadMapPixelCF(const char *iMapName, int level, unsigned x, unsigned y);
+
+ // ReadCompleteViewMapPixel
+ /*! Reads a pixel in the complete view map
+ * \return the floating value stored for that pixel
+ * \param level
+ * The level of the pyramid in which we wish to read the pixel
+ * \param x
+ * The x-coordinate of the pixel we wish to read. The origin is
+ * in the lower-left corner.
+ * \param y
+ * The y-coordinate of the pixel we wish to read. The origin is
+ * in the lower-left corner.
+ */
+ LIB_STROKE_EXPORT
+ float ReadCompleteViewMapPixelCF(int level, unsigned x, unsigned y);
+
+ // ReadOrientedViewMapPixel
+ /*! Reads a pixel in one of the oriented view map images
+ * \return the floating value stored for that pixel
+ * \param iOrientation
+ * The number telling which orientation we want to check
+ * \param level
+ * The level of the pyramid in which we wish to read the pixel
+ * \param x
+ * The x-coordinate of the pixel we wish to read. The origin is
+ * in the lower-left corner.
+ * \param y
+ * The y-coordinate of the pixel we wish to read. The origin is
+ * in the lower-left corner.
+ */
+ LIB_STROKE_EXPORT
+ float ReadDirectionalViewMapPixelCF(int iOrientation, int level, unsigned x, unsigned y);
+
+ // DEBUG
+ LIB_STROKE_EXPORT
+ FEdge * GetSelectedFEdgeCF();
+
+} // end of namespace ContextFunctions
+
+#endif // CONTEXT_FUNCTIONS_HPP
+
diff --git a/source/blender/freestyle/intern/stroke/Curve.cpp b/source/blender/freestyle/intern/stroke/Curve.cpp
new file mode 100755
index 00000000000..f7b255c3ef4
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/Curve.cpp
@@ -0,0 +1,818 @@
+
+//
+// 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 "Curve.h"
+#include "CurveIterators.h"
+#include "CurveAdvancedIterators.h"
+
+ /**********************************/
+ /* */
+ /* */
+ /* CurvePoint */
+ /* */
+ /* */
+ /**********************************/
+
+CurvePoint::CurvePoint()
+{
+ __A=0;
+ __B=0;
+ _t2d=0;
+}
+
+CurvePoint::CurvePoint(SVertex *iA, SVertex *iB, float t)
+{
+ __A=iA;
+ __B=iB;
+ _t2d=t;
+ if((iA == 0) && (t == 1.f))
+ {
+ _Point2d=__B->point2d();
+ _Point3d=__B->point3d();
+ }
+ else if((iB == 0) && (t == 0.f))
+ {
+ _Point2d=__A->point2d();
+ _Point3d=__A->point3d();
+ }
+ else
+ {
+ _Point2d=__A->point2d()+_t2d*(__B->point2d()-__A->point2d());
+ _Point3d=__A->point3d()+_t2d*(__B->point3d()-__A->point3d());
+ }
+}
+
+CurvePoint::CurvePoint(CurvePoint *iA, CurvePoint *iB, float t3)
+{
+ float t1=iA->t2d();
+ float t2=iB->t2d();
+ if((iA->A() == iB->A()) && (iA->B() == iB->B()) && (iA->A() != 0) && (iA->B() != 0) && (iB->A() != 0) && (iB->B() != 0))
+ {
+ __A=iA->A();
+ __B=iB->B();
+ _t2d=t1+t2*t3-t1*t3;
+ }
+ else if((iA->B() == 0) && (iB->B() == 0))
+ {
+ __A = iA->A();
+ __B = iB->A();
+ _t2d = t3;
+ }
+ else if((iA->t2d() == 0) && (iB->t2d() == 0))
+ {
+ __A = iA->A();
+ __B = iB->A();
+ _t2d = t3;
+ }
+ else if(iA->A() == iB->A()){
+ if(iA->t2d() == 0){
+ __A = iB->A();
+ __B = iB->B();
+ _t2d = t3;
+ }else if(iB->t2d() == 0){
+ __A = iA->A();
+ __B = iA->B();
+ _t2d = t3;
+ }
+ }else if(iA->B() == iB->B()){
+ if(iA->t2d() == 1){
+ __A = iB->A();
+ __B = iB->B();
+ _t2d = t3;
+ }else if(iB->t2d() == 1){
+ __A = iA->A();
+ __B = iA->B();
+ _t2d = t3;
+ }
+ }
+ else if(iA->B() == iB->A())
+ {
+ if((iA->t2d() != 1.f) && (iB->t2d() == 0.f))
+ {
+ __A = iA->A();
+ __B = iA->B();
+ _t2d=t1+t3-t1*t3;
+ //_t2d = t3;
+ }
+ else if((iA->t2d() == 1.f) && (iB->t2d() != 0.f))
+ {
+ __A = iB->A();
+ __B = iB->B();
+ //_t2d = t3;
+ _t2d=t2*t3;
+ }
+
+ }
+ //_Point2d=__A->point2d()+_t2d*(__B->point2d()-__A->point2d());
+ //_Point3d=__A->point3d()+_t2d*(__B->point3d()-__A->point3d());
+
+ _Point2d= iA->point2d()+t3*(iB->point2d()-iA->point2d());
+ _Point3d=__A->point3d()+_t2d*(__B->point3d()-__A->point3d());
+}
+
+CurvePoint::CurvePoint(const CurvePoint& iBrother)
+{
+ __A=iBrother.__A;
+ __B=iBrother.__B;
+ _t2d=iBrother._t2d;
+ _Point2d=iBrother._Point2d;
+ _Point3d=iBrother._Point3d;
+}
+
+CurvePoint& CurvePoint::operator=(const CurvePoint& iBrother)
+{
+ __A=iBrother.__A;
+ __B=iBrother.__B;
+ _t2d=iBrother._t2d;
+ _Point2d=iBrother._Point2d;
+ _Point3d=iBrother._Point3d;
+ return *this;
+}
+
+
+FEdge *CurvePoint::fedge()
+{
+ if(getNature() & Nature::T_VERTEX)
+ return 0;
+ return __A->fedge();
+}
+
+
+FEdge* CurvePoint::getFEdge(Interface0D& inter)
+{
+ CurvePoint* iVertexB = dynamic_cast<CurvePoint*>(&inter);
+ if (!iVertexB)
+ return 0;
+ if(((__A == iVertexB->__A) && (__B == iVertexB->__B))
+ ||
+ ((__A == iVertexB->__B) && (__B == iVertexB->__A)))
+ return __A->getFEdge(*__B);
+ else if(__B == 0)
+ {
+ if(iVertexB->__B == 0)
+ return __A->getFEdge(*(iVertexB->__A));
+ else if(iVertexB->__A == __A)
+ return __A->getFEdge(*(iVertexB->__B));
+ else if(iVertexB->__B == __A)
+ return __A->getFEdge(*(iVertexB->__A));
+ }
+ else if(iVertexB->__B == 0)
+ {
+ if(iVertexB->__A == __A)
+ return __B->getFEdge(*(iVertexB->__A));
+ else if(iVertexB->__A == __B)
+ return __A->getFEdge(*(iVertexB->__A));
+ }
+ else if(__B == iVertexB->__A)
+ {
+ if((_t2d != 1) && (iVertexB->_t2d == 0))
+ return __A->getFEdge(*__B);
+ if((_t2d == 1) && (iVertexB->_t2d != 0))
+ return iVertexB->__A->getFEdge(*(iVertexB->__B));
+ }
+ else if(__B == iVertexB->__B)
+ {
+ if((_t2d != 1) && (iVertexB->_t2d == 1))
+ return __A->getFEdge(*__B);
+ if((_t2d == 1) && (iVertexB->_t2d != 1))
+ return iVertexB->__A->getFEdge(*(iVertexB->__B));
+ }
+ else if(__A == iVertexB->__A)
+ {
+ if((_t2d == 0) && (iVertexB->_t2d != 0))
+ return iVertexB->__A->getFEdge(*(iVertexB->__B));
+ if((_t2d != 0) && (iVertexB->_t2d == 0))
+ return __A->getFEdge(*__B);
+ }
+ else if(__A == iVertexB->__B)
+ {
+ if((_t2d == 0) && (iVertexB->_t2d != 1))
+ return iVertexB->__A->getFEdge(*(iVertexB->__B));
+ if((_t2d != 0) && (iVertexB->_t2d == 1))
+ return __A->getFEdge(*__B);
+ }
+
+ cerr << "Warning: you should not be there..." << endl;
+
+ return 0;
+}
+
+
+ Vec3r CurvePoint::normal() const
+{
+ if(__B == 0)
+ return __A->normal();
+ if(__A == 0)
+ return __B->normal();
+ Vec3r Na = __A->normal();
+ if(Exception::getException())
+ Na = Vec3r(0,0,0);
+ Vec3r Nb = __B->normal();
+ if(Exception::getException())
+ Nb = Vec3r(0,0,0);
+ // compute t3d:
+ real t3d = SilhouetteGeomEngine::ImageToWorldParameter(__A->getFEdge(*__B),_t2d);
+ return ((1-t3d)*Na+t3d*Nb);
+}
+
+
+ // Material CurvePoint::material() const
+ //{
+ // if(__A == 0)
+ // return __B->material();
+ // return __A->material();
+ //}
+
+
+// Id CurvePoint::shape_id() const
+// {
+// if(__A == 0)
+// return __B->shape_id();
+// return __A->shape_id();
+// }
+
+
+ const SShape * CurvePoint::shape() const
+{
+ if(__A == 0)
+ return __B->shape();
+ return __A->shape();
+}
+
+
+
+// float CurvePoint::shape_importance() const
+// {
+
+// if(__A == 0)
+
+// return __B->shape_importance();
+// return __A->shape_importance();
+// }
+
+
+ // const unsigned CurvePoint::qi() const
+ //{
+ // if(__A == 0)
+ // return __B->qi();
+ // if(__B == 0)
+ // return __A->qi();
+ // return __A->getFEdge(*__B)->qi();
+ //}
+
+
+ occluder_container::const_iterator CurvePoint::occluders_begin() const
+{
+ if(__A == 0)
+ return __B->occluders_begin();
+ if(__B == 0)
+ return __A->occluders_begin();
+ return __A->getFEdge(*__B)->occluders_begin();
+}
+
+ occluder_container::const_iterator CurvePoint::occluders_end() const
+{
+ if(__A == 0)
+ return __B->occluders_end();
+ if(__B == 0)
+ return __A->occluders_end();
+ return __A->getFEdge(*__B)->occluders_end();
+}
+
+ bool CurvePoint::occluders_empty() const
+{
+ if(__A == 0)
+ return __B->occluders_empty();
+ if(__B == 0)
+ return __A->occluders_empty();
+ return __A->getFEdge(*__B)->occluders_empty();
+}
+
+ int CurvePoint::occluders_size() const
+{
+ if(__A == 0)
+ return __B->occluders_size();
+ if(__B == 0)
+ return __A->occluders_size();
+ return __A->getFEdge(*__B)->occluders_size();
+}
+
+ const SShape * CurvePoint::occluded_shape() const
+{
+ if(__A == 0)
+ return __B->occluded_shape();
+ if(__B == 0)
+ return __A->occluded_shape();
+ return __A->getFEdge(*__B)->occluded_shape();
+}
+
+ const Polygon3r& CurvePoint::occludee() const
+{
+ if(__A == 0)
+ return __B->occludee();
+ if(__B == 0)
+ return __A->occludee();
+ return __A->getFEdge(*__B)->occludee();
+}
+
+ const bool CurvePoint::occludee_empty() const
+{
+ if(__A == 0)
+ return __B->occludee_empty();
+ if(__B == 0)
+ return __A->occludee_empty();
+ return __A->getFEdge(*__B)->occludee_empty();
+}
+
+ real CurvePoint::z_discontinuity() const
+{
+ if(__A == 0)
+ return __B->z_discontinuity();
+ if(__B == 0)
+ return __A->z_discontinuity();
+ if(__A->getFEdge(*__B) == 0)
+ return 0.0;
+
+ return __A->getFEdge(*__B)->z_discontinuity();
+}
+//
+// float CurvePoint::local_average_depth() const
+//{
+// return local_average_depth_function<CurvePoint >(this);
+//}
+//
+// float CurvePoint::local_depth_variance() const
+//{
+// return local_depth_variance_function<CurvePoint >(this);
+//}
+//
+// real CurvePoint::local_average_density(float sigma) const
+//{
+// //return local_average_density<CurvePoint >(this);
+//
+// return density_function<CurvePoint >(this);
+//}
+// Vec3r shaded_color() const ;
+//
+// Vec3r CurvePoint::orientation2d() const
+// {
+// if(__A == 0)
+// return __B->orientation2d();
+// if(__B == 0)
+// return __A->orientation2d();
+// return __B->point2d()-__A->point2d();
+// }
+//
+// Vec3r CurvePoint::orientation3d() const
+// {
+// if(__A == 0)
+// return __B->orientation3d();
+// if(__B == 0)
+// return __A->orientation3d();
+// return __B->point3d()-__A->point3d();
+// }
+
+// real curvature2d() const {return viewedge()->curvature2d((_VertexA->point2d()+_VertexB->point2d())/2.0);}
+//
+// Vec3r CurvePoint::curvature2d_as_vector() const
+//{
+// // Vec3r edgeA = (_FEdges[0])->orientation2d().normalize();
+// // Vec3r edgeB = (_FEdges[1])->orientation2d().normalize();
+// // return edgeA+edgeB;
+// //
+// if(__A == 0)
+// return __B->curvature2d_as_vector();
+// if(__B == 0)
+// return __A->curvature2d_as_vector();
+// return ((1-_t2d)*__A->curvature2d_as_vector()+_t2d*__B->curvature2d_as_vector());
+//}
+//
+// real CurvePoint::curvature2d_as_angle() const
+//{
+// // Vec3r edgeA = (_FEdges[0])->orientation2d();
+// // Vec3r edgeB = (_FEdges[1])->orientation2d();
+// // Vec2d N1(-edgeA.y(), edgeA.x());N1.normalize();
+// // Vec2d N2(-edgeB.y(), edgeB.x());N2.normalize();
+// // return acos((N1*N2));
+//
+// if(__A == 0)
+// return __B->curvature2d_as_angle();
+// if(__B == 0)
+// return __A->curvature2d_as_angle();
+// return ((1-_t2d)*__A->curvature2d_as_angle()+_t2d*__B->curvature2d_as_angle());
+//}
+
+
+real CurvePoint::curvatureFredo() const
+{
+ if(__A == 0)
+ return __B->curvatureFredo();
+ if(__B == 0)
+ return __A->curvatureFredo();
+ return ((1-_t2d)*__A->curvatureFredo()+_t2d*__B->curvatureFredo());
+}
+
+Vec2d CurvePoint::directionFredo () const
+{
+ if(__A == 0)
+ return __B->directionFredo();
+ if(__B == 0)
+ return __A->directionFredo();
+ return ((1-_t2d)*__A->directionFredo()+_t2d*__B->directionFredo());
+}
+
+ /**********************************/
+ /* */
+ /* */
+ /* Curve */
+ /* */
+ /* */
+ /**********************************/
+
+/* for functions */
+
+
+Curve::~Curve()
+{
+ if(!_Vertices.empty())
+ {
+ for(vertex_container::iterator it=_Vertices.begin(), itend =_Vertices.end();
+ it!=itend;
+ ++it)
+ {
+ delete (*it);
+ }
+ _Vertices.clear();
+ }
+}
+
+/*! iterators access */
+Curve::point_iterator Curve::points_begin(float step)
+{
+ vertex_container::iterator second = _Vertices.begin();++second;
+ return point_iterator(_Vertices.begin(), second, _Vertices.begin(), _Vertices.end(), _nSegments, step, 0.f, 0.f);
+ //return point_iterator(_Vertices.begin(), second, _nSegments, step, 0.f, 0.f);
+}
+Curve::const_point_iterator Curve::points_begin(float step) const
+{
+ vertex_container::const_iterator second = _Vertices.begin();++second;
+ return const_point_iterator(_Vertices.begin(), second, _Vertices.begin(), _Vertices.end(), _nSegments, step, 0.f, 0.f);
+ //return const_point_iterator(_Vertices.begin(), second, _nSegments, step, 0.f, 0.f);
+}
+Curve::point_iterator Curve::points_end(float step)
+{
+ return point_iterator(_Vertices.end(), _Vertices.end(), _Vertices.begin(), _Vertices.end(), _nSegments, step, 1.f, _Length);
+ //return point_iterator(_Vertices.end(), _Vertices.end(), _nSegments, step, 1.f, _Length);
+}
+Curve::const_point_iterator Curve::points_end(float step) const
+{
+ return const_point_iterator(_Vertices.end(), _Vertices.end(), _Vertices.begin(), _Vertices.end(), _nSegments, step, 1.f, _Length);
+ //return const_point_iterator(_Vertices.end(), _Vertices.end(), _nSegments, step, 1.f, _Length);
+}
+
+// Adavnced Iterators access
+Curve::point_iterator Curve::vertices_begin(){return points_begin(0);}
+Curve::const_point_iterator Curve::vertices_begin() const {return points_begin(0);}
+Curve::point_iterator Curve::vertices_end(){return points_end(0);}
+Curve::const_point_iterator Curve::vertices_end() const {return points_end(0);}
+
+// specialized iterators access
+CurveInternal::CurvePointIterator Curve::curvePointsBegin(float t){
+ vertex_container::iterator second = _Vertices.begin();++second;
+ return CurveInternal::CurvePointIterator(_Vertices.begin(), second, _Vertices.begin(), _Vertices.end(), 0, _nSegments, _Length, t, 0.f, 0.f);
+}
+
+CurveInternal::CurvePointIterator Curve::curvePointsEnd(float t){
+ vertex_container::iterator last = _Vertices.end();--last;
+ return CurveInternal::CurvePointIterator(last, _Vertices.end(), _Vertices.begin(), _Vertices.end(), _nSegments, _nSegments, _Length, t, 0.f, _Length);
+}
+
+CurveInternal::CurvePointIterator Curve::curveVerticesBegin(){
+ return curvePointsBegin(0);
+}
+
+CurveInternal::CurvePointIterator Curve::curveVerticesEnd(){
+ return curvePointsEnd(0);
+}
+
+Interface0DIterator Curve::pointsBegin(float t){
+ vertex_container::iterator second = _Vertices.begin();++second;
+ Interface0DIterator ret(new CurveInternal::CurvePointIterator(_Vertices.begin(), second, _Vertices.begin(), _Vertices.end(), 0, _nSegments, _Length, t, 0.f, 0.f));
+ return ret;
+}
+
+Interface0DIterator Curve::pointsEnd(float t){
+ vertex_container::iterator last = _Vertices.end();--last;
+ Interface0DIterator ret(new CurveInternal::CurvePointIterator(last, _Vertices.end(), _Vertices.begin(), _Vertices.end(), _nSegments, _nSegments, _Length, t, 0.f, _Length));
+ return ret;
+}
+
+Interface0DIterator Curve::verticesBegin(){
+ return pointsBegin(0);
+}
+
+Interface0DIterator Curve::verticesEnd(){
+ return pointsEnd(0);
+}
+
+
+// Vec3r shaded_color(int iCombination = 0) const ;
+//
+// Vec3r Curve::orientation2d(point_iterator it) const
+//{
+// return (*it)->orientation2d();
+//}
+/* template <class BaseVertex> */
+/* Vec3r Curve::orientation2d(int iCombination) const */
+/* { */
+/* return edge_orientation2d_function<Curve >(this, iCombination); */
+/* } */
+//
+// Vec3r Curve::orientation3d(point_iterator it) const
+//{
+// return (*it)->orientation3d();
+//}
+/* */
+/* Vec3r Curve::orientation3d(int iCombination) const */
+/* { */
+/* return edge_orientation3d_function<Curve >(this, iCombination); */
+/* } */
+// real curvature2d(point_iterator it) const {return (*it)->curvature2d();}
+// real curvature2d(int iCombination = 0) const ;
+
+// Material Curve::material() const
+//{
+// const_vertex_iterator v=vertices_begin(), vend=vertices_end();
+// const Material& mat = (*v)->material();
+// for(;v!=vend;++v)
+// {
+// if((*v)->material() != mat)
+// Exception::raiseException();
+// }
+// return mat;
+//}
+
+// int Curve::qi() const
+//{
+// const_vertex_iterator v=vertices_begin(), vend=vertices_end();
+// int qi_= (*v)->qi();
+// for(;v!=vend;++v)
+// {
+// if((*v)->qi() != qi_)
+// Exception::raiseException();
+// }
+// return qi_;
+//}
+// occluder_container::const_iterator occluders_begin() const {return _FEdgeA->occluders().begin();}
+// occluder_container::const_iterator occluders_end() const {return _FEdgeA->occluders().end();}
+
+//int Curve::occluders_size() const
+//{
+// return qi();
+//}
+
+// bool Curve::occluders_empty() const
+//{
+// const_vertex_iterator v=vertices_begin(), vend=vertices_end();
+// bool empty = (*v)->occluders_empty();
+// for(;v!=vend;++v)
+// {
+// if((*v)->occluders_empty() != empty)
+// Exception::raiseException();
+// }
+// return empty;
+//}
+// const Polygon3r& occludee() const {return *(_FEdgeA->aFace());}
+
+// const SShape * Curve::occluded_shape() const
+//{
+// const_vertex_iterator v=vertices_begin(), vend=vertices_end();
+// const SShape *sshape = (*v)->occluded_shape();
+// for(;v!=vend;++v)
+// {
+// if((*v)->occluded_shape() != sshape)
+// Exception::raiseException();
+// }
+// return sshape;
+//}
+
+
+// const bool Curve::occludee_empty() const
+//{
+// const_vertex_iterator v=vertices_begin(), vend=vertices_end();
+// bool empty = (*v)->occludee_empty();
+// for(;v!=vend;++v)
+// {
+// if((*v)->occludee_empty() != empty)
+// Exception::raiseException();
+// }
+// return empty;
+//}
+/* */
+/* real Curve::z_discontinuity(int iCombination) const */
+/* { */
+/* return z_discontinuity_edge_function<Curve >(this, iCombination); */
+/* } */
+
+// int Curve::shape_id() const
+// {
+// const_vertex_iterator v=vertices_begin(), vend=vertices_end();
+// Id id = (*v)->shape_id();
+// for(;v!=vend;++v)
+// {
+// if((*v)->shape_id() != id)
+// Exception::raiseException();
+// }
+// return id.first;
+// }
+
+
+// const SShape * Curve::shape() const
+//{
+// const_vertex_iterator v=vertices_begin(), vend=vertices_end();
+// const SShape *sshape = (*v)->shape();
+// for(;v!=vend;++v)
+// {
+// if((*v)->shape() != sshape)
+// Exception::raiseException();
+// }
+// return sshape;
+//}
+
+
+// occluder_container::const_iterator Curve::occluders_begin() const
+//{
+// const_vertex_iterator v=vertices_begin();
+// return (*v)->occluders_begin();
+//}
+//
+//
+// occluder_container::const_iterator Curve::occluders_end() const
+//{
+// const_vertex_iterator v=vertices_end();
+// return (*v)->occluders_end();
+//}
+
+/* */
+/* Vec3r Curve::curvature2d_as_vector(int iCombination) const */
+/* { */
+/* return curvature2d_as_vector_edge_function<Curve >(this, iCombination); */
+/* } */
+/* */
+/* real Curve::curvature2d_as_angle(int iCombination) const */
+/* { */
+/* return curvature2d_as_angle_edge_function<Curve >(this, iCombination); */
+/* } */
+
+/* */
+/* float Curve::shape_importance(int iCombination) const */
+/* { */
+/* return shape_importance_edge_function<Curve >(this, iCombination); */
+/* } */
+
+/* */
+/* float Curve::local_average_depth(int iCombination) const */
+/* { */
+/* return local_average_depth_edge_function<Curve >(this, iCombination); */
+/* } */
+/* */
+/* float Curve::local_depth_variance(int iCombination ) const */
+/* { */
+/* return local_depth_variance_edge_function<Curve >(this, iCombination); */
+/* // local_depth_variance_functor<Point> functor; */
+/* // float result; */
+/* // Evaluate<float, local_depth_variance_functor<Point> >(&functor, iCombination, result); */
+/* // return result; */
+/* } */
+
+/* */
+/* real Curve::local_average_density(float sigma, int iCombination ) const */
+/* { */
+/* return density_edge_function<Curve >(this, iCombination); */
+/* // density_functor<Point> functor; */
+/* // real result; */
+/* // Evaluate<real, density_functor<Point> >(&functor, iCombination, result); */
+/* // return result; */
+/* } */
+
+#define EPS_CURVA_DIR 0.01
+
+
+void Curve::computeCurvatureAndOrientation ()
+{
+// const_vertex_iterator v=vertices_begin(), vend=vertices_end(), v2, prevV, v0;
+// Vec2d p0, p1, p2;
+// Vec3r p;
+
+// p=(*v)->point2d();
+// p0=Vec2d(p[0], p[1]);
+// prevV=v; ++v;
+// p=(*v)->point2d();
+// p1=Vec2d(p[0], p[1]);
+// Vec2d prevDir(p1-p0);
+
+// for(;v!=vend;++v)
+// {
+// v2=v; ++v2;
+// if (v2==vend) break;
+// Vec3r p2=(*v2)->point2d();
+
+// Vec2d BA=p0-p1;
+// Vec2d BC=p2-p1;
+// real lba=BA.norm(), lbc=BC.norm();
+// BA.normalizeSafe();
+// BC.normalizeSafe();
+// Vec2d normalCurvature=BA+BC;
+// Vec2d dir=Vec2d(BC-BA);
+// Vec2d normal=Vec2d(-dir[1], dir[0]);
+
+// normal.normalizeSafe();
+// real curvature=normalCurvature*normal;
+// if (lba+lbc > MY_EPSILON)
+// curvature/=(0.5*lba+lbc);
+// if (dir.norm() < MY_EPSILON)
+// dir=0.1*prevDir;
+// (*v)->setCurvatureFredo(curvature);
+// (*v)->setDirectionFredo(dir);
+
+// prevV=v; p0=p1; p1=p2; prevDir=dir; prevDir.normalize();
+// }
+// (*v)->setCurvatureFredo((*prevV)->curvatureFredo());
+// (*v)->setDirectionFredo((*v)->point2d()-(*prevV)->point2d());
+// v0=vertices_begin(); v2=v0; ++v2;
+// (*v0)->setCurvatureFredo((*v2)->curvatureFredo());
+// (*v0)->setDirectionFredo((*v2)->point2d()-(*v0)->point2d());
+
+// //closed curve case one day...
+
+// //
+// return;
+
+// //numerical degeneracy verification.. we'll see later
+// const_vertex_iterator vLastReliable=vertices_begin();
+
+// v=vertices_begin();
+// p=(*v)->point2d();
+// p0=Vec2d(p[0], p[1]);
+// prevV=v; ++v;
+// p=(*v)->point2d();
+// p1=Vec2d(p[0], p[1]);
+// bool isReliable=false;
+// if ((p1-p0).norm>EPS_CURVA)
+// {
+// vLastReliable=v;
+// isReliable=true;
+// }
+
+// for(;v!=vend;++v)
+// {
+// v2=v; ++v2;
+// if (v2==vend) break;
+// Vec3r p2=(*v2)->point2d();
+
+// Vec2d BA=p0-p1;
+// Vec2d BC=p2-p1;
+// real lba=BA.norm(), lbc=BC.norm();
+
+// if ((lba+lbc)<EPS_CURVA)
+// {
+// isReliable=false;
+// cerr<<"/";
+// }
+// else
+// {
+// if (!isReliable)//previous points were not reliable
+// {
+// const_vertex_iterator vfix=vLastReliable;
+// vfix++;
+// for (; vfix!=v; ++vfix)
+// {
+// (*vfix)->setCurvatureFredo((*v)->curvatureFredo());
+// (*vfix)->setDirectionFredo((*v)->directionFredo());
+// }
+// }
+// isReliable=true;
+// vLastReliable=v;
+// }
+// prevV=v; p0=p1; p1=p2;
+// }
+
+}
diff --git a/source/blender/freestyle/intern/stroke/Curve.h b/source/blender/freestyle/intern/stroke/Curve.h
new file mode 100755
index 00000000000..400f27e5d5a
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/Curve.h
@@ -0,0 +1,463 @@
+//
+// Filename : Curve.h
+// Author(s) : Stephane Grabli
+// Purpose : Class to define a container for curves
+// Date of creation : 11/01/2003
+//
+///////////////////////////////////////////////////////////////////////////////
+
+
+//
+// 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef CURVE_H
+# define CURVE_H
+
+# include <deque>
+# include "../system/BaseIterator.h"
+# include "../geometry/Geom.h"
+//# include "../scene_graph/Material.h"
+# include "../view_map/Silhouette.h"
+# include "../view_map/SilhouetteGeomEngine.h"
+# include "../view_map/Interface0D.h"
+# include "../view_map/Interface1D.h"
+
+using namespace std;
+using namespace Geometry;
+
+ /**********************************/
+ /* */
+ /* */
+ /* CurvePoint */
+ /* */
+ /* */
+ /**********************************/
+
+/*! Class to represent a point of a curve.
+ * A CurvePoint can be any point of a 1D curve
+ * (it doesn't have to be a vertex of the curve).
+ * Any Interface1D is built upon ViewEdges, themselves
+ * built upon FEdges. Therefore, a curve is basically
+ * a polyline made of a list SVertex.
+ * Thus, a CurvePoint is built by lineraly interpolating
+ * two SVertex.
+ * CurvePoint can be used as virtual points while
+ * querying 0D information along a curve at a given resolution.
+ */
+class LIB_STROKE_EXPORT CurvePoint : public Interface0D
+{
+public: // Implementation of Interface0D
+ /*! Returns the string "CurvePoint"*/
+ virtual string getExactTypeName() const {
+ return "CurvePoint";
+ }
+
+ // Data access methods
+ /*! Returns the 3D X coordinate of the point */
+ virtual real getX() const {
+ return _Point3d.x();
+ }
+ /*! Returns the 3D Y coordinate of the point */
+ virtual real getY() const {
+ return _Point3d.y();
+ }
+ /*! Returns the 3D Z coordinate of the point */
+ virtual real getZ() const {
+ return _Point3d.z();
+ }
+ /*! Returns the 3D point. */
+ virtual Vec3f getPoint3D() const {
+ return _Point3d;
+ }
+ /*! Returns the projected 3D X coordinate of the point */
+ virtual real getProjectedX() const {
+ return _Point2d.x();
+ }
+ /*! Returns the projected 3D Y coordinate of the point */
+ virtual real getProjectedY() const {
+ return _Point2d.y();
+ }
+ /*! Returns the projected 3D Z coordinate of the point */
+ virtual real getProjectedZ() const {
+ return _Point2d.z();
+ }
+ /*! Returns the 2D point. */
+ virtual Vec2f getPoint2D() const {
+ return Vec2f((float)_Point2d.x(),(float)_Point2d.y());
+ }
+
+ virtual FEdge* getFEdge(Interface0D& inter);
+ /*! Returns the CurvePoint's Id */
+ virtual Id getId() const {
+ Id id;
+ if(_t2d == 0)
+ return __A->getId();
+ else if(_t2d == 1)
+ return __B->getId();
+ return id;
+ }
+ /*! Returns the CurvePoint's Nature */
+ virtual Nature::VertexNature getNature() const {
+ Nature::VertexNature nature = Nature::POINT;
+ if(_t2d == 0)
+ nature |= __A->getNature();
+ else if(_t2d == 1)
+ nature |= __B->getNature();
+ return nature;
+ }
+
+ /*! Cast the Interface0D in SVertex if it can be. */
+ virtual SVertex * castToSVertex(){
+ if(_t2d == 0)
+ return __A;
+ else if(_t2d == 1)
+ return __B;
+ return Interface0D::castToSVertex();
+ }
+
+ /*! Cast the Interface0D in ViewVertex if it can be. */
+ virtual ViewVertex * castToViewVertex(){
+ if(_t2d == 0)
+ return __A->castToViewVertex();
+ else if(_t2d == 1)
+ return __B->castToViewVertex();
+ return Interface0D::castToViewVertex();
+ }
+
+ /*! Cast the Interface0D in NonTVertex if it can be. */
+ virtual NonTVertex * castToNonTVertex(){
+ if(_t2d == 0)
+ return __A->castToNonTVertex();
+ else if(_t2d == 1)
+ return __B->castToNonTVertex();
+ return Interface0D::castToNonTVertex();
+ }
+
+ /*! Cast the Interface0D in TVertex if it can be. */
+ virtual TVertex * castToTVertex(){
+ if(_t2d == 0)
+ return __A->castToTVertex();
+ else if(_t2d == 1)
+ return __B->castToTVertex();
+ return Interface0D::castToTVertex();
+ }
+public:
+ typedef SVertex vertex_type;
+protected:
+ SVertex *__A;
+ SVertex *__B;
+ float _t2d;
+ //float _t3d;
+ Vec3r _Point2d;
+ Vec3r _Point3d;
+public:
+ /*! Defult Constructor. */
+ CurvePoint();
+ /*! Builds a CurvePoint from two SVertex and an interpolation
+ * parameter.
+ * \param iA
+ * The first SVertex
+ * \param iB
+ * The second SVertex
+ * \param t2d
+ * A 2D interpolation parameter
+ * used to linearly interpolate \a iA and \a iB
+ */
+ CurvePoint(SVertex *iA, SVertex *iB, float t2d) ;
+ /*! Builds a CurvePoint from two CurvePoint and an interpolation parameter.
+ * \param iA
+ * The first CurvePoint
+ * \param iB
+ * The second CurvePoint
+ * \param t2d
+ * The 2D interpolation parameter used
+ * to linearly interpolate \a iA and \a iB.
+ */
+ CurvePoint(CurvePoint *iA, CurvePoint *iB, float t2d) ;
+ // CurvePoint(SVertex *iA, SVertex *iB, float t2d, float t3d) ;
+ /*! Copy Constructor. */
+ CurvePoint(const CurvePoint& iBrother) ;
+ /*! Operator = */
+ CurvePoint& operator=(const CurvePoint& iBrother) ;
+ /*! Destructor */
+ virtual ~CurvePoint() {}
+ /*! Operator == */
+ bool operator==(const CurvePoint& b){
+ return ((__A==b.__A) && (__B==b.__B) && (_t2d==b._t2d));
+ }
+
+ /* accessors */
+ /*! Returns the first SVertex upon which
+ * the CurvePoint is built. */
+ inline SVertex * A() {return __A;}
+ /*! Returns the second SVertex upon which
+ * the CurvePoint is built. */
+ inline SVertex * B() {return __B;}
+ /*! Returns the interpolation parameter. */
+ inline float t2d() const {return _t2d;}
+ //inline const float t3d() const {return _t3d;}
+
+ /* modifiers */
+ /*! Sets the first SVertex upon which to build
+ * the CurvePoint.
+ */
+ inline void SetA(SVertex *iA) {__A = iA;}
+ /*! Sets the second SVertex upon which to build
+ * the CurvePoint.
+ */
+ inline void SetB(SVertex *iB) {__B = iB;}
+ /*! Sets the 2D interpolation parameter to use.
+ */
+ inline void SetT2d(float t) {_t2d = t;}
+ //inline void SetT3d(float t) {_t3d = t;}
+
+ /* Information access interface */
+
+ FEdge *fedge() ;
+ inline const Vec3r& point2d() const {return _Point2d;}
+ inline const Vec3r& point3d() const {return _Point3d;}
+ Vec3r normal() const ;
+ //Material material() const ;
+ // Id shape_id() const ;
+ const SShape * shape() const ;
+ // float shape_importance() const ;
+
+ //const unsigned qi() const ;
+ occluder_container::const_iterator occluders_begin() const ;
+ occluder_container::const_iterator occluders_end() const ;
+ bool occluders_empty() const ;
+ int occluders_size() const ;
+ const Polygon3r& occludee() const ;
+ const SShape * occluded_shape() const ;
+ const bool occludee_empty() const ;
+ real z_discontinuity() const ;
+ // float local_average_depth() const ;
+ // float local_depth_variance() const ;
+ // real local_average_density(float sigma = 2.3f) const ;
+ // Vec3r shaded_color() const ;
+// Vec3r orientation2d() const ;
+// Vec3r orientation3d() const ;
+ // // real curvature2d() const {return viewedge()->curvature2d((_VertexA->point2d()+_VertexB->point2d())/2.0);}
+ // Vec3r curvature2d_as_vector() const ;
+ // /*! angle in radians */
+ // real curvature2d_as_angle() const ;
+
+ real curvatureFredo () const;
+ Vec2d directionFredo () const;
+};
+
+
+ /**********************************/
+ /* */
+ /* */
+ /* Curve */
+ /* */
+ /* */
+ /**********************************/
+
+namespace CurveInternal {
+ class CurvePoint_const_traits;
+ class CurvePoint_nonconst_traits;
+ template<class Traits> class __point_iterator;
+ class CurvePointIterator;
+} // end of namespace CurveInternal
+
+/*! Base class for curves made of CurvePoints.
+ * SVertex is the type of the initial curve vertices.
+ * A Chain is a specialization of a Curve.
+ */
+class LIB_STROKE_EXPORT Curve : public Interface1D
+{
+public:
+ typedef CurvePoint Vertex;
+ typedef CurvePoint Point;
+ typedef Point point_type;
+ typedef Vertex vertex_type;
+ typedef deque<Vertex*> vertex_container;
+
+ /* Iterator to iterate over a vertex edges */
+
+ typedef CurveInternal::__point_iterator<CurveInternal::CurvePoint_nonconst_traits > point_iterator;
+ typedef CurveInternal::__point_iterator<CurveInternal::CurvePoint_const_traits > const_point_iterator;
+ typedef point_iterator vertex_iterator ;
+ typedef const_point_iterator const_vertex_iterator ;
+
+protected:
+ vertex_container _Vertices;
+ double _Length;
+ Id _Id;
+ unsigned _nSegments; // number of segments
+
+public:
+ /*! Default Constructor. */
+ Curve() {_Length = 0;_Id = 0;_nSegments=0;}
+ /*! Builds a Curve from its id */
+ Curve(const Id& id) {_Length = 0;_Id = id;_nSegments=0;}
+ /*! Copy Constructor. */
+ Curve(const Curve& iBrother) {_Length = iBrother._Length;_Vertices = iBrother._Vertices;_Id=iBrother._Id;_nSegments=0;}
+ /*! Destructor. */
+ virtual ~Curve() ;
+
+ /*
+ fredo's curvature storage
+ */
+ void computeCurvatureAndOrientation ();
+
+ /*! Adds a single vertex (CurvePoint) at the end of the Curve */
+ inline void push_vertex_back(Vertex *iVertex)
+ {
+ if(!_Vertices.empty())
+ {
+ Vec3r vec_tmp(iVertex->point2d() - _Vertices.back()->point2d());
+ _Length += vec_tmp.norm();
+ ++_nSegments;
+ }
+ Vertex * new_vertex = new Vertex(*iVertex);
+ _Vertices.push_back(new_vertex);
+ }
+ /*! Adds a single vertex (SVertex) at the end of the Curve */
+ inline void push_vertex_back(SVertex *iVertex)
+ {
+ if(!_Vertices.empty())
+ {
+ Vec3r vec_tmp(iVertex->point2d() - _Vertices.back()->point2d());
+ _Length += vec_tmp.norm();
+ ++_nSegments;
+ }
+ Vertex *new_vertex = new Vertex(iVertex, 0,0);
+ _Vertices.push_back(new_vertex);
+ }
+ /*! Adds a single vertex (CurvePoint) at the front of the Curve */
+ inline void push_vertex_front(Vertex *iVertex)
+ {
+ if(!_Vertices.empty())
+ {
+ Vec3r vec_tmp(iVertex->point2d() - _Vertices.front()->point2d());
+ _Length += vec_tmp.norm();
+ ++_nSegments;
+ }
+ Vertex * new_vertex = new Vertex(*iVertex);
+ _Vertices.push_front(new_vertex);
+ }
+ /*! Adds a single vertex (SVertex) at the front of the Curve */
+ inline void push_vertex_front(SVertex *iVertex)
+ {
+ if(!_Vertices.empty())
+ {
+ Vec3r vec_tmp(iVertex->point2d() - _Vertices.front()->point2d());
+ _Length += vec_tmp.norm();
+ ++_nSegments;
+ }
+ Vertex *new_vertex = new Vertex(iVertex, 0,0);
+ _Vertices.push_front(new_vertex);
+ }
+ /*! Returns true is the Curve doesn't have any Vertex yet. */
+ inline bool empty() const {return _Vertices.empty();}
+ /*! Returns the 2D length of the Curve.*/
+ inline real getLength2D() const {return _Length;}
+ /*! Returns the Id of the 1D element .*/
+ virtual Id getId() const {
+ return _Id;
+ }
+ /*! Returns the number of segments in the
+ * oplyline constituing the Curve.
+ */
+ inline unsigned int nSegments() const {return _nSegments;}
+
+ inline void setId(const Id& id){_Id = id;}
+ /* Information access interface */
+
+
+ //inline Vec3r shaded_color(int iCombination = 0) const ;
+ // inline Vec3r orientation2d(point_iterator it) const ;
+ //Vec3r orientation2d(int iCombination = 0) const ;
+ // Vec3r orientation3d(point_iterator it) const ;
+ //Vec3r orientation3d(int iCombination = 0) const ;
+ // real curvature2d(point_iterator it) const {return (*it)->curvature2d();}
+ // real curvature2d(int iCombination = 0) const ;
+ //Material material() const ;
+ //int qi() const ;
+ // occluder_container::const_iterator occluders_begin() const ;
+ // occluder_container::const_iterator occluders_end() const ;
+ //int occluders_size() const;
+ //bool occluders_empty() const ;
+ // const Polygon3r& occludee() const {return *(_FEdgeA->aFace());}
+ //const SShape * occluded_shape() const;
+ //const bool occludee_empty() const ;
+ //real z_discontinuity(int iCombination = 0) const ;
+ // int shape_id() const ;
+ //const SShape * shape() const ;
+ //float shape_importance(int iCombination=0) const ;
+ //float local_average_depth(int iCombination = 0) const;
+ //float local_depth_variance(int iCombination = 0) const ;
+ //real local_average_density(float sigma = 2.3f, int iCombination = 0) const ;
+ //Vec3r curvature2d_as_vector(int iCombination=0) const ;
+ /*! angle in radians */
+ //real curvature2d_as_angle(int iCombination=0) const ;
+
+ /* advanced iterators access */
+ point_iterator points_begin(float step = 0);
+ const_point_iterator points_begin(float step = 0) const;
+ point_iterator points_end(float step = 0);
+ const_point_iterator points_end(float step = 0) const;
+
+ // methods given for convenience */
+ point_iterator vertices_begin();
+ const_point_iterator vertices_begin() const;
+ point_iterator vertices_end();
+ const_point_iterator vertices_end() const;
+
+ // specialized iterators access
+ CurveInternal::CurvePointIterator curvePointsBegin(float t=0.f);
+ CurveInternal::CurvePointIterator curvePointsEnd(float t=0.f);
+
+ CurveInternal::CurvePointIterator curveVerticesBegin();
+ CurveInternal::CurvePointIterator curveVerticesEnd();
+
+ // Iterators access
+ /*! Returns an Interface0DIterator pointing onto
+ * the first vertex of the Curve and that can iterate
+ * over the \a vertices of the Curve.
+ */
+ virtual Interface0DIterator verticesBegin();
+ /*! Returns an Interface0DIterator pointing after
+ * the last vertex of the Curve and that can iterate
+ * over the \a vertices of the Curve.
+ */
+ virtual Interface0DIterator verticesEnd();
+ /*! Returns an Interface0DIterator pointing onto
+ * the first point of the Curve and that can iterate
+ * over the \a points of the Curve at any resolution.
+ * At each iteration a virtual temporary CurvePoint
+ * is created.
+ */
+ virtual Interface0DIterator pointsBegin(float t=0.f);
+ /*! Returns an Interface0DIterator pointing after
+ * the last point of the Curve and that can iterate
+ * over the \a points of the Curve at any resolution.
+ * At each iteration a virtual temporary CurvePoint
+ * is created.
+ */
+ virtual Interface0DIterator pointsEnd(float t=0.f);
+};
+
+
+
+#endif
diff --git a/source/blender/freestyle/intern/stroke/CurveAdvancedIterators.h b/source/blender/freestyle/intern/stroke/CurveAdvancedIterators.h
new file mode 100755
index 00000000000..dfc9f2719f8
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/CurveAdvancedIterators.h
@@ -0,0 +1,378 @@
+//
+// Filename : CurveAdvancedIterators.h
+// Author(s) : Stephane Grabli
+// Purpose : Iterators used to iterate over the elements of the Curve
+// Can't be used in python
+// Date of creation : 01/08/2003
+//
+///////////////////////////////////////////////////////////////////////////////
+
+
+//
+// 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef ADVANCEDCURVEITERATORS_H
+# define ADVANCEDCURVEITERATORS_H
+
+# include "Stroke.h"
+
+namespace CurveInternal {
+
+ class CurvePoint_const_traits : public Const_traits<CurvePoint*> {
+ public:
+ typedef deque<CurvePoint*> vertex_container;
+ typedef vertex_container::const_iterator vertex_container_iterator;
+ typedef SVertex vertex_type;
+ };
+
+ class CurvePoint_nonconst_traits : public Nonconst_traits<CurvePoint*> {
+ public:
+ typedef deque<CurvePoint*> vertex_container;
+ typedef vertex_container::iterator vertex_container_iterator ;
+ typedef SVertex vertex_type;
+ };
+
+ /**********************************/
+ /* */
+ /* */
+ /* CurvePoint Iterator */
+ /* */
+ /* */
+ /**********************************/
+
+
+ /*! iterator on a curve. Allows an iterating outside
+ * initial vertices. A CurvePoint is instanciated an returned
+ * when the iterator is dereferenced.
+ */
+
+ template<class Traits>
+ class __point_iterator : public IteratorBase<Traits, BidirectionalIteratorTag_Traits>
+ {
+ public:
+ typedef __point_iterator <Traits> Self;
+ typedef typename Traits::vertex_container_iterator vertex_container_iterator;
+ typedef typename Traits::vertex_type vertex_type;
+ typedef CurvePoint Point;
+ typedef Point point_type;
+
+ typedef __point_iterator<CurvePoint_nonconst_traits > iterator;
+ typedef __point_iterator<CurvePoint_const_traits > const_iterator;
+
+ // public:
+ // typedef Vertex vertex_type ;
+ // typedef vertex_container_iterator vertex_iterator_type;
+ // typedef CurvePoint<Vertex> Point;
+ // typedef Point point_type;
+ typedef IteratorBase<Traits,BidirectionalIteratorTag_Traits> parent_class;
+ //# if defined(__GNUC__) && (__GNUC__ < 3)
+ // typedef bidirectional_iterator<CurvePoint<Vertex>,ptrdiff_t> bidirectional_point_iterator;
+ //# else
+ // typedef iterator<bidirectional_iterator_tag, CurvePoint<Vertex>,ptrdiff_t> bidirectional_point_iterator;
+ //# endif
+ friend class Curve;
+ //friend class Curve::vertex_iterator;
+ //friend class __point_iterator<CurvePoint_nonconst_traits >;
+ //friend class iterator;
+ //protected:
+ public:
+ float _CurvilinearLength;
+ float _step;
+ vertex_container_iterator __A;
+ vertex_container_iterator __B;
+ vertex_container_iterator _begin;
+ vertex_container_iterator _end;
+ int _n;
+ int _currentn;
+ float _t;
+ mutable Point *_Point;
+
+ public:
+
+ public:
+ inline __point_iterator(float step = 0.f)
+ : parent_class()
+ {
+ _step = step;
+ _CurvilinearLength = 0.f;
+ _t = 0.f;
+ _Point = 0;
+ _n = 0;
+ _currentn = 0;
+ }
+
+ inline __point_iterator(const iterator& iBrother)
+ : parent_class()
+ {
+ __A = iBrother.__A;
+ __B = iBrother.__B;
+ _begin = iBrother._begin;
+ _end = iBrother._end;
+ _CurvilinearLength = iBrother._CurvilinearLength;
+ _step = iBrother._step;
+ _t = iBrother._t;
+ if(iBrother._Point == 0)
+ _Point = 0;
+ else
+ _Point = new Point(*(iBrother._Point));
+ _n = iBrother._n;
+ _currentn = iBrother._currentn;
+ }
+ inline __point_iterator(const const_iterator& iBrother)
+ : parent_class()
+ {
+ __A = iBrother.__A;
+ __B = iBrother.__B;
+ _begin = iBrother._begin;
+ _end = iBrother._end;
+ _CurvilinearLength = iBrother._CurvilinearLength;
+ _step = iBrother._step;
+ _t = iBrother._t;
+ if(iBrother._Point == 0)
+ _Point = 0;
+ else
+ _Point = new Point(*(iBrother._Point));
+ _n = iBrother._n;
+ _currentn = iBrother._currentn;
+ }
+ inline Self& operator=(const Self& iBrother)
+ {
+ //((bidirectional_point_iterator*)this)->operator=(iBrother);
+ __A = iBrother.__A;
+ __B = iBrother.__B;
+ _begin = iBrother._begin;
+ _end = iBrother._end;
+ _CurvilinearLength = iBrother._CurvilinearLength;
+ _step = iBrother._step;
+ _t = iBrother._t;
+ if(iBrother._Point == 0)
+ _Point = 0;
+ else
+ _Point = new Point(*(iBrother._Point));
+ _n = iBrother._n;
+ _currentn = iBrother._currentn;
+ return *this;
+ }
+ virtual ~__point_iterator()
+ {
+ if(_Point != 0)
+ delete _Point;
+ }
+ //protected://FIXME
+ public:
+ inline __point_iterator(vertex_container_iterator iA,
+ vertex_container_iterator iB,
+ vertex_container_iterator ibegin,
+ vertex_container_iterator iend,
+ int currentn,
+ int n,
+ float step, float t=0.f, float iCurvilinearLength = 0.f)
+ : parent_class()
+ {
+ __A = iA;
+ __B = iB;
+ _begin = ibegin;
+ _end = iend;
+ _CurvilinearLength = iCurvilinearLength;
+ _step = step;
+ _t = t;
+ _Point = 0;
+ _n = n;
+ _currentn = currentn;
+ }
+
+ public:
+
+ // operators
+ inline Self& operator++() // operator corresponding to ++i
+ {
+ increment();
+ return *this;
+ }
+ inline Self operator++(int) // opérateur correspondant à i++
+ { // c.a.d qui renvoie la valeur *puis* incrémente.
+ Self tmp = *this; // C'est pour cela qu'on stocke la valeur
+ increment(); // dans un temporaire.
+ return tmp;
+ }
+ inline Self& operator--() // operator corresponding to ++i
+ {
+ decrement();
+ return *this;
+ }
+ inline Self operator--(int) // opérateur correspondant à i++
+ { // c.a.d qui renvoie la valeur *puis* incrémente.
+ Self tmp = *this; // C'est pour cela qu'on stocke la valeur
+ decrement(); // dans un temporaire.
+ return tmp;
+ }
+
+ // comparibility
+ virtual bool operator!=(const Self& b) const
+ {
+ return ((__A!=b.__A) || (__B!=b.__B) || (_t != b._t));
+ }
+ virtual bool operator==(const Self& b) const
+ {
+ return !(*this != b);
+ }
+
+ // dereferencing
+ virtual typename Traits::reference operator*() const
+ {
+ if(_Point != 0)
+ {
+ delete _Point;
+ _Point = 0;
+ }
+ if((_currentn < 0) || (_currentn >= _n))
+ return _Point; // 0 in this case
+ return (_Point = new Point(*__A,*__B,_t));
+ }
+ virtual typename Traits::pointer operator->() const { return &(operator*());}
+
+ public:
+ virtual bool begin() const
+ {
+ if((__A == _begin) && (_t < (float)M_EPSILON))
+ return true;
+ return false;
+ }
+ virtual bool end() const
+ {
+ if((__B == _end))
+ return true;
+ return false;
+ }
+ protected:
+ virtual void increment()
+ {
+ if(_Point != 0)
+ {
+ delete _Point;
+ _Point = 0;
+ }
+ if((_currentn == _n-1) && (_t == 1.f))
+ {
+ // we're setting the iterator to end
+ ++__A;
+ ++__B;
+ ++_currentn;
+ _t = 0.f;
+ return;
+ }
+
+ if(0 == _step) // means we iterate over initial vertices
+ {
+ Vec3r vec_tmp((*__B)->point2d() - (*__A)->point2d());
+ _CurvilinearLength += vec_tmp.norm();
+ if(_currentn == _n-1)
+ {
+ _t = 1.f;
+ return;
+ }
+ ++__B;
+ ++__A;
+ ++_currentn;
+ return;
+ }
+
+ // compute the new position:
+ Vec3r vec_tmp2((*__A)->point2d() - (*__B)->point2d());
+ float normAB = vec_tmp2.norm();
+
+ if(normAB > M_EPSILON)
+ {
+ _CurvilinearLength += _step;
+ _t = _t + _step/normAB;
+ }
+ else
+ _t = 1.f; // AB is a null segment, we're directly at its end
+ //if normAB ~= 0, we don't change these values
+ if(_t >= 1)
+ {
+ _CurvilinearLength -= normAB*(_t-1);
+ if(_currentn == _n-1)
+ _t=1.f;
+ else
+ {
+ _t = 0.f;
+ ++_currentn;
+ ++__A;++__B;
+ }
+ }
+ }
+ virtual void decrement()
+ {
+ if(_Point != 0)
+ {
+ delete _Point;
+ _Point = 0;
+ }
+
+ if(_t == 0.f) //we're at the beginning of the edge
+ {
+ _t = 1.f;
+ --_currentn;
+ --__A; --__B;
+ if(_currentn == _n-1)
+ return;
+ }
+
+ if(0 == _step) // means we iterate over initial vertices
+ {
+ Vec3r vec_tmp((*__B)->point2d() - (*__A)->point2d());
+ _CurvilinearLength -= vec_tmp.norm();
+ _t = 0;
+ return;
+ }
+
+ // compute the new position:
+ Vec3r vec_tmp2((*__A)->point2d() - (*__B)->point2d());
+ float normAB = vec_tmp2.norm();
+
+ if(normAB >M_EPSILON)
+ {
+ _CurvilinearLength -= _step;
+ _t = _t - _step/normAB;
+ }
+ else
+ _t = -1.f; // We just need a negative value here
+
+ // round value
+ if(fabs(_t) < (float)M_EPSILON)
+ _t = 0.0;
+ if(_t < 0)
+ {
+ if(_currentn == 0)
+ _CurvilinearLength = 0.f;
+ else
+ _CurvilinearLength += normAB*(-_t);
+ _t = 0.f;
+ }
+ }
+ };
+
+
+
+} // end of namespace StrokeInternal
+
+
+#endif // ADVANCEDCURVEITERATORS_H
diff --git a/source/blender/freestyle/intern/stroke/CurveIterators.h b/source/blender/freestyle/intern/stroke/CurveIterators.h
new file mode 100755
index 00000000000..92f8bf065f4
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/CurveIterators.h
@@ -0,0 +1,295 @@
+//
+// Filename : CurveIterators.h
+// Author(s) : Stephane Grabli
+// Purpose : Iterators used to iterate over the elements of the Curve
+// Date of creation : 01/08/2003
+//
+///////////////////////////////////////////////////////////////////////////////
+
+
+//
+// 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef CURVEITERATORS_H
+# define CURVEITERATORS_H
+
+#include "Stroke.h"
+#include "Curve.h"
+
+namespace CurveInternal {
+
+ /*! iterator on a curve. Allows an iterating outside
+ * initial vertices. A CurvePoint is instanciated an returned
+ * when the iterator is dereferenced.
+ */
+
+ class CurvePointIterator : public Interface0DIteratorNested
+ {
+ public:
+ friend class ::Curve;
+ public:
+ float _CurvilinearLength;
+ float _step;
+ ::Curve::vertex_container::iterator __A;
+ ::Curve::vertex_container::iterator __B;
+ ::Curve::vertex_container::iterator _begin;
+ ::Curve::vertex_container::iterator _end;
+ int _n;
+ int _currentn;
+ float _t;
+ mutable CurvePoint _Point;
+ float _CurveLength;
+
+ public:
+
+ public:
+ inline CurvePointIterator(float step = 0.f)
+ : Interface0DIteratorNested()
+ {
+ _step = step;
+ _CurvilinearLength = 0.f;
+ _t = 0.f;
+ //_Point = 0;
+ _n = 0;
+ _currentn = 0;
+ _CurveLength=0;
+ }
+
+ inline CurvePointIterator(const CurvePointIterator& iBrother)
+ : Interface0DIteratorNested()
+ {
+ __A = iBrother.__A;
+ __B = iBrother.__B;
+ _begin = iBrother._begin;
+ _end = iBrother._end;
+ _CurvilinearLength = iBrother._CurvilinearLength;
+ _step = iBrother._step;
+ _t = iBrother._t;
+ _Point = iBrother._Point;
+ _n = iBrother._n;
+ _currentn = iBrother._currentn;
+ _CurveLength = iBrother._CurveLength;
+ }
+ inline CurvePointIterator& operator=(const CurvePointIterator& iBrother)
+ {
+ __A = iBrother.__A;
+ __B = iBrother.__B;
+ _begin = iBrother._begin;
+ _end = iBrother._end;
+ _CurvilinearLength = iBrother._CurvilinearLength;
+ _step = iBrother._step;
+ _t = iBrother._t;
+ _Point = iBrother._Point;
+ _n = iBrother._n;
+ _currentn = iBrother._currentn;
+ _CurveLength = iBrother._CurveLength;
+ return *this;
+ }
+ virtual ~CurvePointIterator()
+ {
+ }
+ protected:
+ inline CurvePointIterator(::Curve::vertex_container::iterator iA,
+ ::Curve::vertex_container::iterator iB,
+ ::Curve::vertex_container::iterator ibegin,
+ ::Curve::vertex_container::iterator iend,
+ int currentn,
+ int n,
+ float iCurveLength,
+ float step, float t=0.f, float iCurvilinearLength = 0.f)
+ : Interface0DIteratorNested()
+ {
+ __A = iA;
+ __B = iB;
+ _begin = ibegin;
+ _end = iend;
+ _CurvilinearLength = iCurvilinearLength;
+ _step = step;
+ _t = t;
+ _n = n;
+ _currentn = currentn;
+ _CurveLength = iCurveLength;
+ }
+
+ public:
+
+ virtual CurvePointIterator* copy() const {
+ return new CurvePointIterator(*this);
+ }
+
+ inline Interface0DIterator CastToInterface0DIterator() const{
+ Interface0DIterator ret(new CurveInternal::CurvePointIterator(*this));
+ return ret;
+ }
+ virtual string getExactTypeName() const {
+ return "CurvePointIterator";
+ }
+
+ // operators
+ inline CurvePointIterator& operator++() // operator corresponding to ++i
+ {
+ increment();
+ return *this;
+ }
+
+ inline CurvePointIterator& operator--() // operator corresponding to ++i
+ {
+ decrement();
+ return *this;
+ }
+
+ // comparibility
+ virtual bool operator==(const Interface0DIteratorNested& b) const
+ {
+ const CurvePointIterator* it_exact = dynamic_cast<const CurvePointIterator*>(&b);
+ if (!it_exact)
+ return false;
+ return ((__A==it_exact->__A) && (__B==it_exact->__B) && (_t == it_exact->_t));
+ }
+
+ // dereferencing
+ virtual CurvePoint& operator*()
+ {
+ return (_Point = CurvePoint(*__A,*__B,_t));
+ }
+ virtual CurvePoint* operator->() { return &(operator*());}
+ public:
+ virtual bool isBegin() const
+ {
+ if((__A == _begin) && (_t < (float)M_EPSILON))
+ return true;
+ return false;
+ }
+ virtual bool isEnd() const
+ {
+ if(__B == _end)
+ return true;
+ return false;
+ }
+ protected:
+ virtual void increment()
+ {
+ if((_currentn == _n-1) && (_t == 1.f))
+ {
+ // we're setting the iterator to end
+ ++__A;
+ ++__B;
+ ++_currentn;
+ _t = 0.f;
+ return;
+ }
+
+ if(0 == _step) // means we iterate over initial vertices
+ {
+ Vec3r vec_tmp((*__B)->point2d() - (*__A)->point2d());
+ _CurvilinearLength += (float)vec_tmp.norm();
+ if(_currentn == _n-1)
+ {
+ _t = 1.f;
+ return;
+ }
+ ++__B;
+ ++__A;
+ ++_currentn;
+ return;
+ }
+
+ // compute the new position:
+ Vec3r vec_tmp2((*__A)->point2d() - (*__B)->point2d());
+ float normAB = (float)vec_tmp2.norm();
+
+ if(normAB > M_EPSILON)
+ {
+ _CurvilinearLength += _step;
+ _t = _t + _step/normAB;
+ }
+ else
+ _t = 1.f; // AB is a null segment, we're directly at its end
+ //if normAB ~= 0, we don't change these values
+ if(_t >= 1)
+ {
+ _CurvilinearLength -= normAB*(_t-1);
+ if(_currentn == _n-1)
+ _t=1.f;
+ else
+ {
+ _t = 0.f;
+ ++_currentn;
+ ++__A;++__B;
+ }
+ }
+ }
+ virtual void decrement()
+ {
+ if(_t == 0.f) //we're at the beginning of the edge
+ {
+ _t = 1.f;
+ --_currentn;
+ --__A; --__B;
+ if(_currentn == _n-1)
+ return;
+ }
+
+ if(0 == _step) // means we iterate over initial vertices
+ {
+ Vec3r vec_tmp((*__B)->point2d() - (*__A)->point2d());
+ _CurvilinearLength -= (float)vec_tmp.norm();
+ _t = 0;
+ return;
+ }
+
+ // compute the new position:
+ Vec3r vec_tmp2((*__A)->point2d() - (*__B)->point2d());
+ float normAB = (float)vec_tmp2.norm();
+
+ if(normAB >M_EPSILON)
+ {
+ _CurvilinearLength -= _step;
+ _t = _t - _step/normAB;
+ }
+ else
+ _t = -1.f; // We just need a negative value here
+
+ // round value
+ if(fabs(_t) < (float)M_EPSILON)
+ _t = 0.0;
+ if(_t < 0)
+ {
+ if(_currentn == 0)
+ _CurvilinearLength = 0.f;
+ else
+ _CurvilinearLength += normAB*(-_t);
+ _t = 0.f;
+ }
+ }
+
+ virtual float t() const{
+ return _CurvilinearLength;
+ }
+ virtual float u() const{
+ return _CurvilinearLength/_CurveLength;
+ }
+ };
+
+
+
+} // end of namespace StrokeInternal
+
+#endif // CURVEITERATORS_H
diff --git a/source/blender/freestyle/intern/stroke/Modifiers.h b/source/blender/freestyle/intern/stroke/Modifiers.h
new file mode 100755
index 00000000000..c3be65ffc89
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/Modifiers.h
@@ -0,0 +1,71 @@
+//
+// Filename : Modifiers.h
+// Author : Stephane Grabli
+// Purpose : modifiers...
+// Date of creation : 05/01/2003
+//
+///////////////////////////////////////////////////////////////////////////////
+
+
+//
+// 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef MODIFIERS_H
+# define MODIFIERS_H
+
+# include "TimeStamp.h"
+
+/* ----------------------------------------- *
+ * *
+ * modifiers *
+ * *
+ * ----------------------------------------- */
+/*! Base class for modifiers.
+ * Modifiers are used in the
+ * Operators in order to "mark"
+ * the processed Interface1D.
+ */
+template<class Edge>
+struct EdgeModifier : public unary_function<Edge,void>
+{
+ /*! Default construction */
+ EdgeModifier() : unary_function<Edge,void>() {}
+ /*! the () operator */
+ virtual void operator()(Edge& iEdge) {}
+};
+
+/*! Modifier that sets the time stamp
+ * of an Interface1D to the time stamp
+ * of the system.
+ */
+template<class Edge>
+struct TimestampModifier : public EdgeModifier<Edge>
+{
+ /*! Default constructor */
+ TimestampModifier() : EdgeModifier<Edge>() {}
+ /*! The () operator. */
+ virtual void operator()(Edge& iEdge)
+ {
+ TimeStamp *timestamp = TimeStamp::instance();
+ iEdge.SetTimeStamp(timestamp->getTimeStamp());
+ }
+};
+
+#endif // MODIFIERS_H
diff --git a/source/blender/freestyle/intern/stroke/Module.h b/source/blender/freestyle/intern/stroke/Module.h
new file mode 100755
index 00000000000..591bb157392
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/Module.h
@@ -0,0 +1,72 @@
+//
+// Filename : Module.h
+// Author(s) : Emmanuel Turquin
+// Purpose : Set the type of the module
+// Date of creation : 01/07/2003
+//
+///////////////////////////////////////////////////////////////////////////////
+
+
+//
+// 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef MODULE_H
+# define MODULE_H
+
+# include "Canvas.h"
+# include "StyleModule.h"
+
+class Module
+{
+public:
+
+ static void setAlwaysRefresh(bool b = true) {
+ getCurrentStyleModule()->setAlwaysRefresh(b);
+ }
+
+ static void setCausal(bool b = true) {
+ getCurrentStyleModule()->setCausal(b);
+ }
+
+ static void setDrawable(bool b = true) {
+ getCurrentStyleModule()->setDrawable(b);
+ }
+
+ static bool getAlwaysRefresh() {
+ return getCurrentStyleModule()->getAlwaysRefresh();
+ }
+
+ static bool getCausal() {
+ return getCurrentStyleModule()->getCausal();
+ }
+
+ static bool getDrawable() {
+ return getCurrentStyleModule()->getDrawable();
+ }
+
+private:
+
+ static StyleModule* getCurrentStyleModule() {
+ Canvas* canvas = Canvas::getInstance();
+ return canvas->getCurrentStyleModule();
+ }
+};
+
+#endif // MODULE_H
diff --git a/source/blender/freestyle/intern/stroke/Operators.cpp b/source/blender/freestyle/intern/stroke/Operators.cpp
new file mode 100755
index 00000000000..121dee3ba26
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/Operators.cpp
@@ -0,0 +1,862 @@
+
+//
+// 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 <algorithm>
+#include "Operators.h"
+#include "Canvas.h"
+#include "Stroke.h"
+
+LIB_STROKE_EXPORT Operators::I1DContainer Operators::_current_view_edges_set;
+LIB_STROKE_EXPORT Operators::I1DContainer Operators::_current_chains_set;
+LIB_STROKE_EXPORT Operators::I1DContainer* Operators::_current_set = NULL;
+LIB_STROKE_EXPORT Operators::StrokesContainer Operators::_current_strokes_set;
+
+void Operators::select(UnaryPredicate1D& pred) {
+ if (!_current_set)
+ return;
+ if(_current_set->empty())
+ return;
+ I1DContainer new_set;
+ I1DContainer rejected;
+ Functions1D::ChainingTimeStampF1D cts;
+ Functions1D::TimeStampF1D ts;
+ I1DContainer::iterator it = _current_set->begin();
+ I1DContainer::iterator itbegin = it;
+ while (it != _current_set->end()) {
+ Interface1D * i1d = *it;
+ cts(*i1d); // mark everyone's chaining time stamp anyway
+ if (pred(*i1d)){
+ new_set.push_back(i1d);
+ ts(*i1d);
+ }else{
+ rejected.push_back(i1d);
+ }
+ ++it;
+ }
+ if((*itbegin)->getExactTypeName() != "ViewEdge"){
+ for (it = rejected.begin();
+ it != rejected.end();
+ ++it)
+ delete *it;
+ }
+ rejected.clear();
+ _current_set->clear();
+ *_current_set = new_set;
+}
+
+
+void Operators::chain(ViewEdgeInternal::ViewEdgeIterator& it,
+ UnaryPredicate1D& pred,
+ UnaryFunction1D<void>& modifier) {
+ if (_current_view_edges_set.empty())
+ return;
+
+ unsigned id = 0;
+ ViewEdge* edge;
+ Chain* new_chain;
+
+ for (I1DContainer::iterator it_edge = _current_view_edges_set.begin();
+ it_edge != _current_view_edges_set.end();
+ ++it_edge) {
+ if (pred(**it_edge))
+ continue;
+
+ edge = dynamic_cast<ViewEdge*>(*it_edge);
+ it.setBegin(edge);
+ it.setCurrentEdge(edge);
+
+ Chain* new_chain = new Chain(id);++id;
+ do {
+ new_chain->push_viewedge_back(*it, it.getOrientation());
+ modifier(**it);
+ ++it;
+ } while (!it.isEnd() && !pred(**it));
+
+ _current_chains_set.push_back(new_chain);
+ }
+
+ if (!_current_chains_set.empty())
+ _current_set = &_current_chains_set;
+}
+
+
+void Operators::chain(ViewEdgeInternal::ViewEdgeIterator& it,
+ UnaryPredicate1D& pred) {
+ if (_current_view_edges_set.empty())
+ return;
+
+ unsigned id = 0;
+ Functions1D::IncrementChainingTimeStampF1D ts;
+ Predicates1D::EqualToChainingTimeStampUP1D pred_ts(TimeStamp::instance()->getTimeStamp()+1);
+
+ ViewEdge* edge;
+ Chain* new_chain;
+
+ for (I1DContainer::iterator it_edge = _current_view_edges_set.begin();
+ it_edge != _current_view_edges_set.end();
+ ++it_edge) {
+ if (pred(**it_edge) || pred_ts(**it_edge))
+ continue;
+
+ edge = dynamic_cast<ViewEdge*>(*it_edge);
+ it.setBegin(edge);
+ it.setCurrentEdge(edge);
+
+ Chain* new_chain = new Chain(id);++id;
+ do {
+ new_chain->push_viewedge_back(*it, it.getOrientation());
+ ts(**it);
+ ++it;
+ } while (!it.isEnd() && !pred(**it) && !pred_ts(**it));
+
+ _current_chains_set.push_back(new_chain);
+ }
+
+ if (!_current_chains_set.empty())
+ _current_set = &_current_chains_set;
+}
+
+
+//void Operators::bidirectionalChain(ViewEdgeIterator& it,
+// UnaryPredicate1D& pred,
+// UnaryFunction1D<void>& modifier) {
+// if (_current_view_edges_set.empty())
+// return;
+//
+// unsigned id = 0;
+// ViewEdge* edge;
+// Chain* new_chain;
+//
+// for (I1DContainer::iterator it_edge = _current_view_edges_set.begin();
+// it_edge != _current_view_edges_set.end();
+// ++it_edge) {
+// if (pred(**it_edge))
+// continue;
+//
+// edge = dynamic_cast<ViewEdge*>(*it_edge);
+// it.setBegin(edge);
+// it.setCurrentEdge(edge);
+//
+// Chain* new_chain = new Chain(id);++id;
+// //ViewEdgeIterator it_back(it);--it_back; // FIXME
+// do {
+// new_chain->push_viewedge_back(*it, it.getOrientation());
+// modifier(**it);
+// ++it;
+// } while (!it.isEnd() && !pred(**it));
+// it.setBegin(edge);
+// it.setCurrentEdge(edge);
+// --it;
+// while (!it.isEnd() && !pred(**it)) {
+// new_chain->push_viewedge_front(*it, it.getOrientation());
+// modifier(**it);
+// --it;
+// }
+//
+// _current_chains_set.push_back(new_chain);
+// }
+//
+// if (!_current_chains_set.empty())
+// _current_set = &_current_chains_set;
+//}
+//
+//void Operators::bidirectionalChain(ViewEdgeIterator& it,
+// UnaryPredicate1D& pred) {
+// if (_current_view_edges_set.empty())
+// return;
+//
+// unsigned id = 0;
+// Functions1D::IncrementChainingTimeStampF1D ts;
+// Predicates1D::EqualToChainingTimeStampUP1D pred_ts(TimeStamp::instance()->getTimeStamp()+1);
+//
+// ViewEdge* edge;
+// Chain* new_chain;
+//
+// for (I1DContainer::iterator it_edge = _current_view_edges_set.begin();
+// it_edge != _current_view_edges_set.end();
+// ++it_edge) {
+// if (pred(**it_edge) || pred_ts(**it_edge))
+// continue;
+//
+// edge = dynamic_cast<ViewEdge*>(*it_edge);
+// it.setBegin(edge);
+// it.setCurrentEdge(edge);
+ //
+ // Chain* new_chain = new Chain(id);++id;
+ // //ViewEdgeIterator it_back(it);--it_back;//FIXME
+ // do {
+ // new_chain->push_viewedge_back(*it, it.getOrientation());
+ // ts(**it);
+ // ++it;
+ // } while (!it.isEnd() && !pred(**it) && !pred_ts(**it));
+ // it.setBegin(edge);
+ // it.setCurrentEdge(edge);
+ // --it;
+ // while (!it.isEnd() && !pred(**it) && !pred_ts(**it)) {
+ // new_chain->push_viewedge_front(*it, it.getOrientation());
+ // ts(**it);
+ // --it;
+ // }
+ //
+ // _current_chains_set.push_back(new_chain);
+ // }
+ //
+ // if (!_current_chains_set.empty())
+ // _current_set = &_current_chains_set;
+ //}
+
+void Operators::bidirectionalChain(ChainingIterator& it, UnaryPredicate1D& pred) {
+ if (_current_view_edges_set.empty())
+ return;
+
+ unsigned id = 0;
+ Functions1D::IncrementChainingTimeStampF1D ts;
+ Predicates1D::EqualToChainingTimeStampUP1D pred_ts(TimeStamp::instance()->getTimeStamp()+1);
+
+ ViewEdge* edge;
+ Chain* new_chain;
+
+ for (I1DContainer::iterator it_edge = _current_view_edges_set.begin();
+ it_edge != _current_view_edges_set.end();
+ ++it_edge) {
+ if (pred(**it_edge) || pred_ts(**it_edge))
+ continue;
+
+ edge = dynamic_cast<ViewEdge*>(*it_edge);
+ // re-init iterator
+ it.setBegin(edge);
+ it.setCurrentEdge(edge);
+ it.setOrientation(true);
+ it.init();
+
+ Chain* new_chain = new Chain(id);++id;
+ //ViewEdgeIterator it_back(it);--it_back;//FIXME
+ do {
+ new_chain->push_viewedge_back(*it, it.getOrientation());
+ ts(**it);
+ it.increment(); // FIXME
+ } while (!it.isEnd() && !pred(**it));
+ it.setBegin(edge);
+ it.setCurrentEdge(edge);
+ it.setOrientation(true);
+ it.decrement(); // FIXME
+ while (!it.isEnd() && !pred(**it)) {
+ new_chain->push_viewedge_front(*it, it.getOrientation());
+ ts(**it);
+ it.decrement();// FIXME
+ }
+ _current_chains_set.push_back(new_chain);
+ }
+
+ if (!_current_chains_set.empty())
+ _current_set = &_current_chains_set;
+}
+
+void Operators::bidirectionalChain(ChainingIterator& it) {
+ if (_current_view_edges_set.empty())
+ return;
+
+ unsigned id = 0;
+ Functions1D::IncrementChainingTimeStampF1D ts;
+ Predicates1D::EqualToChainingTimeStampUP1D pred_ts(TimeStamp::instance()->getTimeStamp()+1);
+
+ ViewEdge* edge;
+ Chain* new_chain;
+
+ for (I1DContainer::iterator it_edge = _current_view_edges_set.begin();
+ it_edge != _current_view_edges_set.end();
+ ++it_edge) {
+ if (pred_ts(**it_edge))
+ continue;
+
+ edge = dynamic_cast<ViewEdge*>(*it_edge);
+ // re-init iterator
+ it.setBegin(edge);
+ it.setCurrentEdge(edge);
+ it.setOrientation(true);
+ it.init();
+
+ Chain* new_chain = new Chain(id);++id;
+ //ViewEdgeIterator it_back(it);--it_back;//FIXME
+ do {
+ new_chain->push_viewedge_back(*it, it.getOrientation());
+ ts(**it);
+ it.increment(); // FIXME
+ } while (!it.isEnd());
+ it.setBegin(edge);
+ it.setCurrentEdge(edge);
+ it.setOrientation(true);
+ it.decrement(); // FIXME
+ while (!it.isEnd()) {
+ new_chain->push_viewedge_front(*it, it.getOrientation());
+ ts(**it);
+ it.decrement();// FIXME
+ }
+ _current_chains_set.push_back(new_chain);
+ }
+
+ if (!_current_chains_set.empty())
+ _current_set = &_current_chains_set;
+}
+
+void Operators::sequentialSplit(UnaryPredicate0D& pred,
+ float sampling)
+{
+ if (_current_chains_set.empty()) {
+ cerr << "Warning: current set empty" << endl;
+ return;
+ }
+ CurvePoint *point;
+ Chain * new_curve;
+ I1DContainer splitted_chains;
+ Interface0DIterator first;
+ Interface0DIterator end;
+ Interface0DIterator last;
+ Interface0DIterator it;
+ I1DContainer::iterator cit = _current_chains_set.begin(), citend = _current_chains_set.end();
+ for (;
+ cit != citend;
+ ++cit) {
+
+ Id currentId = (*cit)->getId();
+ new_curve = new Chain(currentId);
+ first = (*cit)->pointsBegin(sampling);
+ end = (*cit)->pointsEnd(sampling);
+ last = end;--last;
+ it = first;
+
+ point = dynamic_cast<CurvePoint*>(&(*it));
+ new_curve->push_vertex_back(point);++it;
+ for(; it!= end; ++it)
+ {
+ point = dynamic_cast<CurvePoint*>(&(*it));
+ new_curve->push_vertex_back(point);
+ if((pred(it)) && (it!=last))
+ {
+ splitted_chains.push_back(new_curve);
+ currentId.setSecond(currentId.getSecond()+1);
+ new_curve = new Chain(currentId);
+ new_curve->push_vertex_back(point);
+ }
+ }
+ if(new_curve->nSegments() == 0){
+ delete new_curve;
+ return;
+ }
+
+ splitted_chains.push_back(new_curve);
+ }
+
+ // Update the current set of chains:
+ cit = _current_chains_set.begin();
+ for(;
+ cit != citend;
+ ++cit){
+ delete (*cit);
+ }
+ _current_chains_set.clear();
+ _current_chains_set = splitted_chains;
+ splitted_chains.clear();
+
+ if (!_current_chains_set.empty())
+ _current_set = &_current_chains_set;
+}
+
+void Operators::sequentialSplit(UnaryPredicate0D& startingPred, UnaryPredicate0D& stoppingPred,
+ float sampling)
+{
+ if (_current_chains_set.empty()) {
+ cerr << "Warning: current set empty" << endl;
+ return;
+ }
+ CurvePoint *point;
+ Chain * new_curve;
+ I1DContainer splitted_chains;
+ Interface0DIterator first;
+ Interface0DIterator end;
+ Interface0DIterator last;
+ Interface0DIterator itStart;
+ Interface0DIterator itStop;
+ I1DContainer::iterator cit = _current_chains_set.begin(), citend = _current_chains_set.end();
+ for (;
+ cit != citend;
+ ++cit) {
+ Id currentId = (*cit)->getId();
+ first = (*cit)->pointsBegin(sampling);
+ end = (*cit)->pointsEnd(sampling);
+ last = end;--last;
+ itStart = first;
+ do{
+ itStop = itStart;++itStop;
+
+ new_curve = new Chain(currentId);
+ currentId.setSecond(currentId.getSecond()+1);
+
+ point = dynamic_cast<CurvePoint*>(&(*itStart));
+ new_curve->push_vertex_back(point);
+ do{
+ point = dynamic_cast<CurvePoint*>(&(*itStop));
+ new_curve->push_vertex_back(point);
+ ++itStop;
+ }while((itStop!=end) && (!stoppingPred(itStop)));
+ if(itStop!=end){
+ point = dynamic_cast<CurvePoint*>(&(*itStop));
+ new_curve->push_vertex_back(point);
+ }
+ if(new_curve->nSegments() == 0){
+ delete new_curve;
+ }else{
+ splitted_chains.push_back(new_curve);
+ }
+ // find next start
+ do{
+ ++itStart;
+ }while((itStart!=end) && (!startingPred(itStart)));
+ }while((itStart!=end) && (itStart!=last));
+ }
+
+ // Update the current set of chains:
+ cit = _current_chains_set.begin();
+ for(;
+ cit != citend;
+ ++cit){
+ delete (*cit);
+ }
+ _current_chains_set.clear();
+ _current_chains_set = splitted_chains;
+ splitted_chains.clear();
+
+ if (!_current_chains_set.empty())
+ _current_set = &_current_chains_set;
+}
+
+#include "CurveIterators.h"
+
+// Internal function
+void __recursiveSplit(Chain *_curve, UnaryFunction0D<double>& func, UnaryPredicate1D& pred, float sampling,
+ Operators::I1DContainer& newChains, Operators::I1DContainer& splitted_chains)
+{
+ if(((_curve->nSegments() == 1) && (sampling == 0)) || (_curve->getLength2D() <= sampling)){
+ newChains.push_back(_curve);
+ return;
+ }
+
+ CurveInternal::CurvePointIterator first = _curve->curvePointsBegin(sampling);
+ CurveInternal::CurvePointIterator second = first; ++second;
+ CurveInternal::CurvePointIterator end = _curve->curvePointsEnd(sampling);
+ CurveInternal::CurvePointIterator it = second;
+ CurveInternal::CurvePointIterator split = second;
+ Interface0DIterator it0d = it.CastToInterface0DIterator();
+ real _min = FLT_MAX;++it;//func(it0d);++it;
+ CurveInternal::CurvePointIterator next = it;++next;
+ real tmp;
+
+ bool bsplit = false;
+ for(; ((it != end) && (next != end)); ++it,++next){
+ it0d = it.CastToInterface0DIterator();
+ tmp = func(it0d);
+ if(tmp < _min){
+ _min = tmp;
+ split = it;
+ bsplit = true;
+ }
+ }
+
+ if(!bsplit){ // we didn't find any minimum
+ newChains.push_back(_curve);
+ return;
+ }
+
+ // retrieves the current splitting id
+ Id * newId = _curve->getSplittingId();
+ if(newId == 0){
+ newId = new Id(_curve->getId());
+ _curve->setSplittingId(newId);
+ }
+
+ Chain *new_curve_a = new Chain(*newId);
+ newId->setSecond(newId->getSecond()+1);
+ new_curve_a->setSplittingId(newId);
+ Chain *new_curve_b = new Chain(*newId);
+ newId->setSecond(newId->getSecond()+1);
+ new_curve_b->setSplittingId(newId);
+
+ CurveInternal::CurvePointIterator vit = _curve->curveVerticesBegin(), vitend=_curve->curveVerticesEnd();
+ CurveInternal::CurvePointIterator vnext = vit; ++vnext;
+
+
+ for(; (vit!=vitend)&&(vnext!=vitend)&&(split._CurvilinearLength-vit._CurvilinearLength> 0.001); ++vit,++vnext){
+ new_curve_a->push_vertex_back(&(*vit));
+ }
+ if((vit==vitend) || (vnext == vitend)){
+ cout << "The split takes place in bad location" << endl;
+ newChains.push_back(_curve);
+ delete new_curve_a;
+ delete new_curve_b;
+ return;
+ }
+
+ // build the two resulting chains
+ if(fabs(vit._CurvilinearLength-split._CurvilinearLength) > 0.001){
+ new_curve_a->push_vertex_back(&(*split));
+ new_curve_b->push_vertex_back(&(*split));
+ }
+ else{
+ new_curve_a->push_vertex_back(&(*vit));
+ }
+
+ for(;vit!=vitend;++vit)
+ new_curve_b->push_vertex_back(&(*vit));
+
+ // let's check whether one or two of the two new curves
+ // satisfy the stopping condition or not.
+ // (if one of them satisfies it, we don't split)
+ if((pred(*new_curve_a)) || (pred(*new_curve_b))){
+ // we don't actually create these two chains
+ newChains.push_back(_curve);
+ delete new_curve_a;
+ delete new_curve_b;
+ return;
+ }
+ // here we know we'll split _curve:
+ splitted_chains.push_back(_curve);
+
+ __recursiveSplit(new_curve_a, func, pred, sampling, newChains, splitted_chains);
+ __recursiveSplit(new_curve_b, func, pred, sampling, newChains, splitted_chains);
+}
+
+void Operators::recursiveSplit(UnaryFunction0D<double>& func, UnaryPredicate1D& pred, float sampling)
+{
+ if (_current_chains_set.empty()) {
+ cerr << "Warning: current set empty" << endl;
+ return;
+ }
+
+ Chain *currentChain = 0;
+ I1DContainer splitted_chains;
+ I1DContainer newChains;
+ I1DContainer::iterator cit = _current_chains_set.begin(), citend = _current_chains_set.end();
+ for (;
+ cit != citend;
+ ++cit) {
+ currentChain = dynamic_cast<Chain*>(*cit);
+ if(!currentChain)
+ continue;
+ // let's check the first one:
+ if(!pred(*currentChain)){
+ __recursiveSplit(currentChain, func, pred, sampling, newChains, splitted_chains);
+ }else{
+ newChains.push_back(currentChain);
+ }
+ }
+ // Update the current set of chains:
+ if(!splitted_chains.empty()){
+ for(cit = splitted_chains.begin(), citend = splitted_chains.end();
+ cit != citend;
+ ++cit){
+ delete (*cit);
+ }
+ splitted_chains.clear();
+ }
+
+ _current_chains_set.clear();
+ _current_chains_set = newChains;
+ newChains.clear();
+
+ if (!_current_chains_set.empty())
+ _current_set = &_current_chains_set;
+}
+
+
+// recursive split with pred 0D
+void __recursiveSplit(Chain *_curve, UnaryFunction0D<double>& func, UnaryPredicate0D& pred0d, UnaryPredicate1D& pred, float sampling,
+ Operators::I1DContainer& newChains, Operators::I1DContainer& splitted_chains)
+{
+ if(((_curve->nSegments() == 1) && (sampling == 0)) || (_curve->getLength2D() <= sampling)){
+ newChains.push_back(_curve);
+ return;
+ }
+
+ CurveInternal::CurvePointIterator first = _curve->curvePointsBegin(sampling);
+ CurveInternal::CurvePointIterator second = first; ++second;
+ CurveInternal::CurvePointIterator end = _curve->curvePointsEnd(sampling);
+ CurveInternal::CurvePointIterator it = second;
+ CurveInternal::CurvePointIterator split = second;
+ Interface0DIterator it0d = it.CastToInterface0DIterator();
+ //real _min = func(it0d);++it;
+ real _min = FLT_MAX;++it;
+ real mean = 0.f;
+ real variance = 0.f;
+ unsigned count = 0;
+ CurveInternal::CurvePointIterator next = it;++next;
+ real tmp;
+
+ bool bsplit = false;
+ for(; ((it != end) && (next != end)); ++it,++next){
+ ++count;
+ it0d = it.CastToInterface0DIterator();
+ if(!pred0d(it0d))
+ continue;
+ tmp = func(it0d);
+ mean += tmp;
+ if(tmp < _min){
+ _min = tmp;
+ split = it;
+ bsplit = true;
+ }
+ }
+ mean /= (float)count;
+
+ //if((!bsplit) || (mean-_min>mean)){ // we didn't find any minimum
+ if(!bsplit){ // we didn't find any minimum
+ newChains.push_back(_curve);
+ return;
+ }
+
+ // retrieves the current splitting id
+ Id * newId = _curve->getSplittingId();
+ if(newId == 0){
+ newId = new Id(_curve->getId());
+ _curve->setSplittingId(newId);
+ }
+
+ Chain *new_curve_a = new Chain(*newId);
+ newId->setSecond(newId->getSecond()+1);
+ new_curve_a->setSplittingId(newId);
+ Chain *new_curve_b = new Chain(*newId);
+ newId->setSecond(newId->getSecond()+1);
+ new_curve_b->setSplittingId(newId);
+
+ CurveInternal::CurvePointIterator vit = _curve->curveVerticesBegin(), vitend=_curve->curveVerticesEnd();
+ CurveInternal::CurvePointIterator vnext = vit; ++vnext;
+
+
+ for(; (vit!=vitend)&&(vnext!=vitend)&&(split._CurvilinearLength-vit._CurvilinearLength> 0.001); ++vit,++vnext){
+ new_curve_a->push_vertex_back(&(*vit));
+ }
+ if((vit==vitend) || (vnext == vitend)){
+ cout << "The split takes place in bad location" << endl;
+ newChains.push_back(_curve);
+ delete new_curve_a;
+ delete new_curve_b;
+ return;
+ }
+
+ // build the two resulting chains
+ if(fabs(vit._CurvilinearLength-split._CurvilinearLength) > 0.001){
+ new_curve_a->push_vertex_back(&(*split));
+ new_curve_b->push_vertex_back(&(*split));
+ }
+ else{
+ new_curve_a->push_vertex_back(&(*vit));
+ }
+
+ for(;vit!=vitend;++vit)
+ new_curve_b->push_vertex_back(&(*vit));
+
+ // let's check whether one or two of the two new curves
+ // satisfy the stopping condition or not.
+ // (if one of them satisfies it, we don't split)
+ if((pred(*new_curve_a)) || (pred(*new_curve_b))){
+ // we don't actually create these two chains
+ newChains.push_back(_curve);
+ delete new_curve_a;
+ delete new_curve_b;
+ return;
+ }
+ // here we know we'll split _curve:
+ splitted_chains.push_back(_curve);
+
+ __recursiveSplit(new_curve_a, func, pred0d, pred, sampling, newChains, splitted_chains);
+ __recursiveSplit(new_curve_b, func, pred0d, pred, sampling, newChains, splitted_chains);
+}
+
+void Operators::recursiveSplit(UnaryFunction0D<double>& func, UnaryPredicate0D& pred0d, UnaryPredicate1D& pred, float sampling)
+{
+ if (_current_chains_set.empty()) {
+ cerr << "Warning: current set empty" << endl;
+ return;
+ }
+
+ Chain *currentChain = 0;
+ I1DContainer splitted_chains;
+ I1DContainer newChains;
+ I1DContainer::iterator cit = _current_chains_set.begin(), citend = _current_chains_set.end();
+ for (;
+ cit != citend;
+ ++cit) {
+ currentChain = dynamic_cast<Chain*>(*cit);
+ if(!currentChain)
+ continue;
+ // let's check the first one:
+ if(!pred(*currentChain)){
+ __recursiveSplit(currentChain, func, pred0d, pred, sampling, newChains, splitted_chains);
+ }else{
+ newChains.push_back(currentChain);
+ }
+ }
+ // Update the current set of chains:
+ if(!splitted_chains.empty()){
+ for(cit = splitted_chains.begin(), citend = splitted_chains.end();
+ cit != citend;
+ ++cit){
+ delete (*cit);
+ }
+ splitted_chains.clear();
+ }
+
+ _current_chains_set.clear();
+ _current_chains_set = newChains;
+ newChains.clear();
+
+ if (!_current_chains_set.empty())
+ _current_set = &_current_chains_set;
+}
+// Internal class
+class PredicateWrapper
+{
+public:
+
+ inline PredicateWrapper(BinaryPredicate1D& pred) {
+ _pred = &pred;
+ }
+
+ inline bool operator()(Interface1D* i1, Interface1D* i2) {
+ return (*_pred)(*i1, *i2);
+ }
+
+private:
+
+ BinaryPredicate1D* _pred;
+};
+
+void Operators::sort(BinaryPredicate1D& pred) {
+ if (!_current_set)
+ return;
+ std::sort(_current_set->begin(), _current_set->end(), PredicateWrapper(pred));
+}
+
+Stroke* createStroke(Interface1D& inter) {
+ Stroke* stroke = new Stroke;
+ stroke->SetId(inter.getId());
+
+ float currentCurvilignAbscissa = 0.f;
+
+ Interface0DIterator it = inter.verticesBegin(), itend = inter.verticesEnd();
+ Interface0DIterator itfirst = it;
+
+ Vec3r current(it->getProjectedX(), it->getProjectedY(), it->getProjectedZ());
+ Vec3r previous = current;
+ SVertex* sv;
+ CurvePoint* cp;
+ StrokeVertex* stroke_vertex;
+
+ do {
+ cp = dynamic_cast<CurvePoint*>(&(*it));
+ if (!cp) {
+ sv = dynamic_cast<SVertex*>(&(*it));
+ if (!sv) {
+ cerr << "Warning: unexpected Vertex type" << endl;
+ continue;
+ }
+ stroke_vertex = new StrokeVertex(sv);
+ }
+ else
+ stroke_vertex = new StrokeVertex(cp);
+ current = stroke_vertex->point2d();
+ Vec3r vec_tmp(current - previous);
+ currentCurvilignAbscissa += vec_tmp.norm();
+ stroke_vertex->SetCurvilinearAbscissa(currentCurvilignAbscissa);
+ stroke->push_back(stroke_vertex);
+ previous = current;
+ ++it;
+ } while((it != itend) && (it != itfirst));
+
+ if (it == itfirst) {
+ // Add last vertex:
+ cp = dynamic_cast<CurvePoint*>(&(*it));
+ if (!cp) {
+ sv = dynamic_cast<SVertex*>(&(*it));
+ if (!sv)
+ cerr << "Warning: unexpected Vertex type" << endl;
+ else
+ stroke_vertex = new StrokeVertex(sv);
+ }
+ else
+ stroke_vertex = new StrokeVertex(cp);
+ current = stroke_vertex->point2d();
+ Vec3r vec_tmp(current - previous);
+ currentCurvilignAbscissa += vec_tmp.norm();
+ stroke_vertex->SetCurvilinearAbscissa(currentCurvilignAbscissa);
+ stroke->push_back(stroke_vertex);
+ }
+ stroke->SetLength(currentCurvilignAbscissa);
+ return stroke;
+}
+
+
+inline void applyShading(Stroke& stroke, vector<StrokeShader*>& shaders) {
+ for (vector<StrokeShader*>::iterator it = shaders.begin();
+ it != shaders.end();
+ ++it)
+ (*it)->shade(stroke);
+}
+
+
+void Operators::create(UnaryPredicate1D& pred, vector<StrokeShader*> shaders) {
+ Canvas* canvas = Canvas::getInstance();
+ if (!_current_set) {
+ cerr << "Warning: current set empty" << endl;
+ return;
+ }
+ for (Operators::I1DContainer::iterator it = _current_set->begin();
+ it != _current_set->end();
+ ++it) {
+ if (!pred(**it))
+ continue;
+ Stroke* stroke = createStroke(**it);
+ if (stroke) {
+ applyShading(*stroke, shaders);
+ canvas->RenderStroke(stroke);
+ _current_strokes_set.push_back(stroke);
+ }
+ }
+}
+
+
+void Operators::reset() {
+ ViewMap* vm = ViewMap::getInstance();
+ if (!vm) {
+ cerr << "Error: no ViewMap computed yet" << endl;
+ return;
+ }
+ _current_view_edges_set.clear();
+ for (I1DContainer::iterator it = _current_chains_set.begin();
+ it != _current_chains_set.end();
+ ++it)
+ delete *it;
+ _current_chains_set.clear();
+ _current_view_edges_set.insert(_current_view_edges_set.begin(),
+ vm->ViewEdges().begin(),
+ vm->ViewEdges().end());
+ _current_set = &_current_view_edges_set;
+ _current_strokes_set.clear();
+}
diff --git a/source/blender/freestyle/intern/stroke/Operators.h b/source/blender/freestyle/intern/stroke/Operators.h
new file mode 100755
index 00000000000..96ecd0aa75b
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/Operators.h
@@ -0,0 +1,311 @@
+//
+// Filename : Operators.h
+// Author(s) : Stephane Grabli, Emmanuel Turquin
+// Purpose : Class gathering stroke creation algorithms
+// Date of creation : 01/07/2003
+//
+///////////////////////////////////////////////////////////////////////////////
+
+
+//
+// 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef OPERATORS_H
+# define OPERATORS_H
+
+# include <vector>
+# include <iostream>
+# include "../view_map/Interface1D.h"
+# include "Predicates1D.h"
+# include "Predicates0D.h"
+# include "../view_map/ViewMap.h"
+# include "Chain.h"
+# include "ChainingIterators.h"
+# include "../system/TimeStamp.h"
+# include "StrokeShader.h"
+
+/*! Class defining the operators used in a style module.
+ * There are 4 classes of operators: Selection, Chaining,
+ * Splitting and Creating. All these operators are user controlled
+ * in the scripting language through Functors, Predicates and Shaders
+ * that are taken as arguments.
+ */
+class LIB_STROKE_EXPORT Operators {
+
+public:
+
+ typedef vector<Interface1D*> I1DContainer;
+ typedef vector<Stroke*> StrokesContainer;
+
+
+ //
+ // Operators
+ //
+ ////////////////////////////////////////////////
+
+ /*! Selects the ViewEdges of the ViewMap verifying
+ * a specified condition.
+ * \param pred The predicate expressing this condition
+ */
+ static void select(UnaryPredicate1D& pred);
+
+ /*! Builds a set of chains from the current set of ViewEdges.
+ * Each ViewEdge of the current list starts a new chain. The chaining
+ * operator then iterates over the ViewEdges of the ViewMap using the
+ * user specified iterator.
+ * This operator only iterates using the increment operator and is
+ * therefore unidirectional.
+ * \param it
+ * The iterator on the ViewEdges of the ViewMap. It contains
+ * the chaining rule.
+ * \param pred
+ * The predicate on the ViewEdge that expresses the stopping
+ * condition.
+ * \param modifier
+ * A function that takes a ViewEdge as argument and that
+ * is used to modify the processed ViewEdge state (the timestamp
+ * incrementation is a typical illustration of such a modifier)
+ */
+ static void chain(ViewEdgeInternal::ViewEdgeIterator& it,
+ UnaryPredicate1D& pred,
+ UnaryFunction1D<void>& modifier);
+
+ /*! Builds a set of chains from the current set of ViewEdges.
+ * Each ViewEdge of the current list starts a new chain. The chaining
+ * operator then iterates over the ViewEdges of the ViewMap using the
+ * user specified iterator.
+ * This operator only iterates using the increment operator and is
+ * therefore unidirectional.
+ * This chaining operator is different from the previous one because
+ * it doesn't take any modifier as argument. Indeed, the time stamp (insuring
+ * that a ViewEdge is processed one time) is automatically managed in this case.
+ * \param it
+ * The iterator on the ViewEdges of the ViewMap. It contains
+ * the chaining rule.
+ * \param pred
+ * The predicate on the ViewEdge that expresses the stopping
+ * condition.
+ */
+ static void chain(ViewEdgeInternal::ViewEdgeIterator& it,
+ UnaryPredicate1D& pred);
+
+ /*! Builds a set of chains from the current set of ViewEdges.
+ * Each ViewEdge of the current list potentially starts a new chain. The chaining
+ * operator then iterates over the ViewEdges of the ViewMap using the
+ * user specified iterator.
+ * This operator iterates both using the increment and decrement operators and is
+ * therefore bidirectional.
+ * This operator works with a ChainingIterator which contains the
+ * chaining rules. It is this last one which can be told
+ * to chain only edges that belong to the selection or not to
+ * process twice a ViewEdge during the chaining.
+ * Each time a ViewEdge is added to a chain, its chaining time stamp
+ * is incremented. This allows you to keep track of
+ * the number of chains to which a ViewEdge belongs to.
+ * \param it
+ * The ChainingIterator on the ViewEdges of the ViewMap. It contains
+ * the chaining rule.
+ * \param pred
+ * The predicate on the ViewEdge that expresses the stopping
+ * condition.
+ */
+ static void bidirectionalChain(ChainingIterator& it, UnaryPredicate1D& pred);
+
+ /*! The only difference with the above bidirectional chaining algorithm is
+ * that we don't need to pass a stopping criterion. This might be desirable
+ * when the stopping criterion is already contained in the iterator
+ * definition.
+ * Builds a set of chains from the current set of ViewEdges.
+ * Each ViewEdge of the current list potentially starts a new chain. The chaining
+ * operator then iterates over the ViewEdges of the ViewMap using the
+ * user specified iterator.
+ * This operator iterates both using the increment and decrement operators and is
+ * therefore bidirectional.
+ * This operator works with a ChainingIterator which contains the
+ * chaining rules. It is this last one which can be told
+ * to chain only edges that belong to the selection or not to
+ * process twice a ViewEdge during the chaining.
+ * Each time a ViewEdge is added to a chain, its chaining time stamp
+ * is incremented. This allows you to keep track of
+ * the number of chains to which a ViewEdge belongs to.
+ * \param it
+ * The ChainingIterator on the ViewEdges of the ViewMap. It contains
+ * the chaining rule.
+ */
+ static void bidirectionalChain(ChainingIterator& it);
+
+ /*! Splits each chain of the current set of chains in a sequential way.
+ * The points of each chain are processed (with a specified sampling) sequentially.
+ * Each time a user specified starting condition is verified, a new chain begins and
+ * ends as soon as a user-defined stopping predicate is verified.
+ * This allows chains overlapping rather than chains partitioning.
+ * The first point of the initial chain is the first point of one of the
+ * resulting chains.
+ * The splitting ends when no more chain can start.
+ * \param startingPred
+ * The predicate on a point that expresses the starting
+ * condition
+ * \param stoppingPred
+ * The predicate on a point that expresses the stopping
+ * condition
+ * \param sampling
+ * The resolution used to sample the chain for the predicates
+ * evaluation. (The chain is not actually resampled, a virtual point
+ * only progresses along the curve using this resolution)
+ */
+ static void sequentialSplit(UnaryPredicate0D& startingPred, UnaryPredicate0D& stoppingPred,
+ float sampling = 0.f);
+
+ /*! Splits each chain of the current set of chains in a sequential way.
+ * The points of each chain are processed (with a specified sampling) sequentially
+ * and each time a user specified condition is verified, the chain is split into two chains.
+ * The resulting set of chains is a partition of the initial chain
+ * \param pred
+ * The predicate on a point that expresses the splitting
+ * condition
+ * \param sampling
+ * The resolution used to sample the chain for the predicate
+ * evaluation. (The chain is not actually resampled, a virtual point
+ * only progresses along the curve using this resolution)
+ */
+ static void sequentialSplit(UnaryPredicate0D& pred,
+ float sampling = 0.f);
+
+ /*! Splits the current set of chains in a recursive way.
+ * We process the points of each chain (with a specified sampling) to find
+ * the point minimizing a specified function. The chain is split in two at this
+ * point and the two new chains are processed in the same way.
+ * The recursivity level is controlled through a predicate 1D that expresses a stopping condition
+ * on the chain that is about to be processed.
+ * \param func
+ * The Unary Function evaluated at each point of the chain.
+ * The splitting point is the point minimizing this function
+ * \param pred
+ * The Unary Predicate ex pressing the recursivity stopping condition.
+ * This predicate is evaluated for each curve before it actually gets
+ * split. If pred(chain) is true, the curve won't be split anymore.
+ * \param sampling
+ * The resolution used to sample the chain for the predicates
+ * evaluation. (The chain is not actually resampled, a virtual point
+ * only progresses along the curve using this resolution)
+ */
+ static void recursiveSplit(UnaryFunction0D<double>& func, UnaryPredicate1D& pred, float sampling = 0);
+
+ /*! Splits the current set of chains in a recursive way.
+ * We process the points of each chain (with a specified sampling) to find
+ * the point minimizing a specified function. The chain is split in two at this
+ * point and the two new chains are processed in the same way.
+ * The user can specify a 0D predicate to make a first selection
+ * on the points that can potentially be split.
+ * A point that doesn't verify the 0D predicate won't be candidate
+ * in realizing the min.
+ * The recursivity level is controlled through a predicate 1D that expresses a stopping condition
+ * on the chain that is about to be processed.
+ * \param func
+ * The Unary Function evaluated at each point of the chain.
+ * The splitting point is the point minimizing this function
+ * \param pred0d
+ * The Unary Predicate 0D used to select the candidate points
+ * where the split can occur.
+ * For example, it is very likely that would rather have
+ * your chain splitting around its middle point than around
+ * one of its extremities. A 0D predicate working on
+ * the curvilinear abscissa allows to add this kind of constraints.
+ * \param pred
+ * The Unary Predicate ex pressing the recursivity stopping condition.
+ * This predicate is evaluated for each curve before it actually gets
+ * split. If pred(chain) is true, the curve won't be split anymore.
+ * \param sampling
+ * The resolution used to sample the chain for the predicates
+ * evaluation. (The chain is not actually resampled, a virtual point
+ * only progresses along the curve using this resolution)
+ *
+ */
+ static void recursiveSplit(UnaryFunction0D<double>& func, UnaryPredicate0D& pred0d, UnaryPredicate1D& pred, float sampling = 0);
+
+ /*! Sorts the current set of chains (or viewedges) according to the
+ * comparison predicate given as argument.
+ * \param pred
+ * The binary predicate used for the comparison
+ */
+ static void sort(BinaryPredicate1D& pred);
+
+ /*! Creates and shades the strokes from the current set of chains.
+ * A predicate can be specified to make a selection pass on the
+ * chains.
+ * \param pred
+ * The predicate that a chain must verify in order to
+ * be transform as a stroke
+ * \param shaders
+ * The list of shaders used to shade the strokes
+ */
+ static void create(UnaryPredicate1D& pred, vector<StrokeShader*> shaders);
+
+ //
+ // Data access
+ //
+ ////////////////////////////////////////////////
+
+ static ViewEdge* getViewEdgeFromIndex(unsigned i) {
+ return dynamic_cast<ViewEdge*>(_current_view_edges_set[i]);
+ }
+
+ static Chain* getChainFromIndex(unsigned i) {
+ return dynamic_cast<Chain*>(_current_chains_set[i]);
+ }
+
+ static Stroke* getStrokeFromIndex(unsigned i) {
+ return _current_strokes_set[i];
+ }
+
+ static unsigned getViewEdgesSize() {
+ return _current_view_edges_set.size();
+ }
+
+ static unsigned getChainsSize() {
+ return _current_chains_set.size();
+ }
+
+ static unsigned getStrokesSize() {
+ return _current_strokes_set.size();
+ }
+
+ //
+ // Not exported in Python
+ //
+ //////////////////////////////////////////////////
+
+ static StrokesContainer* getStrokesSet() {
+ return &_current_strokes_set;
+ }
+
+ static void reset();
+
+private:
+
+ Operators() {}
+
+ static I1DContainer _current_view_edges_set;
+ static I1DContainer _current_chains_set;
+ static I1DContainer* _current_set;
+ static StrokesContainer _current_strokes_set;
+};
+
+#endif // OPERATORS_H
diff --git a/source/blender/freestyle/intern/stroke/PSStrokeRenderer.cpp b/source/blender/freestyle/intern/stroke/PSStrokeRenderer.cpp
new file mode 100755
index 00000000000..dc9c94e0e11
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/PSStrokeRenderer.cpp
@@ -0,0 +1,89 @@
+
+//
+// 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 "PSStrokeRenderer.h"
+# include "Canvas.h"
+
+PSStrokeRenderer::PSStrokeRenderer(const char* iFileName)
+:StrokeRenderer(){
+ if(!iFileName)
+ iFileName = "freestyle.ps";
+ // open the stream:
+ _ofstream.open(iFileName, ios::out);
+ if(!_ofstream.is_open()){
+ cerr << "couldn't open the output file " << iFileName << endl;
+ }
+ _ofstream << "%!PS-Adobe-2.0 EPSF-2.0" << endl;
+ _ofstream << "%%Creator: Freestyle (http://artis.imag.fr/Software/Freestyle)" << endl;
+ _ofstream << "%%BoundingBox: " << 0 << " "<< 0 << " " << Canvas::getInstance()->width() << " " << Canvas::getInstance()->height() << endl;
+ _ofstream << "%%EndComments" << endl;
+}
+
+PSStrokeRenderer::~PSStrokeRenderer(){
+ Close();
+}
+
+void PSStrokeRenderer::RenderStrokeRep(StrokeRep *iStrokeRep) const{
+ RenderStrokeRepBasic(iStrokeRep);
+}
+
+void PSStrokeRenderer::RenderStrokeRepBasic(StrokeRep *iStrokeRep) const{
+ vector<Strip*>& strips = iStrokeRep->getStrips();
+ Strip::vertex_container::iterator v[3];
+ StrokeVertexRep *svRep[3];
+ Vec3r color[3];
+ for(vector<Strip*>::iterator s=strips.begin(), send=strips.end();
+ s!=send;
+ ++s){
+ Strip::vertex_container& vertices = (*s)->vertices();
+ v[0] = vertices.begin();
+ v[1] = v[0];++(v[1]);
+ v[2] = v[1]; ++(v[2]);
+
+ while(v[2]!=vertices.end()){
+ svRep[0] = *(v[0]);
+ svRep[1] = *(v[1]);
+ svRep[2] = *(v[2]);
+
+ color[0] = svRep[0]->color();
+ //color[1] = svRep[1]->color();
+ //color[2] = svRep[2]->color();
+
+ _ofstream << "newpath" << endl;
+ _ofstream << (color[0])[0] << " " << (color[0])[1] << " " << (color[0])[2] << " setrgbcolor" <<endl;
+ _ofstream << svRep[0]->point2d()[0] << " " <<svRep[0]->point2d()[1] << " moveto" << endl;
+ _ofstream << svRep[1]->point2d()[0] << " " <<svRep[1]->point2d()[1] << " lineto" << endl;
+ _ofstream << svRep[2]->point2d()[0] << " " <<svRep[2]->point2d()[1] << " lineto" << endl;
+ _ofstream << "closepath" << endl;
+ _ofstream << "fill" << endl;
+
+ ++v[0];
+ ++v[1];
+ ++v[2];
+ }
+ }
+}
+
+void PSStrokeRenderer::Close(){
+ if(_ofstream.is_open())
+ _ofstream.close();
+}
+
diff --git a/source/blender/freestyle/intern/stroke/PSStrokeRenderer.h b/source/blender/freestyle/intern/stroke/PSStrokeRenderer.h
new file mode 100755
index 00000000000..821c016ab91
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/PSStrokeRenderer.h
@@ -0,0 +1,63 @@
+//
+// Filename : PSStrokeRenderer.h
+// Author(s) : Stephane Grabli
+// Purpose : Class to define the Postscript rendering of a stroke
+// Date of creation : 10/26/2004
+//
+///////////////////////////////////////////////////////////////////////////////
+
+
+//
+// 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef PSSTROKERENDERER_H
+# define PSSTROKERENDERER_H
+
+# include "../system/FreestyleConfig.h"
+# include "StrokeRenderer.h"
+# include <fstream>
+
+/**********************************/
+/* */
+/* */
+/* PSStrokeRenderer */
+/* */
+/* */
+/**********************************/
+
+class LIB_STROKE_EXPORT PSStrokeRenderer : public StrokeRenderer
+{
+public:
+ PSStrokeRenderer(const char * iFileName = 0);
+ virtual ~PSStrokeRenderer();
+
+ /*! Renders a stroke rep */
+ virtual void RenderStrokeRep(StrokeRep *iStrokeRep) const;
+ virtual void RenderStrokeRepBasic(StrokeRep *iStrokeRep) const;
+
+ /*! Closes the output PS file */
+ void Close();
+
+protected:
+ mutable ofstream _ofstream;
+};
+
+#endif // PSSTROKERENDERER_H
+
diff --git a/source/blender/freestyle/intern/stroke/Predicates0D.h b/source/blender/freestyle/intern/stroke/Predicates0D.h
new file mode 100755
index 00000000000..4c2dfacdf98
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/Predicates0D.h
@@ -0,0 +1,160 @@
+//
+// Filename : Predicates0D.h
+// Author(s) : Stephane Grabli, Emmanuel Turquin
+// Purpose : Class gathering stroke creation algorithms
+// Date of creation : 01/07/2003
+//
+///////////////////////////////////////////////////////////////////////////////
+
+
+//
+// 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef PREDICATES0D_H
+# define PREDICATES0D_H
+
+# include "../view_map/Functions0D.h"
+
+//
+// UnaryPredicate0D (base class for predicates in 0D)
+//
+///////////////////////////////////////////////////////////
+/*! Base class for Unary Predicates that work
+ * on Interface0DIterator.
+ * A UnaryPredicate0D is a functor that evaluates
+ * a condition on a Interface0DIterator and returns
+ * true or false depending on whether this condition is
+ * satisfied or not.
+ * The UnaryPredicate0D is used by calling its () operator.
+ * Any inherited class must overload the () operator.
+ */
+class UnaryPredicate0D
+{
+public:
+ /*! Default constructor. */
+ UnaryPredicate0D() {}
+ /*! Destructor. */
+ virtual ~UnaryPredicate0D() {}
+ /*! Returns the string of the name
+ * of the UnaryPredicate0D.
+ */
+ virtual string getName() const {
+ return "UnaryPredicate0D";
+ }
+ /*! The () operator. Must be overload
+ * by inherited classes.
+ * \param it
+ * The Interface0DIterator pointing onto the
+ * Interface0D at which we wish to evaluate
+ * the predicate.
+ * \return true if the condition is satisfied,
+ * false otherwise.
+ */
+ virtual bool operator()(Interface0DIterator& it) {
+ cerr << "Warning: operator() not implemented" << endl;
+ return false;
+ }
+};
+
+
+//
+// BinaryPredicate0D (base class for predicates in 0D)
+//
+///////////////////////////////////////////////////////////
+/*! Base class for Binary Predicates working on Interface0D.
+ * A BinaryPredicate0D is typically an ordering relation
+ * between two Interface0D.
+ * It evaluates a relation between 2 Interface0D and
+ * returns true or false.
+ * It is used by calling the () operator.
+ */
+class BinaryPredicate0D
+{
+public:
+ /*! Default constructor. */
+ BinaryPredicate0D() {}
+ /*! Destructor. */
+ virtual ~BinaryPredicate0D() {}
+ /*! Returns the string of the name of the
+ * binary predicate.
+ */
+ virtual string getName() const {
+ return "BinaryPredicate0D";
+ }
+
+ /*! The () operator. Must be overload by inherited classes.
+ * It evaluates a relation between 2 Interface0D.
+ * \param inter1
+ * The first Interface0D.
+ * \param inter2
+ * The second Interface0D.
+ * \return true or false.
+ */
+ virtual bool operator()(Interface0D& inter1, Interface0D& inter2) {
+ cerr << "Warning: operator() not implemented" << endl;
+ return false;
+ }
+};
+
+
+//
+// Predicates definitions
+//
+///////////////////////////////////////////////////////////
+
+namespace Predicates0D {
+
+ // TrueUP0D
+ /*! Returns true any time */
+ class TrueUP0D : public UnaryPredicate0D
+ {
+ public:
+ /*! Default constructor. */
+ TrueUP0D() {}
+ /*! Returns the string "TrueUP0D"*/
+ string getName() const {
+ return "TrueUP0D";
+ }
+ /*! The () operator. */
+ bool operator()(Interface0DIterator&) {
+ return true;
+ }
+ };
+
+ // FalseUP0D
+ /*! Returns false any time */
+ class FalseUP0D : public UnaryPredicate0D
+ {
+ public:
+ /*! Default constructor. */
+ FalseUP0D() {}
+ /*! Returns the string "FalseUP0D"*/
+ string getName() const {
+ return "FalseUP0D";
+ }
+ /*! The () operator. */
+ bool operator()(Interface0DIterator&) {
+ return false;
+ }
+ };
+
+} // end of namespace Predicates0D
+
+#endif // PREDICATES0D_H
diff --git a/source/blender/freestyle/intern/stroke/Predicates1D.h b/source/blender/freestyle/intern/stroke/Predicates1D.h
new file mode 100755
index 00000000000..cf9a3283ae4
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/Predicates1D.h
@@ -0,0 +1,438 @@
+//
+// Filename : Predicates1D.h
+// Author(s) : Stephane Grabli, Emmanuel Turquin
+// Purpose : Class gathering stroke creation algorithms
+// Date of creation : 01/07/2003
+//
+///////////////////////////////////////////////////////////////////////////////
+
+
+//
+// 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef PREDICATES1D_H
+# define PREDICATES1D_H
+
+# include <string>
+# include "../system/TimeStamp.h"
+# include "../view_map/Interface1D.h"
+# include "../view_map/Functions1D.h"
+# include "AdvancedFunctions1D.h"
+
+//
+// UnaryPredicate1D (base class for predicates in 1D)
+//
+///////////////////////////////////////////////////////////
+/*! Base class for Unary Predicates that work
+ * on Interface1D.
+ * A UnaryPredicate1D is a functor that evaluates
+ * a condition on a Interface1D and returns
+ * true or false depending on whether this condition is
+ * satisfied or not.
+ * The UnaryPredicate1D is used by calling its () operator.
+ * Any inherited class must overload the () operator.
+ */
+class UnaryPredicate1D
+{
+public:
+ /*! Default constructor. */
+ UnaryPredicate1D() {}
+ /*! Destructor. */
+ virtual ~UnaryPredicate1D() {}
+ /*! Returns the string of the name
+ * of the UnaryPredicate1D.
+ */
+ virtual string getName() const {
+ return "UnaryPredicate1D";
+ }
+ /*! The () operator. Must be overload
+ * by inherited classes.
+ * \param inter
+ * The Interface1D on which we wish to evaluate
+ * the predicate.
+ * \return true if the condition is satisfied,
+ * false otherwise.
+ */
+ virtual bool operator()(Interface1D& inter) {
+ cerr << "Warning: operator() not implemented" << endl;
+ return false;
+ }
+};
+
+
+//
+// BinaryPredicate1D (base class for predicates in 1D)
+//
+///////////////////////////////////////////////////////////
+/*! Base class for Binary Predicates working on Interface1D.
+ * A BinaryPredicate1D is typically an ordering relation
+ * between two Interface1D.
+ * It evaluates a relation between 2 Interface1D and
+ * returns true or false.
+ * It is used by calling the () operator.
+ */
+class BinaryPredicate1D
+{
+public:
+ /*! Default constructor. */
+ BinaryPredicate1D() {}
+ /*! Destructor. */
+ virtual ~BinaryPredicate1D() {}
+ /*! Returns the string of the name of the
+ * binary predicate.
+ */
+ virtual string getName() const {
+ return "BinaryPredicate1D";
+ }
+ /*! The () operator. Must be overload by inherited classes.
+ * It evaluates a relation between 2 Interface1D.
+ * \param inter1
+ * The first Interface1D.
+ * \param inter2
+ * The second Interface1D.
+ * \return true or false.
+ */
+ virtual bool operator()(Interface1D& inter1, Interface1D& inter2) {
+ cerr << "Warning: operator() not implemented" << endl;
+ return false;
+ }
+};
+
+
+//
+// Predicates definitions
+//
+///////////////////////////////////////////////////////////
+
+namespace Predicates1D {
+
+ // TrueUP1D
+ /*! Returns true */
+ class TrueUP1D : public UnaryPredicate1D
+ {
+ public:
+ /*! Constructor */
+ TrueUP1D() {}
+ /*! Returns the string "TrueUP1D"*/
+ string getName() const {
+ return "TrueUP1D";
+ }
+ /*! the () operator */
+ bool operator()(Interface1D&) {
+ return true;
+ }
+ };
+
+ // FalseUP1D
+ /*! Returns false */
+ class FalseUP1D : public UnaryPredicate1D
+ {
+ public:
+ /*! Constructor */
+ FalseUP1D() {}
+ /*! Returns the string "FalseUP1D"*/
+ string getName() const {
+ return "FalseUP1D";
+ }
+ /*! the () operator */
+ bool operator()(Interface1D&) {
+ return false;
+ }
+ };
+
+ // QuantitativeInvisibilityUP1D
+ /*! Returns true if the Quantitative Invisibility evaluated
+ * at an Interface1D, using the QuantitativeInvisibilityF1D
+ * functor, equals a certain user-defined value.
+ */
+ class QuantitativeInvisibilityUP1D : public UnaryPredicate1D
+ {
+ public:
+ /*! Builds the Predicate.
+ * \param qi
+ * The Quantitative Invisibility you want
+ * the Interface1D to have
+ */
+ QuantitativeInvisibilityUP1D(unsigned qi = 0) : _qi(qi) {}
+ /*! Returns the string "QuantitativeInvisibilityUP1D"*/
+ string getName() const {
+ return "QuantitativeInvisibilityUP1D";
+ }
+ /*! the () operator */
+ bool operator()(Interface1D& inter) {
+ Functions1D::QuantitativeInvisibilityF1D func;
+ return (func(inter) == _qi);
+ }
+ private:
+ unsigned _qi;
+ };
+
+ // ContourUP1D
+ /*! Returns true if the Interface1D is a contour.
+ * An Interface1D is a contour if it is borded
+ * by a different shape on each of its sides.
+ */
+ class ContourUP1D : public UnaryPredicate1D
+ {
+ private:
+ Functions1D::CurveNatureF1D _getNature;
+ public:
+ /*! Returns the string "ContourUP1D"*/
+ string getName() const {
+ return "ContourUP1D";
+ }
+ /*! The () operator. */
+ bool operator()(Interface1D& inter) {
+ if((_getNature(inter) & Nature::SILHOUETTE) || (_getNature(inter) & Nature::BORDER)){
+ Interface0DIterator it=inter.verticesBegin();
+ for(; !it.isEnd(); ++it){
+ if(Functions0D::getOccludeeF0D(it) != Functions0D::getShapeF0D(it))
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+
+ // ExternalContourUP1D
+ /*! Returns true if the Interface1D is an external contour.
+ * An Interface1D is an external contour if it is borded
+ * by no shape on one of its sides.
+ */
+ class ExternalContourUP1D : public UnaryPredicate1D
+ {
+ private:
+ Functions1D::CurveNatureF1D _getNature;
+ public:
+ /*! Returns the string "ExternalContourUP1D"*/
+ string getName() const {
+ return "ExternalContourUP1D";
+ }
+ /*! The () operator. */
+ bool operator()(Interface1D& inter) {
+ if((_getNature(inter) & Nature::SILHOUETTE) || (_getNature(inter) & Nature::BORDER)){
+ set<ViewShape*> occluded;
+ Functions1D::getOccludeeF1D(inter, occluded);
+ for(set<ViewShape*>::iterator os=occluded.begin(), osend=occluded.end();
+ os!=osend;
+ ++os){
+ if((*os) == 0)
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+
+ // EqualToTimeStampUP1D
+ /*! Returns true if the Interface1D's time stamp
+ * is equal to a certain user-defined value.
+ */
+ class EqualToTimeStampUP1D : public UnaryPredicate1D
+ {
+ protected:
+ unsigned _timeStamp;
+ public:
+ EqualToTimeStampUP1D(unsigned ts) : UnaryPredicate1D(){
+ _timeStamp = ts;
+ }
+ /*! Returns the string "EqualToTimeStampUP1D"*/
+ string getName() const {
+ return "EqualToTimeStampUP1D";
+ }
+ /*! The () operator. */
+ bool operator()(Interface1D& inter) {
+ return (inter.getTimeStamp() == _timeStamp);
+ }
+ };
+
+ // EqualToChainingTimeStampUP1D
+ /*! Returns true if the Interface1D's time stamp
+ * is equal to a certain user-defined value.
+ */
+ class EqualToChainingTimeStampUP1D : public UnaryPredicate1D
+ {
+ protected:
+ unsigned _timeStamp;
+ public:
+ EqualToChainingTimeStampUP1D(unsigned ts) : UnaryPredicate1D(){
+ _timeStamp = ts;
+ }
+ /*! Returns the string "EqualToChainingTimeStampUP1D"*/
+ string getName() const {
+ return "EqualToChainingTimeStampUP1D";
+ }
+ /*! The () operator. */
+ bool operator()(Interface1D& inter) {
+ ViewEdge* edge = dynamic_cast<ViewEdge*>(&inter);
+ if (!edge)
+ return false;
+ return (edge->getChainingTimeStamp() >= _timeStamp);
+ }
+ };
+
+ // ShapeUP1D
+ /*! Returns true if the shape to which the Interface1D
+ * belongs to has the same Id as the one specified by the
+ * user.
+ */
+ class ShapeUP1D: public UnaryPredicate1D
+ {
+ private:
+ Id _id;
+ public:
+ /*! Builds the Predicate.
+ * \param idFirst
+ * The first Id component.
+ * \param idSecond
+ * The second Id component.
+ */
+ ShapeUP1D(unsigned idFirst, unsigned idSecond=0)
+ : UnaryPredicate1D(){
+ _id = Id(idFirst, idSecond);
+ }
+ /*! Returns the string "ShapeUP1D"*/
+ string getName() const {
+ return "ShapeUP1D";
+ }
+ /*! The () operator. */
+ bool operator()(Interface1D& inter) {
+ set<ViewShape*> shapes;
+ Functions1D::getShapeF1D(inter, shapes);
+ for(set<ViewShape*>::iterator s=shapes.begin(), send=shapes.end();
+ s!=send;
+ ++s){
+ if((*s)->getId() == _id)
+ return true;
+ }
+ return false;
+ }
+ };
+
+ //
+ // Binary Predicates definitions
+ //
+ ///////////////////////////////////////////////////////////
+
+ // TrueBP1D
+ /*! Returns true. */
+ class TrueBP1D : public BinaryPredicate1D
+ {
+ public:
+ /*! Returns the string "TrueBP1D"*/
+ string getName() const {
+ return "TrueBP1D";
+ }
+ /*! The () operator. */
+ bool operator()(Interface1D& i1, Interface1D& i2) {
+ return true;
+ }
+ };
+
+ // FalseBP1D
+ /*! Returns false. */
+ class FalseBP1D : public BinaryPredicate1D
+ {
+ public:
+ /*! Returns the string "FalseBP1D"*/
+ string getName() const {
+ return "FalseBP1D";
+ }
+ /*! The () operator. */
+ bool operator()(Interface1D& i1, Interface1D& i2) {
+ return false;
+ }
+ };
+
+ // Length2DBP1D
+ /*! Returns true if the 2D length of the Interface1D i1
+ * is less than the 2D length of the Interface1D i2.
+ */
+ class Length2DBP1D : public BinaryPredicate1D
+ {
+ public:
+ /*! Returns the string "Length2DBP1D"*/
+ string getName() const {
+ return "Length2DBP1D";
+ }
+ /*! The () operator. */
+ bool operator()(Interface1D& i1, Interface1D& i2) {
+ return (i1.getLength2D() > i2.getLength2D());
+ }
+ };
+
+ // SameShapeIdBP1D
+ /*! Returns true if the Interface1D i1 and i2 belong
+ * to the same shape.
+ */
+ class SameShapeIdBP1D : public BinaryPredicate1D
+ {
+ public:
+ /*! Returns the string "SameShapeIdBP1D"*/
+ string getName() const {
+ return "SameShapeIdBP1D";
+ }
+ /*! The () operator. */
+ bool operator()(Interface1D& i1, Interface1D& i2) {
+ set<ViewShape*> shapes1;
+ Functions1D::getShapeF1D(i1, shapes1);
+ set<ViewShape*> shapes2;
+ Functions1D::getShapeF1D(i2, shapes2);
+ // FIXME:// n2 algo, can do better...
+ for(set<ViewShape*>::iterator s=shapes1.begin(), send=shapes1.end();
+ s!=send;
+ ++s){
+ Id current = (*s)->getId();
+ for(set<ViewShape*>::iterator s2=shapes2.begin(), s2end=shapes2.end();
+ s2!=s2end;
+ ++s2){
+ if((*s2)->getId() == current)
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+
+ // ViewMapGradientNormBP1D
+ /*! Returns true if the evaluation of the
+ * Gradient norm Function is higher for Interface1D i1
+ * than for i2.
+ */
+ class ViewMapGradientNormBP1D : public BinaryPredicate1D
+ {
+ private:
+ Functions1D::GetViewMapGradientNormF1D _func;
+ public:
+ ViewMapGradientNormBP1D(int level, IntegrationType iType=MEAN, float sampling=2.0)
+ : BinaryPredicate1D(), _func(level, iType, sampling) {
+ }
+ /*! Returns the string "ViewMapGradientNormBP1D"*/
+ string getName() const {
+ return "ViewMapGradientNormBP1D";
+ }
+ /*! The () operator. */
+ bool operator()(Interface1D& i1, Interface1D& i2) {
+ return (_func(i1) > _func(i2));
+ }
+ };
+} // end of namespace Predicates1D
+
+#endif // PREDICATES1D_H
diff --git a/source/blender/freestyle/intern/stroke/QInformationMap.h b/source/blender/freestyle/intern/stroke/QInformationMap.h
new file mode 100755
index 00000000000..2542bdba147
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/QInformationMap.h
@@ -0,0 +1,58 @@
+//
+// Filename : QInformationMap.h
+// Author : Stephane Grabli
+// Purpose : Class defining an information map using a QImage
+// Date of creation : 04/01/2003
+//
+///////////////////////////////////////////////////////////////////////////////
+
+
+//
+// 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef QINFORMATIONMAP_H
+# define QINFORMATIONMAP_H
+
+# include <qimage.h>
+# include "InformationMap.h"
+
+class QInformationMap : public InformationMap
+{
+private:
+ QImage _map; // the image or a piece of image
+
+public:
+ QInformationMap();
+ QInformationMap(const QImage&);
+ QInformationMap(const QInformationMap&);
+ QInformationMap& operator=(const QInformationMap&);
+
+ //float getSmoothedPixel(int x, int y, float sigma = 0.2f)
+ virtual float getMean(int x, int y) ;
+ virtual void retrieveMeanAndVariance(int x, int y, float &oMean, float &oVariance) ;
+
+ inline const QImage& map() const {return _map;}
+ inline void SetMap(const QImage& iMap, float iw, float ih) {_map = iMap.copy();_w=iw;_h=ih;}
+
+protected:
+ virtual float computeGaussian(int x, int y);
+};
+
+#endif // QINFORMATIONMAP_H
diff --git a/source/blender/freestyle/intern/stroke/Stroke.cpp b/source/blender/freestyle/intern/stroke/Stroke.cpp
new file mode 100755
index 00000000000..d6ff4d255c4
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/Stroke.cpp
@@ -0,0 +1,949 @@
+
+//
+// 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 "Stroke.h"
+#include "StrokeRenderer.h"
+#include "StrokeIterators.h"
+#include "StrokeAdvancedIterators.h"
+
+ /**********************************/
+ /* */
+ /* */
+ /* StrokeAttribute */
+ /* */
+ /* */
+ /**********************************/
+
+StrokeAttribute::StrokeAttribute()
+{
+ int i;
+ _alpha = 1.f;
+ _thickness[0] = 1.f;
+ _thickness[1] = 1.f;
+ for(i=0; i<3; ++i)
+ _color[i] = 0.2f;
+ _color[0]=0.8;
+ _userAttributesReal = 0;
+ _userAttributesVec2f = 0;
+ _userAttributesVec3f = 0;
+ _visible = true;
+}
+StrokeAttribute::StrokeAttribute(const StrokeAttribute& iBrother)
+{
+ _alpha = iBrother._alpha;
+ _thickness[0] = iBrother._thickness[0];
+ _thickness[1] = iBrother._thickness[1];
+ for(int i=0; i<3; ++i)
+ _color[i] = iBrother._color[i];
+ _visible = iBrother._visible;
+ if(iBrother._userAttributesReal)
+ _userAttributesReal = new realMap(*iBrother._userAttributesReal);
+ else
+ _userAttributesReal = 0;
+ if(iBrother._userAttributesVec2f)
+ _userAttributesVec2f = new Vec2fMap(*iBrother._userAttributesVec2f);
+ else
+ _userAttributesVec2f = 0;
+ if(iBrother._userAttributesVec3f)
+ _userAttributesVec3f = new Vec3fMap(*iBrother._userAttributesVec3f);
+ else
+ _userAttributesVec3f = 0;
+}
+StrokeAttribute::StrokeAttribute( float iRColor, float iGColor, float iBColor,
+ float iAlpha,
+ float iRThickness, float iLThickness)
+{
+ _color[0] = iRColor;
+ _color[1] = iGColor;
+ _color[2] = iBColor;
+
+ _alpha = iAlpha;
+
+ _thickness[0] = iRThickness;
+ _thickness[1] = iLThickness;
+
+ _visible = true;
+
+ _userAttributesReal = 0;
+ _userAttributesVec2f = 0;
+ _userAttributesVec3f = 0;
+}
+StrokeAttribute::StrokeAttribute(const StrokeAttribute& a1, const StrokeAttribute& a2, float t)
+
+{
+
+ _alpha = (1-t)*a1._alpha + t*a2._alpha;
+ _thickness[0] = (1-t)*a1._thickness[0] + t*a2._thickness[0];
+ _thickness[1] = (1-t)*a1._thickness[1] + t*a2._thickness[1];
+ for(int i=0; i<3; ++i)
+ _color[i] = (1-t)*a1._color[i] + t*a2._color[i];
+
+ _visible = true;
+
+ // FIXME: a verifier (et a ameliorer)
+ if((a1._userAttributesReal) && (a2._userAttributesReal)){
+ if(a1._userAttributesReal->size() == a2._userAttributesReal->size()){
+ _userAttributesReal = new realMap;
+ realMap::iterator it1=a1._userAttributesReal->begin(), it1end=a1._userAttributesReal->end();
+ realMap::iterator it2=a2._userAttributesReal->begin(), it2end=a2._userAttributesReal->end();
+ for(; (it1!=it1end); ++it1){
+ (*_userAttributesReal)[(*it1).first] = ((1-t)*(*it1).second+t*(*it2).second);
+ }
+ }
+ }else{
+ _userAttributesReal = 0;
+ }
+ if((a1._userAttributesVec2f) && (a2._userAttributesVec2f)){
+ if(a1._userAttributesVec2f->size() == a2._userAttributesVec2f->size()){
+ _userAttributesVec2f = new Vec2fMap;
+ Vec2fMap::iterator it1=a1._userAttributesVec2f->begin(), it1end=a1._userAttributesVec2f->end();
+ Vec2fMap::iterator it2=a2._userAttributesVec2f->begin(), it2end=a2._userAttributesVec2f->end();
+ for(; (it1!=it1end); ++it1){
+ (*_userAttributesVec2f)[(*it1).first] = ((1-t)*(*it1).second+t*(*it2).second);
+ }
+ }
+ }else{
+ _userAttributesVec2f = 0;
+ }
+ if((a1._userAttributesVec3f) && (a2._userAttributesVec3f)){
+ if(a1._userAttributesVec3f->size() == a2._userAttributesVec3f->size()){
+ _userAttributesVec3f = new Vec3fMap;
+ Vec3fMap::iterator it1=a1._userAttributesVec3f->begin(), it1end=a1._userAttributesVec3f->end();
+ Vec3fMap::iterator it2=a2._userAttributesVec3f->begin(), it2end=a2._userAttributesVec3f->end();
+ for(; (it1!=it1end); ++it1){
+ (*_userAttributesVec3f)[(*it1).first] = ((1-t)*(*it1).second+t*(*it2).second);
+ }
+ }
+ }else{
+ _userAttributesVec3f = 0;
+ }
+
+}
+StrokeAttribute::~StrokeAttribute()
+{
+ if(_userAttributesReal){
+ _userAttributesReal->clear();
+ delete _userAttributesReal;
+ }
+ if(_userAttributesVec2f){
+ _userAttributesVec2f->clear();
+ delete _userAttributesVec2f;
+ }
+ if(_userAttributesVec3f){
+ _userAttributesVec3f->clear();
+ delete _userAttributesVec3f;
+ }
+}
+
+StrokeAttribute& StrokeAttribute::operator=(const StrokeAttribute& iBrother)
+{
+ int i;
+ _alpha = iBrother._alpha;
+ _thickness[0] = iBrother._thickness[0];
+ _thickness[1] = iBrother._thickness[1];
+ for(i=0; i<3; ++i)
+ _color[i] = iBrother._color[i];
+ _visible = iBrother._visible;
+ if(iBrother._userAttributesReal){
+ if(!_userAttributesReal)
+ _userAttributesReal = new realMap;
+ _userAttributesReal = new realMap(*(iBrother._userAttributesReal));
+ }else{
+ _userAttributesReal = 0;
+ }
+ if(iBrother._userAttributesVec2f){
+ if(!_userAttributesVec2f)
+ _userAttributesVec2f = new Vec2fMap;
+ _userAttributesVec2f = new Vec2fMap(*(iBrother._userAttributesVec2f));
+ }else{
+ _userAttributesVec2f = 0;
+ }
+ if(iBrother._userAttributesVec3f){
+ if(!_userAttributesVec3f)
+ _userAttributesVec3f = new Vec3fMap;
+ _userAttributesVec3f = new Vec3fMap(*(iBrother._userAttributesVec3f));
+ }else{
+ _userAttributesVec3f = 0;
+ }
+ return *this;
+}
+
+float StrokeAttribute::getAttributeReal(const char *iName) const{
+ if(!_userAttributesReal){
+ cout << "StrokeAttribute warning: no real attribute was defined"<< endl;
+ return 0;
+ }
+ realMap::iterator a = _userAttributesReal->find(iName);
+ if(a ==_userAttributesReal->end()){
+ cout << "StrokeAttribute warning: no real attribute was added with the name " << iName << endl;
+ return 0;
+ }
+ return (*a).second;
+}
+Vec2f StrokeAttribute::getAttributeVec2f(const char *iName) const{
+ if(!_userAttributesVec2f){
+ cout << "StrokeAttribute warning: no Vec2f attribute was defined "<< endl;
+ return 0;
+ }
+ Vec2fMap::iterator a = _userAttributesVec2f->find(iName);
+ if(a ==_userAttributesVec2f->end()){
+ cout << "StrokeAttribute warning: no Vec2f attribute was added with the name " << iName << endl;
+ return 0;
+ }
+ return (*a).second;
+}
+Vec3f StrokeAttribute::getAttributeVec3f(const char *iName) const{
+ if(!_userAttributesVec3f){
+ cout << "StrokeAttribute warning: no Vec3f attribute was defined"<< endl;
+ return 0;
+ }
+ Vec3fMap::iterator a = _userAttributesVec3f->find(iName);
+ if(a ==_userAttributesVec3f->end()){
+ cout << "StrokeAttribute warning: no Vec3f attribute was added with the name " << iName << endl;
+ return 0;
+ }
+ return (*a).second;
+}
+bool StrokeAttribute::isAttributeAvailableReal(const char *iName) const{
+ if(!_userAttributesReal){
+ return false;
+ }
+ realMap::iterator a = _userAttributesReal->find(iName);
+ if(a ==_userAttributesReal->end()){
+ return false;
+ }
+ return true;
+}
+bool StrokeAttribute::isAttributeAvailableVec2f(const char *iName) const{
+ if(!_userAttributesVec2f){
+ return false;
+ }
+ Vec2fMap::iterator a = _userAttributesVec2f->find(iName);
+ if(a ==_userAttributesVec2f->end()){
+ return false;
+ }
+ return true;
+}
+bool StrokeAttribute::isAttributeAvailableVec3f(const char *iName) const{
+ if(!_userAttributesVec3f){
+ return false;
+ }
+ Vec3fMap::iterator a = _userAttributesVec3f->find(iName);
+ if(a ==_userAttributesVec3f->end()){
+ return false;
+ }
+ return true;
+}
+void StrokeAttribute::setAttributeReal(const char *iName, float att){
+ if(!_userAttributesReal)
+ _userAttributesReal = new realMap;
+ (*_userAttributesReal)[iName] = att;
+}
+void StrokeAttribute::setAttributeVec2f(const char *iName, const Vec2f& att){
+ if(!_userAttributesVec2f)
+ _userAttributesVec2f = new Vec2fMap;
+ (*_userAttributesVec2f)[iName] = att;
+}
+void StrokeAttribute::setAttributeVec3f(const char *iName, const Vec3f& att){
+ if(!_userAttributesVec3f)
+ _userAttributesVec3f = new Vec3fMap;
+ (*_userAttributesVec3f)[iName] = att;
+}
+ /**********************************/
+ /* */
+ /* */
+ /* StrokeVertex */
+ /* */
+ /* */
+ /**********************************/
+
+StrokeVertex::StrokeVertex()
+
+:CurvePoint()
+{
+
+ _CurvilignAbscissa = 0.f;
+
+ _StrokeLength = 0.f;
+}
+
+
+
+StrokeVertex::StrokeVertex(const StrokeVertex& iBrother)
+
+:CurvePoint(iBrother)
+{
+ _Attribute = iBrother._Attribute;
+
+ _CurvilignAbscissa = 0.f;
+
+ _StrokeLength = 0.f;
+}
+StrokeVertex::StrokeVertex(SVertex *iSVertex)
+
+:CurvePoint(iSVertex,0,0.f)
+
+{
+
+ _CurvilignAbscissa = 0.f;
+
+ _StrokeLength = 0.f;
+
+}
+
+
+
+StrokeVertex::StrokeVertex(CurvePoint *iPoint)
+
+:CurvePoint(*iPoint)
+
+{
+
+ _CurvilignAbscissa = 0.f;
+
+ _StrokeLength = 0.f;
+
+}
+
+
+
+StrokeVertex::StrokeVertex(StrokeVertex *iA, StrokeVertex *iB, float t3)
+
+:CurvePoint(iA,iB,t3)
+
+{
+
+ // interpolate attributes:
+
+ _Attribute = StrokeAttribute(iA->attribute(), iB->attribute(), t3);
+ _CurvilignAbscissa = (1-t3)*iA->curvilinearAbscissa()+t3*iB->curvilinearAbscissa();
+ _StrokeLength = iA->strokeLength();
+
+}
+
+
+
+StrokeVertex::StrokeVertex(SVertex *iSVertex, const StrokeAttribute& iAttribute)
+
+:CurvePoint(iSVertex,0,0.f)
+
+{
+
+ _Attribute = iAttribute;
+
+ _CurvilignAbscissa = 0.f;
+
+ _StrokeLength = 0.f;
+
+}
+StrokeVertex::~StrokeVertex()
+{
+}
+
+StrokeVertex& StrokeVertex::operator=(const StrokeVertex& iBrother)
+{
+ ((CurvePoint*)this)->operator=(iBrother);
+ _Attribute = iBrother._Attribute;
+
+ _CurvilignAbscissa = 0.f;
+
+ _StrokeLength = 0.f;
+ return *this;
+}
+
+ /**********************************/
+ /* */
+ /* */
+ /* Stroke */
+ /* */
+ /* */
+ /**********************************/
+
+Stroke::Stroke()
+{
+ _Length = 0;
+ _id = 0;
+ _sampling = FLT_MAX;
+ //_mediumType = DEFAULT_STROKE;
+ _mediumType = OPAQUE_MEDIUM;
+ _textureId = 0;
+ _tips = false;
+ _rep = 0;
+}
+
+Stroke::Stroke(const Stroke& iBrother)
+{
+ for(vertex_container::const_iterator v=iBrother._Vertices.begin(), vend=iBrother._Vertices.end();
+ v!=vend;
+ v++)
+ {
+ _Vertices.push_back(*v);
+ }
+ _Length = 0;
+ _id = iBrother._id;
+ _ViewEdges = iBrother._ViewEdges;
+ _sampling = iBrother._sampling;
+ _mediumType = iBrother._mediumType;
+ _textureId = iBrother._textureId;
+ _tips = iBrother._tips;
+ _rep = new StrokeRep(*(iBrother._rep));
+}
+
+Stroke::~Stroke()
+{
+ if(!_Vertices.empty())
+ {
+ for(vertex_container::iterator v=_Vertices.begin(), vend=_Vertices.end();
+ v!=vend;
+ v++)
+ {
+ delete (*v);
+ }
+ _Vertices.clear();
+ }
+
+ _ViewEdges.clear();
+ if(_rep != 0)
+ {
+ delete _rep;
+ _rep = 0;
+ }
+}
+
+Stroke& Stroke::operator=(const Stroke& iBrother)
+{
+ if(!_Vertices.empty())
+ _Vertices.clear();
+
+ for(vertex_container::const_iterator v=iBrother._Vertices.begin(), vend=iBrother._Vertices.end();
+ v!=vend;
+ v++)
+ {
+ _Vertices.push_back(*v);
+ }
+ _Length = iBrother._Length;
+ _id = iBrother._id;
+ _ViewEdges = iBrother._ViewEdges;
+ _sampling = iBrother._sampling;
+ if(_rep) delete _rep;
+ if(iBrother._rep)
+ _rep = new StrokeRep(*(iBrother._rep));
+ return *this;
+}
+
+
+void Stroke::SetLength(float iLength)
+{
+ _Length = iLength;
+ for(vertex_container::iterator v=_Vertices.begin(), vend=_Vertices.end();
+ v!=vend;
+ ++v)
+ {
+ (*v)->SetStrokeLength(iLength);
+ }
+}
+
+float Stroke::ComputeSampling(int iNVertices)
+{
+ if(iNVertices <= _Vertices.size())
+ return _sampling;
+
+ float sampling = _Length/(float)(iNVertices-_Vertices.size()+1);
+ return sampling;
+}
+
+class StrokeSegment
+{
+public:
+ StrokeInternal::StrokeVertexIterator _begin;
+ StrokeInternal::StrokeVertexIterator _end;
+ float _length;
+ int _n;
+ float _sampling;
+ bool _resampled;
+
+ StrokeSegment(StrokeInternal::StrokeVertexIterator ibegin,
+ StrokeInternal::StrokeVertexIterator iend,
+ float ilength,
+ int in,
+ float isampling)
+ {
+ _begin=ibegin;
+ _end=iend;
+ _length=ilength;
+ _n=in;
+ _sampling = isampling;
+ _resampled = false;
+ }
+};
+
+void Stroke::Resample(int iNPoints)
+{
+ int vertsize = strokeVerticesSize();
+ if(iNPoints <= vertsize)
+ return;
+
+ StrokeInternal::StrokeVertexIterator it = strokeVerticesBegin();
+ StrokeInternal::StrokeVertexIterator next = it;++next;
+ StrokeInternal::StrokeVertexIterator itend = strokeVerticesEnd();
+
+ vertex_container newVertices;
+ real t=0.f;
+ StrokeVertex * newVertex = 0;
+ vector<StrokeSegment> strokeSegments;
+ int N=0;
+ float meanlength = 0;
+ int nsegments = 0;
+ while(((it!=itend)&&(next!=itend)))
+ {
+ Vec3r a((it)->point2d());
+ Vec3r b((next)->point2d());
+ Vec3r vec_tmp(b - a);
+ real norm_var = vec_tmp.norm();
+ int numberOfPointsToAdd = (int)floor((iNPoints-strokeVerticesSize())*norm_var/_Length);
+ float csampling = norm_var/(float)(numberOfPointsToAdd+1);
+ strokeSegments.push_back(StrokeSegment(it,next,norm_var,numberOfPointsToAdd, csampling));
+ N+=numberOfPointsToAdd;
+ meanlength += norm_var;
+ ++nsegments;
+ ++it; ++next;
+ }
+ meanlength /= (float)nsegments;
+
+ // if we don't have enough points let's resample
+ // finer some segments
+ int NPointsToAdd = iNPoints-vertsize;
+ bool checkEveryone = false;
+ while(N < NPointsToAdd)
+ {
+ for(vector<StrokeSegment>::iterator s=strokeSegments.begin(), send=strokeSegments.end();
+ s!=send;
+ ++s)
+ {
+ if(s->_sampling == 0.f)
+ continue;
+
+ if(s->_resampled == false)
+ {
+ if((!checkEveryone) && (s->_length < meanlength))
+ continue;
+ //resample
+ s->_n = s->_n+1;
+ s->_sampling = s->_length/(float)(s->_n+1);
+ s->_resampled = true;
+ N++;
+ if(N == NPointsToAdd)
+ break;
+ }
+ }
+ checkEveryone = true;
+ }
+ //actually resample:
+ for(vector<StrokeSegment>::iterator s=strokeSegments.begin(), send=strokeSegments.end();
+ s!=send;
+ ++s)
+ {
+ newVertices.push_back(&(*(s->_begin)));
+ if(s->_sampling < _sampling)
+ _sampling = s->_sampling;
+
+ t = s->_sampling/s->_length;
+ for(int i=0; i<s->_n; ++i)
+ {
+ newVertex = new StrokeVertex(&(*(s->_begin)),&(*(s->_end)),t);
+ newVertices.push_back(newVertex);
+ t += s->_sampling/s->_length;
+ }
+ it=s->_begin;
+ next=s->_end;
+ }
+
+ // add last:
+ ++it;++next;
+ if((it != itend) && (next == itend))// && (t == 0.f))
+ newVertices.push_back(&(*it));
+
+ int newsize = newVertices.size();
+ if(newsize != iNPoints)
+ cerr << "Warning: incorrect points number" << endl;
+
+ _Vertices.clear();
+ _Vertices = newVertices;
+ newVertices.clear();
+
+ if(_rep)
+ {
+ delete _rep;
+ _rep = new StrokeRep(this);
+ }
+}
+
+
+void Stroke::Resample(float iSampling)
+{
+ // cerr<<"old size :"<<strokeVerticesSize()<<endl;
+ if(iSampling == 0)
+
+ return;
+ if(iSampling >= _sampling)
+ return ;
+
+ _sampling = iSampling;
+ // Resample...
+ //real curvilinearLength = 0.f;
+ vertex_container newVertices;
+ real t=0.f;
+ StrokeVertex * newVertex = 0;
+ StrokeInternal::StrokeVertexIterator it = strokeVerticesBegin();
+ StrokeInternal::StrokeVertexIterator next = it;++next;
+ StrokeInternal::StrokeVertexIterator itend = strokeVerticesEnd();
+ while(((it!=itend)&&(next!=itend)))
+ {
+ newVertices.push_back(&(*it));
+ Vec3r a((it)->point2d());
+ Vec3r b((next)->point2d());
+ Vec3r vec_tmp(b - a);
+ real norm_var = vec_tmp.norm();
+ if(norm_var <= _sampling)
+ {
+ //curvilinearLength += norm_var;
+ ++it; ++next;
+ continue;
+ }
+
+ //curvilinearLength += _sampling;
+ t = _sampling/norm_var;
+ float limit = 0.99f;
+ while(t<limit)
+ {
+ newVertex = new StrokeVertex(&(*it),&(*next),t);
+ //newVertex->SetCurvilinearAbscissa(curvilinearLength);
+ newVertices.push_back(newVertex);
+ t = t + _sampling/norm_var;
+ }
+ ++it; ++next;
+ }
+ // add last:
+ if((it != itend) && (next == itend))// && (t == 0.f))
+ newVertices.push_back(&(*it));
+
+ _Vertices.clear();
+ _Vertices = newVertices;
+ newVertices.clear();
+
+ if(_rep)
+ {
+ delete _rep;
+ _rep = new StrokeRep(this);
+ }
+}
+
+void Stroke::RemoveVertex(StrokeVertex *iVertex)
+{
+ vertex_container::iterator it=_Vertices.begin(), itend=_Vertices.end();
+ for(;
+ it!=itend;
+ ++it)
+ {
+ if((*it) == iVertex)
+ {
+ delete iVertex;
+ it = _Vertices.erase(it); // it is now the element just after the erased element
+ break;
+ }
+ }
+ // recompute various values (length, curvilign abscissa)
+ float curvabsc = 0.f;
+ it=_Vertices.begin();
+ itend=_Vertices.end();
+ vertex_container::iterator previous=it;
+ for(;
+ (it!=itend);
+ ++it)
+ {
+ if(it != previous)
+ curvabsc += ((*it)->point2d()-(*previous)->point2d()).norm();
+ (*it)->SetCurvilinearAbscissa(curvabsc);
+ previous = it;
+ }
+ _Length = curvabsc;
+ it=_Vertices.begin();
+ for(;
+ (it!=itend);
+ ++it)
+ {
+ (*it)->SetStrokeLength(_Length);
+ }
+}
+
+void Stroke::InsertVertex(StrokeVertex *iVertex, StrokeInternal::StrokeVertexIterator next)
+{
+ vertex_container::iterator it=_Vertices.begin(), itend=_Vertices.end();
+
+ vertex_container::iterator itnext = next.getIt();
+ _Vertices.insert(itnext, iVertex);
+ // recompute various values (length, curvilign abscissa)
+ float curvabsc = 0.f;
+ it=_Vertices.begin();
+ itend=_Vertices.end();
+ vertex_container::iterator previous=it;
+ for(;
+ (it!=itend);
+ ++it)
+ {
+ curvabsc += ((*it)->point2d()-(*previous)->point2d()).norm();
+ (*it)->SetCurvilinearAbscissa(curvabsc);
+ previous = it;
+ }
+ _Length = curvabsc;
+ for(;
+ (it!=itend);
+ ++it)
+ {
+ (*it)->SetStrokeLength(_Length);
+ }
+}
+
+//! embedding vertex iterator
+Stroke::const_vertex_iterator Stroke::vertices_begin() const { return const_vertex_iterator(_Vertices.begin(),_Vertices.begin(), _Vertices.end()); }
+Stroke::const_vertex_iterator Stroke::vertices_end() const { return const_vertex_iterator(_Vertices.end(),_Vertices.begin(), _Vertices.end()); }
+Stroke::vertex_iterator Stroke::vertices_end() { return vertex_iterator(_Vertices.end(),_Vertices.begin(), _Vertices.end()); }
+
+StrokeInternal::StrokeVertexIterator Stroke::strokeVerticesBegin(float t) {
+ if((t!=0) && (t < _sampling))
+ Resample(t);
+ return StrokeInternal::StrokeVertexIterator(this->_Vertices.begin(), this->_Vertices.begin(), this->_Vertices.end());
+}
+
+StrokeInternal::StrokeVertexIterator Stroke::strokeVerticesEnd() {
+ return StrokeInternal::StrokeVertexIterator(this->_Vertices.end(), this->_Vertices.begin(), this->_Vertices.end());
+}
+
+Interface0DIterator Stroke::verticesBegin() {
+ Interface0DIterator ret(new StrokeInternal::StrokeVertexIterator(this->_Vertices.begin(),
+ this->_Vertices.begin(),
+ this->_Vertices.end()));
+ return ret;
+}
+
+Interface0DIterator Stroke::verticesEnd() {
+ Interface0DIterator ret(new StrokeInternal::StrokeVertexIterator(this->_Vertices.end(),
+ this->_Vertices.begin(),
+ this->_Vertices.end()));
+ return ret;
+}
+
+Interface0DIterator Stroke::pointsBegin(float t) {
+ return verticesBegin(); // FIXME
+}
+
+Interface0DIterator Stroke::pointsEnd(float t) {
+ return verticesEnd();
+}
+
+void Stroke::Render(const StrokeRenderer *iRenderer)
+{
+ if(!_rep)
+ _rep = new StrokeRep(this);
+ iRenderer->RenderStrokeRep(_rep);
+}
+
+void Stroke::RenderBasic(const StrokeRenderer *iRenderer)
+{
+ if(!_rep)
+ _rep = new StrokeRep(this);
+ iRenderer->RenderStrokeRepBasic(_rep);
+}
+
+Stroke::vertex_iterator Stroke::vertices_begin(float sampling)
+{
+ // Resample if necessary
+ if((sampling != 0) && (sampling < _sampling))
+ Resample(sampling);
+ return vertex_iterator(_Vertices.begin(),_Vertices.begin(),_Vertices.end());
+ //return _Vertices.begin();
+}
+//
+//Stroke::vertex_iterator Stroke::vertices_last()
+//{
+// vertex_iterator res = vertices_begin();
+// vertex_iterator next = res;++next;
+// while(!next.end())
+// {
+// ++next;
+// ++res;
+// }
+// return res;
+//}
+//
+//Stroke::const_vertex_iterator Stroke::vertices_last() const
+//{
+// const_vertex_iterator res = vertices_begin();
+// const_vertex_iterator next = res;++next;
+// while(!next.end())
+// {
+// ++next;
+// ++res;
+// }
+// return res;
+//}
+
+//Stroke::vertex_container::reverse_iterator Stroke::vertices_last(float sampling)
+//{
+// // Resample if necessary
+// if(sampling < _sampling)
+// Resample(sampling);
+// return _Vertices.rbegin();
+//}
+
+
+//inline Vec3r shaded_color(int iCombination = 0) const ;
+//inline Vec<3,real> Stroke::orientation2d(const_vertex_iterator it) const
+//{
+// return iterator_edge_orientation2d_function<Stroke, const_vertex_iterator>(this, it);
+//}
+// Vec3r Stroke::orientation2d(int iCombination) const
+// {
+// return edge_orientation2d_function<Stroke>(*this, iCombination);
+// }
+//inline Vec3r Stroke::orientation3d(const_vertex_iterator it) const
+//{
+// return iterator_edge_orientation3d_function<Stroke, const_vertex_iterator>(*this, it);
+//}
+// Vec3r Stroke::orientation3d(int iCombination) const
+// {
+// return edge_orientation3d_function<Stroke>(*this, iCombination);
+// }
+
+//Material Stroke::material() const
+//{
+// const_vertex_iterator v=vertices_begin(), vend=strokeVerticesEnd();
+// Material mat = (*v)->material();
+// for(;v!=vend;++v)
+// {
+// if(mat != (*v)->material())
+// Exception::raiseException();
+// }
+// return mat;
+//}
+
+//int Stroke::qi() const
+//{
+// const_vertex_iterator v=vertices_begin(), vend=vertices_end();
+// int qi_= (*v)->qi();
+// for(;v!=vend;++v)
+// {
+// if((*v)->qi() != qi_)
+// Exception::raiseException();
+// }
+// return qi_;
+//}
+//inline occluder_container::const_iterator occluders_begin() const {return _FEdgeA->occluders().begin();}
+//inline occluder_container::const_iterator occluders_end() const {return _FEdgeA->occluders().end();}
+
+//int Stroke::occluders_size() const
+//{
+// return qi();
+//}
+//
+//bool Stroke::occluders_empty() const
+//{
+// const_vertex_iterator v=vertices_begin(), vend=vertices_end();
+// bool empty = (*v)->occluders_empty();
+// for(;v!=vend;++v)
+// {
+// if((*v)->occluders_empty() != empty)
+// Exception::raiseException();
+// }
+// return empty;
+//}
+////inline const polygon3d& occludee() const {return *(_FEdgeA->aFace());}
+//const SShape * Stroke::occluded_shape() const
+//{
+// const_vertex_iterator v=vertices_begin(), vend=vertices_end();
+// const SShape *sshape = (*v)->occluded_shape();
+// for(;v!=vend;++v)
+// {
+// if((*v)->occluded_shape() != sshape)
+// Exception::raiseException();
+// }
+// return sshape;
+//}
+//
+//const bool Stroke::occludee_empty() const
+//{
+// const_vertex_iterator v=vertices_begin(), vend=vertices_end();
+// bool empty = (*v)->occludee_empty();
+// for(;v!=vend;++v)
+// {
+// if((*v)->occludee_empty() != empty)
+// Exception::raiseException();
+// }
+// return empty;
+//}
+
+//const SShape * Stroke::shape() const
+//{
+// const_vertex_iterator v=vertices_begin(), vend=vertices_end();
+// const SShape *sshape = (*v)->shape();
+// for(;v!=vend;++v)
+// {
+// if((*v)->shape() != sshape)
+// Exception::raiseException();
+// }
+// return sshape;
+//}
+
+// real Stroke::z_discontinuity(int iCombination) const
+// {
+// return z_discontinuity_edge_function<Stroke>(*this, iCombination);
+// }
+
+// Vec3r Stroke::curvature2d_as_vector(int iCombination) const
+// {
+// return curvature2d_as_vector_edge_function<Stroke>(*this, iCombination);
+// }
+
+// real Stroke::curvature2d_as_angle(int iCombination) const
+// {
+// return curvature2d_as_angle_edge_function<Stroke>(*this, iCombination);
+// }
+
+// float Stroke::shape_importance(int iCombination) const
+// {
+// return shape_importance_edge_function<Stroke>(*this, iCombination);
+// }
+
+
+// float Stroke::local_average_depth(int iCombination ) const
+// {
+// return local_average_depth_edge_function<Stroke >(*this, iCombination);
+// }
+
+// float Stroke::local_depth_variance(int iCombination) const
+// {
+// return local_depth_variance_edge_function<Stroke>(*this, iCombination);
+// }
+
+// real Stroke::local_average_density(float sigma , int iCombination ) const
+// {
+// return density_edge_function<Stroke>(*this, iCombination);
+// }
diff --git a/source/blender/freestyle/intern/stroke/Stroke.h b/source/blender/freestyle/intern/stroke/Stroke.h
new file mode 100755
index 00000000000..a5cf51f8224
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/Stroke.h
@@ -0,0 +1,584 @@
+//
+// Filename : Stroke.h
+// Author(s) : Stephane Grabli
+// Purpose : Classes to define a stroke
+// Date of creation : 09/09/2002
+//
+///////////////////////////////////////////////////////////////////////////////
+
+
+//
+// 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef STROKE_H
+# define STROKE_H
+
+# include <vector>
+# include <map>
+# include "../system/FreestyleConfig.h"
+# include "../view_map/Silhouette.h"
+# include "Curve.h"
+# include "../view_map/Interface1D.h"
+# include "../system/StringUtils.h"
+
+//
+// StrokeAttribute
+//
+////////////////////////////////////////////////////////
+
+/*! Class to define an attribute associated to a Stroke Vertex.
+ * This attribute stores the color, alpha and thickness values
+ * for a Stroke Vertex.
+ */
+class LIB_STROKE_EXPORT StrokeAttribute
+{
+public:
+
+ /*! default constructor */
+ StrokeAttribute();
+ /*! Copy constructor */
+ StrokeAttribute(const StrokeAttribute& iBrother);
+ /*! Builds a stroke vertex attribute from
+ * a set of parameters.
+ * \param iRColor
+ * The Red Component value.
+ * \param iGColor
+ * The Green Component value.
+ * \param iBColor
+ * The Blue Component value.
+ * \param iAlpha
+ * The transparency value
+ * \param iRThickness
+ * The thickness of the stroke on the right
+ * \param iLThickness
+ * The Thickness of the stroke on the left
+ */
+ StrokeAttribute(float iRColor, float iGColor, float iBColor,
+ float iAlpha,
+ float iRThickness, float iLThickness);
+
+ /*! Interpolation constructor.
+ * Builds a StrokeAttribute from two
+ * StrokeAttributes and an interpolation parameter.
+ * \param a1
+ * The first Attribute.
+ * \param a2
+ * The second parameter.
+ * \param t
+ * The interpolation parameter.
+ */
+ StrokeAttribute(const StrokeAttribute& a1, const StrokeAttribute& a2, float t);
+
+ /*! destructor */
+ virtual ~StrokeAttribute();
+
+ /* operators */
+ /*! operator = */
+ StrokeAttribute& operator=(const StrokeAttribute& iBrother);
+
+ /* accessors */
+ /*! Returns the attribute's color.
+ * \return The array of 3 floats containing the R,G,B values
+ * of the attribute's color.
+ */
+ inline const float* getColor() const { return _color; }
+ /*! Returns the R color component. */
+ inline const float getColorR() const { return _color[0]; }
+ /*! Returns the G color component. */
+ inline const float getColorG() const { return _color[1]; }
+ /*! Returns the B color component. */
+ inline const float getColorB() const { return _color[2]; }
+ /*! Returns the RGB color components. */
+ inline Vec3f getColorRGB() const { return Vec3f(_color[0], _color[1], _color[2]); }
+ /*! Returns the alpha color component. */
+ inline float getAlpha() const { return _alpha; }
+ /*! Returns the attribute's thickness.
+ * \return an array of 2 floats. the first value is
+ * the thickness on the right of the vertex when following
+ * the stroke, the second one is the thickness on the left.
+ */
+ inline const float* getThickness() const { return _thickness; }
+ /*! Returns the thickness on the right of the vertex when following the
+ * stroke. */
+ inline const float getThicknessR() const { return _thickness[0]; }
+ /*! Returns the thickness on the left of the vertex when following the
+ * stroke. */
+ inline const float getThicknessL() const { return _thickness[1]; }
+ /*! Returns the thickness on the right and on the left of the vertex when following the
+ * stroke. */
+ inline Vec2f getThicknessRL() const { return Vec2f(_thickness[0], _thickness[1]); }
+
+ /*! Returns true if the strokevertex is visible, false otherwise */
+ inline bool isVisible() const {return _visible;}
+
+ /*! Returns an attribute of type real
+ * \param iName
+ * The name of the attribute
+ */
+ float getAttributeReal(const char *iName) const;
+ /*! Returns an attribute of type Vec2f
+ * \param iName
+ * The name of the attribute
+ */
+ Vec2f getAttributeVec2f(const char *iName) const;
+ /*! Returns an attribute of type Vec3f
+ * \param iName
+ * The name of the attribute
+ */
+ Vec3f getAttributeVec3f(const char *iName) const;
+
+ /*! Checks whether the attribute iName is availbale */
+ bool isAttributeAvailableReal(const char *iName) const ;
+ /*! Checks whether the attribute iName is availbale */
+ bool isAttributeAvailableVec2f(const char *iName) const ;
+ /*! Checks whether the attribute iName is availbale */
+ bool isAttributeAvailableVec3f(const char *iName) const ;
+
+ /* modifiers */
+ /*! Sets the attribute's color.
+ * \param r
+ * The new R value.
+ * \param g
+ * The new G value.
+ * \param b
+ * The new B value.
+ */
+ inline void setColor(float r, float g, float b) { _color[0]=r; _color[1]=g; _color[2]=b; }
+ /*! Sets the attribute's color.
+ * \param iRGB
+ * The new RGB values.
+ */
+ inline void setColor(const Vec3f& iRGB) { _color[0]=iRGB[0]; _color[1]=iRGB[1]; _color[2]=iRGB[2]; }
+ /*! Sets the attribute's alpha value.
+ * \param alpha
+ * The new alpha value.
+ */
+ inline void setAlpha(float alpha) { _alpha = alpha; }
+ /*! Sets the attribute's thickness.
+ * \param tr
+ * The thickness on the right of the vertex when following the stroke.
+ * \param tl
+ * The thickness on the left of the vertex when following the stroke.
+ */
+ inline void setThickness(float tr, float tl) { _thickness[0]=tr; _thickness[1]=tl; }
+ /*! Sets the attribute's thickness.
+ * \param tRL
+ * The thickness on the right and on the left of the vertex when following the stroke.
+ */
+ inline void setThickness(const Vec2f& tRL) { _thickness[0]=tRL[0]; _thickness[1]=tRL[1]; }
+
+ /*! Sets the visible flag. True means visible. */
+ inline void SetVisible(bool iVisible){ _visible = iVisible; }
+
+ /*! Adds a user defined attribute of type real
+ * If there is no attribute of name iName, it is added.
+ * Otherwise, the new value replaces the old one.
+ * \param iName
+ * The name of the attribute
+ * \param att
+ * The attribute's value
+ */
+ void setAttributeReal(const char *iName, float att);
+ /*! Adds a user defined attribute of type Vec2f
+ * If there is no attribute of name iName, it is added.
+ * Otherwise, the new value replaces the old one.
+ * \param iName
+ * The name of the attribute
+ * \param att
+ * The attribute's value
+ */
+ void setAttributeVec2f(const char *iName, const Vec2f& att);
+ /*! Adds a user defined attribute of type Vec3f
+ * If there is no attribute of name iName, it is added.
+ * Otherwise, the new value replaces the old one.
+ * \param iName
+ * The name of the attribute
+ * \param att
+ * The attribute's value
+ */
+ void setAttributeVec3f(const char *iName, const Vec3f& att);
+
+private:
+
+ typedef std::map<const char*, float, StringUtils::ltstr> realMap ;
+ typedef std::map<const char*, Vec2f, StringUtils::ltstr> Vec2fMap ;
+ typedef std::map<const char*, Vec3f, StringUtils::ltstr> Vec3fMap ;
+
+ float _color[3]; //! the color
+ float _alpha; //! alpha
+ float _thickness[2]; //! the thickness on the right and on the left of the backbone vertex (the stroke is oriented)
+ bool _visible;
+ realMap *_userAttributesReal;
+ Vec2fMap *_userAttributesVec2f;
+ Vec3fMap *_userAttributesVec3f;
+};
+
+
+//
+// StrokeVertex
+//
+////////////////////////////////////////////////////////
+
+/*! Class to define a stroke vertex.
+ */
+class LIB_STROKE_EXPORT StrokeVertex : public CurvePoint
+{
+public: // Implementation of Interface0D
+
+ /*! Returns the string "StrokeVertex"*/
+ virtual string getExactTypeName() const {
+ return "StrokeVertex";
+ }
+
+private:
+
+ StrokeAttribute _Attribute; //! The attribute associated to the vertex
+ float _CurvilignAbscissa; //! the curvilign abscissa
+ float _StrokeLength; // stroke length
+
+public:
+
+ /*! default constructor */
+ StrokeVertex();
+ /*! Copy constructor */
+ StrokeVertex(const StrokeVertex& iBrother);
+ /*! Builds a stroke vertex from a SVertex */
+ StrokeVertex(SVertex *iSVertex);
+ /*! Builds a stroke vertex from a CurvePoint */
+ StrokeVertex(CurvePoint *iPoint);
+ /*! Builds Stroke Vertex from 2 stroke vertices and an interpolation parameter*/
+ StrokeVertex(StrokeVertex *iA, StrokeVertex *iB, float t3);
+ /*! Builds a stroke from a view vertex and an attribute */
+ StrokeVertex(SVertex *iSVertex, const StrokeAttribute& iAttribute);
+ /*! destructor */
+ virtual ~StrokeVertex();
+
+ /* operators */
+ /*! operator = */
+ StrokeVertex& operator=(const StrokeVertex& iBrother);
+
+ /* accessors */
+ /*! Returns the 2D point x coordinate */
+ inline real x() const { return _Point2d[0]; }
+ /*! Returns the 2D point y coordinate */
+ inline real y() const { return _Point2d[1]; }
+ /*! Returns the 2D point coordinates as a Vec2d */
+ Vec2f getPoint () {return Vec2f((float)point2d()[0], (float)point2d()[1]);}
+ /*! Returns the ith 2D point coordinate (i=0 or 1)*/
+ inline real operator[](const int i) const { return _Point2d[i]; }
+ /*! Returns the StrokeAttribute for this StrokeVertex */
+ inline const StrokeAttribute& attribute() const { return _Attribute; }
+ /*! Returns a non-const reference to the StrokeAttribute of this StrokeVertex */
+ inline StrokeAttribute& attribute() {return _Attribute;}
+ /*! Returns the curvilinear abscissa */
+ inline float curvilinearAbscissa() const {return _CurvilignAbscissa;}
+ /*! Returns the length of the Stroke to which this StrokeVertex belongs */
+ inline float strokeLength() const {return _StrokeLength;}
+ /*! Returns the curvilinear abscissa of this StrokeVertex in the Stroke */
+ inline float u() const {return _CurvilignAbscissa/_StrokeLength;}
+
+ /* modifiers */
+ /*! Sets the 2D x value */
+ inline void SetX(real x) { _Point2d[0]=x; }
+ /*! Sets the 2D y value */
+ inline void SetY(real y) { _Point2d[1]=y; }
+ /*! Sets the 2D x and y values */
+ inline void SetPoint(real x, real y) { _Point2d[0]=x; _Point2d[1]=y;}
+ /*! Sets the 2D x and y values */
+ inline void SetPoint(const Vec2f& p) { _Point2d[0] = p[0];_Point2d[1] = p[1];}
+ /*! Returns a reference to the ith 2D point coordinate (i=0 or 1) */
+ inline real& operator[](const int i) { return _Point2d[i]; }
+ /*! Sets the attribute. */
+ inline void SetAttribute(const StrokeAttribute& iAttribute) { _Attribute = iAttribute; }
+ /*! Sets the curvilinear abscissa of this StrokeVertex in the Stroke */
+ inline void SetCurvilinearAbscissa(float iAbscissa) {_CurvilignAbscissa = iAbscissa;}
+ /*! Sets the Stroke's length (it's only a value stored by the Stroke Vertex, it won't
+ * change the real Stroke's length.)
+ */
+ inline void SetStrokeLength(float iLength) {_StrokeLength = iLength;}
+
+ /* interface definition */
+ /* inherited */
+
+};
+
+
+//
+// Stroke
+//
+////////////////////////////////////////////////////////
+
+class StrokeRenderer;
+class StrokeRep;
+
+namespace StrokeInternal {
+ class vertex_const_traits ;
+ class vertex_nonconst_traits ;
+ template<class Traits> class vertex_iterator_base;
+ class StrokeVertexIterator;
+} // end of namespace StrokeInternal
+
+/*! Class to define a stroke.
+ * A stroke is made of a set of 2D vertices (StrokeVertex), regularly spaced out.
+ * This set of vertices defines the stroke's backbone geometry.
+ * Each of these stroke vertices defines the stroke's shape and appearance
+ * at this vertex position.
+ */
+class LIB_STROKE_EXPORT Stroke : public Interface1D
+{
+public: // Implementation of Interface1D
+
+ /*! Returns the string "Stroke" */
+ virtual string getExactTypeName() const {
+ return "Stroke";
+ }
+
+ // Data access methods
+
+ /*! Returns the Id of the Stroke */
+ virtual Id getId() const {
+ return _id;
+ }
+ /*! The different blending modes
+ * available to similate the interaction
+ * media-medium.
+ */
+ typedef enum{
+ DRY_MEDIUM,/*!< To simulate a dry medium such as Pencil or Charcoal.*/
+ HUMID_MEDIUM,/*!< To simulate ink painting (color substraction blending).*/
+ OPAQUE_MEDIUM, /*!< To simulate an opaque medium (oil, spray...).*/
+ } MediumType;
+
+
+public:
+ typedef std::deque<StrokeVertex*> vertex_container; // the vertices container
+ typedef std::vector<ViewEdge*> viewedge_container; // the viewedges container
+ typedef StrokeInternal::vertex_iterator_base<StrokeInternal::vertex_nonconst_traits > vertex_iterator;
+ typedef StrokeInternal::vertex_iterator_base<StrokeInternal::vertex_const_traits> const_vertex_iterator;
+
+public:
+ //typedef StrokeVertex vertex_type;
+private:
+ vertex_container _Vertices; //! The stroke's backbone vertices
+ Id _id;
+ float _Length; // The stroke length
+ viewedge_container _ViewEdges;
+ float _sampling;
+ StrokeRenderer *_renderer; // mark implementation OpenGL renderer
+ MediumType _mediumType;
+ unsigned int _textureId;
+ bool _tips;
+ Vec2r _extremityOrientations[2]; // the orientations of the first and last extermity
+ StrokeRep *_rep;
+
+public:
+ /*! default constructor */
+ Stroke();
+ /*! copy constructor */
+ Stroke(const Stroke& iBrother);
+ /*! Builds a stroke from a set of StrokeVertex.
+ * This constructor is templated by an iterator type.
+ * This iterator type must allow the vertices parsing
+ * using the ++ operator.
+ * \param iBegin
+ * The iterator pointing to the first vertex.
+ * \param iEnd
+ * The iterator pointing to the end of the vertex list.
+ */
+ template<class InputVertexIterator>
+ Stroke(InputVertexIterator iBegin, InputVertexIterator iEnd);
+
+ /*! Destructor */
+ virtual ~Stroke();
+
+ /* operators */
+ /*! operator = */
+ Stroke& operator=(const Stroke& iBrother);
+
+ /*! Compute the sampling needed to get iNVertices
+ * vertices.
+ * If the specified number of vertices is less than the
+ * actual number of vertices, the actual sampling value is returned.
+ * (To remove Vertices, use the RemoveVertex() method of this class).
+ * \param iNVertices
+ * The number of StrokeVertices we eventually want
+ * in our Stroke.
+ * \return the sampling that must be used in the Resample(float) method.
+ * @see Resample(int)
+ * @see Resample(float)
+ */
+ float ComputeSampling(int iNVertices);
+
+ /*! Resampling method.
+ * Resamples the curve so that it eventually
+ * has iNPoints. That means it is going
+ * to add iNPoints-vertices_size, if vertices_size
+ * is the number of points we already have.
+ * Is vertices_size >= iNPoints, no resampling is done.
+ * \param iNPoints
+ * The number of vertices we eventually want in our stroke.
+ */
+ void Resample(int iNPoints);
+
+ /*! Resampling method.
+ * Resamples the curve with a given sampling.
+ * If this sampling is < to the actual sampling
+ * value, no resampling is done.
+ * \param iSampling
+ * The new sampling value.
+ */
+ void Resample(float iSampling);
+
+ /*! Removes the stroke vertex iVertex
+ * from the stroke.
+ * The length and curvilinear abscissa are updated
+ * consequently.
+ */
+ void RemoveVertex(StrokeVertex *iVertex);
+
+ /*! Inserts the stroke vertex iVertex
+ * in the stroke before next.
+ * The length, curvilinear abscissa are updated
+ * consequently.
+ * \param iVertex
+ * The StrokeVertex to insert in the Stroke.
+ * \param next
+ * A StrokeVertexIterator pointing to the StrokeVeretx before
+ * which iVertex must be inserted.
+ */
+ void InsertVertex(StrokeVertex *iVertex, StrokeInternal::StrokeVertexIterator next);
+
+ /* Render method */
+ void Render(const StrokeRenderer *iRenderer );
+ void RenderBasic(const StrokeRenderer *iRenderer );
+
+ /* Iterator definition */
+
+ /* accessors */
+ /*! Returns the 2D length of the Stroke */
+ inline real getLength2D() const {return _Length;}
+ /*! Returns a reference to the time stamp value of the stroke. */
+ /*! Returns the MediumType used for this Stroke. */
+ inline MediumType getMediumType() const {return _mediumType;}
+ /*! Returns the id of the texture used to simulate th marks system
+ * for this Stroke
+ */
+ inline unsigned int getTextureId() {return _textureId;}
+ /*! Returns true if this Stroke uses a texture with tips, false
+ * otherwise.
+ */
+ inline bool hasTips() const {return _tips;}
+ /* these advanced iterators are used only in C++ */
+ inline int vertices_size() const {return _Vertices.size();}
+ inline viewedge_container::const_iterator viewedges_begin() const {return _ViewEdges.begin();}
+ inline viewedge_container::iterator viewedges_begin() {return _ViewEdges.begin();}
+ inline viewedge_container::const_iterator viewedges_end() const {return _ViewEdges.end();}
+ inline viewedge_container::iterator viewedges_end() {return _ViewEdges.end();}
+ inline int viewedges_size() const {return _ViewEdges.size();}
+
+ inline Vec2r getBeginningOrientation() const {return _extremityOrientations[0];}
+ inline real getBeginningOrientationX() const {return _extremityOrientations[0].x();}
+ inline real getBeginningOrientationY() const {return _extremityOrientations[0].y();}
+ inline Vec2r getEndingOrientation() const {return _extremityOrientations[1];}
+ inline real getEndingOrientationX() const {return _extremityOrientations[1].x();}
+ inline real getEndingOrientationY() const {return _extremityOrientations[1].y();}
+
+
+ /* modifiers */
+ /*! Sets the Id of the Stroke. */
+ inline void SetId(const Id& id) {_id = id;}
+ /*! Sets the 2D length of the Stroke. */
+ void SetLength(float iLength);
+ /*! Sets the medium type that must be used for this Stroke. */
+ inline void SetMediumType(MediumType iType) {_mediumType = iType;}
+ /*! Sets the texture id to be used to simulate the marks system for this Stroke. */
+ inline void SetTextureId(unsigned int id) {_textureId = id;}
+ /*! Sets the flag telling whether this stroke is using a texture with
+ * tips or not.
+ */
+ inline void SetTips(bool iTips) {_tips = iTips;}
+
+ inline void push_back(StrokeVertex* iVertex) { _Vertices.push_back(iVertex); }
+ inline void push_front(StrokeVertex* iVertex) { _Vertices.push_front(iVertex); }
+ inline void AddViewEdge(ViewEdge *iViewEdge) {_ViewEdges.push_back(iViewEdge);}
+ inline void SetBeginningOrientation(const Vec2r& iOrientation) {_extremityOrientations[0] = iOrientation;}
+ inline void SetBeginningOrientation(real x, real y) {_extremityOrientations[0] = Vec2r(x,y);}
+ inline void SetEndingOrientation(const Vec2r& iOrientation) {_extremityOrientations[1] = iOrientation;}
+ inline void SetEndingOrientation(real x, real y) {_extremityOrientations[1] = Vec2r(x,y);}
+
+ /* Information access interface */
+
+ // embedding vertex iterator
+ const_vertex_iterator vertices_begin() const;
+ vertex_iterator vertices_begin(float t=0.f);
+ const_vertex_iterator vertices_end() const;
+ vertex_iterator vertices_end();
+
+ /*! Returns a StrokeVertexIterator pointing on the first StrokeVertex of the
+ * Stroke. One can specifly a sampling value to resample the Stroke
+ * on the fly if needed.
+ * \param t
+ * The resampling value with which we want our Stroke to be resampled.
+ * If 0 is specified, no resampling is done.
+ */
+ StrokeInternal::StrokeVertexIterator strokeVerticesBegin(float t=0.f);
+ /*! Returns a StrokeVertexIterator pointing after the last StrokeVertex of the
+ * Stroke.
+ */
+ StrokeInternal::StrokeVertexIterator strokeVerticesEnd();
+ /*! Returns the number of StrokeVertex constituing the Stroke. */
+ inline unsigned int strokeVerticesSize() const {return _Vertices.size();}
+
+ // Iterator access (Interface1D)
+ /*! Returns an Interface0DIterator pointing on the first StrokeVertex of the
+ * Stroke.
+ */
+ virtual Interface0DIterator verticesBegin();
+ /*! Returns an Interface0DIterator pointing after the last StrokeVertex of the
+ * Stroke.
+ */
+ virtual Interface0DIterator verticesEnd();
+
+ virtual Interface0DIterator pointsBegin(float t=0.f);
+ virtual Interface0DIterator pointsEnd(float t=0.f);
+};
+
+
+
+//
+// Implementation
+//
+////////////////////////////////////////////////////////
+
+
+template<class InputVertexIterator>
+Stroke::Stroke(InputVertexIterator iBegin, InputVertexIterator iEnd)
+{
+ for(InputVertexIterator v=iBegin, vend=iEnd;
+ v!=vend;
+ v++)
+ {
+ _Vertices.push_back(*v);
+ }
+ _Length = 0;
+ _id = 0;
+}
+
+#endif // STROKE_H
diff --git a/source/blender/freestyle/intern/stroke/StrokeAdvancedIterators.h b/source/blender/freestyle/intern/stroke/StrokeAdvancedIterators.h
new file mode 100755
index 00000000000..279a0b12089
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/StrokeAdvancedIterators.h
@@ -0,0 +1,142 @@
+//
+// Filename : StrokeAdvancedIterators.h
+// Author(s) : Stephane Grabli
+// Purpose : Iterators used to iterate over the elements of the Stroke
+// Can't be used in python
+// Date of creation : 01/07/2003
+//
+///////////////////////////////////////////////////////////////////////////////
+
+
+//
+// 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef STROKEADVANCEDITERATORS_H
+# define STROKEADVANCEDITERATORS_H
+
+# include "Stroke.h"
+
+namespace StrokeInternal {
+
+ class vertex_const_traits : public Const_traits<StrokeVertex*> {
+ public:
+ typedef std::deque<StrokeVertex*> vertex_container;
+ typedef vertex_container::const_iterator vertex_container_iterator ;
+ };
+ class vertex_nonconst_traits : public Nonconst_traits<StrokeVertex*> {
+ public:
+ typedef std::deque<StrokeVertex*> vertex_container; //! the vertices container
+ typedef vertex_container::iterator vertex_container_iterator ;
+ };
+
+
+ template<class Traits>
+ class vertex_iterator_base : public IteratorBase<Traits,BidirectionalIteratorTag_Traits>
+ {
+ public:
+ typedef vertex_iterator_base<Traits> Self;
+ protected:
+ typedef IteratorBase<Traits,BidirectionalIteratorTag_Traits> parent_class;
+ typedef typename Traits::vertex_container_iterator vertex_container_iterator;
+ typedef vertex_iterator_base<vertex_nonconst_traits> iterator;
+ typedef vertex_iterator_base<vertex_const_traits> const_iterator;
+ //protected:
+ public:
+ vertex_container_iterator _it;
+ vertex_container_iterator _begin;
+ vertex_container_iterator _end;
+ public:
+ friend class Stroke;
+ //friend class vertex_iterator;
+ inline vertex_iterator_base()
+ : parent_class()
+ {}
+ inline vertex_iterator_base(const iterator& iBrother)
+ : parent_class()
+ {_it = iBrother._it;_begin = iBrother._begin;_end = iBrother._end;}
+ inline vertex_iterator_base(const const_iterator& iBrother)
+ : parent_class()
+ {_it = iBrother._it;_begin = iBrother._begin;_end = iBrother._end;}
+ //protected://FIXME
+ public:
+ inline vertex_iterator_base(vertex_container_iterator it, vertex_container_iterator begin, vertex_container_iterator end)
+ : parent_class()
+ {
+ _it = it;
+ _begin = begin;
+ _end = end;
+ }
+
+ public:
+ virtual ~vertex_iterator_base() {}
+
+ virtual bool begin() const {return _it==_begin? true : false;}
+ virtual bool end() const {return _it==_end ? true : false;}
+
+ // operators
+ inline Self& operator++() // operator corresponding to ++i
+ {
+ ++_it;
+ return *(this);
+ }
+ inline Self operator++(int) // opérateur correspondant à i++
+ {
+ Self tmp = *this; // C'est pour cela qu'on stocke la valeur
+ ++_it; // dans un temporaire.
+ return tmp;
+ }
+ inline Self& operator--() // operator corresponding to ++i
+ {
+ --_it;
+ return *(this);
+ }
+ inline Self operator--(int) // opérateur correspondant à i++
+ { // c.a.d qui renvoie la valeur *puis* incrémente.
+ Self tmp = *this; // C'est pour cela qu'on stocke la valeur
+ --_it; // dans un temporaire.
+ return tmp;
+ }
+
+ // comparibility
+ virtual bool operator!=(const Self& b) const
+ {
+ return (_it != b._it);
+ }
+ virtual bool operator==(const Self& b) const
+ {
+ return !(*this != b);
+ }
+
+ // dereferencing
+ virtual typename Traits::reference operator*() const {return *(_it);}
+ virtual typename Traits::pointer operator->() const { return &(operator*());}
+
+ /*! accessors */
+ inline vertex_container_iterator it() const {return _it;}
+ inline vertex_container_iterator getBegin() const {return _begin;}
+ inline vertex_container_iterator getEnd() const {return _end;}
+ };
+
+} // end of namespace StrokeInternal
+
+
+#endif // STROKEADVANCEDITERATORS_H
+
+
diff --git a/source/blender/freestyle/intern/stroke/StrokeIO.cpp b/source/blender/freestyle/intern/stroke/StrokeIO.cpp
new file mode 100755
index 00000000000..7f540939fa1
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/StrokeIO.cpp
@@ -0,0 +1,55 @@
+//
+// 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 "StrokeIO.h"
+#include "StrokeAdvancedIterators.h"
+
+
+ostream& operator<<(ostream& out, const StrokeAttribute& iStrokeAttribute){
+ out << " StrokeAttribute" << endl;
+ out << " color : (" << iStrokeAttribute.getColorR() << "," << iStrokeAttribute.getColorG() << "," << iStrokeAttribute.getColorB() << ")" << endl;
+ out << " alpha : " << iStrokeAttribute.getAlpha() << endl;
+ out << " thickness : " << iStrokeAttribute.getThicknessR() << ", " << iStrokeAttribute.getThicknessL() << endl;
+ out << " visible : " << iStrokeAttribute.isVisible() << endl;
+ return out;
+}
+
+ostream& operator<<(ostream& out, const StrokeVertex& iStrokeVertex){
+ out << " StrokeVertex" << endl;
+ out << " id : " << iStrokeVertex.getId() << endl;
+ out << " curvilinear length : " << iStrokeVertex.curvilinearAbscissa() << endl;
+ out << " 2d coordinates : (" << iStrokeVertex.getProjectedX() << "," << iStrokeVertex.getProjectedY() << "," << iStrokeVertex.getProjectedZ() << ")" << endl;
+ out << " 3d coordinates : (" << iStrokeVertex.getX() << "," << iStrokeVertex.getY() << "," << iStrokeVertex.getZ() << ")"<< endl;
+ out << iStrokeVertex.attribute() << endl;
+ return out;
+}
+
+ostream& operator<<(ostream& out, const Stroke& iStroke){
+ out << "Stroke" << endl;
+ out << " id : " << iStroke.getId() << endl;
+ out << " length : " << iStroke.getLength2D() << endl;
+ out << " medium type : " << iStroke.getMediumType() << endl;
+ for(Stroke::const_vertex_iterator v=iStroke.vertices_begin(), vend=iStroke.vertices_end();
+ v!=vend;
+ ++v){
+ out << *(*v) << endl;
+ }
+ return out;
+} \ No newline at end of file
diff --git a/source/blender/freestyle/intern/stroke/StrokeIO.h b/source/blender/freestyle/intern/stroke/StrokeIO.h
new file mode 100755
index 00000000000..42b99420f4a
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/StrokeIO.h
@@ -0,0 +1,47 @@
+//
+// Filename : StrokeIO.h
+// Author(s) : Stephane Grabli
+// Purpose : Functions to manage I/O for the stroke
+// Date of creation : 03/02/2004
+//
+///////////////////////////////////////////////////////////////////////////////
+
+
+//
+// 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef STROKEIO_H
+# define STROKEIO_H
+
+# include <iostream>
+# include "../system/FreestyleConfig.h"
+# include "Stroke.h"
+
+LIB_STROKE_EXPORT
+ostream& operator<<(ostream& out, const StrokeAttribute& iStrokeAttribute);
+
+LIB_STROKE_EXPORT
+ostream& operator<<(ostream& out, const StrokeVertex& iStrokeVertex);
+
+LIB_STROKE_EXPORT
+ostream& operator<<(ostream& out, const Stroke& iStroke);
+
+
+#endif // STROKEIO_H \ No newline at end of file
diff --git a/source/blender/freestyle/intern/stroke/StrokeIterators.h b/source/blender/freestyle/intern/stroke/StrokeIterators.h
new file mode 100755
index 00000000000..9cc08a0532a
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/StrokeIterators.h
@@ -0,0 +1,227 @@
+//
+// Filename : StrokeIterators.h
+// Author(s) : Stephane Grabli
+// Purpose : Iterators used to iterate over the elements of the Stroke
+// Date of creation : 01/07/2003
+//
+///////////////////////////////////////////////////////////////////////////////
+
+
+//
+// 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef STROKEITERATORS_H
+# define STROKEITERATORS_H
+
+# include "Stroke.h"
+
+namespace StrokeInternal {
+
+ //
+ // StrokeVertexIterator
+ //
+ /////////////////////////////////////////////////
+
+ /*! Class defining an iterator designed to iterate over
+ * the StrokeVertex of a Stroke.
+ * An instance of a StrokeVertexIterator can only be obtained
+ * from a Stroke by calling strokeVerticesBegin() or strokeVerticesEnd().
+ * It is iterating over the same vertices as an Interface0DIterator.
+ * The difference resides in the object access. Indeed, an Interface0DIterator
+ * allows only an access to an Interface0D whereas we could need
+ * to access the specialized StrokeVertex type. In this case, one
+ * should use a StrokeVertexIterator.
+ * The castToInterface0DIterator() method is useful to get an Interface0DIterator
+ * from a StrokeVertexIterator in order to call any functions of the
+ * type UnaryFunction0D.
+ * \attention In the scripting language, you must call
+ * \code it2 = StrokeVertexIterator(it1) \endcode instead of
+ * \code it2 = it1 \endcode
+ * where \a it1 and \a it2 are 2 StrokeVertexIterator.
+ * Otherwise, incrementing \a it1 will also increment \a it2.
+ */
+ class StrokeVertexIterator : public Interface0DIteratorNested
+ {
+ public:
+
+ /*! Default constructor. */
+ StrokeVertexIterator() {}
+
+ /*! Copy constructor. */
+ StrokeVertexIterator(const StrokeVertexIterator& vi) {
+ _it = vi._it;
+ _begin = vi._begin;
+ _end = vi._end;
+ }
+
+ StrokeVertexIterator(const ::Stroke::vertex_container::iterator& it,
+ const ::Stroke::vertex_container::iterator& begin,
+ const ::Stroke::vertex_container::iterator& end) {
+ _it = it;
+ _begin = begin;
+ _end = end;
+ }
+
+ virtual ~StrokeVertexIterator() {}
+
+ /*! Casts this StrokeVertexIterator into an Interface0DIterator.
+ * Useful for any call to a function of the type UnaryFunction0D.
+ */
+ inline Interface0DIterator castToInterface0DIterator() const {
+ Interface0DIterator ret(new StrokeVertexIterator(*this));
+ return ret;
+ }
+ /*! operator=
+ * \attention In the scripting language, you must call
+ * \code it2 = StrokeVertexIterator(it1) \endcode instead of
+ * \code it2 = it1 \endcode
+ * where \a it1 and \a it2 are 2 StrokeVertexIterator.
+ * Otherwise, incrementing \a it1 will also increment \a it2.
+ *
+ */
+ StrokeVertexIterator& operator=(const StrokeVertexIterator& vi) {
+ _it = vi._it;
+ _begin = vi._begin;
+ _end = vi._end;
+ return *this;
+ }
+
+ /*! Returns the string "StrokeVertexIterator". */
+ virtual string getExactTypeName() const {
+ return "StrokeVertexIterator";
+ }
+
+ /*! Returns a reference to the pointed StrokeVertex.
+ * In the scripting language, you must call
+ * "getObject()"instead.
+ */
+ virtual StrokeVertex& operator*() {
+ return **_it;
+ }
+
+ /*! Returns a pointer to the pointed StrokeVertex.
+ * Can't be called in the scripting language.
+ */
+ virtual StrokeVertex* operator->() {
+ return &(operator*());
+ }
+
+ /*! Increments. In the scripting language, call
+ * "increment()".
+ */
+ virtual StrokeVertexIterator& operator++() {
+ increment();
+ return *this;
+ }
+
+ /*! Increments. In the scripting language, call
+ * "increment()".
+ */
+ virtual StrokeVertexIterator operator++(int) {
+ StrokeVertexIterator ret(*this);
+ increment();
+ return ret;
+ }
+
+ /*! Decrements. In the scripting language, call
+ * "decrement()".
+ */
+ virtual StrokeVertexIterator& operator--() {
+ decrement();
+ return *this;
+ }
+
+ /*! Decrements. In the scripting language, call
+ * "decrement()".
+ */
+ virtual StrokeVertexIterator operator--(int) {
+ StrokeVertexIterator ret(*this);
+ decrement();
+ return ret;
+ }
+
+ /*! Increments. */
+ virtual void increment() {
+ ++_it;
+ }
+
+ /*! Decrements. */
+ virtual void decrement() {
+ --_it;
+ }
+
+ /*! Returns true if the pointed StrokeVertex is the
+ * first of the Stroke.
+ */
+ bool isBegin() const {
+ return _it == _begin;
+ }
+
+ /*! Returns true if the pointed StrokeVertex is after the
+ * last StrokeVertex of the Stroke.
+ */
+ bool isEnd() const {
+ return _it == _end;
+ }
+
+ /*! operator == */
+ virtual bool operator==(const Interface0DIteratorNested& it) const {
+ const StrokeVertexIterator* it_exact = dynamic_cast<const StrokeVertexIterator*>(&it);
+ if (!it_exact)
+ return false;
+ return (_it == it_exact->_it);
+ }
+
+ /*! Returns the curvilinear abscissa of the current point */
+ virtual float t() const{
+ return (*_it)->curvilinearAbscissa();
+ }
+ /*! Returns the point's parameter in the stroke */
+ virtual float u() const{
+ return (*_it)->u();
+ }
+
+ /*! Cloning method */
+ virtual StrokeVertexIterator* copy() const {
+ return new StrokeVertexIterator(*this);
+ }
+
+ //
+ // Not exported in Python
+ //
+ //////////////////////////////////////////////////
+
+ const ::Stroke::vertex_container::iterator& getIt() {
+ return _it;
+ }
+
+ private:
+
+ ::Stroke::vertex_container::iterator _it;
+ ::Stroke::vertex_container::iterator _begin;
+ ::Stroke::vertex_container::iterator _end;
+ };
+
+} // end of namespace StrokeInternal
+
+
+#endif // STROKEITERATORS_H
+
+
diff --git a/source/blender/freestyle/intern/stroke/StrokeLayer.cpp b/source/blender/freestyle/intern/stroke/StrokeLayer.cpp
new file mode 100755
index 00000000000..8b469399ca8
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/StrokeLayer.cpp
@@ -0,0 +1,55 @@
+
+//
+// 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 "StrokeLayer.h"
+#include "Stroke.h"
+#include "Canvas.h"
+
+StrokeLayer::~StrokeLayer()
+{
+ clear();
+}
+
+void StrokeLayer::Render(const StrokeRenderer *iRenderer )
+{
+ for(StrokeLayer::stroke_container::iterator s=_strokes.begin(), send=_strokes.end();
+ s!=send;
+ ++s){
+ (*s)->Render(iRenderer);
+ }
+}
+
+void StrokeLayer::RenderBasic(const StrokeRenderer *iRenderer )
+{
+ for(StrokeLayer::stroke_container::iterator s=_strokes.begin(), send=_strokes.end();
+ s!=send;
+ ++s){
+ (*s)->RenderBasic(iRenderer);
+ }
+}
+void StrokeLayer::clear()
+{
+ for(stroke_container::iterator s=_strokes.begin(), send=_strokes.end();
+ s!=send;
+ ++s)
+ delete *s;
+ _strokes.clear();
+}
diff --git a/source/blender/freestyle/intern/stroke/StrokeLayer.h b/source/blender/freestyle/intern/stroke/StrokeLayer.h
new file mode 100755
index 00000000000..b89b77a85a7
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/StrokeLayer.h
@@ -0,0 +1,75 @@
+//
+// Filename : StrokeLayer.h
+// Author : Stephane Grabli
+// Purpose : Class to define a layer of strokes.
+// Date of creation : 18/12/2002
+//
+///////////////////////////////////////////////////////////////////////////////
+
+
+//
+// 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef STROKELAYER_H
+# define STROKELAYER_H
+
+# include <deque>
+
+class Stroke;
+class StrokeRenderer;
+class StrokeLayer
+{
+public:
+ typedef std::deque<Stroke*> stroke_container;
+
+protected:
+ stroke_container _strokes;
+public:
+ StrokeLayer() {}
+ StrokeLayer(const stroke_container& iStrokes)
+ {
+ _strokes = iStrokes;
+ }
+ StrokeLayer(const StrokeLayer& iBrother)
+ {
+ _strokes = iBrother._strokes;
+ }
+ virtual ~StrokeLayer() ;
+
+ /*! Render method */
+ void Render(const StrokeRenderer *iRenderer );
+ void RenderBasic(const StrokeRenderer *iRenderer );
+
+ /*! clears the layer */
+ void clear() ;
+
+ /*! accessors */
+ inline stroke_container::iterator strokes_begin() {return _strokes.begin();}
+ inline stroke_container::iterator strokes_end() {return _strokes.end();}
+ inline int strokes_size() const {return _strokes.size();}
+ inline bool empty() const {return _strokes.empty();}
+
+ /*! modifiers */
+ inline void SetStrokes(stroke_container& iStrokes) {_strokes = iStrokes;}
+ inline void AddStroke(Stroke *iStroke) {_strokes.push_back(iStroke);}
+
+};
+
+#endif // STROKELAYER_H
diff --git a/source/blender/freestyle/intern/stroke/StrokeRenderer.cpp b/source/blender/freestyle/intern/stroke/StrokeRenderer.cpp
new file mode 100755
index 00000000000..e747fb4f5cd
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/StrokeRenderer.cpp
@@ -0,0 +1,146 @@
+
+//
+// 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 "StrokeRenderer.h"
+#include "../geometry/GeomUtils.h"
+using namespace std;
+
+/**********************************/
+/* */
+/* */
+/* StrokeRenderer */
+/* */
+/* */
+/**********************************/
+
+LIB_STROKE_EXPORT
+TextureManager *StrokeRenderer::_textureManager = 0;
+
+StrokeRenderer::StrokeRenderer ()
+{
+}
+
+StrokeRenderer::~StrokeRenderer ()
+{
+}
+
+bool StrokeRenderer::loadTextures()
+{
+ _textureManager->load();
+ return true;
+}
+
+// unsigned int StrokeRenderer::getPaperTextureIndex(unsigned int index)
+// {
+ // return _textureManager->getPaperTextureIndex(index);
+// }
+
+
+/**********************************/
+/* */
+/* */
+/* TextureManager */
+/* */
+/* */
+/**********************************/
+
+
+LIB_STROKE_EXPORT
+TextureManager* TextureManager::_pInstance = 0;
+
+LIB_STROKE_EXPORT
+vector<string> TextureManager::_papertextures;
+
+LIB_STROKE_EXPORT
+string TextureManager::_patterns_path;
+
+LIB_STROKE_EXPORT
+string TextureManager::_brushes_path;
+
+TextureManager::TextureManager ()
+{
+ _papertexname = NULL;
+ _hasLoadedTextures=false;
+ _pInstance = this;
+ _defaultTextureId = 0;
+}
+
+TextureManager::~TextureManager ()
+{
+ if (_papertexname)
+ delete _papertexname;
+ if(!_brushesMap.empty())
+ _brushesMap.clear();
+ _pInstance = 0;
+}
+
+void TextureManager::load()
+{
+ if(_hasLoadedTextures)
+ return ;
+ loadPapers();
+ loadStandardBrushes();
+ _hasLoadedTextures = true;
+}
+
+unsigned TextureManager::getBrushTextureIndex(string name, Stroke::MediumType loadingMode)
+{
+ BrushTexture bt(name,loadingMode);
+ brushesMap::iterator b = _brushesMap.find(bt);
+ if(b == _brushesMap.end()){
+ unsigned texId = loadBrush(name, loadingMode);
+ _brushesMap[bt] = texId;
+ return texId;
+ cout << "brush file " << name << " not found" << endl;
+ return 0;
+ }else{
+ return _brushesMap[bt];
+ }
+}
+
+vector<string>& TextureManager::Options::getPaperTextures() {
+ return _papertextures;
+}
+
+void TextureManager::Options::setPaperTextures(const vector<string>& sl) {
+ _papertextures = sl;
+}
+
+void TextureManager::Options::setPatternsPath(const string& path) {
+ _patterns_path = path;
+}
+
+string TextureManager::Options::getPatternsPath() {
+ return _patterns_path;
+}
+
+void TextureManager::Options::setBrushesPath(const string& path) {
+ _brushes_path = path;
+}
+
+string TextureManager::Options::getBrushesPath() {
+ return _brushes_path;
+}
+
+unsigned TextureManager::getPaperTexturesNumber() {
+ return _papertextures.size();
+}
+
diff --git a/source/blender/freestyle/intern/stroke/StrokeRenderer.h b/source/blender/freestyle/intern/stroke/StrokeRenderer.h
new file mode 100755
index 00000000000..d192fe30145
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/StrokeRenderer.h
@@ -0,0 +1,140 @@
+//
+// Filename : StrokeRenderer.h
+// Author(s) : Fredo Durand
+// Purpose : Classes to render a stroke with OpenGL
+// Date of creation : 09/09/2002
+//
+///////////////////////////////////////////////////////////////////////////////
+
+
+//
+// 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef STROKE_RENDERER_H
+# define STROKE_RENDERER_H
+
+# include <vector>
+# include <map>
+# include <utility>
+# include "../system/FreestyleConfig.h"
+# include "Stroke.h"
+# include "StrokeRep.h"
+# include <string.h>
+
+
+/**********************************/
+/* */
+/* */
+/* TextureManager */
+/* */
+/* */
+/**********************************/
+
+
+/*! Class to load textures
+ */
+class LIB_STROKE_EXPORT TextureManager
+{
+public:
+
+ TextureManager ();
+ virtual ~TextureManager ();
+ static TextureManager * getInstance() {return _pInstance;}
+ void load () ;
+ unsigned getBrushTextureIndex(string name, Stroke::MediumType iType = Stroke::OPAQUE_MEDIUM) ;
+ unsigned getPaperTextureIndex(unsigned i) { return _papertexname[i]; }
+
+ static unsigned getPaperTexturesNumber();
+ inline bool hasLoaded() const {return _hasLoadedTextures;}
+ inline unsigned int getDefaultTextureId() const {return _defaultTextureId;}
+
+ struct LIB_STROKE_EXPORT Options
+ {
+ static void setPaperTextures(const vector<string>& sl);
+ static vector<string>& getPaperTextures();
+
+ static void setPatternsPath(const string& path);
+ static string getPatternsPath();
+
+ static void setBrushesPath(const string& path);
+ static string getBrushesPath();
+ };
+
+ protected:
+ virtual void loadPapers() = 0;
+ virtual void loadStandardBrushes() = 0;
+ virtual unsigned loadBrush(string fileName, Stroke::MediumType = Stroke::OPAQUE_MEDIUM) = 0;
+
+ typedef std::pair<string,Stroke::MediumType> BrushTexture;
+ struct cmpBrushTexture{
+ bool operator()(const BrushTexture& bt1, const BrushTexture& bt2) const{
+ int r = strcmp(bt1.first.c_str(), bt2.first.c_str());
+ if(r != 0)
+ return (r<0);
+ else
+ return (bt1.second < bt2.second);
+ }
+ };
+ typedef std::map<BrushTexture, unsigned, cmpBrushTexture> brushesMap;
+
+ static TextureManager * _pInstance;
+ bool _hasLoadedTextures;
+ brushesMap _brushesMap;
+ unsigned* _papertexname;
+ static string _patterns_path;
+ static string _brushes_path;
+ static vector<string> _papertextures;
+ unsigned int _defaultTextureId;
+};
+
+
+/**********************************/
+/* */
+/* */
+/* StrokeRenderer */
+/* */
+/* */
+/**********************************/
+
+/*! Class to render a stroke.
+ Creates a triangle strip and stores it
+ strip is lazily created at the first rendering
+*/
+class LIB_STROKE_EXPORT StrokeRenderer
+{
+ public:
+ StrokeRenderer();
+ virtual ~StrokeRenderer ();
+
+ /*! Renders a stroke rep */
+ virtual void RenderStrokeRep(StrokeRep *iStrokeRep) const = 0;
+ virtual void RenderStrokeRepBasic(StrokeRep *iStrokeRep) const = 0;
+
+ // initializes the texture manager
+ // lazy, checks if it has already been done
+ static bool loadTextures() ;
+
+ //static unsigned int getTextureIndex(unsigned int index) ;
+ //static unsigned int getPaperTextureIndex(unsigned int index) ;
+ static TextureManager *_textureManager;
+};
+
+
+#endif // STROKE_RENDERER_H
diff --git a/source/blender/freestyle/intern/stroke/StrokeRep.cpp b/source/blender/freestyle/intern/stroke/StrokeRep.cpp
new file mode 100755
index 00000000000..055e1fb1be4
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/StrokeRep.cpp
@@ -0,0 +1,820 @@
+
+//
+// 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 "StrokeRep.h"
+#include "Stroke.h"
+#include "StrokeRenderer.h"
+#include "StrokeAdvancedIterators.h"
+#include "StrokeIterators.h"
+
+using namespace std;
+
+//
+// STROKE VERTEX REP
+/////////////////////////////////////
+StrokeVertexRep::StrokeVertexRep(const StrokeVertexRep& iBrother){
+ _point2d = iBrother._point2d;
+ _texCoord = iBrother._texCoord;
+ _color = iBrother._color;
+ _alpha = iBrother._alpha;
+}
+
+//
+// STRIP
+/////////////////////////////////////
+
+Strip::Strip(const vector<StrokeVertex*>& iStrokeVertices, bool hasTips, bool beginTip, bool endTip){
+ createStrip(iStrokeVertices);
+ if (!hasTips)
+ computeTexCoord (iStrokeVertices);
+ else
+ computeTexCoordWithTips (iStrokeVertices, beginTip, endTip);
+}
+Strip::Strip(const Strip& iBrother){
+ if(!iBrother._vertices.empty()){
+ for(vertex_container::const_iterator v=iBrother._vertices.begin(), vend=iBrother._vertices.end();
+ v!=vend;
+ ++v){
+ _vertices.push_back(new StrokeVertexRep(**v));
+ }
+ }
+ _averageThickness = iBrother._averageThickness;
+}
+
+Strip::~Strip(){
+ if(!_vertices.empty()){
+ for(vertex_container::iterator v=_vertices.begin(), vend=_vertices.end();
+ v!=vend;
+ ++v){
+ delete (*v);
+ }
+ _vertices.clear();
+ }
+}
+
+//////////////////////////
+// Strip creation
+//////////////////////////
+#define EPS_SINGULARITY_RENDERER 0.05
+#define ZERO 0.00001
+#define MAX_RATIO_LENGTH_SINGU 2
+#define HUGE_COORD 1e4
+
+bool notValid (Vec2r p)
+{
+ return (p[0]!=p[0]) || (p[1]!=p[1]) || (fabs(p[0])>HUGE_COORD) || (fabs(p[1])>HUGE_COORD)
+ || (p[0] <-HUGE_COORD) || (p[1]<-HUGE_COORD);
+}
+
+real crossP(const Vec2r& A, const Vec2r& B){
+ return A[0]*B[1] - A[1]*B[0];
+}
+
+void
+Strip::createStrip (const vector<StrokeVertex*>& iStrokeVertices)
+{
+ //computeParameterization();
+ if (iStrokeVertices.size() <2)
+ {
+ cerr << "Warning: strip has less than 2 vertices" << endl;
+ return;
+ }
+ _vertices.reserve(2*iStrokeVertices.size());
+ if(!_vertices.empty()){
+ for(vertex_container::iterator v=_vertices.begin(), vend=_vertices.end();
+ v!=vend;
+ ++v){
+ delete (*v);
+ }
+ _vertices.clear();
+ }
+ _averageThickness=0.0;
+
+ vector<StrokeVertex*>::const_iterator v ,vend, v2, vPrev;
+ StrokeVertex *sv, *sv2, *svPrev;
+
+ //special case of first vertex
+ v=iStrokeVertices.begin();
+ sv=*v;
+ vPrev=v; //in case the stroke has only 2 vertices;
+ ++v; sv2=*v;
+ Vec2r dir(sv2->getPoint()-sv->getPoint());
+ Vec2r orthDir(-dir[1], dir[0]);
+ if (orthDir.norm() > ZERO)
+ orthDir.normalize();
+ const float *thickness = sv->attribute().getThickness();
+ _vertices.push_back(new StrokeVertexRep(sv->getPoint()+thickness[1]*orthDir));
+ _vertices.push_back(new StrokeVertexRep(sv->getPoint()-thickness[0]*orthDir));
+
+ Vec2r stripDir(orthDir);
+ // check whether the orientation
+ // was user defined
+ if(sv->attribute().isAttributeAvailableVec2f("orientation")){
+ Vec2r userDir = sv->attribute().getAttributeVec2f("orientation");
+ userDir.normalize();
+ Vec2r t(orthDir[1], -orthDir[0]);
+ real dp1 = userDir*orthDir;
+ real dp2 = userDir*t;
+ real h = (thickness[1]+thickness[0])/dp1;
+ real x = fabs(h*dp2/2.0);
+ if(dp1>0){
+ //i'm in the upper part of the unit circle
+ if(dp2>0){
+ //i'm in the upper-right part of the unit circle
+ // i must move vertex 1
+ _vertices[1]->setPoint2d(_vertices[0]->point2d()-userDir*(h));
+ //_vertices[0]->setPoint2d(_vertices[0]->point2d()+t*x);
+ //_vertices[1]->setPoint2d(_vertices[1]->point2d()-t*x);
+ }else{
+ //i'm in the upper-left part of the unit circle
+ // i must move vertex 0
+ _vertices[0]->setPoint2d(_vertices[1]->point2d()+userDir*(h));
+ //_vertices[0]->setPoint2d(_vertices[0]->point2d()-t*x);
+ //_vertices[1]->setPoint2d(_vertices[1]->point2d()+t*x);
+ }
+ }else{
+ //i'm in the lower part of the unit circle
+ if(dp2>0){
+ //i'm in the lower-right part of the unit circle
+ // i must move vertex 0
+ //_vertices[0]->setPoint2d(_vertices[1]->point2d()-userDir*(h));
+ _vertices[0]->setPoint2d(_vertices[0]->point2d()-t*x);
+ //_vertices[1]->setPoint2d(_vertices[1]->point2d()+t*x);
+ }else{
+ //i'm in the lower-left part of the unit circle
+ // i must move vertex 1
+ _vertices[1]->setPoint2d(_vertices[0]->point2d()+userDir*(h));
+ //_vertices[0]->setPoint2d(_vertices[0]->point2d()-t*x);
+ //_vertices[1]->setPoint2d(_vertices[1]->point2d()-t*x);
+ }
+ }
+ }
+
+
+ // Vec2r userDir = _stroke->getBeginningOrientation();
+ // if(userDir != Vec2r(0,0)){
+ // userDir.normalize();
+ // real o1 = (orthDir*userDir);
+ // real o2 = crossP(orthDir,userDir);
+ // real orientation = o1 * o2;
+ // if(orientation > 0){
+ // // then the vertex to move is v0
+ // if(o1 > 0)
+ // _vertex[0]=_vertex[1]+userDir;
+ // else
+ // _vertex[0]=_vertex[1]-userDir;
+ // }
+ // if(orientation < 0){
+ // // then we must move v1
+ // if(o1 < 0)
+ // _vertex[1]=_vertex[0]+userDir;
+ // else
+ // _vertex[1]=_vertex[0]-userDir;
+ // }
+ // }
+
+ int i=2; //2 because we have already processed the first vertex
+
+ for(vend=iStrokeVertices.end();
+ v!=vend;
+ v++){
+ v2=v; ++v2;
+ if (v2==vend) break;
+ sv= (*v); sv2 = (*v2); svPrev=(*vPrev);
+ Vec2r p(sv->getPoint()), p2(sv2->getPoint()), pPrev(svPrev->getPoint());
+
+ //direction and orthogonal vector to the next segment
+ Vec2r dir(p2-p);
+ float dirNorm=dir.norm();
+ dir.normalize();
+ Vec2r orthDir(-dir[1], dir[0]);
+ Vec2r stripDir = orthDir;
+ if(sv->attribute().isAttributeAvailableVec2f("orientation")){
+ Vec2r userDir = sv->attribute().getAttributeVec2f("orientation");
+ userDir.normalize();
+ real dp = userDir*orthDir;
+ if(dp<0)
+ userDir = userDir*(-1.f);
+ stripDir = userDir;
+ }
+
+ //direction and orthogonal vector to the previous segment
+ Vec2r dirPrev(p-pPrev);
+ float dirPrevNorm=dirPrev.norm();
+ dirPrev.normalize();
+ Vec2r orthDirPrev(-dirPrev[1], dirPrev[0]);
+ Vec2r stripDirPrev = orthDirPrev;
+ if(svPrev->attribute().isAttributeAvailableVec2f("orientation")){
+ Vec2r userDir = svPrev->attribute().getAttributeVec2f("orientation");
+ userDir.normalize();
+ real dp = userDir*orthDir;
+ if(dp<0)
+ userDir = userDir*(-1.f);
+ stripDirPrev = userDir;
+ }
+
+ const float *thickness = sv->attribute().getThickness();
+ _averageThickness+=thickness[0]+thickness[1];
+ Vec2r pInter;
+ int interResult;
+
+ interResult=GeomUtils::intersect2dLine2dLine(Vec2r(pPrev+thickness[1]*stripDirPrev), Vec2r(p+thickness[1]*stripDirPrev),
+ Vec2r(p+thickness[1]*stripDir), Vec2r(p2+thickness[1]*stripDir),
+ pInter);
+
+ if (interResult==GeomUtils::DO_INTERSECT)
+ _vertices.push_back(new StrokeVertexRep(pInter));
+ else
+ _vertices.push_back(new StrokeVertexRep(p+thickness[1]*stripDir));
+ ++i;
+
+ interResult=GeomUtils::intersect2dLine2dLine(Vec2r(pPrev-thickness[0]*stripDirPrev), Vec2r(p-thickness[0]*stripDirPrev),
+ Vec2r(p-thickness[0]*stripDir), Vec2r(p2-thickness[0]*stripDir),
+ pInter);
+ if (interResult==GeomUtils::DO_INTERSECT)
+ _vertices.push_back(new StrokeVertexRep(pInter));
+ else
+ _vertices.push_back(new StrokeVertexRep(p-thickness[0]*stripDir));
+ ++i;
+
+ // if the angle is obtuse, we simply average the directions to avoid the singularity
+ stripDir=stripDir+stripDirPrev;
+ if ((dirNorm<ZERO) || (dirPrevNorm<ZERO) || (stripDir.norm() < ZERO)) {
+ stripDir[0] = 0;
+ stripDir[1] = 0;
+ }else
+ stripDir.normalize();
+
+ Vec2r vec_tmp(_vertices[i-2]->point2d()-p);
+ if ((vec_tmp.norm() > thickness[1]*MAX_RATIO_LENGTH_SINGU) ||
+ (dirNorm<ZERO) || (dirPrevNorm<ZERO) ||
+ notValid(_vertices[i-2]->point2d())
+ || (fabs(stripDir * dir) < EPS_SINGULARITY_RENDERER))
+ _vertices[i-2]->setPoint2d(p+thickness[1]*stripDir);
+
+ vec_tmp = _vertices[i-1]->point2d()-p;
+ if ((vec_tmp.norm() > thickness[1]*MAX_RATIO_LENGTH_SINGU) ||
+ (dirNorm<ZERO) || (dirPrevNorm<ZERO) ||
+ notValid(_vertices[i-1]->point2d())
+ || (fabs(stripDir * dir)<EPS_SINGULARITY_RENDERER))
+ _vertices[i-1]->setPoint2d(p-thickness[0]*stripDir);
+
+ vPrev=v;
+ } // end of for
+
+ //special case of last vertex
+ sv=*v;
+ sv2=*vPrev;
+ dir=Vec2r (sv->getPoint()-sv2->getPoint());
+ orthDir=Vec2r(-dir[1], dir[0]);
+ if (orthDir.norm() > ZERO)
+ orthDir.normalize();
+ const float *thicknessLast = sv->attribute().getThickness();
+ _vertices.push_back(new StrokeVertexRep(sv->getPoint()+thicknessLast[1]*orthDir));
+ ++i;
+ _vertices.push_back(new StrokeVertexRep(sv->getPoint()-thicknessLast[0]*orthDir));
+ int n = i;
+ ++i;
+
+ // check whether the orientation
+ // was user defined
+ if(sv->attribute().isAttributeAvailableVec2f("orientation")){
+ Vec2r userDir = sv->attribute().getAttributeVec2f("orientation");
+ userDir.normalize();
+ Vec2r t(orthDir[1], -orthDir[0]);
+ real dp1 = userDir*orthDir;
+ real dp2 = userDir*t;
+ real h = (thicknessLast[1]+thicknessLast[0])/dp1;
+ real x = fabs(h*dp2/2.0);
+ if(dp1>0){
+ //i'm in the upper part of the unit circle
+ if(dp2>0){
+ //i'm in the upper-right part of the unit circle
+ // i must move vertex n-1
+ _vertices[n-1]->setPoint2d(_vertices[n]->point2d()-userDir*(h));
+ //_vertices[n-1]->setPoint2d(_vertices[n-1]->point2d()+t*x);
+ //_vertices[n]->setPoint2d(_vertices[n]->point2d()-t*x);
+ }else{
+ //i'm in the upper-left part of the unit circle
+ // i must move vertex n
+ _vertices[n]->setPoint2d(_vertices[n-1]->point2d()+userDir*(h));
+ //_vertices[n-1]->setPoint2d(_vertices[n-1]->point2d()-t*x);
+ //_vertices[n]->setPoint2d(_vertices[n]->point2d()+t*x);
+ }
+ }else{
+ //i'm in the lower part of the unit circle
+ if(dp2>0){
+ //i'm in the lower-right part of the unit circle
+ // i must move vertex n
+ _vertices[n]->setPoint2d(_vertices[n-1]->point2d()-userDir*(h));
+ //_vertices[n-1]->setPoint2d(_vertices[n-1]->point2d()-t*x);
+ //_vertices[n]->setPoint2d(_vertices[n]->point2d()+t*x);
+ }else{
+ //i'm in the lower-left part of the unit circle
+ // i must move vertex n-1
+ _vertices[n-1]->setPoint2d(_vertices[n]->point2d()+userDir*(h));
+ //_vertices[n-1]->setPoint2d(_vertices[n-1]->point2d()+t*x);
+ //_vertices[n]->setPoint2d(_vertices[n]->point2d()-t*x);
+ }
+ }
+ }
+
+
+ // check whether the orientation of the extremity
+ // was user defined
+ // userDir = _stroke->getEndingOrientation();
+ // if(userDir != Vec2r(0,0)){
+ // userDir.normalize();
+ // real o1 = (orthDir*userDir);
+ // real o2 = crossP(orthDir,userDir);
+ // real orientation = o1 * o2;
+ // if(orientation > 0){
+ // // then the vertex to move is vn
+ // if(o1 < 0)
+ // _vertex[n]=_vertex[n-1]+userDir;
+ // else
+ // _vertex[n]=_vertex[n-1]-userDir;
+ // }
+ // if(orientation < 0){
+ // // then we must move vn-1
+ // if(o1 > 0)
+ // _vertex[n-1]=_vertex[n]+userDir;
+ // else
+ // _vertex[n-1]=_vertex[n]-userDir;
+ // }
+ // }
+
+ _averageThickness/=float(iStrokeVertices.size()-2);
+ //I did not use the first and last vertex for the average
+ if (iStrokeVertices.size()<3)
+ _averageThickness=0.5*(thicknessLast[1]+thicknessLast[0]+thickness[0]+thickness[1]);
+
+ if (i!=2*iStrokeVertices.size())
+ cerr << "Warning: problem with stripe size\n";
+
+ cleanUpSingularities (iStrokeVertices);
+}
+
+// CLEAN UP
+/////////////////////////
+
+void
+Strip::cleanUpSingularities (const vector<StrokeVertex*>& iStrokeVertices)
+{
+ int k;
+ unsigned sizeStrip = _vertices.size();
+
+ for (k=0; k<sizeStrip; k++)
+ if (notValid(_vertices[k]->point2d()))
+ {
+ cerr << "Warning: strip vertex " << k << " non valid" << endl;
+ return;
+ }
+
+ //return;
+ if (iStrokeVertices.size()<2) return;
+ int i=0, j;
+ vector<StrokeVertex*>::const_iterator v ,vend, v2, vPrev;
+ StrokeVertex *sv, *sv2, *svPrev;
+
+ bool singu1=false, singu2=false;
+ int timeSinceSingu1=0, timeSinceSingu2=0;
+
+ //special case of first vertex
+ v=iStrokeVertices.begin();
+ for(vend=iStrokeVertices.end();
+ v!=vend;
+ v++)
+ {
+ v2=v; ++v2;
+ if (v2==vend) break;
+ sv= (*v); sv2 = (*v2);
+ Vec2r p(sv->getPoint()), p2(sv2->getPoint());
+
+ Vec2r dir(p2-p);
+ if (dir.norm() > ZERO)
+ dir.normalize();
+ Vec2r dir1, dir2;
+ dir1=_vertices[2*i+2]->point2d()-_vertices[2*i]->point2d();
+ dir2=_vertices[2*i+3]->point2d()-_vertices[2*i+1]->point2d();
+
+ if ((dir1 * dir) < -ZERO)
+ {
+ singu1=true;
+ timeSinceSingu1++;
+ }
+ else
+ {
+ if (singu1)
+ {
+ int toto=i-timeSinceSingu1;
+ if (toto<0)
+ cerr << "Stephane dit \"Toto\"" << endl;
+ //traverse all the vertices of the singularity and average them
+ Vec2r avP(0.0,0.0);
+ for (j=i-timeSinceSingu1; j<i+1; j++)
+ avP=Vec2r(avP+_vertices[2*j]->point2d());
+ avP=Vec2r(1.0/float(timeSinceSingu1+1)*avP);
+ for (j=i-timeSinceSingu1; j<i+1; j++)
+ _vertices[2*j]->setPoint2d(avP);
+ //_vertex[2*j]=_vertex[2*i];
+ singu1=false; timeSinceSingu1=0;
+ }
+ }
+ if ((dir2 * dir) < -ZERO)
+ {
+ singu2=true;
+ timeSinceSingu2++;
+ }
+ else
+ {
+ if (singu2)
+ {
+ int toto=i-timeSinceSingu2;
+ if (toto<0)
+ cerr << "Stephane dit \"Toto\"" << endl;
+ //traverse all the vertices of the singularity and average them
+ Vec2r avP(0.0,0.0);
+ for (j=i-timeSinceSingu2; j<i+1; j++)
+ avP=Vec2r(avP+_vertices[2*j+1]->point2d());
+ avP=Vec2r(1.0/float(timeSinceSingu2+1)*avP);
+ for (j=i-timeSinceSingu2; j<i+1; j++)
+ _vertices[2*j+1]->setPoint2d(avP);
+ //_vertex[2*j+1]=_vertex[2*i+1];
+ singu2=false; timeSinceSingu2=0;
+ }
+ }
+ i++;
+ }
+
+ if (singu1)
+ {
+ //traverse all the vertices of the singularity and average them
+ Vec2r avP(0.0,0.0);
+ for (int j=i-timeSinceSingu1; j<i; j++)
+ avP=Vec2r(avP+_vertices[2*j]->point2d());
+ avP=Vec2r(1.0/float(timeSinceSingu1)*avP);
+ for (j=i-timeSinceSingu1; j<i; j++)
+ _vertices[2*j]->setPoint2d(avP);
+ }
+ if (singu2)
+ {
+ //traverse all the vertices of the singularity and average them
+ Vec2r avP(0.0,0.0);
+ for (j=i-timeSinceSingu2; j<i; j++)
+ avP=Vec2r(avP+_vertices[2*j+1]->point2d());
+ avP=Vec2r(1.0/float(timeSinceSingu2)*avP);
+ for (j=i-timeSinceSingu2; j<i; j++)
+ _vertices[2*j+1]->setPoint2d(avP);
+ }
+
+
+ for (k=0; k<sizeStrip; k++)
+ if (notValid(_vertices[k]->point2d()))
+ {
+ cerr << "Warning: strip vertex " << k << " non valid after cleanup"<<endl;
+ return;
+ }
+}
+
+
+// Texture coordinates
+////////////////////////////////
+
+void
+Strip::computeTexCoord (const vector<StrokeVertex*>& iStrokeVertices)
+{
+ vector<StrokeVertex*>::const_iterator v ,vend;
+ StrokeVertex *sv;
+ int i=0;
+ for(v=iStrokeVertices.begin(), vend=iStrokeVertices.end();
+ v!=vend; v++)
+ {
+ sv= (*v);
+ _vertices[i]->setTexCoord(Vec2r((real)(sv->curvilinearAbscissa() / _averageThickness),0));
+ _vertices[i]->setColor(Vec3r(sv->attribute().getColor()[0],sv->attribute().getColor()[1],sv->attribute().getColor()[2]));
+ _vertices[i]->setAlpha(sv->attribute().getAlpha());
+ i++;
+ _vertices[i]->setTexCoord(Vec2r((real)(sv->curvilinearAbscissa() / _averageThickness),1));
+ _vertices[i]->setColor(Vec3r(sv->attribute().getColor()[0],sv->attribute().getColor()[1],sv->attribute().getColor()[2]));
+ _vertices[i]->setAlpha(sv->attribute().getAlpha());
+ i++;
+ // cerr<<"col=("<<sv->attribute().getColor()[0]<<", "
+ // <<sv->attribute().getColor()[1]<<", "<<sv->attribute().getColor()[2]<<")"<<endl;
+ }
+}
+
+void
+Strip::computeTexCoordWithTips (const vector<StrokeVertex*>& iStrokeVertices, bool tipBegin, bool tipEnd)
+{
+ unsigned int sizeStrip = _vertices.size()+8; //for the transition between the tip and the body
+ vector<StrokeVertex*>::const_iterator v ,vend;
+ StrokeVertex *sv;
+
+ v=iStrokeVertices.begin();
+ vend=iStrokeVertices.end();
+ float l=(*v)->strokeLength()/_averageThickness;
+ int tiles=int(l);
+ float fact=(float(tiles)+0.5)/l;
+ float uTip2=float(tiles)+0.25;
+ float u=0;
+ float uPrev;
+ int i=0;
+ float t;
+ StrokeVertexRep *tvRep1, *tvRep2;
+
+ // cerr<<"l="<<l<<" tiles="<<tiles<<" _averageThicnkess="
+ // <<_averageThickness<<" strokeLength="<<(*v)->strokeLength()<<endl;
+ //
+ vector<StrokeVertexRep*>::iterator currentSV = _vertices.begin();
+ StrokeVertexRep *svRep;
+ if(tipBegin){
+ for(;v!=vend; v++)
+ {
+ sv= (*v);
+ svRep = *currentSV;
+ u=sv->curvilinearAbscissa()/_averageThickness*fact;
+ if (u>0.25) break;
+
+
+ svRep->setTexCoord(Vec2r((real)u, 0.5));
+ svRep->setColor(Vec3r(sv->attribute().getColor()[0],sv->attribute().getColor()[1],sv->attribute().getColor()[2]));
+ svRep->setAlpha(sv->attribute().getAlpha());
+ i++;
+ ++currentSV;
+
+ svRep = *currentSV;
+ svRep->setTexCoord(Vec2r((real)u, 1));
+ svRep->setColor(Vec3r(sv->attribute().getColor()[0],sv->attribute().getColor()[1],sv->attribute().getColor()[2]));
+ svRep->setAlpha(sv->attribute().getAlpha());
+ i++;
+ ++currentSV;
+ uPrev=u;
+ }
+ //first transition vertex
+
+ if (fabs(u-uPrev)>ZERO)
+ t= (0.25-uPrev)/(u-uPrev);
+ else t=0;
+ //if (!tiles) t=0.5;
+ tvRep1 = new StrokeVertexRep(Vec2r((1-t)*_vertices[i-2]->point2d()+t*_vertices[i]->point2d()));
+ tvRep1->setTexCoord(Vec2r(0.25,0.5));
+ tvRep1->setColor(Vec3r((1-t)*_vertices[i-2]->color()+
+ t*Vec3r(sv->attribute().getColor()[0],sv->attribute().getColor()[1],sv->attribute().getColor()[2])));
+ tvRep1->setAlpha((1-t)*_vertices[i-2]->alpha()+t*sv->attribute().getAlpha());
+ i++;
+
+ tvRep2 = new StrokeVertexRep(Vec2r((1-t)*_vertices[i-2]->point2d()+t*_vertices[i]->point2d()));
+ tvRep2->setTexCoord(Vec2r(0.25,1));
+ tvRep2->setColor(Vec3r((1-t)*_vertices[i-2]->color()+
+ t*Vec3r(sv->attribute().getColor()[0],sv->attribute().getColor()[1],sv->attribute().getColor()[2])));
+ tvRep2->setAlpha((1-t)*_vertices[i-2]->alpha()+t*sv->attribute().getAlpha());
+ i++;
+
+ currentSV = _vertices.insert(currentSV, tvRep1);
+ ++currentSV;
+ currentSV = _vertices.insert(currentSV, tvRep2);
+ ++currentSV;
+
+ //copy the vertices with different texture coordinates
+ tvRep1 = new StrokeVertexRep(_vertices[i-2]->point2d());
+ tvRep1->setTexCoord(Vec2r(0.25,0));
+ tvRep1->setColor(_vertices[i-2]->color());
+ tvRep1->setAlpha(_vertices[i-2]->alpha());
+ i++;
+
+ tvRep2 = new StrokeVertexRep(_vertices[i-2]->point2d());
+ tvRep2->setTexCoord(Vec2r(0.25,0.5));
+ tvRep2->setColor(_vertices[i-2]->color());
+ tvRep2->setAlpha(_vertices[i-2]->alpha());
+ i++;
+
+ currentSV = _vertices.insert(currentSV, tvRep1);
+ ++currentSV;
+ currentSV = _vertices.insert(currentSV, tvRep2);
+ ++currentSV;
+ }
+ uPrev=0;
+
+ //body of the stroke
+ for(;v!=vend; v++)
+ {
+ sv= (*v);
+ svRep = *currentSV;
+ u=sv->curvilinearAbscissa()/_averageThickness*fact-0.25;
+ if (u>tiles) break;
+
+ svRep->setTexCoord(Vec2r((real)u, 0));
+ svRep->setColor(Vec3r(sv->attribute().getColor()[0],sv->attribute().getColor()[1],sv->attribute().getColor()[2]));
+ svRep->setAlpha(sv->attribute().getAlpha());
+ i++;
+ ++currentSV;
+
+ svRep = *currentSV;
+ svRep->setTexCoord(Vec2r((real)u, 0.5));
+ svRep->setColor(Vec3r(sv->attribute().getColor()[0],sv->attribute().getColor()[1],sv->attribute().getColor()[2]));
+ svRep->setAlpha(sv->attribute().getAlpha());
+ i++;
+ ++currentSV;
+
+ uPrev=u;
+ }
+ if(tipEnd){
+ //second transition vertex
+ if ((fabs(u-uPrev)>ZERO))
+ t= (float(tiles)-uPrev)/(u-uPrev);
+ else t=0;
+
+ tvRep1 = new StrokeVertexRep(Vec2r((1-t)*_vertices[i-2]->point2d()+t*_vertices[i]->point2d()));
+ tvRep1->setTexCoord(Vec2r((real)tiles,0));
+ tvRep1->setColor(Vec3r((1-t)*_vertices[i-2]->color()+
+ t*Vec3r(sv->attribute().getColor()[0],sv->attribute().getColor()[1],sv->attribute().getColor()[2])));
+ tvRep1->setAlpha((1-t)*_vertices[i-2]->alpha()+t*sv->attribute().getAlpha());
+ i++;
+
+ tvRep2 = new StrokeVertexRep(Vec2r((1-t)*_vertices[i-2]->point2d()+t*_vertices[i]->point2d()));
+ tvRep2->setTexCoord(Vec2r((real)tiles,0.5));
+ tvRep2->setColor(Vec3r((1-t)*_vertices[i-2]->color()+
+ t*Vec3r(sv->attribute().getColor()[0],sv->attribute().getColor()[1],sv->attribute().getColor()[2])));
+ tvRep2->setAlpha((1-t)*_vertices[i-2]->alpha()+t*sv->attribute().getAlpha());
+ i++;
+
+ currentSV = _vertices.insert(currentSV, tvRep1);
+ ++currentSV;
+ currentSV = _vertices.insert(currentSV, tvRep2);
+ ++currentSV;
+
+ //copy the vertices with different texture coordinates
+ tvRep1 = new StrokeVertexRep(_vertices[i-2]->point2d());
+ tvRep1->setTexCoord(Vec2r(0.75,0.5));
+ tvRep1->setColor(_vertices[i-2]->color());
+ tvRep1->setAlpha(_vertices[i-2]->alpha());
+ i++;
+
+ tvRep2 = new StrokeVertexRep(_vertices[i-2]->point2d());
+ tvRep2->setTexCoord(Vec2r(0.75,1));
+ tvRep2->setColor(_vertices[i-2]->color());
+ tvRep2->setAlpha(_vertices[i-2]->alpha());
+ i++;
+
+ currentSV = _vertices.insert(currentSV, tvRep1);
+ ++currentSV;
+ currentSV = _vertices.insert(currentSV, tvRep2);
+ ++currentSV;
+
+ //end tip
+ for(;v!=vend; v++)
+ {
+ sv= (*v);
+ svRep = *currentSV;
+ u=0.75+sv->curvilinearAbscissa()/_averageThickness*fact-float(tiles)-0.25;
+
+ svRep->setTexCoord(Vec2r((real)u, 0.5));
+ svRep->setColor(Vec3r(sv->attribute().getColor()[0],sv->attribute().getColor()[1],sv->attribute().getColor()[2]));
+ svRep->setAlpha(sv->attribute().getAlpha());
+ i++;
+ ++currentSV;
+
+ svRep = *currentSV;
+ svRep->setTexCoord(Vec2r((real)u, 1));
+ svRep->setColor(Vec3r(sv->attribute().getColor()[0],sv->attribute().getColor()[1],sv->attribute().getColor()[2]));
+ svRep->setAlpha(sv->attribute().getAlpha());
+ i++;
+ ++currentSV;
+ }
+ }
+ //cerr<<"u="<<u<<" i="<<i<<"/"<<_sizeStrip<<endl;;
+
+ // for (i=0; i<_sizeStrip; i++)
+ // _alpha[i]=1.0;
+
+ // for (i=0; i<_sizeStrip; i++)
+ // cerr<<"("<<_texCoord[i][0]<<", "<<_texCoord[i][1]<<") ";
+ // cerr<<endl;
+
+
+ // Vec2r vec_tmp;
+ // for (i=0; i<_sizeStrip/2; i++)
+ // vec_tmp = _vertex[2*i] - _vertex[2*i+1];
+ // if (vec_tmp.norm() > 4*_averageThickness)
+ // cerr << "Warning (from Fredo): There is a pb in the texture coordinates computation" << endl;
+}
+
+//
+// StrokeRep
+/////////////////////////////////////
+
+StrokeRep::StrokeRep()
+{
+ _stroke = 0;
+ _strokeType=Stroke::OPAQUE_MEDIUM;
+ TextureManager * ptm = TextureManager::getInstance();
+ if(ptm)
+ _textureId = ptm->getDefaultTextureId();
+ // _averageTextureAlpha=0.5; //default value
+ // if (_strokeType==OIL_STROKE)
+ // _averageTextureAlpha=0.75;
+ // if (_strokeType>=NO_BLEND_STROKE)
+ // _averageTextureAlpha=1.0
+}
+
+StrokeRep::StrokeRep(Stroke *iStroke)
+{
+ _stroke = iStroke;
+ _strokeType = iStroke->getMediumType();
+ _textureId = iStroke->getTextureId();
+ if(_textureId == 0){
+ TextureManager * ptm = TextureManager::getInstance();
+ if(ptm)
+ _textureId = ptm->getDefaultTextureId();
+ }
+
+ // _averageTextureAlpha=0.5; //default value
+ // if (_strokeType==OIL_STROKE)
+ // _averageTextureAlpha=0.75;
+ // if (_strokeType>=NO_BLEND_STROKE)
+ // _averageTextureAlpha=1.0;
+ create();
+}
+
+StrokeRep::StrokeRep(const StrokeRep& iBrother)
+{
+ int i=0;
+ _stroke = iBrother._stroke;
+ _strokeType=iBrother._strokeType;
+ _textureId = iBrother._textureId;
+ for(vector<Strip*>::const_iterator s=iBrother._strips.begin(), send=iBrother._strips.end();
+ s!=send;
+ ++s){
+ _strips.push_back(new Strip(**s));
+ }
+}
+
+
+StrokeRep::~StrokeRep()
+{
+ if(!_strips.empty()){
+ for(vector<Strip*>::iterator s=_strips.begin(), send=_strips.end();
+ s!=send;
+ ++s){
+ delete (*s);
+ }
+ _strips.clear();
+ }
+}
+
+void StrokeRep::create(){
+ vector<StrokeVertex*> strip;
+ StrokeInternal::StrokeVertexIterator v = _stroke->strokeVerticesBegin();
+ StrokeInternal::StrokeVertexIterator vend = _stroke->strokeVerticesEnd();
+
+ bool first=true;
+ bool end=false;
+ while(v!=vend){
+ while((v!=vend) && (!(*v).attribute().isVisible())){
+ ++v;
+ first = false;
+ }
+ while( (v!=vend) && ((*v).attribute().isVisible()) ) {
+ strip.push_back(&(*v));
+ ++v;
+ }
+ if(v!=vend){
+ // add the last vertex and create
+ strip.push_back(&(*v));
+ }else{
+ end=true;
+ }
+ if((!strip.empty()) && (strip.size()>1) ){
+ _strips.push_back(new Strip(strip, _stroke->hasTips(), first, end));
+ strip.clear();
+ }
+ first = false;
+ }
+}
+
+void StrokeRep::Render(const StrokeRenderer *iRenderer)
+{
+ iRenderer->RenderStrokeRep(this);
+}
+
+
+
diff --git a/source/blender/freestyle/intern/stroke/StrokeRep.h b/source/blender/freestyle/intern/stroke/StrokeRep.h
new file mode 100755
index 00000000000..129769e5489
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/StrokeRep.h
@@ -0,0 +1,138 @@
+//
+// Filename : StrokeRep.h
+// Author(s) : Stephane Grabli
+// Purpose : Class to define the representation of a stroke
+// (for display purpose)
+// Date of creation : 05/03/2003
+//
+///////////////////////////////////////////////////////////////////////////////
+
+
+//
+// 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef STROKEREP_H
+# define STROKEREP_H
+
+# include "../geometry/Geom.h"
+using namespace Geometry;
+
+//symbolic constant to call the appropriate renderers and textures
+// # define NO_TEXTURE_WITH_BLEND_STROKE -2
+// # define NO_TEXTURE_STROKE -1
+// # define PSEUDO_CHARCOAL_STROKE 0
+// # define WASH_BRUSH_STROKE 1
+// # define OIL_STROKE 2
+// # define NO_BLEND_STROKE 3
+// # define CHARCOAL_MIN_STROKE 4
+// # define BRUSH_MIN_STROKE 5
+// # define OPAQUE_DRY_STROKE 6
+// # define OPAQUE_STROKE 7
+//
+// # define DEFAULT_STROKE 0
+//
+// # define NUMBER_STROKE_RENDERER 8
+
+#include "Stroke.h"
+
+class StrokeVertexRep{
+public:
+ StrokeVertexRep(){}
+ StrokeVertexRep(const Vec2r& iPoint2d){_point2d=iPoint2d;}
+ StrokeVertexRep(const StrokeVertexRep& iBrother);
+ virtual ~StrokeVertexRep(){}
+
+ inline Vec2r& point2d() {return _point2d;}
+ inline Vec2r& texCoord() {return _texCoord;}
+ inline Vec3r& color() {return _color;}
+ inline float alpha() {return _alpha;}
+
+ inline void setPoint2d(const Vec2r& p){_point2d = p;}
+ inline void setTexCoord(const Vec2r& p){_texCoord = p;}
+ inline void setColor(const Vec3r& p){_color = p;}
+ inline void setAlpha(float a){_alpha = a;}
+protected:
+ Vec2r _point2d;
+ Vec2r _texCoord;
+ Vec3r _color;
+ float _alpha;
+};
+
+class Strip{
+public:
+ typedef std::vector<StrokeVertexRep*> vertex_container;
+protected:
+ vertex_container _vertices;
+ float _averageThickness;
+
+
+public:
+ Strip(const std::vector<StrokeVertex*>& iStrokeVertices, bool hasTips=false, bool tipBegin=false, bool tipEnd=false) ;
+ Strip(const Strip& iBrother);
+ virtual ~Strip() ;
+
+protected:
+ void createStrip(const std::vector<StrokeVertex*>& iStrokeVertices);
+ void cleanUpSingularities(const std::vector<StrokeVertex*>& iStrokeVertices);
+ void computeTexCoord (const std::vector<StrokeVertex*>& iStrokeVertices);
+ void computeTexCoordWithTips (const std::vector<StrokeVertex*>& iStrokeVertices, bool tipBegin, bool tipEnd);
+public:
+ inline int sizeStrip() const {return _vertices.size();}
+ inline vertex_container& vertices() {return _vertices;}
+};
+
+class StrokeRep
+{
+protected:
+ Stroke *_stroke;
+ vector<Strip*> _strips;
+ Stroke::MediumType _strokeType;
+ unsigned int _textureId;
+
+ // float _averageTextureAlpha;
+
+
+public:
+ StrokeRep();
+ StrokeRep(const StrokeRep&);
+ StrokeRep(Stroke *iStroke);
+ virtual ~StrokeRep();
+
+ /*! Creates the strips */
+ virtual void create() ;
+
+ /*! Renders the stroke using a Renderer */
+ virtual void Render(const StrokeRenderer *iRenderer) ;
+
+ /*! accessors */
+ inline Stroke::MediumType getMediumType() const {return _strokeType;}
+ inline unsigned getTextureId() const {return _textureId;}
+ inline vector<Strip*>& getStrips() {return _strips;}
+ inline unsigned int getNumberOfStrips() const {return _strips.size();}
+ inline Stroke * getStroke() {return _stroke;}
+
+ /*! modifiers */
+ inline void setMediumType(Stroke::MediumType itype) {_strokeType=itype;}
+ inline void SetTextureId(unsigned textureId) {_textureId = textureId;}
+
+
+};
+
+#endif // STROKEREP_H
diff --git a/source/blender/freestyle/intern/stroke/StrokeShader.h b/source/blender/freestyle/intern/stroke/StrokeShader.h
new file mode 100755
index 00000000000..fa1289f6e0f
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/StrokeShader.h
@@ -0,0 +1,119 @@
+//
+// Filename : StrokeShader.h
+// Author(s) : Stephane Grabli, Emmanuel Turquin
+// Purpose : Class defining StrokeShader
+// Date of creation : 01/07/2003
+//
+///////////////////////////////////////////////////////////////////////////////
+
+
+//
+// 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef SHADERS_H
+# define SHADERS_H
+
+# include <iostream>
+# include <vector>
+
+//
+// StrokeShader base class
+//
+//////////////////////////////////////////////////////
+
+class Stroke;
+/*! Base class for Stroke Shaders.
+ * Any Stroke Shader must inherit from
+ * this class and overload the shade() method.
+ * A StrokeShader is designed to modify any
+ * Stroke's attribute such as Thickness, Color,
+ * Geometry, Texture, Blending mode...
+ * The basic way to achieve this operation consists
+ * in iterating over the StrokeVertices of the Stroke
+ * and to modify each one's StrokeAttribute.
+ * Here is a python code example of such an iteration:
+ * \code
+ * it = ioStroke.strokeVerticesBegin()
+ * while it.isEnd() == 0:
+ * att = it.getObject().attribute()
+ * ## perform here any attribute modification
+ * it.increment()
+ * \endcode
+ * Here is a C++ code example of such an iteration:
+ * \code
+ * for(StrokeInternal::StrokeVertexIterator v=ioStroke.strokeVerticesBegin(), vend=ioStroke.strokeVerticesEnd();
+ * v!=vend;
+ * ++v){
+ * StrokeAttribute& att = v->attribute();
+ * // perform any attribute modification here...
+ * }
+ * \endcode
+ */
+class LIB_STROKE_EXPORT StrokeShader
+{
+public:
+ /*! Default constructor. */
+ StrokeShader() {}
+ /*! Destructor. */
+ virtual ~StrokeShader() {}
+ /*! Returns the string corresponding to the
+ * shader's name.
+ */
+ virtual string getName() const {
+ return "StrokeShader";
+ }
+ /*! The shading method. This method must
+ * be overloaded by inherited classes.
+ * The shading method is designed to modify any
+ * Stroke's attribute such as Thickness, Color,
+ * Geometry, Texture, Blending mode...
+ * The basic way to achieve this operation consists
+ * in iterating over the StrokeVertices of the Stroke
+ * and to modify each one's StrokeAttribute.
+ * Here is a python code example of such an iteration:
+ * \code
+ * it = ioStroke.strokeVerticesBegin()
+ * while it.isEnd() == 0:
+ * att = it.getObject().attribute()
+ * ## perform here any attribute modification
+ * it.increment()
+ * \endcode
+ * Here is a C++ code example of such an iteration:
+ * \code
+ * for(StrokeInternal::StrokeVertexIterator v=ioStroke.strokeVerticesBegin(), vend=ioStroke.strokeVerticesEnd();
+ * v!=vend;
+ * ++v){
+ * StrokeAttribute& att = v->attribute();
+ * // perform any attribute modification here...
+ * }
+ * \endcode
+ * \param ioStroke
+ * The stroke we wish to shade. this Stroke
+ * is modified by the Shader (which typically
+ * modifies the Stroke's attribute's values such
+ * as Color, Thickness, Geometry...)
+ */
+ virtual void shade(Stroke& ioStroke) const {
+ cerr << "Warning: method shade() not implemented" << endl;
+ }
+
+};
+
+# endif // SHADERS_H
diff --git a/source/blender/freestyle/intern/stroke/StrokeTesselator.cpp b/source/blender/freestyle/intern/stroke/StrokeTesselator.cpp
new file mode 100755
index 00000000000..6d0f5aa847c
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/StrokeTesselator.cpp
@@ -0,0 +1,88 @@
+
+//
+// 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 "../scene_graph/OrientedLineRep.h"
+#include "../scene_graph/NodeGroup.h"
+#include "../scene_graph/NodeShape.h"
+#include "StrokeTesselator.h"
+#include "StrokeAdvancedIterators.h"
+
+LineRep* StrokeTesselator::Tesselate(Stroke *iStroke)
+{
+ if(0 == iStroke)
+ return 0;
+
+ LineRep* line;
+ line = new OrientedLineRep();
+
+ Stroke::vertex_iterator v,vend;
+ if(2 == iStroke->vertices_size())
+ {
+ line->SetStyle(LineRep::LINES);
+ v = iStroke->vertices_begin();
+ StrokeVertex *svA= (*v);
+ v++;
+ StrokeVertex *svB = (*v);
+ Vec3r A((*svA)[0], (*svA)[1], 0);
+ Vec3r B((*svB)[0], (*svB)[1], 0);
+ line->AddVertex(A);
+ line->AddVertex(B);
+ }
+ else
+ {
+ if(_overloadMaterial)
+ line->SetMaterial(_Material);
+
+ line->SetStyle(LineRep::LINE_STRIP);
+
+ for(v=iStroke->vertices_begin(), vend=iStroke->vertices_end();
+ v!=vend;
+ v++)
+ {
+ StrokeVertex *sv= (*v);
+ Vec3r V((*sv)[0], (*sv)[1], 0);
+ line->AddVertex(V);
+ }
+ }
+ line->SetId(iStroke->getId());
+ line->ComputeBBox();
+
+ return line;
+}
+
+template<class StrokeVertexIterator>
+NodeGroup* StrokeTesselator::Tesselate(StrokeVertexIterator begin, StrokeVertexIterator end)
+{
+ NodeGroup *group = new NodeGroup;
+ NodeShape *tshape = new NodeShape;
+ group->AddChild(tshape);
+ //tshape->material().SetDiffuse(0.f, 0.f, 0.f, 1.f);
+ tshape->SetMaterial(_Material);
+
+ for(StrokeVertexIterator c=begin, cend=end;
+ c!=cend;
+ c++)
+ {
+ tshape->AddRep(Tesselate((*c)));
+ }
+
+ return group;
+}
diff --git a/source/blender/freestyle/intern/stroke/StrokeTesselator.h b/source/blender/freestyle/intern/stroke/StrokeTesselator.h
new file mode 100755
index 00000000000..767d82d3d98
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/StrokeTesselator.h
@@ -0,0 +1,67 @@
+//
+// Filename : StrokeTesselator.h
+// Author(s) : Stephane Grabli
+// Purpose : Class to build a Node Tree designed to be displayed
+// from a set of strokes structure.
+// Date of creation : 26/03/2002
+//
+///////////////////////////////////////////////////////////////////////////////
+
+
+//
+// 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef STROKETESSELATOR_H
+# define STROKETESSELATOR_H
+
+# include "../scene_graph/LineRep.h"
+# include "Stroke.h"
+
+class StrokeTesselator
+{
+public:
+
+ inline StrokeTesselator() {_Material.SetDiffuse(0,0,0,1);_overloadMaterial=false;}
+ virtual ~StrokeTesselator() {}
+
+ /*! Builds a line rep contained from a Stroke
+ */
+ LineRep* Tesselate(Stroke* iStroke) ;
+
+ /*! Builds a set of lines rep contained under a
+ * a NodeShape, itself contained under a NodeGroup from a
+ * set of strokes
+ */
+ template<class StrokeIterator>
+ NodeGroup* Tesselate(StrokeIterator begin, StrokeIterator end) ;
+
+
+
+ inline void SetMaterial(const Material& iMaterial) {_Material=iMaterial;_overloadMaterial=true;}
+ inline const Material& material() const {return _Material;}
+
+private:
+
+ Material _Material;
+ bool _overloadMaterial;
+};
+
+#endif // STROKETESSELATOR_H
+
diff --git a/source/blender/freestyle/intern/stroke/StyleModule.h b/source/blender/freestyle/intern/stroke/StyleModule.h
new file mode 100755
index 00000000000..3d39e53515b
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/StyleModule.h
@@ -0,0 +1,144 @@
+//
+// Filename : StyleModule.h
+// Author(s) : Stephane Grabli, Emmanuel Turquin
+// Purpose : Class representing a style module
+// Date of creation : 01/07/2003
+//
+///////////////////////////////////////////////////////////////////////////////
+
+
+//
+// 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef STYLE_MODULE_H
+# define STYLE_MODULE_H
+
+# include <iostream>
+# include <string>
+# include "../system/StringUtils.h"
+# include "StrokeLayer.h"
+# include "../system/Interpreter.h"
+# include "Operators.h"
+# include "StrokeShader.h"
+
+using namespace std;
+
+class StyleModule
+{
+public:
+
+ StyleModule(const string& file_name,
+ Interpreter* inter) : _file_name(file_name) {
+ _always_refresh = false;
+ _causal = false;
+ _drawable = true;
+ _modified = true;
+ _displayed = true;
+ _inter = inter;
+ }
+
+ ~StyleModule() {}
+
+ StrokeLayer* execute() {
+ if (!_inter) {
+ cerr << "Error: no interpreter was found to execute the script" << endl;
+ return NULL;
+ }
+ Operators::reset();
+ if (_inter->interpretFile(_file_name))
+ return NULL;
+ Operators::StrokesContainer* strokes_set = Operators::getStrokesSet();
+ if (!_drawable || strokes_set->empty())
+ return NULL;
+ StrokeLayer* sl = new StrokeLayer;
+ for (Operators::StrokesContainer::iterator it = strokes_set->begin();
+ it != strokes_set->end();
+ ++it)
+ sl->AddStroke(*it);
+
+ return sl;
+ }
+
+ // accessors
+
+ const string getFileName() const {
+ return _file_name;
+ }
+
+ bool getAlwaysRefresh() const {
+ return _always_refresh;
+ }
+
+ bool getCausal() const {
+ return _causal;
+ }
+
+ bool getDrawable() const {
+ return _drawable;
+ }
+
+ bool getModified() const {
+ return _modified;
+ }
+
+ bool getDisplayed() const {
+ return _displayed;
+ }
+
+ // modifiers
+
+ void setFileName(const string& file_name) {
+ _file_name = file_name;
+ }
+
+ void setAlwaysRefresh(bool b = true) {
+ _always_refresh = b;
+ }
+
+ void setCausal(bool b = true) {
+ _causal = b;
+ }
+
+ void setDrawable(bool b = true) {
+ _drawable = b;
+ }
+
+ void setModified(bool b = true) {
+ if (_always_refresh)
+ return;
+ _modified = b;
+ }
+
+ void setDisplayed(bool b = true) {
+ _displayed = b;
+ }
+
+private:
+
+ string _file_name;
+ bool _always_refresh;
+ bool _causal;
+ bool _drawable;
+ bool _modified;
+ bool _displayed;
+ Interpreter* _inter;
+};
+
+#endif // STYLE_MODULE_H
diff --git a/source/blender/freestyle/intern/stroke/TextStrokeRenderer.cpp b/source/blender/freestyle/intern/stroke/TextStrokeRenderer.cpp
new file mode 100755
index 00000000000..ea5af287bbe
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/TextStrokeRenderer.cpp
@@ -0,0 +1,73 @@
+
+//
+// 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 "TextStrokeRenderer.h"
+# include "Canvas.h"
+# include "StrokeIterators.h"
+
+TextStrokeRenderer::TextStrokeRenderer(const char* iFileName)
+:StrokeRenderer(){
+ if(!iFileName)
+ iFileName = "freestyle.txt";
+ // open the stream:
+ _ofstream.open(iFileName, ios::out);
+ if(!_ofstream.is_open()){
+ cerr << "couldn't open the output file " << iFileName << endl;
+ }
+ _ofstream << "%!FREESTYLE" << endl;
+ _ofstream << "%Creator: Freestyle (http://artis.imag.fr/Software/Freestyle)" << endl;
+ // Bounding box
+ _ofstream << 0 << " "<< 0 << " " << Canvas::getInstance()->width() << " " << Canvas::getInstance()->height() << endl;
+ _ofstream << "%u x y z tleft tright r g b ..." << endl;
+}
+
+TextStrokeRenderer::~TextStrokeRenderer(){
+ Close();
+}
+
+void TextStrokeRenderer::RenderStrokeRep(StrokeRep *iStrokeRep) const{
+ RenderStrokeRepBasic(iStrokeRep);
+}
+
+void TextStrokeRenderer::RenderStrokeRepBasic(StrokeRep *iStrokeRep) const{
+ Stroke *stroke = iStrokeRep->getStroke();
+ if(!stroke){
+ cerr << "no stroke associated with Rep" << endl;
+ return;
+ }
+
+ StrokeInternal::StrokeVertexIterator v = stroke->strokeVerticesBegin();
+ StrokeAttribute att;
+ while(!v.isEnd()){
+ att = v->attribute();
+ _ofstream << v->u() << " " << v->getProjectedX() << " " << v->getProjectedY() << " " << v->getProjectedZ() << " " \
+ << att.getThicknessL() << " " << att.getThicknessR() << " " \
+ << att.getColorR() << " " << att.getColorG() << " " << att.getColorB() << " ";
+ ++v;
+ }
+ _ofstream << endl;
+}
+
+void TextStrokeRenderer::Close(){
+ if(_ofstream.is_open())
+ _ofstream.close();
+}
+
diff --git a/source/blender/freestyle/intern/stroke/TextStrokeRenderer.h b/source/blender/freestyle/intern/stroke/TextStrokeRenderer.h
new file mode 100755
index 00000000000..ef610d63bdd
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/TextStrokeRenderer.h
@@ -0,0 +1,68 @@
+//
+// Filename : TextStrokeRenderer.h
+// Author(s) : Stephane Grabli
+// Purpose : Class to define the text rendering of a stroke
+// Format:
+// x y width height // bbox
+// //list of vertices :
+// t x y z t1 t2 r g b alpha ...
+// ...
+// Date of creation : 01/14/2005
+//
+///////////////////////////////////////////////////////////////////////////////
+
+
+//
+// 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef TEXTSTROKERENDERER_H
+# define TEXTSTROKERENDERER_H
+
+# include "../system/FreestyleConfig.h"
+# include "StrokeRenderer.h"
+# include <fstream>
+
+/**********************************/
+/* */
+/* */
+/* TextStrokeRenderer */
+/* */
+/* */
+/**********************************/
+
+class LIB_STROKE_EXPORT TextStrokeRenderer : public StrokeRenderer
+{
+public:
+ TextStrokeRenderer(const char * iFileName = 0);
+ virtual ~TextStrokeRenderer();
+
+ /*! Renders a stroke rep */
+ virtual void RenderStrokeRep(StrokeRep *iStrokeRep) const;
+ virtual void RenderStrokeRepBasic(StrokeRep *iStrokeRep) const;
+
+ /*! Closes the output file */
+ void Close();
+
+protected:
+ mutable ofstream _ofstream;
+};
+
+#endif // TEXTSTROKERENDERER_H
+
diff --git a/source/blender/freestyle/intern/stroke/src.pri b/source/blender/freestyle/intern/stroke/src.pri
new file mode 100755
index 00000000000..09707f86dbc
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/src.pri
@@ -0,0 +1,54 @@
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# W A R N I N G ! ! ! #
+# a u t h o r i z e d p e r s o n a l o n l y #
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+STROKE_DIR = ../stroke
+
+SOURCES *= $${STROKE_DIR}/AdvancedFunctions0D.cpp \
+ $${STROKE_DIR}/AdvancedFunctions1D.cpp \
+ $${STROKE_DIR}/AdvancedStrokeShaders.cpp \
+ $${STROKE_DIR}/BasicStrokeShaders.cpp \
+ $${STROKE_DIR}/Canvas.cpp \
+ $${STROKE_DIR}/Chain.cpp \
+ $${STROKE_DIR}/ChainingIterators.cpp \
+ $${STROKE_DIR}/ContextFunctions.cpp \
+ $${STROKE_DIR}/Operators.cpp \
+ $${STROKE_DIR}/PSStrokeRenderer.cpp \
+ $${STROKE_DIR}/Stroke.cpp \
+ $${STROKE_DIR}/StrokeIO.cpp \
+ $${STROKE_DIR}/StrokeLayer.cpp \
+ $${STROKE_DIR}/StrokeRenderer.cpp \
+ $${STROKE_DIR}/StrokeRep.cpp \
+ $${STROKE_DIR}/StrokeTesselator.cpp \
+ $${STROKE_DIR}/TextStrokeRenderer.cpp \
+ $${STROKE_DIR}/Curve.cpp
+
+HEADERS *= $${STROKE_DIR}/AdvancedFunctions0D.h \
+ $${STROKE_DIR}/AdvancedFunctions1D.h \
+ $${STROKE_DIR}/AdvancedPredicates1D.h \
+ $${STROKE_DIR}/AdvancedStrokeShaders.h \
+ $${STROKE_DIR}/BasicStrokeShaders.h \
+ $${STROKE_DIR}/Canvas.h \
+ $${STROKE_DIR}/Chain.h \
+ $${STROKE_DIR}/ChainingIterators.h \
+ $${STROKE_DIR}/ContextFunctions.h \
+ $${STROKE_DIR}/Curve.h \
+ $${STROKE_DIR}/CurveIterators.h \
+ $${STROKE_DIR}/CurveAdvancedIterators.h \
+ $${STROKE_DIR}/Module.h \
+ $${STROKE_DIR}/Operators.h \
+ $${STROKE_DIR}/Predicates1D.h \
+ $${STROKE_DIR}/Predicates0D.h \
+ $${STROKE_DIR}/PSStrokeRenderer.h \
+ $${STROKE_DIR}/Stroke.h \
+ $${STROKE_DIR}/StrokeIO.h \
+ $${STROKE_DIR}/StrokeIterators.h \
+ $${STROKE_DIR}/StrokeAdvancedIterators.h \
+ $${STROKE_DIR}/StrokeShader.h \
+ $${STROKE_DIR}/StrokeLayer.h \
+ $${STROKE_DIR}/StrokeRenderer.h \
+ $${STROKE_DIR}/StrokeRep.h \
+ $${STROKE_DIR}/StrokeTesselator.h \
+ $${STROKE_DIR}/StyleModule.h \
+ $${STROKE_DIR}/TextStrokeRenderer.h
diff --git a/source/blender/freestyle/intern/stroke/stroke.pro b/source/blender/freestyle/intern/stroke/stroke.pro
new file mode 100755
index 00000000000..90c0cc96592
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/stroke.pro
@@ -0,0 +1,89 @@
+# This file should be viewed as a -*- mode: Makefile -*-
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# W A R N I N G ! ! ! #
+# a u t h o r i z e d p e r s o n a l o n l y #
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+include(../Config.pri)
+
+TEMPLATE = lib
+
+TARGET = $${LIB_STROKE}
+VERSION = $${APPVERSION}
+TARGET_VERSION_EXT = $${APPVERSION_MAJ}.$${APPVERSION_MID}
+
+#
+# CONFIG
+#
+#######################################
+
+CONFIG *= dll
+
+#
+# DEFINES
+#
+#######################################
+
+win32:DEFINES *= MAKE_LIB_STROKE_DLL
+
+#
+# INCLUDE PATH
+#
+#######################################
+
+#INCLUDEPATH *= ../geometry ../image ../system ../view_map \
+# ../winged_edge ../scene_graph
+
+#
+# BUILD DIRECTORIES
+#
+#######################################
+
+BUILD_DIR = ../../build
+
+OBJECTS_DIR = $${BUILD_DIR}/$${REL_OBJECTS_DIR}
+!win32:DESTDIR = $${BUILD_DIR}/$${REL_DESTDIR}/lib
+win32:DESTDIR = $${BUILD_DIR}/$${REL_DESTDIR}
+
+#
+# LIBS
+#
+#######################################
+
+win32:LIBS *= $${DESTDIR}/$${LIB_GEOMETRY}$${LIBVERSION}.lib \
+ $${DESTDIR}/$${LIB_IMAGE}$${LIBVERSION}.lib \
+ $${DESTDIR}/$${LIB_SCENE_GRAPH}$${LIBVERSION}.lib \
+ $${DESTDIR}/$${LIB_SYSTEM}$${LIBVERSION}.lib \
+ $${DESTDIR}/$${LIB_WINGED_EDGE}$${LIBVERSION}.lib \
+ $${DESTDIR}/$${LIB_VIEW_MAP}$${LIBVERSION}.lib
+
+!win32 {
+ lib_bundle {
+ LIBS += -F$${DESTDIR} -framework $${LIB_GEOMETRY} -framework $${LIB_IMAGE} -framework $${LIB_SCENE_GRAPH} -framework $${LIB_SYSTEM} -framework $${LIB_WINGED_EDGE} -framework $${LIB_VIEW_MAP}
+ } else {
+ LIBS *= -L$${DESTDIR} -l$${LIB_GEOMETRY} -l$${LIB_IMAGE} -l$${LIB_SCENE_GRAPH} \
+ -l$${LIB_SYSTEM} -l$${LIB_WINGED_EDGE} -l$${LIB_VIEW_MAP}
+ }
+}
+
+#
+# INSTALL
+#
+#######################################
+
+LIB_DIR = ../../lib
+# install library
+target.path = $$LIB_DIR
+# "make install" configuration options
+INSTALLS += target
+
+#
+# SOURCES & HEADERS
+#
+#######################################
+
+
+!static {
+ include(src.pri)
+}