Index: source/blender/freestyle/intern/stroke/StrokeRep.cpp |
=================================================================== |
--- source/blender/freestyle/intern/stroke/StrokeRep.cpp (revision 0) |
+++ source/blender/freestyle/intern/stroke/StrokeRep.cpp (working copy) |
@@ -0,0 +1,789 @@ |
+/* |
+ * ***** 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/StrokeRep.cpp |
+ * \ingroup freestyle |
+ * \brief Class to define the representation of a stroke (for display purpose) |
+ * \author Stephane Grabli |
+ * \date 05/03/2003 |
+ */ |
+ |
+#include "Stroke.h" |
+#include "StrokeAdvancedIterators.h" |
+#include "StrokeIterators.h" |
+#include "StrokeRenderer.h" |
+#include "StrokeRep.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 1.0e4 |
+ |
+static 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); |
+} |
+ |
+static 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(); |
+ Vec2r stripDir(orthDir); |
+ // check whether the orientation was user defined |
+ if (sv->attribute().isAttributeAvailableVec2f("orientation")) { |
+ Vec2r userDir = sv->attribute().getAttributeVec2f("orientation"); |
+ userDir.normalize(); |
+ real dp = userDir * orthDir; |
+ if (dp < 0) |
+ userDir = userDir * (-1.0f); |
+ stripDir = userDir; |
+ } |
+ const float *thickness = sv->attribute().getThickness(); |
+ _vertices.push_back(new StrokeVertexRep(sv->getPoint() + thickness[1] * stripDir)); |
+ _vertices.push_back(new StrokeVertexRep(sv->getPoint() - thickness[0] * stripDir)); |
+ |
+#if 0 |
+ 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; |
+ } |
+ } |
+#endif |
+ |
+ 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.0f); |
+ 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.0f); |
+ 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[0] * 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(); |
+ Vec2r stripDirLast(orthDir); |
+ // check whether the orientation was user defined |
+ if (sv->attribute().isAttributeAvailableVec2f("orientation")) { |
+ Vec2r userDir = sv->attribute().getAttributeVec2f("orientation"); |
+ userDir.normalize(); |
+ real dp = userDir * orthDir; |
+ if (dp < 0) |
+ userDir = userDir * (-1.0f); |
+ stripDirLast = userDir; |
+ } |
+ const float *thicknessLast = sv->attribute().getThickness(); |
+ _vertices.push_back(new StrokeVertexRep(sv->getPoint() + thicknessLast[1] * stripDirLast)); |
+ ++i; |
+ _vertices.push_back(new StrokeVertexRep(sv->getPoint() - thicknessLast[0] * stripDirLast)); |
+ ++i; |
+ |
+#if 0 |
+ int n = i - 1; |
+ // 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; |
+ } |
+ } |
+#endif |
+ |
+ _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 * (int)iStrokeVertices.size()) |
+ cerr << "Warning: problem with stripe size\n"; |
+ |
+ cleanUpSingularities (iStrokeVertices); |
+} |
+ |
+// CLEAN UP |
+///////////////////////// |
+ |
+void Strip::cleanUpSingularities (const vector<StrokeVertex*>& iStrokeVertices) |
+{ |
+ int k; |
+ int 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; //soc unused - *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 (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++; |
+#if 0 |
+ cerr << "col=("<<sv->attribute().getColor()[0] << ", " |
+ << sv->attribute().getColor()[1] << ", " << sv->attribute().getColor()[2] << ")" << endl; |
+#endif |
+ } |
+} |
+ |
+void Strip::computeTexCoordWithTips (const vector<StrokeVertex*>& iStrokeVertices, bool tipBegin, bool tipEnd) |
+{ |
+ //soc unused - unsigned int sizeStrip = _vertices.size() + 8; //for the transition between the tip and the body |
+ vector<StrokeVertex*>::const_iterator v, vend; |
+ StrokeVertex *sv = NULL; |
+ |
+ v = iStrokeVertices.begin(); |
+ vend = iStrokeVertices.end(); |
+ float l = (*v)->strokeLength() / _averageThickness; |
+ int tiles = int(l); |
+ float fact = (float(tiles) + 0.5) / l; |
+ //soc unused - float uTip2 = float(tiles) + 0.25; |
+ float u = 0; |
+ float uPrev = 0; |
+ int i = 0; |
+ float t; |
+ StrokeVertexRep *tvRep1, *tvRep2; |
+ |
+#if 0 |
+ cerr << "l=" << l << " tiles=" << tiles << " _averageThicnkess=" |
+ << _averageThickness << " strokeLength=" << (*v)->strokeLength() << endl; |
+#endif |
+ |
+ 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 0 |
+ if (!tiles) |
+ t = 0.5; |
+#endif |
+ 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; |
+ } |
+ } |
+ |
+#if 0 |
+ 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; |
+#endif |
+} |
+ |
+// |
+// StrokeRep |
+///////////////////////////////////// |
+ |
+StrokeRep::StrokeRep() |
+{ |
+ _stroke = 0; |
+ _strokeType = Stroke::OPAQUE_MEDIUM; |
+ TextureManager *ptm = TextureManager::getInstance(); |
+ if (ptm) |
+ _textureId = ptm->getDefaultTextureId(); |
+#if 0 |
+ _averageTextureAlpha = 0.5; //default value |
+ if (_strokeType == OIL_STROKE) |
+ _averageTextureAlpha = 0.75; |
+ if (_strokeType >= NO_BLEND_STROKE) |
+ _averageTextureAlpha = 1.0 |
+#endif |
+} |
+ |
+StrokeRep::StrokeRep(Stroke *iStroke) |
+{ |
+ _stroke = iStroke; |
+ _strokeType = iStroke->getMediumType(); |
+ _textureId = iStroke->getTextureId(); |
+ if (_textureId == 0) { |
+ TextureManager *ptm = TextureManager::getInstance(); |
+ if (ptm) |
+ _textureId = ptm->getDefaultTextureId(); |
+ } |
+ |
+#if 0 |
+ _averageTextureAlpha = 0.5; //default value |
+ if (_strokeType == OIL_STROKE) |
+ _averageTextureAlpha = 0.75; |
+ if (_strokeType >= NO_BLEND_STROKE) |
+ _averageTextureAlpha = 1.0; |
+#endif |
+ create(); |
+} |
+ |
+StrokeRep::StrokeRep(const StrokeRep& iBrother) |
+{ |
+ //soc unused - 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); |
+} |