1 // Copyright (C) 2012-2019 The VPaint Developers.
2 // See the COPYRIGHT file at the top-level directory of this distribution
3 // and at https://github.com/dalboris/vpaint/blob/master/COPYRIGHT
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16
17 #include "../XmlStreamReader.h"
18 #include "../XmlStreamWriter.h"
19 #include <QTextStream>
20 #include <QtDebug>
21 #include <QMessageBox>
22 #include <array>
23 #include <vector>
24
25 #include "../SaveAndLoad.h"
26 #include "../Random.h"
27
28 #include "EdgeGeometry.h"
29
30 #include "KeyVertex.h"
31 #include "KeyEdge.h"
32 #include "KeyFace.h"
33 #include "../DevSettings.h"
34 #include "../Global.h"
35
36 #include "../OpenGL.h"
37
38 #if defined(__APPLE__) && defined(__MACH__)
39 # include <OpenGL/glu.h>
40 #else
41 # include <GL/glu.h>
42 #endif
43
44 // ------- Unnamed namespace for non-friend non-member helper functions -------
45
46 namespace
47 {
48
49 using namespace VectorAnimationComplex;
50
51 // Active tesselator
52 GLUtesselator * tobj = 0;
53
54 // Offline tesselator: outputs the triangulation as offlineTessTriangles
55 GLUtesselator * tobjOffline = 0;
56 Triangles offlineTessTriangles;
57 GLenum offlineTessWhich;
58 int offlineTessIter;
59 double offlineTessAX, offlineTessAY;
60 double offlineTessBX, offlineTessBY;
61 double offlineTessCX, offlineTessCY;
62
63 #ifdef _WIN32
64 #define CALLBACK __stdcall
65 #else
66 #define CALLBACK
67 #endif
68
offlineTessBegin(GLenum which)69 void CALLBACK offlineTessBegin(GLenum which)
70 {
71 offlineTessWhich = which;
72 offlineTessIter = 0;
73 }
74
offlineTessEnd(void)75 void CALLBACK offlineTessEnd(void)
76 {
77 }
78
offlineTessError(GLenum errorCode)79 void CALLBACK offlineTessError(GLenum errorCode)
80 {
81 const GLubyte *estring;
82 estring = gluErrorString(errorCode);
83
84 qDebug() << "Tessellation Error:" << estring;
85 }
86
offlineTessVertex(GLvoid * vertex)87 void CALLBACK offlineTessVertex(GLvoid *vertex)
88 {
89 const GLdouble *pointer = (GLdouble *) vertex;
90
91 if(offlineTessWhich == GL_TRIANGLES)
92 {
93 if(offlineTessIter == 0)
94 {
95 offlineTessAX = pointer[0];
96 offlineTessAY = pointer[1];
97 offlineTessIter = 1;
98 }
99 else if(offlineTessIter == 1)
100 {
101 offlineTessBX = pointer[0];
102 offlineTessBY = pointer[1];
103 offlineTessIter = 2;
104 }
105 else
106 {
107 offlineTessCX = pointer[0];
108 offlineTessCY = pointer[1];
109 offlineTessIter = 0;
110
111 offlineTessTriangles.append(offlineTessAX, offlineTessAY,
112 offlineTessBX, offlineTessBY,
113 offlineTessCX, offlineTessCY);
114 }
115 }
116 else if(offlineTessWhich == GL_TRIANGLE_FAN)
117 {
118 if(offlineTessIter == 0)
119 {
120 offlineTessAX = pointer[0];
121 offlineTessAY = pointer[1];
122 offlineTessIter = 1;
123 }
124 else if(offlineTessIter == 1)
125 {
126 offlineTessBX = pointer[0];
127 offlineTessBY = pointer[1];
128 offlineTessIter = 2;
129 }
130 else
131 {
132 offlineTessCX = pointer[0];
133 offlineTessCY = pointer[1];
134
135 offlineTessTriangles.append(offlineTessAX, offlineTessAY,
136 offlineTessBX, offlineTessBY,
137 offlineTessCX, offlineTessCY);
138
139 offlineTessBX = offlineTessCX;
140 offlineTessBY = offlineTessCY;
141 }
142 }
143 else if(offlineTessWhich == GL_TRIANGLE_STRIP)
144 {
145 if(offlineTessIter == 0)
146 {
147 offlineTessAX = pointer[0];
148 offlineTessAY = pointer[1];
149 offlineTessIter = 1;
150 }
151 else if(offlineTessIter == 1)
152 {
153 offlineTessBX = pointer[0];
154 offlineTessBY = pointer[1];
155 offlineTessIter = 2;
156 }
157 else if(offlineTessIter == 2)
158 {
159 offlineTessCX = pointer[0];
160 offlineTessCY = pointer[1];
161
162 offlineTessTriangles.append(offlineTessAX, offlineTessAY,
163 offlineTessBX, offlineTessBY,
164 offlineTessCX, offlineTessCY);
165
166 offlineTessAX = offlineTessCX;
167 offlineTessAY = offlineTessCY;
168 offlineTessIter = 3;
169 }
170 else
171 {
172 offlineTessCX = pointer[0];
173 offlineTessCY = pointer[1];
174
175 offlineTessTriangles.append(offlineTessAX, offlineTessAY,
176 offlineTessBX, offlineTessBY,
177 offlineTessCX, offlineTessCY);
178
179 offlineTessBX = offlineTessCX;
180 offlineTessBY = offlineTessCY;
181 offlineTessIter = 2;
182 }
183 }
184 else if(offlineTessWhich == GL_LINE_LOOP)
185 {
186 }
187 }
188
offlineTessCombine(GLdouble coords[3],GLdouble * [4],GLfloat[4],GLdouble ** dataOut)189 void CALLBACK offlineTessCombine(GLdouble coords[3],
190 GLdouble * /*vertex_data*/ [4],
191 GLfloat /*weight*/ [4], GLdouble **dataOut )
192 {
193 GLdouble * vertex = (GLdouble *) malloc(6 * sizeof(GLdouble));
194 vertex[0] = coords[0];
195 vertex[1] = coords[1];
196 vertex[2] = coords[2];
197
198 *dataOut = vertex;
199 }
200
201 typedef std::vector< std::vector< std::array<GLdouble, 3> > > PolygonData;
202
createPolygonData(const QList<Cycle> & cycles)203 PolygonData createPolygonData(const QList<Cycle> & cycles)
204 {
205 PolygonData vertices;
206 for(int k=0; k<cycles.size(); ++k) // for each cycle
207 {
208 vertices << std::vector< std::array<GLdouble, 3> >(); // create a contour data
209
210 for(int i=0; i<cycles[k].size(); ++i) // for each edge in the cycle
211 {
212 QList<Eigen::Vector2d> & sampling = cycles[k][i].edge->geometry()->sampling();
213 if(cycles[k][i].side)
214 {
215 int last = sampling.size()-1;
216 if(i+1<cycles[k].size())
217 {
218 // if there is a following edge, then don't insert last vertex
219 // otherwise it will be duplicated
220 last--;
221 }
222 for(int j=0; j<=last; ++j)
223 {
224 std::array<GLdouble, 3> a = {sampling[j][0], sampling[j][1], 0};
225 vertices.back().emplace_back(a);
226 }
227 }
228 else
229 {
230 int first = 0;
231 if(i+1<cycles[k].size())
232 {
233 // if there is a following edge, then don't insert last vertex
234 // otherwise it will be duplicated
235 first++;
236 }
237 for(int j=sampling.size()-1; j>=first; --j)
238 {
239 std::array<GLdouble, 3> a = {sampling[j][0], sampling[j][1], 0};
240 vertices.back().emplace_back(a);
241 }
242 }
243 }
244 }
245
246 return vertices;
247 }
248
computeTrianglesFromCycles(const QList<Cycle> & cycles,Triangles & triangles)249 void computeTrianglesFromCycles(const QList<Cycle> & cycles, Triangles & triangles)
250 {
251
252 // Creating polygon data for GLU tesselator
253 PolygonData vertices = createPolygonData(cycles);
254
255 // Creating the GLU tesselation object
256 if(!tobjOffline)
257 {
258 tobjOffline = gluNewTess();
259 }
260 if(tobj != tobjOffline)
261 {
262 tobj = tobjOffline;
263
264 gluTessCallback(tobj, GLU_TESS_VERTEX,
265 (GLvoid (CALLBACK*) ()) &offlineTessVertex);
266 gluTessCallback(tobj, GLU_TESS_BEGIN,
267 (GLvoid (CALLBACK*) ()) &offlineTessBegin);
268 gluTessCallback(tobj, GLU_TESS_END,
269 (GLvoid (CALLBACK*) ()) &offlineTessEnd);
270 gluTessCallback(tobj, GLU_TESS_ERROR,
271 (GLvoid (CALLBACK*) ()) &offlineTessError);
272 gluTessCallback(tobj, GLU_TESS_COMBINE,
273 (GLvoid (CALLBACK*) ()) &offlineTessCombine);
274 }
275
276 // Using the tesselation object
277 gluTessProperty(tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD);
278
279 // Specifying data
280 offlineTessTriangles.clear();
281 gluTessBeginPolygon(tobj, NULL);
282 {
283 for(auto & vec: vertices) // for each cycle
284 {
285 gluTessBeginContour(tobj); // draw a contour
286 {
287 for(auto & v: vec) // for each vertex in cycle
288 {
289 // safeguard against NaN and other oddities
290 const double MAX_VALUE = 10000;
291 const double MIN_VALUE = -10000;
292 if( v[0] > MIN_VALUE &&
293 v[0] < MAX_VALUE &&
294 v[1] > MIN_VALUE &&
295 v[1] < MAX_VALUE &&
296 v[2] > MIN_VALUE &&
297 v[2] < MAX_VALUE )
298 {
299 gluTessVertex(tobj, v.data(), v.data()); // send vertex
300 }
301 else
302 {
303 qDebug() << "ignored vertex" << v[0] << v[1] << v[2] << "for tesselation";
304 }
305 }
306 }
307 gluTessEndContour(tobj);
308 }
309 }
310 gluTessEndPolygon(tobj);
311
312 // Tranfer to member data
313 triangles = offlineTessTriangles;
314 }
315
316 }
317
318
319 namespace VectorAnimationComplex
320 {
321
322 // ------------------------------- Key Face -------------------------------
323
KeyFace(VAC * vac,const Time & t)324 KeyFace::KeyFace(VAC * vac, const Time & t) :
325 Cell(vac),
326 KeyCell(vac, t),
327 FaceCell(vac)
328 {
329 initColor_();
330 }
331
KeyFace(VAC * vac,const Cycle & cycle)332 KeyFace::KeyFace(VAC * vac, const Cycle & cycle) :
333 Cell(vac),
334 KeyCell(vac, cycle.time()),
335 FaceCell(vac)
336 {
337 addCycle(cycle);
338 initColor_();
339 }
340
KeyFace(VAC * vac,const QList<Cycle> & cycles)341 KeyFace::KeyFace(VAC * vac, const QList<Cycle> & cycles) :
342 Cell(vac),
343 KeyCell(vac, cycles[0].time()),
344 FaceCell(vac)
345 {
346 addCycles(cycles);
347 initColor_();
348 }
349
initColor_()350 void KeyFace::initColor_()
351 {
352 // Random color
353 /*
354 // using hsv to rgb
355 double H = Random::random(60./60.,200./60.);
356 double S = 0.2;
357 double V = 1;
358
359 double C = V*S;
360 double X = C * ( 1 - std::abs(std::fmod(H,2)-1) );
361 double R1, G1, B1;
362 if(H<1) { R1=C; G1=X; B1=0;}
363 else if(H<2) { R1=X; G1=C; B1=0;}
364 else if(H<3) { R1=0; G1=C; B1=X;}
365 else if(H<4) { R1=0; G1=X; B1=C;}
366 else if(H<5) { R1=X; G1=0; B1=C;}
367 else { R1=C; G1=0; B1=X;}
368 double m = V - C;
369 color_[0] = R1+m;
370 color_[1] = G1+m;
371 color_[2] = B1+m;
372 color_[3] = 1;
373 */
374
375 // Color from GUI
376 setColor(global()->faceColor());
377 }
378
clearCycles_()379 void KeyFace::clearCycles_()
380 {
381 foreach(Cell * cell, spatialBoundary())
382 removeMeFromSpatialStarOf_(cell);
383
384 cycles_.clear();
385 processGeometryChanged_();
386 }
387
setCycles(const QList<Cycle> & cycles)388 void KeyFace::setCycles(const QList<Cycle> & cycles)
389 {
390 clearCycles_();
391 addCycles(cycles);
392 }
393
addCycles(const QList<Cycle> & cycles)394 void KeyFace::addCycles(const QList<Cycle> & cycles)
395 {
396 for(int i=0; i<cycles.size(); ++i)
397 addCycle(cycles[i]);
398 }
399
addCycle(const Cycle & cycle)400 void KeyFace::addCycle(const Cycle & cycle)
401 {
402 cycles_ << cycle;
403 foreach(KeyCell * cell, cycle.cells())
404 addMeToSpatialStarOf_(cell);
405 processGeometryChanged_();
406 }
407
triangulate_(Time time,Triangles & out) const408 void KeyFace::triangulate_(Time time, Triangles & out) const
409 {
410 out.clear();
411 if (exists(time))
412 computeTrianglesFromCycles(cycles_, out);
413 }
414
getSampling(Time) const415 QList<QList<Eigen::Vector2d> > KeyFace::getSampling(Time /*time*/) const
416 {
417 QList<QList<Eigen::Vector2d> > res;
418 PolygonData data = createPolygonData(cycles_);
419
420 for(unsigned int k=0; k<data.size(); ++k) // for each cycle
421 {
422 res << QList<Eigen::Vector2d>();
423 for(unsigned int i=0; i<data[k].size(); ++i) // for each edge in the cycle
424 {
425 res[k] << Eigen::Vector2d(data[k][i][0], data[k][i][1]);
426 }
427 }
428
429 return res;
430 }
431
xmlType_() const432 QString KeyFace::xmlType_() const
433 {
434 return "face";
435 }
436
write_(XmlStreamWriter & xml) const437 void KeyFace::write_(XmlStreamWriter & xml) const
438 {
439 // Base classes
440 Cell::write_(xml);
441 KeyCell::write_(xml);
442 FaceCell::write_(xml);
443
444 // Cycles
445 QString cyclesstring;
446 for(int i=0; i<cycles_.size(); ++i)
447 {
448 if(i>0)
449 cyclesstring += " ";
450 cyclesstring += cycles_[i].toString();
451 }
452 xml.writeAttribute("cycles", cyclesstring);
453 }
454
KeyFace(VAC * vac,XmlStreamReader & xml)455 KeyFace::KeyFace(VAC * vac, XmlStreamReader & xml) :
456 Cell(vac, xml),
457 KeyCell(vac, xml),
458 FaceCell(vac, xml)
459 {
460 // Cycles
461 QString str;
462 QStringRef d = xml.attributes().value("cycles");
463 bool opened = false;
464 for(int i=0; i<d.length(); ++i)
465 {
466 QChar c = d.at(i);
467 if(c == '[')
468 opened = true;
469 if(opened)
470 str += c;
471 if(c==']')
472 {
473 cycles_ << Cycle();
474 cycles_.last().fromString(str);
475 opened = false;
476 str.clear();
477 }
478 }
479 }
480
save_(QTextStream & out)481 void KeyFace::save_(QTextStream & out)
482 {
483 // Base classes
484 Cell::save_(out);
485 KeyCell::save_(out);
486 FaceCell::save_(out);
487
488 // Cycles
489 out << Save::newField("Cycles") << cycles_;
490 }
491
KeyFace(VAC * vac,QTextStream & in)492 KeyFace::KeyFace(VAC * vac, QTextStream & in) :
493 Cell(vac, in),
494 KeyCell(vac, in),
495 FaceCell(vac, in)
496 {
497 Field field;
498
499 // Cycles
500 in >> /*field >>*/ cycles_; // Reason of comment: see Cell::Cell(VAC * vac, QTextStream & in)
501 }
502
read2ndPass()503 void KeyFace::read2ndPass()
504 {
505 // Base classes
506 Cell::read2ndPass();
507 KeyCell::read2ndPass();
508 FaceCell::read2ndPass();
509
510 // Cycles
511 for(int i=0; i<cycles_.size(); ++i)
512 cycles_[i].convertTempIdsToPointers(vac());
513 }
514
~KeyFace()515 KeyFace::~KeyFace()
516 {
517 }
518
spatialBoundary() const519 CellSet KeyFace::spatialBoundary() const
520 {
521 CellSet res;
522
523 for(int i=0; i<cycles_.size(); ++i)
524 {
525 CellSet cells = cycles_[i].cells();
526 res.unite(cells);
527 }
528
529 return res;
530 }
531
updateBoundary_impl(KeyEdge * oldEdge,const KeyEdgeList & newEdges)532 void KeyFace::updateBoundary_impl(KeyEdge * oldEdge, const KeyEdgeList & newEdges)
533 {
534 for(int i=0; i<cycles_.size(); ++i)
535 cycles_[i].replaceEdges(oldEdge, newEdges);
536 }
537
538 // Update boundary
updateBoundary_impl(KeyVertex * oldVertex,KeyVertex * newVertex)539 void KeyFace::updateBoundary_impl(KeyVertex * oldVertex, KeyVertex * newVertex)
540 {
541 for(int i=0; i<cycles_.size(); ++i)
542 cycles_[i].replaceVertex(oldVertex, newVertex);
543 }
544
updateBoundary_impl(const KeyHalfedge & oldHalfedge,const KeyHalfedge & newHalfedge)545 void KeyFace::updateBoundary_impl(const KeyHalfedge & oldHalfedge, const KeyHalfedge & newHalfedge)
546 {
547 for(int i=0; i<cycles_.size(); ++i)
548 cycles_[i].replaceHalfedge(oldHalfedge, newHalfedge);
549 }
550
clone()551 KeyFace * KeyFace::clone()
552 {
553 return new KeyFace(this);
554 }
555
remapPointers(VAC * newVAC)556 void KeyFace::remapPointers(VAC * newVAC)
557 {
558 Cell::remapPointers(newVAC);
559 KeyCell::remapPointers(newVAC);
560 FaceCell::remapPointers(newVAC);
561
562 for(int i=0; i<cycles_.size(); ++i)
563 cycles_[i].remapPointers(newVAC);
564 }
565
KeyFace(KeyFace * other)566 KeyFace::KeyFace(KeyFace * other) :
567 Cell(other),
568 KeyCell(other),
569 FaceCell(other)
570 {
571 cycles_ = other->cycles_;
572 }
573
check_() const574 bool KeyFace::check_() const
575 {
576 // todo
577 return true;
578 }
579
580 // --------------------------- Preview Key Face ---------------------------
581
582
PreviewKeyFace()583 PreviewKeyFace::PreviewKeyFace() :
584 cycles_()
585 {
586 }
587
PreviewKeyFace(const Cycle & cycle)588 PreviewKeyFace::PreviewKeyFace(const Cycle & cycle) :
589 cycles_()
590 {
591 cycles_ << cycle;
592 computeTriangles_();
593 }
594
PreviewKeyFace(const QList<Cycle> & cycles)595 PreviewKeyFace::PreviewKeyFace(const QList<Cycle> & cycles) :
596 cycles_(cycles)
597 {
598 }
599
clear()600 void PreviewKeyFace::clear()
601 {
602 cycles_.clear();
603 triangles_.clear();
604 }
605
operator <<(const Cycle & cycle)606 PreviewKeyFace & PreviewKeyFace::operator<< (const Cycle & cycle)
607 {
608 cycles_ << cycle;
609 computeTriangles_();
610 return *this;
611 }
612
computeTriangles_()613 void PreviewKeyFace::computeTriangles_()
614 {
615 computeTrianglesFromCycles(cycles_,triangles_);
616 }
617
intersects(double x,double y) const618 bool PreviewKeyFace::intersects(double x, double y) const
619 {
620 return triangles_.intersects(Eigen::Vector2d(x,y));
621 }
622
draw(ViewSettings &)623 void PreviewKeyFace::draw(ViewSettings & /*viewSettings*/)
624 {
625 // Setting the color
626 glColor4d(0.9,0.9,0.9,0.8);
627
628 // Drawing
629 triangles_.draw();
630 }
631
632 }
633