1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 
4 /*!
5     \file   nanovdb_validate.cc
6 
7     \author Ken Museth
8 
9     \date   October 13, 2020
10 
11     \brief  Command-line tool that validates Grids in nanovdb files
12 */
13 
14 #include <nanovdb/util/IO.h> // this is required to read (and write) NanoVDB files on the host
15 #include <nanovdb/util/GridValidator.h>
16 #include <iomanip>
17 #include <sstream>
18 
usage(const std::string & progName,int exitStatus=EXIT_FAILURE)19 void usage [[noreturn]] (const std::string& progName, int exitStatus = EXIT_FAILURE)
20 {
21     std::cerr << "\nUsage: " << progName << " [options] *.nvdb\n"
22               << "Which: Validates grids in one or more NanoVDB files\n\n"
23               << "Options:\n"
24               << "-g,--grid name\tOnly validate grids matching the specified string name\n"
25               << "-h,--help\tPrints this message\n"
26               << "-v,--verbose\tPrint verbose information information useful for debugging\n"
27               << "--version\tPrint version information to the terminal\n";
28     exit(exitStatus);
29 }
30 
version(const char * progName,int exitStatus=EXIT_SUCCESS)31 void version [[noreturn]] (const char* progName, int exitStatus = EXIT_SUCCESS)
32 {
33     printf("\n%s was build against NanoVDB version %s\n", progName, nanovdb::Version().c_str());
34     exit(exitStatus);
35 }
36 
main(int argc,char * argv[])37 int main(int argc, char* argv[])
38 {
39     int exitStatus = EXIT_SUCCESS;
40 
41     bool                     verbose = false;
42     bool                     detailed = true;
43     std::string              gridName;
44     std::vector<std::string> fileNames;
45     for (int i = 1; i < argc; ++i) {
46         std::string arg = argv[i];
47         if (arg[0] == '-') {
48             if (arg == "-h" || arg == "--help") {
49                 usage(argv[0], EXIT_SUCCESS);
50             } else if (arg == "--version") {
51                 version(argv[0]);
52             } else if (arg == "-v" || arg == "--verbose") {
53                 verbose = true;
54             } else if (arg == "-g" || arg == "--grid") {
55                 if (i + 1 == argc) {
56                     std::cerr << "\nExpected a grid name to follow the -g,--grid option\n";
57                     usage(argv[0]);
58                 } else {
59                     gridName.assign(argv[++i]);
60                 }
61             } else {
62                 std::cerr << "\nIllegal option: \"" << arg << "\"\n";
63                 usage(argv[0]);
64             }
65         } else if (!arg.empty()) {
66             fileNames.push_back(arg);
67         }
68     }
69     if (fileNames.size() == 0) {
70         std::cerr << "\nExpected at least one input NanoVDB file\n";
71         usage(argv[0]);
72     }
73 
74     const auto nameKey = nanovdb::io::stringHash(gridName);
75 
76     try {
77         for (auto& file : fileNames) {
78             auto list = nanovdb::io::readGridMetaData(file);
79             if (!gridName.empty()) {
80                 std::vector<nanovdb::io::GridMetaData> tmp;
81                 for (auto& m : list) {
82                     if (nameKey == m.nameKey && gridName == m.gridName)
83                         tmp.emplace_back(m);
84                 }
85                 list = tmp;
86             }
87             if (list.size() == 0) {
88                 continue;
89             }
90 
91             if (verbose) {
92                 std::cout << "\nThe file \"" << file << "\" contains the following matching " << list.size() << " grid(s):\n";
93             }
94 
95             for (auto& m : list) {
96                 auto handle = nanovdb::io::readGrid(file, m.gridName);
97                 auto gridType = handle.gridType();
98                 bool test = false;
99                 if (gridType == nanovdb::GridType::End) {
100                     std::cerr << "GridHandle was empty\n" << std::endl;
101                     usage(argv[0]);
102                 } else if (auto* grid = handle.grid<float>()) {
103                     test = isValid(*grid, detailed, verbose);
104                 } else if (auto* grid = handle.grid<nanovdb::Vec3f>()) {
105                     test = isValid(*grid, detailed, verbose);
106                 } else if (auto* grid = handle.grid<uint32_t>()) {
107                     test = isValid(*grid, detailed, verbose);
108                 } else if (auto* grid = handle.grid<int32_t>()) {
109                     test = isValid(*grid, detailed, verbose);
110                 } else if (auto* grid = handle.grid<int16_t>()) {
111                     test = isValid(*grid, detailed, verbose);
112                 } else if (auto* grid = handle.grid<int64_t>()) {
113                     test = isValid(*grid, detailed, verbose);
114                 } else if (auto* grid = handle.grid<int16_t>()) {
115                     test = isValid(*grid, detailed, verbose);
116                 } else if (auto* grid = handle.grid<double>()) {
117                     test = isValid(*grid, detailed, verbose);
118                 } else if (auto* grid = handle.grid<nanovdb::Vec3d>()) {
119                     test = isValid(*grid, detailed, verbose);
120                 } else if (auto* grid = handle.grid<nanovdb::ValueMask>()) {
121                     test = isValid(*grid, detailed, verbose);
122                 } else if (auto* grid = handle.grid<nanovdb::Rgba8>()) {
123                     test = isValid(*grid, detailed, verbose);
124                 } else if (auto* grid = handle.grid<nanovdb::Fp4>()) {
125                     test = isValid(*grid, detailed, verbose);
126                 } else if (auto* grid = handle.grid<nanovdb::Fp8>()) {
127                     test = isValid(*grid, detailed, verbose);
128                 } else if (auto* grid = handle.grid<nanovdb::Fp16>()) {
129                     test = isValid(*grid, detailed, verbose);
130                 } else if (auto* grid = handle.grid<nanovdb::FpN>()) {
131                     test = isValid(*grid, detailed, verbose);
132                 } else if (auto* grid = handle.grid<bool>()) {
133                     test = isValid(*grid, detailed, verbose);
134                 } else {
135                     std::cerr << "Unsupported GridType: \"" << nanovdb::toStr(gridType) << "\"\n" << std::endl;
136                     usage(argv[0]);
137                 }
138                 if (verbose) {
139                     std::cout << "Grid named \"" << m.gridName << "\": " << (test ? "passed" : "failed") << std::endl;
140                 } else if (!test) {
141                     std::cout << "Grid named \"" << m.gridName << "\": failed" << std::endl;
142                 }
143             }
144         }
145     }
146     catch (const std::exception& e) {
147         std::cerr << "An exception occurred: \"" << e.what() << "\"" << std::endl;
148         exitStatus = EXIT_FAILURE;
149     }
150     catch (...) {
151         std::cerr << "Exception oof unexpected type caught" << std::endl;
152         exitStatus = EXIT_FAILURE;
153     }
154 
155     return exitStatus;
156 }
157