/* * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "IfAssert.h" #include "IfShape.h" ///////////////////////////////////////////////////////////////////////////// // // Constructor. // ///////////////////////////////////////////////////////////////////////////// IfShape::IfShape() { // Level 1: camera = NULL; // Level 2: lights = NULL; clipPlanes = NULL; environment = NULL; lightModel = NULL; // Level 3: texture = NULL; // Level 4: drawStyle = NULL; shapeHints = NULL; material = NULL; other = NULL; // Level 5: complexity = NULL; coords = NULL; font = NULL; materialBinding = NULL; normals = NULL; normalBinding = NULL; profileCoords = NULL; profiles = NULL; texCoords = NULL; texCoordBinding = NULL; // IfShape: shape = NULL; transform.makeIdentity(); textureTransforms = NULL; differenceLevel = -1; differenceCode = NONE; dontFlatten = FALSE; } ///////////////////////////////////////////////////////////////////////////// // // Destructor. // ///////////////////////////////////////////////////////////////////////////// IfShape::~IfShape() { clearNodes(); } ///////////////////////////////////////////////////////////////////////////// // // This compares two IfShape instances and returns the first level // (1-5) at which they differ, a comparison code (-1, 0, or +1) // to indicate the result, and a more specific difference code. // ///////////////////////////////////////////////////////////////////////////// int IfShape::compare(const IfShape *s1, const IfShape *s2, int &level, DifferenceCode &diffCode) { ////////////////////////////////////////////////////////////////// // // The first two macros are used to make quick comparisons between // nodes that are unlikely to differ from one shape to the // next. They just compare node pointers for equality. Nodes that // are compared by examining values in fields are handled // specially, using the other macros. // #define COMPARE_NODES(node, code) \ if (s1->node != s2->node) { \ diffCode = code; \ return s2->node - s1->node; \ } #define COMPARE_LISTS(list, code) \ if (s1->list != s2->list) { \ int c = compareLists(s1->list, s2->list); \ if (c != 0) { \ diffCode = code; \ return c; \ } \ } #define COMPARE_NULL_NODE_POINTERS(node, code) \ if (s1->node == NULL) { \ diffCode = code; \ return -1; \ } \ if (s2->node == NULL) { \ diffCode = code; \ return 1; \ } #define COMPARE_INT_FIELDS(node, field, code) \ if (s1->node->field.getValue() != s2->node->field.getValue()) { \ diffCode = code; \ return ((int) s2->node->field.getValue() - \ (int) s1->node->field.getValue()); \ } #define COMPARE_FLOAT_FIELDS(node, field, code) \ if (s1->node->field.getValue() != s2->node->field.getValue()) { \ int c = compareFloats(s1->node->field.getValue(), \ s2->node->field.getValue()); \ if (c != 0) { \ diffCode = code; \ return c; \ } \ } #define COMPARE_MFLOAT_FIELDS(node, field, code) \ if (s1->node->field.getNum() != s2->node->field.getNum()) \ return s2->node->field.getNum() - s1->node->field.getNum(); \ if (s1->node->field.getNum() == 1) { \ int c = compareFloats(s1->node->field[0], s2->node->field[0]); \ if (c != 0) { \ diffCode = code; \ return c; \ } \ } \ else { \ diffCode = code; \ return s2->node - s1->node; \ } #define COMPARE_MCOLOR_FIELDS(node, field, code) \ if (s1->node->field.getNum() != s2->node->field.getNum()) \ return s2->node->field.getNum() - s1->node->field.getNum(); \ if (s1->node->field.getNum() == 1) { \ int c = compareColors(s1->node->field[0], s2->node->field[0]); \ if (c != 0) { \ diffCode = code; \ return c; \ } \ } \ else { \ diffCode = code; \ return s2->node - s1->node; \ } ////////////////////////////////////////////////////////////////// level = 1; COMPARE_NODES(camera, CAMERA); level = 2; COMPARE_LISTS(lights, LIGHTS); COMPARE_LISTS(clipPlanes, CLIP_PLANES); COMPARE_NODES(environment, ENVIRONMENT); COMPARE_NODES(lightModel, LIGHT_MODEL); level = 3; // Comparing textures uses the file names if they are set if (s1->texture != s2->texture) { COMPARE_NULL_NODE_POINTERS(texture, TEXTURE); const SbString &name1 = s1->texture->filename.getValue(); const SbString &name2 = s2->texture->filename.getValue(); // If no names, use the texture nodes themselves if (! name1) return s2->texture - s1->texture; int c = strcmp(name1.getString(), name2.getString()); if (c != 0) return c; } level = 4; // Comparing draw style tests the values in the nodes if (s1->drawStyle != s2->drawStyle) { COMPARE_NULL_NODE_POINTERS(drawStyle, DRAW_STYLE); COMPARE_INT_FIELDS(drawStyle, style, DRAW_STYLE); COMPARE_FLOAT_FIELDS(drawStyle, pointSize, DRAW_STYLE); COMPARE_FLOAT_FIELDS(drawStyle, lineWidth, DRAW_STYLE); COMPARE_INT_FIELDS(drawStyle, linePattern, DRAW_STYLE); } // Comparing shape hints tests the values in the nodes if (s1->shapeHints != s2->shapeHints) { COMPARE_NULL_NODE_POINTERS(shapeHints, SHAPE_HINTS); COMPARE_INT_FIELDS(shapeHints, vertexOrdering, SHAPE_HINTS); COMPARE_INT_FIELDS(shapeHints, shapeType, SHAPE_HINTS); COMPARE_INT_FIELDS(shapeHints, faceType, SHAPE_HINTS); COMPARE_FLOAT_FIELDS(shapeHints, creaseAngle, SHAPE_HINTS); } COMPARE_LISTS(other, OTHER); // Comparing materials tests the values in the nodes if there is // only one material in each. // NOTE: the material comparison has to come last within this // level so that the IfMerger stuff works properly. if (s1->material != s2->material) { COMPARE_NULL_NODE_POINTERS(material, MATERIAL); COMPARE_MCOLOR_FIELDS(material, ambientColor, MATERIAL); COMPARE_MCOLOR_FIELDS(material, diffuseColor, MATERIAL); COMPARE_MCOLOR_FIELDS(material, specularColor, MATERIAL); COMPARE_MCOLOR_FIELDS(material, emissiveColor, MATERIAL); COMPARE_MFLOAT_FIELDS(material, shininess, MATERIAL); COMPARE_MFLOAT_FIELDS(material, transparency, MATERIAL); } // If nothing else differs, the shape must. We usually consider // them to be the same in this case. However, if the shape is not // really a shape (it may be a File or similar node), we need to // make sure it is not "flattened" later on. To indicate this, we // return a level 5 difference. (We can still return that they are // the same, since the difference matters only after they have // been sorted, when the levels are computed for real.) if (s1->dontFlatten || s2->dontFlatten) { level = 5; return 0; } // If we got here, they're the same, except for the // shape. Consider them to be the same, even though they actually // differ at Level 5. level = 0; return 0; #undef COMPARE_NODES #undef COMPARE_LISTS } ///////////////////////////////////////////////////////////////////////////// // // Compares two node lists for equality. // ///////////////////////////////////////////////////////////////////////////// int IfShape::compareLists(const SoNodeList *l1, const SoNodeList *l2) { if (l1 == NULL) return -1; if (l2 == NULL) return 1; if (l1->getLength() != l2->getLength()) return l2->getLength() - l1->getLength(); for (int i = 0; i < l1->getLength(); i++) if ((*l1)[i] != (*l2)[i]) return (*l2)[i] - (*l2)[i]; return 0; } ///////////////////////////////////////////////////////////////////////////// // // Compares two floating point numbers for equality. // ///////////////////////////////////////////////////////////////////////////// int IfShape::compareFloats(float f1, float f2) { if (f1 < f2) return -1; else if (f1 > f2) return 1; else return 0; } ///////////////////////////////////////////////////////////////////////////// // // Compares two colors for equality. // ///////////////////////////////////////////////////////////////////////////// int IfShape::compareColors(const SbColor &c1, const SbColor &c2) { for (int i = 0; i < 3; i++) { if (c1[i] < c2[i]) return -1; else if (c1[i] > c2[i]) return 1; } return 0; } ///////////////////////////////////////////////////////////////////////////// // // Adds the appropriate nodes for the given level to the given // group node. // ///////////////////////////////////////////////////////////////////////////// void IfShape::addNodesForLevel(SoGroup *group, int level) { #define ADD_NODE(n) if (n != NULL) group->addChild(n) #define ADD_LIST(l) if (l != NULL) { \ for (i = 0; i < (*l).getLength(); i++) \ group->addChild((*l)[i]); \ } int i; ASSERT(level > 0 && level <= 5); switch (level) { case 1: ADD_NODE(camera); break; case 2: ADD_LIST(lights); ADD_LIST(clipPlanes); ADD_NODE(environment); ADD_NODE(lightModel); break; case 3: ADD_NODE(texture); break; case 4: ADD_NODE(drawStyle); ADD_NODE(shapeHints); ADD_NODE(material); ADD_LIST(other); break; case 5: // For level 5, we add each set of nodes under its own // separator { SoSeparator *sep = new SoSeparator; group->addChild(sep); group = sep; } ADD_NODE(complexity); ADD_NODE(coords); ADD_NODE(font); ADD_NODE(materialBinding); ADD_NODE(normals); ADD_NODE(normalBinding); ADD_NODE(profileCoords); ADD_LIST(profiles); ADD_NODE(texCoords); ADD_NODE(texCoordBinding); // Handle matrices specially if (transform != SbMatrix::identity()) { SoMatrixTransform *xf = new SoMatrixTransform; group->addChild(xf); xf->matrix = transform; } ADD_LIST(textureTransforms); ADD_NODE(shape); break; default: fprintf(stderr, "Error in IfShape::addNodesForLevel(level %d)\n", level); } #undef ADD_NODE #undef ADD_LIST } ///////////////////////////////////////////////////////////////////////////// // // Unref's non-NULL node pointers. // ///////////////////////////////////////////////////////////////////////////// void IfShape::clearNodes() { #define CLEAR_NODE(name) if (name != NULL) { name->unref(); name = NULL; } #define CLEAR_LIST(name) if (name != NULL) { delete name; name = NULL; } CLEAR_NODE(camera); CLEAR_NODE(environment); CLEAR_NODE(lightModel); CLEAR_NODE(texture); CLEAR_NODE(drawStyle); CLEAR_NODE(shapeHints); CLEAR_NODE(material); CLEAR_NODE(complexity); CLEAR_NODE(coords); CLEAR_NODE(font); CLEAR_NODE(materialBinding); CLEAR_NODE(normals); CLEAR_NODE(normalBinding); CLEAR_NODE(profileCoords); CLEAR_NODE(texCoords); CLEAR_NODE(texCoordBinding); CLEAR_NODE(shape); CLEAR_LIST(lights); CLEAR_LIST(clipPlanes); CLEAR_LIST(other); CLEAR_LIST(profiles); #undef CLEAR_NODE #undef CLEAR_LIST }