From 169b1a02ad5927512b85f21d21712200a2999fc0 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Tue, 27 May 2008 12:06:50 +0000 Subject: [PATCH] From Gino van den Bergen, "I've refactored the single ReadedWriterVRML2.cpp into multiple files. The reason for doing this was to break up the horribly long function osg::ref_ptr ReaderWriterVRML2::convertFromVRML(openvrml::node *obj) The fixes are: * Added the source's parent directory as search directory for image files. * The material properties are now set in the stateset of the Geode rather than the Geometry. This will allow geometries to be reused with different material properties in future updates. NB: I planned for a caching scheme in which multiple occurences of the same primitive (e.g., Cylinders with radius 0.8 and height 1.2), would use the same Geometry object. Unfortunately, my planning moved me to other areas, but I might still finish the caching scheme in a quiet hour. For the time being I decided it would be a good thing to already submit my current changes. " --- src/osgPlugins/vrml/CMakeLists.txt | 10 +- src/osgPlugins/vrml/IndexedFaceSet.cpp | 329 ++++++++++ src/osgPlugins/vrml/Primitives.cpp | 395 ++++++++++++ src/osgPlugins/vrml/ReaderWriterVRML2.cpp | 722 ++-------------------- src/osgPlugins/vrml/ReaderWriterVRML2.h | 71 +++ 5 files changed, 841 insertions(+), 686 deletions(-) create mode 100644 src/osgPlugins/vrml/IndexedFaceSet.cpp create mode 100644 src/osgPlugins/vrml/Primitives.cpp create mode 100644 src/osgPlugins/vrml/ReaderWriterVRML2.h diff --git a/src/osgPlugins/vrml/CMakeLists.txt b/src/osgPlugins/vrml/CMakeLists.txt index 10c885545..a57ce6ca6 100644 --- a/src/osgPlugins/vrml/CMakeLists.txt +++ b/src/osgPlugins/vrml/CMakeLists.txt @@ -11,7 +11,15 @@ ELSE(WIN32) SET(TARGET_LIBRARIES_VARS OPENVRML_LIBRARY) ENDIF(WIN32) -SET(TARGET_SRC ReaderWriterVRML2.cpp ) +SET(TARGET_SRC + IndexedFaceSet.cpp + Primitives.cpp + ReaderWriterVRML2.cpp +) + +SET(TARGET_H + ReaderWriterVRML2.h +) #### end var setup ### SETUP_PLUGIN(vrml) diff --git a/src/osgPlugins/vrml/IndexedFaceSet.cpp b/src/osgPlugins/vrml/IndexedFaceSet.cpp new file mode 100644 index 000000000..3ae4c5f04 --- /dev/null +++ b/src/osgPlugins/vrml/IndexedFaceSet.cpp @@ -0,0 +1,329 @@ +// -*-c++-*- + +#include "ReaderWriterVRML2.h" + + +#if defined(_MSC_VER) +# pragma warning(disable: 4250) +# pragma warning(disable: 4290) +# pragma warning(disable: 4800) +#endif + +#include +#include +#include +#include +#include + +#include + + +osg::ref_ptr ReaderWriterVRML2::convertVRML97IndexedFaceSet(openvrml::vrml97_node::indexed_face_set_node *vrml_ifs) +{ + osg::ref_ptr osg_geom = new osg::Geometry(); + + osg_geom->addPrimitiveSet(new osg::DrawArrayLengths(osg::PrimitiveSet::POLYGON)); + osg::StateSet *osg_stateset = osg_geom->getOrCreateStateSet(); + + // get array of vertex coordinate_nodes + { + const openvrml::field_value& fv = vrml_ifs->field("coord"); + const openvrml::sfnode& sfn = dynamic_cast(fv); + openvrml::vrml97_node::coordinate_node* vrml_coord_node = dynamic_cast(sfn.value.get()); + + const std::vector& vrml_coord = vrml_coord_node->point(); + osg::ref_ptr osg_vertices = new osg::Vec3Array(); + + unsigned i; + for (i = 0; i < vrml_coord.size(); i++) + { + openvrml::vec3f vec = vrml_coord[i]; + osg_vertices->push_back(osg::Vec3(vec[0], vec[1], vec[2])); + } + + osg_geom->setVertexArray(osg_vertices.get()); + + // get array of vertex indices + const openvrml::field_value &fv2 = vrml_ifs->field("coordIndex"); + const openvrml::mfint32 &vrml_coord_index = dynamic_cast(fv2); + + osg::ref_ptr osg_vert_index = new osg::IntArray(); + + int num_vert = 0; + for (i = 0; i < vrml_coord_index.value.size(); i++) + { + int index = vrml_coord_index.value[i]; + if (index == -1) + { + static_cast(osg_geom->getPrimitiveSet(0))->push_back(num_vert); + num_vert = 0; + } + else + { + osg_vert_index->push_back(index); + ++num_vert; + } + } + if (num_vert) + { + //GvdB: Last coordIndex wasn't -1 + static_cast(osg_geom->getPrimitiveSet(0))->push_back(num_vert); + } + + osg_geom->setVertexIndices(osg_vert_index.get()); + } + + { + // get texture coordinate_nodes + const openvrml::field_value &fv = vrml_ifs->field("texCoord"); + const openvrml::sfnode &sfn = dynamic_cast(fv); + openvrml::vrml97_node::texture_coordinate_node *vrml_tex_coord_node = + dynamic_cast(sfn.value.get()); + + if (vrml_tex_coord_node != 0) // if no texture, node is NULL pointer + { + const std::vector &vrml_tex_coord = vrml_tex_coord_node->point(); + osg::ref_ptr osg_texcoords = new osg::Vec2Array(); + + unsigned i; + for (i = 0; i < vrml_tex_coord.size(); i++) + { + openvrml::vec2f vec = vrml_tex_coord[i]; + osg_texcoords->push_back(osg::Vec2(vec[0], vec[1])); + } + + osg_geom->setTexCoordArray(0, osg_texcoords.get()); + + // get array of texture indices + const openvrml::field_value &fv2 = vrml_ifs->field("texCoordIndex"); + const openvrml::mfint32 &vrml_tex_coord_index = dynamic_cast(fv2); + + osg::ref_ptr osg_tex_coord_index = new osg::IntArray(); + + if(vrml_tex_coord_index.value.size() > 0) + { + for (i = 0; i < vrml_tex_coord_index.value.size(); i++) + { + int index = vrml_tex_coord_index.value[i]; + if (index != -1) { + osg_tex_coord_index->push_back(index); + } + } + osg_geom->setTexCoordIndices(0, osg_tex_coord_index.get()); + } else + // no indices defined, use coordIndex + osg_geom->setTexCoordIndices(0, osg_geom->getVertexIndices()); + } + } + + // get array of normals per vertex (if specified) + { + const openvrml::field_value& fv = vrml_ifs->field("normal"); + const openvrml::sfnode& sfn = dynamic_cast(fv); + openvrml::vrml97_node::normal_node* vrml_normal_node = dynamic_cast(sfn.value.get()); + + if (vrml_normal_node != 0) // if no normals, node is NULL pointer + { + const std::vector& vrml_normal_coord = vrml_normal_node->vector(); + + osg::ref_ptr osg_normalcoords = new osg::Vec3Array(); + + unsigned i; + for (i = 0; i < vrml_normal_coord.size(); i++) + { + const openvrml::vec3f vec = vrml_normal_coord[i]; + osg_normalcoords->push_back(osg::Vec3(vec[0], vec[1], vec[2])); + } + osg_geom->setNormalArray(osg_normalcoords.get()); + + // get array of normal indices + const openvrml::field_value& fv2 = vrml_ifs->field("normalIndex"); + const openvrml::mfint32& vrml_normal_index = dynamic_cast(fv2); + + osg::ref_ptr osg_normal_index = new osg::IntArray(); + + if (vrml_normal_index.value.size() > 0) + { + for (i = 0; i < vrml_normal_index.value.size(); i++) + { + int index = vrml_normal_index.value[i]; + if (index != -1) + { + osg_normal_index->push_back(index); + } + } + osg_geom->setNormalIndices(osg_normal_index.get()); + } + else + // unspecified, use the coordIndex field + osg_geom->setNormalIndices(osg_geom->getVertexIndices()); + + // get normal binding + const openvrml::field_value &fv3 = vrml_ifs->field("normalPerVertex"); + const openvrml::sfbool &vrml_norm_per_vertex = dynamic_cast(fv3); + + if (vrml_norm_per_vertex.value) + { + osg_geom->setNormalBinding(osg::Geometry::BIND_PER_VERTEX); + } else + { + osg_geom->setNormalBinding(osg::Geometry::BIND_PER_PRIMITIVE); + } + } + } + + // get array of colours per vertex (if specified) + { + const openvrml::field_value &fv = vrml_ifs->field("color"); + const openvrml::sfnode &sfn = dynamic_cast(fv); + openvrml::vrml97_node::color_node *vrml_color_node = + dynamic_cast(sfn.value.get()); + + if (vrml_color_node != 0) // if no colors, node is NULL pointer + { + const std::vector &vrml_colors = vrml_color_node->color(); + + osg::ref_ptr osg_colors = new osg::Vec3Array(); + + unsigned i; + for (i = 0; i < vrml_colors.size(); i++) + { + const openvrml::color color = vrml_colors[i]; + osg_colors->push_back(osg::Vec3(color.r(), color.g(), color.b())); + } + osg_geom->setColorArray(osg_colors.get()); + + // get array of color indices + const openvrml::field_value &fv2 = vrml_ifs->field("colorIndex"); + const openvrml::mfint32 &vrml_color_index = dynamic_cast(fv2); + + osg::ref_ptr osg_color_index = new osg::IntArray(); + + if(vrml_color_index.value.size() > 0) + { + for (i = 0; i < vrml_color_index.value.size(); i++) + { + int index = vrml_color_index.value[i]; + if (index != -1) { + osg_color_index->push_back(index); + } + } + osg_geom->setColorIndices(osg_color_index.get()); + } else + // unspecified, use coordIndices field + osg_geom->setColorIndices(osg_geom->getVertexIndices()); + + // get color binding + const openvrml::field_value &fv3 = vrml_ifs->field("colorPerVertex"); + const openvrml::sfbool &vrml_color_per_vertex = dynamic_cast(fv3); + + if (vrml_color_per_vertex.value) + { + osg_geom->setColorBinding(osg::Geometry::BIND_PER_VERTEX); + } else + { + osg_geom->setColorBinding(osg::Geometry::BIND_PER_PRIMITIVE); + } + } + } + + if (static_cast(vrml_ifs->field("solid")).value) + { + osg_geom->getOrCreateStateSet()->setAttributeAndModes(new osg::CullFace(osg::CullFace::BACK)); + } + + if (!osg_geom->getNormalArray()) + { +#if 0 + // GvdB: This is what I wanted to do, but got zero normals since the triangles were considered temporaries (?) + osgUtil::SmoothingVisitor().smooth(*osg_geom); +#else + // GvdB: So I ended up computing the smoothing normals myself. Also, I might add support for "creaseAngle" if a big need for it rises. + // However, for now I can perfectly live with the fact that all edges are smoothed despite the use of a crease angle. + osg::Vec3Array& coords = *static_cast(osg_geom->getVertexArray()); + assert(coords.size()); + + osg::Vec3Array* normals = new osg::Vec3Array(coords.size()); + + for (osg::Vec3Array::iterator it = normals->begin(); it != normals->end(); ++it) + { + (*it).set(0.0f, 0.0f, 0.0f); + } + + + osg::IntArray& indices = *static_cast(osg_geom->getVertexIndices()); + osg::DrawArrayLengths& lengths = *static_cast(osg_geom->getPrimitiveSet(0)); + int index = 0; + + for (osg::DrawArrayLengths::iterator it = lengths.begin(); it != lengths.end(); ++it) + { + assert(*it >= 3); + const osg::Vec3& v0 = coords[indices[index]]; + const osg::Vec3& v1 = coords[indices[index + 1]]; + const osg::Vec3& v2 = coords[indices[index + 2]]; + + osg::Vec3 normal = (v1 - v0) ^ (v2 - v0); + normal.normalize(); + + for (int i = 0; i != *it; ++i) + { + (*normals)[indices[index + i]] += normal; + } + + index += *it; + } + + assert(index == indices.size()); + + for(osg::Vec3Array::iterator it = normals->begin(); it != normals->end(); ++it) + { + (*it).normalize(); + } + + osg_geom->setNormalArray(normals); + osg_geom->setNormalIndices(osg_geom->getVertexIndices()); + osg_geom->setNormalBinding(osg::Geometry::BIND_PER_VERTEX); + +#endif + } + + + osg::DrawArrayLengths& lengths = *static_cast(osg_geom->getPrimitiveSet(0)); + + osg::DrawArrayLengths::iterator it = lengths.begin(); + if (it != lengths.end()) + { + switch (*it) + { + case 3: + while (++it != lengths.end() && *it == 3) + ; + + if (it == lengths.end()) + { + // All polys are triangles + osg::ref_ptr mesh = new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES); + mesh->setCount(lengths.size() * 3); + osg_geom->removePrimitiveSet(0); + osg_geom->addPrimitiveSet(mesh.get()); + } + break; + + case 4: + while (++it != lengths.end() && *it == 4) + ; + + if (it == lengths.end()) + { + // All polys are quads + osg::ref_ptr mesh = new osg::DrawArrays(osg::PrimitiveSet::QUADS); + mesh->setCount(lengths.size() * 4); + osg_geom->removePrimitiveSet(0); + osg_geom->addPrimitiveSet(mesh.get()); + } + + break; + } + } + return osg_geom.get(); +} diff --git a/src/osgPlugins/vrml/Primitives.cpp b/src/osgPlugins/vrml/Primitives.cpp new file mode 100644 index 000000000..76c86c7a8 --- /dev/null +++ b/src/osgPlugins/vrml/Primitives.cpp @@ -0,0 +1,395 @@ +// -*-c++-*- + +#include "ReaderWriterVRML2.h" + +#include + +#if defined(_MSC_VER) +# pragma warning(disable: 4250) +# pragma warning(disable: 4290) +# pragma warning(disable: 4800) +#endif + +#include +#include +#include +#include +#include + +#include + +osg::ref_ptr ReaderWriterVRML2::convertVRML97Box(openvrml::vrml97_node::box_node* vrml_box) +{ + osg::ref_ptr osg_geom = new osg::Geometry(); + + const openvrml::vec3f& size = static_cast(vrml_box->field("size")).value; + + osg::Vec3 halfSize(size[0] * 0.5f, size[1] * 0.5f, size[2] * 0.5f); + + osg::ref_ptr osg_vertices = new osg::Vec3Array(); + osg::ref_ptr osg_texcoords = new osg::Vec2Array(); + osg::ref_ptr osg_normals = new osg::Vec3Array(); + + osg::ref_ptr box = new osg::DrawArrays(osg::PrimitiveSet::QUADS); + + osg_vertices->push_back(osg::Vec3(-halfSize[0], halfSize[1], halfSize[2])); + osg_vertices->push_back(osg::Vec3(-halfSize[0], -halfSize[1], halfSize[2])); + osg_vertices->push_back(osg::Vec3(halfSize[0], -halfSize[1], halfSize[2])); + osg_vertices->push_back(osg::Vec3(halfSize[0], halfSize[1], halfSize[2])); + + osg_vertices->push_back(osg::Vec3(halfSize[0], halfSize[1], -halfSize[2])); + osg_vertices->push_back(osg::Vec3(halfSize[0], -halfSize[1], -halfSize[2])); + osg_vertices->push_back(osg::Vec3(-halfSize[0], -halfSize[1], -halfSize[2])); + osg_vertices->push_back(osg::Vec3(-halfSize[0], halfSize[1], -halfSize[2])); + + osg_vertices->push_back(osg::Vec3(halfSize[0], halfSize[1], halfSize[2])); + osg_vertices->push_back(osg::Vec3(halfSize[0], -halfSize[1], halfSize[2])); + osg_vertices->push_back(osg::Vec3(halfSize[0], -halfSize[1], -halfSize[2])); + osg_vertices->push_back(osg::Vec3(halfSize[0], halfSize[1], -halfSize[2])); + + osg_vertices->push_back(osg::Vec3(-halfSize[0], halfSize[1], -halfSize[2])); + osg_vertices->push_back(osg::Vec3(-halfSize[0], -halfSize[1], -halfSize[2])); + osg_vertices->push_back(osg::Vec3(-halfSize[0], -halfSize[1], halfSize[2])); + osg_vertices->push_back(osg::Vec3(-halfSize[0], halfSize[1], halfSize[2])); + + osg_vertices->push_back(osg::Vec3(-halfSize[0], halfSize[1], -halfSize[2])); + osg_vertices->push_back(osg::Vec3(-halfSize[0], halfSize[1], halfSize[2])); + osg_vertices->push_back(osg::Vec3(halfSize[0], halfSize[1], halfSize[2])); + osg_vertices->push_back(osg::Vec3(halfSize[0], halfSize[1], -halfSize[2])); + + osg_vertices->push_back(osg::Vec3(-halfSize[0], -halfSize[1], halfSize[2])); + osg_vertices->push_back(osg::Vec3(-halfSize[0], -halfSize[1], -halfSize[2])); + osg_vertices->push_back(osg::Vec3(halfSize[0], -halfSize[1], -halfSize[2])); + osg_vertices->push_back(osg::Vec3(halfSize[0], -halfSize[1], halfSize[2])); + + for (int i = 0; i != 6; ++i) + { + osg_texcoords->push_back(osg::Vec2(0.0f, 1.0f)); + osg_texcoords->push_back(osg::Vec2(0.0f, 0.0f)); + osg_texcoords->push_back(osg::Vec2(1.0f, 0.0f)); + osg_texcoords->push_back(osg::Vec2(1.0f, 1.0f)); + } + + osg_normals->push_back(osg::Vec3(0.0f, 0.0f, 1.0f)); + osg_normals->push_back(osg::Vec3(0.0f, 0.0f, -1.0f)); + osg_normals->push_back(osg::Vec3(1.0f, 0.0f, 0.0f)); + osg_normals->push_back(osg::Vec3(-1.0f, 0.0f, 0.0f)); + osg_normals->push_back(osg::Vec3(0.0f, 1.0f, 0.0f)); + osg_normals->push_back(osg::Vec3(0.0f, -1.0f, 0.0f)); + + box->setCount(osg_vertices->size()); + + osg_geom->addPrimitiveSet(box.get()); + + osg_geom->setVertexArray(osg_vertices.get()); + osg_geom->setTexCoordArray(0, osg_texcoords.get()); + osg_geom->setNormalArray(osg_normals.get()); + osg_geom->setNormalBinding(osg::Geometry::BIND_PER_PRIMITIVE); + + osg_geom->getOrCreateStateSet()->setAttributeAndModes(new osg::CullFace(osg::CullFace::BACK)); + + return osg_geom.get(); +} + + +osg::ref_ptr ReaderWriterVRML2::convertVRML97Sphere(openvrml::vrml97_node::sphere_node* vrml_sphere) +{ + osg::ref_ptr osg_geom = new osg::Geometry(); + + float radius = static_cast(vrml_sphere->field("radius")).value; + + osg::ref_ptr osg_vertices = new osg::Vec3Array(); + osg::ref_ptr osg_texcoords = new osg::Vec2Array(); + osg::ref_ptr osg_normals = new osg::Vec3Array(); + + unsigned int numSegments = 40; + unsigned int numRows = 20; + + const float thetaDelta = 2.0f * float(osg::PI) / float(numSegments); + const float texCoordSDelta = 1.0f / float(numSegments); + const float phiDelta = float(osg::PI) / float(numRows); + const float texCoordTDelta = 1.0f / float(numRows); + + float phi = -0.5f * float(osg::PI); + float texCoordT = 0.0f; + + osg::ref_ptr sphere = new osg::DrawArrayLengths(osg::PrimitiveSet::QUAD_STRIP); + + for (unsigned int i = 0; i < numRows; ++i, phi += phiDelta, texCoordT += texCoordTDelta) + { + std::complex latBottom = std::polar(1.0f, phi); + std::complex latTop = std::polar(1.0f, phi + phiDelta); + std::complex eBottom = latBottom * radius; + std::complex eTop = latTop * radius; + + float theta = 0.0f; + float texCoordS = 0.0f; + + for (unsigned int j = 0; j < numSegments; ++j, theta += thetaDelta, texCoordS += texCoordSDelta) + { + std::complex n = -std::polar(1.0f, theta); + + osg_normals->push_back(osg::Vec3(latTop.real() * n.imag(), latTop.imag(), latTop.real() * n.real())); + osg_normals->push_back(osg::Vec3(latBottom.real() * n.imag(), latBottom.imag(), latBottom.real() * n.real())); + + osg_texcoords->push_back(osg::Vec2(texCoordS, texCoordT + texCoordTDelta)); + osg_texcoords->push_back(osg::Vec2(texCoordS, texCoordT)); + + osg_vertices->push_back(osg::Vec3(eTop.real() * n.imag(), eTop.imag(), eTop.real() * n.real())); + osg_vertices->push_back(osg::Vec3(eBottom.real() * n.imag(), eBottom.imag(), eBottom.real() * n.real())); + } + + osg_normals->push_back(osg::Vec3(0.0f, latTop.imag(), -latTop.real())); + osg_normals->push_back(osg::Vec3(0.0f, latBottom.imag(), -latBottom.real())); + + osg_texcoords->push_back(osg::Vec2(1.0f, texCoordT + texCoordTDelta)); + osg_texcoords->push_back(osg::Vec2(1.0f, texCoordT)); + + osg_vertices->push_back(osg::Vec3(0.0f, eTop.imag(), -eTop.real())); + osg_vertices->push_back(osg::Vec3(0.0f, eBottom.imag(), -eBottom.real())); + + sphere->push_back(numSegments * 2 + 2); + } + + osg_geom->addPrimitiveSet(sphere.get()); + + osg_geom->setVertexArray(osg_vertices.get()); + osg_geom->setTexCoordArray(0, osg_texcoords.get()); + osg_geom->setNormalArray(osg_normals.get()); + osg_geom->setNormalBinding(osg::Geometry::BIND_PER_VERTEX); + + osg_geom->getOrCreateStateSet()->setAttributeAndModes(new osg::CullFace(osg::CullFace::BACK)); + + return osg_geom.get(); +} + + +osg::ref_ptr ReaderWriterVRML2::convertVRML97Cone(openvrml::vrml97_node::cone_node* vrml_cone) +{ + osg::ref_ptr osg_geom = new osg::Geometry(); + + float height = static_cast(vrml_cone->field("height")).value; + float radius = static_cast(vrml_cone->field("bottomRadius")).value; + + osg::ref_ptr osg_vertices = new osg::Vec3Array(); + osg::ref_ptr osg_texcoords = new osg::Vec2Array(); + osg::ref_ptr osg_normals = new osg::Vec3Array(); + + unsigned int numSegments = 40; + + const float thetaDelta = 2.0f * float(osg::PI) / float(numSegments); + + float topY = height * 0.5f; + float bottomY = height * -0.5f; + + if (static_cast(vrml_cone->field("side")).value) + { + osg::ref_ptr side = new osg::DrawArrays(osg::PrimitiveSet::QUAD_STRIP); + + const float texCoordDelta = 1.0f / float(numSegments); + float theta = 0.0f; + float texCoord = 0.0f; + + for (unsigned int i = 0; i < numSegments; ++i, theta += thetaDelta, texCoord += texCoordDelta) + { + std::complex n = -std::polar(1.0f, theta); + std::complex e = n * radius; + + osg::Vec3 normal(n.imag() * height, radius, n.real() * height); + normal.normalize(); + + osg_normals->push_back(normal); + osg_normals->push_back(normal); + + osg_texcoords->push_back(osg::Vec2(texCoord, 1.0f)); + osg_texcoords->push_back(osg::Vec2(texCoord, 0.0f)); + + osg_vertices->push_back(osg::Vec3(0.0f, topY, 0.0f)); + osg_vertices->push_back(osg::Vec3(e.imag(), bottomY, e.real())); + } + + // do last point by hand to ensure no round off errors. + + osg::Vec3 normal(0.0f, radius, -height); + normal.normalize(); + + osg_normals->push_back(normal); + osg_normals->push_back(normal); + + osg_texcoords->push_back(osg::Vec2(1.0f, 1.0f)); + osg_texcoords->push_back(osg::Vec2(1.0f, 0.0f)); + + osg_vertices->push_back(osg::Vec3(0.0f, topY, 0.0f)); + osg_vertices->push_back(osg::Vec3(0.0f, bottomY, -radius)); + + side->setCount(osg_vertices->size()); + osg_geom->addPrimitiveSet(side.get()); + } + + if (static_cast(vrml_cone->field("bottom")).value) + { + osg::ref_ptr bottom = new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_FAN); + + + size_t first = osg_vertices->size(); + bottom->setFirst(first); + + float theta = 0.0f; + + for (unsigned int i = 0; i < numSegments; ++i, theta += thetaDelta) + { + std::complex n = -std::polar(1.0f, theta); + std::complex e = n * radius; + + osg_normals->push_back(osg::Vec3(0.0f, -1.0f, 0.0f)); + osg_texcoords->push_back(osg::Vec2(0.5f - 0.5f * n.imag(), 0.5f + 0.5f * n.real())); + osg_vertices->push_back(osg::Vec3(-e.imag(), bottomY, e.real())); + } + + // do last point by hand to ensure no round off errors. + + osg_normals->push_back(osg::Vec3(0.0f, -1.0f, 0.0f)); + osg_texcoords->push_back(osg::Vec2(0.5f, 0.0f)); + osg_vertices->push_back(osg::Vec3(0.0f, bottomY, -radius)); + + bottom->setCount(osg_vertices->size() - first); + osg_geom->addPrimitiveSet(bottom.get()); + } + + osg_geom->setVertexArray(osg_vertices.get()); + osg_geom->setTexCoordArray(0, osg_texcoords.get()); + osg_geom->setNormalArray(osg_normals.get()); + osg_geom->setNormalBinding(osg::Geometry::BIND_PER_VERTEX); + + osg_geom->getOrCreateStateSet()->setAttributeAndModes(new osg::CullFace(osg::CullFace::BACK)); + + return osg_geom.get(); +} + +osg::ref_ptr ReaderWriterVRML2::convertVRML97Cylinder(openvrml::vrml97_node::cylinder_node* vrml_cylinder) +{ + osg::ref_ptr osg_geom = new osg::Geometry(); + + float height = static_cast(vrml_cylinder->field("height")).value; + float radius = static_cast(vrml_cylinder->field("radius")).value; + + osg::ref_ptr osg_vertices = new osg::Vec3Array(); + osg::ref_ptr osg_texcoords = new osg::Vec2Array(); + osg::ref_ptr osg_normals = new osg::Vec3Array(); + + unsigned int numSegments = 40; + + const float thetaDelta = 2.0f * float(osg::PI) / float(numSegments); + + + float topY = height * 0.5f; + float bottomY = height * -0.5f; + + if (static_cast(vrml_cylinder->field("side")).value) + { + osg::ref_ptr side = new osg::DrawArrays(osg::PrimitiveSet::QUAD_STRIP); + + const float texCoordDelta = 1.0f / float(numSegments); + float theta = 0.0f; + float texCoord = 0.0f; + + for (unsigned int i = 0; i < numSegments; ++i, theta += thetaDelta, texCoord += texCoordDelta) + { + std::complex n = -std::polar(1.0f, theta); + std::complex e = n * radius; + + osg::Vec3 normal(n.imag(), 0.0f, n.real()); + + osg_normals->push_back(normal); + osg_normals->push_back(normal); + + osg_texcoords->push_back(osg::Vec2(texCoord, 1.0f)); + osg_texcoords->push_back(osg::Vec2(texCoord, 0.0f)); + + osg_vertices->push_back(osg::Vec3(e.imag(), topY, e.real())); + osg_vertices->push_back(osg::Vec3(e.imag(), bottomY, e.real())); + } + + // do last point by hand to ensure no round off errors. + + osg::Vec3 normal(0.0f, 0.0f, -1.0f); + osg_normals->push_back(normal); + osg_normals->push_back(normal); + + osg_texcoords->push_back(osg::Vec2(1.0f, 1.0f)); + osg_texcoords->push_back(osg::Vec2(1.0f, 0.0f)); + + osg_vertices->push_back(osg::Vec3(0.0f, topY, -radius)); + osg_vertices->push_back(osg::Vec3(0.0f, bottomY, -radius)); + + side->setCount(osg_vertices->size()); + osg_geom->addPrimitiveSet(side.get()); + } + + if (static_cast(vrml_cylinder->field("bottom")).value) + { + osg::ref_ptr bottom = new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_FAN); + + size_t first = osg_vertices->size(); + bottom->setFirst(first); + + float theta = 0.0f; + + for (unsigned int i = 0; i < numSegments; ++i, theta += thetaDelta) + { + std::complex n = -std::polar(1.0f, theta); + std::complex e = n * radius; + + osg_normals->push_back(osg::Vec3(0.0f, -1.0f, 0.0f)); + osg_texcoords->push_back(osg::Vec2(0.5f - 0.5f * n.imag(), 0.5f + 0.5f * n.real())); + osg_vertices->push_back(osg::Vec3(-e.imag(), bottomY, e.real())); + } + + // do last point by hand to ensure no round off errors. + + osg_normals->push_back(osg::Vec3(0.0f, -1.0f, 0.0f)); + osg_texcoords->push_back(osg::Vec2(0.5f, 0.0f)); + osg_vertices->push_back(osg::Vec3(0.0f, bottomY, -radius)); + + bottom->setCount(osg_vertices->size() - first); + osg_geom->addPrimitiveSet(bottom.get()); + } + + if (static_cast(vrml_cylinder->field("top")).value) + { + osg::ref_ptr top = new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_FAN); + + size_t first = osg_vertices->size(); + top->setFirst(first); + + float theta = 0.0f; + + for (unsigned int i = 0; i < numSegments; ++i, theta += thetaDelta) + { + std::complex n = -std::polar(1.0f, theta); + std::complex e = n * radius; + + osg_normals->push_back(osg::Vec3(0.0f, 1.0f, 0.0f)); + osg_texcoords->push_back(osg::Vec2(0.5f + 0.5f * n.imag(), 0.5f - 0.5f * n.real())); + osg_vertices->push_back(osg::Vec3(e.imag(), topY, e.real())); + } + + // do last point by hand to ensure no round off errors. + + osg_normals->push_back(osg::Vec3(0.0f, 1.0f, 0.0f)); + osg_texcoords->push_back(osg::Vec2(0.5f, 1.0f)); + osg_vertices->push_back(osg::Vec3(0.0f, topY, -radius)); + + top->setCount(osg_vertices->size() - first); + osg_geom->addPrimitiveSet(top.get()); + } + + osg_geom->setVertexArray(osg_vertices.get()); + osg_geom->setTexCoordArray(0, osg_texcoords.get()); + osg_geom->setNormalArray(osg_normals.get()); + osg_geom->setNormalBinding(osg::Geometry::BIND_PER_VERTEX); + + osg_geom->getOrCreateStateSet()->setAttributeAndModes(new osg::CullFace(osg::CullFace::BACK)); + + return osg_geom.get(); +} diff --git a/src/osgPlugins/vrml/ReaderWriterVRML2.cpp b/src/osgPlugins/vrml/ReaderWriterVRML2.cpp index 02ad6ab7b..03066922b 100644 --- a/src/osgPlugins/vrml/ReaderWriterVRML2.cpp +++ b/src/osgPlugins/vrml/ReaderWriterVRML2.cpp @@ -14,10 +14,16 @@ * */ +#include "ReaderWriterVRML2.h" + #include #include -#include -#include + +#if defined(_MSC_VER) +# pragma warning(disable: 4250) +# pragma warning(disable: 4290) +# pragma warning(disable: 4800) +#endif #include #include @@ -50,29 +56,6 @@ #include -/** - * OpenSceneGraph plugin wrapper/converter. - */ -class ReaderWriterVRML2 : public osgDB::ReaderWriter -{ - public: - ReaderWriterVRML2() { } - - virtual const char* className() - { - return "VRML2 Reader/Writer"; - } - - virtual bool acceptsExtension(const std::string& extension) - { - return osgDB::equalCaseInsensitive(extension, "wrl") ? true : false; - } - - virtual ReadResult readNode(const std::string&, const osgDB::ReaderWriter::Options *options = NULL) const; - private: - osg::ref_ptr convertFromVRML(openvrml::node *obj) const; -}; - // Register with Registry to instantiate the above reader/writer. REGISTER_OSGPLUGIN(vrml, ReaderWriterVRML2) @@ -95,6 +78,8 @@ osgDB::ReaderWriter::ReadResult ReaderWriterVRML2::readNode(const std::string &f else // relative path fileName = unixFileName; + + std::fstream null; openvrml::browser *browser = new openvrml::browser(null, null); @@ -115,17 +100,17 @@ osgDB::ReaderWriter::ReadResult ReaderWriterVRML2::readNode(const std::string &f 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1)); - + osgDB::getDataFilePathList().push_front(osgDB::getFilePath(unixFileName)); for (unsigned i = 0; i < mfn.size(); i++) { openvrml::node *vrml_node = mfn[i].get(); osg_root->addChild(convertFromVRML(vrml_node).get()); } - + osgDB::getDataFilePathList().pop_front(); return osg_root.get(); } } -osg::ref_ptr ReaderWriterVRML2::convertFromVRML(openvrml::node *obj) const +osg::ref_ptr ReaderWriterVRML2::convertFromVRML(openvrml::node *obj) { std::string name = obj->id(); static int osgLightNum = 0; //light @@ -158,7 +143,8 @@ osg::ref_ptr ReaderWriterVRML2::convertFromVRML(openvrml::node *obj) return osg_group.get(); - } else if (obj->type.id == "Transform") // Handle transforms + } + else if (obj->type.id == "Transform") // Handle transforms { openvrml::vrml97_node::transform_node *vrml_transform; vrml_transform = dynamic_cast(obj); @@ -185,16 +171,10 @@ osg::ref_ptr ReaderWriterVRML2::convertFromVRML(openvrml::node *obj) return osg_m.get(); - } else if (obj->type.id == "Shape") // Handle Shape node + } + else if (obj->type.id == "Shape") // Handle Shape node { - osg::ref_ptr osg_geode = new osg::Geode(); - osg::ref_ptr osg_geom = new osg::Geometry(); - osg_geode->addDrawable(osg_geom.get()); - osg::StateSet *osg_stateset = osg_geom->getOrCreateStateSet(); - - osg::ref_ptr osg_mat = new osg::Material(); - osg_stateset->setAttributeAndModes(osg_mat.get()); - osg_mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); + osg::ref_ptr osg_geom; // parse the geometry { @@ -210,663 +190,23 @@ osg::ref_ptr ReaderWriterVRML2::convertFromVRML(openvrml::node *obj) if (openvrml::vrml97_node::indexed_face_set_node *vrml_ifs = dynamic_cast(vrml_geom)) { - osg_geom->addPrimitiveSet(new osg::DrawArrayLengths(osg::PrimitiveSet::POLYGON)); - - // get array of vertex coordinate_nodes - { - const openvrml::field_value& fv = vrml_ifs->field("coord"); - const openvrml::sfnode& sfn = dynamic_cast(fv); - openvrml::vrml97_node::coordinate_node* vrml_coord_node = dynamic_cast(sfn.value.get()); - - const std::vector& vrml_coord = vrml_coord_node->point(); - osg::ref_ptr osg_vertices = new osg::Vec3Array(); - - unsigned i; - for (i = 0; i < vrml_coord.size(); i++) - { - openvrml::vec3f vec = vrml_coord[i]; - osg_vertices->push_back(osg::Vec3(vec[0], vec[1], vec[2])); - } - - osg_geom->setVertexArray(osg_vertices.get()); - - // get array of vertex indices - const openvrml::field_value &fv2 = vrml_ifs->field("coordIndex"); - const openvrml::mfint32 &vrml_coord_index = dynamic_cast(fv2); - - osg::ref_ptr osg_vert_index = new osg::IntArray(); - - int num_vert = 0; - for (i = 0; i < vrml_coord_index.value.size(); i++) - { - int index = vrml_coord_index.value[i]; - if (index == -1) - { - static_cast(osg_geom->getPrimitiveSet(0))->push_back(num_vert); - num_vert = 0; - } - else - { - osg_vert_index->push_back(index); - ++num_vert; - } - } - if (num_vert) - { - //GvdB: Last coordIndex wasn't -1 - static_cast(osg_geom->getPrimitiveSet(0))->push_back(num_vert); - } - - osg_geom->setVertexIndices(osg_vert_index.get()); - } - - { - // get texture coordinate_nodes - const openvrml::field_value &fv = vrml_ifs->field("texCoord"); - const openvrml::sfnode &sfn = dynamic_cast(fv); - openvrml::vrml97_node::texture_coordinate_node *vrml_tex_coord_node = - dynamic_cast(sfn.value.get()); - - if (vrml_tex_coord_node != 0) // if no texture, node is NULL pointer - { - const std::vector &vrml_tex_coord = vrml_tex_coord_node->point(); - osg::ref_ptr osg_texcoords = new osg::Vec2Array(); - - unsigned i; - for (i = 0; i < vrml_tex_coord.size(); i++) - { - openvrml::vec2f vec = vrml_tex_coord[i]; - osg_texcoords->push_back(osg::Vec2(vec[0], vec[1])); - } - - osg_geom->setTexCoordArray(0, osg_texcoords.get()); - - // get array of texture indices - const openvrml::field_value &fv2 = vrml_ifs->field("texCoordIndex"); - const openvrml::mfint32 &vrml_tex_coord_index = dynamic_cast(fv2); - - osg::ref_ptr osg_tex_coord_index = new osg::IntArray(); - - if(vrml_tex_coord_index.value.size() > 0) - { - for (i = 0; i < vrml_tex_coord_index.value.size(); i++) - { - int index = vrml_tex_coord_index.value[i]; - if (index != -1) { - osg_tex_coord_index->push_back(index); - } - } - osg_geom->setTexCoordIndices(0, osg_tex_coord_index.get()); - } else - // no indices defined, use coordIndex - osg_geom->setTexCoordIndices(0, osg_geom->getVertexIndices()); - } - } - - // get array of normals per vertex (if specified) - { - const openvrml::field_value& fv = vrml_ifs->field("normal"); - const openvrml::sfnode& sfn = dynamic_cast(fv); - openvrml::vrml97_node::normal_node* vrml_normal_node = dynamic_cast(sfn.value.get()); - - if (vrml_normal_node != 0) // if no normals, node is NULL pointer - { - const std::vector& vrml_normal_coord = vrml_normal_node->vector(); - - osg::ref_ptr osg_normalcoords = new osg::Vec3Array(); - - unsigned i; - for (i = 0; i < vrml_normal_coord.size(); i++) - { - const openvrml::vec3f vec = vrml_normal_coord[i]; - osg_normalcoords->push_back(osg::Vec3(vec[0], vec[1], vec[2])); - } - osg_geom->setNormalArray(osg_normalcoords.get()); - - // get array of normal indices - const openvrml::field_value& fv2 = vrml_ifs->field("normalIndex"); - const openvrml::mfint32& vrml_normal_index = dynamic_cast(fv2); - - osg::ref_ptr osg_normal_index = new osg::IntArray(); - - if (vrml_normal_index.value.size() > 0) - { - for (i = 0; i < vrml_normal_index.value.size(); i++) - { - int index = vrml_normal_index.value[i]; - if (index != -1) - { - osg_normal_index->push_back(index); - } - } - osg_geom->setNormalIndices(osg_normal_index.get()); - } - else - // unspecified, use the coordIndex field - osg_geom->setNormalIndices(osg_geom->getVertexIndices()); - - // get normal binding - const openvrml::field_value &fv3 = vrml_ifs->field("normalPerVertex"); - const openvrml::sfbool &vrml_norm_per_vertex = dynamic_cast(fv3); - - if (vrml_norm_per_vertex.value) - { - osg_geom->setNormalBinding(osg::Geometry::BIND_PER_VERTEX); - } else - { - osg_geom->setNormalBinding(osg::Geometry::BIND_PER_PRIMITIVE); - } - } - } - - // get array of colours per vertex (if specified) - { - const openvrml::field_value &fv = vrml_ifs->field("color"); - const openvrml::sfnode &sfn = dynamic_cast(fv); - openvrml::vrml97_node::color_node *vrml_color_node = - dynamic_cast(sfn.value.get()); - - if (vrml_color_node != 0) // if no colors, node is NULL pointer - { - const std::vector &vrml_colors = vrml_color_node->color(); - - osg::ref_ptr osg_colors = new osg::Vec3Array(); - - unsigned i; - for (i = 0; i < vrml_colors.size(); i++) - { - const openvrml::color color = vrml_colors[i]; - osg_colors->push_back(osg::Vec3(color.r(), color.g(), color.b())); - } - osg_geom->setColorArray(osg_colors.get()); - - // get array of color indices - const openvrml::field_value &fv2 = vrml_ifs->field("colorIndex"); - const openvrml::mfint32 &vrml_color_index = dynamic_cast(fv2); - - osg::ref_ptr osg_color_index = new osg::IntArray(); - - if(vrml_color_index.value.size() > 0) - { - for (i = 0; i < vrml_color_index.value.size(); i++) - { - int index = vrml_color_index.value[i]; - if (index != -1) { - osg_color_index->push_back(index); - } - } - osg_geom->setColorIndices(osg_color_index.get()); - } else - // unspecified, use coordIndices field - osg_geom->setColorIndices(osg_geom->getVertexIndices()); - - // get color binding - const openvrml::field_value &fv3 = vrml_ifs->field("colorPerVertex"); - const openvrml::sfbool &vrml_color_per_vertex = dynamic_cast(fv3); - - if (vrml_color_per_vertex.value) - { - osg_geom->setColorBinding(osg::Geometry::BIND_PER_VERTEX); - } else - { - osg_geom->setColorBinding(osg::Geometry::BIND_PER_PRIMITIVE); - } - } - } - - if (static_cast(vrml_ifs->field("solid")).value) - { - osg_stateset->setAttributeAndModes(new osg::CullFace(osg::CullFace::BACK)); - } - - if (!osg_geom->getNormalArray()) - { -#if 0 - // GvdB: This is what I wanted to do, but got zero normals since the triangles were considered temporaries (?) - osgUtil::SmoothingVisitor().smooth(*osg_geom); -#else - // GvdB: So I ended up computing the smoothing normals myself. Also, I might add support for "creaseAngle" if a big need for it rises. - // However, for now I can perfectly live with the fact that all edges are smoothed despite the use of a crease angle. - osg::Vec3Array& coords = *static_cast(osg_geom->getVertexArray()); - assert(coords.size()); - - osg::Vec3Array* normals = new osg::Vec3Array(coords.size()); - - for (osg::Vec3Array::iterator it = normals->begin(); it != normals->end(); ++it) - { - (*it).set(0.0f, 0.0f, 0.0f); - } - - - osg::IntArray& indices = *static_cast(osg_geom->getVertexIndices()); - osg::DrawArrayLengths& lengths = *static_cast(osg_geom->getPrimitiveSet(0)); - int index = 0; - - for (osg::DrawArrayLengths::iterator it = lengths.begin(); it != lengths.end(); ++it) - { - assert(*it >= 3); - const osg::Vec3& v0 = coords[indices[index]]; - const osg::Vec3& v1 = coords[indices[index + 1]]; - const osg::Vec3& v2 = coords[indices[index + 2]]; - - osg::Vec3 normal = (v1 - v0) ^ (v2 - v0); - normal.normalize(); - - for (int i = 0; i != *it; ++i) - { - (*normals)[indices[index + i]] += normal; - } - - index += *it; - } - - assert(index == indices.size()); - - for(osg::Vec3Array::iterator it = normals->begin(); it != normals->end(); ++it) - { - (*it).normalize(); - } - - osg_geom->setNormalArray(normals); - osg_geom->setNormalIndices(osg_geom->getVertexIndices()); - osg_geom->setNormalBinding(osg::Geometry::BIND_PER_VERTEX); - -#endif - } - - - osg::DrawArrayLengths& lengths = *static_cast(osg_geom->getPrimitiveSet(0)); - - osg::DrawArrayLengths::iterator it = lengths.begin(); - if (it != lengths.end()) - { - switch (*it) - { - case 3: - while (++it != lengths.end() && *it == 3) - ; - - if (it == lengths.end()) - { - // All polys are triangles - osg::ref_ptr mesh = new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES); - mesh->setCount(lengths.size() * 3); - osg_geom->removePrimitiveSet(0); - osg_geom->addPrimitiveSet(mesh.get()); - } - break; - - case 4: - while (++it != lengths.end() && *it == 4) - ; - - if (it == lengths.end()) - { - // All polys are quads - osg::ref_ptr mesh = new osg::DrawArrays(osg::PrimitiveSet::QUADS); - mesh->setCount(lengths.size() * 4); - osg_geom->removePrimitiveSet(0); - osg_geom->addPrimitiveSet(mesh.get()); - } - - break; - } - } + osg_geom = convertVRML97IndexedFaceSet(vrml_ifs); } else if (openvrml::vrml97_node::box_node* vrml_box = dynamic_cast(vrml_geom)) { - const openvrml::vec3f& size = static_cast(vrml_box->field("size")).value; - - osg::Vec3 halfSize(size[0] * 0.5f, size[1] * 0.5f, size[2] * 0.5f); - - osg::ref_ptr osg_vertices = new osg::Vec3Array(); - osg::ref_ptr osg_texcoords = new osg::Vec2Array(); - osg::ref_ptr osg_normals = new osg::Vec3Array(); - - osg::ref_ptr box = new osg::DrawArrays(osg::PrimitiveSet::QUADS); - - osg_vertices->push_back(osg::Vec3(-halfSize[0], halfSize[1], halfSize[2])); - osg_vertices->push_back(osg::Vec3(-halfSize[0], -halfSize[1], halfSize[2])); - osg_vertices->push_back(osg::Vec3(halfSize[0], -halfSize[1], halfSize[2])); - osg_vertices->push_back(osg::Vec3(halfSize[0], halfSize[1], halfSize[2])); - - osg_vertices->push_back(osg::Vec3(halfSize[0], halfSize[1], -halfSize[2])); - osg_vertices->push_back(osg::Vec3(halfSize[0], -halfSize[1], -halfSize[2])); - osg_vertices->push_back(osg::Vec3(-halfSize[0], -halfSize[1], -halfSize[2])); - osg_vertices->push_back(osg::Vec3(-halfSize[0], halfSize[1], -halfSize[2])); - - osg_vertices->push_back(osg::Vec3(halfSize[0], halfSize[1], halfSize[2])); - osg_vertices->push_back(osg::Vec3(halfSize[0], -halfSize[1], halfSize[2])); - osg_vertices->push_back(osg::Vec3(halfSize[0], -halfSize[1], -halfSize[2])); - osg_vertices->push_back(osg::Vec3(halfSize[0], halfSize[1], -halfSize[2])); - - osg_vertices->push_back(osg::Vec3(-halfSize[0], halfSize[1], -halfSize[2])); - osg_vertices->push_back(osg::Vec3(-halfSize[0], -halfSize[1], -halfSize[2])); - osg_vertices->push_back(osg::Vec3(-halfSize[0], -halfSize[1], halfSize[2])); - osg_vertices->push_back(osg::Vec3(-halfSize[0], halfSize[1], halfSize[2])); - - osg_vertices->push_back(osg::Vec3(-halfSize[0], halfSize[1], -halfSize[2])); - osg_vertices->push_back(osg::Vec3(-halfSize[0], halfSize[1], halfSize[2])); - osg_vertices->push_back(osg::Vec3(halfSize[0], halfSize[1], halfSize[2])); - osg_vertices->push_back(osg::Vec3(halfSize[0], halfSize[1], -halfSize[2])); - - osg_vertices->push_back(osg::Vec3(-halfSize[0], -halfSize[1], halfSize[2])); - osg_vertices->push_back(osg::Vec3(-halfSize[0], -halfSize[1], -halfSize[2])); - osg_vertices->push_back(osg::Vec3(halfSize[0], -halfSize[1], -halfSize[2])); - osg_vertices->push_back(osg::Vec3(halfSize[0], -halfSize[1], halfSize[2])); - - for (int i = 0; i != 6; ++i) - { - osg_texcoords->push_back(osg::Vec2(0.0f, 1.0f)); - osg_texcoords->push_back(osg::Vec2(0.0f, 0.0f)); - osg_texcoords->push_back(osg::Vec2(1.0f, 0.0f)); - osg_texcoords->push_back(osg::Vec2(1.0f, 1.0f)); - } - - osg_normals->push_back(osg::Vec3(0.0f, 0.0f, 1.0f)); - osg_normals->push_back(osg::Vec3(0.0f, 0.0f, -1.0f)); - osg_normals->push_back(osg::Vec3(1.0f, 0.0f, 0.0f)); - osg_normals->push_back(osg::Vec3(-1.0f, 0.0f, 0.0f)); - osg_normals->push_back(osg::Vec3(0.0f, 1.0f, 0.0f)); - osg_normals->push_back(osg::Vec3(0.0f, -1.0f, 0.0f)); - - box->setCount(osg_vertices->size()); - - osg_geom->addPrimitiveSet(box.get()); - - osg_geom->setVertexArray(osg_vertices.get()); - osg_geom->setTexCoordArray(0, osg_texcoords.get()); - osg_geom->setNormalArray(osg_normals.get()); - osg_geom->setNormalBinding(osg::Geometry::BIND_PER_PRIMITIVE); - - osg_stateset->setAttributeAndModes(new osg::CullFace(osg::CullFace::BACK)); + osg_geom = convertVRML97Box(vrml_box); } else if (openvrml::vrml97_node::sphere_node* vrml_sphere = dynamic_cast(vrml_geom)) { - float radius = static_cast(vrml_sphere->field("radius")).value; - - osg::ref_ptr osg_vertices = new osg::Vec3Array(); - osg::ref_ptr osg_texcoords = new osg::Vec2Array(); - osg::ref_ptr osg_normals = new osg::Vec3Array(); - - unsigned int numSegments = 40; - unsigned int numRows = 20; - - const float thetaDelta = 2.0f * float(osg::PI) / float(numSegments); - const float texCoordSDelta = 1.0f / float(numSegments); - const float phiDelta = float(osg::PI) / float(numRows); - const float texCoordTDelta = 1.0f / float(numRows); - - float phi = -0.5f * float(osg::PI); - float texCoordT = 0.0f; - - osg::ref_ptr sphere = new osg::DrawArrayLengths(osg::PrimitiveSet::QUAD_STRIP); - - for (unsigned int i = 0; i < numRows; ++i, phi += phiDelta, texCoordT += texCoordTDelta) - { - std::complex latBottom = std::polar(1.0f, phi); - std::complex latTop = std::polar(1.0f, phi + phiDelta); - std::complex eBottom = latBottom * radius; - std::complex eTop = latTop * radius; - - float theta = 0.0f; - float texCoordS = 0.0f; - - for (unsigned int j = 0; j < numSegments; ++j, theta += thetaDelta, texCoordS += texCoordSDelta) - { - std::complex n = -std::polar(1.0f, theta); - - osg_normals->push_back(osg::Vec3(latTop.real() * n.imag(), latTop.imag(), latTop.real() * n.real())); - osg_normals->push_back(osg::Vec3(latBottom.real() * n.imag(), latBottom.imag(), latBottom.real() * n.real())); - - osg_texcoords->push_back(osg::Vec2(texCoordS, texCoordT + texCoordTDelta)); - osg_texcoords->push_back(osg::Vec2(texCoordS, texCoordT)); - - osg_vertices->push_back(osg::Vec3(eTop.real() * n.imag(), eTop.imag(), eTop.real() * n.real())); - osg_vertices->push_back(osg::Vec3(eBottom.real() * n.imag(), eBottom.imag(), eBottom.real() * n.real())); - } - - osg_normals->push_back(osg::Vec3(0.0f, latTop.imag(), -latTop.real())); - osg_normals->push_back(osg::Vec3(0.0f, latBottom.imag(), -latBottom.real())); - - osg_texcoords->push_back(osg::Vec2(1.0f, texCoordT + texCoordTDelta)); - osg_texcoords->push_back(osg::Vec2(1.0f, texCoordT)); - - osg_vertices->push_back(osg::Vec3(0.0f, eTop.imag(), -eTop.real())); - osg_vertices->push_back(osg::Vec3(0.0f, eBottom.imag(), -eBottom.real())); - - sphere->push_back(numSegments * 2 + 2); - } - - osg_geom->addPrimitiveSet(sphere.get()); - - osg_geom->setVertexArray(osg_vertices.get()); - osg_geom->setTexCoordArray(0, osg_texcoords.get()); - osg_geom->setNormalArray(osg_normals.get()); - osg_geom->setNormalBinding(osg::Geometry::BIND_PER_VERTEX); - - osg_stateset->setAttributeAndModes(new osg::CullFace(osg::CullFace::BACK)); - + osg_geom = convertVRML97Sphere(vrml_sphere); } else if (openvrml::vrml97_node::cone_node* vrml_cone = dynamic_cast(vrml_geom)) { - float height = static_cast(vrml_cone->field("height")).value; - float radius = static_cast(vrml_cone->field("bottomRadius")).value; - - osg::ref_ptr osg_vertices = new osg::Vec3Array(); - osg::ref_ptr osg_texcoords = new osg::Vec2Array(); - osg::ref_ptr osg_normals = new osg::Vec3Array(); - - unsigned int numSegments = 40; - - const float thetaDelta = 2.0f * float(osg::PI) / float(numSegments); - - float topY = height * 0.5f; - float bottomY = height * -0.5f; - - if (static_cast(vrml_cone->field("side")).value) - { - osg::ref_ptr side = new osg::DrawArrays(osg::PrimitiveSet::QUAD_STRIP); - - const float texCoordDelta = 1.0f / float(numSegments); - float theta = 0.0f; - float texCoord = 0.0f; - - for (unsigned int i = 0; i < numSegments; ++i, theta += thetaDelta, texCoord += texCoordDelta) - { - std::complex n = -std::polar(1.0f, theta); - std::complex e = n * radius; - - osg::Vec3 normal(n.imag() * height, radius, n.real() * height); - normal.normalize(); - - osg_normals->push_back(normal); - osg_normals->push_back(normal); - - osg_texcoords->push_back(osg::Vec2(texCoord, 1.0f)); - osg_texcoords->push_back(osg::Vec2(texCoord, 0.0f)); - - osg_vertices->push_back(osg::Vec3(0.0f, topY, 0.0f)); - osg_vertices->push_back(osg::Vec3(e.imag(), bottomY, e.real())); - } - - // do last point by hand to ensure no round off errors. - - osg::Vec3 normal(0.0f, radius, -height); - normal.normalize(); - - osg_normals->push_back(normal); - osg_normals->push_back(normal); - - osg_texcoords->push_back(osg::Vec2(1.0f, 1.0f)); - osg_texcoords->push_back(osg::Vec2(1.0f, 0.0f)); - - osg_vertices->push_back(osg::Vec3(0.0f, topY, 0.0f)); - osg_vertices->push_back(osg::Vec3(0.0f, bottomY, -radius)); - - side->setCount(osg_vertices->size()); - osg_geom->addPrimitiveSet(side.get()); - } - - if (static_cast(vrml_cone->field("bottom")).value) - { - osg::ref_ptr bottom = new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_FAN); - - - size_t first = osg_vertices->size(); - bottom->setFirst(first); - - float theta = 0.0f; - - for (unsigned int i = 0; i < numSegments; ++i, theta += thetaDelta) - { - std::complex n = -std::polar(1.0f, theta); - std::complex e = n * radius; - - osg_normals->push_back(osg::Vec3(0.0f, -1.0f, 0.0f)); - osg_texcoords->push_back(osg::Vec2(0.5f - 0.5f * n.imag(), 0.5f + 0.5f * n.real())); - osg_vertices->push_back(osg::Vec3(-e.imag(), bottomY, e.real())); - } - - // do last point by hand to ensure no round off errors. - - osg_normals->push_back(osg::Vec3(0.0f, -1.0f, 0.0f)); - osg_texcoords->push_back(osg::Vec2(0.5f, 0.0f)); - osg_vertices->push_back(osg::Vec3(0.0f, bottomY, -radius)); - - bottom->setCount(osg_vertices->size() - first); - osg_geom->addPrimitiveSet(bottom.get()); - } - - osg_geom->setVertexArray(osg_vertices.get()); - osg_geom->setTexCoordArray(0, osg_texcoords.get()); - osg_geom->setNormalArray(osg_normals.get()); - osg_geom->setNormalBinding(osg::Geometry::BIND_PER_VERTEX); - - osg_stateset->setAttributeAndModes(new osg::CullFace(osg::CullFace::BACK)); + osg_geom = convertVRML97Cone(vrml_cone); } else if (openvrml::vrml97_node::cylinder_node* vrml_cylinder = dynamic_cast(vrml_geom)) { - float height = static_cast(vrml_cylinder->field("height")).value; - float radius = static_cast(vrml_cylinder->field("radius")).value; - - osg::ref_ptr osg_vertices = new osg::Vec3Array(); - osg::ref_ptr osg_texcoords = new osg::Vec2Array(); - osg::ref_ptr osg_normals = new osg::Vec3Array(); - - unsigned int numSegments = 40; - - const float thetaDelta = 2.0f * float(osg::PI) / float(numSegments); - - - float topY = height * 0.5f; - float bottomY = height * -0.5f; - - if (static_cast(vrml_cylinder->field("side")).value) - { - osg::ref_ptr side = new osg::DrawArrays(osg::PrimitiveSet::QUAD_STRIP); - - const float texCoordDelta = 1.0f / float(numSegments); - float theta = 0.0f; - float texCoord = 0.0f; - - for (unsigned int i = 0; i < numSegments; ++i, theta += thetaDelta, texCoord += texCoordDelta) - { - std::complex n = -std::polar(1.0f, theta); - std::complex e = n * radius; - - osg::Vec3 normal(n.imag(), 0.0f, n.real()); - - osg_normals->push_back(normal); - osg_normals->push_back(normal); - - osg_texcoords->push_back(osg::Vec2(texCoord, 1.0f)); - osg_texcoords->push_back(osg::Vec2(texCoord, 0.0f)); - - osg_vertices->push_back(osg::Vec3(e.imag(), topY, e.real())); - osg_vertices->push_back(osg::Vec3(e.imag(), bottomY, e.real())); - } - - // do last point by hand to ensure no round off errors. - - osg::Vec3 normal(0.0f, 0.0f, -1.0f); - osg_normals->push_back(normal); - osg_normals->push_back(normal); - - osg_texcoords->push_back(osg::Vec2(1.0f, 1.0f)); - osg_texcoords->push_back(osg::Vec2(1.0f, 0.0f)); - - osg_vertices->push_back(osg::Vec3(0.0f, topY, -radius)); - osg_vertices->push_back(osg::Vec3(0.0f, bottomY, -radius)); - - side->setCount(osg_vertices->size()); - osg_geom->addPrimitiveSet(side.get()); - } - - if (static_cast(vrml_cylinder->field("bottom")).value) - { - osg::ref_ptr bottom = new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_FAN); - - size_t first = osg_vertices->size(); - bottom->setFirst(first); - - float theta = 0.0f; - - for (unsigned int i = 0; i < numSegments; ++i, theta += thetaDelta) - { - std::complex n = -std::polar(1.0f, theta); - std::complex e = n * radius; - - osg_normals->push_back(osg::Vec3(0.0f, -1.0f, 0.0f)); - osg_texcoords->push_back(osg::Vec2(0.5f - 0.5f * n.imag(), 0.5f + 0.5f * n.real())); - osg_vertices->push_back(osg::Vec3(-e.imag(), bottomY, e.real())); - } - - // do last point by hand to ensure no round off errors. - - osg_normals->push_back(osg::Vec3(0.0f, -1.0f, 0.0f)); - osg_texcoords->push_back(osg::Vec2(0.5f, 0.0f)); - osg_vertices->push_back(osg::Vec3(0.0f, bottomY, -radius)); - - bottom->setCount(osg_vertices->size() - first); - osg_geom->addPrimitiveSet(bottom.get()); - } - - if (static_cast(vrml_cylinder->field("top")).value) - { - osg::ref_ptr top = new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_FAN); - - size_t first = osg_vertices->size(); - top->setFirst(first); - - float theta = 0.0f; - - for (unsigned int i = 0; i < numSegments; ++i, theta += thetaDelta) - { - std::complex n = -std::polar(1.0f, theta); - std::complex e = n * radius; - - osg_normals->push_back(osg::Vec3(0.0f, 1.0f, 0.0f)); - osg_texcoords->push_back(osg::Vec2(0.5f + 0.5f * n.imag(), 0.5f - 0.5f * n.real())); - osg_vertices->push_back(osg::Vec3(e.imag(), topY, e.real())); - } - - // do last point by hand to ensure no round off errors. - - osg_normals->push_back(osg::Vec3(0.0f, 1.0f, 0.0f)); - osg_texcoords->push_back(osg::Vec2(0.5f, 1.0f)); - osg_vertices->push_back(osg::Vec3(0.0f, topY, -radius)); - - top->setCount(osg_vertices->size() - first); - osg_geom->addPrimitiveSet(top.get()); - } - - osg_geom->setVertexArray(osg_vertices.get()); - osg_geom->setTexCoordArray(0, osg_texcoords.get()); - osg_geom->setNormalArray(osg_normals.get()); - osg_geom->setNormalBinding(osg::Geometry::BIND_PER_VERTEX); - - osg_stateset->setAttributeAndModes(new osg::CullFace(osg::CullFace::BACK)); + osg_geom = convertVRML97Cylinder(vrml_cylinder); } else { @@ -875,6 +215,15 @@ osg::ref_ptr ReaderWriterVRML2::convertFromVRML(openvrml::node *obj) } } + osg::ref_ptr osg_geode = new osg::Geode(); + osg_geode->addDrawable(osg_geom.get()); + osg::StateSet *osg_stateset = osg_geode->getOrCreateStateSet(); + + osg::ref_ptr osg_mat = new osg::Material(); + osg_stateset->setAttributeAndModes(osg_mat.get()); + osg_mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); + + // parse the appearance { const openvrml::field_value &fv = obj->field("appearance"); @@ -985,7 +334,8 @@ osg::ref_ptr ReaderWriterVRML2::convertFromVRML(openvrml::node *obj) osg_stateset->setTextureAttributeAndModes(0, texture.get()); //osg_stateset->setMode(GL_BLEND,osg::StateAttribute::ON); //bhbn - } else { + } + else { std::cerr << "texture file " << url << " not found !" << std::endl << std::flush; } } @@ -993,7 +343,9 @@ osg::ref_ptr ReaderWriterVRML2::convertFromVRML(openvrml::node *obj) } return osg_geode.get(); - } else { + } + else + { return 0; } diff --git a/src/osgPlugins/vrml/ReaderWriterVRML2.h b/src/osgPlugins/vrml/ReaderWriterVRML2.h new file mode 100644 index 000000000..844eff71b --- /dev/null +++ b/src/osgPlugins/vrml/ReaderWriterVRML2.h @@ -0,0 +1,71 @@ +// -*-c++-*- + +/* + * + * VRML2 file converter for OpenSceneGraph. + * + * authors : Jan Ciger (jan.ciger@gmail.com), + * Tolga Abaci (tolga.abaci@gmail.com), + * Bruno Herbelin (bruno.herbelin@gmail.com) + * + * (c) VRlab EPFL, Switzerland, 2004-2006 + * + * Gino van den Bergen, DTECTA (gino@dtecta.com) + * + */ + +#include + +#include +#include + +#include +#include +#include +#include + +namespace openvrml +{ + class node; + + namespace vrml97_node + { + class indexed_face_set_node; + class box_node; + class sphere_node; + class cone_node; + class cylinder_node; + } +} + +/** + * OpenSceneGraph plugin wrapper/converter. + */ +class ReaderWriterVRML2 + : public osgDB::ReaderWriter +{ +public: + ReaderWriterVRML2() + {} + + virtual const char* className() + { + return "VRML2 Reader/Writer"; + } + + virtual bool acceptsExtension(const std::string& extension) + { + return osgDB::equalCaseInsensitive(extension, "wrl"); + } + + virtual ReadResult readNode(const std::string&, const osgDB::ReaderWriter::Options *options = NULL) const; + +private: + static osg::ref_ptr convertFromVRML(openvrml::node *obj); + + static osg::ref_ptr convertVRML97IndexedFaceSet(openvrml::vrml97_node::indexed_face_set_node *vrml_ifs); + static osg::ref_ptr convertVRML97Box(openvrml::vrml97_node::box_node* vrml_box); + static osg::ref_ptr convertVRML97Sphere(openvrml::vrml97_node::sphere_node* vrml_sphere); + static osg::ref_ptr convertVRML97Cone(openvrml::vrml97_node::cone_node* vrml_cone); + static osg::ref_ptr convertVRML97Cylinder(openvrml::vrml97_node::cylinder_node* vrml_cylinder); +};