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