Restructure mjCMesh for caching.
PiperOrigin-RevId: 662496475 Change-Id: I4c3a58a63ef2c3b1196b3e6b30eb556b5528ff7f
This commit is contained in:
committed by
Copybara-Service
parent
4ebf381b4d
commit
39896f8064
@@ -932,13 +932,13 @@ bool mjCFlexcomp::MakeMesh(mjCModel* model, char* error, int error_sz) {
|
|||||||
// LoadOBJ uses userXXX, extra processing needed
|
// LoadOBJ uses userXXX, extra processing needed
|
||||||
if (isobj) {
|
if (isobj) {
|
||||||
// check sizes
|
// check sizes
|
||||||
if (mesh.vert_.empty() || mesh.face_.empty()) {
|
if (mesh.Vert().empty() || mesh.Face().empty()) {
|
||||||
return comperr(error, "Vertex and face data required", error_sz);
|
return comperr(error, "Vertex and face data required", error_sz);
|
||||||
}
|
}
|
||||||
if (mesh.vert_.size()%3) {
|
if (mesh.Vert().size()%3) {
|
||||||
return comperr(error, "Vertex data must be multiple of 3", error_sz);
|
return comperr(error, "Vertex data must be multiple of 3", error_sz);
|
||||||
}
|
}
|
||||||
if (mesh.face_.size()%3) {
|
if (mesh.Face().size()%3) {
|
||||||
return comperr(error, "Face data must be multiple of 3", error_sz);
|
return comperr(error, "Face data must be multiple of 3", error_sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -947,12 +947,12 @@ bool mjCFlexcomp::MakeMesh(mjCModel* model, char* error, int error_sz) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// copy faces
|
// copy faces
|
||||||
element = mesh.face_;
|
element = mesh.Face();
|
||||||
|
|
||||||
// copy vertices, convert from float to double
|
// copy vertices, convert from float to double
|
||||||
point = vector<double> (mesh.nvert()*3);
|
point = vector<double> (mesh.nvert()*3);
|
||||||
for (int i=0; i < mesh.nvert()*3; i++) {
|
for (int i=0; i < mesh.nvert()*3; i++) {
|
||||||
point[i] = (double) mesh.vert_[i];
|
point[i] = (double) mesh.Vert(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
+33
-32
@@ -22,6 +22,7 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -249,12 +250,6 @@ mjCMesh::~mjCMesh() {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void mjCMesh::set_needhull(bool needhull) {
|
|
||||||
needhull_ = needhull;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// generate mesh using marching cubes
|
// generate mesh using marching cubes
|
||||||
void mjCMesh::LoadSDF() {
|
void mjCMesh::LoadSDF() {
|
||||||
if (plugin_name.empty() && plugin_instance_name.empty()) {
|
if (plugin_name.empty() && plugin_instance_name.empty()) {
|
||||||
@@ -338,8 +333,10 @@ void mjCMesh::LoadSDF() {
|
|||||||
delete[] field;
|
delete[] field;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mjCMesh::CacheOBJ(mjCCache* cache, const mjResource* resource) {
|
void mjCMesh::CacheMesh(mjCCache* cache, const mjResource* resource,
|
||||||
|
std::string_view asset_type) {
|
||||||
if (cache == nullptr) return;
|
if (cache == nullptr) return;
|
||||||
|
if (asset_type != "model/obj") return; // only OBJ files are cached
|
||||||
|
|
||||||
// cache mesh data into new mesh object
|
// cache mesh data into new mesh object
|
||||||
mjCMesh *mesh = new mjCMesh();
|
mjCMesh *mesh = new mjCMesh();
|
||||||
@@ -379,6 +376,8 @@ void mjCMesh::Compile(const mjVFS* vfs) {
|
|||||||
CopyFromSpec();
|
CopyFromSpec();
|
||||||
visual_ = true;
|
visual_ = true;
|
||||||
std::string asset_type = GetAssetContentType(file_, content_type_);
|
std::string asset_type = GetAssetContentType(file_, content_type_);
|
||||||
|
mjResource* resource = nullptr;
|
||||||
|
mjCCache *cache = reinterpret_cast<mjCCache*>(mj_globalCache());
|
||||||
|
|
||||||
// load file
|
// load file
|
||||||
if (!file_.empty()) {
|
if (!file_.empty()) {
|
||||||
@@ -404,25 +403,30 @@ void mjCMesh::Compile(const mjVFS* vfs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string filename = mjuu_combinePaths(model->meshdir_, file_);
|
std::string filename = mjuu_combinePaths(model->meshdir_, file_);
|
||||||
mjResource* resource = LoadResource(model->modelfiledir_, filename, vfs);
|
resource = LoadResource(model->modelfiledir_, filename, vfs);
|
||||||
|
|
||||||
try {
|
// try loading from cache
|
||||||
if (asset_type == "model/stl") {
|
if (cache != nullptr && LoadCachedMesh(cache, resource)) {
|
||||||
LoadSTL(resource);
|
mju_closeResource(resource);
|
||||||
} else if (asset_type == "model/obj") {
|
resource = nullptr;
|
||||||
// try loading from cache
|
}
|
||||||
mjCCache *cache = reinterpret_cast<mjCCache*>(mj_globalCache());
|
|
||||||
if (!cache || !LoadCachedOBJ(cache, resource)) {
|
if (resource != nullptr) {
|
||||||
|
try {
|
||||||
|
if (asset_type == "model/stl") {
|
||||||
|
LoadSTL(resource);
|
||||||
|
} else if (asset_type == "model/obj"){
|
||||||
LoadOBJ(resource);
|
LoadOBJ(resource);
|
||||||
CacheOBJ(cache, resource);
|
} else {
|
||||||
|
LoadMSH(resource);
|
||||||
}
|
}
|
||||||
} else {
|
} catch (mjCError err) {
|
||||||
LoadMSH(resource);
|
mju_closeResource(resource);
|
||||||
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CacheMesh(cache, resource, asset_type);
|
||||||
mju_closeResource(resource);
|
mju_closeResource(resource);
|
||||||
} catch (mjCError err) {
|
|
||||||
mju_closeResource(resource);
|
|
||||||
throw err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check repeated mesh data
|
// check repeated mesh data
|
||||||
@@ -456,19 +460,16 @@ void mjCMesh::Compile(const mjVFS* vfs) {
|
|||||||
} else if (facetexcoord_.empty()) {
|
} else if (facetexcoord_.empty()) {
|
||||||
facetexcoord_ = spec_facetexcoord_;
|
facetexcoord_ = spec_facetexcoord_;
|
||||||
}
|
}
|
||||||
}
|
} else if (plugin.active) {
|
||||||
|
LoadSDF(); // create using marching cubes
|
||||||
// create using marching cubes
|
|
||||||
else if (plugin.active) {
|
|
||||||
LoadSDF();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check sizes
|
// check sizes
|
||||||
if (vert_.size()<12) throw mjCError(this, "at least 4 vertices required");
|
if (vert_.size() < 12) throw mjCError(this, "at least 4 vertices required");
|
||||||
if (vert_.size()%3) throw mjCError(this, "vertex data must be a multiple of 3");
|
if (vert_.size() % 3) throw mjCError(this, "vertex data must be a multiple of 3");
|
||||||
if (normal_.size()%3) throw mjCError(this, "normal data must be a multiple of 3");
|
if (normal_.size() % 3) throw mjCError(this, "normal data must be a multiple of 3");
|
||||||
if (texcoord_.size()%2) throw mjCError(this, "texcoord must be a multiple of 2");
|
if (texcoord_.size() % 2) throw mjCError(this, "texcoord must be a multiple of 2");
|
||||||
if (face_.size()%3) throw mjCError(this, "face data must be a multiple of 3");
|
if (face_.size() % 3) throw mjCError(this, "face data must be a multiple of 3");
|
||||||
|
|
||||||
// check texcoord size if no face texcoord indices are given
|
// check texcoord size if no face texcoord indices are given
|
||||||
if (!texcoord_.empty() && texcoord_.size() != 2 * nvert() &&
|
if (!texcoord_.empty() && texcoord_.size() != 2 * nvert() &&
|
||||||
@@ -981,7 +982,7 @@ void mjCMesh::LoadOBJ(mjResource* resource) {
|
|||||||
|
|
||||||
|
|
||||||
// load OBJ from cached asset, return true on success
|
// load OBJ from cached asset, return true on success
|
||||||
bool mjCMesh::LoadCachedOBJ(mjCCache *cache, const mjResource* resource) {
|
bool mjCMesh::LoadCachedMesh(mjCCache *cache, const mjResource* resource) {
|
||||||
// check that asset has all data
|
// check that asset has all data
|
||||||
if (!cache->PopulateData(resource, [&](const void* data) {
|
if (!cache->PopulateData(resource, [&](const void* data) {
|
||||||
const mjCMesh* mesh = static_cast<const mjCMesh*>(data);
|
const mjCMesh* mesh = static_cast<const mjCMesh*>(data);
|
||||||
|
|||||||
@@ -1310,7 +1310,7 @@ void mjCModel::SetDefaultNames(std::vector<T*>& assets) {
|
|||||||
for (int i=0; i<assets.size(); i++) {
|
for (int i=0; i<assets.size(); i++) {
|
||||||
assets[i]->CopyFromSpec();
|
assets[i]->CopyFromSpec();
|
||||||
if (assets[i]->name.empty()) {
|
if (assets[i]->name.empty()) {
|
||||||
stripped = mjuu_strippath(assets[i]->get_file());
|
stripped = mjuu_strippath(assets[i]->File());
|
||||||
assets[i]->name = mjuu_stripext(stripped);
|
assets[i]->name = mjuu_stripext(stripped);
|
||||||
names[assets[i]->name].push_back(i);
|
names[assets[i]->name].push_back(i);
|
||||||
}
|
}
|
||||||
@@ -1365,8 +1365,8 @@ template <typename T>
|
|||||||
static size_t getpathslength(std::vector<T> list) {
|
static size_t getpathslength(std::vector<T> list) {
|
||||||
size_t result = 0;
|
size_t result = 0;
|
||||||
for (const auto& element : list) {
|
for (const auto& element : list) {
|
||||||
if (!element->get_file().empty()) {
|
if (!element->File().empty()) {
|
||||||
result += element->get_file().length() + 1;
|
result += element->File().length() + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1827,10 +1827,10 @@ template <class T>
|
|||||||
static int pathlist(vector<T*>& list, int adr, int* path_adr, char* paths) {
|
static int pathlist(vector<T*>& list, int adr, int* path_adr, char* paths) {
|
||||||
for (unsigned int i = 0; i < list.size(); ++i) {
|
for (unsigned int i = 0; i < list.size(); ++i) {
|
||||||
path_adr[i] = -1;
|
path_adr[i] = -1;
|
||||||
if (!list[i] || list[i]->get_file().empty()) {
|
if (!list[i] || list[i]->File().empty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
adr = addtolist(list[i]->get_file(), adr, &path_adr[i], paths);
|
adr = addtolist(list[i]->File(), adr, &path_adr[i], paths);
|
||||||
}
|
}
|
||||||
|
|
||||||
return adr;
|
return adr;
|
||||||
@@ -2310,7 +2310,7 @@ void mjCModel::CopyObjects(mjModel* m) {
|
|||||||
m->mesh_graphadr[i] = (pme->szgraph() ? graph_adr : -1);
|
m->mesh_graphadr[i] = (pme->szgraph() ? graph_adr : -1);
|
||||||
m->mesh_bvhnum[i] = pme->tree().Nbvh();
|
m->mesh_bvhnum[i] = pme->tree().Nbvh();
|
||||||
m->mesh_bvhadr[i] = pme->tree().Nbvh() ? bvh_adr : -1;
|
m->mesh_bvhadr[i] = pme->tree().Nbvh() ? bvh_adr : -1;
|
||||||
mjuu_copyvec(&m->mesh_scale[3 * i], pme->get_scale(), 3);
|
mjuu_copyvec(&m->mesh_scale[3 * i], pme->Scale(), 3);
|
||||||
mjuu_copyvec(&m->mesh_pos[3 * i], pme->GetOffsetPosPtr(), 3);
|
mjuu_copyvec(&m->mesh_pos[3 * i], pme->GetOffsetPosPtr(), 3);
|
||||||
mjuu_copyvec(&m->mesh_quat[4 * i], pme->GetOffsetQuatPtr(), 4);
|
mjuu_copyvec(&m->mesh_quat[4 * i], pme->GetOffsetQuatPtr(), 4);
|
||||||
|
|
||||||
@@ -3466,7 +3466,7 @@ void mjCModel::TryCompile(mjModel*& m, mjData*& d, const mjVFS* vfs) {
|
|||||||
if (geoms_[i]->mesh &&
|
if (geoms_[i]->mesh &&
|
||||||
(geoms_[i]->spec.type==mjGEOM_MESH || geoms_[i]->spec.type==mjGEOM_SDF) &&
|
(geoms_[i]->spec.type==mjGEOM_MESH || geoms_[i]->spec.type==mjGEOM_SDF) &&
|
||||||
(geoms_[i]->spec.contype || geoms_[i]->spec.conaffinity)) {
|
(geoms_[i]->spec.contype || geoms_[i]->spec.conaffinity)) {
|
||||||
geoms_[i]->mesh->set_needhull(true);
|
geoms_[i]->mesh->SetNeedHull(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+38
-34
@@ -788,9 +788,6 @@ class mjCMesh_ : public mjCBase {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class mjCMesh: public mjCMesh_, private mjsMesh {
|
class mjCMesh: public mjCMesh_, private mjsMesh {
|
||||||
friend class mjCModel;
|
|
||||||
friend class mjCFlexcomp;
|
|
||||||
friend class mjXWriter;
|
|
||||||
public:
|
public:
|
||||||
mjCMesh(mjCModel* = nullptr, mjCDef* = nullptr);
|
mjCMesh(mjCModel* = nullptr, mjCDef* = nullptr);
|
||||||
mjCMesh(const mjCMesh& other);
|
mjCMesh(const mjCMesh& other);
|
||||||
@@ -804,20 +801,24 @@ class mjCMesh: public mjCMesh_, private mjsMesh {
|
|||||||
void CopyFromSpec(void);
|
void CopyFromSpec(void);
|
||||||
void PointToLocal(void);
|
void PointToLocal(void);
|
||||||
|
|
||||||
// public getters and setters
|
// accessors
|
||||||
const std::string& get_content_type() const { return content_type_; }
|
const mjsPlugin& Plugin() const { return plugin; }
|
||||||
const std::string& get_file() const { return file_; }
|
const std::string& ContentType() const { return content_type_; }
|
||||||
const double* get_refpos() const { return refpos; }
|
const std::string& File() const { return file_; }
|
||||||
const double* get_refquat() const { return refquat; }
|
const double* Refpos() const { return refpos; }
|
||||||
const double* get_scale() const { return scale; }
|
const double* Refquat() const { return refquat; }
|
||||||
bool get_smoothnormal() const { return smoothnormal; }
|
const double* Scale() const { return scale; }
|
||||||
void set_needhull(bool needhull);
|
bool SmoothNormal() const { return smoothnormal; }
|
||||||
|
const std::vector<float>& Vert() const { return vert_; }
|
||||||
|
float Vert(int i) const { return vert_[i]; }
|
||||||
|
const std::vector<float>& UserVert() const { return spec_vert_; }
|
||||||
|
const std::vector<float>& UserNormal() const { return spec_normal_; }
|
||||||
|
const std::vector<float>& UserTexcoord() const { return spec_texcoord_; }
|
||||||
|
const std::vector<int>& Face() const { return face_; }
|
||||||
|
const std::vector<int>& UserFace() const { return spec_face_; }
|
||||||
|
|
||||||
// public getters for user data
|
// setters
|
||||||
const std::vector<float>& get_uservert() const { return spec_vert_; }
|
void SetNeedHull(bool needhull) { needhull_ = needhull; }
|
||||||
const std::vector<float>& get_usernormal() const { return spec_normal_; }
|
|
||||||
const std::vector<float>& get_usertexcoord() const { return spec_texcoord_; }
|
|
||||||
const std::vector<int>& get_userface() const { return spec_face_; }
|
|
||||||
|
|
||||||
// mesh properties computed by Compile
|
// mesh properties computed by Compile
|
||||||
const double* aamm() const { return aamm_; }
|
const double* aamm() const { return aamm_; }
|
||||||
@@ -858,23 +859,27 @@ class mjCMesh: public mjCMesh_, private mjsMesh {
|
|||||||
// sets properties of a bounding volume given a face id
|
// sets properties of a bounding volume given a face id
|
||||||
void SetBoundingVolume(int faceid);
|
void SetBoundingVolume(int faceid);
|
||||||
|
|
||||||
|
void LoadOBJ(mjResource* resource); // load mesh in wavefront OBJ format
|
||||||
|
void LoadSTL(mjResource* resource); // load mesh in STL BIN format
|
||||||
|
void LoadMSH(mjResource* resource); // load mesh in MSH BIN format
|
||||||
|
|
||||||
|
void RemoveRepeated(); // remove repeated vertices
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void LoadOBJ(mjResource* resource); // load mesh in wavefront OBJ format
|
// load mesh from cache asset, return true on success (OBJ files are only supported)
|
||||||
// load OBJ from cache asset, return true on success
|
bool LoadCachedMesh(mjCCache *cache, const mjResource* resource);
|
||||||
bool LoadCachedOBJ(mjCCache *cache, const mjResource* resource);
|
// store mesh into asset cache (OBJ files are only supported)
|
||||||
// put OBJ into asset cache
|
void CacheMesh(mjCCache *cache, const mjResource* resource,
|
||||||
void CacheOBJ(mjCCache *cache, const mjResource* resource);
|
std::string_view asset_type);
|
||||||
void LoadSTL(mjResource* resource); // load mesh in STL BIN format
|
|
||||||
void LoadMSH(mjResource* resource); // load mesh in MSH BIN format
|
|
||||||
void LoadSDF(); // generate mesh using marching cubes
|
void LoadSDF(); // generate mesh using marching cubes
|
||||||
void MakeGraph(void); // make graph of convex hull
|
void MakeGraph(); // make graph of convex hull
|
||||||
void CopyGraph(void); // copy graph into face data
|
void CopyGraph(); // copy graph into face data
|
||||||
void MakeNormal(void); // compute vertex normals
|
void MakeNormal(); // compute vertex normals
|
||||||
void MakeCenter(void); // compute face circumcircle data
|
void MakeCenter(); // compute face circumcircle data
|
||||||
void Process(); // compute inertial properties
|
void Process(); // compute inertial properties
|
||||||
void ApplyTransformations(); // apply user transformations
|
void ApplyTransformations(); // apply user transformations
|
||||||
void ComputeFaceCentroid(double[3]); // compute centroid of all faces
|
void ComputeFaceCentroid(double[3]); // compute centroid of all faces
|
||||||
void RemoveRepeated(void); // remove repeated vertices
|
|
||||||
void CheckMesh(mjtGeomInertia type); // check if the mesh is valid
|
void CheckMesh(mjtGeomInertia type); // check if the mesh is valid
|
||||||
|
|
||||||
// mesh data to be copied into mjModel
|
// mesh data to be copied into mjModel
|
||||||
@@ -940,7 +945,7 @@ class mjCSkin: public mjCSkin_, private mjsSkin {
|
|||||||
using mjCBase::name;
|
using mjCBase::name;
|
||||||
using mjCBase::info;
|
using mjCBase::info;
|
||||||
|
|
||||||
const std::string& get_file() const { return file_; }
|
const std::string& File() const { return file_; }
|
||||||
const std::string& get_material() const { return material_; }
|
const std::string& get_material() const { return material_; }
|
||||||
const std::vector<float>& get_vert() const { return vert_; }
|
const std::vector<float>& get_vert() const { return vert_; }
|
||||||
const std::vector<float>& get_texcoord() const { return texcoord_; }
|
const std::vector<float>& get_texcoord() const { return texcoord_; }
|
||||||
@@ -997,7 +1002,7 @@ class mjCHField : public mjCHField_, private mjsHField {
|
|||||||
void CopyFromSpec(void);
|
void CopyFromSpec(void);
|
||||||
void PointToLocal(void);
|
void PointToLocal(void);
|
||||||
|
|
||||||
std::string get_file() const { return file_; }
|
std::string File() const { return file_; }
|
||||||
|
|
||||||
// getter for user data
|
// getter for user data
|
||||||
std::vector<float>& get_userdata() { return userdata_; }
|
std::vector<float>& get_userdata() { return userdata_; }
|
||||||
@@ -1044,7 +1049,7 @@ class mjCTexture : public mjCTexture_, private mjsTexture {
|
|||||||
void CopyFromSpec(void);
|
void CopyFromSpec(void);
|
||||||
void PointToLocal(void);
|
void PointToLocal(void);
|
||||||
|
|
||||||
std::string get_file() const { return file_; }
|
std::string File() const { return file_; }
|
||||||
std::string get_content_type() const { return content_type_; }
|
std::string get_content_type() const { return content_type_; }
|
||||||
std::vector<std::string> get_cubefiles() const { return cubefiles_; }
|
std::vector<std::string> get_cubefiles() const { return cubefiles_; }
|
||||||
|
|
||||||
@@ -1194,13 +1199,12 @@ class mjCBodyPair : public mjCBodyPair_, private mjsExclude {
|
|||||||
std::string get_bodyname1() const { return bodyname1_; }
|
std::string get_bodyname1() const { return bodyname1_; }
|
||||||
std::string get_bodyname2() const { return bodyname2_; }
|
std::string get_bodyname2() const { return bodyname2_; }
|
||||||
|
|
||||||
int GetSignature(void) {
|
int GetSignature() {
|
||||||
return signature;
|
return signature;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void Compile(); // compiler
|
||||||
void Compile(void); // compiler
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -39,8 +39,6 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
using std::size_t;
|
|
||||||
using std::string;
|
|
||||||
using tinyxml2::XMLComment;
|
using tinyxml2::XMLComment;
|
||||||
using tinyxml2::XMLDocument;
|
using tinyxml2::XMLDocument;
|
||||||
using tinyxml2::XMLElement;
|
using tinyxml2::XMLElement;
|
||||||
@@ -64,7 +62,7 @@ class mj_XMLPrinter : public tinyxml2::XMLPrinter {
|
|||||||
|
|
||||||
|
|
||||||
// save XML file using custom 2-space indentation
|
// save XML file using custom 2-space indentation
|
||||||
static string WriteDoc(XMLDocument& doc, char *error, size_t error_sz) {
|
static std::string WriteDoc(XMLDocument& doc, char *error, size_t error_sz) {
|
||||||
doc.ClearError();
|
doc.ClearError();
|
||||||
mj_XMLPrinter stream(nullptr, /*compact=*/false);
|
mj_XMLPrinter stream(nullptr, /*compact=*/false);
|
||||||
doc.Print(&stream);
|
doc.Print(&stream);
|
||||||
@@ -72,7 +70,7 @@ static string WriteDoc(XMLDocument& doc, char *error, size_t error_sz) {
|
|||||||
mjCopyError(error, doc.ErrorStr(), error_sz);
|
mjCopyError(error, doc.ErrorStr(), error_sz);
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
std::string str = string(stream.CStr());
|
std::string str = std::string(stream.CStr());
|
||||||
|
|
||||||
// top level sections
|
// top level sections
|
||||||
std::array<std::string, 17> sections = {
|
std::array<std::string, 17> sections = {
|
||||||
@@ -86,10 +84,10 @@ static string WriteDoc(XMLDocument& doc, char *error, size_t error_sz) {
|
|||||||
|
|
||||||
// insert newlines before section headers
|
// insert newlines before section headers
|
||||||
for (const std::string& section : sections) {
|
for (const std::string& section : sections) {
|
||||||
size_t pos = 0;
|
std::size_t pos = 0;
|
||||||
while ((pos = str.find(section, pos)) != std::string::npos) {
|
while ((pos = str.find(section, pos)) != std::string::npos) {
|
||||||
// find newline before this section
|
// find newline before this section
|
||||||
size_t line_pos = str.rfind('\n', pos);
|
std::size_t line_pos = str.rfind('\n', pos);
|
||||||
|
|
||||||
// save position of first section
|
// save position of first section
|
||||||
if (line_pos < first_pos) first_pos = line_pos;
|
if (line_pos < first_pos) first_pos = line_pos;
|
||||||
@@ -127,7 +125,7 @@ XMLElement* mjXWriter::InsertEnd(XMLElement* parent, const char* name) {
|
|||||||
|
|
||||||
// write flex
|
// write flex
|
||||||
void mjXWriter::OneFlex(XMLElement* elem, const mjCFlex* pflex) {
|
void mjXWriter::OneFlex(XMLElement* elem, const mjCFlex* pflex) {
|
||||||
string text;
|
std::string text;
|
||||||
mjCFlex defflex;
|
mjCFlex defflex;
|
||||||
|
|
||||||
// common attributes
|
// common attributes
|
||||||
@@ -195,7 +193,7 @@ void mjXWriter::OneFlex(XMLElement* elem, const mjCFlex* pflex) {
|
|||||||
|
|
||||||
// write mesh
|
// write mesh
|
||||||
void mjXWriter::OneMesh(XMLElement* elem, const mjCMesh* pmesh, mjCDef* def) {
|
void mjXWriter::OneMesh(XMLElement* elem, const mjCMesh* pmesh, mjCDef* def) {
|
||||||
string text;
|
std::string text;
|
||||||
|
|
||||||
// regular
|
// regular
|
||||||
if (!writingdefaults) {
|
if (!writingdefaults) {
|
||||||
@@ -203,60 +201,60 @@ void mjXWriter::OneMesh(XMLElement* elem, const mjCMesh* pmesh, mjCDef* def) {
|
|||||||
if (pmesh->classname != "main") {
|
if (pmesh->classname != "main") {
|
||||||
WriteAttrTxt(elem, "class", pmesh->classname);
|
WriteAttrTxt(elem, "class", pmesh->classname);
|
||||||
}
|
}
|
||||||
WriteAttrTxt(elem, "content_type", pmesh->get_content_type());
|
WriteAttrTxt(elem, "content_type", pmesh->ContentType());
|
||||||
WriteAttrTxt(elem, "file", pmesh->get_file());
|
WriteAttrTxt(elem, "file", pmesh->File());
|
||||||
|
|
||||||
// write vertex data
|
// write vertex data
|
||||||
if (!pmesh->get_uservert().empty()) {
|
if (!pmesh->UserVert().empty()) {
|
||||||
text = VectorToString(pmesh->get_uservert());
|
text = VectorToString(pmesh->UserVert());
|
||||||
WriteAttrTxt(elem, "vertex", text);
|
WriteAttrTxt(elem, "vertex", text);
|
||||||
}
|
}
|
||||||
|
|
||||||
// write normal data
|
// write normal data
|
||||||
if (!pmesh->get_usernormal().empty()) {
|
if (!pmesh->UserNormal().empty()) {
|
||||||
text = VectorToString(pmesh->get_usernormal());
|
text = VectorToString(pmesh->UserNormal());
|
||||||
WriteAttrTxt(elem, "normal", text);
|
WriteAttrTxt(elem, "normal", text);
|
||||||
}
|
}
|
||||||
|
|
||||||
// write texcoord data
|
// write texcoord data
|
||||||
if (!pmesh->get_usertexcoord().empty()) {
|
if (!pmesh->UserTexcoord().empty()) {
|
||||||
text = VectorToString(pmesh->get_usertexcoord());
|
text = VectorToString(pmesh->UserTexcoord());
|
||||||
WriteAttrTxt(elem, "texcoord", text);
|
WriteAttrTxt(elem, "texcoord", text);
|
||||||
}
|
}
|
||||||
|
|
||||||
// write face data
|
// write face data
|
||||||
if (!pmesh->get_userface().empty()) {
|
if (!pmesh->UserFace().empty()) {
|
||||||
text = VectorToString(pmesh->get_userface());
|
text = VectorToString(pmesh->UserFace());
|
||||||
WriteAttrTxt(elem, "face", text);
|
WriteAttrTxt(elem, "face", text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// defaults and regular
|
// defaults and regular
|
||||||
WriteAttr(elem, "refpos", 3, pmesh->refpos, def->Mesh().refpos);
|
WriteAttr(elem, "refpos", 3, pmesh->Refpos(), def->Mesh().Refpos());
|
||||||
WriteAttr(elem, "refquat", 4, pmesh->refquat, def->Mesh().refquat);
|
WriteAttr(elem, "refquat", 4, pmesh->Refquat(), def->Mesh().Refquat());
|
||||||
WriteAttr(elem, "scale", 3, pmesh->scale, def->Mesh().scale);
|
WriteAttr(elem, "scale", 3, pmesh->Scale(), def->Mesh().Scale());
|
||||||
WriteAttrKey(elem, "smoothnormal", bool_map, 2, pmesh->get_smoothnormal(),
|
WriteAttrKey(elem, "smoothnormal", bool_map, 2, pmesh->SmoothNormal(),
|
||||||
def->Mesh().get_smoothnormal());
|
def->Mesh().SmoothNormal());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// write skin
|
// write skin
|
||||||
void mjXWriter::OneSkin(XMLElement* elem, const mjCSkin* pskin) {
|
void mjXWriter::OneSkin(XMLElement* elem, const mjCSkin* pskin) {
|
||||||
string text;
|
std::string text;
|
||||||
mjCDef mydef;
|
mjCDef mydef;
|
||||||
float zero = 0;
|
float zero = 0;
|
||||||
|
|
||||||
// write attributes
|
// write attributes
|
||||||
WriteAttrTxt(elem, "name", pskin->name);
|
WriteAttrTxt(elem, "name", pskin->name);
|
||||||
WriteAttrTxt(elem, "file", pskin->get_file());
|
WriteAttrTxt(elem, "file", pskin->File());
|
||||||
WriteAttrTxt(elem, "material", pskin->get_material());
|
WriteAttrTxt(elem, "material", pskin->get_material());
|
||||||
WriteAttrInt(elem, "group", pskin->group, 0);
|
WriteAttrInt(elem, "group", pskin->group, 0);
|
||||||
WriteAttr(elem, "rgba", 4, pskin->rgba, mydef.Geom().rgba);
|
WriteAttr(elem, "rgba", 4, pskin->rgba, mydef.Geom().rgba);
|
||||||
WriteAttr(elem, "inflate", 1, &pskin->inflate, &zero);
|
WriteAttr(elem, "inflate", 1, &pskin->inflate, &zero);
|
||||||
|
|
||||||
// write data if no file
|
// write data if no file
|
||||||
if (pskin->get_file().empty()) {
|
if (pskin->File().empty()) {
|
||||||
// mesh vert
|
// mesh vert
|
||||||
text = VectorToString(pskin->get_vert());
|
text = VectorToString(pskin->get_vert());
|
||||||
WriteAttrTxt(elem, "vertex", text);
|
WriteAttrTxt(elem, "vertex", text);
|
||||||
@@ -846,7 +844,7 @@ void mjXWriter::SetModel(const mjSpec* spec) {
|
|||||||
|
|
||||||
|
|
||||||
// save existing model in MJCF canonical format, must be compiled
|
// save existing model in MJCF canonical format, must be compiled
|
||||||
string mjXWriter::Write(char *error, size_t error_sz) {
|
std::string mjXWriter::Write(char *error, size_t error_sz) {
|
||||||
// check model
|
// check model
|
||||||
if (!model || !model->IsCompiled()) {
|
if (!model || !model->IsCompiled()) {
|
||||||
mjCopyError(error, "XML Write error: Only compiled model can be written", error_sz);
|
mjCopyError(error, "XML Write error: Only compiled model can be written", error_sz);
|
||||||
@@ -862,7 +860,7 @@ string mjXWriter::Write(char *error, size_t error_sz) {
|
|||||||
doc.InsertFirstChild(root);
|
doc.InsertFirstChild(root);
|
||||||
|
|
||||||
// write comment if present
|
// write comment if present
|
||||||
string text = mjs_getString(model->comment);
|
std::string text = mjs_getString(model->comment);
|
||||||
if (!text.empty()) {
|
if (!text.empty()) {
|
||||||
XMLComment* comment = doc.NewComment(text.c_str());
|
XMLComment* comment = doc.NewComment(text.c_str());
|
||||||
root->LinkEndChild(comment);
|
root->LinkEndChild(comment);
|
||||||
@@ -1456,7 +1454,7 @@ void mjXWriter::Asset(XMLElement* root) {
|
|||||||
else if (ptex->get_cubefiles()[0].empty() && ptex->get_cubefiles()[1].empty() &&
|
else if (ptex->get_cubefiles()[0].empty() && ptex->get_cubefiles()[1].empty() &&
|
||||||
ptex->get_cubefiles()[2].empty() && ptex->get_cubefiles()[3].empty() &&
|
ptex->get_cubefiles()[2].empty() && ptex->get_cubefiles()[3].empty() &&
|
||||||
ptex->get_cubefiles()[4].empty() && ptex->get_cubefiles()[5].empty() &&
|
ptex->get_cubefiles()[4].empty() && ptex->get_cubefiles()[5].empty() &&
|
||||||
ptex->get_file().empty() && ptex->gridsize[0] == 1 && ptex->gridsize[1] == 1) {
|
ptex->File().empty() && ptex->gridsize[0] == 1 && ptex->gridsize[1] == 1) {
|
||||||
throw mjXError(0, "no support for buffer textures.");
|
throw mjXError(0, "no support for buffer textures.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1464,7 +1462,7 @@ void mjXWriter::Asset(XMLElement* root) {
|
|||||||
else {
|
else {
|
||||||
// write single file
|
// write single file
|
||||||
WriteAttrTxt(elem, "content_type", ptex->get_content_type());
|
WriteAttrTxt(elem, "content_type", ptex->get_content_type());
|
||||||
WriteAttrTxt(elem, "file", ptex->get_file());
|
WriteAttrTxt(elem, "file", ptex->File());
|
||||||
|
|
||||||
// write separate files
|
// write separate files
|
||||||
WriteAttrTxt(elem, "fileright", ptex->get_cubefiles()[0]);
|
WriteAttrTxt(elem, "fileright", ptex->get_cubefiles()[0]);
|
||||||
@@ -1501,10 +1499,10 @@ void mjXWriter::Asset(XMLElement* root) {
|
|||||||
for (int i=0; i<nmesh; i++) {
|
for (int i=0; i<nmesh; i++) {
|
||||||
// create element and write
|
// create element and write
|
||||||
mjCMesh* pmesh = (mjCMesh*)model->GetObject(mjOBJ_MESH, i);
|
mjCMesh* pmesh = (mjCMesh*)model->GetObject(mjOBJ_MESH, i);
|
||||||
if (pmesh->plugin.active) {
|
if (pmesh->Plugin().active) {
|
||||||
elem = InsertEnd(section, "mesh");
|
elem = InsertEnd(section, "mesh");
|
||||||
WriteAttrTxt(elem, "name", pmesh->name);
|
WriteAttrTxt(elem, "name", pmesh->name);
|
||||||
OnePlugin(InsertEnd(elem, "plugin"), &pmesh->plugin);
|
OnePlugin(InsertEnd(elem, "plugin"), &pmesh->Plugin());
|
||||||
} else{
|
} else{
|
||||||
elem = InsertEnd(section, "mesh");
|
elem = InsertEnd(section, "mesh");
|
||||||
OneMesh(elem, pmesh, model->def_map[pmesh->classname]);
|
OneMesh(elem, pmesh, model->def_map[pmesh->classname]);
|
||||||
@@ -1527,7 +1525,7 @@ void mjXWriter::Asset(XMLElement* root) {
|
|||||||
WriteAttrInt(elem, "nrow", phf->nrow);
|
WriteAttrInt(elem, "nrow", phf->nrow);
|
||||||
WriteAttrInt(elem, "ncol", phf->ncol);
|
WriteAttrInt(elem, "ncol", phf->ncol);
|
||||||
if (!phf->get_userdata().empty()) {
|
if (!phf->get_userdata().empty()) {
|
||||||
string text;
|
std::string text;
|
||||||
Vector2String(text, phf->get_userdata(), phf->ncol);
|
Vector2String(text, phf->get_userdata(), phf->ncol);
|
||||||
WriteAttrTxt(elem, "elevation", text);
|
WriteAttrTxt(elem, "elevation", text);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user