/* * * 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/ * */ /* * Copyright (C) 1990,91,92 Silicon Graphics, Inc. * _______________________________________________________________________ ______________ S I L I C O N G R A P H I C S I N C . ____________ | | $Revision: 1.1.1.1 $ | | Classes: | SoSceneManager | | Author(s): David Mott, Alain Dumesny | ______________ S I L I C O N G R A P H I C S I N C . ____________ _______________________________________________________________________ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Sensor which touches realTime as soon as possible after a redraw SoSFTime *SoSceneManager::realTime = NULL; SoOneShotSensor *SoSceneManager::realTimeSensor = NULL; SbBool SoSceneManager::updateRealTime = TRUE; //////////////////////////////////////////////////////////////////////// // // Constructor // SoSceneManager::SoSceneManager() // //////////////////////////////////////////////////////////////////////// { bkgColor.setValue(0,0,0); bkgIndex = 0; rgbMode = TRUE; graphicsInitNeeded = TRUE; // inventor specific variables scene = NULL; raCreatedHere = TRUE; renderAction = new SoGLRenderAction(SbVec2s(1,1)); heaCreatedHere = TRUE; handleEventAction = new SoHandleEventAction(SbVec2s(1,1)); renderCB = NULL; renderCBData = NULL; active = FALSE; needToSendVP = TRUE; // create the scene sensor (used for automatic rendering) // do not attach the sensor here. That's done when we // become active, and the user supplies a redraw callback. sceneSensor = new SoNodeSensor; sceneSensor->setData((void *) this); #ifdef DEBUG if (SoDebug::GetEnv("IV_DEBUG_SENSORS")) { SoDebug::NamePtr("sceneChangeSensor", sceneSensor); } #endif // Assume default priority now. We'll set the sensor priority // before we attach, just in case the user changes the priority // before that occurs. setRedrawPriority(getDefaultRedrawPriority()); // setup the sensor to touch real time after a redraw if (! realTimeSensor) { realTime = (SoSFTime *) SoDB::getGlobalField("realTime"); realTimeSensor = new SoOneShotSensor; realTimeSensor->setFunction((SoSensorCB *) &SoSceneManager::realTimeSensorCB); #ifdef DEBUG if (SoDebug::GetEnv("IV_DEBUG_SENSORS")) { SoDebug::NamePtr("realTimeSensor", realTimeSensor); } #endif } } //////////////////////////////////////////////////////////////////////// // // Destructor // SoSceneManager::~SoSceneManager() // //////////////////////////////////////////////////////////////////////// { // delete actions if (raCreatedHere) delete renderAction; if (heaCreatedHere) delete handleEventAction; // detach the scene setSceneGraph(NULL); delete sceneSensor; } //////////////////////////////////////////////////////////////////////// // // Set a new render action, for instance for highlighting. // // public // void SoSceneManager::setGLRenderAction(SoGLRenderAction *ra) // //////////////////////////////////////////////////////////////////////// { #ifdef DEBUG if (ra == NULL) SoDebugError::post("SoSceneManager::setGLRenderAction", "a NULL render action was passed. This is bad!"); #endif // Make sure the viewport region is set // (be paranoid and check for NULL) if (renderAction != NULL) { SbViewportRegion rgn(renderAction->getViewportRegion()); ra->setViewportRegion(rgn); } // Get rid of the old render action if it was created here. if (raCreatedHere) { delete renderAction; raCreatedHere = FALSE; } // Set to the new render action. renderAction = ra; } //////////////////////////////////////////////////////////////////////// // // Set a new handle event action. Passing NULL will shut off event // handling. // // public // void SoSceneManager::setHandleEventAction(SoHandleEventAction *hea) // //////////////////////////////////////////////////////////////////////// { // Make sure the viewport region is set if ((handleEventAction != NULL) && (hea != NULL)) { SbViewportRegion rgn(handleEventAction->getViewportRegion()); hea->setViewportRegion(rgn); } // Get rid of the old render action if it was created here. if (heaCreatedHere) { delete handleEventAction; heaCreatedHere = FALSE; } // Set to the new render action. handleEventAction = hea; } //////////////////////////////////////////////////////////////////////// // // Description: // Make the new user supplied scene graph the rendering root. // // use: virtual public // void SoSceneManager::setSceneGraph(SoNode *newScene) // //////////////////////////////////////////////////////////////////////// { SbBool currentlyActive = isActive(); deactivate(); // ref the new scene if (newScene != NULL) newScene->ref(); // check if there already is a scene graph if (scene != NULL) scene->unref(); // now set the new scene graph scene = newScene; if (currentlyActive) activate(); } //////////////////////////////////////////////////////////////////////// // // Description: // Return the user supplied scene graph. // // use: virtual public // SoNode * SoSceneManager::getSceneGraph() const // //////////////////////////////////////////////////////////////////////// { return scene; } //////////////////////////////////////////////////////////////////////// // // Description: // Process the passed X event. // // use: virtual protected // SbBool SoSceneManager::processEvent(const SoEvent *event) // //////////////////////////////////////////////////////////////////////// { if ((scene != NULL) && (handleEventAction != NULL)) { handleEventAction->setEvent(event); handleEventAction->apply(scene); return handleEventAction->isHandled(); } else return FALSE; } //////////////////////////////////////////////////////////////////////// // // Initialize the window for rendering. // A window MUST be set before this is called. // // use: public // void SoSceneManager::reinitialize() // //////////////////////////////////////////////////////////////////////// { graphicsInitNeeded = TRUE; // we have a new window, so re-init the render action renderAction->invalidateState(); } //////////////////////////////////////////////////////////////////////// // // Set the size of the window. // // use: public // void SoSceneManager::setWindowSize(const SbVec2s &newSize) // //////////////////////////////////////////////////////////////////////// { SbViewportRegion rgn(renderAction->getViewportRegion()); rgn.setWindowSize(newSize); if (renderAction != NULL) renderAction->setViewportRegion(rgn); if (handleEventAction != NULL) handleEventAction->setViewportRegion(rgn); // make sure to call glViewport() with the new size needToSendVP = TRUE; } //////////////////////////////////////////////////////////////////////// // // Set the size of the window. // // use: public // const SbVec2s & SoSceneManager::getWindowSize() const // //////////////////////////////////////////////////////////////////////// { return renderAction->getViewportRegion().getWindowSize(); } //////////////////////////////////////////////////////////////////////// // // Set the size of the viewport within the window. // // use: public // void SoSceneManager::setSize(const SbVec2s &newSize) // //////////////////////////////////////////////////////////////////////// { SbViewportRegion rgn(renderAction->getViewportRegion()); const SbVec2s &origin = rgn.getViewportOriginPixels(); rgn.setViewportPixels(origin, newSize); if (renderAction != NULL) renderAction->setViewportRegion(rgn); if (handleEventAction != NULL) handleEventAction->setViewportRegion(rgn); } //////////////////////////////////////////////////////////////////////// // // Set origin relative to the window. // // use: public // void SoSceneManager::setOrigin(const SbVec2s &newOrigin) // //////////////////////////////////////////////////////////////////////// { SbViewportRegion rgn(renderAction->getViewportRegion()); const SbVec2s &size = rgn.getViewportSizePixels(); rgn.setViewportPixels(newOrigin, size); if (renderAction != NULL) renderAction->setViewportRegion(rgn); if (handleEventAction != NULL) handleEventAction->setViewportRegion(rgn); } //////////////////////////////////////////////////////////////////////// // // Get viewport size. // // use: public // const SbVec2s & SoSceneManager::getSize() const // //////////////////////////////////////////////////////////////////////// { return renderAction->getViewportRegion().getViewportSizePixels(); } //////////////////////////////////////////////////////////////////////// // // Get origin relative to the window. // // use: public // const SbVec2s & SoSceneManager::getOrigin() const // //////////////////////////////////////////////////////////////////////// { return renderAction->getViewportRegion().getViewportOriginPixels(); } //////////////////////////////////////////////////////////////////////// // // Set the viewport region instead of setting size and origin separately. // // use: public // void SoSceneManager::setViewportRegion(const SbViewportRegion &rgn) // //////////////////////////////////////////////////////////////////////// { if (renderAction != NULL) renderAction->setViewportRegion(rgn); if (handleEventAction != NULL) handleEventAction->setViewportRegion(rgn); } //////////////////////////////////////////////////////////////////////// // // Get the viewport region. // // use: public // const SbViewportRegion & SoSceneManager::getViewportRegion() const // //////////////////////////////////////////////////////////////////////// { return renderAction->getViewportRegion(); } //////////////////////////////////////////////////////////////////////// // // Set to RGB mode or color map mode. // // use: public // void SoSceneManager::setRGBMode(SbBool onOrOff) // //////////////////////////////////////////////////////////////////////// { rgbMode = onOrOff; // the render action determines color map/rgb at initialization //???pauli renderAction->reinitialize(); } //////////////////////////////////////////////////////////////////////// // // Description: // Sets antialiasing on GL rendering action. // // use: public // void SoSceneManager::setAntialiasing(SbBool smoothing, int numPasses) // //////////////////////////////////////////////////////////////////////// { renderAction->setSmoothing( smoothing ); renderAction->setNumPasses( numPasses ); // Set render action callback for multiple pass rendering. This // makes sure to clear background to correct color between frames. if ( numPasses > 1 ) renderAction->setPassCallback(antialiasingCallback, this); else renderAction->setPassCallback(NULL, NULL); } //////////////////////////////////////////////////////////////////////// // // Description: // Gets antialiasing on GL rendering action. // // use: public // void SoSceneManager::getAntialiasing(SbBool &smoothing, int &numPasses) const // //////////////////////////////////////////////////////////////////////// { smoothing = renderAction->isSmoothing(); numPasses = renderAction->getNumPasses(); } //////////////////////////////////////////////////////////////////////// // // This routine is called to render the scene graph. // A window MUST be set before this is called. // // use: public // void SoSceneManager::render(SbBool clearWindow, SbBool clearZbuffer) // //////////////////////////////////////////////////////////////////////// { // reinitialize if necessary if (graphicsInitNeeded) { int numBits[1]; glGetIntegerv(GL_DEPTH_BITS, numBits); needZbuffer = (numBits[0] != 0); // FALSE for overlay windows ! if (needZbuffer) glDepthFunc(GL_LEQUAL); // needed for hidden line rendering graphicsInitNeeded = FALSE; } // // when the window changes size, we need to call glViewport() before // we can do a color clear. // if (needToSendVP) { const SbViewportRegion &theRegion = renderAction->getViewportRegion(); SbVec2s size = theRegion.getViewportSizePixels(); SbVec2s origin = theRegion.getViewportOriginPixels(); glViewport(origin[0], origin[1], size[0], size[1]); needToSendVP = FALSE; } // // clear to the background color and clear the zbuffer // if (clearWindow) { if (rgbMode) glClearColor(bkgColor[0], bkgColor[1], bkgColor[2], 0); else glClearIndex(bkgIndex); // clear the color+zbuffer at the same time if we can if (needZbuffer && clearZbuffer) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); else glClear(GL_COLOR_BUFFER_BIT); } // check to see if only the zbuffer is needed... else if (needZbuffer && clearZbuffer) glClear(GL_DEPTH_BUFFER_BIT); // render the scene graph! if (scene != NULL) renderAction->apply(scene); // sensor doesn't need to fire again if it's still scheduled sceneSensor->unschedule(); // schedule the realTime One shot sensor to update the real time // as soon as we can now that we have rendered the scene. This will // enable us to render things that are animating with a consistent // time across mutiple renderAreas, while providing the maximum // optainable frame rate (much better than a hard coded 30 or 60 // times/sec timer sensor). if (updateRealTime) realTimeSensor->schedule(); } //////////////////////////////////////////////////////////////////////// // // Description: // Callback to update the realTime global field. // // Use: static private void SoSceneManager::realTimeSensorCB() // //////////////////////////////////////////////////////////////////////// { realTime->setValue(SbTime::getTimeOfDay()); } //////////////////////////////////////////////////////////////////////// // // Description: // Enables/Disable the realTime update after each redraw // // Use: static public void SoSceneManager::enableRealTimeUpdate(SbBool flag) // //////////////////////////////////////////////////////////////////////// { if (updateRealTime == flag) return; updateRealTime = flag; if (updateRealTime) realTimeSensor->schedule(); else realTimeSensor->unschedule(); } //////////////////////////////////////////////////////////////////////// // // The scene manager will only employ sensors while it is active. // // use: public, virtual // void SoSceneManager::activate() { // attach sceneSensor to top node for redrawing purpose // only if the user has specified a redraw callback (i.e. // auto-redraw is enabled) if (renderCB != NULL) { if (scene != NULL && sceneSensor->getAttachedNode() == NULL) { sceneSensor->setFunction((SoSensorCB *) &SoSceneManager::sceneSensorCallback); sceneSensor->attach(scene); } } active = TRUE; } void SoSceneManager::deactivate() { sceneSensor->detach(); sceneSensor->setFunction(NULL); active = FALSE; } //////////////////////////////////////////////////////////////////////// // // Set the rendering callback. The app can supply this to enable // automatic redrawing of the scene. This callback should perform // window specific graphics initialization, then call the scene manager // render() method. // // use: public // void SoSceneManager::setRenderCallback( SoSceneManagerRenderCB *f, void *userData) // //////////////////////////////////////////////////////////////////////// { renderCB = f; renderCBData = userData; if (f != NULL) { // if we are active, attach the scene sensor if (active) { if (scene != NULL && sceneSensor->getAttachedNode() == NULL) { sceneSensor->setFunction((SoSensorCB *) &SoSceneManager::sceneSensorCallback); sceneSensor->attach(scene); } } } else { // detach the scene sensor (whether active or not) sceneSensor->detach(); sceneSensor->setFunction(NULL); } } //////////////////////////////////////////////////////////////////////// // // Priority of the redraw sensor // // public // void SoSceneManager::setRedrawPriority(uint32_t priority) // //////////////////////////////////////////////////////////////////////// { sceneSensor->setPriority(priority); } //////////////////////////////////////////////////////////////////////// // // Priority of the redraw sensor // // public // uint32_t SoSceneManager::getRedrawPriority() const // //////////////////////////////////////////////////////////////////////// { return sceneSensor->getPriority(); } // //////////////////////////////////////////////////////////////////////// // static callbacks stubs //////////////////////////////////////////////////////////////////////// // void SoSceneManager::antialiasingCallback( void *r ) { SoSceneManager *mgr = (SoSceneManager *) r; if (mgr->rgbMode) glClearColor(mgr->bkgColor[0], mgr->bkgColor[1], mgr->bkgColor[2], 0); else glClearIndex( mgr->bkgIndex ); glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); } void SoSceneManager::sceneSensorCallback(SoSceneManager *mgr, SoSensor *) { #ifdef DEBUG if (mgr->renderCB == NULL) { SoDebugError::post("SoSceneManager::sceneSensorCallback", "Callback was fired, but auto-redraw is turned off."); return; } if (! mgr->isActive()) { SoDebugError::post("SoSceneManager::sceneSensorCallback", "Callback was fired, but scene manager not active."); return; } #endif // redraw that scene graph! mgr->redraw(); } // //////////////////////////////////////////////////////////////////////// // real short methods //////////////////////////////////////////////////////////////////////// // void SoSceneManager::redraw() { if (renderCB != NULL) (*renderCB)(renderCBData, this); } void SoSceneManager::scheduleRedraw() { // The sceneSensor will only schedule itself if a CB func is set. // We only set the sensor CB func if autoRedraw is on and we are active. // Thus, there are no flags to check here. Just call schedule, and // the sensor will do the right thing. sceneSensor->schedule(); } void SoSceneManager::setBackgroundColor(const SbColor &c) { bkgColor = c; if (isRGBMode()) scheduleRedraw(); } void SoSceneManager::setBackgroundIndex(int index) { bkgIndex = index; if (! isRGBMode()) scheduleRedraw(); }