Files
Mujoco_WASM/sample/compile.cc
T
Yuval Tassa c5473d9923 Print compilation time in sample/compile, allow compilation with no output.
PiperOrigin-RevId: 735692355
Change-Id: I4371f800ec150f8d665cf164b50a0e5a0b5ac082
2025-03-11 03:25:51 -07:00

172 lines
3.9 KiB
C++

// Copyright 2021 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <chrono>
#include <cctype>
#include <cstddef>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <ratio>
#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"
" if outfile is missing no output will be generated\n\n"
" Example: compile model.xml model.mjb\n";
// timer
mjtNum gettm(void) {
using std::chrono::steady_clock;
using Microseconds = std::chrono::duration<double, std::micro>;
static steady_clock::time_point tm_start = steady_clock::now();
auto elapsed = Microseconds(steady_clock::now() - tm_start);
return elapsed.count();
}
// deallocate and print message
int finish(const char* msg = 0, mjModel* m = 0) {
// deallocated everything
if (m) {
mj_deleteModel(m);
}
// print message
if (msg) {
std::cout << msg << std::endl;
}
return 0;
}
// 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;
}
}
// main function
int main(int argc, char** argv) {
// model and error
mjModel* m = 0;
char error[1000];
// print help if arguments are missing
if (argc!=3 && argc!=2) {
return finish(helpstring);
}
// determine file types
int type1 = filetype(argv[1]);
int type2 = argc==2 ? typeNONE : filetype(argv[2]);
// check types
if (type1==typeUNKNOWN || type1==typeTXT ||
type2==typeUNKNOWN || (type1==typeMJB && type2==typeXML)) {
return finish("Illegal combination of file formats");
}
// 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') {
std::fclose(fp);
return finish();
}
}
// load model
double starttime = gettm();
if (type1==typeXML) {
m = mj_loadXML(argv[1], 0, error, 1000);
} else {
m = mj_loadModel(argv[1], 0);
}
double tottime = 1e-6 * (gettm() - starttime); // total time, in seconds
// check error
if (!m) {
if (type1==typeXML) {
return finish(error, 0);
} else {
return finish("Could not load model", 0);
}
}
// save model
if (type2==typeXML) {
if (!mj_saveLastXML(argv[2], m, error, 1000)) {
return finish(error, m);
}
} else if (type2==typeMJB) {
mj_saveModel(m, argv[2], 0, 0);
} else if (type2==typeTXT) {
mj_printModel(m, argv[2]);
}
// finalize
char msg[1000];
snprintf(msg, sizeof(msg), "Done.\nCompiled in %.3g seconds\n", tottime);
return finish(msg, m);
}