Main Page   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

glNormalViewer

Introduction

This an example of how to write a new processor. Here we want to define a processor displaying in a GL context the normals of the model and controlling the length of the normals.

GL::NormalRendererStateVariables

To control the length of the normals displayed to screen, we have to memorize a variable global to the traverse of the scene graph. That's why we derive StateVariables and add methods to set and get the length.

GL::NormalRendererGroupingVisitor

To draw the normals in the correct coordinates, we have to push the Transform matrices. Thus we define the methods enterTransform and leaveTransform operating on the GL::Transform node that belongs to the Grouping component.

GL::NormalRendererGeometry3DVisitor

To draw the normals we have to visit the GL::IndexedFaceSet node which already has the vertexArrays updated to be rendered by OpenGL. We just have to get the normals from the arrays. That is here that we get the length of the normals. The instance of the GL::NormalRendererStateVariables is given by GVManager which controls the number of instances.

GL::NormalRenderer

This is the facade of the processor which aggregates the visitors of the different components.

NormalX3DGLScene

We customize SimpleX3DGLScene by adding methods relative to the display of the normals.

code

GL_NormalRendererStateVariables.h




#ifndef GLNORMALRENDERERGLOBALVARIABLES_H
#define GLNORMALRENDERERGLOBALVARIABLES_H

#include <X3DTK/kernel.h>

namespace X3DTK {
namespace GL {


class NormalRendererStateVariables : public StateVariables
{
public:
  NormalRendererStateVariables();
  virtual ~NormalRendererStateVariables();
  
  void setNormalLength(float value);
  float getNormalLength() const {return _normalLength;};
  
private:
  float _normalLength;
};

}
}

#endif

GL_NormalRendererStateVariables.cpp

#include "GL_NormalRendererStateVariables.h"

namespace X3DTK {
namespace GL {

NormalRendererStateVariables::NormalRendererStateVariables()
: StateVariables(), _normalLength(1.0f)
{
}

NormalRendererStateVariables::~NormalRendererStateVariables()
{
}

void NormalRendererStateVariables::setNormalLength(float value)
{
  _normalLength = value;
}

}
}

GL_NormalRendererGroupingVisitor.h




#ifndef GLNORMALRENDERERGROUPINGVISITOR_H
#define GLNORMALRENDERERGROUPINGVISITOR_H

#include <X3DTK/gl_scenegraph.h>

namespace X3DTK {
namespace GL {


class NormalRendererGroupingVisitor : public GroupingVisitor
{
public:
  NormalRendererGroupingVisitor();
  virtual ~NormalRendererGroupingVisitor();

  virtual void enterTransform(Transform *T) const;

  virtual void leaveTransform(Transform *T) const;
};

}
}

#endif

GL_NormalRendererGroupingVisitor.cpp

#include "GL_NormalRendererGroupingVisitor.h"

namespace X3DTK {
namespace GL {

NormalRendererGroupingVisitor::NormalRendererGroupingVisitor()
: GroupingVisitor()
{
  // Enter functions.
  defineEnterFunction(&NormalRendererGroupingVisitor::enterTransform);

  // Leave functions
  defineLeaveFunction(&NormalRendererGroupingVisitor::leaveTransform);
}

NormalRendererGroupingVisitor::~NormalRendererGroupingVisitor()
{
}

void NormalRendererGroupingVisitor::enterTransform(Transform *T) const
{
  // Changing the coordinates system.
  glMatrixMode(GL_MODELVIEW);
  glPushMatrix();
  glMultMatrixf(&T->getTransformMatrix().front());
}

void NormalRendererGroupingVisitor::leaveTransform(Transform *T) const
{
  // Returning to the old coordinates system.
  glMatrixMode(GL_MODELVIEW);
  glPopMatrix();  
}

}
}

GL_NormalRendererGeometry3DVisitor.h




#ifndef GLNORMALRENDERERGEOMETRY3DVISITOR_H
#define GLNORMALRENDERERGEOMETRY3DVISITOR_H

#include "GL_NormalRendererStateVariables.h"

#include <X3DTK/gl_scenegraph.h>

namespace X3DTK {
namespace GL {


class NormalRendererGeometry3DVisitor : public Geometry3DVisitor
{
public:
  NormalRendererGeometry3DVisitor();
  virtual ~NormalRendererGeometry3DVisitor();

  virtual void enterIndexedFaceSet(IndexedFaceSet *I) const;

protected:
  NormalRendererStateVariables *stateVariables;
};

}
}

#endif

GL_NormalRendererGeometry3DVisitor.cpp

#include "GL_NormalRendererGeometry3DVisitor.h"

#include <vector>

using namespace std;

