1 
2 
3 // TnzCore includes
4 #include "tgl.h"
5 
6 // TnzExt includes
7 #include "ext/ttexturesstorage.h"
8 #include "ext/plasticdeformerstorage.h"
9 
10 // tcg includes
11 #include "tcg/tcg_iterator_ops.h"
12 
13 #include "ext/meshutils.h"
14 
15 //********************************************************************************************
16 //    Templated drawing functions
17 //********************************************************************************************
18 
19 namespace {
20 
21 struct NoColorFunction {
faceColor__anond10e7e000111::NoColorFunction22   void faceColor(int f, int m) {}
edgeColor__anond10e7e000111::NoColorFunction23   void edgeColor(int e, int m) {}
vertexColor__anond10e7e000111::NoColorFunction24   void vertexColor(int v, int m) {}
25 };
26 
27 //-------------------------------------------------------------------------------
28 
29 template <typename VerticesContainer, typename PointType,
30           typename ColorFunction>
tglDrawEdges(const TTextureMesh & mesh,const VerticesContainer & vertices,ColorFunction colorFunction)31 inline void tglDrawEdges(const TTextureMesh &mesh,
32                          const VerticesContainer &vertices,
33                          ColorFunction colorFunction) {
34   // Draw the mesh wireframe
35   glBegin(GL_LINES);
36 
37   TTextureMesh::edges_container::const_iterator et, eEnd = mesh.edges().end();
38 
39   for (et = mesh.edges().begin(); et != eEnd; ++et) {
40     const TTextureMesh::edge_type &ed = *et;
41 
42     int v0 = ed.vertex(0), v1 = ed.vertex(1);
43 
44     const PointType &p0 = vertices[v0];
45     const PointType &p1 = vertices[v1];
46 
47     colorFunction.edgeColor(et.index(), -1);
48 
49     colorFunction.vertexColor(v0, -1);
50     glVertex2d(tcg::point_traits<PointType>::x(p0),
51                tcg::point_traits<PointType>::y(p0));
52 
53     colorFunction.vertexColor(v1, -1);
54     glVertex2d(tcg::point_traits<PointType>::x(p1),
55                tcg::point_traits<PointType>::y(p1));
56   }
57 
58   glEnd();
59 }
60 
61 //-------------------------------------------------------------------------------
62 
63 template <typename ColorFunction>
tglDrawFaces(const TMeshImage & meshImage,ColorFunction colorFunction)64 inline void tglDrawFaces(const TMeshImage &meshImage,
65                          ColorFunction colorFunction) {
66   glBegin(GL_TRIANGLES);
67 
68   int m, mCount = meshImage.meshes().size();
69   for (m = 0; m != mCount; ++m) {
70     const TTextureMesh &mesh                  = *meshImage.meshes()[m];
71     const tcg::list<TTextureVertex> &vertices = mesh.vertices();
72 
73     // Draw the mesh wireframe
74     TTextureMesh::faces_container::const_iterator ft, fEnd = mesh.faces().end();
75 
76     for (ft = mesh.faces().begin(); ft != fEnd; ++ft) {
77       int v0, v1, v2;
78       mesh.faceVertices(ft.index(), v0, v1, v2);
79 
80       const TTextureVertex &p0 = vertices[v0];
81       const TTextureVertex &p1 = vertices[v1];
82       const TTextureVertex &p2 = vertices[v2];
83 
84       colorFunction.faceColor(ft.index(), m);
85 
86       colorFunction.vertexColor(v0, m), glVertex2d(p0.P().x, p0.P().y);
87       colorFunction.vertexColor(v1, m), glVertex2d(p1.P().x, p1.P().y);
88       colorFunction.vertexColor(v2, m), glVertex2d(p2.P().x, p2.P().y);
89     }
90   }
91 
92   glEnd();
93 }
94 
95 //-------------------------------------------------------------------------------
96 
97 template <typename ColorFunction>
tglDrawFaces(const TMeshImage & meshImage,const PlasticDeformerDataGroup * group,ColorFunction colorFunction)98 inline void tglDrawFaces(const TMeshImage &meshImage,
99                          const PlasticDeformerDataGroup *group,
100                          ColorFunction colorFunction) {
101   glBegin(GL_TRIANGLES);
102 
103   // Draw faces according to the group's sorted faces list
104   typedef std::vector<std::pair<int, int>> SortedFacesVector;
105 
106   const SortedFacesVector &sortedFaces     = group->m_sortedFaces;
107   const std::vector<TTextureMeshP> &meshes = meshImage.meshes();
108 
109   int m = -1;
110   const TTextureMesh *mesh;
111   const double *dstCoords;
112 
113   int v0, v1, v2;
114 
115   // Draw each face individually. Change tile and mesh data only if they change
116   SortedFacesVector::const_iterator sft, sfEnd(sortedFaces.end());
117   for (sft = sortedFaces.begin(); sft != sfEnd; ++sft) {
118     int f = sft->first, m_ = sft->second;
119 
120     if (m != m_) {
121       m = m_;
122 
123       mesh      = meshes[m].getPointer();
124       dstCoords = group->m_datas[m].m_output.get();
125     }
126 
127     mesh->faceVertices(f, v0, v1, v2);
128 
129     const double *d0 = dstCoords + (v0 << 1), *d1 = dstCoords + (v1 << 1),
130                  *d2 = dstCoords + (v2 << 1);
131 
132     colorFunction.faceColor(f, m);
133 
134     colorFunction.vertexColor(v0, m), glVertex2d(*d0, *(d0 + 1));
135     colorFunction.vertexColor(v1, m), glVertex2d(*d1, *(d1 + 1));
136     colorFunction.vertexColor(v2, m), glVertex2d(*d2, *(d2 + 1));
137   }
138 
139   glEnd();
140 }
141 
142 }  // namespace
143 
144 //********************************************************************************************
145 //    Mesh Image Utility  functions implementation
146 //********************************************************************************************
147 
transform(const TMeshImageP & meshImage,const TAffine & aff)148 void transform(const TMeshImageP &meshImage, const TAffine &aff) {
149   const std::vector<TTextureMeshP> &meshes = meshImage->meshes();
150 
151   int m, mCount = meshes.size();
152   for (m = 0; m != mCount; ++m) {
153     TTextureMesh &mesh = *meshes[m];
154 
155     tcg::list<TTextureMesh::vertex_type> &vertices = mesh.vertices();
156 
157     tcg::list<TTextureMesh::vertex_type>::iterator vt, vEnd(vertices.end());
158     for (vt = vertices.begin(); vt != vEnd; ++vt) vt->P() = aff * vt->P();
159   }
160 }
161 
162 //-------------------------------------------------------------------------------
163 
tglDrawEdges(const TMeshImage & mi,const PlasticDeformerDataGroup * group)164 void tglDrawEdges(const TMeshImage &mi, const PlasticDeformerDataGroup *group) {
165   const std::vector<TTextureMeshP> &meshes = mi.meshes();
166 
167   int m, mCount = meshes.size();
168   if (group) {
169     for (m = 0; m != mCount; ++m)
170       tglDrawEdges<const TPointD *, TPointD, NoColorFunction>(
171           *meshes[m], (const TPointD *)group->m_datas[m].m_output.get(),
172           NoColorFunction());
173   } else {
174     for (m = 0; m != mCount; ++m) {
175       const TTextureMesh &mesh = *meshes[m];
176 
177       tglDrawEdges<tcg::list<TTextureMesh::vertex_type>, TTextureVertex,
178                    NoColorFunction>(mesh, mesh.vertices(), NoColorFunction());
179     }
180   }
181 }
182 
183 //-------------------------------------------------------------------------------
184 
tglDrawFaces(const TMeshImage & image,const PlasticDeformerDataGroup * group)185 void tglDrawFaces(const TMeshImage &image,
186                   const PlasticDeformerDataGroup *group) {
187   if (group)
188     tglDrawFaces(image, group, NoColorFunction());
189   else
190     tglDrawFaces(image, NoColorFunction());
191 }
192 
193 //********************************************************************************************
194 //    Colored drawing functions
195 //********************************************************************************************
196 
197 namespace {
198 
199 struct LinearColorFunction {
200   typedef double (*ValueFunc)(const LinearColorFunction *cf, int m,
201                               int primitive);
202 
203 public:
204   const TMeshImage &m_meshImg;
205   const PlasticDeformerDataGroup *m_group;
206 
207   double m_min, m_max;
208   double *m_cMin, *m_cMax;
209 
210   double m_dt;
211   bool m_degenerate;
212 
213   ValueFunc m_func;
214 
215 public:
LinearColorFunction__anond10e7e000211::LinearColorFunction216   LinearColorFunction(const TMeshImage &meshImg,
217                       const PlasticDeformerDataGroup *group, double min,
218                       double max, double *cMin, double *cMax, ValueFunc func)
219       : m_meshImg(meshImg)
220       , m_group(group)
221       , m_min(min)
222       , m_max(max)
223       , m_cMin(cMin)
224       , m_cMax(cMax)
225       , m_dt(max - min)
226       , m_degenerate(m_dt < 1e-4)
227       , m_func(func) {}
228 
operator ()__anond10e7e000211::LinearColorFunction229   void operator()(int primitive, int m) {
230     if (m_degenerate) {
231       glColor4d(0.5 * (m_cMin[0] + m_cMax[0]), 0.5 * (m_cMin[1] + m_cMax[1]),
232                 0.5 * (m_cMin[2] + m_cMax[2]), 0.5 * (m_cMin[3] + m_cMax[3]));
233       return;
234     }
235 
236     double val = m_func(this, m, primitive);
237     double t = (val - m_min) / m_dt, one_t = (m_max - val) / m_dt;
238 
239     glColor4d(
240         one_t * m_cMin[0] + t * m_cMax[0], one_t * m_cMin[1] + t * m_cMax[1],
241         one_t * m_cMin[2] + t * m_cMax[2], one_t * m_cMin[3] + t * m_cMax[3]);
242   }
243 };
244 
245 //-------------------------------------------------------------------------------
246 
247 struct LinearVertexColorFunction final : public LinearColorFunction,
248                                          public NoColorFunction {
LinearVertexColorFunction__anond10e7e000211::LinearVertexColorFunction249   LinearVertexColorFunction(const TMeshImage &meshImg,
250                             const PlasticDeformerDataGroup *group, double min,
251                             double max, double *cMin, double *cMax,
252                             ValueFunc func)
253       : LinearColorFunction(meshImg, group, min, max, cMin, cMax, func) {}
254 
vertexColor__anond10e7e000211::LinearVertexColorFunction255   void vertexColor(int v, int m) { operator()(v, m); }
256 };
257 
258 //-------------------------------------------------------------------------------
259 
260 struct LinearFaceColorFunction final : public LinearColorFunction,
261                                        public NoColorFunction {
LinearFaceColorFunction__anond10e7e000211::LinearFaceColorFunction262   LinearFaceColorFunction(const TMeshImage &meshImg,
263                           const PlasticDeformerDataGroup *group, double min,
264                           double max, double *cMin, double *cMax,
265                           ValueFunc func)
266       : LinearColorFunction(meshImg, group, min, max, cMin, cMax, func) {}
267 
faceColor__anond10e7e000211::LinearFaceColorFunction268   void faceColor(int v, int m) { operator()(v, m); }
269 };
270 
271 }  // namespace
272 
273 //===============================================================================
274 
tglDrawSO(const TMeshImage & image,double minColor[4],double maxColor[4],const PlasticDeformerDataGroup * group,bool deformedDomain)275 void tglDrawSO(const TMeshImage &image, double minColor[4], double maxColor[4],
276                const PlasticDeformerDataGroup *group, bool deformedDomain) {
277   struct locals {
278     static double returnSO(const LinearColorFunction *cf, int m, int f) {
279       return cf->m_group->m_datas[m].m_so[f];
280     }
281   };
282 
283   double min = 0.0, max = 0.0;
284   if (group) min = group->m_soMin, max = group->m_soMax;
285 
286   LinearFaceColorFunction colorFunction(image, group, min, max, minColor,
287                                         maxColor, locals::returnSO);
288 
289   if (group && deformedDomain)
290     tglDrawFaces(image, group, colorFunction);
291   else
292     tglDrawFaces(image, colorFunction);
293 }
294 
295 //-------------------------------------------------------------------------------
296 
tglDrawRigidity(const TMeshImage & image,double minColor[4],double maxColor[4],const PlasticDeformerDataGroup * group,bool deformedDomain)297 void tglDrawRigidity(const TMeshImage &image, double minColor[4],
298                      double maxColor[4], const PlasticDeformerDataGroup *group,
299                      bool deformedDomain) {
300   struct locals {
301     static double returnRigidity(const LinearColorFunction *cf, int m, int v) {
302       return cf->m_meshImg.meshes()[m]->vertex(v).P().rigidity;
303     }
304   };
305 
306   LinearVertexColorFunction colorFunction(image, group, 1.0, 1e4, minColor,
307                                           maxColor, locals::returnRigidity);
308 
309   if (group && deformedDomain)
310     tglDrawFaces(image, group, colorFunction);
311   else
312     tglDrawFaces(image, colorFunction);
313 }
314 
315 //***********************************************************************************************
316 //    Texturized drawing  implementation
317 //***********************************************************************************************
318 
tglDraw(const TMeshImage & meshImage,const DrawableTextureData & texData,const TAffine & meshToTexAff,const PlasticDeformerDataGroup & group)319 void tglDraw(const TMeshImage &meshImage, const DrawableTextureData &texData,
320              const TAffine &meshToTexAff,
321              const PlasticDeformerDataGroup &group) {
322   typedef MeshTexturizer::TextureData::TileData TileData;
323 
324   // Prepare OpenGL
325   glPushAttrib(GL_COLOR_BUFFER_BIT | GL_LINE_BIT |
326                GL_HINT_BIT);  // Preserve original status bits
327 
328   glEnable(GL_BLEND);
329   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
330   glEnable(GL_LINE_SMOOTH);
331   glLineWidth(1.0f);
332 
333   glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
334 
335   // Prepare variables
336   const std::vector<TTextureMeshP> &meshes = meshImage.meshes();
337   const TTextureMesh *mesh;
338 
339   typedef std::vector<std::pair<int, int>> SortedFacesVector;
340   const SortedFacesVector &sortedFaces = group.m_sortedFaces;
341 
342   const MeshTexturizer::TextureData *td = texData.m_textureData;
343   int t, tCount = td->m_tileDatas.size();
344 
345   GLuint texId = -1;
346   int m        = -1;
347   const double *dstCoords;
348 
349   int v0, v1, v2;
350   int e1ovi, e2ovi;  // Edge X's Other Vertex Index (see below)
351 
352   // Prepare each tile's affine
353   std::vector<TAffine> tileAff(tCount);
354   for (t = 0; t != tCount; ++t) {
355     const TileData &tileData = td->m_tileDatas[t];
356     const TRectD &tileRect   = tileData.m_tileGeometry;
357 
358     tileAff[t] = TScale(1.0 / (tileRect.x1 - tileRect.x0),
359                         1.0 / (tileRect.y1 - tileRect.y0)) *
360                  TTranslation(-tileRect.x0, -tileRect.y0) * meshToTexAff;
361   }
362 
363   // Draw each face individually, according to the group's sorted faces list.
364   // Change tile and mesh data only if they change - improves performance
365 
366   SortedFacesVector::const_iterator sft, sfEnd(sortedFaces.end());
367   for (sft = sortedFaces.begin(); sft != sfEnd; ++sft) {
368     int f = sft->first, m_ = sft->second;
369 
370     if (m != m_) {
371       // Change mesh if different from current
372       m = m_;
373 
374       mesh      = meshes[m].getPointer();
375       dstCoords = group.m_datas[m].m_output.get();
376     }
377 
378     // Draw each face
379     const TTextureMesh::face_type &fc = mesh->face(f);
380 
381     const TTextureMesh::edge_type &ed0 = mesh->edge(fc.edge(0)),
382                                   &ed1 = mesh->edge(fc.edge(1)),
383                                   &ed2 = mesh->edge(fc.edge(2));
384 
385     {
386       v0 = ed0.vertex(0);
387       v1 = ed0.vertex(1);
388       v2 = ed1.vertex((ed1.vertex(0) == v0) | (ed1.vertex(0) == v1));
389 
390       e1ovi = (ed1.vertex(0) == v1) |
391               (ed1.vertex(1) == v1);  // ed1 and ed2 will refer to vertexes
392       e2ovi = 1 - e1ovi;              // with index 2 and these.
393     }
394 
395     const TPointD &p0 = mesh->vertex(v0).P(), &p1 = mesh->vertex(v1).P(),
396                   &p2 = mesh->vertex(v2).P();
397 
398     for (t = 0; t != tCount; ++t) {
399       // Draw face against tile
400       const TileData &tileData = td->m_tileDatas[t];
401 
402       // Map each face vertex to tile coordinates
403       TPointD s[3] = {tileAff[t] * p0, tileAff[t] * p1, tileAff[t] * p2};
404 
405       // Test the face bbox - tile intersection
406       if (std::min({s[0].x, s[1].x, s[2].x}) > 1.0 ||
407           std::min({s[0].y, s[1].y, s[2].y}) > 1.0 ||
408           std::max({s[0].x, s[1].x, s[2].x}) < 0.0 ||
409           std::max({s[0].y, s[1].y, s[2].y}) < 0.0)
410         continue;
411 
412       // If the tile has changed, interrupt the glBegin/glEnd block and bind the
413       // OpenGL texture corresponding to the new tile
414       if (tileData.m_textureId != texId) {
415         texId = tileData.m_textureId;
416 
417         glBindTexture(
418             GL_TEXTURE_2D,
419             tileData
420                 .m_textureId);  // This must be OUTSIDE a glBegin/glEnd block
421       }
422 
423       const double *d[3] = {dstCoords + (v0 << 1), dstCoords + (v1 << 1),
424                             dstCoords + (v2 << 1)};
425 
426       /*
427 Now, draw primitives. A note about pixel arithmetic, here.
428 
429 Since line antialiasing in OpenGL just manipulates output fragments' alpha
430 components,
431 we must require that the input texture is NONPREMULTIPLIED.
432 
433 Furthermore, this function does not rely on the assumption that the output alpha
434 component
435 is discarded (as it happens when drawing on screen). This means that just using
436 a simple
437 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) is not an option, since this
438 way THE INPUT
439 SRC ALPHA GETS MULTIPLIED BY ITSELF - see glBlendFunc's docs - and that shows.
440 
441 The solution is to separate the rendering of RGB and M components - the formers
442 use
443 GL_SRC_ALPHA, while the latter uses GL_ONE. The result is a PREMULTIPLIED image.
444 */
445 
446       // First, draw antialiased face edges on the mesh border.
447       bool drawEd0 = (ed0.facesCount() < 2), drawEd1 = (ed1.facesCount() < 2),
448            drawEd2 = (ed2.facesCount() < 2);
449 
450       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
451       glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
452 
453       glBegin(GL_LINES);
454       {
455         if (drawEd0) {
456           glTexCoord2d(s[0].x, s[0].y), glVertex2d(*d[0], *(d[0] + 1));
457           glTexCoord2d(s[1].x, s[1].y), glVertex2d(*d[1], *(d[1] + 1));
458         }
459 
460         if (drawEd1) {
461           glTexCoord2d(s[e1ovi].x, s[e1ovi].y),
462               glVertex2d(*d[e1ovi], *(d[e1ovi] + 1));
463           glTexCoord2d(s[2].x, s[2].y), glVertex2d(*d[2], *(d[2] + 1));
464         }
465 
466         if (drawEd2) {
467           glTexCoord2d(s[e2ovi].x, s[e2ovi].y),
468               glVertex2d(*d[e2ovi], *(d[e2ovi] + 1));
469           glTexCoord2d(s[2].x, s[2].y), glVertex2d(*d[2], *(d[2] + 1));
470         }
471       }
472       glEnd();
473 
474       glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
475       glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
476 
477       glBegin(GL_LINES);
478       {
479         if (drawEd0) {
480           glTexCoord2d(s[0].x, s[0].y), glVertex2d(*d[0], *(d[0] + 1));
481           glTexCoord2d(s[1].x, s[1].y), glVertex2d(*d[1], *(d[1] + 1));
482         }
483 
484         if (drawEd1) {
485           glTexCoord2d(s[e1ovi].x, s[e1ovi].y),
486               glVertex2d(*d[e1ovi], *(d[e1ovi] + 1));
487           glTexCoord2d(s[2].x, s[2].y), glVertex2d(*d[2], *(d[2] + 1));
488         }
489 
490         if (drawEd2) {
491           glTexCoord2d(s[e2ovi].x, s[e2ovi].y),
492               glVertex2d(*d[e2ovi], *(d[e2ovi] + 1));
493           glTexCoord2d(s[2].x, s[2].y), glVertex2d(*d[2], *(d[2] + 1));
494         }
495       }
496       glEnd();
497 
498       // Finally, draw the face
499       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
500       glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
501 
502       glBegin(GL_TRIANGLES);
503       {
504         glTexCoord2d(s[0].x, s[0].y), glVertex2d(*d[0], *(d[0] + 1));
505         glTexCoord2d(s[1].x, s[1].y), glVertex2d(*d[1], *(d[1] + 1));
506         glTexCoord2d(s[2].x, s[2].y), glVertex2d(*d[2], *(d[2] + 1));
507       }
508       glEnd();
509 
510       glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
511       glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
512 
513       glBegin(GL_TRIANGLES);
514       {
515         glTexCoord2d(s[0].x, s[0].y), glVertex2d(*d[0], *(d[0] + 1));
516         glTexCoord2d(s[1].x, s[1].y), glVertex2d(*d[1], *(d[1] + 1));
517         glTexCoord2d(s[2].x, s[2].y), glVertex2d(*d[2], *(d[2] + 1));
518       }
519       glEnd();
520     }
521   }
522 
523   glBindTexture(GL_TEXTURE_2D, 0);  // Unbind texture
524 
525   glPopAttrib();
526 }
527