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