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.
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.
#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 SFNode 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 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(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. defineNode<Icosahedron>(); } } }
#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(); virtual void enterIcosahedron(Icosahedron *I) const; }; } } #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. defineEnterFunction(&MyBBoxUpdaterGeometry3DVisitor::enterIcosahedron); } void MyBBoxUpdaterGeometry3DVisitor::enterIcosahedron(Icosahedron *I) const { // 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 SFNode 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) { } 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(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 FCylinder; // My visitor for the Geometry3D component of the GLCreator module. class MyGLBuilderGeometry3DVisitor : public GLBuilderGeometry3DVisitor { public: // Constructor. MyGLBuilderGeometry3DVisitor(); // Enters an FCylinder. void enterFCylinder(FCylinder *C) const; }; } } #endif
#include "X3D_MyGLBuilderGeometry3DVisitor.h" #include "X3D_FCylinder.h" #include "GL_FCylinder.h" #include <iostream> using namespace std; namespace X3DTK { namespace X3D { MyGLBuilderGeometry3DVisitor::MyGLBuilderGeometry3DVisitor() : GLBuilderGeometry3DVisitor() { // Define new enter function for FCylinder. defineEnterFunction(&MyGLBuilderGeometry3DVisitor::enterFCylinder); } void MyGLBuilderGeometry3DVisitor::enterFCylinder(FCylinder *C) const { GL::SFNode GC = stateVariables->getNode(C); if (GC == 0) { GC = new GL::FCylinder(); GC->setX3DReference(C); stateVariables->addCoupleNode(C, GC); } stateVariables->pushNode(GC); } } }
#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_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()); #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); // Shows the derivation tree. SFType::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(); }