GCC Code Coverage Report


Directory: ./
File: lib/geogram_gfx/mesh/mesh_gfx.h
Date: 2026-09-07 02:28:19
Exec Total Coverage
Lines: 0 161 0.0%
Functions: 0 8 0.0%
Branches: 0 140 0.0%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2000-2022 Inria
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * * Neither the name of the ALICE Project-Team nor the names of its
14 * contributors may be used to endorse or promote products derived from this
15 * software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 *
29 * Contact: Bruno Levy
30 *
31 * https://www.inria.fr/fr/bruno-levy
32 *
33 * Inria,
34 * Domaine de Voluceau,
35 * 78150 Le Chesnay - Rocquencourt
36 * FRANCE
37 *
38 */
39
40 #ifndef GEOGRAM_GFX_MESH_GFX
41 #define GEOGRAM_GFX_MESH_GFX
42
43 #include <geogram_gfx/basic/common.h>
44 #include <geogram_gfx/GLUP/GLUP.h>
45 #include <geogram_gfx/GLUP/GLUP_private.h>
46 #include <geogram/mesh/mesh.h>
47
48 /**
49 * \file geogram_gfx/mesh/mesh_gfx.h
50 * \brief A class to display a mesh using OpenGL/GLUP.
51 */
52
53 namespace GEO {
54
55 class MeshGfxImpl;
56
57 /**
58 * \brief Draws a mesh using OpenGL.
59 */
60 class GEOGRAM_GFX_API MeshGfx {
61 public:
62
63 /**
64 * \brief MeshGfx constructor.
65 */
66 MeshGfx();
67
68 /**
69 * \brief MeshGfx destructor.
70 */
71 ~MeshGfx();
72
73 /**
74 * \brief Forbids MeshGfx copy..
75 */
76 MeshGfx(const MeshGfx& rhs) = delete;
77
78 /**
79 * \brief Forbids MeshGfx copy..
80 */
81 MeshGfx& operator=(const MeshGfx& rhs) = delete;
82
83 /**
84 * \brief Draws the vertices of the mesh.
85 * \details If a vertices selection is set, only the
86 * vertices in the selection are drawn
87 * \see set_vertices_selection()
88 */
89 void draw_vertices();
90
91 /**
92 * \brief Draws the edges of the mesh.
93 */
94 void draw_edges();
95
96 /**
97 * \brief Draws the surfacic part of the mesh.
98 */
99 void draw_surface();
100
101 /**
102 * \brief Draws the borders of the surfacic
103 * part of the mesh.
104 */
105 void draw_surface_borders();
106
107 /**
108 * \brief Draws the volumetric part of the mesh.
109 */
110 void draw_volume();
111
112 /**
113 * \brief Gets the mesh visibility flag.
114 * \details The mesh visibility flags specifies
115 * whether mesh edges should be drawn. The used
116 * color can be specified by set_mesh_color()
117 * \retval true if mesh edges should be displayed
118 * \retval false otherwise
119 */
120 bool get_show_mesh() const {
121 return show_mesh_;
122 }
123
124 /**
125 * \brief Sets the mesh visibility flag.
126 * \param[in] x the new value of the mesh visibility flag.
127 * \details The mesh visibility flags specifies
128 * whether mesh edges should be drawn. The used
129 * color can be specified by set_mesh_color()
130 */
131 void set_show_mesh(bool x) {
132 show_mesh_ = x;
133 }
134
135 /**
136 * \brief Gets the mesh width
137 * \details The mesh width is taken into account
138 * when the mesh visibility flag is set
139 * (by set_show_mesh()), when drawing facets
140 * and cells.
141 * \return the mesh width
142 */
143 index_t get_mesh_width() const {
144 return mesh_width_;
145 }
146
147 /**
148 * \brief Sets the mesh width
149 * \details The mesh width is taken into account
150 * when the mesh visibility flag is set
151 * (by set_show_mesh()), when drawing facets
152 * and cells.
153 * \param[in] x the mesh width (minimum is 1)
154 */
155 void set_mesh_width(index_t x) {
156 mesh_width_ = x;
157 }
158
159 /**
160 * \brief Gets the mesh border width
161 * \details The mesh border width is the one used
162 * by draw_surface_borders()
163 * \return the mesh border width
164 */
165 index_t get_mesh_border_width() const {
166 return mesh_border_width_;
167 }
168
169 /**
170 * \brief Sets the mesh border width
171 * \details The mesh border width is the one used
172 * by draw_surface_borders()
173 * \param[in] x the mesh width (minimum is 1)
174 */
175 void set_mesh_border_width(index_t x) {
176 mesh_border_width_ = x;
177 }
178
179 /**
180 * \brief Gets the cells shrink coefficient.
181 * \details The cells shrink coefficient is used
182 * to display cells slighly smaller than what they are.
183 * Cells shrinking is only supported in GLSL mode.
184 * \return the cells shrink coefficient, betwe 0.0 (no shrink)
185 * and 1.0 (full shrink)
186 */
187 double get_shrink() const {
188 return shrink_;
189 }
190
191 /**
192 * \brief Sets the cells shrink coefficient.
193 * \details The cells shrink coefficient is used
194 * to display cells slighly smaller than what they are.
195 * Cells shrinking is only supported in GLSL mode.
196 * \param[in] x the cells shrink coefficient, betwe 0.0 (no shrink)
197 * and 1.0 (full shrink)
198 */
199 void set_shrink(double x) {
200 shrink_ = x;
201 if(shrink_ < 0.0) {
202 shrink_ = 0.0;
203 } else if(shrink_ > 1.0) {
204 shrink_ = 1.0;
205 }
206 }
207
208
209 /**
210 * \brief Gets the animate flag
211 * \details When animate mode is activated and the
212 * mesh has 6d vertices, then an animation is displayed.
213 * The first three coordinates correspond to the vertex
214 * position at initial time (t=0). The last three coordinates
215 * correspond to the vertex position at final time (t=1).
216 * \retval true if animation is used
217 * \retval false otherwise
218 * \see get_time(), set_time()
219 */
220 bool get_animate() const {
221 return animate_;
222 }
223
224 /**
225 * \brief Gets the animate flag
226 * \details When animate mode is activated and the
227 * mesh has 6d vertices, then an animation is displayed.
228 * The first three coordinates correspond to the vertex
229 * position at initial time (t=0). The last three coordinates
230 * correspond to the vertex position at final time (t=1).
231 * \param[in] x true if animation should be used, false otherwise
232 * \see get_time(), set_time()
233 */
234 void set_animate(bool x) {
235 animate_ = x;
236 }
237
238 /**
239 * \brief Gets the time of the animation.
240 * \details Used if animate mode is set.
241 * \return the time of the animation, betwe 0.0 (initial)
242 * and 1.0 (final)
243 * \see get_animate(), set_animate()
244 */
245 double get_time() const {
246 return time_;
247 }
248
249 /**
250 * \brief Gets the time of the animation.
251 * \details Used if animate mode is set.
252 * \param[in] x the time of the animation, betwe 0.0 (initial)
253 * and 1.0 (final)
254 * \see get_animate(), set_animate()
255 */
256 void set_time(double x) {
257 time_ = x;
258 if(time_ < 0.0) {
259 time_ = 0.0;
260 } else if(time_ > 1.0) {
261 time_ = 1.0;
262 }
263 }
264
265 /**
266 * \brief Gets the cell visibility flag.
267 * \details It is possible to specify cell visibility
268 * flags for each individual cell type.
269 * \param[in] type one of MESH_TET, MESH_HEX, MESH_PRISM, MESH_PYRAMID
270 * \retval true if the cells of \p type should be displayed
271 * \retval false otherwise
272 */
273 bool get_draw_cells(MeshCellType type) const {
274 return draw_cells_[type];
275 }
276
277
278 /**
279 * \brief Sets the cell visibility flag.
280 * \details It is possible to specify cell visibility
281 * flags for each individual cell type.
282 * \param[in] type one of MESH_TET, MESH_HEX, MESH_PRISM, MESH_PYRAMID
283 * \param[in] x true if mesh cells of type \p type should be displayed,
284 * false otherwise.
285 */
286 void set_draw_cells(MeshCellType type, bool x) {
287 draw_cells_[type] = x;
288 }
289
290 /**
291 * \brief Sets the points color
292 * \details Specifies the color used to display points
293 * \param[in] r , g , b , a the components of the points color,
294 * in (0.0 .. 1.0)
295 * \see draw_points()
296 */
297 void set_points_color(float r, float g, float b, float a=1.0f) {
298 points_color_[0] = r;
299 points_color_[1] = g;
300 points_color_[2] = b;
301 points_color_[3] = a;
302 }
303
304 /**
305 * \brief Gets the points color
306 * \param[out] r , g , b , a the components of the points color,
307 * in (0.0 .. 1.0)
308 * \see draw_points()
309 */
310 void get_points_color(float& r, float& g, float& b, float& a) const {
311 r = points_color_[0];
312 g = points_color_[1];
313 b = points_color_[2];
314 a = points_color_[3];
315 }
316
317 /**
318 * \brief Sets the point size
319 * \param[in] x the point size (minimum 1)
320 * \see draw_points()
321 */
322 void set_points_size(float x) {
323 points_size_ = x;
324 }
325
326 /**
327 * \brief Gets the point size
328 * \return the point size
329 * \see draw_points()
330 */
331 float get_points_size() const {
332 return points_size_;
333 }
334
335 /**
336 * \brief Sets the mesh color
337 * \details Specifies the mesh color to be used if
338 * mesh edges should be displayed.
339 * \param[in] r , g , b , a the components of the mesh color,
340 * in (0.0 .. 1.0)
341 * \see set_show_mesh(), draw_surface(), draw_volume()
342 */
343 void set_mesh_color(float r, float g, float b, float a=1.0f) {
344 mesh_color_[0] = r;
345 mesh_color_[1] = g;
346 mesh_color_[2] = b;
347 mesh_color_[3] = a;
348 }
349
350 /**
351 * \brief Gets the mesh color
352 * \param[out] r , g , b , a the components of the mesh color,
353 * in (0.0 .. 1.0)
354 * \see set_show_mesh(), draw_surface(), draw_volume()
355 */
356 void get_mesh_color(float& r, float& g, float& b, float& a) const {
357 r = mesh_color_[0];
358 g = mesh_color_[1];
359 b = mesh_color_[2];
360 a = mesh_color_[3];
361 }
362
363 /**
364 * \brief Sets the surface color
365 * \details Specifies the color used to display the
366 * surfacic part of the mesh. It specifies the color
367 * of both frontfacing and backfacing faces.
368 * \param[in] r , g , b , a the components of the surface color,
369 * in (0.0 .. 1.0)
370 * \see draw_surface(), set_backface_surface_color()
371 */
372 void set_surface_color(float r, float g, float b, float a=1.0f) {
373 surface_color_[0] = r;
374 surface_color_[1] = g;
375 surface_color_[2] = b;
376 surface_color_[3] = a;
377 backface_surface_color_[0] = r;
378 backface_surface_color_[1] = g;
379 backface_surface_color_[2] = b;
380 backface_surface_color_[3] = a;
381 }
382
383 /**
384 * \brief Gets the surface color
385 * \param[out] r , g , b , a the components of the surface color,
386 * in (0.0 .. 1.0)
387 * \see draw_surface()
388 */
389 void get_surface_color(float& r, float& g, float& b, float& a) const {
390 r = surface_color_[0];
391 g = surface_color_[1];
392 b = surface_color_[2];
393 a = surface_color_[3];
394 }
395
396 /**
397 * \brief Sets the surface color for backfacing faces.
398 * \details Specifies the color used to display the
399 * backfaces of the surfacic part of the mesh.
400 * \param[in] r , g , b , a the components of the surface color,
401 * in (0.0 .. 1.0)
402 * \see set_show_mesh(), draw_surface(), draw_volume()
403 */
404 void set_backface_surface_color(
405 float r, float g, float b, float a=1.0f
406 ) {
407 backface_surface_color_[0] = r;
408 backface_surface_color_[1] = g;
409 backface_surface_color_[2] = b;
410 backface_surface_color_[3] = a;
411 }
412
413 /**
414 * \brief Sets the color used to display mesh cells.
415 * \param[in] r , g , b , a the components of the cells color,
416 * in (0.0 .. 1.0)
417 * \see set_cells_colors_by_type(), draw_volume()
418 */
419 void set_cells_color(float r, float g, float b, float a=1.0f) {
420 for(index_t i=0; i<MESH_NB_CELL_TYPES; ++i) {
421 cells_color_[i][0] = r;
422 cells_color_[i][1] = g;
423 cells_color_[i][2] = b;
424 cells_color_[i][3] = a;
425 }
426 }
427
428 /**
429 * \brief Gets the cells color
430 * \param[out] r , g , b , a the components of the cells color,
431 * in (0.0 .. 1.0)
432 * \see set_cells_colors_by_type(), draw_volume()
433 */
434 void get_cells_color(float& r, float& g, float& b, float& a) const {
435 r = cells_color_[0][0];
436 g = cells_color_[0][1];
437 b = cells_color_[0][2];
438 a = cells_color_[0][3];
439 }
440
441 /**
442 * \brief Sets a different color for each mesh cell type
443 * \details it uses the following colors:
444 * - tets: red
445 * - hexes: white
446 * - prisms: green
447 * - pyramids: blue
448 * \see set_cells_color(), draw_volume()
449 */
450 void set_cells_colors_by_type() {
451 cells_colors_by_type_ = true;
452 set_cells_color(MESH_TET, 1.0f, 0.0f, 0.0f);
453 set_cells_color(MESH_HEX, 0.9f, 0.9f, 0.9f);
454 set_cells_color(MESH_PRISM, 0.0f, 1.0f, 0.0f);
455 set_cells_color(MESH_PYRAMID, 0.0f, 0.0f, 1.0f);
456 set_cells_color(MESH_CONNECTOR, 1.0f, 0.8f, 0.0f);
457 }
458
459 /**
460 * \brief Gets the lighing flag
461 * \retval true if lighting should be used
462 * \retval false otherwise
463 */
464 bool get_lighting() const {
465 return lighting_;
466 }
467
468 /**
469 * \brief Sets the lighting flag
470 * \param[in] x true if lighting should be used, false
471 * otherwise.
472 */
473 void set_lighting(bool x) {
474 lighting_ = x;
475 }
476
477 /**
478 * \brief Sets the mesh
479 * \param[in] M a pointer to the mesh that should be
480 * displayed.
481 */
482 void set_mesh(const Mesh* M);
483
484 /**
485 * \brief Gets the mesh
486 * \return a pointer to the mesh that will be displayed.
487 */
488 const Mesh* mesh() const {
489 return mesh_;
490 }
491
492 /**
493 * \brief Sets picking mode.
494 * \details If picking mode is MESH_NONE, then normal drawing
495 * is activated, else the color is replaced with the index of
496 * the elements.
497 * \param[in] what a bitwise or ('|') combination of
498 * MESH_VERTICES, MESH_EDGES, MESH_FACETS, MESH_CELLS,
499 * or MESH_NONE if picking mode should be deactivated
500 * \note Picking mode is currently only implemented with
501 * GLSL support at least v1.5.
502 */
503 void set_picking_mode(MeshElementsFlags what) {
504 picking_mode_ = what;
505 }
506
507 /**
508 * \brief Gets the current picking mode.
509 * \return a bitwise or ('|') combination of
510 * MESH_VERTICES, MESH_EDGES, MESH_FACETS, MESH_CELLS,
511 * or MESH_NONE if picking mode is deactivated
512 */
513 MeshElementsFlags get_picking_mode() const {
514 return picking_mode_;
515 }
516
517
518 /**
519 * \brief Sets the object-wide picking id.
520 * \details When the object-wide picking id is set,
521 * it is used to draw all primitives in the picking buffer.
522 * \param[in] id the object-wide picking id, or index_t(-1) if
523 * normal per-primitive picking should be used.
524 */
525 void set_object_picking_id(index_t id) {
526 object_picking_id_ = id;
527 }
528
529 /**
530 * \brief Gets the object-wide picking id.
531 * \return the object-wide picking id, or index_t(-1) if
532 * normal per-primitive picking should be used.
533 */
534 index_t get_object_picking_id() const {
535 return object_picking_id_;
536 }
537
538 /**
539 * \brief Sets the vertices selection.
540 * \details If set, the vertices selection is used to determine
541 * which vertices should be drawn by draw_vertices().
542 * \param[in] name the name of a Property<bool> bound to
543 * the vertices of the mesh.
544 * \see draw_vertices()
545 */
546 void set_vertices_selection(const std::string& name) {
547 if(vertices_selection_ != name) {
548 vertices_selection_ = name;
549 vertices_selection_filter_.attribute_name = name;
550 vertices_selection_filter_.dirty = true;
551 }
552 }
553
554 /**
555 * \brief Gets the vertices selection.
556 * \return the name of the vertices selection, or an
557 * empty string if no vertices selection is set.
558 */
559 const std::string& get_vertices_selection() const {
560 return vertices_selection_;
561 }
562
563 /**
564 * \brief Sets the parameters for displaying a
565 * scalar attribute using texture mapping.
566 * \param[in] subelements one of MESH_VERTICES, MESH_FACETS,
567 * MESH_FACET_CORNERS, MESH_CELLS, MESH_CELL_CORNERS,
568 * MESH_CELL_FACETS
569 * \param[in] name name of the attribute with an optional index,
570 * for instance, "foobar[5]" refers to the 5th coordinate of
571 * the "foobar" vector attribute.
572 * \param[in] attr_min value of the attribute that is bound to
573 * the leftmost color in the colormap
574 * \param[in] attr_max value of the attribute that is bound to
575 * the rightmost color in the colormap
576 * \param[in] colormap_texture the texture to be used to display
577 * the attribute colors
578 * \param[in] repeat the number of times the colorramp should be
579 * repeated within the specified range.
580 */
581 void set_scalar_attribute(
582 MeshElementsFlags subelements,
583 const std::string& name,
584 double attr_min, double attr_max,
585 GLuint colormap_texture,
586 index_t repeat = 1
587 );
588
589 /**
590 * \brief Sets the parameters for texture mapping.
591 * \param[in] subelements the subelements that have texture
592 * coordinates.
593 * \param[in] attribute_name the name of the attribute that
594 * has the texture coordinates. Can be a 2d or 3d vector attribute.
595 * \param[in] texture the texture.
596 * \param[in] repeat the number of times the texture should be repeated
597 * in the unit square in texture space.
598 */
599 void set_texturing(
600 MeshElementsFlags subelements,
601 const std::string& attribute_name,
602 GLuint texture,
603 index_t texture_dim,
604 index_t repeat = 1
605 );
606
607
608 /**
609 * \brief Unsets scalar attribute display.
610 */
611 void unset_scalar_attribute() {
612 attribute_subelements_ = MESH_NONE;
613 attribute_min_ = 0.0;
614 attribute_max_ = 0.0;
615 attribute_texture_ = 0;
616 attribute_repeat_ = 1;
617 attribute_dim_ = 0;
618 }
619
620 /**
621 * \brief Sets primitive filtering
622 * \details Primitive filtering deactivates display of some
623 * primitives based on their id and an attribute. The attribute
624 * is of type Numeric::uint8. If the attribute value is zero, then
625 * the corresponding primitive is not displayed.
626 * \param[in] subelements one of
627 * MESH_VERTICES, MESH_FACETS, MESH_CELLS, MESH_ALL_ELEMENTS
628 * \param[in] name the name of the attribute with the
629 * filter. Default is "filter"
630 */
631 void set_filter(
632 MeshElementsFlags subelements,
633 const std::string& name = "filter"
634 );
635
636 /**
637 * \brief Unset primitive filtering
638 */
639 void unset_filters();
640
641
642 /**
643 * \brief Deallocates OpenGL objects
644 */
645 void cleanup();
646
647 protected:
648
649 void draw_vertices_array();
650 void draw_vertices_immediate_plain();
651 void draw_vertices_immediate_attrib();
652 void draw_vertices_selection();
653
654 void draw_edges_array();
655 void draw_edges_immediate_plain();
656 void draw_edges_immediate_attrib();
657 void draw_edges_picking_filter();
658
659 void draw_triangles();
660 void draw_triangles_array();
661 void draw_triangles_immediate_plain();
662 void draw_triangles_immediate_attrib();
663
664 void draw_quads();
665 void draw_quads_array();
666 void draw_quads_immediate_plain();
667 void draw_quads_immediate_attrib();
668
669 void draw_triangles_and_quads();
670 void draw_triangles_and_quads_array();
671 void draw_triangles_and_quads_immediate_plain();
672 void draw_triangles_and_quads_immediate_attrib();
673
674 void draw_polygons();
675 void draw_polygons_plain();
676 void draw_polygons_attrib();
677
678 void draw_tets();
679 void draw_tets_array();
680 void draw_tets_immediate_plain();
681 void draw_tets_immediate_attrib();
682
683 void draw_hybrid();
684 void draw_hybrid_array();
685 void draw_hybrid_immediate_plain();
686 void draw_hybrid_immediate_attrib();
687
688 void set_cells_color(MeshCellType type, float r, float g, float b) {
689 cells_color_[type][0] = r;
690 cells_color_[type][1] = g;
691 cells_color_[type][2] = b;
692 }
693
694 void draw_attribute_as_tex_coord(index_t element) {
695 if(picking_mode_ == MESH_NONE) {
696 switch(attribute_dim_) {
697 case 1:
698 glupPrivateTexCoord1d(scalar_attribute_[element]);
699 break;
700 case 2:
701 glupPrivateTexCoord2d(
702 tex_coord_attribute_[0][element],
703 tex_coord_attribute_[1][element]
704 );
705 break;
706 case 3:
707 glupPrivateTexCoord3d(
708 tex_coord_attribute_[0][element],
709 tex_coord_attribute_[1][element],
710 tex_coord_attribute_[2][element]
711 );
712 break;
713 }
714 }
715 }
716
717 void draw_vertex_with_attribute(index_t vertex) {
718 if(attribute_subelements_ == MESH_VERTICES) {
719 draw_attribute_as_tex_coord(vertex);
720 }
721 draw_vertex(vertex);
722 }
723
724 void draw_surface_vertex_with_attribute(
725 index_t vertex, index_t facet, index_t corner
726 ) {
727 if(attribute_subelements_ == MESH_VERTICES) {
728 draw_attribute_as_tex_coord(vertex);
729 } else if(attribute_subelements_ == MESH_FACETS) {
730 draw_attribute_as_tex_coord(facet);
731 } else if(attribute_subelements_ == MESH_FACET_CORNERS) {
732 draw_attribute_as_tex_coord(corner);
733 }
734 draw_vertex(vertex);
735 }
736
737 void draw_volume_vertex_with_attribute(
738 index_t vertex, index_t cell, index_t cell_corner
739 ) {
740 if(attribute_subelements_ == MESH_VERTICES) {
741 draw_attribute_as_tex_coord(vertex);
742 } else if(attribute_subelements_ == MESH_CELLS) {
743 draw_attribute_as_tex_coord(cell);
744 } else if(attribute_subelements_ == MESH_CELL_CORNERS) {
745 draw_attribute_as_tex_coord(cell_corner);
746 }
747 draw_vertex(vertex);
748 }
749
750 void draw_vertex(index_t v) {
751 if(do_animation_) {
752 if(mesh_->vertices.single_precision()) {
753 const GLUPfloat* p =
754 mesh_->vertices.single_precision_point_ptr(v);
755 float t = float(time_);
756 float s = 1.0f - float(time_);
757 glupPrivateVertex3f(
758 s*p[0] + t*p[3],
759 s*p[1] + t*p[4],
760 s*p[2] + t*p[5]
761 );
762 } else {
763 const GLUPdouble* p = mesh_->vertices.point_ptr(v);
764 double s = 1.0 - time_;
765 glupPrivateVertex3d(
766 s*p[0] + time_*p[3],
767 s*p[1] + time_*p[4],
768 s*p[2] + time_*p[5]
769 );
770 }
771 } else {
772 if(mesh_->vertices.single_precision()) {
773 if(mesh_->vertices.dimension() < 3) {
774 glupPrivateVertex2fv(
775 mesh_->vertices.single_precision_point_ptr(v)
776 );
777 } else {
778 glupPrivateVertex3fv(
779 mesh_->vertices.single_precision_point_ptr(v)
780 );
781 }
782 } else {
783 if(mesh_->vertices.dimension() < 3) {
784 glupPrivateVertex2dv(
785 mesh_->vertices.point_ptr(v)
786 );
787 } else {
788 glupPrivateVertex3dv(
789 mesh_->vertices.point_ptr(v)
790 );
791 }
792 }
793 }
794 }
795
796 void draw_surface_mesh_with_lines();
797
798 /**
799 * \brief Sets GLUP drawing parameters.
800 */
801 void set_GLUP_parameters();
802
803 /**
804 * \brief Sets GLUP picking mode for drawing primitives
805 * of a given type, or deactivates GLUP picking if MeshGfx picking mode
806 * is deactivated.
807 * \param[in] what one of
808 * MESH_VERTICES, MESH_EDGES, MESH_FACETS, MESH_CELLS.
809 */
810 void set_GLUP_picking(MeshElementsFlags what);
811
812
813 /**
814 * \brief Encodes an id as the current vertex color.
815 * \details This is required for drawing polygons, that
816 * cannot use standard GLUP primitives and picking.
817 */
818 void set_GLUP_vertex_color_from_picking_id(index_t id);
819
820
821 /**
822 * \brief Updates the Vertex Buffer Objects and Vertex Array
823 * Objects.
824 * \details The buffer objects are updated if buffer_objects_dirty_
825 * is set, then buffer_objects_dirty_ is reset. If
826 * buffer_objects_dirty_ is not set, it checks whether the sizes
827 * of the buffer objects match the size of the mesh arrays.
828 */
829 void update_buffer_objects_if_needed();
830
831
832 /**
833 * \brief Updates the buffer objects used to display attributes.
834 * \details The buffer objects are updated if
835 * attribute_buffer_objects_dirty_
836 * is set, then attribute_buffer_objects_dirty_ is reset. If
837 * attribute_buffer_objects_dirty_ is not set, it checks whether
838 * the sizes of the buffer objects match the size of the mesh arrays.
839 */
840 void update_attribute_buffer_objects_if_needed();
841
842
843 /**
844 * \brief Binds the attribute buffer object to a Vertex Array
845 * Object.
846 * \param[in] VAO one of vertices_VAO_, edges_VAO_, facets_VAO_
847 * or cells_VAO_. If zero, the function does nothing.
848 * \pre attribute_.is_bound()
849 */
850 void bind_attribute_buffer_object(GLuint VAO);
851
852
853 /**
854 * \brief Unbinds the attribute buffer object from a Vertex
855 * Array Object.
856 * \param[in] VAO one of vertices_VAO_, edges_VAO_, facets_VAO_
857 * or cells_VAO_. If zero, the function does nothing.
858 */
859 void unbind_attribute_buffer_object(GLuint VAO);
860
861 /**
862 * \brief Binds the vertices VBO to the current VAO.
863 */
864 void bind_vertices_VBO();
865
866 /**
867 * \brief Setups drawing for attributes.
868 * \details If no attribute is bound, does nothing.
869 */
870 void begin_attributes();
871
872 /**
873 * \brief Deactivates drawing for attributes.
874 */
875 void end_attributes();
876
877
878 /**
879 * \brief Tests whether array mode can be used
880 * to draw a specified GLUP primitive.
881 * \param[in] prim the GLUP primitive
882 */
883 bool can_use_array_mode(GLUPprimitive prim) const;
884
885 void update_surface_elements();
886
887 void update_volume_elements();
888
889 protected:
890 bool show_mesh_;
891 index_t mesh_width_;
892 index_t mesh_border_width_;
893 double shrink_;
894 bool animate_;
895 double time_;
896 bool draw_cells_[MESH_NB_CELL_TYPES];
897 float points_size_;
898
899 float points_color_[4];
900 float mesh_color_[4];
901 float surface_color_[4];
902 float backface_surface_color_[4];
903 float cells_color_[MESH_NB_CELL_TYPES][4];
904 bool cells_colors_by_type_;
905
906 bool lighting_;
907
908 MeshElementsFlags picking_mode_;
909 index_t object_picking_id_;
910
911 std::string vertices_selection_;
912
913 bool do_animation_;
914
915 const Mesh* mesh_;
916 bool triangles_and_quads_;
917 bool quads_;
918 bool has_cells_[MESH_NB_CELL_TYPES];
919
920 bool buffer_objects_dirty_;
921 bool attributes_buffer_objects_dirty_;
922 bool long_vector_attribute_;
923
924 GLuint vertices_VAO_;
925 GLuint edges_VAO_;
926 GLuint facets_VAO_;
927 GLuint cells_VAO_;
928
929 GLuint vertices_VBO_;
930 GLuint edge_indices_VBO_;
931 GLuint facet_indices_VBO_;
932 GLuint cell_indices_VBO_;
933 GLuint vertices_attribute_VBO_;
934
935 MeshElementsFlags attribute_subelements_;
936 std::string attribute_name_;
937 index_t attribute_dim_;
938 double attribute_min_;
939 double attribute_max_;
940 GLuint attribute_texture_;
941 index_t attribute_texture_dim_;
942 index_t attribute_repeat_;
943 ReadOnlyScalarAttributeAdapter scalar_attribute_;
944 ReadOnlyScalarAttributeAdapter tex_coord_attribute_[3];
945 bool ES_profile_;
946
947 /**
948 * \brief Filters primitives based on their id and on
949 * an attribute.
950 */
951 struct Filter {
952 Filter();
953 ~Filter();
954
955 /**
956 * \brief Begins rendering with primitive filtering.
957 * \param[in] attributes_manager a reference to the
958 * attributes manager where the property is stored
959 * \param[in] hw_primitive_filtering if set, uses
960 * hardware primitive fitering
961 * (GLUP_PRIMITIVES_FILTERING), else one may use
962 * the function test() instead.
963 * \retval true if attribute filtering is active, that is,
964 * if attribute name is not the empty string and if an
965 * the attribute exists
966 * \retval false otherwise
967 */
968 bool begin(
969 AttributesManager& attributes_manager,
970 bool hw_primitive_filtering=true
971 );
972
973 /**
974 * \brief Needs to be called after rendering.
975 */
976 void end();
977
978 /**
979 * \brief Deallocates GPU objects.
980 */
981 void deallocate();
982
983 /**
984 * \brief Tests an individual primitive.
985 * \retval true if the primitive should be
986 * displayed
987 * \retval false otherwise
988 */
989 bool test(index_t primitive_id) const {
990 return (
991 !attribute.is_bound() ||
992 attribute[primitive_id] != 0
993 );
994 }
995
996 std::string attribute_name;
997 Attribute<Numeric::uint8> attribute;
998 GLuint VBO;
999 GLuint texture;
1000 bool dirty;
1001 };
1002
1003 Filter vertices_filter_;
1004 Filter edges_filter_;
1005 Filter facets_filter_;
1006 Filter cells_filter_;
1007 Filter vertices_selection_filter_;
1008
1009 /**
1010 * \brief Tests whether hardware primitive filtering is supported.
1011 * \details On some higher profiles (GLUP150, GLUP440), it is possible
1012 * to filter primitives in the shaders. It reduces GPU transfers by
1013 * making it possible to reuse the same VBOs even when the list of
1014 * objects to display changes.
1015 */
1016 bool hw_filtering_supported() const;
1017
1018 /**
1019 * \brief Generic function to extract element sequences to draw
1020 * \details Tests the filter if set, and finds all intervals of
1021 * primitives to render. For each interval, it calls
1022 * glupBasePickingId(GLUPuint64(begin)) so that picking Ids are
1023 * correct.
1024 * \param[in] elements the MeshSubElementsStore to render
1025 * \param[in] draw the function to be called for each (begin,end)
1026 * sequence of elements to be drawn, where begin is the index of
1027 * the first element, and end one position past the index of the
1028 * last element.
1029 */
1030 void draw_sequences(
1031 const MeshSubElementsStore& elements,
1032 std::function<void(index_t, index_t)> draw
1033 ) {
1034 // GLUP hardware primitive filtering.
1035 // Not supported in all profiles.
1036 // If supported, primitives are filtered by the GPU,
1037 // else, they are filtered here explicitly.
1038 const bool hw_filtering = hw_filtering_supported();
1039
1040 Filter* filter = nullptr;
1041 if(&elements == &mesh_->vertices) {
1042 filter = &vertices_filter_;
1043 } else if(&elements == &mesh_->edges) {
1044 filter = &edges_filter_;
1045 } else if(&elements == &mesh_->facets) {
1046 filter = &facets_filter_;
1047 } else if(&elements == &mesh_->cells) {
1048 filter = &cells_filter_;
1049 }
1050 geo_assert(filter != nullptr) ;
1051
1052 filter->begin(elements.attributes(), hw_filtering);
1053 index_t e = 0;
1054 while(e < elements.nb()) {
1055 while(e<elements.nb() && !(hw_filtering||filter->test(e))) {
1056 ++e;
1057 }
1058 if(e<elements.nb()) {
1059 index_t begin = e;
1060 while(e<elements.nb() && (hw_filtering||filter->test(e))) {
1061 ++e;
1062 }
1063 index_t end = e;
1064 glupBasePickingId(GLUPuint64(begin));
1065 draw(begin,end);
1066 }
1067 }
1068 filter->end();
1069 glupBasePickingId(0);
1070 }
1071
1072 /**
1073 * \brief Generic function to extract element sequences to draw
1074 * \details Tests the filter if set, and finds all intervals of
1075 * primitives to render. For each interval, it calls
1076 * glupBasePickingId(GLUPuint64(begin)) so that picking Ids are
1077 * correct.
1078 * \param[in] elements the MeshSubElementsStore to render
1079 * \param[in] predicate a function that tests which elements should
1080 * be drawn or not
1081 * \param[in] draw the function to be called for each (begin,end)
1082 * sequence of elements to be drawn, where begin is the index of
1083 * the first element, and end one position past the index of the
1084 * last element.
1085 */
1086 void draw_sequences_if(
1087 const MeshSubElementsStore& elements,
1088 std::function<bool(index_t)> predicate,
1089 std::function<void(index_t, index_t)> draw
1090 ) {
1091 // GLUP hardware primitive filtering.
1092 // Not supported in all profiles.
1093 // If supported, primitives are filtered by the GPU,
1094 // else, they are filtered here explicitly.
1095 const bool hw_filtering = hw_filtering_supported();
1096
1097 Filter* filter = nullptr;
1098 if(&elements == &mesh_->vertices) {
1099 filter = &vertices_filter_;
1100 } else if(&elements == &mesh_->edges) {
1101 filter = &edges_filter_;
1102 } else if(&elements == &mesh_->facets) {
1103 filter = &facets_filter_;
1104 } else if(&elements == &mesh_->cells) {
1105 filter = &cells_filter_;
1106 }
1107 geo_assert(filter != nullptr) ;
1108 filter->begin(elements.attributes(), hw_filtering);
1109
1110 index_t e = 0;
1111 while(e < elements.nb()) {
1112 while(
1113 e<elements.nb() && (
1114 !(hw_filtering || filter->test(e)) || !predicate(e))
1115 ) {
1116 ++e;
1117 }
1118 if(e<elements.nb()) {
1119 index_t begin = e;
1120 while(
1121 e<elements.nb() &&
1122 (hw_filtering || filter->test(e)) &&
1123 predicate(e)
1124 ) {
1125 ++e;
1126 }
1127 index_t end = e;
1128 glupBasePickingId(GLUPuint64(begin));
1129 draw(begin,end);
1130 }
1131 }
1132 filter->end();
1133 glupBasePickingId(0);
1134 }
1135
1136 };
1137
1138 }
1139
1140 #endif
1141