Materialx Protobuf API 1.39.5
Serialization API to convert between MaterialX and Google Protobuf formats.
Loading...
Searching...
No Matches
main.cpp File Reference

Main program for converting MaterialX documents to and from Protobuf format. More...

#include "materialx_serializer.h"
#include <MaterialXCore/Document.h>
#include <MaterialXFormat/XmlIo.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <cstring>
#include <filesystem>

Functions

std::string writeFile (const std::string &input_path, const std::string &output_folder, const std::string &suffix, const std::string &content, bool debug_print, bool binary_mode=false)
 Write content to a file.
 
std::pair< bool, std::vector< std::string > > compareMtlxDocuments (mx::DocumentPtr doc1, mx::DocumentPtr doc2)
 Compare two MaterialX documents for equivalence.
 
std::string toLower (const std::string &str)
 Convert string to lowercase.
 
bool endsWith (const std::string &str, const std::string &suffix)
 Check if string ends with suffix.
 
void printUsage (const char *program_name)
 
int main (int argc, char *argv[])
 

Detailed Description

Main program for converting MaterialX documents to and from Protobuf format.

Function Documentation

◆ compareMtlxDocuments()

std::pair< bool, std::vector< std::string > > compareMtlxDocuments ( mx::DocumentPtr doc1,
mx::DocumentPtr doc2 )

Compare two MaterialX documents for equivalence.

Parameters
doc1First document
doc2Second document
Returns
Pair of (is_same, differences)
72 {
73 mx::ElementEquivalenceOptions options;
74 std::string message;
75 bool is_same = doc1->isEquivalent(doc2, options, &message);
76
77 std::vector<std::string> differences;
78 if (!is_same && !message.empty()) {
79 differences.push_back(message);
80 std::cout << "Differences found between MaterialX documents:" << std::endl;
81 std::cout << message << std::endl;
82 }
83
84 std::cout << "Documents are equivalent: " << (is_same ? "true" : "false") << std::endl;
85 return {is_same, differences};
86}

◆ endsWith()

bool endsWith ( const std::string & str,
const std::string & suffix )

Check if string ends with suffix.

101 {
102 if (suffix.size() > str.size()) return false;
103 return str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
104}

◆ main()

