void SoActionMethodList::setUp() //////////////////////////////////////////////////////////////////////// { if (numValidTypes == SoType::getNumTypes()) return; // Already set up the table // SoNode's slot must be filled in. If this action doesn't have a // parent action, it is filled in with the null action. If it // does have a parent action, a dummy action is used, and the // table is overwritten with the parent's method wherever the // dummy action appears in a second pass. int i = SoNode::getActionMethodIndex(SoNode::getClassTypeId()); if ((*this)[i] == NULL) { if (parent == NULL) (*this)[i] = SoAction::nullAction; else (*this)[i] = dummyAction; } // Next, find all nodes derived from SoNode (note: it is a good // thing we don't have to do this often, since getAllDerivedFrom // must look through the entire list of types). SoTypeList nodes; SoType::getAllDerivedFrom(SoNode::getClassTypeId(), nodes); // Now, for any empty slots, fill in the slot from a parent with a // non-NULL slot: for (i = 0; i < nodes.getLength(); i++) { SoType n = nodes[i]; if ((*this)[SoNode::getActionMethodIndex(n)] == NULL) { (*this)[SoNode::getActionMethodIndex(n)] = parentMethod(n); } } // Inherit any undefined methods from parent class if (parent != NULL) { parent->setUp(); for (i = 0; i < getLength(); i++) { SoActionMethod &method = (*this)[i]; if (method == dummyAction) method = (*parent)[i]; } } numValidTypes = SoType::getNumTypes(); }
/*! This method appends all the class types derived from \a type to \a list, and returns the number of types added to the list. Internal types are not included in the list, nor are they counted. \a type itself is also added to the list, as a type is seen as a derivation of its own type. NB: do not write code which depends in any way on the order of the elements returned in \a list. Here is a small, stand-alone example which shows how this method can be used for introspection, listing all subclasses of the SoBase superclass: \code #include <stdio.h> #include <Inventor/SoDB.h> #include <Inventor/lists/SoTypeList.h> static void list_subtypes(SoType t, unsigned int indent = 0) { SoTypeList tl; SoType::getAllDerivedFrom(t, tl); for (unsigned int i=0; i < indent; i++) { printf(" "); } printf("%s\n", t.getName().getString()); indent++; for (int j=0; j < tl.getLength(); j++) { if (tl[j].getParent() == t) { // only interested in direct descendents list_subtypes(tl[j], indent); } } } int main(void) { SoDB::init(); list_subtypes(SoType::fromName("SoBase")); return 0; } \endcode */ int SoType::getAllDerivedFrom(const SoType type, SoTypeList & list) { assert(type != SoType::badType() && "argument is badType()"); int counter = 0; int n = SoType::typedatalist->getLength(); for (int i = 0; i < n; i++) { if ((*SoType::typedatalist)[i]) { SoType chktype = (*SoType::typedatalist)[i]->type; if (!chktype.isInternal() && chktype.isDerivedFrom(type)) { list.append(chktype); counter++; } } } return counter; }
void IfWeeder::findMaterialsAndShapes(SoNode *root) { // Since we know the structure of the given scene graph (which is // after fixing has occurred), we can be efficient here. Just // search for all materials in the scene. For each material, the // shapes affected by it must be under the separator that is the // material's parent node. So just search for all shapes under // that separator, making sure that the path to the shape comes // after the material. // First, create a dictionary so we can tell when we've found a // multiple instance of a material SbDict materialDict; // Search for all materials in the scene SoSearchAction sa; sa.setType(SoMaterial::getClassTypeId()); sa.setInterest(SoSearchAction::ALL); sa.apply(root); // Set up another search action to find all shapes using a // material. Note that we have to search for all node types that // should be considered shapes. SoSearchAction sa2; sa2.setInterest(SoSearchAction::ALL); // These are the shape types SoTypeList shapeTypes; IfTypes::getShapeTypes(&shapeTypes); // Process each material, adding new ones to the list materialList = new SbPList; for (int i = 0; i < sa.getPaths().getLength(); i++) { const SoPath *path = (const SoPath *) sa.getPaths()[i]; ASSERT(path->getLength() > 1); ASSERT(path->getTail()->getTypeId() == SoMaterial::getClassTypeId()); SoMaterial *material = (SoMaterial *) path->getTail(); // Add to the dictionary if necessary, or use the existing // entry void *entryPtr; IfWeederMaterialEntry *entry; if (materialDict.find((unsigned long) material, entryPtr)) { entry = (IfWeederMaterialEntry *) entryPtr; if (! entry->canWeed) continue; } else { entry = new IfWeederMaterialEntry; entry->material = material; entry->canWeed = TRUE; materialDict.enter((unsigned long) material, entry); materialList->append(entry); } // If any node above the material in the path is an opaque // group, we can't really weed this material int j; for (j = path->getLength() - 2; j >= 0; j--) { if (IfTypes::isOpaqueGroupType(path->getNode(j)->getTypeId())) { entry->canWeed = FALSE; break; } } if (! entry->canWeed) continue; ASSERT(path->getNodeFromTail(1)-> isOfType(SoSeparator::getClassTypeId())); SoSeparator *parent = (SoSeparator *) path->getNodeFromTail(1); int materialIndex = path->getIndexFromTail(0); // Find all shapes using the material, adding them to the list // of shapes in the material's entry. Store all the paths to // them in this list SoPathList pathsToShapes; for (int type = 0; type < shapeTypes.getLength(); type++) { sa2.setType(shapeTypes[type]); sa2.apply(parent); for (j = 0; j < sa2.getPaths().getLength(); j++) pathsToShapes.append(sa2.getPaths()[j]); } for (j = 0; j < pathsToShapes.getLength(); j++) { const SoPath *shapePath = (const SoPath *) pathsToShapes[j]; // We can't weed the material at all if a shape other than // the one we created is found SoType tailType = shapePath->getTail()->getTypeId(); if (tailType != SoIndexedTriangleStripSet::getClassTypeId() && tailType != SoIndexedFaceSet::getClassTypeId()) { entry->canWeed = FALSE; break; } // Make sure the shape comes after the material and does // not get its materials from a vertex property // node. else if (shapePath->getIndex(1) > materialIndex) { SoIndexedShape *is = (SoIndexedShape *) shapePath->getTail(); // ??? If the shape's materialIndex field has the // ??? default value, we assume that it might have to // ??? access all the material values. To check, we would // ??? have to look at the coordIndex values if the // ??? material binding is not OVERALL. This change could // ??? not be done in time for the release. See bug 311071. if (is->materialIndex.getNum() == 1 && is->materialIndex[0] < 0) { entry->canWeed = FALSE; break; } SoVertexProperty *vp = (SoVertexProperty *) is->vertexProperty.getValue(); if (vp == NULL || vp->orderedRGBA.getNum() == 0) entry->shapes.append(shapePath->getTail()); } } } }