1 /*
2     main.cpp -- Instant Meshes application entry point
3 
4     This file is part of the implementation of
5 
6         Instant Field-Aligned Meshes
7         Wenzel Jakob, Daniele Panozzo, Marco Tarini, and Olga Sorkine-Hornung
8         In ACM Transactions on Graphics (Proc. SIGGRAPH Asia 2015)
9 
10     All rights reserved. Use of this source code is governed by a
11     BSD-style license that can be found in the LICENSE.txt file.
12 */
13 
14 #include "batch.h"
15 #include "viewer.h"
16 #include "serializer.h"
17 #include <thread>
18 #include <cstdlib>
19 
20 /* Force usage of discrete GPU on laptops */
21 NANOGUI_FORCE_DISCRETE_GPU();
22 
23 int nprocs = -1;
24 
main(int argc,char ** argv)25 int main(int argc, char **argv) {
26     std::vector<std::string> args;
27     bool extrinsic = true, dominant = false, align_to_boundaries = false;
28     bool fullscreen = false, help = false, deterministic = false, compat = false;
29     int rosy = 4, posy = 4, face_count = -1, vertex_count = -1;
30     uint32_t knn_points = 10, smooth_iter = 2;
31     Float crease_angle = -1, scale = -1;
32     std::string batchOutput;
33     #if defined(__APPLE__)
34         bool launched_from_finder = false;
35     #endif
36 
37     try {
38         for (int i=1; i<argc; ++i) {
39             if (strcmp("--fullscreen", argv[i]) == 0 || strcmp("-F", argv[i]) == 0) {
40                 fullscreen = true;
41             } else if (strcmp("--help", argv[i]) == 0 || strcmp("-h", argv[i]) == 0) {
42                 help = true;
43             } else if (strcmp("--deterministic", argv[i]) == 0 || strcmp("-d", argv[i]) == 0) {
44                 deterministic = true;
45             } else if (strcmp("--intrinsic", argv[i]) == 0 || strcmp("-i", argv[i]) == 0) {
46                 extrinsic = false;
47             } else if (strcmp("--boundaries", argv[i]) == 0 || strcmp("-b", argv[i]) == 0) {
48                 align_to_boundaries = true;
49             } else if (strcmp("--threads", argv[i]) == 0 || strcmp("-t", argv[i]) == 0) {
50                 if (++i >= argc) {
51                     cerr << "Missing thread count!" << endl;
52                     return -1;
53                 }
54                 nprocs = str_to_uint32_t(argv[i]);
55             } else if (strcmp("--smooth", argv[i]) == 0 || strcmp("-S", argv[i]) == 0) {
56                 if (++i >= argc) {
57                     cerr << "Missing smoothing iteration count argument!" << endl;
58                     return -1;
59                 }
60                 smooth_iter = str_to_uint32_t(argv[i]);
61             } else if (strcmp("--knn", argv[i]) == 0 || strcmp("-k", argv[i]) == 0) {
62                 if (++i >= argc) {
63                     cerr << "Missing knn point count argument!" << endl;
64                     return -1;
65                 }
66                 knn_points = str_to_uint32_t(argv[i]);
67             } else if (strcmp("--crease", argv[i]) == 0 || strcmp("-c", argv[i]) == 0) {
68                 if (++i >= argc) {
69                     cerr << "Missing crease angle argument!" << endl;
70                     return -1;
71                 }
72                 crease_angle = str_to_float(argv[i]);
73             } else if (strcmp("--rosy", argv[i]) == 0 || strcmp("-r", argv[i]) == 0) {
74                 if (++i >= argc) {
75                     cerr << "Missing rotation symmetry type!" << endl;
76                     return -1;
77                 }
78                 rosy = str_to_int32_t(argv[i]);
79             } else if (strcmp("--posy", argv[i]) == 0 || strcmp("-p", argv[i]) == 0) {
80                 if (++i >= argc) {
81                     cerr << "Missing position symmetry type!" << endl;
82                     return -1;
83                 }
84                 posy = str_to_int32_t(argv[i]);
85                 if (posy == 6)
86                     posy = 3;
87             } else if (strcmp("--scale", argv[i]) == 0 || strcmp("-s", argv[i]) == 0) {
88                 if (++i >= argc) {
89                     cerr << "Missing scale argument!" << endl;
90                     return -1;
91                 }
92                 scale = str_to_float(argv[i]);
93             } else if (strcmp("--faces", argv[i]) == 0 || strcmp("-f", argv[i]) == 0) {
94                 if (++i >= argc) {
95                     cerr << "Missing face count argument!" << endl;
96                     return -1;
97                 }
98                 face_count = str_to_int32_t(argv[i]);
99             } else if (strcmp("--vertices", argv[i]) == 0 || strcmp("-v", argv[i]) == 0) {
100                 if (++i >= argc) {
101                     cerr << "Missing vertex count argument!" << endl;
102                     return -1;
103                 }
104                 vertex_count = str_to_int32_t(argv[i]);
105             } else if (strcmp("--output", argv[i]) == 0 || strcmp("-o", argv[i]) == 0) {
106                 if (++i >= argc) {
107                     cerr << "Missing batch mode output file argument!" << endl;
108                     return -1;
109                 }
110                 batchOutput = argv[i];
111             } else if (strcmp("--dominant", argv[i]) == 0 || strcmp("-D", argv[i]) == 0) {
112                 dominant = true;
113             } else if (strcmp("--compat", argv[i]) == 0 || strcmp("-C", argv[i]) == 0) {
114                 compat = true;
115 #if defined(__APPLE__)
116             } else if (strncmp("-psn", argv[i], 4) == 0) {
117                 launched_from_finder = true;
118 #endif
119             } else {
120                 if (strncmp(argv[i], "-", 1) == 0) {
121                     cerr << "Invalid argument: \"" << argv[i] << "\"!" << endl;
122                     help = true;
123                 }
124                 args.push_back(argv[i]);
125             }
126         }
127     } catch (const std::exception &e) {
128         cout << "Error: " << e.what() << endl;
129         help = true;
130     }
131 
132     if ((posy != 3 && posy != 4) || (rosy != 2 && rosy != 4 && rosy != 6)) {
133         cerr << "Error: Invalid symmetry type!" << endl;
134         help  = true;
135     }
136 
137     int nConstraints = 0;
138     nConstraints += scale > 0 ? 1 : 0;
139     nConstraints += face_count > 0 ? 1 : 0;
140     nConstraints += vertex_count > 0 ? 1 : 0;
141 
142     if (nConstraints > 1) {
143         cerr << "Error: Only one of the --scale, --face and --vertices parameters can be used at once!" << endl;
144         help = true;
145     }
146 
147     if (args.size() > 1 || help || (!batchOutput.empty() && args.size() == 0)) {
148         cout << "Syntax: " << argv[0] << " [options] <input mesh / point cloud / application state snapshot>" << endl;
149         cout << "Options:" << endl;
150         cout << "   -o, --output <output>     Writes to the specified PLY/OBJ output file in batch mode" << endl;
151         cout << "   -t, --threads <count>     Number of threads used for parallel computations" << endl;
152         cout << "   -d, --deterministic       Prefer (slower) deterministic algorithms" << endl;
153         cout << "   -c, --crease <degrees>    Dihedral angle threshold for creases" << endl;
154         cout << "   -S, --smooth <iter>       Number of smoothing & ray tracing reprojection steps (default: 2)" << endl;
155         cout << "   -D, --dominant            Generate a tri/quad dominant mesh instead of a pure tri/quad mesh" << endl;
156         cout << "   -i, --intrinsic           Intrinsic mode (extrinsic is the default)" << endl;
157         cout << "   -b, --boundaries          Align to boundaries (only applies when the mesh is not closed)" << endl;
158         cout << "   -r, --rosy <number>       Specifies the orientation symmetry type (2, 4, or 6)" << endl;
159         cout << "   -p, --posy <number>       Specifies the position symmetry type (4 or 6)" << endl;
160         cout << "   -s, --scale <scale>       Desired world space length of edges in the output" << endl;
161         cout << "   -f, --faces <count>       Desired face count of the output mesh" << endl;
162         cout << "   -v, --vertices <count>    Desired vertex count of the output mesh" << endl;
163         cout << "   -C, --compat              Compatibility mode to load snapshots from old software versions" << endl;
164         cout << "   -k, --knn <count>         Point cloud mode: number of adjacent points to consider" << endl;
165         cout << "   -F, --fullscreen          Open a full-screen window" << endl;
166         cout << "   -h, --help                Display this message" << endl;
167         return -1;
168     }
169 
170     if (args.size() == 0)
171         cout << "Running in GUI mode, start with -h for instructions on batch mode." << endl;
172 
173     tbb::task_scheduler_init init(nprocs == -1 ? tbb::task_scheduler_init::automatic : nprocs);
174 
175     if (!batchOutput.empty() && args.size() == 1) {
176         try {
177             batch_process(args[0], batchOutput, rosy, posy, scale, face_count,
178                           vertex_count, crease_angle, extrinsic,
179                           align_to_boundaries, smooth_iter, knn_points,
180                           !dominant, deterministic);
181             return 0;
182         } catch (const std::exception &e) {
183             cerr << "Caught runtime error : " << e.what() << endl;
184             return -1;
185         }
186     }
187 
188     try {
189         nanogui::init();
190 
191         #if defined(__APPLE__)
192             if (launched_from_finder)
193                 nanogui::chdir_to_bundle_parent();
194         #endif
195 
196         {
197             nanogui::ref<Viewer> viewer = new Viewer(fullscreen, deterministic);
198             viewer->setVisible(true);
199 
200             if (args.size() == 1) {
201                 if (Serializer::isSerializedFile(args[0])) {
202                     viewer->loadState(args[0], compat);
203                 } else {
204                     viewer->loadInput(args[0], crease_angle,
205                             scale, face_count, vertex_count,
206                             rosy, posy, knn_points);
207                     viewer->setExtrinsic(extrinsic);
208                 }
209             }
210 
211             nanogui::mainloop();
212         }
213 
214         nanogui::shutdown();
215     } catch (const std::runtime_error &e) {
216         std::string error_msg = std::string("Caught a fatal error: ") + std::string(e.what());
217         #if defined(_WIN32)
218             MessageBoxA(nullptr, error_msg.c_str(), NULL, MB_ICONERROR | MB_OK);
219         #else
220             std::cerr << error_msg << endl;
221         #endif
222         return -1;
223     }
224 
225     return EXIT_SUCCESS;
226 }
227