namespace X3DTK {
namespace GL {

NormalRendererGeometry3DVisitor::NormalRendererGeometry3DVisitor()
: Geometry3DVisitor()
{
  // Enter functions.
  defineEnterFunction(&NormalRendererGeometry3DVisitor::enterIndexedFaceSet);

  // StateVariables assignation.
  stateVariables = GraphTraversal::getInstanceOf<NormalRendererStateVariables>();
}

NormalRendererGeometry3DVisitor::~NormalRendererGeometry3DVisitor()
{
}

void NormalRendererGeometry3DVisitor::enterIndexedFaceSet(IndexedFaceSet *G) const
{
  float coef = stateVariables->getNormalLength();

  glColor3f(1.0f, 0.0f, 0.0f);
  glDisable(GL_LIGHTING);
  
  // enumerating all the vertex formats. The method is simple: Get the normal vector of
  // vertex and drawing the line.
  // It is important to get a reference to the vertex array, to avoid a copy of the datas.
  
  if ((G->getColor()) && (G->getTexCoord()))
  {
    const vector<T2F_C4F_N3F_V3F> &vertexArray = G->T2F_C4F_N3F_V3F_vertexArray();
    
    glBegin(GL_LINES);
    for (vector<T2F_C4F_N3F_V3F>::const_iterator it = vertexArray.begin(); it != vertexArray.end(); ++it)
    {
      SFVec3f vertex = (*it).vertex;
      SFVec3f vnormal = vertex + coef*(*it).normal;
      glVertex3fv(vertex.f_data());
      glVertex3fv(vnormal.f_data());
    }
    glEnd();    
  }  
    
  if ((G->getColor()) && (!G->getTexCoord()))
  {
    const vector<C4F_N3F_V3F> &vertexArray = G->C4F_N3F_V3F_vertexArray();
    
    glBegin(GL_LINES);
    for (vector<C4F_N3F_V3F>::const_iterator it = vertexArray.begin(); it != vertexArray.end(); ++it)
    {
      SFVec3f vertex = (*it).vertex;
      SFVec3f vnormal = vertex + coef*(*it).normal;
      glVertex3fv(vertex.f_data());
      glVertex3fv(vnormal.f_data());
    }
    glEnd();    
  }  
    
  if ((!G->getColor()) && (G->getTexCoord()))
  {
    const vector<T2F_N3F_V3F> &vertexArray = G->T2F_N3F_V3F_vertexArray();
    
    glBegin(GL_LINES);
    for (vector<T2F_N3F_V3F>::const_iterator it = vertexArray.begin(); it != vertexArray.end(); ++it)
    {
      SFVec3f vertex = (*it).vertex;
      SFVec3f vnormal = vertex + coef*(*it).normal;
      glVertex3fv(vertex.f_data());
      glVertex3fv(vnormal.f_data());
    }
    glEnd();    
  }  
  
  if ((!G->getColor()) && (!G->getTexCoord()))
  {
    const vector<N3F_V3F> &vertexArray = G->N3F_V3F_vertexArray();
    
    glBegin(GL_LINES);
    for (vector<N3F_V3F>::const_iterator it = vertexArray.begin(); it != vertexArray.end(); ++it)
    {
      SFVec3f vertex = (*it).vertex;
      SFVec3f vnormal = vertex + coef*(*it).normal;
      glVertex3fv(vertex.f_data());
      glVertex3fv(vnormal.f_data());
    }
    glEnd();    
  }
  
  glEnable(GL_LIGHTING);
}

}
}

GL_NormalRenderer.h




#ifndef GLNORMALRENDERER_H
#define GLNORMALRENDERER_H

#include "GL_NormalRendererStateVariables.h"

#include <X3DTK/gl_scenegraph.h>

namespace X3DTK {
namespace GL {


class NormalRenderer : public X3DOnePassProcessor
{
public:
  NormalRenderer();
  virtual ~NormalRenderer();
  
  void setNormalLength(float value);
    
  virtual void render(SFNode N) const;

protected:
  NormalRendererStateVariables *stateVariables;
};

}
}

#endif

GL_NormalRenderer.cpp

#include "GL_NormalRenderer.h"
#include "GL_NormalRendererGeometry3DVisitor.h"
#include "GL_NormalRendererGroupingVisitor.h"

#include <iostream>

using namespace std;

namespace X3DTK {
namespace GL {

NormalRenderer::NormalRenderer()
{
  // Getting the StateVariables to initialize its values.
  stateVariables = GraphTraversal::getInstanceOf<NormalRendererStateVariables>();

  // The algorithm for drawing the normals is based upon a graphTraversal traversal of the 
  // GL scene graph.
  graphTraversal = new DFSGraphTraversal();
  
  // Setting the component visitor to the tree traversal algorithm.
  graphTraversal->setComponentVisitor(new NormalRendererGeometry3DVisitor());
  graphTraversal->setComponentVisitor(new NormalRendererGroupingVisitor());
}

NormalRenderer::~NormalRenderer()
{
  // Removing the StateVariables.
  GraphTraversal::removeInstanceOf<NormalRendererStateVariables>();

  delete graphTraversal;
}

void NormalRenderer::setNormalLength(float value)
{
  stateVariables->setNormalLength(value);
}

void NormalRenderer::render(SFNode N) const
{
  glDisable(GL_COLOR_MATERIAL);
  graphTraversal->traverse(N);
}

}
}

