This is an example on how to create a new X3D node that we want to render. Here we define an X3D::Icosahedron
node.
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 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.
X3D::Icosahedron
belongs to it.
BboxUpdater
processor. We derive BboxUpdaterGeometry3DVisitor to add the enterIcosahedron
function.
X3D::Icosahedron
, we first have to define its openGL equivalent node, GL::Icosahedron
. Note that there are different namespaces for the scene graphs X3D and GL. The special methods update
and render
have to be redefined. Note that the clone
method is also present.
GLBuilderGeometry3DVisitor
, which will create the GL::Icosahedron
from an X3D::Icosahedron
.
#ifndef ICOSAHEDRON_H #define ICOSAHEDRON_H #include <X3DTK/x3dscenegraph.h> namespace X3DTK { namespace X3D { class Icosahedron : public X3DGeometry3DNode { public: // Constructor. Icosahedron(); // Constructs a Cylinder from its attributes. Icosahedron(SFFloat radius); // Clones the node. virtual SFNode clone() const; // sets the number of sections. void setRadius(SFFloat radius); // gets the number of sections. inline SFFloat getRadius() const {return _radius;}; // Loads the attributes from a X3DFileElement e. virtual void load(const X3DFileElement *element); // Writes the attributes of the node. virtual SFString write() const; protected: // Copy constructor. Icosahedron(const Icosahedron &I); private: SFFloat _radius; }; } } #endif
#include "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 must be the same than the one // entered for the creation function, otherwise the node won't be loaded. 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) { } SFNode Icosahedron::clone() const { // Returns the copy constructor. return new Icosahedron(*this); } void Icosahedron::setRadius(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/x3dscenegraph.h> namespace X3DTK { namespace X3D { // Concrete component Creator for the geometry3D component defining the default // X3D nodes. class MyGeometry3DCreator : public Geometry3DCreator { public: // Constructor. MyGeometry3DCreator(); }; } } #endif
#include "MyGeometry3DCreator.h" #include "Icosahedron.h" namespace X3DTK { namespace X3D { MyGeometry3DCreator::MyGeometry3DCreator() : Geometry3DCreator() { // Defines a new creation function for the Icosahedron node. defineNewNode<Icosahedron>(); } } }
#ifndef MYBBOXUPDATERGEOMETRY3DVISITOR_H #define MYBBOXUPDATERGEOMETRY3DVISITOR_H #include <X3DTK/bboxupdater.h> namespace X3DTK { namespace X3D { class Icosahedron; // Visitor for the Geometry3D component of the MyBBoxUpdater processor. class MyBBoxUpdaterGeometry3DVisitor : public BBoxUpdaterGeometry3DVisitor { public: // Constructor. MyBBoxUpdaterGeometry3DVisitor(); // Enters an X3DAbstractNode. virtual void enterIcosahedron(Icosahedron *I) const; }; } } #endif
#include "MyBBoxUpdaterGeometry3DVisitor.h" #include "Icosahedron.h" #include <iostream> using namespace std; namespace X3DTK { namespace X3D { MyBBoxUpdaterGeometry3DVisitor::MyBBoxUpdaterGeometry3DVisitor() : BBoxUpdaterGeometry3DVisitor() { // Defines the new enter function for the X3DAbstractNode. defineNewEnterFunction(&MyBBoxUpdaterGeometry3DVisitor::enterIcosahedron); // GlobalVariables assignation. globalVariables = GVManager::getInstanceOf<BBoxUpdaterGlobalVariables>(); } void MyBBoxUpdaterGeometry3DVisitor::enterIcosahedron(Icosahedron *I) const { // Checking whether the BBox of the node has already been computed. BBox *BB = globalVariables->getBBox(I); if (BB == 0) { BB = new BBox(SFVec3f(0.0f, 0.0f, 0.0f), SFVec3f(2.0f*I->getRadius(), 2.0f*I->getRadius(), 2.0f*I->getRadius())); globalVariables->addBBox(I, BB); globalVariables->setShapeBBox(*BB); } } } }
#ifndef GL_ICOSAHEDRON_H #define GL_ICOSAHEDRON_H #include <X3DTK/glscenegraph.h> namespace X3DTK { namespace GL { // Class providing a implementation of the X3DGLNode corresponding to the X3DNode // Icosahedron. class Icosahedron : public X3DGeometry3DNode { public: // Constructor. Icosahedron(); // Clones the node. virtual SFNode clone() const; void setRadius(SFFloat radius); inline SFFloat getRadius() const {return _radius;}; virtual void update(); virtual void render() const; protected: // Copy constructor. Icosahedron(const Icosahedron &I); private: MFVec3f _vertices; short _indexes[12][5]; MFVec3f _normal; SFFloat _radius; }; } } #endif
#include "GL_Icosahedron.h" #include "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) { } SFNode 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(M_PI/3.0); const float s = sin(M_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(SFFloat radius) { _radius = radius; } void Icosahedron::render() 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/glbuilder.h> namespace X3DTK { namespace X3D { // My visitor for the Geometry3D component of the GLCreator module. class MyGLBuilderGeometry3DVisitor : public GLBuilderGeometry3DVisitor { public: // Constructor. MyGLBuilderGeometry3DVisitor(); }; } } #endif
#include "MyGLBuilderGeometry3DVisitor.h" #include "FCylinder.h" #include "GL_FCylinder.h" #include <iostream> using namespace std; namespace X3DTK { namespace X3D { MyGLBuilderGeometry3DVisitor::MyGLBuilderGeometry3DVisitor() : GLBuilderGeometry3DVisitor() { // Define new enter function for FCylinder. defineNewEnterFunction(&MyGLBuilderGeometry3DVisitor::enterNode<FCylinder, GL::FCylinder>); } } }
#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 "MyGeometry3DCreator.h" #include "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 changing its X3DLoader, GLCreator scene.getLoader()->setComponentCreator(new X3D::MyGeometry3DCreator()); scene.getGLBuilder()->setComponentVisitor(new X3D::MyGLBuilderGeometry3DVisitor()); glEnable(GL_RESCALE_NORMAL); 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); // Shows the derivation tree. Type::printDerivationTree(); cout << endl; // 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(); }