meshExtension

Introduction

In this example, we show how to instantiate the template MESH scene graph API "MESH" relative classes with Mesh data structures of your own.

The template Mesh relative classes are X3DTK::X3D::MeshBuilder which builds the MESH scene graph and all the processors of the MESH scene graph. As you saw it myStructureComputer you can use the default instantiations (X3DTK::X3D::DefMeshBuilder) and you the MESH scene graph in a non-template C++ code. If you need to add information per vertex, you can create you own data structure by aggregating vertex data structures.

That is what is done in this example, where we want to add a weight information per vertex, aggregating into X3DTK::MESH::MyVertexData:

In this example we also show how to define a new X3D node that contains the weight information as well as the processors to fill the Mesh structure from it.

Some important functions and classes:

Deriving X3D::Coordinate

We derive X3DTK::X3D::Coordinate to add a weight attribute per vertex. So we add a weight member of type X3DTK::MFFloat. As we did it in newNodeViewer for the X3DTK::X3D::FCylinder node, we record the type name as well as the new attribute in the constructor.

Loading X3D::MyCoordinate

We extend the X3DTK::X3D::Loader by setting X3DTK::X3D::MyRenderingCreator as a new creator for the Rendering component.

Defining the new Mesh data structure

To extend the template Mesh class, we define a structure managing the weight data. We call it X3DTK::MESH::VertexWeightData because it is a per vertex information. Then we define our own vertex data, by aggregating the structures we need. Here we want point data, normal data and of course weight data. For that we use the automatic class generation via X3DTK::clist and X3DTK::tlist. Thus define X3DTK::MESH::MyVertexData, X3DTK::MESH::MyFaceData, X3DTK::MESH::MyMeshData.

For Visual Studio 6 users, notice the use of the TEMPLATE_SPECIALIZATION_SUPPORTED preprocessor definition. The difference between the two codes is that in the case of TEMPLATE_SPECIALIZATION_SUPPORTED, the access of data is optional and there won't be a compilation error if the data is not present. The type list cannot be defined in Visual Studio 6, that is why the inheritance is hand-made.

Filling the new Mesh data structure

To fill the new structure, we need to extend the processor X3DTK::X3D::MeshBuilder, by adding a visitor function for X3DTK::X3D::MyCoordinate in which we access to the weight data of the vertices. That is why we derive X3DTK::X3D::MeshBuilderRenderingVisitor.

Saving the new Mesh data structure

We want to build an X3D scene graph from our new mesh structure by taking account of the weight data to create an X3DTK::X3D::MyCoordinate node. We extend X3DTK::MESH::MeshX3DBuilder by deriving X3DTK::MESH::MeshX3DBuilderCoreVisitor.

Using the new data structure.

To use the new data structure, we simply need to create new instances of the X3DTK::X3D::MeshBuilder, X3DTK::MESH::MeshX3DBuilder with our X3DTK::MESH::MyVertexData, X3DTK::MESH::MyFaceData, X3DTK::MESH::MyMeshData as template parameters.

Code

X3D_MyCoordinate.h

#ifndef MYCOORDINATE_H
#define MYCOORDINATE_H

#include <X3DTK/X3D/scenegraph.h>

namespace X3DTK {
namespace X3D {

// Class X3D::MyCoordinate extending the X3D::Coordinate node by adding a weight information.

class MyCoordinate : public Coordinate
{
public:
  MyCoordinate();
  
  void setWeight(const MFFloat &weight);             
  inline const MFFloat &getWeight() const {return _weight;};

private:  
  MFFloat _weight;    
};

}
}

#endif

X3D_MyCoordinate.cpp

#include "X3D_MyCoordinate.h"

#include <iostream>

using namespace std;

namespace X3DTK {
namespace X3D {

MyCoordinate::MyCoordinate()
: Coordinate()
{
  define(Recorder<MyCoordinate>::getTypeName("MyCoordinate"));
  
  define(Recorder<MyCoordinate, MFFloat>::getAttribute("weight", &MyCoordinate::_weight, MFFloat()));
}
             
void MyCoordinate::setWeight(const MFFloat &weight)            
{
  _weight = weight;
}
 
}
}

X3D_MyRenderingCreator.h

#ifndef MYRENDERINGCREATOR_H
#define MYRENDERINGCREATOR_H

