/* * * 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/ * */ // // Convert from/to ASCII/binary Inventor // #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static void print_usage(const char *progname) { (void)fprintf(stderr, "Usage: %s [-bfth] [-o filename] file ...\n", progname); (void)fprintf(stderr, "-b : Output binary format (default ASCII)\n"); (void)fprintf(stderr, "-o : Write output to [filename]\n"); (void)fprintf(stderr, "-f : Expand File nodes\n"); (void)fprintf(stderr, "-t : Expand Texture2 nodes\n"); (void)fprintf(stderr, "-h : This message (help)\n"); (void)fprintf(stderr, "If given a filename of '-' or if not given\n"); (void)fprintf(stderr, "any filenames, standard input will be read\n"); exit(99); } static int parse_args(int argc, char **argv, char **outfilename, int &expandFileNodes, int &expandTextureNodes) { int err = 0; // Flag: error in options? int c; int result=0; // 0 = ASCII, 1 = BINARY while ((c = getopt(argc, argv, "bfto:h")) != -1) { switch(c) { case 'b': result = 1; break; case 'f': expandFileNodes = 1; break; case 't': expandTextureNodes = 1; break; case 'o': *outfilename = optarg; break; case 'h': // Help default: err = 1; break; } } if (err) { print_usage(argv[0]); } return result; } // // This routine searches for and expands all SoFile nodes in the // given scene graph. It does this by making all the children of a // SoFile node the children of its parent. // static void nukeFileNodes(SoNode *&root) { // // Special case: if root is a file node, replace it with a group. // if (root->isOfType(SoFile::getClassTypeId())) { SoFile *f = (SoFile *)root; SoGroup *g = f->copyChildren(); root->unref(); root = g; root->ref(); } // Search for all file nodes SoSearchAction sa; sa.setType(SoFile::getClassTypeId()); sa.setInterest(SoSearchAction::FIRST); sa.setSearchingAll(TRUE); sa.apply(root); // We'll keep on searching until there are no more file nodes // left. We don't search for all file nodes at once, because we // need to modify the scene graph, and so the paths returned may // be truncated (if there are several file nodes under a group, if // there are files within files, etc). Dealing properly with that // is complicated-- it is easier (but slower) to just reapply the // search until it fails. // We need an SoFullPath here because we're searching node kit // contents. SoFullPath *p = (SoFullPath *) sa.getPath(); while (p != NULL) { SoGroup *parent = (SoGroup *)p->getNodeFromTail(1); assert(parent != NULL); SoFile *file = (SoFile *)p->getTail(); // If the filename includes a directory path, add the directory name // to the list of directories where to look for input files const char* filename = file->name.getValue().getString(); const char *slashPtr; char *searchPath = NULL; if ((slashPtr = strrchr(filename, '/')) != NULL) { searchPath = strdup(filename); searchPath[slashPtr - filename] = '\0'; SoInput::addDirectoryFirst(searchPath); } int fileIndex = parent->findChild(file); assert(fileIndex != -1); // Now, add group of all children to file's parent's list of children, // right after the file node: SoGroup *fileGroup = file->copyChildren(); fileGroup->ref(); if (fileGroup != NULL) parent->insertChild(fileGroup, fileIndex+1); else // So we can at least see where the file node contents were // supposed to go. parent->insertChild(new SoGroup, fileIndex+1); // And expand the child node from the group. // Note that if the File node is multiply instanced, // the groups will not be instanced, but the children of the // groups will be. parent->removeChild(fileIndex); sa.apply(root); p = (SoFullPath *) sa.getPath(); } } // // This routine searches for and expands all SoTexture2 nodes in the // given scene graph. It does this by doing a // startEditing/finishEditing operation on the image field of the // texture nodes. // static void nukeTextureNodes(SoNode *&root) { // Search for all texture nodes SoSearchAction sa; sa.setType(SoTexture2::getClassTypeId()); sa.setInterest(SoSearchAction::ALL); sa.apply(root); SoPathList &pl = sa.getPaths(); for (int i = 0; i < pl.getLength(); i++) { SoTexture2 *tex = (SoTexture2 *)((SoFullPath *) pl[i])->getTail(); // Stuff returned by startEditing: SbVec2s size; int nc; (void)tex->image.startEditing(size, nc); tex->image.finishEditing(); } } main(int argc, char **argv) { int expandFileNodes = 0; int expandTextureNodes = 0; SoInteraction::init(); // Search children of node kits. This is needed to be able to // find and expand nodes in the "contents" of SoWrapperKits. SoBaseKit::setSearchingChildren(TRUE); // Parse arguments char *outputfile = NULL; int binary = 0; binary = parse_args(argc, argv, &outputfile, expandFileNodes, expandTextureNodes); // read stuff: SoInput in; SoNode *root; SoNodeList nodeList; if (optind == argc) { ++argc; // Act like one argument "-" was given argv[optind] = "-"; } for (; optind < argc; optind++) { char *filename = argv[optind]; if (strcmp(filename, "-") == 0) { if (isatty(fileno(stdin))) { fprintf(stderr, "Trying to read from standard input, "); fprintf(stderr, "but standard input is a tty!\n"); print_usage(argv[0]); } in.setFilePointer(stdin); filename = NULL; // Tested later... } else if (in.openFile(filename) == FALSE) { fprintf(stderr, "Could not open file %s\n", filename); } // If the filename includes a directory path, add the directory name // to the list of directories where to look for input files if (filename != NULL) { const char *slashPtr; char *searchPath = NULL; if ((slashPtr = strrchr(filename, '/')) != NULL) { searchPath = strdup(filename); searchPath[slashPtr - filename] = '\0'; in.addDirectoryFirst(searchPath); } } do { int read_ok = SoDB::read(&in, root); if (!read_ok) { fprintf(stderr, "Error reading %s\n", filename == NULL ? "stdin" : filename); print_usage(argv[0]); } else if (root != NULL) { root->ref(); if (expandFileNodes) { nukeFileNodes(root); } if (expandTextureNodes) { nukeTextureNodes(root); } nodeList.append(root); root->unref(); } } while (root != NULL); if (filename != NULL) in.closeFile(); } // write stuff SoOutput out; out.setBinary(binary); if (outputfile == NULL) { out.setFilePointer(stdout); } else { if (out.openFile(outputfile) == FALSE) { fprintf(stderr, "Couldn't open %s for writing\n", outputfile); print_usage(argv[0]); } } SoWriteAction writer(&out); for (int i = 0; i < nodeList.getLength(); i++) { writer.apply(nodeList[i]); } if (outputfile != NULL) out.closeFile(); return 0; }