diff options
Diffstat (limited to 'source/blender/freestyle/intern/stroke/BasicStrokeShaders.cpp')
-rw-r--r-- | source/blender/freestyle/intern/stroke/BasicStrokeShaders.cpp | 2128 |
1 files changed, 1033 insertions, 1095 deletions
diff --git a/source/blender/freestyle/intern/stroke/BasicStrokeShaders.cpp b/source/blender/freestyle/intern/stroke/BasicStrokeShaders.cpp index eea6da40c9f..852a36571d4 100644 --- a/source/blender/freestyle/intern/stroke/BasicStrokeShaders.cpp +++ b/source/blender/freestyle/intern/stroke/BasicStrokeShaders.cpp @@ -1,1170 +1,1108 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/freestyle/intern/stroke/BasicStrokeShaders.cpp + * \ingroup freestyle + * \brief Class gathering basic stroke shaders + * \author Stephane Grabli + * \date 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. -// -/////////////////////////////////////////////////////////////////////////////// - -#include "StrokeRenderer.h" #include <fstream> + +#include "AdvancedFunctions0D.h" +#include "AdvancedFunctions1D.h" #include "BasicStrokeShaders.h" +#include "StrokeIO.h" +#include "StrokeIterators.h" +#include "StrokeRenderer.h" + #include "../system/PseudoNoise.h" #include "../system/RandGen.h" +#include "../system/StringUtils.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 "StrokeIO.h" //soc #include <qimage.h> //soc #include <QString> + extern "C" { -#include "IMB_imbuf.h" -#include "IMB_imbuf_types.h" +# include "IMB_imbuf.h" +# include "IMB_imbuf_types.h" } // Internal function -// soc -// 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; -// } -// } -static void convert(ImBuf *imBuf, float **oArray, unsigned &oSize) { +#if 0 // soc +void convert(const QImage& iImage, float **oArray, unsigned &oSize) +{ + oSize = iImage.width(); + *oArray = new float[oSize]; + for (unsigned int i = 0; i < oSize; ++i) { + QRgb rgb = iImage.pixel(i,0); + (*oArray)[i] = ((float)qBlue(rgb)) / 255.0f; + } +} +#endif + +static void convert(ImBuf *imBuf, float **oArray, unsigned &oSize) +{ oSize = imBuf->x; - *oArray = new float[oSize]; + *oArray = new float[oSize]; char *pix; - for(unsigned i=0; i < oSize; ++i) { - pix = (char*) imBuf->rect + i*4; - (*oArray)[i] = ((float) pix[2] )/255.f; - } + for (unsigned int i = 0; i < oSize; ++i) { + pix = (char*) imBuf->rect + i * 4; + (*oArray)[i] = ((float) pix[2]) / 255.0f; + } } namespace StrokeShaders { - // - // Thickness modifiers - // - ////////////////////////////////////////////////////////// - - int 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); - } +// +// Thickness modifiers +// +////////////////////////////////////////////////////////// + +int 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) { + // XXX What's the use of i here? And is not the thickness always overriden by the last line of the loop? + 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); + } return 0; - } - - int 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); - } +} + +int 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) { + // XXX What's the use of i here? And is not the thickness always overriden by the last line of the loop? + 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); + } return 0; - } - - int 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; - } +} + +int IncreasingThicknessShader::shade(Stroke& stroke) const +{ + int n = stroke.strokeVerticesSize() - 1, i; + StrokeInternal::StrokeVertexIterator v, vend; + for (i = 0, v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd(); + v != vend; + ++v, ++i) + { + float t; + if (i < (float)n / 2.0f) + 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); + } return 0; - } - - int 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; - } +} + +int ConstrainedIncreasingThicknessShader::shade(Stroke& stroke) const +{ + float slength = stroke.getLength2D(); + float maxT = min(_ratio*slength,_ThicknessMax); + int n = stroke.strokeVerticesSize() - 1, i; + StrokeInternal::StrokeVertexIterator v, vend; + for (i = 0, v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd(); + v != vend; + ++v, ++i) + { + // XXX Why not using an if/else here? Else, if last condition is true, everything else is computed for nothing! + float t; + if (i < (float)n / 2.0f) + 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); + } return 0; - } - - - int LengthDependingThicknessShader::shade(Stroke& stroke) const - { - float step = (_maxThickness-_minThickness)/3.f; - float l = stroke.getLength2D(); - float thickness = 0.0; - 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); - } +} + + +int LengthDependingThicknessShader::shade(Stroke& stroke) const +{ + float step = (_maxThickness - _minThickness) / 3.0f; + float l = stroke.getLength2D(); + float thickness = 0.0f; + if (l > 300.0f) + thickness = _minThickness + 3.0f * step; + else if ((l < 300.0f) && (l > 100.0f)) + thickness = _minThickness + 2.0f * step; + else if ((l < 100.0f) && (l > 50.0f)) + thickness = _minThickness + 1.0f * step; + else // else if (l < 50.0f), tsst... + thickness = _minThickness; + + StrokeInternal::StrokeVertexIterator v, vend; + int i = 0; + int size = stroke.strokeVerticesSize(); + for (v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd(); v != vend; ++v) { + // XXX What's the use of i here? And is not the thickness always overriden by the last line of the loop? + 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); + } return 0; - } - - - ThicknessVariationPatternShader::ThicknessVariationPatternShader(const string pattern_name, - float iMinThickness, - float iMaxThickness, - bool stretch) - : StrokeShader() { - _stretch = stretch; - _minThickness = iMinThickness; - _maxThickness = iMaxThickness; - ImBuf *image = 0; //soc - 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()) { - //soc image.load(j->c_str()); - /* OCIO_TODO: support different input color space */ - image = IMB_loadiffname(j->c_str(), 0, NULL); - break; - } - } - if (image == 0) //soc - cerr << "Error: cannot find pattern \"" << pattern_name - << "\" - check the path in the Options" << endl; - else - convert(image, &_aThickness, _size); - } - - int 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; +} + + +ThicknessVariationPatternShader::ThicknessVariationPatternShader(const string pattern_name, float iMinThickness, + float iMaxThickness, bool stretch) +: StrokeShader() +{ + _stretch = stretch; + _minThickness = iMinThickness; + _maxThickness = iMaxThickness; + ImBuf *image = NULL; //soc + 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()) { + //soc image.load(j->c_str()); + /* OCIO_TODO: support different input color space */ + image = IMB_loadiffname(j->c_str(), 0, NULL); + break; + } } + if (image == NULL) //soc + cerr << "Error: cannot find pattern \"" << pattern_name << "\" - check the path in the Options" << endl; 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; - } + convert(image, &_aThickness, _size); +} + + +int 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.0f; + thicknessR = _minThickness/2.0f; + } + if (thicknessR+thicknessL > _maxThickness) { + thicknessL = _maxThickness/2.0f; + thicknessR = _maxThickness/2.0f; + } + if ((sig == 0) || (sig == vert_size - 1)) + v->attribute().setThickness(1, 1); + else + v->attribute().setThickness(thicknessR, thicknessL); + ++sig; + } return 0; - } - - - 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;} - - - int 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); - } - +} + + +static const unsigned NB_VALUE_NOISE = 512; + +ThicknessNoiseShader::ThicknessNoiseShader() : StrokeShader() +{ + _amplitude = 1.0f; + _scale = 1.0f / 2.0f / (float)NB_VALUE_NOISE; +} + +ThicknessNoiseShader::ThicknessNoiseShader(float iAmplitude, float iPeriod) : StrokeShader() +{ + _amplitude = iAmplitude; + _scale = 1.0f / iPeriod / (float)NB_VALUE_NOISE; +} + +int ThicknessNoiseShader::shade(Stroke& stroke) const +{ + StrokeInternal::StrokeVertexIterator v = stroke.strokeVerticesBegin(), vend; + 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 (vend = stroke.strokeVerticesEnd(); 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); + } + return 0; - } - - // - // Color shaders - // - /////////////////////////////////////////////////////////////////////////////// - - int 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]); - } +} + +// +// Color shaders +// +/////////////////////////////////////////////////////////////////////////////// + +int 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]); + } return 0; - } - - int 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; - } +} + +int IncreasingColorShader::shade(Stroke& stroke) const +{ + StrokeInternal::StrokeVertexIterator v, vend; + int n = stroke.strokeVerticesSize() - 1, yo; + float newcolor[4]; + for (yo = 0, v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd(); + v != vend; + ++v, ++yo) + { + 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]); + } return 0; - } - - ColorVariationPatternShader::ColorVariationPatternShader(const string pattern_name, - bool stretch) - : StrokeShader() { - _stretch = stretch; - ImBuf *image = 0; //soc - 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()) { - /* OCIO_TODO: support different input color space */ - image = IMB_loadiffname(j->c_str(), 0, NULL); //soc - break; - } - } - if (image == 0) //soc - cerr << "Error: cannot find pattern \"" << pattern_name - << "\" - check the path in the Options" << endl; - else - convert(image, &_aVariation, _size); - } - - int 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; +} + +ColorVariationPatternShader::ColorVariationPatternShader(const string pattern_name, bool stretch) : StrokeShader() +{ + _stretch = stretch; + ImBuf *image = NULL; //soc + 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()) { + /* OCIO_TODO: support different input color space */ + image = IMB_loadiffname(j->c_str(), 0, NULL); //soc + break; + } } + if (image == NULL) //soc + cerr << "Error: cannot find pattern \"" << pattern_name << "\" - check the path in the Options" << endl; 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); - } + convert(image, &_aVariation, _size); +} + +int 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); + } return 0; - } - - int MaterialColorShader::shade(Stroke& stroke) const - { - Interface0DIterator v, vend; - Functions0D::MaterialF0D fun; - StrokeVertex *sv; - for(v=stroke.verticesBegin(), vend=stroke.verticesEnd(); - v!=vend; - ++v) - { - if (fun(v) < 0) - return -1; - const float *diffuse = fun.result.diffuse(); - sv = dynamic_cast<StrokeVertex*>(&(*v)); - sv->attribute().setColor(diffuse[0]*_coefficient, diffuse[1]*_coefficient, diffuse[2]*_coefficient); - sv->attribute().setAlpha(diffuse[3]); - } +} + +int MaterialColorShader::shade(Stroke& stroke) const +{ + Interface0DIterator v, vend; + Functions0D::MaterialF0D fun; + StrokeVertex *sv; + for (v = stroke.verticesBegin(), vend = stroke.verticesEnd(); v != vend; ++v) { + if (fun(v) < 0) + return -1; + const float *diffuse = fun.result.diffuse(); + sv = dynamic_cast<StrokeVertex*>(&(*v)); + sv->attribute().setColor(diffuse[0] * _coefficient, diffuse[1] * _coefficient, diffuse[2] * _coefficient); + sv->attribute().setAlpha(diffuse[3]); + } return 0; - } - - - int CalligraphicColorShader::shade(Stroke& stroke) const - { - Interface0DIterator v; - Functions0D::VertexOrientation2DF0D fun; - StrokeVertex* sv; - for(v=stroke.verticesBegin(); - !v.isEnd(); - ++v) - { - if (fun(v) < 0) - return -1; - Vec2f vertexOri(fun.result); - 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); - } +} + + +int CalligraphicColorShader::shade(Stroke& stroke) const +{ + Interface0DIterator v; + Functions0D::VertexOrientation2DF0D fun; + StrokeVertex *sv; + for (v = stroke.verticesBegin(); !v.isEnd(); ++v) { + if (fun(v) < 0) + return -1; + Vec2f vertexOri(fun.result); + 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); + } return 0; - } - - - 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;} - - - int 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); - } - +} + + +ColorNoiseShader::ColorNoiseShader() : StrokeShader() +{ + _amplitude = 1.0f; + _scale = 1.0f / 2.0f / (float)NB_VALUE_NOISE; +} + +ColorNoiseShader::ColorNoiseShader(float iAmplitude, float iPeriod) : StrokeShader() +{ + _amplitude = iAmplitude; + _scale = 1.0f / iPeriod / (float)NB_VALUE_NOISE; +} + +int ColorNoiseShader::shade(Stroke& stroke) const +{ + StrokeInternal::StrokeVertexIterator v = stroke.strokeVerticesBegin(), vend; + real initU = v->strokeLength() * real(NB_VALUE_NOISE) + RandGen::drand48() * real(NB_VALUE_NOISE); + + real bruit; + PseudoNoise mynoise; + for (vend = stroke.strokeVerticesEnd(); 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); + } + return 0; - } - - - // - // Texture Shaders - // - /////////////////////////////////////////////////////////////////////////////// - - int 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 0; - string pathname; - Stroke::MediumType mediumType; - bool hasTips = false; - switch(_textureId) - { - case 0: - //pathname = TextureManager::Options::getBrushesPath() + "/charcoalAlpha.bmp"; +} + + +// +// Texture Shaders +// +/////////////////////////////////////////////////////////////////////////////// + +int TextureAssignerShader::shade(Stroke& stroke) const +{ +#if 0 + 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); +#endif + + TextureManager *instance = TextureManager::getInstance(); + if (!instance) + return 0; + 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); + 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); return 0; - } - - // FIXME - int StrokeTextureShader::shade(Stroke& stroke) const - { - TextureManager * instance = TextureManager::getInstance(); - if(!instance) - return 0; - string pathname = TextureManager::Options::getBrushesPath() + "/" + _texturePath; - unsigned int texId = instance->getBrushTextureIndex(pathname, _mediumType); - stroke.setMediumType(_mediumType); - stroke.setTips(_tips); - stroke.setTextureId(texId); +} + +// FIXME +int StrokeTextureShader::shade(Stroke& stroke) const +{ + TextureManager *instance = TextureManager::getInstance(); + if (!instance) + return 0; + string pathname = TextureManager::Options::getBrushesPath() + "/" + _texturePath; + unsigned int texId = instance->getBrushTextureIndex(pathname, _mediumType); + stroke.setMediumType(_mediumType); + stroke.setTips(_tips); + stroke.setTextureId(texId); return 0; - } - - // - // Geometry Shaders - // - /////////////////////////////////////////////////////////////////////////////// - - int BackboneStretcherShader::shade(Stroke& stroke) const - { - float l=stroke.getLength2D(); - if(l <= 1e-6) - return 0; - - 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]); +} + +// +// Geometry Shaders +// +/////////////////////////////////////////////////////////////////////////////// + +int BackboneStretcherShader::shade(Stroke& stroke) const +{ + float l = stroke.getLength2D(); + if (l <= 1.0e-6) + return 0; + + 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]); stroke.UpdateLength(); return 0; - } +} - int SamplingShader::shade(Stroke& stroke) const - { - stroke.Resample(_sampling); +int SamplingShader::shade(Stroke& stroke) const +{ + stroke.Resample(_sampling); return 0; - } - - int ExternalContourStretcherShader::shade(Stroke& stroke) const - { - //float l=stroke.getLength2D(); - Interface0DIterator it=stroke.verticesBegin(); - Functions0D::Normal2DF0D fun; - StrokeVertex* sv; - while (!it.isEnd()) - { - if (fun(it) < 0) - return -1; - Vec2f n(fun.result); - sv = dynamic_cast<StrokeVertex*>(&(*it)); - Vec2d newPoint(sv->x()+_amount*n.x(), sv->y()+_amount*n.y()); - sv->setPoint(newPoint[0], newPoint[1]); - ++it; - } +} + +int ExternalContourStretcherShader::shade(Stroke& stroke) const +{ + //float l = stroke.getLength2D(); + Interface0DIterator it; + Functions0D::Normal2DF0D fun; + StrokeVertex* sv; + for (it = stroke.verticesBegin(); !it.isEnd(); ++it) { + if (fun(it) < 0) + return -1; + Vec2f n(fun.result); + sv = dynamic_cast<StrokeVertex*>(&(*it)); + Vec2d newPoint(sv->x() + _amount * n.x(), sv->y() + _amount * n.y()); + sv->setPoint(newPoint[0], newPoint[1]); + } stroke.UpdateLength(); return 0; - } - - int BSplineShader::shade(Stroke& stroke) const - { - if(stroke.strokeVerticesSize() < 4) - return 0; - - // 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; - } +} + +int BSplineShader::shade(Stroke& stroke) const +{ + if (stroke.strokeVerticesSize() < 4) + return 0; + + // Find the new vertices + vector<Vec2d> newVertices; + double t = 0.0; + float _sampling = 5.0f; + + 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 0 + if (p1 == end) + p1 = p0; +#endif + 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 = newVertices.begin(), pend = newVertices.end(); + vector<Vec2d>::iterator last = p; + n = 0; + StrokeInternal::StrokeVertexIterator it, itend; + for (it = stroke.strokeVerticesBegin(), itend = stroke.strokeVerticesEnd(); + (it != itend) && (p != pend); + ++it, ++p, ++n) + { + it->setX(p->x()); + it->setY(p->y()); + last = p; + } + + // nExtraVertex should stay unassigned + for (int i = 0; i < nExtraVertex; ++i, ++it, ++n) { + it->setX(last->x()); + it->setY(last->y()); + if (it.isEnd()) { + // XXX Shouldn't we break in this case??? + cerr << "Warning: Problem encountered while creating B-spline" << endl; + } + } stroke.UpdateLength(); return 0; - } - - //!! Bezier curve stroke shader - int BezierCurveShader::shade(Stroke& stroke) const - { - if(stroke.strokeVerticesSize() < 4) - return 0; - - // 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; - } +} + +//!! Bezier curve stroke shader +int BezierCurveShader::shade(Stroke& stroke) const +{ + if (stroke.strokeVerticesSize() < 4) + return 0; + + // Build the Bezier curve from this set of data points: + vector<Vec2d> data; + StrokeInternal::StrokeVertexIterator v = stroke.strokeVerticesBegin(), vend; + data.push_back(Vec2d(v->x(), v->y())); //first one + StrokeInternal::StrokeVertexIterator previous = v; + ++v; + for (vend = stroke.strokeVerticesEnd(); 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; + } + +#if 0 + Vec2d tmp; + bool equal = false; + if (data.front() == data.back()) { + tmp = data.back(); + data.pop_back(); + equal = true; + } +#endif + // 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; + vector<Vec2d>& segmentsVertices = (*s)->vertices(); + vector<Vec2d>::iterator p, pend; + // first point + CurveVertices.push_back(segmentsVertices[0]); + for (send = bsegments.end(); s != send; ++s) { + segmentsVertices = (*s)->vertices(); + p = segmentsVertices.begin(); + ++p; + for (pend = segmentsVertices.end(); p != pend; ++p) { + CurveVertices.push_back((*p)); + } + } + +#if 0 + if (equal) { + if (data.back() == data.front()) { + vector<Vec2d>::iterator d = data.begin(), dend; + cout << "ending point = starting point" << endl; + cout << "---------------DATA----------" << endl; + for (dend = data.end(); d != dend; ++d) { + cout << d->x() << "-" << d->y() << endl; + } + cout << "--------------BEZIER RESULT----------" << endl; + for (d = CurveVertices.begin(), dend = CurveVertices.end(); d != dend; ++d) { + cout << d->x() << "-" << d->y() << endl; + } + } + } +#endif + + // Resample the Stroke depending on the number of vertices of the bezier curve: + int originalSize = CurveVertices.size(); +#if 0 + float sampling = stroke.ComputeSampling(originalSize); + stroke.Resample(sampling); +#endif + 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(); + vector<Vec2d>::iterator last = p; + int n; + StrokeInternal::StrokeVertexIterator it, itend; +#if 0 + for (; p != pend; ++n, ++p); +#endif + for (n = 0, it = stroke.strokeVerticesBegin(), itend = stroke.strokeVerticesEnd(), pend = CurveVertices.end(); + (it != itend) && (p != pend); + ++it, ++p, ++n) + { + it->setX(p->x()); + it->setY(p->y()); +#if 0 + double x = p->x(); + double y = p->y(); + cout << "x = " << x << "-" << "y = " << y << endl; +#endif + last = p; + } stroke.UpdateLength(); - // Deal with extra vertices: - if(nExtraVertex == 0) - return 0; - - // 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; - } + // Deal with extra vertices: + if (nExtraVertex == 0) + return 0; + + // nExtraVertex should stay unassigned + vector<StrokeAttribute> attributes; + vector<StrokeVertex*> verticesToRemove; + for (int i = 0; i < nExtraVertex; ++i, ++it, ++n) { + verticesToRemove.push_back(&(*it)); + if (it.isEnd()) { + // XXX Shocking! :P Shouldn't we break in this case??? + cout << "fucked up" << endl; + } + } + for (it = stroke.strokeVerticesBegin(); it != itend; ++it) { + attributes.push_back(it->attribute()); + } + + for (vector<StrokeVertex*>::iterator vr = verticesToRemove.begin(), vrend = verticesToRemove.end(); + vr != vrend; + ++vr) + { + stroke.RemoveVertex(*vr); + } + + 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 = stroke.strokeVerticesBegin(), itend = stroke.strokeVerticesEnd(); + (it != itend) && (a != aend); + ++it) + { + (it)->setAttribute(*a); + if ((index <= index1) || (index > index2)) + ++a; + ++index; + } return 0; - } +} - int 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; +int 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) < 0) - return -1; + return -1; if (fun.result > _curvatureThreshold) - return 0; - - Functions0D::VertexOrientation2DF0D ori_fun; - Functions0D::Curvature2DAngleF0D curv_fun; - Functions1D::Normal2DF1D norm_fun; - Interface0DIterator it=stroke.verticesBegin(); - StrokeVertex* sv; - while (!it.isEnd()) - { - if (ori_fun(it) < 0) - return -1; - Vec2f ntmp(ori_fun.result); - Vec2f n(ntmp.y(), -ntmp.x()); - if (norm_fun(stroke) < 0) - return -1; - Vec2f strokeN(norm_fun.result); - 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)); - if (curv_fun(it) < 0) - return -1; - float curvature_coeff = (M_PI-curv_fun.result)/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; - } + return 0; + + Functions0D::VertexOrientation2DF0D ori_fun; + Functions0D::Curvature2DAngleF0D curv_fun; + Functions1D::Normal2DF1D norm_fun; + Interface0DIterator it; + StrokeVertex *sv; + for (it = stroke.verticesBegin(); !it.isEnd(); ++it) { + if (ori_fun(it) < 0) + return -1; + Vec2f ntmp(ori_fun.result); + Vec2f n(ntmp.y(), -ntmp.x()); + if (norm_fun(stroke) < 0) + return -1; + Vec2f strokeN(norm_fun.result); + if (n*strokeN < 0) { + n[0] = -n[0]; + n[1] = -n[1]; + } + sv = dynamic_cast<StrokeVertex*>(&(*it)); + float u = sv->u(); + float t = 4.0f * (0.25f - (u - 0.5) * (u - 0.5)); + if (curv_fun(it) < 0) + return -1; + float curvature_coeff = (M_PI - curv_fun.result) / 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]); + } stroke.UpdateLength(); return 0; - } - - 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) +} + +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) { - Vec2d P(it->x(), it->y()); - float d = GeomUtils::distPointSegment(P,A,B); - if(d > maxE) - maxE = d; + _begin = b; + _last = l; + A = Vec2d((_begin)->x(), (_begin)->y()); + B = Vec2d((_last)->x(), (_last)->y()); + size = iSize; } - _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) + + float error() { - ++it; - ++actualSize; + float maxE = 0.0f; + 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 = (size > 1) ? size / 2 : 1; + for (int i = 0; i <= actualSize; ++it, ++i); + + CurvePiece *second = new CurvePiece(it, _last, size - actualSize + 1); + size = actualSize; + _last = it; + B = Vec2d((_last)->x(), (_last)->y()); + return second; + } +}; + +int 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; + 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); + } +#if 0 + u.normalize(); + (*a)->setPoint((*a)->x() - u.x() * 10, (*a)->y() - u.y() * 10); +#endif } - CurvePiece * second = new CurvePiece(it, _last, size-actualSize+1); - size = actualSize; - _last = it; - B = Vec2d((_last)->x(), (_last)->y()); - return second; - } - }; - - int 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); - } stroke.UpdateLength(); - // delete stuff - for(cp=_results.begin(), cpend=_results.end(); - cp!=cpend; - ++cp) - { - delete (*cp); - } - _results.clear(); + // delete stuff + for (cp = _results.begin(), cpend = _results.end(); cp != cpend; ++cp) { + delete (*cp); + } + _results.clear(); return 0; - } - - int 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(); +} + +int 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(); if (norm_fun(stroke) < 0) - return -1; - Vec2f strokeN(norm_fun.result); - 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); - } + return -1; + Vec2f strokeN(norm_fun.result); + if (n * strokeN < 0) { + n[0] = -n[0]; + n[1] = -n[1]; + } + float offset = (piece.error()) / 2.0f * _offset; + StrokeInternal::StrokeVertexIterator v, vend; + for (v = a, vend = stroke.strokeVerticesEnd(); 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); + } stroke.UpdateLength(); return 0; - } - - ///////////////////////////////////////// - // - // Tip Remover - // - ///////////////////////////////////////// - - - TipRemoverShader::TipRemoverShader(real tipLength) - : StrokeShader() - { - _tipLength = tipLength; - } - - int - TipRemoverShader::shade(Stroke& stroke) const - { - int originalSize = stroke.strokeVerticesSize(); - - if(originalSize<4) - return 0; - - 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 0; - - 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((int)stroke.strokeVerticesSize() != originalSize) //soc - 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! +} + +///////////////////////////////////////// +// +// Tip Remover +// +///////////////////////////////////////// + + +TipRemoverShader::TipRemoverShader(real tipLength) : StrokeShader() +{ + _tipLength = tipLength; +} + +int TipRemoverShader::shade(Stroke& stroke) const +{ + int originalSize = stroke.strokeVerticesSize(); + + if (originalSize < 4) + return 0; + + StrokeInternal::StrokeVertexIterator v, vend; + vector<StrokeVertex*> verticesToRemove; + vector<StrokeAttribute> oldAttributes; + for (v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd(); 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 0; + + vector<StrokeVertex*>::iterator sv, svend; + for (sv = verticesToRemove.begin(), svend = verticesToRemove.end(); sv != svend; ++sv) { + stroke.RemoveVertex((*sv)); + } + + // Resample so that our new stroke have the same number of vertices than before + stroke.Resample(originalSize); + + if ((int)stroke.strokeVerticesSize() != originalSize) //soc + cerr << "Warning: resampling problem" << endl; + + // assign old attributes to new stroke vertices: + vector<StrokeAttribute>::iterator a = oldAttributes.begin(), aend = oldAttributes.end(); + //cout << "-----------------------------------------------" << endl; + for (v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd(); + (v != vend) && (a != aend); + ++v, ++a) + { + v->setAttribute(*a); + //cout << "thickness = " << (*a).getThickness()[0] << "-" << (*a).getThickness()[1] << endl; + } + // we're done! return 0; - } +} - int streamShader::shade(Stroke& stroke) const{ - cout << stroke << endl; +int streamShader::shade(Stroke& stroke) const +{ + cout << stroke << endl; return 0; - } - int fstreamShader::shade(Stroke& stroke) const{ - _stream << stroke << endl; +} + +int fstreamShader::shade(Stroke& stroke) const +{ + _stream << stroke << endl; return 0; - } +} } // end of namespace StrokeShaders - |