#include <X3DTK/X3D/scenegraph.h>

namespace X3DTK {
namespace X3D {

// Component creator for the Rendering component defining the default 
// X3D nodes plus MyCoordinate.

class MyRenderingCreator : public RenderingCreator
{
public:
  MyRenderingCreator();
};

}
}

#endif

X3D_MyRenderingCreator.cpp

#include "X3D_MyRenderingCreator.h"
#include "X3D_MyCoordinate.h"

namespace X3DTK {
namespace X3D {

MyRenderingCreator::MyRenderingCreator()
: RenderingCreator()
{
  // Defines the new creation functions for the new nodes.
  define(Recorder<MyCoordinate>::getCreationFunction());
}

}
}

MESH_MyMeshData.h

#ifndef MESHMYMESHDATA_H
#define MESHMYMESHDATA_H

#include <X3DTK/MESH/scenegraph.h>

namespace X3DTK {
namespace MESH {

// My vertex data structure containing the weight information.

class VertexWeightData
{
public:
  void setWeight(const SFFloat &weight) {_weight = weight;};
  inline const SFFloat &getWeight() const {return _weight;};
  
private:
  SFFloat _weight;  
};

// My Mesh data aggregates.
#ifdef TEMPLATE_SPECIALIZATION_SUPPORTED

typedef clist<tlist<VertexPointData, tlist<VertexNormalData, tlist<VertexWeightData> > > > MyVertexData;
typedef clist<tlist<FaceNormalData> > MyFaceData;
typedef clist<tlist<MeshNormalData> > MyMeshData;

#else

class MyVertexData : public VertexData, public VertexWeightData {};
class MyFaceData : public FaceData {};
class MyMeshData : public MeshData {};

#endif

}
}

#endif

X3D_MyMeshBuilderRenderingVisitor.h

#ifndef MYMESHBUILDERRENDERINGVISITOR_H
#define MYMESHBUILDERRENDERINGVISITOR_H

#include <X3DTK/X3D/meshbuilder.h>
#include "X3D_MyCoordinate.h"

namespace X3DTK {
namespace X3D {

// Visitor for the Rendering component of the MyMeshBuilder processor.

template<class MData, class VData, class EData, class FData, bool readOnly>
class MyMeshBuilderRenderingVisitor : public TemplateMeshBuilderRenderingVisitor<MData, VData, EData, FData, readOnly>
{
public:
  MyMeshBuilderRenderingVisitor();
  
  static void enterMyCoordinate(MyCoordinate *C);
};

}
}

#include "X3D_MyMeshBuilderRenderingVisitor.inl"

#endif

X3D_MyMeshBuilderRenderingVisitor.inl

namespace X3DTK {
namespace X3D {

template<class MData, class VData, class EData, class FData, bool RW>
MyMeshBuilderRenderingVisitor<MData, VData, EData, FData, RW>::MyMeshBuilderRenderingVisitor()
: TemplateMeshBuilderRenderingVisitor<MData, VData, EData, FData, RW>()
{
  define(Recorder<MyCoordinate>::getEnterFunction(&MyMeshBuilderRenderingVisitor::enterMyCoordinate));
}

template<class MData, class VData, class EData, class FData, bool RW>
void MyMeshBuilderRenderingVisitor<MData, VData, EData, FData, RW>::enterMyCoordinate(MyCoordinate *C)
{
  TemplateMeshBuilderStateVariables<MData, VData, EData, FData, RW> *stateVariables = Singleton<TemplateMeshBuilderStateVariables<MData, VData, EData, FData, RW> >::getInstance();
  
  MESH::TemplateVertex<MData, VData, EData, FData, RW> *MC = dynamic_cast<MESH::TemplateVertex<MData, VData, EData, FData, RW> *>(stateVariables->getNode(C));
  if (MC != 0)
  {
    // Filling the Vertices.
    const MFFloat &weight = C->getWeight();
    
    const typename MESH::TemplateVertex<MData, VData, EData, FData, RW>::MFVertex &vertices = MC->getVertices();
    
    // Test the optional presence of MESH::VertexPointData in VData.
    #ifdef TEMPLATE_SPECIALIZATION_SUPPORTED
    if (VData::template find<MESH::VertexWeightData>() && weight.size() >= vertices.size())
    #endif
    {
      MFFloat::const_iterator w = weight.begin();
      
      // Accessing the MESH::VertexWeightData of VData.
      for (typename MESH::TemplateVertex<MData, VData, EData, FData, RW>::MFVertex::const_iterator v = vertices.begin(); v != vertices.end(); ++v)
      {
        #ifdef TEMPLATE_SPECIALIZATION_SUPPORTED
        (*v)->template ogetData<MESH::VertexWeightData>().setWeight(*w);
        #else
        (*v)->data().setWeight(*w);
        #endif
        ++w;  
      }  
    }
    
    stateVariables->addCoupleNode(C, MC);  
  }
  stateVariables->pushNode(MC);
}

}
}

