| 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 |