GCC Code Coverage Report


Directory: ./
File: lib/geogram_gfx/gui/simple_mesh_application.cpp
Date: 2026-09-07 02:37:58
Exec Total Coverage
Lines: 0 412 0.0%
Functions: 0 29 0.0%
Branches: 0 514 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 #include <geogram_gfx/gui/simple_mesh_application.h>
41 #include <geogram/mesh/mesh_io.h>
42 #include <geogram/basic/file_system.h>
43 #include <geogram/basic/command_line.h>
44 #include <geogram/basic/stopwatch.h>
45
46 namespace GEO {
47
48 /**********************************************************************/
49
50 SimpleMeshApplication::SimpleMeshApplication(
51 const std::string& name
52 ) : SimpleApplication(name) {
53
54 set_default_filename("out.meshb");
55
56 anim_speed_ = 1.0f;
57 anim_time_ = 0.0f;
58
59 show_vertices_ = false;
60 show_vertices_selection_ = true;
61 vertices_size_ = 1.0f;
62 vertices_color_ = vec4f(0.0f, 1.0f, 0.0f, 1.0f);
63 vertices_transparency_ = 0.0f;
64
65 show_surface_ = true;
66 surface_color_ = vec4f(0.5f, 0.5f, 1.0f, 1.0f);
67 surface_color_2_ = vec4f(1.0f, 0.5f, 0.0f, 1.0f);
68 show_surface_sides_ = false;
69
70 show_mesh_ = true;
71 mesh_color_ = vec4f(0.05f, 0.05f, 0.05f, 1.0f);
72 mesh_width_ = 0.1f;
73
74 show_surface_borders_ = true;
75 surface_borders_color_ = vec4f(0.0f, 0.85f, 0.85f, 1.0f);
76 surface_borders_width_ = 0.3f;
77
78 show_volume_ = false;
79 volume_color_ = vec4f(0.9f, 0.9f, 0.9f, 1.0f);
80 cells_shrink_ = 0.0f;
81 show_colored_cells_ = false;
82 show_hexes_ = true;
83 show_connectors_ = true;
84
85 show_attributes_ = false;
86 current_colormap_index_ = 3;
87 attribute_min_ = 0.0f;
88 attribute_max_ = 0.0f;
89 attribute_ = "vertices.point_fp32[0]";
90 attribute_name_ = "point_fp32[0]";
91 attribute_subelements_ = MESH_VERTICES;
92
93 add_key_toggle("p", &show_vertices_, "vertices");
94 add_key_toggle("S", &show_surface_, "surface");
95 add_key_toggle("c", &show_surface_sides_, "two-sided");
96 add_key_toggle("B", &show_surface_borders_, "borders");
97 add_key_toggle("m", &show_mesh_, "mesh");
98 add_key_toggle("V", &show_volume_, "volume");
99 add_key_toggle("j", &show_hexes_, "hexes");
100 add_key_toggle("k", &show_connectors_, "connectors");
101 add_key_toggle("C", &show_colored_cells_, "colored cells");
102
103 add_key_func("r", decrement_anim_time_callback, "- anim speed");
104 add_key_func("t", increment_anim_time_callback, "+ anim speed");
105 add_key_func("x", decrement_cells_shrink_callback, "- cells shrink");
106 add_key_func("w", increment_cells_shrink_callback, "+ cells shrink");
107 }
108
109
110 void SimpleMeshApplication::install_key_file_navigation() {
111 add_key_func("down", next_file, "load next file");
112 add_key_func("up", prev_file, "load previous file");
113 add_key_func("home", first_file, "load first file in directory");
114 add_key_func("end", last_file, "load last file in directory");
115 }
116
117 void SimpleMeshApplication::geogram_initialize(int argc, char** argv) {
118 GEO::initialize(GEO::GEOGRAM_INSTALL_ALL);
119 GEO::CmdLine::declare_arg(
120 "attributes", true, "load mesh attributes"
121 );
122
123 GEO::CmdLine::declare_arg(
124 "single_precision", true, "use single precision vertices (FP32)"
125 );
126 SimpleApplication::geogram_initialize(argc, argv);
127 }
128
129 std::string SimpleMeshApplication::supported_read_file_extensions() {
130 std::vector<std::string> extensions;
131 GEO::MeshIOHandlerFactory::list_creators(extensions);
132 return String::join_strings(extensions, ';');
133 }
134
135 std::string SimpleMeshApplication::supported_write_file_extensions() {
136 std::vector<std::string> extensions;
137 GEO::MeshIOHandlerFactory::list_creators(extensions);
138 return String::join_strings(extensions, ';');
139 }
140
141 void SimpleMeshApplication::show_attributes() {
142 show_attributes_ = true;
143 }
144
145 void SimpleMeshApplication::hide_attributes() {
146 show_attributes_ = false;
147 }
148
149 void SimpleMeshApplication::autorange() {
150 if(attribute_subelements_ != MESH_NONE) {
151 attribute_min_ = 0.0;
152 attribute_max_ = 0.0;
153 const MeshSubElementsStore& subelements =
154 mesh_.get_subelements_by_type(attribute_subelements_);
155 ReadOnlyScalarAttributeAdapter attribute(
156 subelements.attributes(), attribute_name_
157 );
158 if(attribute.is_bound()) {
159 attribute_min_ = Numeric::max_float32();
160 attribute_max_ = Numeric::min_float32();
161 for(index_t i=0; i<subelements.nb(); ++i) {
162 attribute_min_ =
163 std::min(attribute_min_, float(attribute[i]));
164 attribute_max_ =
165 std::max(attribute_max_, float(attribute[i]));
166 }
167 }
168 }
169 }
170
171 std::string SimpleMeshApplication::attribute_names() {
172 return mesh_.get_scalar_attributes();
173 }
174
175 void SimpleMeshApplication::set_attribute(const std::string& attribute) {
176 attribute_ = attribute;
177 std::string subelements_name;
178 String::split_string(
179 attribute_, '.',
180 subelements_name,
181 attribute_name_
182 );
183 attribute_subelements_ =
184 mesh_.name_to_subelements_type(subelements_name);
185 if(attribute_min_ == 0.0f && attribute_max_ == 0.0f) {
186 autorange();
187 }
188 }
189
190 void SimpleMeshApplication::draw_object_properties() {
191 SimpleApplication::draw_object_properties();
192 float s = float(scaling());
193 ImGui::Checkbox("attributes", &show_attributes_);
194 if(show_attributes_) {
195 if(attribute_min_ == 0.0f && attribute_max_ == 0.0f) {
196 autorange();
197 }
198 if(ImGui::Button(
199 (attribute_ + "##Attribute").c_str(), ImVec2(-1,0))
200 ) {
201 ImGui::OpenPopup("##Attributes");
202 }
203 if(ImGui::BeginPopup("##Attributes")) {
204 std::vector<std::string> attributes;
205 String::split_string(attribute_names(), ';', attributes);
206 for(index_t i=0; i<attributes.size(); ++i) {
207 if(ImGui::Button(attributes[i].c_str())) {
208 set_attribute(attributes[i]);
209 ImGui::CloseCurrentPopup();
210 }
211 }
212 ImGui::EndPopup();
213 }
214 ImGui::InputFloat("min",&attribute_min_);
215 ImGui::InputFloat("max",&attribute_max_);
216 if(ImGui::Button("autorange", ImVec2(-1,0))) {
217 autorange();
218 }
219 if(ImGui::ImageButton(
220 "choose_colormap",
221 static_cast<ImTextureID>(
222 colormaps_[current_colormap_index_].texture
223 ),
224 ImVec2(115.0f*s,8.0f*s))
225 ) {
226 ImGui::OpenPopup("##Colormap");
227 }
228 if(ImGui::BeginPopup("##Colormap")) {
229 for(index_t i=0; i<colormaps_.size(); ++i) {
230 if(ImGui::ImageButton(
231 colormaps_[i].name.c_str(),
232 static_cast<ImTextureID>(colormaps_[i].texture),
233 ImVec2(100.0f*s,8.0f*s))
234 ) {
235 current_colormap_index_ = i;
236 ImGui::CloseCurrentPopup();
237 }
238 }
239 ImGui::EndPopup();
240 }
241 }
242
243 if(mesh_.vertices.dimension() >= 6) {
244 ImGui::Separator();
245 ImGui::Checkbox(
246 "Animate", animate_ptr()
247 );
248 ImGui::SliderFloat("spd.", &anim_speed_, 1.0f, 10.0f, "%.1f");
249 ImGui::SliderFloat("t.", &anim_time_, 0.0f, 1.0f, "%.2f");
250 }
251
252 ImGui::Separator();
253 ImGui::Checkbox("##VertOnOff", &show_vertices_);
254 ImGui::SameLine();
255 ImGui::ColorEdit3WithPalette("Vert.", vertices_color_.data());
256
257 if(show_vertices_) {
258 ImGui::Checkbox("selection", &show_vertices_selection_);
259 ImGui::SliderFloat("sz.", &vertices_size_, 0.1f, 5.0f, "%.1f");
260 ImGui::InputFloat(
261 "trsp.", &vertices_transparency_, 0.0f, 1.0f, "%.3f"
262 );
263 }
264
265 if(mesh_.facets.nb() != 0) {
266 ImGui::Separator();
267 ImGui::Checkbox("##SurfOnOff", &show_surface_);
268 ImGui::SameLine();
269 ImGui::ColorEdit3WithPalette(
270 "Surf.", surface_color_.data()
271 );
272 if(show_surface_) {
273 ImGui::Checkbox("##SidesOnOff", &show_surface_sides_);
274 ImGui::SameLine();
275 ImGui::ColorEdit3WithPalette(
276 "2sided", surface_color_2_.data()
277 );
278
279 ImGui::Checkbox("##MeshOnOff", &show_mesh_);
280 ImGui::SameLine();
281 ImGui::ColorEdit3WithPalette("mesh", mesh_color_.data());
282 if(show_mesh_) {
283 ImGui::SliderFloat(
284 "wid.##mesh", &mesh_width_, 0.1f, 2.0f, "%.1f"
285 );
286 }
287
288 ImGui::Checkbox("##BordersOnOff", &show_surface_borders_);
289 ImGui::SameLine();
290 ImGui::ColorEdit3WithPalette(
291 "borders", surface_borders_color_.data()
292 );
293 if(show_surface_borders_) {
294 ImGui::SliderFloat(
295 "wid.##borders",
296 &surface_borders_width_, 0.1f, 2.0f, "%.1f"
297 );
298 }
299 }
300 }
301
302 if(mesh_.cells.nb() != 0) {
303 ImGui::Separator();
304 ImGui::Checkbox("##VolumeOnOff", &show_volume_);
305 ImGui::SameLine();
306 ImGui::ColorEdit3WithPalette("Volume", volume_color_.data());
307 if(show_volume_) {
308 ImGui::SliderFloat(
309 "shrk.", &cells_shrink_, 0.0f, 1.0f, "%.2f"
310 );
311 if(!mesh_.cells.are_simplices()) {
312 ImGui::Checkbox("colored cells", &show_colored_cells_);
313 ImGui::Checkbox("hexes", &show_hexes_);
314 }
315 }
316 }
317 }
318
319 void SimpleMeshApplication::increment_anim_time_callback() {
320 instance()->anim_time_ = std::min(
321 instance()->anim_time_ + 0.05f, 1.0f
322 );
323 }
324
325 void SimpleMeshApplication::decrement_anim_time_callback() {
326 instance()->anim_time_ = std::max(
327 instance()->anim_time_ - 0.05f, 0.0f
328 );
329 }
330
331 void SimpleMeshApplication::increment_cells_shrink_callback() {
332 instance()->cells_shrink_ = std::min(
333 instance()->cells_shrink_ + 0.05f, 1.0f
334 );
335 }
336
337 void SimpleMeshApplication::decrement_cells_shrink_callback() {
338 instance()->cells_shrink_ = std::max(
339 instance()->cells_shrink_ - 0.05f, 0.0f
340 );
341 }
342
343 void SimpleMeshApplication::first_file() {
344 instance()->current_file_ = "";
345 next_file();
346 }
347
348 void SimpleMeshApplication::last_file() {
349 instance()->current_file_ = "";
350 prev_file();
351 }
352
353 void SimpleMeshApplication::prev_file() {
354 std::vector<std::string> files;
355 std::string dirname = FileSystem::get_current_working_directory();
356 if(instance()->current_file_ != "") {
357 dirname = FileSystem::dir_name(instance()->current_file_);
358 }
359 FileSystem::get_files(dirname, files);
360 std::sort(files.begin(), files.end());
361 if(files.size() == 0) {
362 return;
363 }
364 auto it = std::find(
365 files.begin(), files.end(), instance()->current_file_
366 );
367 if(it == files.end()) {
368 it = files.begin();
369 }
370 do {
371 if(it == files.begin()) {
372 it = files.end();
373 --it;
374 } else {
375 --it;
376 }
377 } while(MeshIOHandler::get_handler(*it) == nullptr);
378 instance()->load(*it);
379 Logger::out("I/O") << "Loaded " << FileSystem::base_name(*it)
380 << "."
381 << FileSystem::extension(*it)
382 << " (" << (it - files.begin() + 1)
383 << "/"
384 << files.size() << ")"
385 << std::endl;
386 }
387
388 void SimpleMeshApplication::next_file() {
389 std::vector<std::string> files;
390 std::string dirname = FileSystem::get_current_working_directory();
391 if(instance()->current_file_ != "") {
392 dirname = FileSystem::dir_name(instance()->current_file_);
393 }
394 FileSystem::get_files(dirname, files);
395 std::sort(files.begin(), files.end());
396 if(files.size() == 0) {
397 return;
398 }
399 auto it = std::find(
400 files.begin(), files.end(), instance()->current_file_
401 );
402 if(it == files.end()) {
403 it = files.begin() + int(files.size()-1);
404 }
405 do {
406 it++;
407 if(it == files.end()) {
408 it = files.begin();
409 }
410 } while(MeshIOHandler::get_handler(*it) == nullptr);
411 instance()->load(*it);
412 Logger::out("I/O") << "Loaded " << FileSystem::base_name(*it)
413 << "."
414 << FileSystem::extension(*it)
415 << " (" << (it - files.begin() + 1)
416 << "/"
417 << files.size() << ")"
418 << std::endl;
419 }
420
421 void SimpleMeshApplication::GL_initialize() {
422 SimpleApplication::GL_initialize();
423 }
424
425 void SimpleMeshApplication::GL_terminate() {
426 mesh_gfx_.cleanup();
427 SimpleApplication::GL_terminate();
428 }
429
430 void SimpleMeshApplication::draw_points() {
431 if(show_vertices_) {
432 if(vertices_transparency_ != 0.0f) {
433 glDepthMask(GL_FALSE);
434 glEnable(GL_BLEND);
435 glBlendEquation(GL_FUNC_ADD);
436 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
437 }
438 mesh_gfx_.set_points_color(
439 vertices_color_.x, vertices_color_.y, vertices_color_.z,
440 1.0f - vertices_transparency_
441 );
442 mesh_gfx_.set_points_size(vertices_size_);
443 mesh_gfx_.draw_vertices();
444
445 if(vertices_transparency_ != 0.0f) {
446 glDisable(GL_BLEND);
447 glDepthMask(GL_TRUE);
448 }
449 }
450
451 if(show_vertices_selection_) {
452 mesh_gfx_.set_points_color(1.0, 0.0, 0.0);
453 mesh_gfx_.set_points_size(2.0f * vertices_size_);
454 mesh_gfx_.set_vertices_selection("selection");
455 mesh_gfx_.draw_vertices();
456 mesh_gfx_.set_vertices_selection("");
457 }
458 }
459
460 void SimpleMeshApplication::draw_surface() {
461 mesh_gfx_.set_mesh_color(0.0, 0.0, 0.0);
462
463 mesh_gfx_.set_surface_color(
464 surface_color_.x, surface_color_.y, surface_color_.z
465 );
466 if(show_surface_sides_) {
467 mesh_gfx_.set_backface_surface_color(
468 surface_color_2_.x, surface_color_2_.y, surface_color_2_.z
469 );
470 }
471
472 mesh_gfx_.set_show_mesh(show_mesh_);
473 mesh_gfx_.set_mesh_color(mesh_color_.x, mesh_color_.y, mesh_color_.z);
474 mesh_gfx_.set_mesh_width(index_t(mesh_width_*10.0f));
475
476 if(show_surface_) {
477 float specular_backup = glupGetSpecular();
478 glupSetSpecular(0.4f);
479 mesh_gfx_.draw_surface();
480 glupSetSpecular(specular_backup);
481 }
482
483 if(show_surface_borders_) {
484 mesh_gfx_.set_mesh_color(
485 surface_borders_color_.x,
486 surface_borders_color_.y,
487 surface_borders_color_.z
488 );
489 mesh_gfx_.set_mesh_border_width(
490 index_t(surface_borders_width_*10.0f)
491 );
492 mesh_gfx_.draw_surface_borders();
493 }
494 }
495
496 void SimpleMeshApplication::draw_edges() {
497 if(show_mesh_) {
498 mesh_gfx_.draw_edges();
499 }
500 }
501
502 void SimpleMeshApplication::draw_volume() {
503 if(show_volume_) {
504
505 if(
506 glupIsEnabled(GLUP_CLIPPING) &&
507 glupGetClipMode() == GLUP_CLIP_SLICE_CELLS
508 ) {
509 mesh_gfx_.set_lighting(false);
510 }
511
512 mesh_gfx_.set_shrink(double(cells_shrink_));
513 mesh_gfx_.set_draw_cells(GEO::MESH_HEX, show_hexes_);
514 mesh_gfx_.set_draw_cells(GEO::MESH_CONNECTOR, show_connectors_);
515
516 if(show_colored_cells_) {
517 mesh_gfx_.set_cells_colors_by_type();
518 } else {
519 mesh_gfx_.set_cells_color(
520 volume_color_.x, volume_color_.y, volume_color_.z
521 );
522 }
523 mesh_gfx_.draw_volume();
524
525 mesh_gfx_.set_lighting(lighting_);
526 }
527 }
528
529 void SimpleMeshApplication::draw_scene() {
530
531 if(mesh_gfx_.mesh() == nullptr) {
532 return;
533 }
534
535 if(animate()) {
536 anim_time_ = float(
537 sin(double(anim_speed_) * GEO::Stopwatch::now())
538 );
539 anim_time_ = 0.5f * (anim_time_ + 1.0f);
540 }
541
542 mesh_gfx_.set_lighting(lighting_);
543 mesh_gfx_.set_time(double(anim_time_));
544
545 if(show_attributes_) {
546 mesh_gfx_.set_scalar_attribute(
547 attribute_subelements_, attribute_name_,
548 double(attribute_min_), double(attribute_max_),
549 colormaps_[current_colormap_index_].texture, 1
550 );
551 } else {
552 mesh_gfx_.unset_scalar_attribute();
553 }
554
555 draw_points();
556 draw_surface();
557 draw_edges();
558 draw_volume();
559 }
560
561 bool SimpleMeshApplication::load(const std::string& filename) {
562
563 if(!FileSystem::is_file(filename)) {
564 Logger::out("I/O") << "is not a file" << std::endl;
565 }
566 mesh_gfx_.set_mesh(nullptr);
567
568 mesh_.clear(false,false);
569
570 if(GEO::CmdLine::get_arg_bool("single_precision")) {
571 mesh_.vertices.set_single_precision();
572 }
573
574 MeshIOFlags flags;
575 if(CmdLine::get_arg_bool("attributes")) {
576 flags.set_attribute(MESH_FACET_REGION);
577 flags.set_attribute(MESH_CELL_REGION);
578 }
579 if(!mesh_load(filename, mesh_, flags)) {
580 return false;
581 }
582
583 if(
584 FileSystem::extension(filename) == "obj6" ||
585 FileSystem::extension(filename) == "tet6"
586 ) {
587 Logger::out("Vorpaview")
588 << "Displaying mesh animation." << std::endl;
589
590 start_animation();
591
592 mesh_gfx_.set_animate(true);
593 double xyzmin[3];
594 double xyzmax[3];
595 get_bbox(mesh_, xyzmin, xyzmax, true);
596 set_region_of_interest(
597 xyzmin[0], xyzmin[1], xyzmin[2],
598 xyzmax[0], xyzmax[1], xyzmax[2]
599 );
600 } else {
601 mesh_gfx_.set_animate(false);
602 mesh_.vertices.set_dimension(3);
603 double xyzmin[3];
604 double xyzmax[3];
605 get_bbox(mesh_, xyzmin, xyzmax, false);
606 set_region_of_interest(
607 xyzmin[0], xyzmin[1], xyzmin[2],
608 xyzmax[0], xyzmax[1], xyzmax[2]
609 );
610 }
611
612 show_vertices_ = (mesh_.facets.nb() == 0);
613 mesh_gfx_.set_mesh(&mesh_);
614 current_file_ = filename;
615 return true;
616 }
617
618 bool SimpleMeshApplication::save(const std::string& filename) {
619 MeshIOFlags flags;
620 if(CmdLine::get_arg_bool("attributes")) {
621 flags.set_attribute(MESH_FACET_REGION);
622 flags.set_attribute(MESH_CELL_REGION);
623 }
624 if(FileSystem::extension(filename) == "geogram") {
625 mesh_.vertices.set_double_precision();
626 }
627 bool result = true;
628 if(mesh_save(mesh_, filename, flags)) {
629 current_file_ = filename;
630 } else {
631 result = false;
632 }
633 if(GEO::CmdLine::get_arg_bool("single_precision")) {
634 mesh_.vertices.set_single_precision();
635 }
636 return result;
637 }
638
639 void SimpleMeshApplication::get_bbox(
640 const Mesh& M_in, double* xyzmin, double* xyzmax, bool animate
641 ) {
642 geo_assert(M_in.vertices.dimension() >= index_t(animate ? 6 : 3));
643 for(index_t c = 0; c < 3; c++) {
644 xyzmin[c] = Numeric::max_float64();
645 xyzmax[c] = Numeric::min_float64();
646 }
647
648 for(index_t v = 0; v < M_in.vertices.nb(); ++v) {
649 if(M_in.vertices.single_precision()) {
650 const float* p = M_in.vertices.single_precision_point_ptr(v);
651 for(coord_index_t c = 0; c < 3; ++c) {
652 xyzmin[c] = std::min(xyzmin[c], double(p[c]));
653 xyzmax[c] = std::max(xyzmax[c], double(p[c]));
654 if(animate) {
655 xyzmin[c] = std::min(xyzmin[c], double(p[c+3]));
656 xyzmax[c] = std::max(xyzmax[c], double(p[c+3]));
657 }
658 }
659 } else {
660 const double* p = M_in.vertices.point_ptr(v);
661 for(coord_index_t c = 0; c < 3; ++c) {
662 xyzmin[c] = std::min(xyzmin[c], p[c]);
663 xyzmax[c] = std::max(xyzmax[c], p[c]);
664 if(animate) {
665 xyzmin[c] = std::min(xyzmin[c], p[c+3]);
666 xyzmax[c] = std::max(xyzmax[c], p[c+3]);
667 }
668 }
669 }
670 }
671 }
672 }
673