This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.cpp
Tamito Kajiyama 7ed7524c91 Got rid of a number of compiler warnings with regard to redefinitions
of _POSIX_C_SOURCE and _XOPEN_SOURCE.  There are no functional changes.
Tested with GCC 4.4.1 on Ubuntu 9.10 (karmic).
2010-04-07 23:28:29 +00:00

432 lines
11 KiB
C++
Executable File

//
// Copyright (C) : Please refer to the COPYRIGHT file distributed
// with this source distribution.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
///////////////////////////////////////////////////////////////////////////////
#include "AdvancedStrokeShaders.h"
#include "../system/PseudoNoise.h"
#include "../system/RandGen.h"
#include "StrokeIterators.h"
/////////////////////////////////////////
//
// CALLIGRAPHICS SHADER
//
/////////////////////////////////////////
CalligraphicShader::CalligraphicShader (real iMinThickness, real iMaxThickness,
const Vec2f &iOrientation, bool clamp)
: StrokeShader()
{
_minThickness=iMinThickness;
_maxThickness=iMaxThickness;
_orientation = iOrientation;
_orientation.normalize();
_clamp = clamp;
}
float ksinToto=0;
int
CalligraphicShader::shade(Stroke &ioStroke) const
{
Interface0DIterator v;
Functions0D::VertexOrientation2DF0D fun;
StrokeVertex* sv;
for(v=ioStroke.verticesBegin();
!v.isEnd();
++v)
{
real thickness;
if (fun(v) < 0)
return -1;
Vec2f vertexOri(fun.result);
Vec2r ori2d(-vertexOri[1], vertexOri[0]);
ori2d.normalizeSafe();
real scal = ori2d * _orientation;
sv = dynamic_cast<StrokeVertex*>(&(*v));
if (_clamp && (scal<0)) {
scal=0.0;
sv->attribute().setColor(1,1,1);
}
else {
scal=fabs(scal);
sv->attribute().setColor(0,0,0);
}
thickness=_minThickness+scal*(_maxThickness-_minThickness);
if (thickness<0.0)
thickness=0.0;
sv->attribute().setThickness(thickness/2.0,thickness/2.0);
}
return 0;
}
//void
//TipRemoverShader::shade(Stroke &ioStroke) const
//{
//
// StrokeInternal::StrokeVertexIterator v, vend;
// for(v=ioStroke.strokeVerticesBegin(), vend=ioStroke.strokeVerticesEnd();
// v!=vend;
// ++v)
// {
// if (((*v)->curvilinearAbscissa()<_tipLength) ||
// ((*v)->strokeLength()-(*v)->curvilinearAbscissa()<_tipLength))
// {
// (*v)->attribute().setThickness(0.0, 0.0);
// (*v)->attribute().setColor(1,1,1);
// }
// }
//
//}
/////////////////////////////////////////
//
// SPATIAL NOISE SHADER
//
/////////////////////////////////////////
static const unsigned NB_VALUE_NOISE = 512;
SpatialNoiseShader::SpatialNoiseShader (float ioamount, float ixScale, int nbOctave,
bool smooth, bool pureRandom)
: StrokeShader()
{
_amount = ioamount;
if (ixScale==0) _xScale=0;
else _xScale=1.0/ixScale/real(NB_VALUE_NOISE);
_nbOctave=nbOctave;
_smooth=smooth;
_pureRandom=pureRandom;
}
int
SpatialNoiseShader::shade(Stroke &ioStroke) const
{
Interface0DIterator v, v2;
v=ioStroke.verticesBegin();
Vec2r p(v->getProjectedX(), v->getProjectedY());
v2=v; ++v2;
Vec2r p0(v2->getProjectedX(), v2->getProjectedY());
p0=p+2*(p-p0);
StrokeVertex* sv;
sv = dynamic_cast<StrokeVertex*>(&(*v));
real initU = sv->strokeLength()*real(NB_VALUE_NOISE);
if (_pureRandom) initU+=RandGen::drand48()*real(NB_VALUE_NOISE);
Functions0D::VertexOrientation2DF0D fun;
while (!v.isEnd())
{
sv = dynamic_cast<StrokeVertex*>(&(*v));
Vec2r p(sv->getPoint());
if (fun(v) < 0)
return -1;
Vec2r vertexOri(fun.result);
Vec2r ori2d(vertexOri[0], vertexOri[1]);
ori2d = Vec2r(p-p0);
ori2d.normalizeSafe();
PseudoNoise mynoise;
real bruit;
if (_smooth)
bruit=mynoise.turbulenceSmooth(_xScale*sv->curvilinearAbscissa()+initU,
_nbOctave);
else
bruit=mynoise.turbulenceLinear(_xScale*sv->curvilinearAbscissa()+initU,
_nbOctave);
Vec2r noise(-ori2d[1]*_amount*bruit,
ori2d[0]*_amount*bruit);
sv->setPoint(p[0]+noise[0], p[1]+noise[1]);
p0=p;
++v;
}
return 0;
}
/////////////////////////////////////////
//
// SMOOTHING SHADER
//
/////////////////////////////////////////
SmoothingShader::SmoothingShader (int ionbIteration, real iFactorPoint, real ifactorCurvature, real iFactorCurvatureDifference,
real iAnisoPoint, real iAnisoNormal, real iAnisoCurvature, real iCarricatureFactor)
: StrokeShader()
{
_nbIterations=ionbIteration;
_factorCurvature=ifactorCurvature;
_factorCurvatureDifference=iFactorCurvatureDifference;
_anisoNormal=iAnisoNormal;
_anisoCurvature=iAnisoCurvature;
_carricatureFactor=iCarricatureFactor;
_factorPoint=iFactorPoint;
_anisoPoint=iAnisoPoint;
}
int
SmoothingShader::shade(Stroke &ioStroke) const
{
//cerr<<" Smoothing a stroke "<<endl;
Smoother smoother(ioStroke);
smoother.smooth(_nbIterations, _factorPoint, _factorCurvature, _factorCurvatureDifference,
_anisoPoint, _anisoNormal, _anisoCurvature, _carricatureFactor);
return 0;
}
// SMOOTHER
////////////////////////////
Smoother::Smoother(Stroke &ioStroke)
{
_stroke=&ioStroke;
_nbVertices=ioStroke.vertices_size();
_vertex=new Vec2r[_nbVertices];
_curvature=new real[_nbVertices];
_normal=new Vec2r[_nbVertices];
StrokeInternal::StrokeVertexIterator v, vend;
int i=0;
for(v = ioStroke.strokeVerticesBegin(), vend = ioStroke.strokeVerticesEnd();
v != vend;
++v)
{
_vertex[i]=(v)->getPoint();
i++;
}
Vec2r vec_tmp(_vertex[0]-_vertex[_nbVertices-1]);
_isClosedCurve = (vec_tmp.norm() < M_EPSILON);
_safeTest=(_nbVertices>4);
}
void Smoother::smooth(int nbIteration, real iFactorPoint, real ifactorCurvature, real iFactorCurvatureDifference,
real iAnisoPoint, real iAnisoNormal, real iAnisoCurvature, real iCarricatureFactor)
{
_factorCurvature=ifactorCurvature;
_factorCurvatureDifference=iFactorCurvatureDifference;
_anisoNormal=iAnisoNormal;
_anisoCurvature=iAnisoCurvature;
_carricatureFactor=iCarricatureFactor;
_factorPoint=iFactorPoint;
_anisoPoint=iAnisoPoint;
for (int i=0; i<nbIteration; i++)
iteration ();
copyVertices();
}
real edgeStopping (real x, real sigma)
{
if (sigma==0.0) return 1.0;
return exp(-x*x/(sigma*sigma));
}
void
Smoother::iteration ()
{
computeCurvature();
for (int i=1; i<_nbVertices-1; i++)
{
real motionNormal=_factorCurvature*_curvature[i]*
edgeStopping(_curvature[i], _anisoNormal);
real diffC1=_curvature[i]-_curvature[i-1];
real diffC2=_curvature[i]-_curvature[i+1];
real motionCurvature=edgeStopping(diffC1, _anisoCurvature)*diffC1 +
edgeStopping(diffC2, _anisoCurvature)*diffC2;//_factorCurvatureDifference;
motionCurvature*=_factorCurvatureDifference;
//motionCurvature=_factorCurvatureDifference*(diffC1+diffC2);
if (_safeTest)
_vertex[i]=Vec2r(_vertex[i]+(motionNormal+motionCurvature)*_normal[i]);
Vec2r v1(_vertex[i-1]-_vertex[i]);
Vec2r v2(_vertex[i+1]-_vertex[i]);
real d1 = v1.norm();
real d2 = v2.norm();
_vertex[i]=Vec2r(_vertex[i]+
_factorPoint*edgeStopping(d2, _anisoPoint)*(_vertex[i-1]-_vertex[i]) +
_factorPoint*edgeStopping(d1, _anisoPoint)*(_vertex[i+1]-_vertex[i]) );
}
if (_isClosedCurve)
{
real motionNormal=_factorCurvature*_curvature[0]*
edgeStopping(_curvature[0], _anisoNormal);
real diffC1=_curvature[0]-_curvature[_nbVertices-2];
real diffC2=_curvature[0]-_curvature[1];
real motionCurvature=edgeStopping(diffC1, _anisoCurvature)*diffC1 +
edgeStopping(diffC2, _anisoCurvature)*diffC2;//_factorCurvatureDifference;
motionCurvature*=_factorCurvatureDifference;
//motionCurvature=_factorCurvatureDifference*(diffC1+diffC2);
_vertex[0]=Vec2r(_vertex[0]+(motionNormal+motionCurvature)*_normal[0]);
_vertex[_nbVertices-1]=_vertex[0];
}
}
void
Smoother::computeCurvature ()
{
int i;
Vec2r BA, BC, normalCurvature;
for (i = 1; i < _nbVertices - 1; i++)
{
BA=_vertex[i-1]-_vertex[i];
BC=_vertex[i+1]-_vertex[i];
real lba=BA.norm(), lbc=BC.norm();
BA.normalizeSafe();
BC.normalizeSafe();
normalCurvature = BA + BC;
_normal[i]=Vec2r(-(BC-BA)[1], (BC-BA)[0]);
_normal[i].normalizeSafe();
_curvature[i] = normalCurvature * _normal[i];
if (lba+lbc > M_EPSILON)
_curvature[i]/=(0.5*lba+lbc);
}
_curvature[0]=_curvature[1];
_curvature[_nbVertices-1]=_curvature[_nbVertices-2];
Vec2r di(_vertex[1]-_vertex[0]);
_normal[0] = Vec2r(-di[1], di[0]);
_normal[0].normalizeSafe();
di=_vertex[_nbVertices-1]-_vertex[_nbVertices-2];
_normal[_nbVertices-1]=Vec2r(-di[1], di[0]);
_normal[_nbVertices-1].normalizeSafe();
if (_isClosedCurve)
{
BA=_vertex[_nbVertices-2]-_vertex[0];
BC=_vertex[1]-_vertex[0];
real lba=BA.norm(), lbc=BC.norm();
BA.normalizeSafe();
BC.normalizeSafe();
normalCurvature = BA + BC;
_normal[i]=Vec2r(-(BC-BA)[1], (BC-BA)[0]);
_normal[i].normalizeSafe();
_curvature[i] = normalCurvature * _normal[i];
if (lba+lbc > M_EPSILON)
_curvature[i]/=(0.5*lba+lbc);
_normal[_nbVertices-1]=_normal[0];
_curvature[_nbVertices-1]=_curvature[0];
}
}
void
Smoother::copyVertices ()
{
int i=0;
StrokeInternal::StrokeVertexIterator v, vend;
for(v=_stroke->strokeVerticesBegin(), vend=_stroke->strokeVerticesEnd();
v!=vend;
++v)
{
const Vec2r p0((v)->getPoint());
const Vec2r p1(_vertex[i]);
Vec2r p(p0 + _carricatureFactor * (p1 - p0));
(v)->setPoint(p[0], p[1]);
i++;
}
}
/////////////////////////////////////////
//
// OMISSION SHADER
//
/////////////////////////////////////////
OmissionShader::OmissionShader (real sizeWindow, real thrVari, real thrFlat, real lFlat)
{
_sizeWindow=sizeWindow;
_thresholdVariation=thrVari;
_thresholdFlat=thrFlat;
_lengthFlat=lFlat;
}
int
OmissionShader::shade(Stroke &ioStroke) const
{
Omitter omi(ioStroke);
omi.omit(_sizeWindow, _thresholdVariation, _thresholdFlat, _lengthFlat);
return 0;
}
// OMITTER
///////////////////////////
Omitter::Omitter (Stroke &ioStroke)
:Smoother (ioStroke)
{
StrokeInternal::StrokeVertexIterator v, vend;
int i=0;
for(v=ioStroke.strokeVerticesBegin(), vend=ioStroke.strokeVerticesEnd();
v!=vend;
++v)
{
_u[i]=(v)->curvilinearAbscissa();
i++;
}
}
void
Omitter::omit (real sizeWindow, real thrVari, real thrFlat, real lFlat)
{
_sizeWindow=sizeWindow;
_thresholdVariation=thrVari;
_thresholdFlat=thrFlat;
_lengthFlat=lFlat;
for (int i=1; i<_nbVertices-1; i++)
{
if (_u[i]<_lengthFlat) continue;
// is the previous segment flat?
int j=i-1;
while ((j>=0) && (_u[i]-_u[j]<_lengthFlat))
{
if ((_normal[j] * _normal[i]) < _thresholdFlat)
; // FIXME
j--;
}
}
}