int main ( int argc,
char * argv[] )
118 {
119 if (argc < 2) {
120 printUsage(argv[0]);
121 return 1;
122 }
123
124 // Parse arguments
125 std::string input_file;
126 bool write_json = false;
127 bool convert_back = false;
128 bool write_mermaid = false;
129 std::string output_folder;
130 int debug_pb_doc = 0;
131
132 for (int i = 1; i < argc; ++i) {
133 std::string arg = argv[i];
134
135 if (arg == "-h" || arg == "--help") {
136 printUsage(argv[0]);
137 return 0;
138 } else if (arg == "-j" || arg == "--json") {
139 write_json = true;
140 } else if (arg == "-cb" || arg == "--convert_back") {
141 convert_back = true;
142 } else if (arg == "-wm" || arg == "--write_mermaid") {
143 write_mermaid = true;
144 } else if (arg == "-of" || arg == "--output_folder") {
145 if (i + 1 < argc) {
146 output_folder = argv[++i];
147 } else {
148 std::cerr << "Error: --output_folder requires an argument" << std::endl;
149 return 1;
150 }
151 } else if (arg == "-dbg" || arg == "--debug_pb_doc") {
152 if (i + 1 < argc) {
153 debug_pb_doc = std::atoi(argv[++i]);
154 } else {
155 std::cerr << "Error: --debug_pb_doc requires an argument" << std::endl;
156 return 1;
157 }
158 } else if (arg[0] != '-') {
159 input_file = arg;
160 } else {
161 std::cerr << "Unknown option: " << arg << std::endl;
162 printUsage(argv[0]);
163 return 1;
164 }
165 }
166
167 if (input_file.empty()) {
168 std::cerr << "Error: No input file specified" << std::endl;
169 printUsage(argv[0]);
170 return 1;
171 }
172
173 try {
174 std::string input_lower = toLower(input_file);
175 bool convert_from_mtlx = endsWith(input_lower, ".mtlx");
176 bool convert_from_protobuf = endsWith(input_lower, ".mxpb");
177
178 MaterialXDocument pb_doc;
179 bool has_pb_doc = false;
180
181 // Protobuf to MaterialX conversion
182 if (convert_from_protobuf) {
183 std::cout << "Reading Protobuf file: " << input_file << std::endl;
184
185 // Read binary file
186 std::ifstream in_stream(input_file, std::ios::binary);
187 if (!in_stream) {
188 std::cerr << "Error: Failed to open input file: " << input_file << std::endl;
189 return 1;
190 }
191
192 std::ostringstream buffer;
193 buffer << in_stream.rdbuf();
194 std::string data = buffer.str();
195 in_stream.close();
196
197 pb_doc = Util::fromString(data);
198 has_pb_doc = true;
199
200 // Convert to MaterialX
201 ProtobufToMaterialX converter;
202 const Version& pb_version = pb_doc.schema_version();
203 std::cout << "Converting Protobuf document using schema version "
204 << pb_version.major() << "." << pb_version.minor() << "." << pb_version.patch()
205 << " and MaterialX " << mx::getVersionString() << "..." << std::endl;
206
207 mx::DocumentPtr doc = converter.convert(pb_doc);
208
209 // Write out MaterialX file
210 std::string new_doc_string = mx::writeToXmlString(doc);
211 writeFile(input_file, output_folder, "_from_pb.mtlx", new_doc_string, true);
212 }
213
214 // MaterialX to Protobuf conversion
215 if (convert_from_mtlx) {
216 std::cout << "Reading MaterialX file: " << input_file << std::endl;
217
218 mx::DocumentPtr doc = mx::createDocument();
219 mx::readFromXmlFile(doc, input_file);
220
221 // Convert and save
222 MaterialXToProtobuf converter;
223 std::cout << "Converting MaterialX document to Protobuf format..." << std::endl;
224 pb_doc = converter.convert(doc);
225 has_pb_doc = true;
226
227 std::string content = Util::toString(pb_doc);
228 writeFile(input_file, output_folder, ".mxpb", content, true, true);
229
230 // Convert back to MaterialX
231 if (convert_back) {
232 ProtobufToMaterialX converter2;
233 mx::DocumentPtr new_doc = converter2.convert(pb_doc);
234
235 auto [is_same, messages] = compareMtlxDocuments(doc, new_doc);
236
237 std::string new_doc_string = mx::writeToXmlString(new_doc);
238 writeFile(input_file, output_folder, "_converted.mtlx", new_doc_string, true);
239 }
240 }
241
242 // Additional outputs
243 if (has_pb_doc) {
244 if (write_mermaid) {
245 std::string mermaid_code = Util::generateMermaidDiagram(pb_doc);
246 writeFile(input_file, output_folder, "_diagram.mmd", mermaid_code, true);
247 }
248
249 if (write_json) {
250 std::string json_str = Util::toJson(pb_doc, 2);
251 writeFile(input_file, output_folder, ".json", json_str, true);
252 }
253
254 if (debug_pb_doc > 0) {
255 std::cout << std::string(80, '*') << std::endl;
256 if (debug_pb_doc == 1) {
258 } else if (debug_pb_doc == 2) {
260 } else if (debug_pb_doc == 3) {
261 Util::debugInspect(pb_doc);
262 }
263 std::cout << std::string(80, '*') << std::endl;
264 }
265 }
266
267 if (!convert_from_mtlx && !convert_from_protobuf) {
268 std::cerr << "Error: Input file must have .mtlx or .mxpb extension" << std::endl;
269 return 1;
270 }
271
272 } catch (const std::exception& e) {
273 std::cerr << "Error: " << e.what() << std::endl;
274 return 1;
275 }
276
277 return 0;
278}
Converter class to transform MaterialX document objects into Protobuf MaterialXDocument messages.
Definition materialx_serializer.h:38
MaterialXDocument convert(mx::DocumentPtr doc)
Convert a MaterialX document object to a Protobuf MaterialXDocument message.
Definition materialx_serializer.cpp:16
Converter class to transform Protobuf MaterialXDocument messages back into MaterialX document objects...
Definition materialx_serializer.h:67
mx::DocumentPtr convert(const MaterialXDocument &pb_doc)
Convert a Protobuf MaterialXDocument message to a MaterialX document object.
Definition materialx_serializer.cpp:67
static std::string toJson(const MaterialXDocument &pb_doc, int indent=2)
Convert Protobuf document to JSON string.
Definition materialx_serializer.cpp:156
static std::string generateMermaidDiagram(const MaterialXDocument &pb_doc)
Generate a Mermaid diagram from protobuf document hierarchy.
Definition materialx_serializer.cpp:290
static MaterialXDocument fromString(const std::string &data)
Parse binary data to create Protobuf document.
Definition materialx_serializer.cpp:140
static std::string toString(const MaterialXDocument &pb_doc)
Serialize Protobuf document to binary string.
Definition materialx_serializer.cpp:148
static void debugInspect(const MaterialXDocument &pb_doc, int max_depth=10)
Print detailed document structure with attributes and children.
Definition materialx_serializer.cpp:166
static void debugInspectCompact(const MaterialXDocument &pb_doc, int max_depth=10)
Print compact document structure.
Definition materialx_serializer.cpp:205
static void debugInspectSimple(const MaterialXDocument &pb_doc)
Print simple tree structure of document.
Definition materialx_serializer.cpp:256
bool endsWith(const std::string &str, const std::string &suffix)
Check if string ends with suffix.
Definition main.cpp:101
std::string toLower(const std::string &str)
Convert string to lowercase.
Definition main.cpp:91
void printUsage(const char *program_name)
Definition main.cpp:106
std::string writeFile(const std::string &input_path, const std::string &output_folder, const std::string &suffix, const std::string &content, bool debug_print, bool binary_mode=false)
Write content to a file.
Definition main.cpp:28
std::pair< bool, std::vector< std::string > > compareMtlxDocuments(mx::DocumentPtr doc1, mx::DocumentPtr doc2)
Compare two MaterialX documents for equivalence.
Definition main.cpp:72