MESH_MyX3DBuilderCoreVisitor.h

#ifndef MYMESHX3DBUILDERVISITOR_H
#define MYMESHX3DBUILDERVISITOR_H

#include <X3DTK/MESH/x3dbuilder.h>
#include "X3D_MyCoordinate.h"

namespace X3DTK {
namespace MESH {

// Visitor for the Core component of the MyX3DBuilder processor.

template<class MData, class VData, class EData, class FData, bool RW>
class MyX3DBuilderCoreVisitor : public TemplateX3DBuilderCoreVisitor<MData, VData, EData, FData, RW>
{
public:
  MyX3DBuilderCoreVisitor();

  static void enterVertex(TemplateVertex<MData, VData, EData, FData, RW> *V);
};

}
}

#include "MESH_MyX3DBuilderCoreVisitor.inl"

#endif

MESH_MyX3DBuilderCoreVisitor.inl

namespace X3DTK {
namespace MESH {

template<class MData, class VData, class EData, class FData, bool RW>
MyX3DBuilderCoreVisitor<MData, VData, EData, FData, RW>::MyX3DBuilderCoreVisitor()
{
  define(Recorder<TemplateVertex<MData, VData, EData, FData, RW> >::getEnterFunction(&MyX3DBuilderCoreVisitor::enterVertex));
}

template<class MData, class VData, class EData, class FData, bool RW>
void MyX3DBuilderCoreVisitor<MData, VData, EData, FData, RW>::enterVertex(TemplateVertex<MData, VData, EData, FData, RW> *V)
{
  // StateVariables assignation.
  TemplateX3DBuilderStateVariables<MData, VData, EData, FData, RW> *stateVariables = Singleton<TemplateX3DBuilderStateVariables<MData, VData, EData, FData, RW> >::getInstance();

  // Test of the presence of MESH::VertexWeightData in VData.
  #ifdef TEMPLATE_SPECIALIZATION_SUPPORTED
  if (!VData::template find<VertexWeightData>())
  {
    // Call to super class function.
    TemplateX3DBuilderCoreVisitor<MData, VData, EData, FData, RW>::enterVertex(V);
  }
  else
  #endif
  {
    // Recoding the creation of the node.
    X3D::MyCoordinate *NC = dynamic_cast<X3D::MyCoordinate *>(stateVariables->getNode(V));
    if (NC == 0)
    {
      // Create a new MyCoordinate.
      NC = new X3D::MyCoordinate();
    
      const typename TemplateVertex<MData, VData, EData, FData, RW>::MFVertex &vertices = V->getVertices();
      
      // Test the optional presence of MESH::VertexPointData in VData.
      #ifdef TEMPLATE_SPECIALIZATION_SUPPORTED
      if (VData::template find<MESH::VertexPointData>())
      #endif
      {
        // Updating Coordinate.
        MFVec3f point;
        // Accessing the MESH::VertexPointData of VData.
        for (typename TemplateVertex<MData, VData, EData, FData, RW>::MFVertex::const_iterator v = vertices.begin(); v != vertices.end(); ++v)
          #ifdef TEMPLATE_SPECIALIZATION_SUPPORTED
          point.push_back(SFVec3f((*v)->template ogetData<MESH::VertexPointData>().getPoint()));
          #else
          point.push_back(SFVec3f((*v)->data().getPoint()));
          #endif
        NC->setPoint(point);
      }
      
      MFFloat weight;

      // Accessing the MESH::VertexWeightData of VData.
      #ifdef TEMPLATE_SPECIALIZATION_SUPPORTED
      if (VData::template find<MESH::VertexWeightData>())
      #endif
      {
        for (typename TemplateVertex<MData, VData, EData, FData, RW>::MFVertex::const_iterator v = vertices.begin(); v != vertices.end(); ++v)
        {
          #ifdef TEMPLATE_SPECIALIZATION_SUPPORTED
          weight.push_back((*v)->template ogetData<MESH::VertexWeightData>().getWeight());
          #else
          weight.push_back((*v)->data().getWeight());
          #endif
        }  
      }

      NC->setWeight(weight);

      // memorizing the couple (V, NC) to avoid to create a new Coordinate 
      // if V is visited a second time.
      stateVariables->addCoupleNode(V, NC);
    }
    stateVariables->pushNode(NC);
  }  
}

}
}

