/* * * Copyright (C) 2000 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * Further, this software is distributed without any warranty that it is * free of the rightful claim of any third person regarding infringement * or the like. Any license provided herein, whether implied or * otherwise, applies only to this software file. Patent licenses, if * any, provided herein do not apply to combinations of this program with * other software, or any other product whatsoever. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, * Mountain View, CA 94043, or: * * http://www.sgi.com * * For further information regarding this notice, see: * * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ * */ #include #include #include #include #include #include #include "IfAssert.h" #include "IfReplacer.h" ///////////////////////////////////////////////////////////////////////////// // // Constructor. // ///////////////////////////////////////////////////////////////////////////// IfReplacer::IfReplacer() { } ///////////////////////////////////////////////////////////////////////////// // // Destructor. // ///////////////////////////////////////////////////////////////////////////// IfReplacer::~IfReplacer() { } ///////////////////////////////////////////////////////////////////////////// // // Replaces nodes in the given scene, in place. // ///////////////////////////////////////////////////////////////////////////// void IfReplacer::replace(SoNode *sceneRoot) { // Replace all SoBaseColor and SoPackedColor nodes with SoMaterial // nodes, which are easier to deal with replaceMaterials(sceneRoot, SoBaseColor::getClassTypeId()); replaceMaterials(sceneRoot, SoPackedColor::getClassTypeId()); } ///////////////////////////////////////////////////////////////////////////// // // Replaces all nodes of the given type with SoMaterial nodes. // ///////////////////////////////////////////////////////////////////////////// void IfReplacer::replaceMaterials(SoNode *sceneRoot, const SoType &typeToReplace) { // Find all nodes of the given type SoSearchAction sa; sa.setType(typeToReplace); sa.setInterest(SoSearchAction::ALL); sa.apply(sceneRoot); // Replace the tail of each path with a material. To do this, we // need to apply an SoCallbackAction to the path to gather the // material components. for (int i = 0; i < sa.getPaths().getLength(); i++) { // Cast the path to a full path, just in case SoFullPath *path = (SoFullPath *) sa.getPaths()[i]; ASSERT(path->getTail()->isOfType(typeToReplace)); // The path better have at least one group above the material if (path->getLength() < 2 || ! path->getNodeFromTail(1)->isOfType(SoGroup::getClassTypeId())) continue; // Create a material node that represents the material in // effect at the tail of the path SoMaterial *newMaterial = createMaterialForPath(path); newMaterial->ref(); // Replace the tail node with that material SoGroup *parent = (SoGroup *) path->getNodeFromTail(1); parent->replaceChild(path->getTail(), newMaterial); newMaterial->unref(); } } ///////////////////////////////////////////////////////////////////////////// // // Creates and returns a material node that represents the material in // effect at the tail of the given path. // ///////////////////////////////////////////////////////////////////////////// SoMaterial * IfReplacer::createMaterialForPath(SoPath *path) { material = NULL; // Apply an SoCallbackAction to the path, and create the material // after we get to the tail node SoCallbackAction cba; cba.addPostTailCallback(materialTailCB, this); cba.apply(path); ASSERT(material != NULL); return material; } ///////////////////////////////////////////////////////////////////////////// // // Stores a material created during traversal of a path. // ///////////////////////////////////////////////////////////////////////////// void IfReplacer::storeMaterial(SoCallbackAction *cba) { // Create a new material material = new SoMaterial; // Copy the values from the elements in the state into the SoState *state = cba->getState(); SoLazyElement *elt = SoLazyElement::getInstance(cba->getState()); // Most values can have only one value material->ambientColor = SoLazyElement::getAmbient(state); material->specularColor = SoLazyElement::getSpecular(state); material->emissiveColor = SoLazyElement::getEmissive(state); material->shininess = SoLazyElement::getShininess(state); // If the element contains packed colors, unpack each one into a // diffuse color and a transparency value. If they are not packed, // set the diffuse colors and transparency values separately. if (elt->isPacked()) { int num = elt->getNumDiffuse(); material->diffuseColor.setNum(num); material->transparency.setNum(num); SbColor *colors = material->diffuseColor.startEditing(); float *trans = material->transparency.startEditing(); const uint32_t *eltPacked = elt->getPackedPointer(); for (int i = 0; i < num; i++) colors[i].setPackedValue(eltPacked[i], trans[i]); material->diffuseColor.finishEditing(); material->transparency.finishEditing(); } else { int num = elt->getNumDiffuse(); material->diffuseColor.setNum(num); SbColor *colors = material->diffuseColor.startEditing(); const SbColor *eltColors = elt->getDiffusePointer(); for (int i = 0; i < num; i++) colors[i] = eltColors[i]; material->diffuseColor.finishEditing(); num = elt->getNumTransparencies(); material->transparency.setNum(num); float *trans = material->transparency.startEditing(); const float *eltTrans = elt->getTransparencyPointer(); for (i = 0; i < num; i++) trans[i] = eltTrans[i]; material->transparency.finishEditing(); } }