Commit 37be8f8b authored by Jan Möbius's avatar Jan Möbius

Merge branch 'PLY_FACE_COLOR' into 'master'

PLY Reader/Writer: Support for face colors (Thanks to Steve and Barb Demlow for the patch)

See merge request !211
parents 449276bc 2c0ba7b7
Pipeline #8768 passed with stage
in 82 minutes and 8 seconds
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
<li>PLY Reader: Fixed endless loop on unknown property list type</li> <li>PLY Reader: Fixed endless loop on unknown property list type</li>
<li>PLY Reader: Fix hang when reading directly from istream (Thanks to Paul Loré for the patch)</li> <li>PLY Reader: Fix hang when reading directly from istream (Thanks to Paul Loré for the patch)</li>
<li>PLY Reader: Fix file load for ASCII PLY without a newline at the end of the file (Thanks to Mathieu Lamarre for the patch ) <li>PLY Reader: Fix file load for ASCII PLY without a newline at the end of the file (Thanks to Mathieu Lamarre for the patch )
<li>PLY Reader/Writer: Support for face colors (Thanks to Steve and Barb Demlow for the patch)</li>
<li>OM Writer/Reader: Update file format version to 2.0. Older files can still be read, but older OpenMesh versions cannot read new format.</li> <li>OM Writer/Reader: Update file format version to 2.0. Older files can still be read, but older OpenMesh versions cannot read new format.</li>
<li>OM Writer/Reader: Fixed inconsistent writing/reading of edge properties</li> <li>OM Writer/Reader: Fixed inconsistent writing/reading of edge properties</li>
<li>OM Writer/Reader: Add option to store status</li> <li>OM Writer/Reader: Add option to store status</li>
......
...@@ -55,7 +55,7 @@ ASCII is not a real option and will be selected, if binary was not defined. ...@@ -55,7 +55,7 @@ ASCII is not a real option and will be selected, if binary was not defined.
<TR><TH>Format/Option<TD>ASCII<TD>Binary<TD>MSB<TD>LSB<TD>Swap<TD>VertexNormal<TD>VertexColor<TD>VertexTexCoord<TD>EdgeColor<TD>FaceNormal<TD>FaceColor<TD>FaceTexCoord<TD>ColorAlpha<TD>ColorFloat<TD>Custom <TR><TH>Format/Option<TD>ASCII<TD>Binary<TD>MSB<TD>LSB<TD>Swap<TD>VertexNormal<TD>VertexColor<TD>VertexTexCoord<TD>EdgeColor<TD>FaceNormal<TD>FaceColor<TD>FaceTexCoord<TD>ColorAlpha<TD>ColorFloat<TD>Custom
<TR><TH>OBJ<TD>x<TD> <TD> <TD> <TD> <TD>x<TD>x *)<TD>x<TD> <TD>x<TD>x<TD>x<TD><TD><TD> <TR><TH>OBJ<TD>x<TD> <TD> <TD> <TD> <TD>x<TD>x *)<TD>x<TD> <TD>x<TD>x<TD>x<TD><TD><TD>
<TR><TH>OFF<TD>x<TD>x<TD> <TD>x<TD> <TD>x<TD>x<TD>x<TD> <TD> <TD>x<TD> <TD>x<TD>x<TD> <TR><TH>OFF<TD>x<TD>x<TD> <TD>x<TD> <TD>x<TD>x<TD>x<TD> <TD> <TD>x<TD> <TD>x<TD>x<TD>
<TR><TH>PLY<TD>x<TD>x<TD>x<TD>x<TD> <TD>x<TD>x<TD>x<TD> <TD> <TD> <TD> <TD>x<TD>x<TD>x **) <TR><TH>PLY<TD>x<TD>x<TD>x<TD>x<TD> <TD>x<TD>x<TD>x<TD> <TD> <TD>x<TD> <TD>x<TD>x<TD>x **)
<TR><TH>OM<TD> <TD>x<TD>x<TD>x<TD>x<TD>x<TD>x<TD>x<TD><TD>x<TD>x<TD><TD><TD><TD>x (\ref tutorial_09 ) <TR><TH>OM<TD> <TD>x<TD>x<TD>x<TD>x<TD>x<TD>x<TD>x<TD><TD>x<TD>x<TD><TD><TD><TD>x (\ref tutorial_09 )
<TR><TH>STL<TD>x<TD>x<TD><TD>x<TD><TD><TD><TD><TD><TD>x<TD><TD><TD><TD><TD> <TR><TH>STL<TD>x<TD>x<TD><TD>x<TD><TD><TD><TD><TD><TD>x<TD><TD><TD><TD><TD>
<TR><TH>VTK ***)<TD>x<TD><TD><TD><TD><TD><TD><TD><TD><TD><TD><TD><TD><TD><TD> <TR><TH>VTK ***)<TD>x<TD><TD><TD><TD><TD><TD><TD><TD><TD><TD><TD><TD><TD><TD>
......
...@@ -335,14 +335,14 @@ public: ...@@ -335,14 +335,14 @@ public:
Vec3f colorf(FaceHandle _fh) const override Vec3f colorf(FaceHandle _fh) const override
{ {
return (mesh_.has_vertex_colors() return (mesh_.has_face_colors()
? color_cast<Vec3f>(mesh_.color(_fh)) ? color_cast<Vec3f>(mesh_.color(_fh))
: Vec3f(0, 0, 0)); : Vec3f(0, 0, 0));
} }
Vec4f colorAf(FaceHandle _fh) const override Vec4f colorAf(FaceHandle _fh) const override
{ {
return (mesh_.has_vertex_colors() return (mesh_.has_face_colors()
? color_cast<Vec4f>(mesh_.color(_fh)) ? color_cast<Vec4f>(mesh_.color(_fh))
: Vec4f(0, 0, 0, 0)); : Vec4f(0, 0, 0, 0));
} }
......
...@@ -425,6 +425,12 @@ bool _PLYReader_::read_ascii(std::istream& _in, BaseImporter& _bi, const Options ...@@ -425,6 +425,12 @@ bool _PLYReader_::read_ascii(std::istream& _in, BaseImporter& _bi, const Options
// faces // faces
for (i = 0; i < faceCount_ && !_in.eof(); ++i) { for (i = 0; i < faceCount_ && !_in.eof(); ++i) {
FaceHandle fh; FaceHandle fh;
c[0] = 0;
c[1] = 0;
c[2] = 0;
c[3] = 255;
for (size_t propertyIndex = 0; propertyIndex < e_it->properties_.size(); ++propertyIndex) { for (size_t propertyIndex = 0; propertyIndex < e_it->properties_.size(); ++propertyIndex) {
PropertyInfo prop = e_it->properties_[propertyIndex]; PropertyInfo prop = e_it->properties_[propertyIndex];
switch (prop.property) { switch (prop.property) {
...@@ -456,6 +462,38 @@ bool _PLYReader_::read_ascii(std::istream& _in, BaseImporter& _bi, const Options ...@@ -456,6 +462,38 @@ bool _PLYReader_::read_ascii(std::istream& _in, BaseImporter& _bi, const Options
++complex_faces; ++complex_faces;
break; break;
case COLORRED:
if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) {
_in >> tmp;
c[0] = static_cast<OpenMesh::Vec4i::value_type> (tmp * 255.0f);
} else
_in >> c[0];
break;
case COLORGREEN:
if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) {
_in >> tmp;
c[1] = static_cast<OpenMesh::Vec4i::value_type> (tmp * 255.0f);
} else
_in >> c[1];
break;
case COLORBLUE:
if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) {
_in >> tmp;
c[2] = static_cast<OpenMesh::Vec4i::value_type> (tmp * 255.0f);
} else
_in >> c[2];
break;
case COLORALPHA:
if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) {
_in >> tmp;
c[3] = static_cast<OpenMesh::Vec4i::value_type> (tmp * 255.0f);
} else
_in >> c[3];
break;
case CUSTOM_PROP: case CUSTOM_PROP:
if (_opt.check(Options::Custom) && fh.is_valid()) if (_opt.check(Options::Custom) && fh.is_valid())
readCustomProperty<false>(_in, _bi, fh, prop.name, prop.value, prop.listIndexType); readCustomProperty<false>(_in, _bi, fh, prop.name, prop.value, prop.listIndexType);
...@@ -468,7 +506,8 @@ bool _PLYReader_::read_ascii(std::istream& _in, BaseImporter& _bi, const Options ...@@ -468,7 +506,8 @@ bool _PLYReader_::read_ascii(std::istream& _in, BaseImporter& _bi, const Options
break; break;
} }
} }
if (_opt.face_has_color())
_bi.set_color(fh, Vec4uc(c));
} }
} }
else else
...@@ -568,29 +607,26 @@ bool _PLYReader_::read_binary(std::istream& _in, BaseImporter& _bi, bool /*_swap ...@@ -568,29 +607,26 @@ bool _PLYReader_::read_binary(std::istream& _in, BaseImporter& _bi, bool /*_swap
readValue(prop.value, _in, t[1]); readValue(prop.value, _in, t[1]);
break; break;
case COLORRED: case COLORRED:
if (prop.value == ValueTypeFLOAT32 || if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) {
prop.value == ValueTypeFLOAT) { readValue(prop.value, _in, tmp);
readValue(prop.value, _in, tmp);
c[0] = static_cast<OpenMesh::Vec4i::value_type> (tmp * 255.0f); c[0] = static_cast<OpenMesh::Vec4i::value_type> (tmp * 255.0f);
} }
else else
readInteger(prop.value, _in, c[0]); readInteger(prop.value, _in, c[0]);
break; break;
case COLORGREEN: case COLORGREEN:
if (prop.value == ValueTypeFLOAT32 || if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) {
prop.value == ValueTypeFLOAT) { readValue(prop.value, _in, tmp);
readValue(prop.value, _in, tmp); c[1] = static_cast<OpenMesh::Vec4i::value_type> (tmp * 255.0f);
c[1] = static_cast<OpenMesh::Vec4i::value_type> (tmp * 255.0f); }
} else
else readInteger(prop.value, _in, c[1]);
readInteger(prop.value, _in, c[1]);
break; break;
case COLORBLUE: case COLORBLUE:
if (prop.value == ValueTypeFLOAT32 || if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) {
prop.value == ValueTypeFLOAT) {
readValue(prop.value, _in, tmp); readValue(prop.value, _in, tmp);
c[2] = static_cast<OpenMesh::Vec4i::value_type> (tmp * 255.0f); c[2] = static_cast<OpenMesh::Vec4i::value_type> (tmp * 255.0f);
} }
...@@ -599,8 +635,7 @@ bool _PLYReader_::read_binary(std::istream& _in, BaseImporter& _bi, bool /*_swap ...@@ -599,8 +635,7 @@ bool _PLYReader_::read_binary(std::istream& _in, BaseImporter& _bi, bool /*_swap
break; break;
case COLORALPHA: case COLORALPHA:
if (prop.value == ValueTypeFLOAT32 || if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) {
prop.value == ValueTypeFLOAT) {
readValue(prop.value, _in, tmp); readValue(prop.value, _in, tmp);
c[3] = static_cast<OpenMesh::Vec4i::value_type> (tmp * 255.0f); c[3] = static_cast<OpenMesh::Vec4i::value_type> (tmp * 255.0f);
} }
...@@ -634,6 +669,12 @@ bool _PLYReader_::read_binary(std::istream& _in, BaseImporter& _bi, bool /*_swap ...@@ -634,6 +669,12 @@ bool _PLYReader_::read_binary(std::istream& _in, BaseImporter& _bi, bool /*_swap
else if (e_it->element_ == FACE) { else if (e_it->element_ == FACE) {
for (unsigned i = 0; i < e_it->count_ && !_in.eof(); ++i) { for (unsigned i = 0; i < e_it->count_ && !_in.eof(); ++i) {
FaceHandle fh; FaceHandle fh;
c[0] = 0;
c[1] = 0;
c[2] = 0;
c[3] = 255;
for (size_t propertyIndex = 0; propertyIndex < e_it->properties_.size(); ++propertyIndex) for (size_t propertyIndex = 0; propertyIndex < e_it->properties_.size(); ++propertyIndex)
{ {
PropertyInfo prop = e_it->properties_[propertyIndex]; PropertyInfo prop = e_it->properties_[propertyIndex];
...@@ -668,7 +709,38 @@ bool _PLYReader_::read_binary(std::istream& _in, BaseImporter& _bi, bool /*_swap ...@@ -668,7 +709,38 @@ bool _PLYReader_::read_binary(std::istream& _in, BaseImporter& _bi, bool /*_swap
if (!fh.is_valid()) if (!fh.is_valid())
++complex_faces; ++complex_faces;
break; break;
case COLORRED:
if (prop.value == ValueTypeFLOAT32 ||
prop.value == ValueTypeFLOAT) {
readValue(prop.value, _in, tmp);
c[0] = static_cast<OpenMesh::Vec4i::value_type> (tmp * 255.0f);
} else
readInteger(prop.value, _in, c[0]);
break;
case COLORGREEN:
if (prop.value == ValueTypeFLOAT32 ||
prop.value == ValueTypeFLOAT) {
readValue(prop.value, _in, tmp);
c[1] = static_cast<OpenMesh::Vec4i::value_type> (tmp * 255.0f);
} else
readInteger(prop.value, _in, c[1]);
break;
case COLORBLUE:
if (prop.value == ValueTypeFLOAT32 ||
prop.value == ValueTypeFLOAT) {
readValue(prop.value, _in, tmp);
c[2] = static_cast<OpenMesh::Vec4i::value_type> (tmp * 255.0f);
} else
readInteger(prop.value, _in, c[2]);
break;
case COLORALPHA:
if (prop.value == ValueTypeFLOAT32 ||
prop.value == ValueTypeFLOAT) {
readValue(prop.value, _in, tmp);
c[3] = static_cast<OpenMesh::Vec4i::value_type> (tmp * 255.0f);
} else
readInteger(prop.value, _in, c[3]);
break;
case CUSTOM_PROP: case CUSTOM_PROP:
if (_opt.check(Options::Custom) && fh.is_valid()) if (_opt.check(Options::Custom) && fh.is_valid())
readCustomProperty<true>(_in, _bi, fh, prop.name, prop.value, prop.listIndexType); readCustomProperty<true>(_in, _bi, fh, prop.name, prop.value, prop.listIndexType);
...@@ -681,6 +753,8 @@ bool _PLYReader_::read_binary(std::istream& _in, BaseImporter& _bi, bool /*_swap ...@@ -681,6 +753,8 @@ bool _PLYReader_::read_binary(std::istream& _in, BaseImporter& _bi, bool /*_swap
break; break;
} }
} }
if (_opt.face_has_color())
_bi.set_color(fh, Vec4uc(c));
} }
} }
else { else {
...@@ -1347,6 +1421,30 @@ bool _PLYReader_::can_u_read(std::istream& _is) const { ...@@ -1347,6 +1421,30 @@ bool _PLYReader_::can_u_read(std::istream& _is) const {
options_ += Options::ColorFloat; options_ += Options::ColorFloat;
} }
} }
else if (elementName == "face") {
if (propertyName == "red") {
entry = PropertyInfo(COLORRED, valueType);
options_ += Options::FaceColor;
if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
options_ += Options::ColorFloat;
} else if (propertyName == "green") {
entry = PropertyInfo(COLORGREEN, valueType);
options_ += Options::FaceColor;
if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
options_ += Options::ColorFloat;
} else if (propertyName == "blue") {
entry = PropertyInfo(COLORBLUE, valueType);
options_ += Options::FaceColor;
if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
options_ += Options::ColorFloat;
} else if (propertyName == "alpha") {
entry = PropertyInfo(COLORALPHA, valueType);
options_ += Options::FaceColor;
options_ += Options::ColorAlpha;
if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
options_ += Options::ColorFloat;
}
}
//not a special property, load as custom //not a special property, load as custom
if (entry.value == Unsupported){ if (entry.value == Unsupported){
......
...@@ -122,14 +122,6 @@ write(std::ostream& _os, BaseExporter& _be, Options _opt, std::streamsize _preci ...@@ -122,14 +122,6 @@ write(std::ostream& _os, BaseExporter& _be, Options _opt, std::streamsize _preci
omerr() << "[PLYWriter] : Warning: Face normals are not supported and thus not exported! " << std::endl; omerr() << "[PLYWriter] : Warning: Face normals are not supported and thus not exported! " << std::endl;
} }
if ( _opt.check(Options::FaceColor) ) {
// Face normals are not supported
// Uncheck these options and output message that
// they are not written out even though they were requested
_opt.unset(Options::FaceColor);
omerr() << "[PLYWriter] : Warning: Face colors are not supported and thus not exported! " << std::endl;
}
options_ = _opt; options_ = _opt;
...@@ -313,6 +305,24 @@ void _PLYWriter_::write_header(std::ostream& _out, BaseExporter& _be, Options& _ ...@@ -313,6 +305,24 @@ void _PLYWriter_::write_header(std::ostream& _out, BaseExporter& _be, Options& _
_out << "element face " << _be.n_faces() << '\n'; _out << "element face " << _be.n_faces() << '\n';
_out << "property list uchar int vertex_indices" << '\n'; _out << "property list uchar int vertex_indices" << '\n';
if ( _opt.face_has_color() ){
if ( _opt.color_is_float() ) {
_out << "property float red" << '\n';
_out << "property float green" << '\n';
_out << "property float blue" << '\n';
if ( _opt.color_has_alpha() )
_out << "property float alpha" << '\n';
} else {
_out << "property uchar red" << '\n';
_out << "property uchar green" << '\n';
_out << "property uchar blue" << '\n';
if ( _opt.color_has_alpha() )
_out << "property uchar alpha" << '\n';
}
}
_ofProps = writeCustomTypeHeader(_out, _be.kernel()->fprops_begin(), _be.kernel()->fprops_end()); _ofProps = writeCustomTypeHeader(_out, _be.kernel()->fprops_begin(), _be.kernel()->fprops_end());
_out << "end_header" << '\n'; _out << "end_header" << '\n';
...@@ -335,6 +345,7 @@ write_ascii(std::ostream& _out, BaseExporter& _be, Options _opt) const ...@@ -335,6 +345,7 @@ write_ascii(std::ostream& _out, BaseExporter& _be, Options _opt) const
OpenMesh::Vec4f cAf; OpenMesh::Vec4f cAf;
OpenMesh::Vec2f t; OpenMesh::Vec2f t;
VertexHandle vh; VertexHandle vh;
FaceHandle fh;
std::vector<VertexHandle> vhandles; std::vector<VertexHandle> vhandles;
std::vector<CustomProperty> vProps; std::vector<CustomProperty> vProps;
...@@ -400,12 +411,37 @@ write_ascii(std::ostream& _out, BaseExporter& _be, Options _opt) const ...@@ -400,12 +411,37 @@ write_ascii(std::ostream& _out, BaseExporter& _be, Options _opt) const
// faces (indices starting at 0) // faces (indices starting at 0)
for (i=0, nF=int(_be.n_faces()); i<nF; ++i) for (i=0, nF=int(_be.n_faces()); i<nF; ++i)
{ {
fh = FaceHandle(i);
// write vertex indices per face // write vertex indices per face
nV = _be.get_vhandles(FaceHandle(i), vhandles); nV = _be.get_vhandles(fh, vhandles);
_out << nV; _out << nV;
for (size_t j=0; j<vhandles.size(); ++j) for (size_t j=0; j<vhandles.size(); ++j)
_out << " " << vhandles[j].idx(); _out << " " << vhandles[j].idx();
// FaceColor
if ( _opt.face_has_color() ) {
//with alpha
if ( _opt.color_has_alpha() ){
if (_opt.color_is_float()) {
cAf = _be.colorAf(fh);
_out << " " << cAf;
} else {
cA = _be.colorAi(fh);
_out << " " << cA;
}
}else{
//without alpha
if (_opt.color_is_float()) {
cf = _be.colorf(fh);
_out << " " << cf;
} else {
c = _be.colori(fh);
_out << " " << c;
}
}
}
// write custom props // write custom props
for (std::vector<CustomProperty>::iterator iter = fProps.begin(); iter < fProps.end(); ++iter) for (std::vector<CustomProperty>::iterator iter = fProps.begin(); iter < fProps.end(); ++iter)
write_customProp<false>(_out,*iter,i); write_customProp<false>(_out,*iter,i);
...@@ -562,6 +598,7 @@ write_binary(std::ostream& _out, BaseExporter& _be, Options _opt) const ...@@ -562,6 +598,7 @@ write_binary(std::ostream& _out, BaseExporter& _be, Options _opt) const
OpenMesh::Vec4uc c; OpenMesh::Vec4uc c;
OpenMesh::Vec4f cf; OpenMesh::Vec4f cf;
VertexHandle vh; VertexHandle vh;
FaceHandle fh;
std::vector<VertexHandle> vhandles; std::vector<VertexHandle> vhandles;
// vProps and fProps will be empty, until custom properties are supported by the binary writer // vProps and fProps will be empty, until custom properties are supported by the binary writer
...@@ -624,12 +661,35 @@ write_binary(std::ostream& _out, BaseExporter& _be, Options _opt) const ...@@ -624,12 +661,35 @@ write_binary(std::ostream& _out, BaseExporter& _be, Options _opt) const
for (i=0, nF=int(_be.n_faces()); i<nF; ++i) for (i=0, nF=int(_be.n_faces()); i<nF; ++i)
{ {
fh = FaceHandle(i);
//face //face
nV = _be.get_vhandles(FaceHandle(i), vhandles); nV = _be.get_vhandles(fh, vhandles);
writeValue(ValueTypeUINT8, _out, nV); writeValue(ValueTypeUINT8, _out, nV);
for (size_t j=0; j<vhandles.size(); ++j) for (size_t j=0; j<vhandles.size(); ++j)
writeValue(ValueTypeINT32, _out, vhandles[j].idx() ); writeValue(ValueTypeINT32, _out, vhandles[j].idx() );
// face color
if ( _opt.face_has_color() ) {
if ( _opt.color_is_float() ) {
cf = _be.colorAf(fh);
writeValue(ValueTypeFLOAT, _out, cf[0]);
writeValue(ValueTypeFLOAT, _out, cf[1]);
writeValue(ValueTypeFLOAT, _out, cf[2]);
if ( _opt.color_has_alpha() )
writeValue(ValueTypeFLOAT, _out, cf[3]);
} else {
c = _be.colorA(fh);
writeValue(ValueTypeUCHAR, _out, (int)c[0]);
writeValue(ValueTypeUCHAR, _out, (int)c[1]);
writeValue(ValueTypeUCHAR, _out, (int)c[2]);
if ( _opt.color_has_alpha() )
writeValue(ValueTypeUCHAR, _out, (int)c[3]);
}
}
for (std::vector<CustomProperty>::iterator iter = fProps.begin(); iter < fProps.end(); ++iter) for (std::vector<CustomProperty>::iterator iter = fProps.begin(); iter < fProps.end(); ++iter)
write_customProp<true>(_out,*iter,i); write_customProp<true>(_out,*iter,i);
} }
......
...@@ -82,6 +82,7 @@ namespace IO { ...@@ -82,6 +82,7 @@ namespace IO {
currently supported options: currently supported options:
- VertexColors - VertexColors
- FaceColors
- Binary - Binary
- Binary -> MSB - Binary -> MSB
*/ */
......
ply
format ascii 1.0
comment VCGLIB generated
element vertex 8
property float x
property float y
property float z
element face 12
property list uchar int vertex_indices
property float red
property float green
property float blue
end_header
-1 -1 -1
1 -1 -1
1 1 -1
-1 1 -1
-1 -1 1
1 -1 1
1 1 1
-1 1 1
3 0 1 2 0.419608 0.462745 0.698039
3 0 2 3 1.0 0.552941 0.419608
3 5 4 7 0.698039 1.0 0.619608
3 5 7 6 0.419608 1.0 0.529412
3 6 2 1 0.643137 0.419608 0.698039
3 6 1 5 0.643137 0.419608 1.0
3 3 7 4 0.698039 0.552941 1.0
3 3 4 0 1.0 0.552941 0.419608
3 7 3 2 0.419608 0.698039 1.0
3 7 2 6 0.419608 0.698039 0.529412
3 5 1 0 1.0 0.419608 1.0
3 5 0 4 0.698039 1.0 1.0
...@@ -800,4 +800,143 @@ TEST_F(OpenMeshReadWritePLY, FailOnUnknownPropertyTypeForLists) { ...@@ -800,4 +800,143 @@ TEST_F(OpenMeshReadWritePLY, FailOnUnknownPropertyTypeForLists) {
EXPECT_EQ(0u, mesh_.n_faces()) << "The number of loaded faces is not correct!"; EXPECT_EQ(0u, mesh_.n_faces()) << "The number of loaded faces is not correct!";
} }
/*
* Load an ASCII PLY file of a cube with float RGB face colors
*/
TEST_F(OpenMeshReadWritePLY, LoadSimplePLYWithFaceColors) {
mesh_.clear();
mesh_.request_face_colors();
OpenMesh::IO::Options options;
options += OpenMesh::IO::Options::FaceColor;
bool ok = OpenMesh::IO::read_mesh(mesh_, "cube-minimal-faceColors.ply",options);
EXPECT_TRUE(ok) << "Unable to load cube-minimal-faceColors.ply";
EXPECT_EQ(8u , mesh_.n_vertices()) << "The number of loaded vertices is not correct!";
EXPECT_EQ(18u, mesh_.n_edges()) << "The number of loaded edges is not correct!";
EXPECT_EQ(12u, mesh_.n_faces()) << "The number of loaded faces is not correct!";
EXPECT_EQ(107, mesh_.color(mesh_.face_handle(0))[0] ) << "Wrong face color at face 0";
EXPECT_EQ(117, mesh_.color(mesh_.face_handle(0))[1] ) << "Wrong face color at face 0";
EXPECT_EQ(177, mesh_.color(mesh_.face_handle(0))[2] ) << "Wrong face color at face 0";
EXPECT_EQ(107, mesh_.color(mesh_.face_handle(3))[0] ) << "Wrong face color at face 3";
EXPECT_EQ(255, mesh_.color(mesh_.face_handle(3))[1] ) << "Wrong face color at face 3";
EXPECT_EQ(135, mesh_.color(mesh_.face_handle(3))[2] ) << "Wrong face color at face 3";
EXPECT_EQ(163, mesh_.color(mesh_.face_handle(4))[0] ) << "Wrong face color at face 4";
EXPECT_EQ(107, mesh_.color(mesh_.face_handle(4))[1] ) << "Wrong face color at face 4";
EXPECT_EQ(177, mesh_.color(mesh_.face_handle(4))[2] ) << "Wrong face color at face 4";
EXPECT_EQ(255, mesh_.color(mesh_.face_handle(7))[0] ) << "Wrong face color at face 7";
EXPECT_EQ(140, mesh_.color(mesh_.face_handle(7))[1] ) << "Wrong face color at face 7";
EXPECT_EQ(107, mesh_.color(mesh_.face_handle(7))[2] ) << "Wrong face color at face 7";
EXPECT_FALSE(options.vertex_has_normal()) << "Wrong user options are returned!";
EXPECT_FALSE(options.vertex_has_texcoord()) << "Wrong user options are returned!";
EXPECT_FALSE(options.vertex_has_color()) << "Wrong user options are returned!";
EXPECT_TRUE(options.face_has_color()) << "Wrong user options are returned!";
EXPECT_FALSE(options.color_has_alpha()) << "Wrong user options are returned!";
EXPECT_FALSE(options.is_binary()) << "Wrong user options are returned!";
mesh_.release_face_colors();
}
/*
* Write and read PLY files with face colors in various formats
*/
TEST_F(OpenMeshReadWritePLY, WriteAndReadPLYWithFaceColors) {
struct Format {
Format(const char* outFileName, OpenMesh::IO::Options options) :
_outFileName(outFileName),
_options(options)
{}
const char* _outFileName;
const OpenMesh::IO::Options _options;
}
formats[] =
{
Format("cube-minimal-faceColors_ascii_uchar.ply",
OpenMesh::IO::Options::Default),
Format("cube-minimal-faceColors_ascii_float.ply",
OpenMesh::IO::Options::ColorFloat),
Format("cube-minimal-faceColors_binary_uchar.ply",
OpenMesh::IO::Options::Binary),
Format("cube-minimal-faceColors_binary_float.ply",
OpenMesh::IO::Options::Binary | OpenMesh::IO::Options::ColorFloat),
// Test writing/reading alpha values (all default 1.0/255), but the test mesh
// Color type has no alpha channel so there's nothing to test below
Format("cube-minimal-faceColors_alpha_ascii_uchar.ply",
OpenMesh::IO::Options::ColorAlpha),
Format("cube-minimal-faceColors_alpha_ascii_float.ply",
OpenMesh::IO::Options::ColorFloat | OpenMesh::IO::Options::ColorAlpha),
Format("cube-minimal-faceColors_alpha_binary_uchar.ply",
OpenMesh::IO::Options::Binary | OpenMesh::IO::Options::ColorAlpha),
Format("cube-minimal-faceColors_alpha_binary_float.ply",
OpenMesh::IO::Options::Binary | OpenMesh::IO::Options::ColorFloat | OpenMesh::IO::Options::ColorAlpha),
};
for (size_t i = 0; i < sizeof(formats) / sizeof(Format); ++i)
{
const char* outFileName = formats[i]._outFileName;
mesh_.clear();
mesh_.request_face_colors();
OpenMesh::IO::Options options;
options += OpenMesh::IO::Options::FaceColor;
bool ok = OpenMesh::IO::read_mesh(mesh_, "cube-minimal-faceColors.ply", options);
EXPECT_TRUE(ok) << "Unable to load cube-minimal-faceColors.ply";
options = formats[i]._options;
options += OpenMesh::IO::Options::FaceColor;
ok = OpenMesh::IO::write_mesh(mesh_, outFileName, options);
EXPECT_TRUE(ok) << "Unable to write " << outFileName;
// Reset for reading: let the reader determine binary/float/etc.
options = OpenMesh::IO::Options::FaceColor;
mesh_.clear();
ok = OpenMesh::IO::read_mesh(mesh_, outFileName, options);
EXPECT_TRUE(ok) << "Unable to load " << outFileName;
EXPECT_EQ(8u , mesh_.n_vertices()) << "The number of loaded vertices is not correct: " << outFileName;
EXPECT_EQ(18u, mesh_.n_edges()) << "The number of loaded edges is not correct: " << outFileName;
EXPECT_EQ(12u, mesh_.n_faces()) << "The number of loaded faces is not correct: " << outFileName;
EXPECT_EQ(107, mesh_.color(mesh_.face_handle(0))[0] ) << "Wrong face color at face 0: " << outFileName;
EXPECT_EQ(117, mesh_.color(mesh_.face_handle(0))[1] ) << "Wrong face color at face 0: " << outFileName;
EXPECT_EQ(177, mesh_.color(mesh_.face_handle(0))[2] ) << "Wrong face color at face 0: " << outFileName;
EXPECT_EQ(107, mesh_.color(mesh_.face_handle(3))[0] ) << "Wrong face color at face 3: " << outFileName;
EXPECT_EQ(255, mesh_.color(mesh_.face_handle(3))[1] ) << "Wrong face color at face 3: " << outFileName;
EXPECT_EQ(135, mesh_.color(mesh_.face_handle(3))[2] ) << "Wrong face color at face 3: " << outFileName;
EXPECT_EQ(163, mesh_.color(mesh_.face_handle(4))[0] ) << "Wrong face color at face 4: " << outFileName;
EXPECT_EQ(107, mesh_.color(mesh_.face_handle(4))[1] ) << "Wrong face color at face 4: " << outFileName;
EXPECT_EQ(177, mesh_.color(mesh_.face_handle(4))[2] ) << "Wrong face color at face 4: " << outFileName;
EXPECT_EQ(255, mesh_.color(mesh_.face_handle(7))[0] ) << "Wrong face color at face 7: " << outFileName;
EXPECT_EQ(140, mesh_.color(mesh_.face_handle(7))[1] ) << "Wrong face color at face 7: " << outFileName;
EXPECT_EQ(107, mesh_.color(mesh_.face_handle(7))[2] ) << "Wrong face color at face 7: " << outFileName;
EXPECT_FALSE(options.vertex_has_normal()) << "Wrong user options are returned: " << outFileName;
EXPECT_FALSE(options.vertex_has_texcoord()) << "Wrong user options are returned: " << outFileName;
EXPECT_FALSE(options.vertex_has_color()) << "Wrong user options are returned: " << outFileName;
EXPECT_TRUE(options.face_has_color()) << "Wrong user options are returned: " << outFileName;
EXPECT_EQ(formats[i]._options.color_is_float(), options.color_is_float()) <<
"Wrong user options are returned: " << outFileName;
EXPECT_EQ(formats[i]._options.is_binary(), options.is_binary()) <<
"Wrong user options are returned: " << outFileName;
mesh_.release_face_colors();
}
}
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment