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(); }
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()); } } } }