Change compile sample to use mj_parse and mj_encode as input/output.
There is a single remaining exception for mjb as it's a special case by bypassing mjSpec. PiperOrigin-RevId: 943556676 Change-Id: Iaf480ea6d2d42a6007b35c23435b25c9eb24ead0
This commit is contained in:
committed by
Copybara-Service
parent
19e175c063
commit
ae58855c15
+81
-111
@@ -12,42 +12,37 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <chrono>
|
||||
#include <cctype>
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <string_view>
|
||||
|
||||
#include <mujoco/mujoco.h>
|
||||
|
||||
|
||||
// help
|
||||
static constexpr char helpstring[] =
|
||||
"\n Usage: compile infile [outfile]\n"
|
||||
" infile can be in mjcf, urdf, mjb format\n"
|
||||
" outfile can be in mjcf, mjb, txt format\n\n"
|
||||
" if infile is mjcf or urdf and outfile is omitted, a detailed\n"
|
||||
" timing breakdown is printed for two compilations (cold and warm cache)\n\n"
|
||||
" Example: compile model.xml [model.mjb]\n";
|
||||
|
||||
|
||||
// timer (seconds)
|
||||
double gettm(void) {
|
||||
using Clock = std::chrono::steady_clock;
|
||||
using Seconds = std::chrono::duration<double>;
|
||||
static const Clock::time_point tm_start = Clock::now();
|
||||
return Seconds(Clock::now() - tm_start).count();
|
||||
}
|
||||
|
||||
static constexpr char kHelp[] =
|
||||
"\n Usage: compile infile [outfile]\n"
|
||||
" infile can be in any format with a registered decoder (e.g. mjcf, "
|
||||
"urdf) or mjb\n"
|
||||
" outfile can be in mjcf, mjb, txt format, or empty\n\n"
|
||||
" if outfile is empty, compilation will be "
|
||||
"timed twice to measure the impact of caching\n\n"
|
||||
" Example: compile model.xml [model.mjb]\n";
|
||||
|
||||
// deallocate and print message
|
||||
int finish(const char* msg = 0, int exitcode = EXIT_SUCCESS, mjModel* m = 0) {
|
||||
int finish(const char* msg = 0, int exitcode = EXIT_SUCCESS, mjModel* m = 0,
|
||||
mjVFS* vfs = 0) {
|
||||
// deallocated everything
|
||||
if (m) {
|
||||
mj_deleteModel(m);
|
||||
}
|
||||
if (vfs) {
|
||||
mj_deleteVFS(vfs);
|
||||
}
|
||||
|
||||
// print message
|
||||
if (msg) {
|
||||
@@ -57,52 +52,20 @@ int finish(const char* msg = 0, int exitcode = EXIT_SUCCESS, mjModel* m = 0) {
|
||||
return exitcode;
|
||||
}
|
||||
|
||||
// check if filename has extension (case-insensitive)
|
||||
bool HasExtension(std::string_view filename, std::string_view ext) {
|
||||
if (filename.length() < ext.length()) return false;
|
||||
|
||||
// possible file types
|
||||
enum {
|
||||
typeUNKNOWN = 0,
|
||||
typeXML,
|
||||
typeMJB,
|
||||
typeTXT,
|
||||
typeNONE
|
||||
};
|
||||
|
||||
|
||||
// determine file type
|
||||
int filetype(const char* filename) {
|
||||
// convert to lower case for string comparison
|
||||
char lower[1000];
|
||||
std::size_t i=0;
|
||||
while (i<std::strlen(filename) && i<999) {
|
||||
lower[i] = (char)tolower(filename[i]);
|
||||
i++;
|
||||
}
|
||||
lower[i] = 0;
|
||||
|
||||
// find last dot
|
||||
int dot = (int)std::strlen(lower);
|
||||
while (dot>=0 && lower[dot]!='.') {
|
||||
dot--;
|
||||
}
|
||||
|
||||
// no dot found
|
||||
if (dot<0) {
|
||||
return typeUNKNOWN;
|
||||
}
|
||||
|
||||
// check extension
|
||||
if (!std::strcmp(lower+dot, ".xml") || !std::strcmp(lower+dot, ".urdf")) {
|
||||
return typeXML;
|
||||
} else if (!std::strcmp(lower+dot, ".mjb")) {
|
||||
return typeMJB;
|
||||
} else if (!std::strcmp(lower+dot, ".txt")) {
|
||||
return typeTXT;
|
||||
} else {
|
||||
return typeUNKNOWN;
|
||||
std::string_view file_ext = filename.substr(filename.length() - ext.length());
|
||||
for (std::size_t i = 0; i < ext.length(); ++i) {
|
||||
if (std::tolower(static_cast<unsigned char>(file_ext[i])) !=
|
||||
std::tolower(static_cast<unsigned char>(ext[i]))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// main function
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
@@ -111,34 +74,33 @@ int main(int argc, char** argv) {
|
||||
char error[1000];
|
||||
|
||||
// print help if arguments are missing
|
||||
if (argc!=3 && argc!=2) {
|
||||
return finish(helpstring, EXIT_FAILURE);
|
||||
if (argc != 3 && argc != 2) {
|
||||
return finish(kHelp, EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// determine file types
|
||||
int type1 = filetype(argv[1]);
|
||||
int type2 = argc==2 ? typeNONE : filetype(argv[2]);
|
||||
const bool is_mjb = HasExtension(argv[1], ".mjb");
|
||||
|
||||
// check types
|
||||
if (type1 == typeUNKNOWN || type1 == typeTXT ||
|
||||
type2 == typeUNKNOWN || (type1 == typeMJB && type2 == typeXML)) {
|
||||
return finish("Illegal combination of file formats", EXIT_FAILURE);
|
||||
if (is_mjb && argc == 3 && HasExtension(argv[2], ".xml")) {
|
||||
return finish("Illegal combination: cannot save binary model to XML",
|
||||
EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// check if output file exists
|
||||
std::FILE* fp = std::fopen(argv[2], "r");
|
||||
if (fp) {
|
||||
std::cout << "Output file already exists, overwrite? (Y/n) ";
|
||||
char c;
|
||||
std::cin >> c;
|
||||
if (c!='y' && c!='Y') {
|
||||
if (argc == 3) {
|
||||
std::FILE* fp = std::fopen(argv[2], "r");
|
||||
if (fp) {
|
||||
std::fclose(fp);
|
||||
return finish();
|
||||
std::cout << "Output file already exists, overwrite? (Y/n) ";
|
||||
char c;
|
||||
std::cin >> c;
|
||||
if (c != 'y' && c != 'Y') {
|
||||
return finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// enable compile timing diagnostics
|
||||
if (type2 == typeNONE) {
|
||||
if (argc == 2) {
|
||||
mjLogConfig config = mju_getLogConfig();
|
||||
config.logfile[0] = '\0';
|
||||
config.topics |= (1 << (mjTOPIC_TIME_CMP - 1));
|
||||
@@ -146,50 +108,58 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
// load model
|
||||
mjSpec* s = nullptr;
|
||||
if (type1==typeXML) {
|
||||
s = mj_parseXML(argv[1], 0, error, 1000);
|
||||
if (!s) {
|
||||
return finish(error, EXIT_FAILURE);
|
||||
}
|
||||
mjVFS vfs;
|
||||
mj_defaultVFS(&vfs);
|
||||
mjSpec* spec = nullptr;
|
||||
|
||||
if (type2 == typeNONE) {
|
||||
std::cout << "Compile 1 (cold cache)\n";
|
||||
}
|
||||
m = mj_compile(s, 0);
|
||||
if (is_mjb) {
|
||||
m = mj_loadModel(argv[1], &vfs);
|
||||
if (!m) {
|
||||
mj_deleteSpec(s);
|
||||
return finish("Could not compile model", EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (type2 == typeNONE) {
|
||||
mj_deleteModel(m);
|
||||
std::cout << "Compile 2 (warm cache)\n";
|
||||
m = mj_compile(s, 0);
|
||||
return finish("Could not load binary model", EXIT_FAILURE, nullptr, &vfs);
|
||||
}
|
||||
} else {
|
||||
m = mj_loadModel(argv[1], 0);
|
||||
spec = mj_parse(argv[1], nullptr, &vfs, error, 1000);
|
||||
if (!spec) {
|
||||
return finish(error, EXIT_FAILURE, nullptr, &vfs);
|
||||
}
|
||||
|
||||
if (argc == 2) {
|
||||
std::cout << "Compile 1 (cold cache)\n";
|
||||
}
|
||||
m = mj_compile(spec, &vfs);
|
||||
if (!m) {
|
||||
auto err_msg = mjs_getError(spec);
|
||||
mj_deleteSpec(spec);
|
||||
return finish(err_msg, EXIT_FAILURE, nullptr, &vfs);
|
||||
}
|
||||
|
||||
if (argc == 2) {
|
||||
mj_deleteModel(m);
|
||||
std::cout << "Compile 2 (warm cache)\n";
|
||||
m = mj_compile(spec, &vfs);
|
||||
}
|
||||
}
|
||||
|
||||
// check error
|
||||
if (!m) {
|
||||
if (s) mj_deleteSpec(s);
|
||||
return finish("Could not load model", EXIT_FAILURE);
|
||||
if (spec) {
|
||||
auto err_msg = mjs_getError(spec);
|
||||
mj_deleteSpec(spec);
|
||||
return finish(err_msg, EXIT_FAILURE, nullptr, &vfs);
|
||||
} else {
|
||||
return finish("Could not load model", EXIT_FAILURE, nullptr, &vfs);
|
||||
}
|
||||
}
|
||||
|
||||
// save model
|
||||
if (type2 == typeXML) {
|
||||
if (!mj_saveLastXML(argv[2], m, error, 1000)) {
|
||||
if (s) mj_deleteSpec(s);
|
||||
return finish(error, EXIT_FAILURE, m);
|
||||
// encode output
|
||||
if (argc == 3) {
|
||||
if (mj_encode(spec, m, argv[2], nullptr, &vfs, error, 1000) < 0) {
|
||||
if (spec) mj_deleteSpec(spec);
|
||||
return finish(error, EXIT_FAILURE, m, &vfs);
|
||||
}
|
||||
} else if (type2 == typeMJB) {
|
||||
mj_saveModel(m, argv[2], 0, 0);
|
||||
} else if (type2 == typeTXT) {
|
||||
mj_printModel(m, argv[2]);
|
||||
}
|
||||
|
||||
// finalize
|
||||
if (s) mj_deleteSpec(s);
|
||||
return finish("Done.", EXIT_SUCCESS, m);
|
||||
if (spec) mj_deleteSpec(spec);
|
||||
return finish("Done.", EXIT_SUCCESS, m, &vfs);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user