◆ printUsage()

void printUsage ( const char * program_name)
106 {
107 std::cout << "Usage: " << program_name << " <inputFile> [options]\n"
108 << "\nOptions:\n"
109 << " -j, --json Output JSON representation of the Protobuf document\n"
110 << " -cb, --convert_back Convert back to MaterialX after Protobuf conversion\n"
111 << " -wm, --write_mermaid Output Mermaid diagram of the Protobuf document\n"
112 << " -of, --output_folder Output folder for converted files\n"
113 << " -dbg, --debug_pb_doc Enable debug output (1=simple, 2=compact, 3=full)\n"
114 << " -h, --help Show this help message\n"
115 << std::endl;
116}

◆ toLower()

std::string toLower ( const std::string & str)

Convert string to lowercase.

91 {
92 std::string result = str;
93 std::transform(result.begin(), result.end(), result.begin(),
94 [](unsigned char c) { return std::tolower(c); });
95 return result;
96}

◆ writeFile()

std::string writeFile ( const std::string & input_path,
const std::string & output_folder,
const std::string & suffix,
const std::string & content,
bool debug_print,
bool binary_mode = false )

Write content to a file.

Parameters
input_pathOriginal input file path
output_folderOutput folder (optional)
suffixSuffix to append to filename
contentContent to write
debug_printWhether to print debug messages
binary_modeWhether to write in binary mode
Returns
Output file path
33 {
34 fs::path input_file(input_path);
35 std::string base_name = input_file.stem().string();
36 std::string output_file = base_name + suffix;
37
38 if (!output_folder.empty()) {
39 fs::path output_path(output_folder);
40 output_file = (output_path / output_file).string();
41 } else {
42 fs::path parent_path = input_file.parent_path();
43 output_file = (parent_path / output_file).string();
44 }
45
46 if (debug_print) {
47 std::cout << "Writing file: " << output_file << std::endl;
48 }
49
50 std::ios_base::openmode mode = std::ios::out;
51 if (binary_mode) {
52 mode |= std::ios::binary;
53 }
54
55 std::ofstream out_stream(output_file, mode);
56 if (!out_stream) {
57 throw std::runtime_error("Failed to open file for writing: " + output_file);
58 }
59
60 out_stream.write(content.c_str(), content.size());
61 out_stream.close();
62
63 return output_file;
64}