home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (C) 1994, Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
- * the contents of this file may not be disclosed to third parties, copied or
- * duplicated in any form, in whole or in part, without the prior written
- * permission of Silicon Graphics, Inc.
- *
- * RESTRICTED RIGHTS LEGEND:
- * Use, duplication or disclosure by the Government is subject to restrictions
- * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
- * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
- * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
- * rights reserved under the Copyright Laws of the United States.
- */
- /*
- | Classes:
- | WorldInfo
- |
- | Author(s): Paul Isaacs
- |
- */
-
-
- #include <stdio.h>
- #include <Inventor/SbLinear.h>
- #include <Inventor/SoDB.h>
- #include <Inventor/SoLists.h>
- #include <Inventor/SbViewportRegion.h>
- #include <Inventor/SoPickedPoint.h>
-
- #include <Inventor/actions/SoGetBoundingBoxAction.h>
- #include <Inventor/actions/SoSearchAction.h>
- #include <Inventor/manips/SoHandleBoxManip.h>
- #include <Inventor/nodes/SoSelection.h>
- #include <Inventor/nodes/SoSeparator.h>
- #include <Inventor/errors/SoDebugError.h>
-
- #include "WorldInfo.h"
- #include "GeneralizedCylinder.h"
-
- WorldInfo::WorldInfo()
- {
- // Make worldRoot
- worldRoot = new SoSeparator;
- worldRoot->ref();
-
- // Add selection node.
-
- selector = new SoSelection;
- worldRoot->addChild(selector);
- selector->addSelectionCallback( &WorldInfo::selectionCB, this );
- selector->addDeselectionCallback( &WorldInfo::deselectionCB, this );
- selector->setPickFilterCallback( &WorldInfo::pickFilterCB, this );
-
- // Put sceneRoot under selector
- sceneRoot = new SoSeparator;
- selector->addChild( sceneRoot );
-
- // Create the deletedNoodles list. We store them so they can be un-deleted.
- deletedNoodles = new SoNodeList;
-
- // This piece will be dragged in z whenever the activePlane moves.
- currentNoodle = NULL;
-
- // Initialize other variables.
- fileName = NULL;
-
- manipType = SoTransform::getClassTypeId();
- }
-
- WorldInfo::~WorldInfo()
- {
- if ( worldRoot ) worldRoot->unref();
- if ( deletedNoodles ) delete deletedNoodles;
- }
-
- /////////////////////////////////////////////////////////////////////
- // Set the type of manipulator being used to move selected noodles.
- // Then install one in each selected noodle.
- //
- void
- WorldInfo::setManipType( SoType newType )
- {
- if ( newType == manipType)
- return;
-
- if ( ! newType.isDerivedFrom( SoTransform::getClassTypeId() ))
- return;
-
- manipType = newType;
-
- // Get all selections; replace their transforms with the new type.
- const SoPathList *pl = selector->getList();
- for (int i = 0; i < selector->getNumSelected(); i++ ) {
-
- SoNode *t = (*pl)[i]->getTail();
- if (t->isOfType(GeneralizedCylinder::getClassTypeId()))
- ((GeneralizedCylinder *)t)->changeTransformType(newType);
- }
- }
-
- /////////////////////////////////////////////////////////////////////
- // Returns a copy of the scene with all noodles replaced by subgraphs
- // of standard inventor nodes.
- SoSeparator *
- WorldInfo::getVanillaSceneCopy()
- {
- if (sceneRoot == NULL)
- return NULL;
-
- SoSeparator *myCopy = (SoSeparator *) sceneRoot->copy();
- myCopy->ref();
-
- // Replace every GeneralizedCylinder in the copy with just the
- // data that draws, removing the nodekit.
- SoSearchAction *sa = new SoSearchAction;
- sa->setType( GeneralizedCylinder::getClassTypeId() );
- sa->setInterest( SoSearchAction::ALL );
- sa->apply( myCopy );
- SoPathList *genCylPaths = &(sa->getPaths());
- SoFullPath *myPath;
- SoNode *myParent;
- GeneralizedCylinder *gc;
- SoGroup *parentGroup;
-
- for ( int i = 0; i < genCylPaths->getLength(); i++ ) {
- myPath = (SoFullPath *) (*genCylPaths)[i];
- myParent = myPath->getNode( myPath->getLength() - 2 );
- gc = (GeneralizedCylinder *) myPath->getTail();
- if ( myParent->isOfType( SoGroup::getClassTypeId() ) == FALSE ) {
- fprintf(stderr,"Error converting scene to vanilla. Found a \n");
- fprintf(stderr,"non-group parent of the generalized cyliinder\n");
- break;
- }
- parentGroup = (SoGroup *) myParent;
- SoSeparator *vanillaObject = gc->makeVanillaVersion();
- parentGroup->replaceChild( gc, vanillaObject );
- }
-
- // Delete the search action BEFORE unrefNodelete. This takes
- // count down to 1.
- delete sa;
-
- // Take count from 1 to 0
- myCopy->unrefNoDelete();
-
- return myCopy;
- }
-
- void
- WorldInfo::setScene( SoSeparator *newScene )
- {
- if (newScene == sceneRoot)
- return;
-
- // Deselect everything.
- selector->deselectAll();
-
- // Always have at least an empty separator in the scene.
- if (newScene == NULL)
- newScene = new SoSeparator;
-
- if (sceneRoot == NULL) {
- #ifdef DEBUG
- SoDebugError::post("WorldInfo::setScene", "old sceneRoot is NULL");
- #endif
- selector->insertChild( newScene, 0 );
- }
- else
- selector->replaceChild( sceneRoot, newScene );
-
- sceneRoot = newScene;
-
- // Now, select the first noodle in the scene
- setFirstNoodleCurrent();
- }
-
- SbBool
- WorldInfo::isSceneEmpty()
- {
- if (sceneRoot == NULL) {
- #ifdef DEBUG
- SoDebugError::post("WorldInfo::setScene", "old sceneRoot is NULL");
- #endif
- return TRUE;
- }
- else
- return ( sceneRoot->getNumChildren() == 0);
- }
-
- void
- WorldInfo::setFileName( char *newFileName )
- {
- if (newFileName == NULL)
- fileName = NULL;
- else
- fileName = strdup( newFileName );
- }
-
- void
- WorldInfo::addNoodle( GeneralizedCylinder *newNoodle )
- {
- if (newNoodle == NULL)
- return;
- sceneRoot->addChild( newNoodle );
- }
-
- void
- WorldInfo::deleteNoodle( GeneralizedCylinder *victim )
- {
- // See if victim is in the selection list...
- // We'd prefer to delete based on selection path, if possible, since we
- // can then deselect.
- SoFullPath *victimPath = NULL;
- for (int i = 0; i < selector->getNumSelected(); i++ ) {
- if ( ((SoNodeKitPath *)selector->getPath(i))->getTail() == victim ) {
- victimPath = (SoFullPath *) selector->getPath(i);
- victimPath->ref();
- break;
- }
- }
- if (victimPath) {
- // deselect old one if it is selected...
- selector->deselect(victimPath);
- }
- else {
- // If it wasn't a selection, get a path to it...
- SoSearchAction sa;
- sa.setNode( victim );
- sa.setInterest( SoSearchAction::FIRST );
- SbBool wasSearchingKits = SoBaseKit::isSearchingChildren();
- SoBaseKit::setSearchingChildren(TRUE);
- sa.apply( selector );
- SoBaseKit::setSearchingChildren(wasSearchingKits);
- victimPath = (SoFullPath *) sa.getPath();
- if (victimPath)
- victimPath->ref();
- }
-
- if ( ! victimPath )
- return;
-
- // Remove piece from parent.
- if (victimPath != NULL) {
- // Get index of victim in the path...
- for (int objInd = victimPath->getLength() - 1; objInd >= 0; objInd --) {
- if ( victimPath->getNode(objInd) == victim )
- break;
- }
- SoNode *parent = NULL;
- SoType bkt = SoBaseKit::getClassTypeId();
- // Remove victim from its parent.
- // For parent, if there's a nodekit above victim, use that first kit.
- for (int pInd = objInd - 1; pInd >= 0; pInd --) {
- if (victimPath->getNode(pInd)->isOfType( bkt ) ) {
- parent = victimPath->getNode(pInd);
- SoBaseKit *k = (SoBaseKit *)parent;
- k->setPart( k->getPartString(victim), NULL );
- break;
- }
- }
- // Otherwise, use the first node above victim.
- if ( parent == NULL ) {
- parent = victimPath->getNodeFromTail( 1 );
- if (parent->isOfType( SoGroup::getClassTypeId() ))
- ((SoGroup *)parent)->removeChild( victim );
- }
-
- }
- victimPath->unref();
- }
-
-
- void
- WorldInfo::deleteCurrentNoodle()
- {
- if (currentNoodle == NULL)
- return;
-
- currentNoodle->ref();
- deleteNoodle( currentNoodle );
- deletedNoodles->append( currentNoodle );
- currentNoodle->unref();
- }
-
- GeneralizedCylinder *
- WorldInfo::undeleteNoodle()
- {
- int num = deletedNoodles->getLength();
- if ( num <= 0)
- return NULL;
-
- GeneralizedCylinder *theNoodle
- = (GeneralizedCylinder *) (*deletedNoodles)[num - 1];
-
- theNoodle->ref();
-
- addNoodle( theNoodle );
-
- // Since we're undeleting the noodle, make it the only selection.
- selector->deselectAll();
- selector->select( theNoodle );
-
- setCurrentNoodle( theNoodle );
-
- theNoodle->unrefNoDelete();
-
- deletedNoodles->remove( num - 1);
-
- return theNoodle;
- }
-
- GeneralizedCylinder *
- WorldInfo::setFirstNoodleCurrent()
- {
- if (sceneRoot == NULL)
- return NULL;
-
- SoSearchAction sa;
- sa.setType( GeneralizedCylinder::getClassTypeId() );
- sa.apply( sceneRoot );
- SoPath *pathToFirst = sa.getPath();
- if (pathToFirst == NULL)
- return NULL;
-
- GeneralizedCylinder *first = (GeneralizedCylinder *) pathToFirst->getTail();
-
- // Since we're undeleting the noodle, make it the only selection.
- selector->deselectAll();
- selector->select( first );
-
- setCurrentNoodle( first );
-
- return first;
- }
-
- GeneralizedCylinder *
- WorldInfo::addNewNoodle()
- {
- GeneralizedCylinder *newOne = new GeneralizedCylinder;
- newOne->ref();
-
- addNoodle( newOne );
-
- // Since we're adding a new noodle, make it the only selection.
- selector->deselectAll();
- selector->select( newOne );
-
- setCurrentNoodle( newOne );
- newOne->unrefNoDelete();
-
- return newOne;
- }
-
- void
- WorldInfo::setCurrentNoodle( GeneralizedCylinder *newNoodle )
- {
- currentNoodle = newNoodle;
-
- // Add a manipulator if necessary...
- if (currentNoodle)
- currentNoodle->changeTransformType( getManipType() );
- }
-
- void
- WorldInfo::selectionCB(void *userData, SoPath *selectPath)
- {
- // Return if pickFilter truncated path down to nothing.
- if (selectPath->getLength() == 0)
- return;
-
- WorldInfo *myself = (WorldInfo *) userData;
-
- SoNodeKitPath *nkPath = (SoNodeKitPath *) selectPath;
- GeneralizedCylinder *g = (GeneralizedCylinder *) nkPath->getTail();
-
- myself->setCurrentNoodle( g );
- }
-
- void
- WorldInfo::deselectionCB(void *, SoPath *deselectPath)
- {
- if (deselectPath->getLength() == 0)
- return;
-
- SoNodeKitPath *nkPath = (SoNodeKitPath *) deselectPath;
- GeneralizedCylinder *g = (GeneralizedCylinder *) nkPath->getTail();
-
- g->changeTransformType( SoTransform::getClassTypeId() );
- }
-
- SoPath *
- WorldInfo::pickFilterCB(void *data, const SoPickedPoint *pick )
- {
- WorldInfo *myself = (WorldInfo *) data;
-
- SoPath *filteredPath = NULL;
- SoFullPath *fullP = (SoFullPath *) pick->getPath();
-
- // Go up the path, and keep popping nodes until the tail is a
- // Generalized Cylinder kit...
- while ( fullP->getLength() > 0 &&
- ! fullP->getTail()->isOfType( GeneralizedCylinder::getClassTypeId() ) )
- fullP->pop();
-
- return fullP;
- }
-