main.cpp

#include "MESH_MyMeshData.h"
#include "X3D_MyRenderingCreator.h"
#include "X3D_MyMeshBuilderRenderingVisitor.h"
#include "MESH_MyX3DBuilderCoreVisitor.h"

#include <X3DTK/X3D/scenegraph.h>
#include <X3DTK/X3D/meshbuilder.h>
#include <X3DTK/MESH/x3dbuilder.h>
#include <X3DTK/X3D/scenesaver.h>

#include <iostream>


#include <X3DTK/graphtester.h>

using namespace X3DTK;
using namespace std;

int main(int argc, char *argv[])
{
  if (argc <= 1)
  {
    cerr << "usage: extendedmeshsaver input" << endl;
    exit(0);
  }
  
  // DefaultLoader to load the default X3D Nodes.
  X3D::Loader *loader = Singleton<X3D::Loader>::getInstance();
  loader->setComponentCreator(new X3D::MyRenderingCreator());
  
  // Instanciation of the new MeshBuilder.
  X3D::TemplateMeshBuilder<MESH::MyMeshData, MESH::MyVertexData, MESH::EdgeData, MESH::MyFaceData, true> *meshbuilder = Singleton<X3D::TemplateMeshBuilder<MESH::MyMeshData, MESH::MyVertexData, MESH::EdgeData, MESH::MyFaceData, true> >::getInstance();
  meshbuilder->setComponentVisitor(new X3D::MyMeshBuilderRenderingVisitor<MESH::MyMeshData, MESH::MyVertexData, MESH::EdgeData, MESH::MyFaceData, true>());

  // Instanciation of the new MeshX3DBuilder.
  MESH::TemplateX3DBuilder<MESH::MyMeshData, MESH::MyVertexData, MESH::EdgeData, MESH::MyFaceData, true> *meshx3dbuilder = Singleton<MESH::TemplateX3DBuilder<MESH::MyMeshData, MESH::MyVertexData, MESH::EdgeData, MESH::MyFaceData, true> >::getInstance();
  meshx3dbuilder->setComponentVisitor(new MESH::MyX3DBuilderCoreVisitor<MESH::MyMeshData, MESH::MyVertexData, MESH::EdgeData, MESH::MyFaceData, true>());  
  
  // Instanciation of the SceneSaver.
  X3D::SceneSaver *saver = Singleton<X3D::SceneSaver>::getInstance();
  
  // Loads the scene.
  X3D::Scene *s = loader->load(argv[1], false);
  
  cout << "s = " << s << endl;
  GraphTester *gt = Singleton<GraphTester>::getInstance();
  gt->test(s);
  
  cout << "end test" << endl;
  
  MESH::Scene *ms = meshbuilder->build(s);
  X3D::Scene *ss = meshx3dbuilder->build(ms);
  saver->saveAs(ss, "myfile.x3d");
  
  // removes all instances.
  Singleton<X3D::TemplateMeshBuilder<MESH::MyMeshData, MESH::MyVertexData, MESH::EdgeData, MESH::MyFaceData, true> >::removeInstance();  
  Singleton<MESH::TemplateX3DBuilder<MESH::MyMeshData, MESH::MyVertexData, MESH::EdgeData, MESH::MyFaceData, true> >::removeInstance();  
  Singleton<X3D::Loader>::removeInstance();  
    
  return 1;
}

Generated on Fri Jul 30 12:02:32 2004 for X3DToolKit by doxygen 1.3.6