/*! \internal Output a string representation of \a section to a debug stream \a dbg. \relates QGLSection */ QDebug operator<<(QDebug dbg, const QGLSection §ion) { dbg.space() << "QGLSection(" << §ion << "- count:" << section.count() << "- smoothing mode:" << (section.smoothing() == QGL::Smooth ? "QGL::Smooth" : "QGL::Faceted") << "\n"; QGL::IndexArray indices = section.indices(); for (int i = 0; i < section.count(); ++i) { int ix = indices[i]; dbg << section.logicalVertexAt(ix) << "\n"; } dbg << ")\n"; return dbg.space(); }
/*! Finish the building of this geometry, optimize it for rendering, and return a pointer to the detached top-level scene node (root node). Since the scene is detached from the builder object, the builder itself may be deleted or go out of scope while the scene lives on: \code void MyView::MyView() { QGLBuilder builder; // construct geometry m_thing = builder.finalizedSceneNode(); } void MyView::~MyView() { delete m_thing; } void MyView::paintGL() { m_thing->draw(painter); } \endcode The root node will have a child node for each section that was created during geometry building. This method must be called exactly once after building the scene. \b{Calling code takes ownership of the scene.} In particular take care to either explicitly destroy the scene when it is no longer needed - as shown above. For more complex applications parent each finalized scene node onto a QObject so it will be implictly cleaned up by Qt. If you use QGLSceneNode::setParent() to do this, you can save an explicit call to addNode() since if setParent() detects that the new parent is a QGLSceneNode it will call addNode() for you: \code // here a top level node for the app is created, and parented to the view QGLSceneNode *topNode = new QGLSceneNode(this); QGLBuilder b1; // build geometry QGLSceneNode *thing = b1.finalizedSceneNode(); // does a QObject::setParent() to manage memory, and also adds to the scene // graph, so no need to call topNode->addNode(thing) thing->setParent(topNode); QGLBuilder b2; // build more geometry QGLSceneNode *anotherThing = b2.finalizedSceneNode(); // again parent on get addNode for free anotherThing->setParent(topNode); \endcode If this builder is destroyed without calling this method to take ownership of the scene, a warning will be printed on the console and the scene will be deleted. If this method is called more than once, on the second and subsequent calls a warning is printed and NULL is returned. This function does the following: \list \li packs all geometry data from sections into QGLSceneNode instances \li recalculates QGLSceneNode start() and count() for the scene \li deletes all QGLBuilder's internal data structures \li returns the top level scene node that references the geometry \li sets the internal pointer to the top level scene node to NULL \endlist \sa sceneNode() */ QGLSceneNode *QGLBuilder::finalizedSceneNode() { if (dptr->rootNode == 0) { qWarning("QGLBuilder::finalizedSceneNode() called twice"); return 0; } QGeometryData g; QMap<quint32, QGeometryData> geos; QMap<QGLSection*, int> offsets; for (int i = 0; i < dptr->sections.count(); ++i) { // pack sections that have the same fields into one geometry QGLSection *s = dptr->sections.at(i); QGL::IndexArray indices = s->indices(); int icnt = indices.size(); int ncnt = nodeCount(s->nodes()); int scnt = s->count(); if (scnt == 0 || icnt == 0 || ncnt == 0) { if (!qgetenv("Q_WARN_EMPTY_MESH").isEmpty()) { if (ncnt == 0) warnIgnore(scnt, s, icnt, ncnt, "nodes empty"); else if (scnt == 0) warnIgnore(scnt, s, icnt, ncnt, "geometry count zero"); else warnIgnore(scnt, s, icnt, ncnt, "index count zero"); } continue; } s->normalizeNormals(); int sectionOffset = 0; int sectionIndexOffset = 0; if (geos.contains(s->fields())) { QGeometryData &gd = geos[s->fields()]; sectionOffset = gd.count(); sectionIndexOffset = gd.indexCount(); offsets.insert(s, sectionIndexOffset); gd.appendGeometry(*s); for (int i = 0; i < icnt; ++i) indices[i] += sectionOffset; gd.appendIndices(indices); } else { g = QGeometryData(*s); geos.insert(s->fields(), g); } } while (dptr->sections.count() > 0) { QGLSection *s = dptr->sections.takeFirst(); dptr->adjustSectionNodes(s, offsets[s], geos[s->fields()]); delete s; } QGLSceneNode *tmp = dptr->rootNode; dptr->rootNode = 0; // indicates root node detached return tmp; }