From 06589ca1c68a89ad821b5f37b25688cb040de2d6 Mon Sep 17 00:00:00 2001 From: Michael Sundqvist Date: Thu, 31 May 2018 16:07:03 +0300 Subject: [PATCH] Refactor ColladaSerializer.cpp, encode material names only once, decode them before passing to OpenCollada functions that take URI parameters --- src/ifcconvert/ColladaSerializer.cpp | 99 +++++++++++----------------- src/ifcconvert/ColladaSerializer.h | 10 ++- 2 files changed, 44 insertions(+), 65 deletions(-) diff --git a/src/ifcconvert/ColladaSerializer.cpp b/src/ifcconvert/ColladaSerializer.cpp index 9ff5171ac9..78531a2a52 100644 --- a/src/ifcconvert/ColladaSerializer.cpp +++ b/src/ifcconvert/ColladaSerializer.cpp @@ -60,11 +60,7 @@ void ColladaSerializer::ColladaExporter::ColladaGeometries::addFloatSource(const source.finish(); } -void ColladaSerializer::ColladaExporter::ColladaGeometries::write( - const std::string &mesh_id, const std::string& /*default_material_name*/, const std::vector& positions, - const std::vector& normals, const std::vector& faces, const std::vector& edges, - const std::vector material_ids, const std::vector& materials, - const std::vector& uvs) +void ColladaSerializer::ColladaExporter::ColladaGeometries::write(std::string mesh_id, std::string, std::vector positions, std::vector normals, std::vector faces, std::vector edges, std::vector material_ids, std::vector materials, std::vector uvs, std::vector material_references) { openMesh(mesh_id); @@ -101,14 +97,8 @@ void ColladaSerializer::ColladaExporter::ColladaGeometries::write( const size_t num_triangles = std::distance(index_range_start, it) / 3; if ((previous_material_id != current_material_id && num_triangles > 0) || (it == faces.end())) { COLLADASW::Triangles triangles(mSW); - std::string material_name = (serializer->settings().get(SerializerSettings::USE_MATERIAL_NAMES) - ? materials[previous_material_id].original_name() : materials[previous_material_id].name()); - if (material_name.empty()) { - material_name = "missing-material-" + materials[previous_material_id].name(); - } - - collada_id(material_name); + std::string material_name = material_references[previous_material_id]; triangles.setMaterial(material_name); triangles.setCount((unsigned long)num_triangles); int offset = 0; @@ -163,15 +153,7 @@ void ColladaSerializer::ColladaExporter::ColladaGeometries::write( for (linelist_t::const_iterator it = linelist.begin(); it != linelist.end(); ++it) { COLLADASW::Lines lines(mSW); - std::string material_name = (serializer->settings().get(SerializerSettings::USE_MATERIAL_NAMES) - ? materials[it->first].original_name() : materials[it->first].name()); - - if (material_name.empty()) { - material_name = "missing-material-" + materials[it->first].name(); - } - - collada_id(material_name); - lines.setMaterial(material_name); + lines.setMaterial(material_references[it->first]); lines.setCount((unsigned long)it->second.size()); int offset = 0; lines.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::VERTEX, "#" + mesh_id + COLLADASW::LibraryGeometries::VERTICES_ID_SUFFIX, offset)); @@ -234,11 +216,13 @@ void ColladaSerializer::ColladaExporter::ColladaScene::add( node.start(); node.addMatrix(matrix_array); COLLADASW::InstanceGeometry instanceGeometry(mSW); - instanceGeometry.setUrl ("#" + geom_name); + instanceGeometry.setUrl("#" + geom_name); BOOST_FOREACH(std::string material_name, material_ids) { - /// @todo This is done 6 times in this file, try to perform this once and be done with the material naming for the export. - collada_id(material_name); - COLLADASW::InstanceMaterial material(material_name, "#" + material_name); + // Unescape to avoid double escaping beucase OpenCollada's material URI parameter escapes XML internally + std::string unescaped = material_name; + IfcUtil::unescape_xml(unescaped); + + COLLADASW::InstanceMaterial material(material_name, "#" + unescaped); instanceGeometry.getBindMaterial().getInstanceMaterialList().push_back(material); } instanceGeometry.add(); @@ -319,17 +303,9 @@ void ColladaSerializer::ColladaExporter::ColladaScene::write() { } } -void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::write(const IfcGeom::Material& material) +void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::write(const IfcGeom::Material &material, const std::string &material_uri) { - std::string material_name = (serializer->settings().get(SerializerSettings::USE_MATERIAL_NAMES) - ? material.original_name() : material.name()); - - if (material_name.empty()) { - material_name = "missing-material-" + material.name(); - } - - collada_id(material_name); - openEffect(material_name + "-fx"); + openEffect(material_uri + "-fx"); COLLADASW::EffectProfile effect(mSW); effect.setShaderType(COLLADASW::EffectProfile::LAMBERT); if (material.hasDiffuse()) { @@ -361,11 +337,29 @@ void ColladaSerializer::ColladaExporter::ColladaMaterials::ColladaEffects::close void ColladaSerializer::ColladaExporter::ColladaMaterials::add(const IfcGeom::Material& material) { if (!contains(material)) { - effects.write(material); + std::string material_name = (serializer->settings().get(SerializerSettings::USE_MATERIAL_NAMES) + ? material.original_name() : material.name()); + + if (material_name.empty()) { + material_name = "missing-material-" + material.name(); + } + + collada_id(material_name); + + effects.write(material, material_name); materials.push_back(material); + material_uris.push_back(material_name); } } +std::string ColladaSerializer::ColladaExporter::ColladaMaterials::getMaterialUri(const IfcGeom::Material& material) { + std::vector::iterator it = std::find(materials.begin(), materials.end(), material); + long index = std::distance(materials.begin(), it); + + std::string material_uri = material_uris.at(static_cast(index)); + return material_uri; +} + bool ColladaSerializer::ColladaExporter::ColladaMaterials::contains(const IfcGeom::Material& material) { return std::find(materials.begin(), materials.end(), material) != materials.end(); } @@ -373,18 +367,13 @@ bool ColladaSerializer::ColladaExporter::ColladaMaterials::contains(const IfcGeo void ColladaSerializer::ColladaExporter::ColladaMaterials::write() { effects.close(); BOOST_FOREACH(const IfcGeom::Material& material, materials) { - std::string material_name = (serializer->settings().get(SerializerSettings::USE_MATERIAL_NAMES) - ? material.original_name() : material.name()); - - if (material_name.empty()) { - material_name = "missing-material-" + material.name(); - } - - std::string material_name_unescaped = material_name; // workaround double-escaping that would occur in addInstanceEffect() - IfcUtil::sanitate_material_name(material_name_unescaped); - collada_id(material_name); + std::string material_name = getMaterialUri(material); openMaterial(material_name); - addInstanceEffect("#" + material_name_unescaped + "-fx"); + + // Unescape to avoid double escaping beucase OpenCollada's addInstanceEffect escapes XML internally + IfcUtil::unescape_xml(material_name); + + addInstanceEffect("#" + material_name + "-fx"); closeMaterial(); } closeLibrary(); @@ -412,21 +401,13 @@ void ColladaSerializer::ColladaExporter::write(const IfcGeom::TriangulationEleme std::vector material_references; BOOST_FOREACH(const IfcGeom::Material& material, mesh.materials()) { - if (!materials.contains(material)) { - materials.add(material); - } - std::string material_name = (serializer->settings().get(SerializerSettings::USE_MATERIAL_NAMES) - ? material.original_name() : material.name()); + materials.add(material); - if (material_name.empty()) { - material_name = "missing-material-" + material.name(); - } - - collada_id(material_name); + std::string material_name = materials.getMaterialUri(material); material_references.push_back(material_name); } - DeferredObject deferred(name, representation_id, o->type(), o->transformation(), mesh.verts(), mesh.normals(), + DeferredObject deferred(name, representation_id, o->type(), o->transformation(), mesh.verts(), mesh.normals(), mesh.faces(), mesh.edges(), mesh.material_ids(), mesh.materials(), material_references, mesh.uvs()); if (serializer->settings().get(SerializerSettings::USE_ELEMENT_HIERARCHY)) { @@ -482,7 +463,7 @@ void ColladaSerializer::ColladaExporter::endDocument() { continue; } geometries_written.insert(it->representation_id); - geometries.write(it->representation_id, it->type, it->vertices, it->normals, it->faces, it->edges, it->material_ids, it->materials, it->uvs); + geometries.write(it->representation_id, it->type, it->vertices, it->normals, it->faces, it->edges, it->material_ids, it->materials, it->uvs, it->material_references); } geometries.close(); diff --git a/src/ifcconvert/ColladaSerializer.h b/src/ifcconvert/ColladaSerializer.h index a0ca6325c2..dbee52260e 100644 --- a/src/ifcconvert/ColladaSerializer.h +++ b/src/ifcconvert/ColladaSerializer.h @@ -69,11 +69,7 @@ private: {} void addFloatSource(const std::string& mesh_id, const std::string& suffix, const std::vector& floats, const char* coords = "XYZ"); - void write(const std::string &mesh_id, const std::string& default_material_name, - const std::vector& positions, const std::vector& normals, - const std::vector& faces, const std::vector& edges, - const std::vector material_ids, const std::vector& materials, - const std::vector& uvs); + void write(std::string mesh_id, std::string default_material_name, std::vector positions, std::vector normals, std::vector faces, std::vector edges, std::vector material_ids, std::vector materials, std::vector uvs, std::vector material_references); void close(); ColladaSerializer *serializer; }; @@ -115,11 +111,12 @@ private: explicit ColladaEffects(COLLADASW::StreamWriter& stream) : COLLADASW::LibraryEffects(&stream) {} - void write(const IfcGeom::Material& material); + void write(const IfcGeom::Material &material, const std::string &material_uri); void close(); ColladaSerializer *serializer; }; std::vector materials; + std::vector material_uris; public: explicit ColladaMaterials(COLLADASW::StreamWriter& stream, ColladaSerializer *_serializer) : COLLADASW::LibraryMaterials(&stream) @@ -127,6 +124,7 @@ private: , effects(stream) {} void add(const IfcGeom::Material& material); + std::string getMaterialUri(const IfcGeom::Material& material); bool contains(const IfcGeom::Material& material); void write(); ColladaSerializer *serializer;