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/StrokeRep.cpp
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/StrokeRep.cpp')
-rwxr-xr-xsource/blender/freestyle/intern/stroke/StrokeRep.cpp820
1 files changed, 820 insertions, 0 deletions
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);
+}
+
+
+