X3DTK::X3DProcessor
to it by deriving the existing ones.
Here we want to define an icosahedron node and render it by the X3DTK::GL::Renderer
processor. It implies to define an X3D::Icosahedron
node belonging to the X3D scene graph, to extend the X3DTK::X3D::Loader
to load it, to extend the X3DTK::X3D::BBoxUpdater
to compute its bounding box necessary for the viewer and to define a X3DTK::GL::Icosahedron
inheriting a X3DTK::GL::X3DNode
belonging to the GL scene graph to draw it.
Some important functions and classes:
X3DTK::X3D::Icosahedron
belongs to it.X3DTK::X3D::BBoxUpdater
processor. We derive X3DTK::X3D::BBoxUpdaterGeometry3DVisitor
to add the enterIcosahedron
function.X3DTK::X3D::Icosahedron
, we first have to define its GL equivalent node, X3DTK::GL::Icosahedron
. Notice that there are different namespaces for the X3D and GL scene graphs. The special methods update and draw have to be redefined.X3DTK::X3D::GLBuilderGeometry3DVisitor
, which will create the X3DTK::GL::Icosahedron
from an X3DTK::X3D::Icosahedron
.#ifndef ICOSAHEDRON_H #define ICOSAHEDRON_H #include <X3DTK/X3D/scenegraph.h> namespace X3DTK { namespace X3D { // New X3D node. class Icosahedron : public X3DGeometryNode { public: Icosahedron(); virtual ~Icosahedron(); void setRadius(const SFFloat &radius); inline const SFFloat &getRadius() const {return _radius;}; private: SFFloat _radius; }; } } #endif
#include "X3D_Icosahedron.h" #include <iostream> using namespace std; namespace X3DTK { namespace X3D { Icosahedron::Icosahedron() : X3DGeometryNode() { // Defines the tag of the node. This string is the one read in the X3D file. define(Recorder<Icosahedron>::getTypeName("Icosahedron", "Geometry3D")); // Defines an attribute of the node. define(Recorder<Icosahedron, SFFloat>::getAttribute("radius", &Icosahedron::_radius, 1.0f)); } Icosahedron::~Icosahedron() { } void Icosahedron::setRadius(const SFFloat &radius) { _radius = radius; } } }
#ifndef MYGEOMETRY3DCREATOR_H #define MYGEOMETRY3DCREATOR_H #include <X3DTK/X3D/scenegraph.h> namespace X3DTK { namespace X3D { // Deriving Geometry3DCreator to define the new node X3D::Icosahedron. class MyGeometry3DCreator : public Geometry3DCreator { public: MyGeometry3DCreator(); }; } } #endif
#include "X3D_MyGeometry3DCreator.h" #include "X3D_Icosahedron.h" namespace X3DTK { namespace X3D { MyGeometry3DCreator::MyGeometry3DCreator() : Geometry3DCreator() { // Defines a new creation function for the Icosahedron node. define(Recorder<Icosahedron>::getCreationFunction()); } } }
#ifndef MYBBOXUPDATERGEOMETRY3DVISITOR_H #define MYBBOXUPDATERGEOMETRY3DVISITOR_H #include <X3DTK/X3D/bboxupdater.h> namespace X3DTK { namespace X3D { class Icosahedron; // Visitor for the Geometry3D component of the MyBBoxUpdater processor. class MyBBoxUpdaterGeometry3DVisitor : public BBoxUpdaterGeometry3DVisitor { public: MyBBoxUpdaterGeometry3DVisitor(); static void enterIcosahedron(Icosahedron *I); }; } } #endif
#include "X3D_MyBBoxUpdaterGeometry3DVisitor.h" #include "X3D_Icosahedron.h" #include <iostream> using namespace std; namespace X3DTK { namespace X3D { MyBBoxUpdaterGeometry3DVisitor::MyBBoxUpdaterGeometry3DVisitor() : BBoxUpdaterGeometry3DVisitor() { // Defines the new enter function for the X3DAbstractNode. define(Recorder<Icosahedron>::getEnterFunction(&MyBBoxUpdaterGeometry3DVisitor::enterIcosahedron)); } void MyBBoxUpdaterGeometry3DVisitor::enterIcosahedron(Icosahedron *I) { // StateVariables assignation BBoxUpdaterStateVariables *stateVariables = Singleton<BBoxUpdaterStateVariables>::getInstance(); // Checking whether the BBox of the node has already been computed or not. BBox *BB = stateVariables->getBBox(I); if (BB == 0) { // Creating a new BBox. BB = new BBox(SFVec3f(0.0f, 0.0f, 0.0f), SFVec3f(I->getRadius(), I->getRadius(), I->getRadius())); // Recording the couple (I, BB) to avoid to create a new BBox // if I is visited a second time. stateVariables->addBBox(I, BB); // Setting the current BBox. stateVariables->setShapeBBox(*BB); } } } }
#ifndef GL_ICOSAHEDRON_H #define GL_ICOSAHEDRON_H #include <X3DTK/GL/scenegraph.h> namespace X3DTK { namespace GL { // Class providing an implementation of the GL node corresponding to // X3D::Icosahedron. class Icosahedron : public X3DGeometryNode { public: Icosahedron(); virtual ~Icosahedron(); void setRadius(const SFFloat &radius); inline const SFFloat &getRadius() const {return _radius;}; virtual void update(); virtual void draw() const; private: MFVec3f _vertices; short _indexes[12][5]; MFVec3f _normal; SFFloat _radius; }; } } #endif
#include "GL_Icosahedron.h" #include "X3D_Icosahedron.h" #include <cmath> #include <iostream> namespace X3DTK { namespace GL { Icosahedron::Icosahedron() : X3DGeometryNode() { // Defines the tag of the node. define(Recorder<Icosahedron>::getTypeName("Icosahedron", "Geometry3D")); // Defines an attribute of the node. define(Recorder<Icosahedron, SFFloat>::getAttribute("radius", &Icosahedron::_radius, 1.0f)); } Icosahedron::~Icosahedron() { } void Icosahedron::update() { X3D::Icosahedron *I = static_cast<X3D::Icosahedron *>(x3dReference); // updating the attributes. _radius = I->getRadius(); // building the vertex array. const float c = cos(PI/3.0); const float s = sin(PI/3.0); _vertices = MFVec3f(20); _vertices[0] = SFVec3f(c+2.0*s, s, 0.0); _vertices[1] = SFVec3f(-c-2.0*s, s, 0.0); _vertices[2] = SFVec3f(c+2.0*s, -s, 0.0); _vertices[3] = SFVec3f(-c-2.0*s, -s, 0.0); _vertices[4] = SFVec3f(0.0, 2.0*s+c, s); _vertices[5] = SFVec3f(0.0, -2.0*s-c, s); _vertices[6] = SFVec3f(0.0, 2.0*s+c, -s); _vertices[7] = SFVec3f(0.0, -2.0*s-c, -s); _vertices[8] = SFVec3f(-c-s, -c-s, c+s); _vertices[9] = SFVec3f(-c-s, c+s, c+s); _vertices[10] = SFVec3f(-c-s, -c-s, -c-s); _vertices[11] = SFVec3f(-c-s, c+s, -c-s); _vertices[12] = SFVec3f(c+s, -c-s, c+s); _vertices[13] = SFVec3f(c+s, c+s, c+s); _vertices[14] = SFVec3f(c+s, -c-s, -c-s); _vertices[15] = SFVec3f(c+s, c+s, -c-s); _vertices[16] = SFVec3f(-s, 0.0, -2.0*s-c); _vertices[17] = SFVec3f(s, 0.0, -2.0*s-c); _vertices[18] = SFVec3f(-s, 0.0, 2.0*s+c); _vertices[19] = SFVec3f(s, 0.0, 2.0*s+c); static short array[12][5] = { { 0, 13, 19, 12, 2 }, { 0, 2, 14, 17, 15 } , { 0, 15, 6, 4, 13 } , { 6, 15, 17, 16, 11 } , { 4, 6, 11, 1, 9 } , { 11, 16, 10, 3, 1 } , { 16, 17, 14, 7, 10 } , { 10, 7, 5, 8, 3 } , { 5, 12, 19, 18, 8 } , { 12, 5, 7, 14, 2 } , { 18, 19, 13, 4, 9 } , { 1, 3, 8, 18, 9 } }; _normal = MFVec3f(12); for (int i = 0; i < 12; ++i) { _normal[i] = SFVec3f(0.0, 0.0, 0.0); for (int j = 0; j < 5; ++j) { _indexes[i][j] = array[i][j]; _normal[i] += _vertices[_indexes[i][j]]; } _normal[i].normalize(); } } void Icosahedron::setRadius(const SFFloat &radius) { _radius = radius; } void Icosahedron::draw() const { // drawing the polygon. // Changing the scale for the radius of the object. float s = _radius/4.47f; glMatrixMode(GL_MODELVIEW); glPushMatrix(); glScalef(s, s, s); for (int i = 0; i < 12; ++i) { // drawing the normals and the faces. glNormal3f(_normal[i].x, _normal[i].y, _normal[i].z); glBegin(GL_POLYGON); for (int j = 0; j < 5; ++j) glVertex3f(_vertices[_indexes[i][j]].x, _vertices[_indexes[i][j]].y, _vertices[_indexes[i][j]].z); glEnd(); } glPopMatrix(); } } }
#ifndef MYGLBUILDERGEOMETRY3DVISITOR_H #define MYGLBUILDERGEOMETRY3DVISITOR_H #include <X3DTK/X3D/glbuilder.h> namespace X3DTK { namespace X3D { class Icosahedron; // Visitor for the Geometry3D component of the GLBuilder processor. class MyGLBuilderGeometry3DVisitor : public GLBuilderGeometry3DVisitor { public: MyGLBuilderGeometry3DVisitor(); static void enterIcosahedron(Icosahedron *C); }; } } #endif
#include "X3D_MyGLBuilderGeometry3DVisitor.h" #include "X3D_Icosahedron.h" #include "GL_Icosahedron.h" #include <iostream> using namespace std; namespace X3DTK { namespace X3D { MyGLBuilderGeometry3DVisitor::MyGLBuilderGeometry3DVisitor() : GLBuilderGeometry3DVisitor() { // Define new enter function for Icosahedron. Note that it is the instanciation of a template method // with implicit parameters. define(Recorder<Icosahedron>::getEnterFunction(&MyGLBuilderGeometry3DVisitor::enterIcosahedron)); } void MyGLBuilderGeometry3DVisitor::enterIcosahedron(Icosahedron *I) { // StateVariables assignation GLBuilderStateVariables *stateVariables = Singleton<GLBuilderStateVariables>::getInstance(); // Checking whether I has been visited or not. GL::X3DNode *GI = stateVariables->getNode(I); if (GI == 0) { // Creating a new GL::Icosahedron. GI = new GL::Icosahedron(); GI->setX3DReference(I); // Recording the couple (I, GI) to avoid to create a new GL::Icosahedron // if I is visited a second time. stateVariables->addCoupleNode(I, GI); } // Pushing GI in the GL nodes stack. stateVariables->pushNode(GI); } } }
#ifndef VIEWER_H #define VIEWER_H #include <QGLViewer/qglviewer.h> #include <X3DTK/simplex3dglscene.h> // Class providing an X3D Viewer by implementing QGLViewer. class Viewer : public QGLViewer { protected : void init(); void draw(); void keyPressEvent(QKeyEvent *e); void loadFile(); void about(); QString helpString() const; void help() const; private: X3DTK::SimpleX3DGLScene scene; }; #endif
#include "Viewer.h" #include "X3D_MyGeometry3DCreator.h" #include "X3D_MyBBoxUpdaterGeometry3DVisitor.h" #include "X3D_MyGLBuilderGeometry3DVisitor.h" #include <qfiledialog.h> #include <qmessagebox.h> #include <X3DTK/kernel.h> using namespace X3DTK; using namespace std; void Viewer::init() { // We customize the SimpleX3DGLScene, by modifying its Loader, BBoxUpdater and GLBuilder. scene.getLoader()->setComponentCreator(new X3D::MyGeometry3DCreator()); scene.getBBoxUpdater()->setComponentVisitor(new X3D::MyBBoxUpdaterGeometry3DVisitor()); scene.getGLBuilder()->setComponentVisitor(new X3D::MyGLBuilderGeometry3DVisitor()); #ifdef GL_RESCALE_NORMAL glEnable(GL_RESCALE_NORMAL); #endif about(); loadFile(); } void Viewer::keyPressEvent(QKeyEvent *e) { switch (e->key()) { case Qt::Key_L : loadFile(); break; default: QGLViewer::keyPressEvent(e); } } void Viewer::loadFile() { QString name = QFileDialog::getOpenFileName("", "X3D files (*.x3d *.X3D);;All files (*)", this); // In case of Cancel if (name.isEmpty()) return; scene.release(); // Loads the scene. scene.load(name); // QGLViewer settings. setSceneBoundingBox(scene.getBBoxMin().f_data(), scene.getBBoxMax().f_data()); showEntireScene(); } void Viewer::draw() { // Draws the scene. scene.draw(); } void Viewer::about() { QMessageBox::about(this, "about the newNodeViewer", "this is an example showing how to create a new node.Type 'h' to display help"); } QString Viewer::helpString() const { QString message(""); 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(); }