Blender  V2.93
StrokeRep.cpp
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
22 #include <cmath>
23 
24 #include "Stroke.h"
26 #include "StrokeIterators.h"
27 #include "StrokeRenderer.h"
28 #include "StrokeRep.h"
29 
30 #include "BKE_global.h"
31 
32 using namespace std;
33 
34 namespace Freestyle {
35 
36 //
37 // STROKE VERTEX REP
39 
40 StrokeVertexRep::StrokeVertexRep(const StrokeVertexRep &iBrother)
41 {
42  _point2d = iBrother._point2d;
43  _texCoord = iBrother._texCoord;
44  _texCoord_w_tips = iBrother._texCoord_w_tips;
45  _color = iBrother._color;
46  _alpha = iBrother._alpha;
47 }
48 
49 //
50 // STRIP
52 
53 Strip::Strip(const vector<StrokeVertex *> &iStrokeVertices,
54  bool hasTex,
55  bool tipBegin,
56  bool tipEnd,
57  float texStep)
58 {
59  createStrip(iStrokeVertices);
60 
61  setVertexColor(iStrokeVertices);
62 
63  if (hasTex) {
64  // We compute both kinds of coordinates to use different kinds of textures
65  computeTexCoord(iStrokeVertices, texStep);
66  computeTexCoordWithTips(iStrokeVertices, tipBegin, tipEnd, texStep);
67  }
68 }
69 
70 Strip::Strip(const Strip &iBrother)
71 {
72  if (!iBrother._vertices.empty()) {
73  for (vertex_container::const_iterator v = iBrother._vertices.begin(),
74  vend = iBrother._vertices.end();
75  v != vend;
76  ++v) {
77  _vertices.push_back(new StrokeVertexRep(**v));
78  }
79  }
80  _averageThickness = iBrother._averageThickness;
81 }
82 
83 Strip::~Strip()
84 {
85  if (!_vertices.empty()) {
86  for (vertex_container::iterator v = _vertices.begin(), vend = _vertices.end(); v != vend;
87  ++v) {
88  delete (*v);
89  }
90  _vertices.clear();
91  }
92 }
93 
95 // Strip creation
97 
98 #define EPS_SINGULARITY_RENDERER 0.05
99 #define ZERO 0.00001
100 #define MAX_RATIO_LENGTH_SINGU 2
101 #define HUGE_COORD 1.0e4
102 
103 static bool notValid(Vec2r p)
104 {
105  return (p[0] != p[0]) || (p[1] != p[1]) || (fabs(p[0]) > HUGE_COORD) ||
106  (fabs(p[1]) > HUGE_COORD) || (p[0] < -HUGE_COORD) || (p[1] < -HUGE_COORD);
107 }
108 
109 #if 0
110 static real crossP(const Vec2r &A, const Vec2r &B)
111 {
112  return A[0] * B[1] - A[1] * B[0];
113 }
114 #endif
115 
116 void Strip::createStrip(const vector<StrokeVertex *> &iStrokeVertices)
117 {
118  // computeParameterization();
119  if (iStrokeVertices.size() < 2) {
120  if (G.debug & G_DEBUG_FREESTYLE) {
121  cout << "Warning: strip has less than 2 vertices" << endl;
122  }
123  return;
124  }
125  _vertices.reserve(2 * iStrokeVertices.size());
126  if (!_vertices.empty()) {
127  for (vertex_container::iterator v = _vertices.begin(), vend = _vertices.end(); v != vend;
128  ++v) {
129  delete (*v);
130  }
131  _vertices.clear();
132  }
133  _averageThickness = 0.0;
134 
135  vector<StrokeVertex *>::const_iterator v, vend, v2, vPrev;
136  StrokeVertex *sv, *sv2, *svPrev;
137  int orientationErrors = 0;
138 
139  // special case of first vertex
140  v2 = v = iStrokeVertices.begin();
141  ++v2;
142  sv = *v;
143  vPrev = v; // in case the stroke has only 2 vertices;
144  sv2 = *v2;
145  Vec2r dir(sv2->getPoint() - sv->getPoint());
146  Vec2r orthDir(-dir[1], dir[0]);
147  if (orthDir.norm() > ZERO) {
148  orthDir.normalize();
149  }
150  Vec2r stripDir(orthDir);
151  // check whether the orientation was user defined
152  if (sv->attribute().isAttributeAvailableVec2f("orientation")) {
153  Vec2r userDir = sv->attribute().getAttributeVec2f("orientation");
154  if (userDir.norm() > 1e-6) {
155  userDir.normalize();
156  real dp = userDir * orthDir;
157  if (dp < 0) {
158  userDir = userDir * (-1.0f);
159  }
160  stripDir = userDir;
161  }
162  else {
163  ++orientationErrors;
164  }
165  }
166  const float *thickness = sv->attribute().getThickness();
167  _vertices.push_back(new StrokeVertexRep(sv->getPoint() + thickness[1] * stripDir));
168  _vertices.push_back(new StrokeVertexRep(sv->getPoint() - thickness[0] * stripDir));
169 
170 #if 0
171  Vec2r userDir = _stroke->getBeginningOrientation();
172  if (userDir != Vec2r(0, 0)) {
173  userDir.normalize();
174  real o1 = (orthDir * userDir);
175  real o2 = crossP(orthDir, userDir);
176  real orientation = o1 * o2;
177  if (orientation > 0) {
178  // then the vertex to move is v0
179  if (o1 > 0) {
180  _vertex[0] = _vertex[1] + userDir;
181  }
182  else {
183  _vertex[0] = _vertex[1] - userDir;
184  }
185  }
186  if (orientation < 0) {
187  // then we must move v1
188  if (o1 < 0) {
189  _vertex[1] = _vertex[0] + userDir;
190  }
191  else {
192  _vertex[1] = _vertex[0] - userDir;
193  }
194  }
195  }
196 #endif
197 
198  int i = 2; // 2 because we have already processed the first vertex
199 
200  for (vend = iStrokeVertices.end(), ++v, ++v2; v2 != vend; vPrev = v++, ++v2) {
201  sv = (*v);
202  sv2 = (*v2);
203  svPrev = (*vPrev);
204  Vec2r p(sv->getPoint()), p2(sv2->getPoint()), pPrev(svPrev->getPoint());
205 
206  // direction and orthogonal vector to the next segment
207  Vec2r dir(p2 - p);
208  float dirNorm = dir.norm();
209  dir.normalize();
210  Vec2r orthDir(-dir[1], dir[0]);
211  Vec2r stripDir = orthDir;
212  if (sv->attribute().isAttributeAvailableVec2f("orientation")) {
213  Vec2r userDir = sv->attribute().getAttributeVec2f("orientation");
214  if (userDir.norm() > 1e-6) {
215  userDir.normalize();
216  real dp = userDir * orthDir;
217  if (dp < 0) {
218  userDir = userDir * (-1.0f);
219  }
220  stripDir = userDir;
221  }
222  else {
223  ++orientationErrors;
224  }
225  }
226 
227  // direction and orthogonal vector to the previous segment
228  Vec2r dirPrev(p - pPrev);
229  float dirPrevNorm = dirPrev.norm();
230  dirPrev.normalize();
231  Vec2r orthDirPrev(-dirPrev[1], dirPrev[0]);
232  Vec2r stripDirPrev = orthDirPrev;
233  if (svPrev->attribute().isAttributeAvailableVec2f("orientation")) {
234  Vec2r userDir = svPrev->attribute().getAttributeVec2f("orientation");
235  if (userDir.norm() > 1e-6) {
236  userDir.normalize();
237  real dp = userDir * orthDir;
238  if (dp < 0) {
239  userDir = userDir * (-1.0f);
240  }
241  stripDirPrev = userDir;
242  }
243  else {
244  ++orientationErrors;
245  }
246  }
247 
248  const float *thickness = sv->attribute().getThickness();
249  _averageThickness += thickness[0] + thickness[1];
250  Vec2r pInter;
251  int interResult;
252 
253  interResult = GeomUtils::intersect2dLine2dLine(Vec2r(pPrev + thickness[1] * stripDirPrev),
254  Vec2r(p + thickness[1] * stripDirPrev),
255  Vec2r(p + thickness[1] * stripDir),
256  Vec2r(p2 + thickness[1] * stripDir),
257  pInter);
258  if (interResult == GeomUtils::DO_INTERSECT) {
259  _vertices.push_back(new StrokeVertexRep(pInter));
260  }
261  else {
262  _vertices.push_back(new StrokeVertexRep(p + thickness[1] * stripDir));
263  }
264  ++i;
265 
266  interResult = GeomUtils::intersect2dLine2dLine(Vec2r(pPrev - thickness[0] * stripDirPrev),
267  Vec2r(p - thickness[0] * stripDirPrev),
268  Vec2r(p - thickness[0] * stripDir),
269  Vec2r(p2 - thickness[0] * stripDir),
270  pInter);
271  if (interResult == GeomUtils::DO_INTERSECT) {
272  _vertices.push_back(new StrokeVertexRep(pInter));
273  }
274  else {
275  _vertices.push_back(new StrokeVertexRep(p - thickness[0] * stripDir));
276  }
277  ++i;
278 
279  // if the angle is obtuse, we simply average the directions to avoid the singularity
280  stripDir = stripDir + stripDirPrev;
281  if ((dirNorm < ZERO) || (dirPrevNorm < ZERO) || (stripDir.norm() < ZERO)) {
282  stripDir[0] = 0;
283  stripDir[1] = 0;
284  }
285  else {
286  stripDir.normalize();
287  }
288 
289  Vec2r vec_tmp(_vertices[i - 2]->point2d() - p);
290  if ((vec_tmp.norm() > thickness[1] * MAX_RATIO_LENGTH_SINGU) || (dirNorm < ZERO) ||
291  (dirPrevNorm < ZERO) || notValid(_vertices[i - 2]->point2d()) ||
292  (fabs(stripDir * dir) < EPS_SINGULARITY_RENDERER)) {
293  _vertices[i - 2]->setPoint2d(p + thickness[1] * stripDir);
294  }
295 
296  vec_tmp = _vertices[i - 1]->point2d() - p;
297  if ((vec_tmp.norm() > thickness[0] * MAX_RATIO_LENGTH_SINGU) || (dirNorm < ZERO) ||
298  (dirPrevNorm < ZERO) || notValid(_vertices[i - 1]->point2d()) ||
299  (fabs(stripDir * dir) < EPS_SINGULARITY_RENDERER)) {
300  _vertices[i - 1]->setPoint2d(p - thickness[0] * stripDir);
301  }
302  } // end of for
303 
304  // special case of last vertex
305  sv = *v;
306  sv2 = *vPrev;
307  dir = Vec2r(sv->getPoint() - sv2->getPoint());
308  orthDir = Vec2r(-dir[1], dir[0]);
309  if (orthDir.norm() > ZERO) {
310  orthDir.normalize();
311  }
312  Vec2r stripDirLast(orthDir);
313  // check whether the orientation was user defined
314  if (sv->attribute().isAttributeAvailableVec2f("orientation")) {
315  Vec2r userDir = sv->attribute().getAttributeVec2f("orientation");
316  if (userDir.norm() > 1e-6) {
317  userDir.normalize();
318  real dp = userDir * orthDir;
319  if (dp < 0) {
320  userDir = userDir * (-1.0f);
321  }
322  stripDirLast = userDir;
323  }
324  else {
325  ++orientationErrors;
326  }
327  }
328  const float *thicknessLast = sv->attribute().getThickness();
329  _vertices.push_back(new StrokeVertexRep(sv->getPoint() + thicknessLast[1] * stripDirLast));
330  ++i;
331  _vertices.push_back(new StrokeVertexRep(sv->getPoint() - thicknessLast[0] * stripDirLast));
332  ++i;
333 
334 #if 0
335  int n = i - 1;
336  // check whether the orientation of the extremity was user defined
337  userDir = _stroke->getEndingOrientation();
338  if (userDir != Vec2r(0, 0)) {
339  userDir.normalize();
340  real o1 = (orthDir * userDir);
341  real o2 = crossP(orthDir, userDir);
342  real orientation = o1 * o2;
343  if (orientation > 0) {
344  // then the vertex to move is vn
345  if (o1 < 0) {
346  _vertex[n] = _vertex[n - 1] + userDir;
347  }
348  else {
349  _vertex[n] = _vertex[n - 1] - userDir;
350  }
351  }
352  if (orientation < 0) {
353  // then we must move vn-1
354  if (o1 > 0) {
355  _vertex[n - 1] = _vertex[n] + userDir;
356  }
357  else {
358  _vertex[n - 1] = _vertex[n] - userDir;
359  }
360  }
361  }
362 #endif
363 
364  _averageThickness /= float(iStrokeVertices.size() - 2);
365  // I did not use the first and last vertex for the average
366  if (iStrokeVertices.size() < 3) {
367  _averageThickness = 0.5 * (thicknessLast[1] + thicknessLast[0] + thickness[0] + thickness[1]);
368  }
369 
370  if (orientationErrors > 0) {
371  if (G.debug & G_DEBUG_FREESTYLE) {
372  cout << "Warning: " << orientationErrors
373  << " invalid zero-length orientation vector(s) found.\n";
374  }
375  }
376 
377  if (i != 2 * (int)iStrokeVertices.size()) {
378  if (G.debug & G_DEBUG_FREESTYLE) {
379  cout << "Warning: problem with stripe size\n";
380  }
381  }
382 
383  cleanUpSingularities(iStrokeVertices);
384 }
385 
386 // CLEAN UP
388 
389 void Strip::cleanUpSingularities(const vector<StrokeVertex *> &iStrokeVertices)
390 {
391  int k;
392  int sizeStrip = _vertices.size();
393 
394  for (k = 0; k < sizeStrip; k++) {
395  if (notValid(_vertices[k]->point2d())) {
396  if (G.debug & G_DEBUG_FREESTYLE) {
397  cout << "Warning: strip vertex " << k << " non valid" << endl;
398  }
399  return;
400  }
401  }
402 
403  // return;
404  if (iStrokeVertices.size() < 2) {
405  return;
406  }
407  int i = 0, j;
408  vector<StrokeVertex *>::const_iterator v, vend, v2;
409  StrokeVertex *sv, *sv2;
410 
411  bool singu1 = false, singu2 = false;
412  int timeSinceSingu1 = 0, timeSinceSingu2 = 0;
413 
414  // special case of first vertex
415  v = iStrokeVertices.begin();
416  for (vend = iStrokeVertices.end(); v != vend; v++) {
417  v2 = v;
418  ++v2;
419  if (v2 == vend) {
420  break;
421  }
422  sv = (*v);
423  sv2 = (*v2);
424  Vec2r p(sv->getPoint()), p2(sv2->getPoint());
425 
426  Vec2r dir(p2 - p);
427  if (dir.norm() > ZERO) {
428  dir.normalize();
429  }
430  Vec2r dir1, dir2;
431  dir1 = _vertices[2 * i + 2]->point2d() - _vertices[2 * i]->point2d();
432  dir2 = _vertices[2 * i + 3]->point2d() - _vertices[2 * i + 1]->point2d();
433 
434  if ((dir1 * dir) < -ZERO) {
435  singu1 = true;
436  timeSinceSingu1++;
437  }
438  else {
439  if (singu1) {
440  int toto = i - timeSinceSingu1;
441  if (toto < 0) {
442  cerr << "Stephane dit \"Toto\"" << endl;
443  }
444  // traverse all the vertices of the singularity and average them
445  Vec2r avP(0.0, 0.0);
446  for (j = i - timeSinceSingu1; j <= i; j++) {
447  avP = Vec2r(avP + _vertices[2 * j]->point2d());
448  }
449  avP = Vec2r(1.0 / float(timeSinceSingu1 + 1) * avP);
450  for (j = i - timeSinceSingu1; j <= i; j++) {
451  _vertices[2 * j]->setPoint2d(avP);
452  }
453  //_vertex[2 * j] = _vertex[2 * i];
454  singu1 = false;
455  timeSinceSingu1 = 0;
456  }
457  }
458  if ((dir2 * dir) < -ZERO) {
459  singu2 = true;
460  timeSinceSingu2++;
461  }
462  else {
463  if (singu2) {
464  int toto = i - timeSinceSingu2;
465  if (toto < 0) {
466  cerr << "Stephane dit \"Toto\"" << endl;
467  }
468  // traverse all the vertices of the singularity and average them
469  Vec2r avP(0.0, 0.0);
470  for (j = i - timeSinceSingu2; j <= i; j++) {
471  avP = Vec2r(avP + _vertices[2 * j + 1]->point2d());
472  }
473  avP = Vec2r(1.0 / float(timeSinceSingu2 + 1) * avP);
474  for (j = i - timeSinceSingu2; j <= i; j++) {
475  _vertices[2 * j + 1]->setPoint2d(avP);
476  }
477  //_vertex[2 * j + 1] = _vertex[2 * i + 1];
478  singu2 = false;
479  timeSinceSingu2 = 0;
480  }
481  }
482  i++;
483  }
484 
485  if (singu1) {
486  // traverse all the vertices of the singularity and average them
487  Vec2r avP(0.0, 0.0);
488  for (j = i - timeSinceSingu1; j < i; j++) {
489  avP = Vec2r(avP + _vertices[2 * j]->point2d());
490  }
491  avP = Vec2r(1.0 / float(timeSinceSingu1) * avP);
492  for (j = i - timeSinceSingu1; j < i; j++) {
493  _vertices[2 * j]->setPoint2d(avP);
494  }
495  }
496  if (singu2) {
497  // traverse all the vertices of the singularity and average them
498  Vec2r avP(0.0, 0.0);
499  for (j = i - timeSinceSingu2; j < i; j++) {
500  avP = Vec2r(avP + _vertices[2 * j + 1]->point2d());
501  }
502  avP = Vec2r(1.0 / float(timeSinceSingu2) * avP);
503  for (j = i - timeSinceSingu2; j < i; j++) {
504  _vertices[2 * j + 1]->setPoint2d(avP);
505  }
506  }
507 
508  for (k = 0; k < sizeStrip; k++) {
509  if (notValid(_vertices[k]->point2d())) {
510  if (G.debug & G_DEBUG_FREESTYLE) {
511  cout << "Warning: strip vertex " << k << " non valid after cleanup" << endl;
512  }
513  return;
514  }
515  }
516 }
517 
518 // Vertex color (RGBA)
520 
521 void Strip::setVertexColor(const vector<StrokeVertex *> &iStrokeVertices)
522 {
523  vector<StrokeVertex *>::const_iterator v, vend;
524  StrokeVertex *sv;
525  int i = 0;
526  for (v = iStrokeVertices.begin(), vend = iStrokeVertices.end(); v != vend; v++) {
527  sv = (*v);
528  _vertices[i]->setColor(Vec3r(sv->attribute().getColorRGB()));
529  _vertices[i]->setAlpha(sv->attribute().getAlpha());
530  i++;
531  _vertices[i]->setColor(Vec3r(sv->attribute().getColorRGB()));
532  _vertices[i]->setAlpha(sv->attribute().getAlpha());
533  i++;
534 #if 0
535  cerr << "col=(" << sv->attribute().getColor()[0] << ", " << sv->attribute().getColor()[1]
536  << ", " << sv->attribute().getColor()[2] << ")" << endl;
537 #endif
538  }
539 }
540 
541 // Texture coordinates
543 
544 void Strip::computeTexCoord(const vector<StrokeVertex *> &iStrokeVertices, float texStep)
545 {
546  vector<StrokeVertex *>::const_iterator v, vend;
547  StrokeVertex *sv;
548  int i = 0;
549  for (v = iStrokeVertices.begin(), vend = iStrokeVertices.end(); v != vend; v++) {
550  sv = (*v);
551  _vertices[i]->setTexCoord(
552  Vec2r((real)(sv->curvilinearAbscissa() / (_averageThickness * texStep)), 0));
553  i++;
554  _vertices[i]->setTexCoord(
555  Vec2r((real)(sv->curvilinearAbscissa() / (_averageThickness * texStep)), -1));
556  i++;
557  }
558 }
559 
560 void Strip::computeTexCoordWithTips(const vector<StrokeVertex *> &iStrokeVertices,
561  bool tipBegin,
562  bool tipEnd,
563  float texStep)
564 {
565  vector<StrokeVertex *>::const_iterator v, vend;
566  StrokeVertex *sv = nullptr;
567  StrokeVertexRep *tvRep[2] = {nullptr};
568 
569  float l, fact, t;
570  float u = 0, uPrev = 0;
571  int tiles;
572  int i = 0;
573  float spacedThickness = _averageThickness * texStep;
574 
575  v = iStrokeVertices.begin();
576  vend = iStrokeVertices.end();
577  l = (*v)->strokeLength() / spacedThickness;
578  tiles = std::roundf(l); // round to the nearest
579  fact = (float(tiles) + 0.5) / l;
580 
581 #if 0
582  cerr << "l=" << l << " tiles=" << tiles << " _averageThicnkess=" << _averageThickness
583  << " strokeLength=" << (*v)->strokeLength() << endl;
584 #endif
585 
586  vector<StrokeVertexRep *>::iterator currentSV = _vertices.begin();
587  StrokeVertexRep *svRep;
588  if (tipBegin) {
589  for (; v != vend; v++) {
590  sv = (*v);
591  svRep = *currentSV;
592  u = sv->curvilinearAbscissa() / spacedThickness * fact;
593  if (u > 0.25) {
594  break;
595  }
596 
597  svRep->setTexCoord(Vec2r((real)u, -0.5), true);
598  i++;
599  ++currentSV;
600 
601  svRep = *currentSV;
602  svRep->setTexCoord(Vec2r((real)u, -1), true);
603  i++;
604  ++currentSV;
605  uPrev = u;
606  }
607 
608  if (v != vend && i >= 2) {
609  // first transition vertex
610  if (fabs(u - uPrev) > ZERO) {
611  t = (0.25 - uPrev) / (u - uPrev);
612  }
613  else {
614  t = 0;
615  }
616  for (int k = 0; k < 2; k++) {
617  tvRep[k] = new StrokeVertexRep((1 - t) * _vertices[i - 2]->point2d() +
618  t * _vertices[i]->point2d());
619  tvRep[k]->setTexCoord((1 - t) * _vertices[i - 2]->texCoord() +
620  t * _vertices[i]->texCoord());
621  // v coord is -0.5 for tvRep[0], -1.0 for tvRep[1]
622  tvRep[k]->setTexCoord(Vec2r(0.25, -0.5 * (k + 1)), true);
623  tvRep[k]->setColor((1 - t) * _vertices[i - 2]->color() +
624  t * Vec3r(sv->attribute().getColorRGB()));
625  tvRep[k]->setAlpha((1 - t) * _vertices[i - 2]->alpha() + t * sv->attribute().getAlpha());
626  i++;
627  }
628  for (int k = 0; k < 2; k++) {
629  currentSV = _vertices.insert(currentSV, tvRep[k]);
630  ++currentSV;
631  }
632 
633  // copy the vertices with different texture coordinates
634  for (int k = 0; k < 2; k++) {
635  tvRep[k] = new StrokeVertexRep(*(_vertices[i - 2]));
636  // v coord is 0.0 for tvRep[0], -0.5 for tvRep[1]
637  tvRep[k]->setTexCoord(Vec2r(0.0, -0.5 * k), true);
638  i++;
639  }
640  for (int k = 0; k < 2; k++) {
641  currentSV = _vertices.insert(currentSV, tvRep[k]);
642  ++currentSV;
643  }
644  }
645  }
646  uPrev = 0;
647 
648  // body of the stroke
649  for (; v != vend; v++) {
650  sv = (*v);
651  svRep = *currentSV;
652  u = sv->curvilinearAbscissa() / spacedThickness * fact - 0.25;
653  if (u > tiles) {
654  break;
655  }
656 
657  svRep->setTexCoord(Vec2r((real)u, 0), true);
658  i++;
659  ++currentSV;
660 
661  svRep = *currentSV;
662  svRep->setTexCoord(Vec2r((real)u, -0.5), true);
663  i++;
664  ++currentSV;
665 
666  uPrev = u;
667  }
668 
669  if (tipEnd) {
670  if (v != vend && i >= 2) {
671  // second transition vertex
672  if (fabs(u - uPrev) > ZERO) {
673  t = (float(tiles) - uPrev) / (u - uPrev);
674  }
675  else {
676  t = 0;
677  }
678  for (int k = 0; k < 2; k++) {
679  tvRep[k] = new StrokeVertexRep((1 - t) * _vertices[i - 2]->point2d() +
680  t * _vertices[i]->point2d());
681  tvRep[k]->setTexCoord((1 - t) * _vertices[i - 2]->texCoord() +
682  t * _vertices[i]->texCoord());
683  // v coord is 0.0 for tvRep[0], -0.5 for tvRep[1]
684  tvRep[k]->setTexCoord(Vec2r((real)tiles, -0.5 * k), true);
685  tvRep[k]->setColor((1 - t) * _vertices[i - 2]->color() +
686  t * Vec3r(sv->attribute().getColorRGB()));
687  tvRep[k]->setAlpha((1 - t) * _vertices[i - 2]->alpha() + t * sv->attribute().getAlpha());
688  i++;
689  }
690  for (int k = 0; k < 2; k++) {
691  currentSV = _vertices.insert(currentSV, tvRep[k]);
692  ++currentSV;
693  }
694 
695  // copy the vertices with different texture coordinates
696  for (int k = 0; k < 2; k++) {
697  tvRep[k] = new StrokeVertexRep(*(_vertices[i - 2]));
698  // v coord is -0.5 for tvRep[0], -1.0 for tvRep[1]
699  tvRep[k]->setTexCoord(Vec2r(0.75, -0.5 * (k + 1)), true);
700  i++;
701  }
702  for (int k = 0; k < 2; k++) {
703  currentSV = _vertices.insert(currentSV, tvRep[k]);
704  ++currentSV;
705  }
706  }
707 
708  // end tip
709  for (; v != vend; v++) {
710  sv = (*v);
711  svRep = *currentSV;
712  u = 0.75 + sv->curvilinearAbscissa() / spacedThickness * fact - float(tiles) - 0.25;
713 
714  svRep->setTexCoord(Vec2r((real)u, -0.5), true);
715  i++;
716  ++currentSV;
717 
718  svRep = *currentSV;
719  svRep->setTexCoord(Vec2r((real)u, -1), true);
720  i++;
721  ++currentSV;
722  }
723  }
724 
725 #if 0
726  cerr << "u=" << u << " i=" << i << "/" << _sizeStrip << endl;
727 
728  for (i = 0; i < _sizeStrip; i++) {
729  _alpha[i] = 1.0;
730  }
731 
732  for (i = 0; i < _sizeStrip; i++) {
733  cerr << "(" << _texCoord[i][0] << ", " << _texCoord[i][1] << ") ";
734  }
735  cerr << endl;
736 
737  Vec2r vec_tmp;
738  for (i = 0; i < _sizeStrip / 2; i++) {
739  vec_tmp = _vertex[2 * i] - _vertex[2 * i + 1];
740  }
741  if (vec_tmp.norm() > 4 * _averageThickness) {
742  cerr << "Warning (from Fredo): There is a pb in the texture coordinates computation" << endl;
743  }
744 #endif
745 }
746 
747 //
748 // StrokeRep
750 
751 StrokeRep::StrokeRep()
752 {
753  _stroke = nullptr;
754  _strokeType = Stroke::OPAQUE_MEDIUM;
755  _nodeTree = nullptr;
756  _hasTex = false;
757  _textureStep = 1.0;
758  for (int a = 0; a < MAX_MTEX; a++) {
759  _mtex[a] = nullptr;
760  }
761  TextureManager *ptm = TextureManager::getInstance();
762  if (ptm) {
763  _textureId = ptm->getDefaultTextureId();
764  }
765 #if 0
766  _averageTextureAlpha = 0.5; //default value
767  if (_strokeType == OIL_STROKE) {
768  _averageTextureAlpha = 0.75;
769  }
770  if (_strokeType >= NO_BLEND_STROKE) {
771  _averageTextureAlpha = 1.0;
772  }
773 #endif
774 }
775 
776 StrokeRep::StrokeRep(Stroke *iStroke)
777 {
778  _stroke = iStroke;
779  _strokeType = iStroke->getMediumType();
780  _nodeTree = iStroke->getNodeTree();
781  _hasTex = iStroke->hasTex();
782  _textureId = iStroke->getTextureId();
783  _textureStep = iStroke->getTextureStep();
784  for (int a = 0; a < MAX_MTEX; a++) {
785  if (iStroke->getMTex(a)) {
786  _mtex[a] = iStroke->getMTex(a);
787  }
788  else {
789  _mtex[a] = nullptr;
790  }
791  }
792  if (_textureId == 0) {
793  TextureManager *ptm = TextureManager::getInstance();
794  if (ptm) {
795  _textureId = ptm->getDefaultTextureId();
796  }
797  }
798 
799 #if 0
800  _averageTextureAlpha = 0.5; //default value
801  if (_strokeType == OIL_STROKE) {
802  _averageTextureAlpha = 0.75;
803  }
804  if (_strokeType >= NO_BLEND_STROKE) {
805  _averageTextureAlpha = 1.0;
806  }
807 #endif
808  create();
809 }
810 
811 StrokeRep::StrokeRep(const StrokeRep &iBrother)
812 {
813  // soc unused - int i = 0;
814  _stroke = iBrother._stroke;
815  _strokeType = iBrother._strokeType;
816  _textureId = iBrother._textureId;
817  _textureStep = iBrother._textureStep;
818  _nodeTree = iBrother._nodeTree;
819  _hasTex = iBrother._hasTex;
820  for (int a = 0; a < MAX_MTEX; a++) {
821  if (iBrother._mtex[a]) {
822  _mtex[a] = iBrother._mtex[a];
823  }
824  else {
825  _mtex[a] = nullptr;
826  }
827  }
828  for (vector<Strip *>::const_iterator s = iBrother._strips.begin(), send = iBrother._strips.end();
829  s != send;
830  ++s) {
831  _strips.push_back(new Strip(**s));
832  }
833 }
834 
835 StrokeRep::~StrokeRep()
836 {
837  if (!_strips.empty()) {
838  for (vector<Strip *>::iterator s = _strips.begin(), send = _strips.end(); s != send; ++s) {
839  delete (*s);
840  }
841  _strips.clear();
842  }
843 }
844 
845 void StrokeRep::create()
846 {
847  vector<StrokeVertex *> strip;
848  StrokeInternal::StrokeVertexIterator v = _stroke->strokeVerticesBegin();
849  StrokeInternal::StrokeVertexIterator vend = _stroke->strokeVerticesEnd();
850 
851  bool first = true;
852  bool end = false;
853  while (v != vend) {
854  while ((v != vend) && (!(*v).attribute().isVisible())) {
855  ++v;
856  first = false;
857  }
858  while ((v != vend) && ((*v).attribute().isVisible())) {
859  strip.push_back(&(*v));
860  ++v;
861  }
862  if (v != vend) {
863  // add the last vertex and create
864  strip.push_back(&(*v));
865  }
866  else {
867  end = true;
868  }
869  if ((!strip.empty()) && (strip.size() > 1)) {
870  _strips.push_back(new Strip(strip, _hasTex, first, end, _textureStep));
871  strip.clear();
872  }
873  first = false;
874  }
875 }
876 
877 void StrokeRep::Render(const StrokeRenderer *iRenderer)
878 {
879  iRenderer->RenderStrokeRep(this);
880 }
881 
882 } /* namespace Freestyle */
typedef float(TangentPoint)[2]
@ G_DEBUG_FREESTYLE
Definition: BKE_global.h:140
struct Strip Strip
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble t
struct Render Render
Definition: RE_pipeline.h:54
Iterators used to iterate over the elements of the Stroke. Can't be used in python.
Iterators used to iterate over the elements of the Stroke.
Classes to render a stroke with OpenGL.
#define EPS_SINGULARITY_RENDERER
Definition: StrokeRep.cpp:98
#define MAX_RATIO_LENGTH_SINGU
Definition: StrokeRep.cpp:100
#define HUGE_COORD
Definition: StrokeRep.cpp:101
#define ZERO
Definition: StrokeRep.cpp:99
Class to define the representation of a stroke (for display purpose)
Classes to define a stroke.
#define MAX_MTEX
Definition: Stroke.h:45
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
#define A
vertex_container _vertices
Definition: StrokeRep.h:142
float _averageThickness
Definition: StrokeRep.h:143
Vec3f getColorRGB() const
Definition: Stroke.h:133
float getAlpha() const
Definition: Stroke.h:139
const float * getThickness() const
Definition: Stroke.h:148
bool isAttributeAvailableVec2f(const char *iName) const
Definition: Stroke.cpp:289
const float * getColor() const
Definition: Stroke.h:109
Vec2f getAttributeVec2f(const char *iName) const
Definition: Stroke.cpp:239
virtual void RenderStrokeRep(StrokeRep *iStrokeRep) const =0
Stroke::MediumType _strokeType
Definition: StrokeRep.h:184
unsigned int _textureId
Definition: StrokeRep.h:185
vector< Strip * > _strips
Definition: StrokeRep.h:183
MTex * _mtex[MAX_MTEX]
Definition: StrokeRep.h:187
bNodeTree * _nodeTree
Definition: StrokeRep.h:188
void setAlpha(float a)
Definition: StrokeRep.h:120
void setTexCoord(const Vec2r &p, bool tips=false)
Definition: StrokeRep.h:105
void setColor(const Vec3r &p)
Definition: StrokeRep.h:115
float curvilinearAbscissa() const
Definition: Stroke.h:400
Vec2r getPoint() const
Definition: Stroke.h:376
const StrokeAttribute & attribute() const
Definition: Stroke.h:388
bool hasTex() const
Definition: Stroke.h:672
bNodeTree * getNodeTree()
Definition: Stroke.h:666
float getTextureStep()
Definition: Stroke.h:654
MTex * getMTex(int idx)
Definition: Stroke.h:660
MediumType getMediumType() const
Definition: Stroke.h:642
unsigned int getTextureId()
Definition: Stroke.h:648
unsigned int getDefaultTextureId() const
value_type norm() const
Definition: VecMat.h:109
Vec< T, N > & normalize()
Definition: VecMat.h:119
static CCL_NAMESPACE_BEGIN const double alpha
#define B
intersection_test intersect2dLine2dLine(const Vec2r &p1, const Vec2r &p2, const Vec2r &p3, const Vec2r &p4, Vec2r &res)
Definition: GeomUtils.cpp:111
VecMat::Vec2< real > Vec2r
Definition: Geom.h:36
VecMat::Vec3< real > Vec3r
Definition: Geom.h:42
inherits from class Rep
Definition: AppCanvas.cpp:32
static bool notValid(Vec2r p)
Definition: StrokeRep.cpp:103
static unsigned a[3]
Definition: RandGen.cpp:92
double real
Definition: Precision.h:26
ccl_device_inline float2 fabs(const float2 &a)
#define G(x, y, z)