NormalX3DGLScene.h




#ifndef NORMALX3DGLSCENE_H
#define NORMALX3DGLSCENE_H

#include "GL_NormalRenderer.h"

#include <X3DTK/simplex3dglscene.h>

namespace X3DTK {

class NormalX3DGLScene : public SimpleX3DGLScene
{
public:
  NormalX3DGLScene();
  virtual ~NormalX3DGLScene();
  
  void setNormal(bool value);
  void setNormalLength(float value);
  
  virtual void draw();

private:
  GL::NormalRenderer *_normalRenderer;
  bool _normal;
};

}

#endif

NormalX3DGLScene.cpp

#include "NormalX3DGLScene.h"

namespace X3DTK {

NormalX3DGLScene::NormalX3DGLScene()
: SimpleX3DGLScene(), _normalRenderer(X3DProcessor::getInstanceOf<GL::NormalRenderer>()), _normal(false)
{
}

NormalX3DGLScene::~NormalX3DGLScene()
{
}

void NormalX3DGLScene::setNormal(bool value)
{
  _normal = value;
}

void NormalX3DGLScene::setNormalLength(float value)
{
  _normalRenderer->setNormalLength(value);
}

void NormalX3DGLScene::draw()
{
  // call to the super class draw method.
  SimpleX3DGLScene::draw();
  // Second pass rendering for the normals.
  if (_normal)
    _normalRenderer->render(glscene);
}

}

Viewer.h




#ifndef VIEWER_H
#define VIEWER_H

#include "NormalX3DGLScene.h"

#include <QGLViewer/qglviewer.h>


class Viewer : public QGLViewer
{
public:
  Viewer(const char *file);
  ~Viewer();
  
protected :
  void loadFile();
  void keyPressEvent(QKeyEvent *e);
  void init();
  void draw();
  void about();
  QString helpString() const;
  void help() const;
  
private:
  float normLength;
  X3DTK::NormalX3DGLScene scene;
  X3DTK::BBox BB;
  char *x3dfile;
  bool normal;
};

#endif

Viewer.cpp

#include "Viewer.h"
#include <X3DTK/gl_renderer.h>

#include <math.h>
#include <iostream>
#include <qfiledialog.h>
#include <qmessagebox.h> 

using namespace X3DTK;
using namespace std;

Viewer::Viewer(const char *file)
: normLength(1.0f), normal(false)
{
  x3dfile = (char *)file;
}

Viewer::~Viewer()
{
  scene.release();
}

void Viewer::keyPressEvent(QKeyEvent *e)
{
  switch (e->key())
  {
    case Qt::Key_L : 
      loadFile(); break;
    case Qt::Key_N : 
      normal = !normal;
      scene.setNormal(normal);
      break;
    case Qt::Key_Minus :
      normLength /= 2.0f;
      scene.setNormalLength(normLength);
      break;
    case Qt::Key_Plus :
      normLength *= 2.0f;
      scene.setNormalLength(normLength);
      break;
    default: 
      QGLViewer::keyPressEvent(e);
  }
  updateGL();
}

void Viewer::loadFile()
{
  QString name = QFileDialog::getOpenFileName("", "X3D files (*.x3d *.X3D);;All files (*)", this);
  
  // In case of Cancel
  if (name.isEmpty())
    return;

  // Loads the file name.
  scene.load(name, false);

  setSceneBoundingBox(scene.getBBoxMin().f_data(), scene.getBBoxMax().f_data());
  showEntireScene();
}

void Viewer::init()
{
#ifdef GL_RESCALE_NORMAL
  glEnable(GL_RESCALE_NORMAL);
#endif
  about();
  loadFile();
}

void Viewer::draw()
{
  //traverse the scene graph
  scene.draw();
}

void Viewer::about()
{
  QMessageBox::about(this, "about the glNormalViewer", "this is an example showing how to create a new processor that displays the normals of a model.Type 'h' to display help");
}

QString Viewer::helpString() const
{
  QString message("");
  
  message += "<b>N</b>" + QString(" enables or disables the display of normals<br>");
  message += "<b>+</b>" + QString(" increases the length of normals<br>");
  message += "<b>-</b>" + QString(" decreases the length of normals<br>");
  message += "<b>L</b>" + QString(" loads a new file<br>");
  
  message += QGLViewer::helpString();
  
  return message;
}

void Viewer::help() const
{
  QMessageBox *mb = new QMessageBox("help", helpString(), QMessageBox::NoIcon,QMessageBox::Ok | QMessageBox::Default, QMessageBox::NoButton,QMessageBox::NoButton, NULL, "Help", false,Qt::WStyle_DialogBorder | Qt::WType_Dialog | Qt::WDestructiveClose);
  mb->show();
}


Generated on Thu Dec 4 13:25:52 2003 for X3DToolKit by doxygen1.2.18