X3DTK::X3D::X3DNode
(inherits X3DTK::X3DAbstractNode
the derivation parent of all nodes) node and apply common 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.
clone
, load
and write
. For the attributes of the node be loaded, the load
method has to be redefined, as well as the write
method, to enable the writing of the X3DTK::X3D::Icosahedron
node in an X3D file.Note that the copy constructor is protected, because the nodes must be passed by pointers, and not by value. Nevertheless we define a clone method to enable the cloning of the scene graph. The other methods are relative to the access and the setting of the attributes of the node.
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
. Note that there are different namespaces for the X3D and GL scene graphs. The special methods update and draw have to be redefined. Note that the clone method is also present.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 X3DGeometry3DNode { public: Icosahedron(); Icosahedron(SFFloat radius); virtual SFAbstractNode clone() const; void setRadius(const SFFloat &radius); inline const SFFloat &getRadius() const {return _radius;}; virtual void load(const X3DFileElement *element); virtual SFString write() const; protected: Icosahedron(const Icosahedron &I); private: SFFloat _radius; }; } } #endif
#include "X3D_Icosahedron.h" #include <iostream> using namespace std; namespace X3DTK { namespace X3D { Icosahedron::Icosahedron() : X3DGeometry3DNode(), _radius(1.0f) { // Defines the tag of the node. This string is the one read in the X3D file. defineTypeName("Icosahedron", "Geometry3D"); } Icosahedron::Icosahedron(SFFloat radius) : X3DGeometry3DNode(), _radius(radius) { // Defines the tag of the node. defineTypeName("Icosahedron", "Geometry3D"); } Icosahedron::Icosahedron(const Icosahedron &I) : X3DGeometry3DNode(I), _radius(I._radius) { } SFAbstractNode Icosahedron::clone() const { // Returns the copy constructor. return new Icosahedron(*this); } void Icosahedron::setRadius(const SFFloat &radius) { _radius = radius; } void Icosahedron::load(const X3DFileElement *element) { // Converting the text attributes to the memory attributes. int index; index = element->getIndexAttribute("radius"); if (index != -1) _radius = element->getAttribute(index).toFloat(); } SFString Icosahedron::write() const { // Converting the memory attributes to the text attributes. SFString attr; if (_radius != 1.0f) attr += " radius=\"" + toSFString(_radius) + "\""; return attr; } } }
#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(2.0f*I->getRadius(), 2.0f*I->getRadius(), 2.0f*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 X3DGeometry3DNode { public: Icosahedron(); virtual SFAbstractNode clone() const; void setRadius(const SFFloat &radius); inline const SFFloat &getRadius() const {return _radius;}; virtual void update(); virtual void draw() const; protected: Icosahedron(const Icosahedron &I); 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() : X3DGeometry3DNode() { // Defines the tag of the node. defineTypeName("Icosahedron", "Geometry3D"); } Icosahedron::Icosahedron(const Icosahedron &I) : X3DGeometry3DNode(I) { } SFAbstractNode Icosahedron::clone() const { // returns the copy constructor. return new Icosahedron(*this); } 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. glMatrixMode(GL_MODELVIEW); glPushMatrix(); glScalef(_radius, _radius, _radius); 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::SFNode 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(); }