/* -*-c++-*- Present3D - Copyright (C) 1999-2006 Robert Osfield * * This software is open source and may be redistributed and/or modified under * the terms of the GNU General Public License (GPL) version 2.0. * The full license is in LICENSE.txt file included with this distribution,. * * This software 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 * include LICENSE.txt for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace osgPresentation; #define USE_CLIENT_STORAGE_HINT 0 class SetToTransparentBin : public osg::NodeVisitor { public: SetToTransparentBin(): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {} virtual void appply(osg::Node& node) { if (node.getStateSet()) { node.getStateSet()->setMode(GL_BLEND,osg::StateAttribute::ON); node.getStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); } } virtual void apply(osg::Geode& geode) { if (geode.getStateSet()) { geode.getStateSet()->setMode(GL_BLEND,osg::StateAttribute::ON); geode.getStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); } for(unsigned int i=0;igetStateSet()) { geode.getDrawable(i)->getStateSet()->setMode(GL_BLEND,osg::StateAttribute::ON); geode.getDrawable(i)->getStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); } } } }; HUDTransform::HUDTransform(HUDSettings* hudSettings): _hudSettings(hudSettings) { setDataVariance(osg::Object::DYNAMIC); setReferenceFrame(osg::Transform::ABSOLUTE_RF); } HUDTransform::~HUDTransform() {} bool HUDTransform::computeLocalToWorldMatrix(osg::Matrix& matrix,osg::NodeVisitor* nv) const { return _hudSettings->getModelViewMatrix(matrix,nv); } bool HUDTransform::computeWorldToLocalMatrix(osg::Matrix& matrix,osg::NodeVisitor* nv) const { return _hudSettings->getInverseModelViewMatrix(matrix,nv); } SlideShowConstructor::SlideShowConstructor(osgDB::Options* options): _options(options) { const osg::DisplaySettings* ds = osg::DisplaySettings::instance().get(); _propertyManager = new osgPresentation::PropertyManager; _propertyEventCallback = new osgPresentation::PropertyEventCallback(_propertyManager.get()); _slideHeight = ds->getScreenHeight(); _slideWidth = ds->getScreenWidth(); _slideDistance = ds->getScreenDistance(); _leftEyeMask = 0x01; _rightEyeMask = 0x02; _hudSettings = new HUDSettings(_slideDistance, ds->getEyeSeparation()*0.5, _leftEyeMask, _rightEyeMask); _backgroundColor.set(0.0f,0.0f,0.0f,0.0f); _presentationDuration = -1.0; // set up title defaults _titleFontDataDefault.font = "fonts/arial.ttf"; _titleFontDataDefault.color.set(1.0f,1.0f,1.0f,1.0f); _titleFontDataDefault.layout =osgText::Text::LEFT_TO_RIGHT; _titleFontDataDefault.alignment = osgText::Text::CENTER_BASE_LINE; _titleFontDataDefault.axisAlignment = osgText::Text::XZ_PLANE; _titleFontDataDefault.characterSize = 0.06f; _titleFontDataDefault.maximumWidth = 0.9f; _titlePositionDataDefault.position.set(0.5f,0.92f,0.0f); // set up text defaults _textFontDataDefault.font = "fonts/arial.ttf"; _textFontDataDefault.color.set(1.0f,1.0f,1.0f,1.0f); _textFontDataDefault.layout = osgText::Text::LEFT_TO_RIGHT; _textFontDataDefault.alignment = osgText::Text::LEFT_BASE_LINE; _textFontDataDefault.axisAlignment = osgText::Text::XZ_PLANE; _textFontDataDefault.characterSize = 0.04f; _textFontDataDefault.maximumWidth = 0.8f; _textPositionDataDefault.position.set(0.1f,0.85f,0.0f); _loopPresentation = false; _autoSteppingActive = false; _slideBackgroundAsHUD = false; _layerToApplyEventCallbackTo = 0; _currentEventCallbacksToApply.clear(); } void SlideShowConstructor::setPresentationAspectRatio(float aspectRatio) { _slideWidth = _slideHeight*aspectRatio; } void SlideShowConstructor::setPresentationAspectRatio(const std::string& str) { if (str=="Reality Theatre") setPresentationAspectRatio(3.0f); else if (str=="Desktop") setPresentationAspectRatio(1280.0f/1024.0f); else { float ratio = (float)atof(str.c_str()); if (ratio!=0.0) setPresentationAspectRatio(1280.0f/1024.0f); else { OSG_WARN<<"Error: presentation aspect ratio incorrect type"<addChild(_presentationSwitch.get()); _root->setName(std::string("Presentation_")+_presentationName); osg::Vec3 slideCenter = _slideOrigin + osg::Vec3(_slideWidth*0.5f,0.0f,_slideHeight*0.5f); HomePosition* hp = new HomePosition; hp->eye.set(0.0f,0.0f,0.0f); hp->center = slideCenter; hp->up.set(0.0f,0.0f,1.0f); OSG_INFO<<" slideCenter "<=0.0) { setDuration(_presentationSwitch.get(),_presentationDuration); } _root->setUserData(hp); if (_loopPresentation) _root->addDescription("loop"); if (_autoSteppingActive) _root->addDescription("auto"); //_root->addEventCallback(_propertyEventCallback.get()); _presentationSwitch->setEventCallback(_propertyEventCallback.get()); for(ScriptEngineMap::iterator itr = _scriptEngines.begin(); itr != _scriptEngines.end(); ++itr) { OSG_NOTICE<<"Assigning '"<first<<"' ScriptEngine to Presentation in createPresentation()."<getOrCreateUserDataContainer()->addUserObject(itr->second.get()); } } LayerAttributes* SlideShowConstructor::getOrCreateLayerAttributes(osg::Node* node) { LayerAttributes* la = dynamic_cast(node->getUserData()); if (!la) { if (node->getUserData()) { OSG_NOTICE<<"UserData already assigned, overriding to set LayerAttributes."<setUserData(la); } return la; } void SlideShowConstructor::setBackgroundColor(const osg::Vec4& color, bool updateClearNode) { _backgroundColor = color; if (updateClearNode && _slideClearNode.valid()) _slideClearNode->setClearColor(_backgroundColor); } void SlideShowConstructor::setTextColor(const osg::Vec4& color) { _titleFontDataDefault.color = color; _textFontDataDefault.color = color; _titleFontData.color = _titleFontDataDefault.color; _textFontData.color = _textFontDataDefault.color; } void SlideShowConstructor::setPresentationName(const std::string& name) { _presentationName = name; if (_presentationSwitch.valid()) _presentationSwitch->setName(std::string("Presentation_")+_presentationName); } void SlideShowConstructor::setPresentationDuration(double duration) { _presentationDuration = duration; if (_presentationDuration>=0.0 && _presentationSwitch.valid()) { setDuration(_presentationSwitch.get(),_presentationDuration); } } osg::ScriptEngine* SlideShowConstructor::getOrCreateScriptEngine(const std::string& language) { ScriptEngineMap::iterator itr = _scriptEngines.find(language); if (itr==_scriptEngines.end()) { addScriptEngine(language); itr = _scriptEngines.find(language); } return (itr!=_scriptEngines.end()) ? itr->second.get() : 0; } void SlideShowConstructor::addScriptEngine(const std::string& scriptEngineName) { if (_scriptEngines.count(scriptEngineName)!=0) { OSG_NOTICE<<"Script engine "< scriptEngine = osgDB::readRefFile(std::string("ScriptEngine.")+scriptEngineName); if (scriptEngine.valid()) { _scriptEngines[scriptEngineName] = scriptEngine; if (_presentationSwitch.valid()) { _presentationSwitch->getOrCreateUserDataContainer()->addUserObject(scriptEngine.get()); } } else { OSG_NOTICE<<"Warning: Failed to load "<setClearColor(_backgroundColor); _slideClearNode->addChild(_slide.get()); _presentationSwitch->addChild(_slideClearNode.get()); _previousLayer = 0; _currentLayer = 0; _filePathData = new FilePathData(osgDB::getDataFilePathList()); _slideClearNode->setUserData(_filePathData.get()); } void SlideShowConstructor::selectSlide(int slideNum) { if (slideNum<0) { addSlide(); } else if (slideNum>=static_cast(_presentationSwitch->getNumChildren())) { addSlide(); } else { _slideClearNode = dynamic_cast(_presentationSwitch->getChild(slideNum)); if (!_slideClearNode || _slideClearNode->getNumChildren()==0 || _slideClearNode->getChild(0)->asSwitch()==0) { addSlide(); } else { _slide = _slideClearNode->getChild(0)->asSwitch(); _previousLayer = _slide->getChild(_slide->getNumChildren()-1)->asGroup(); _currentLayer = 0; } } } void SlideShowConstructor::setSlideDuration(double duration) { if (!_slide) addSlide(); if (_slide.valid()) { setDuration(_slide.get(),duration); } } void SlideShowConstructor::pushCurrentLayer(osg::Group* group) { if (_currentLayer.valid()) { _currentLayer->addChild(group); _layerStack.push_back(_currentLayer.get()); } _currentLayer = group; } void SlideShowConstructor::popCurrentLayer() { if (!_layerStack.empty()) { _currentLayer = _layerStack.back(); _layerStack.pop_back(); } else { _currentLayer = 0; } } void SlideShowConstructor::addLayer(bool inheritPreviousLayers, bool defineAsBaseLayer) { if (!_slide) addSlide(); _currentLayer = new osg::Group; _currentLayer->setName("Layer"); // OSG_NOTICE<<"addLayer"<setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); } else { osg::Texture2D* texture = new osg::Texture2D(image.get()); texture->setResizeNonPowerOfTwoHint(false); texture->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINEAR); texture->setFilter(osg::Texture::MAG_FILTER,osg::Texture::LINEAR); #if USE_CLIENT_STORAGE_HINT texture->setClientStorageHint(true); #endif backgroundStateSet->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); } background->addDrawable(backgroundQuad); if (_slideBackgroundAsHUD) { HUDTransform* hudTransform = new HUDTransform(_hudSettings.get()); hudTransform->addChild(background); addToCurrentLayer(hudTransform); } else { addToCurrentLayer(background); } } if (!_slideTitle.empty()) { osg::Geode* geode = new osg::Geode; osg::Vec3 localPosition = computePositionInModelCoords(_titlePositionData); osgText::Text* text = new osgText::Text; text->setFont(osgText::readRefFontFile(_titleFontData.font, _options.get())); text->setColor(_titleFontData.color); text->setCharacterSize(_titleFontData.characterSize*_slideHeight); text->setFontResolution(110,120); text->setMaximumWidth(_titleFontData.maximumWidth*_slideWidth); text->setLayout(_titleFontData.layout); text->setAlignment(_titleFontData.alignment); text->setAxisAlignment(_titleFontData.axisAlignment); //text->setPosition(_titlePositionData.position); text->setPosition(localPosition); text->setText(_slideTitle); geode->addDrawable(text); addToCurrentLayer(decorateSubgraphForPosition(geode, _titlePositionData)); } } else { // copy previous layer's children across into new layer. for(unsigned int i=0;i<_previousLayer->getNumChildren();++i) { addToCurrentLayer(_previousLayer->getChild(i)); } } if (!defineAsBaseLayer) { _slide->addChild(_currentLayer.get()); } _previousLayer = _currentLayer; } void SlideShowConstructor::selectLayer(int layerNum) { if (!_slide) { addSlide(); addLayer(); } else if (layerNum>=0 && layerNum(_slide->getNumChildren()) && _slide->getChild(layerNum)->asGroup()) { _currentLayer = _slide->getChild(layerNum)->asGroup(); _previousLayer = _currentLayer; } else { addLayer(); } } void SlideShowConstructor::setLayerDuration(double duration) { if (!_currentLayer) addLayer(); if (_currentLayer.valid()) { setDuration(_currentLayer.get(),duration); } } void SlideShowConstructor::addToCurrentLayer(osg::Node* subgraph) { if (!subgraph) return; if (!_currentLayer) addLayer(); if (!_currentEventCallbacksToApply.empty()) { if (_layerToApplyEventCallbackTo==0 || _currentLayer==_layerToApplyEventCallbackTo) { OSG_INFO<<"Assigning event callbacks."<addEventCallback(itr->get()); } } else { OSG_INFO<<"Ignoring event callback from previous layer."<addChild(subgraph); } void SlideShowConstructor::addEventHandler(PresentationContext presentationContext, osg::ref_ptr handler) { switch(presentationContext) { case(CURRENT_PRESENTATION): OSG_NOTICE<<"Need to add event handler to presentation."<addUpdateCallback(propertyAnimation); break; case(CURRENT_SLIDE): OSG_NOTICE<<"Need to add PropertyAnimation to slide."<addUpdateCallback(propertyAnimation); break; case(CURRENT_LAYER): OSG_NOTICE<<"Need to add PropertyAnimation to layer."<addUpdateCallback(propertyAnimation); } break; } } void SlideShowConstructor::addScriptCallback(PresentationContext presentationContext, ScriptCallbackType scriptCallbackType, const std::string& name) { switch(presentationContext) { case(CURRENT_PRESENTATION): OSG_NOTICE<<" Adding ScriptCallback to presentation."<addUpdateCallback(new osg::ScriptNodeCallback(script_itr->second.get(), entry_point)); break; case(EVENT_SCRIPT) : node->addEventCallback(new osg::ScriptNodeCallback(script_itr->second.get(), entry_point)); break; } } else { OSG_NOTICE<<"Warning: script '"<first, itr->second, node); } } osg::Node* SlideShowConstructor::decorateSubgraphForPosition(osg::Node* node, PositionData& positionData) { osg::Node* subgraph = node; if (positionData.requiresMaterialAnimation()) { subgraph = attachMaterialAnimation(subgraph,positionData); } if (positionData.rotation[0]!=0.0) { osg::MatrixTransform* animation_transform = new osg::MatrixTransform; animation_transform->setDataVariance(osg::Object::DYNAMIC); animation_transform->setUpdateCallback( new osgUtil::TransformCallback(subgraph->getBound().center(), osg::Vec3(positionData.rotation[1],positionData.rotation[2],positionData.rotation[3]), osg::DegreesToRadians(positionData.rotation[0]))); animation_transform->addChild(subgraph); subgraph = animation_transform; } if (positionData.hud) { HUDTransform* hudTransform = new HUDTransform(_hudSettings.get()); hudTransform->addChild(subgraph); subgraph = hudTransform; } return subgraph; } void SlideShowConstructor::addBullet(const std::string& bullet, PositionData& positionData, FontData& fontData, const ScriptData& scriptData) { osg::Geode* geode = new osg::Geode; osgText::Text* text = new osgText::Text; osg::Vec3 localPosition = computePositionInModelCoords(positionData); text->setFont(osgText::readRefFontFile(fontData.font, _options.get())); text->setColor(fontData.color); text->setCharacterSize(fontData.characterSize*_slideHeight); text->setCharacterSizeMode(fontData.characterSizeMode); text->setFontResolution(110,120); text->setMaximumWidth(fontData.maximumWidth*_slideWidth); text->setLayout(fontData.layout); text->setAlignment(fontData.alignment); text->setAxisAlignment(fontData.axisAlignment); text->setPosition(localPosition); if (positionData.autoRotate) { text->setAxisAlignment(osgText::Text::SCREEN); } if (positionData.autoScale) { text->setCharacterSizeMode(osgText::Text::SCREEN_COORDS); } text->setText(bullet); const osg::BoundingBox& bb = text->getBoundingBox(); // note, this increment is only "correct" when text is on the plane of the slide.. // will need to make this more general later. localPosition.z() = bb.zMin()-fontData.characterSize*_slideHeight*1.5; geode->addDrawable(text); addToCurrentLayer( decorateSubgraphForPosition(geode, positionData) ); bool needToApplyPosition = (_textPositionData.position == positionData.position); if (needToApplyPosition) { updatePositionFromInModelCoords(localPosition, _textPositionData); } if (scriptData.hasScripts()) addScriptsToNode(scriptData, geode); } void SlideShowConstructor::addParagraph(const std::string& paragraph, PositionData& positionData, FontData& fontData, const ScriptData& scriptData) { osg::Geode* geode = new osg::Geode; osg::Vec3 localPosition = computePositionInModelCoords(positionData); osgText::Text* text = new osgText::Text; text->setFont(osgText::readRefFontFile(fontData.font, _options.get())); text->setColor(fontData.color); text->setCharacterSize(fontData.characterSize*_slideHeight); text->setCharacterSizeMode(fontData.characterSizeMode); text->setFontResolution(110,120); text->setMaximumWidth(fontData.maximumWidth*_slideWidth); text->setLayout(fontData.layout); text->setAlignment(fontData.alignment); text->setAxisAlignment(fontData.axisAlignment); text->setPosition(localPosition); if (positionData.autoRotate) { text->setAxisAlignment(osgText::Text::SCREEN); } if (positionData.autoScale) { text->setCharacterSizeMode(osgText::Text::SCREEN_COORDS); } text->setText(paragraph); const osg::BoundingBox& bb = text->getBoundingBox(); // note, this increment is only "correct" when text is on the plane of the slide.. // will need to make this more general later. localPosition.z() = bb.zMin()-fontData.characterSize*_slideHeight*1.5; geode->addDrawable(text); addToCurrentLayer( decorateSubgraphForPosition(geode, positionData) ); bool needToApplyPosition = (_textPositionData.position == positionData.position); if (needToApplyPosition) { updatePositionFromInModelCoords(localPosition, _textPositionData); } if (scriptData.hasScripts()) addScriptsToNode(scriptData, geode); } class FindImageStreamsVisitor : public osg::NodeVisitor { public: FindImageStreamsVisitor(): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {} virtual void apply(osg::Node& node) { if (node.getStateSet()) { process(node.getStateSet()); } traverse(node); } virtual void apply(osg::Geode& node) { if (node.getStateSet()) { process(node.getStateSet()); } for(unsigned int i=0;igetStateSet()) { process(drawable->getStateSet()); } } } void process(osg::StateSet* ss) { for(unsigned int i=0;igetTextureAttributeList().size();++i) { osg::Texture* texture = dynamic_cast(ss->getTextureAttribute(i,osg::StateAttribute::TEXTURE)); osg::Image* image = texture ? texture->getImage(0) : 0; osg::ImageStream* imageStream = image ? dynamic_cast(image) : 0; if (imageStream) { texture->setDataVariance(osg::Object::DYNAMIC); texture->setUnRefImageDataAfterApply(false); texture->setResizeNonPowerOfTwoHint(false); texture->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINEAR); texture->setFilter(osg::Texture::MAG_FILTER,osg::Texture::LINEAR); #if USE_CLIENT_STORAGE_HINT texture->setClientStorageHint(true); #endif } } } }; void SlideShowConstructor::findImageStreamsAndAddCallbacks(osg::Node* node) { FindImageStreamsVisitor fisv; node->accept(fisv); } osg::Geometry* SlideShowConstructor::createTexturedQuadGeometry(const osg::Vec3& pos, const osg::Vec4& rotation, float width, float height, osg::Image* image, bool& usedTextureRectangle) { osg::Geometry* pictureQuad = 0; osg::ref_ptr texture = 0; osg::StateSet* stateset = 0; osg::Vec3 positionVec = pos; osg::Vec3 widthVec(width,0.0f,0.0f); osg::Vec3 heightVec(0.0f,0.0f,height); osg::Matrixd rotationMatrix = osg::Matrixd::rotate(osg::DegreesToRadians(rotation[0]),rotation[1],rotation[2],rotation[3]); widthVec = widthVec*rotationMatrix; heightVec = heightVec*rotationMatrix; osg::ImageStream* imageStream = dynamic_cast(image); // let the video-plugin create a texture for us, if supported if(imageStream && getenv("P3D_ENABLE_CORE_VIDEO")) { texture = imageStream->createSuitableTexture(); } bool flipYAxis = image->getOrigin()==osg::Image::TOP_LEFT; #if 1 bool useTextureRectangle = false; #else #ifdef __sgi bool useTextureRectangle = false; #else bool useTextureRectangle = true; #endif #endif // pass back info on wether texture 2D is used. usedTextureRectangle = useTextureRectangle; if (!texture) { if (useTextureRectangle) { texture = new osg::TextureRectangle(image); } else { texture = new osg::Texture2D(image); texture->setResizeNonPowerOfTwoHint(false); texture->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINEAR); texture->setFilter(osg::Texture::MAG_FILTER,osg::Texture::LINEAR); #if USE_CLIENT_STORAGE_HINT texture->setClientStorageHint(true); #endif } } if (texture) { float l = 0.0f; float b = 0.0f; float r = (texture->getTextureTarget() == GL_TEXTURE_RECTANGLE) ? static_cast(image->s()) : 1.0f; float t = (texture->getTextureTarget() == GL_TEXTURE_RECTANGLE) ? static_cast(image->t()) : 1.0f; if (flipYAxis) std::swap(t,b); pictureQuad = osg::createTexturedQuadGeometry(positionVec, widthVec, heightVec, l, b, r, t); stateset = pictureQuad->getOrCreateStateSet(); stateset->setTextureAttributeAndModes(0, texture.get(), osg::StateAttribute::ON); } if (!pictureQuad) return 0; if (imageStream) { imageStream->pause(); OSG_INFO<<"Reading video "<getFileName()<setClientStorageHint(true); #endif } return pictureQuad; } osg::ref_ptr SlideShowConstructor::readImage(const std::string& filename, const ImageData& imageData) { osg::ref_ptr options = _options; if (!imageData.options.empty()) { options = _options->cloneOptions(); options->setOptionString(imageData.options); } osg::ref_ptr image; osgDB::DirectoryContents filenames; if (imageData.imageSequence) { // check for wild cards if (filename.find('*')!=std::string::npos) { OSG_INFO<<"Expanding wildcard "< imageSequence = new osg::ImageSequence; imageSequence->setMode(imageData.imageSequencePagingMode); bool firstLoad = true; for(osgDB::DirectoryContents::iterator itr = filenames.begin(); itr != filenames.end(); ++itr) { if (imageSequence->getMode()==osg::ImageSequence::PRE_LOAD_ALL_IMAGES) { OSG_INFO<<"Attempting to read "<<*itr< loadedImage = osgDB::readRefImageFile(*itr, options.get()); if (loadedImage.valid()) { OSG_INFO<<"Loaded image "<<*itr<addImage(loadedImage.get()); } } else { OSG_INFO<<"Adding filename for load image on demand "<<*itr<addImageFile(*itr); if (firstLoad) { osg::ref_ptr loadedImage = osgDB::readRefImageFile(*itr, options.get()); if (loadedImage.valid()) { imageSequence->addImage(loadedImage.get()); firstLoad = false; } } } } #if 0 if (imageSequence->getMode()==osg::ImageSequence::PAGE_AND_DISCARD_USED_IMAGES) { if (_options.valid()) { OSG_NOTICE<<"Object cache usage _options "<getObjectCacheHint()< options = _options.valid() ? _options->cloneOptions() : (new osgDB::Options); if (!imageData.options.empty()) { options->setOptionString(imageData.options); } OSG_NOTICE<<"Disabling object cache usage"<setObjectCacheHint(osgDB::Options::CACHE_NONE); imageSequence->setReadOptions(options); } #endif if (imageData.duration>0.0) { imageSequence->setLength(imageData.duration); } else { unsigned int maxNum = imageSequence->getNumImageData(); imageSequence->setLength(double(maxNum)*(1.0/imageData.fps)); } if (imageData.imageSequenceInteractionMode==ImageData::USE_MOUSE_X_POSITION) { imageSequence->setName("USE_MOUSE_X_POSITION"); } else if (imageData.imageSequenceInteractionMode==ImageData::USE_MOUSE_Y_POSITION) { imageSequence->setName("USE_MOUSE_Y_POSITION"); } imageSequence->play(); image = imageSequence; } if (image.valid()) { if (imageData.delayTime>0.0) image->setUserValue("delay",imageData.delayTime); if (imageData.startTime>0.0) image->setUserValue("start",imageData.startTime); if (imageData.stopTime>0.0) image->setUserValue("stop",imageData.stopTime); } else { OSG_NOTICE<<"Could not load image file: "<getNodePath(), _source); float volume=0.0f; pr>>volume; if (pr.ok()) { OSG_NOTICE<<"VolumeCallback : volume="<setVolume(volume); } else { OSG_NOTICE<<"Problem in reading, VolumeCallback : volume="< _movie; std::string _source; }; void SlideShowConstructor::setUpMovieVolume(osg::Node* subgraph, osg::ImageStream* imageStream, const ImageData& imageData) { if (containsPropertyReference(imageData.volume)) { subgraph->addUpdateCallback(new VolumeCallback(imageStream, imageData.volume)); } else { float volume; std::istringstream sstream(imageData.volume); sstream>>volume; if (!sstream.fail()) { OSG_NOTICE<<"Setting volume "<setVolume( volume ); } else { OSG_NOTICE<<"Invalid volume setting: "< image = readImage(filename, imageData); if (!image) return; bool isImageTranslucent = false; osg::ImageStream* imageStream = dynamic_cast(image.get()); if (imageStream) { imageStream->setLoopingMode(imageData.loopingMode); isImageTranslucent = imageStream->getPixelFormat()==GL_RGBA || imageStream->getPixelFormat()==GL_BGRA; } else { isImageTranslucent = image->isImageTranslucent(); } if (imageData.blendingHint==ImageData::ON) { isImageTranslucent = true; } else if (imageData.blendingHint==ImageData::OFF) { isImageTranslucent = false; } float s = image->s(); float t = image->t(); float sx = imageData.region_in_pixel_coords ? 1.0f : s; float sy = imageData.region_in_pixel_coords ? 1.0f : t; float x1 = imageData.region[0]*sx; float y1 = imageData.region[1]*sy; float x2 = imageData.region[2]*sx; float y2 = imageData.region[3]*sy; float aspectRatio = (y2-y1)/(x2-x1); float image_width = _slideWidth*positionData.scale.x(); float image_height = image_width*aspectRatio*positionData.scale.y()/positionData.scale.x(); float offset = 0.0f; osg::Vec3 pos = computePositionInModelCoords(positionData); osg::Vec3 image_local_pos = osg::Vec3(-image_width*0.5f+offset,-offset,-image_height*0.5f-offset); osg::Vec3 image_pos = positionData.autoRotate ? image_local_pos : (pos+image_local_pos); bool usedTextureRectangle = false; osg::Geometry* pictureQuad = createTexturedQuadGeometry(image_pos, positionData.rotate, image_width, image_height, image.get(), usedTextureRectangle); osg::StateSet* pictureStateSet = pictureQuad->getOrCreateStateSet(); attachTexMat(pictureStateSet, imageData, s, t, usedTextureRectangle); osg::Node* subgraph = 0; if (positionData.autoRotate) { osg::Billboard* picture = new osg::Billboard; picture->setMode(osg::Billboard::POINT_ROT_EYE); picture->setNormal(osg::Vec3(0.0f,-1.0f,0.0f)); picture->setAxis(osg::Vec3(0.0f,0.0f,1.0f)); picture->addDrawable(pictureQuad,pos); subgraph = picture; } else { osg::Geode* picture = new osg::Geode; picture->addDrawable(pictureQuad); subgraph = picture; } // attach any meterial animation. if (positionData.requiresMaterialAnimation()) subgraph = attachMaterialAnimation(subgraph,positionData); if (isImageTranslucent) { SetToTransparentBin sttb; subgraph->accept(sttb); pictureStateSet->setMode(GL_BLEND, osg::StateAttribute::ON); } if (imageStream && !imageData.volume.empty()) { setUpMovieVolume(subgraph, imageStream, imageData); } osg::ImageSequence* imageSequence = dynamic_cast(image.get()); if (imageSequence) { if (imageData.imageSequenceInteractionMode==ImageData::USE_MOUSE_X_POSITION) { subgraph->setUpdateCallback(new osgPresentation::ImageSequenceUpdateCallback(imageSequence, _propertyManager.get(), "mouse.x_normalized")); } else if (imageData.imageSequenceInteractionMode==ImageData::USE_MOUSE_Y_POSITION) { subgraph->setUpdateCallback(new osgPresentation::ImageSequenceUpdateCallback(imageSequence, _propertyManager.get(), "mouse.y_normalized")); } } // attached any rotation if (positionData.rotation[0]!=0.0) { osg::MatrixTransform* animation_transform = new osg::MatrixTransform; animation_transform->setDataVariance(osg::Object::DYNAMIC); animation_transform->setUpdateCallback( new osgUtil::TransformCallback(subgraph->getBound().center(), osg::Vec3(positionData.rotation[1],positionData.rotation[2],positionData.rotation[3]), osg::DegreesToRadians(positionData.rotation[0]))); animation_transform->addChild(subgraph); subgraph = animation_transform; } // attached any animation osg::AnimationPathCallback* animation = getAnimationPathCallback(positionData); if (animation) { OSG_INFO<<"Have animation path for image"<getBound().center(); osg::PositionAttitudeTransform* animation_transform = new osg::PositionAttitudeTransform; animation_transform->setDataVariance(osg::Object::DYNAMIC); animation_transform->setPivotPoint(pivot); animation->setPivotPoint(pivot); animation_transform->setUpdateCallback(animation); animation_transform->setReferenceFrame(positionData.absolute_path ? osg::Transform::ABSOLUTE_RF: osg::Transform::RELATIVE_RF); animation_transform->addChild(subgraph); subgraph = animation_transform; } if (positionData.hud) { HUDTransform* hudTransform = new HUDTransform(_hudSettings.get()); hudTransform->addChild(subgraph); subgraph = hudTransform; } addToCurrentLayer(subgraph); if (scriptData.hasScripts()) addScriptsToNode(scriptData, subgraph); } void SlideShowConstructor::addStereoImagePair(const std::string& filenameLeft, const ImageData& imageDataLeft, const std::string& filenameRight, const ImageData& imageDataRight,const PositionData& positionData, const ScriptData& scriptData) { osg::ref_ptr imageLeft = readImage(filenameLeft, imageDataLeft); osg::ref_ptr imageRight = (filenameRight==filenameLeft) ? imageLeft : readImage(filenameRight, imageDataRight); if (!imageLeft && !imageRight) return; bool isImageTranslucent = false; osg::ImageStream* imageStreamLeft = dynamic_cast(imageLeft.get()); if (imageStreamLeft) { imageStreamLeft->setLoopingMode(imageDataLeft.loopingMode); isImageTranslucent = imageStreamLeft->getPixelFormat()==GL_RGBA || imageStreamLeft->getPixelFormat()==GL_BGRA; } else { isImageTranslucent = imageLeft->isImageTranslucent(); } osg::ImageStream* imageStreamRight = dynamic_cast(imageRight.get()); if (imageStreamRight) { imageStreamRight->setLoopingMode(imageDataRight.loopingMode); if (!isImageTranslucent) { isImageTranslucent = imageStreamRight->getPixelFormat()==GL_RGBA || imageStreamRight->getPixelFormat()==GL_BGRA; } } else if (!isImageTranslucent) { isImageTranslucent = imageRight->isImageTranslucent(); } if (imageDataLeft.blendingHint==ImageData::ON || imageDataRight.blendingHint==ImageData::ON) { isImageTranslucent = true; } else if (imageDataLeft.blendingHint==ImageData::OFF || imageDataRight.blendingHint==ImageData::OFF) { isImageTranslucent = false; } float s = imageLeft->s(); float t = imageLeft->t(); float sx = imageDataLeft.region_in_pixel_coords ? 1.0f : s; float sy = imageDataLeft.region_in_pixel_coords ? 1.0f : t; float x1 = imageDataLeft.region[0]*sx; float y1 = imageDataLeft.region[1]*sy; float x2 = imageDataLeft.region[2]*sx; float y2 = imageDataLeft.region[3]*sy; float aspectRatio = (y2-y1)/(x2-x1); float image_width = _slideWidth*positionData.scale.x(); float image_height = image_width*aspectRatio*positionData.scale.y()/positionData.scale.x(); float offset = 0.0f; bool usedTextureRectangle = false; osg::Vec3 pos = computePositionInModelCoords(positionData); osg::Vec3 image_local_pos = osg::Vec3(-image_width*0.5f+offset,-offset,-image_height*0.5f-offset); osg::Vec3 image_pos = positionData.autoRotate ? image_local_pos : (pos+image_local_pos); osg::Node* pictureLeft = 0; { osg::Geometry* pictureLeftQuad = createTexturedQuadGeometry(image_pos, positionData.rotate, image_width,image_height,imageLeft.get(),usedTextureRectangle); osg::StateSet* pictureLeftStateSet = pictureLeftQuad->getOrCreateStateSet(); if (isImageTranslucent) { pictureLeftStateSet->setMode(GL_BLEND, osg::StateAttribute::ON); } attachTexMat(pictureLeftStateSet, imageDataLeft, s, t, usedTextureRectangle); if (positionData.autoRotate) { osg::Billboard* billboard = new osg::Billboard; billboard->setMode(osg::Billboard::POINT_ROT_EYE); billboard->setNormal(osg::Vec3(0.0f,-1.0f,0.0f)); billboard->setAxis(osg::Vec3(0.0f,0.0f,1.0f)); billboard->addDrawable(pictureLeftQuad,pos); pictureLeft = billboard; } else { osg::Geode* geode = new osg::Geode; geode->addDrawable(pictureLeftQuad); pictureLeft = geode; } pictureLeft->setNodeMask(_leftEyeMask); } osg::Node* pictureRight = 0; { osg::Geometry* pictureRightQuad = createTexturedQuadGeometry(image_pos, positionData.rotate, image_width,image_height,imageRight.get(),usedTextureRectangle); osg::StateSet* pictureRightStateSet = pictureRightQuad->getOrCreateStateSet(); if (isImageTranslucent) { pictureRightStateSet->setMode(GL_BLEND, osg::StateAttribute::ON); } attachTexMat(pictureRightStateSet, imageDataRight, s, t, usedTextureRectangle); if (positionData.autoRotate) { osg::Billboard* billboard = new osg::Billboard; billboard->setMode(osg::Billboard::POINT_ROT_EYE); billboard->setNormal(osg::Vec3(0.0f,-1.0f,0.0f)); billboard->setAxis(osg::Vec3(0.0f,0.0f,1.0f)); billboard->addDrawable(pictureRightQuad,pos); pictureRight = billboard; } else { osg::Geode* geode = new osg::Geode; geode->addDrawable(pictureRightQuad); pictureRight = geode; } pictureRight->setNodeMask(_rightEyeMask); } osg::Group* subgraph = new osg::Group; subgraph->addChild(pictureLeft); subgraph->addChild(pictureRight); if (imageStreamLeft && !imageDataLeft.volume.empty()) { setUpMovieVolume(subgraph, imageStreamLeft, imageDataLeft); } if (imageStreamRight && !imageDataRight.volume.empty()) { setUpMovieVolume(subgraph, imageStreamRight, imageDataRight); } osg::ImageSequence* imageSequence = dynamic_cast(imageLeft.get()); if (imageSequence) { if (imageDataLeft.imageSequenceInteractionMode==ImageData::USE_MOUSE_X_POSITION) { subgraph->setUpdateCallback(new osgPresentation::ImageSequenceUpdateCallback(imageSequence, _propertyManager.get(), "mouse.x_normalized")); } else if (imageDataLeft.imageSequenceInteractionMode==ImageData::USE_MOUSE_Y_POSITION) { subgraph->setUpdateCallback(new osgPresentation::ImageSequenceUpdateCallback(imageSequence, _propertyManager.get(), "mouse.y_normalized")); } } // attach any meterial animation. if (positionData.requiresMaterialAnimation()) subgraph = attachMaterialAnimation(subgraph,positionData)->asGroup(); if (isImageTranslucent) { SetToTransparentBin sttb; subgraph->accept(sttb); } // attached any rotation if (positionData.rotation[0]!=0.0) { osg::MatrixTransform* animation_transform = new osg::MatrixTransform; animation_transform->setDataVariance(osg::Object::DYNAMIC); animation_transform->setUpdateCallback( new osgUtil::TransformCallback(subgraph->getBound().center(), osg::Vec3(positionData.rotation[1],positionData.rotation[2],positionData.rotation[3]), osg::DegreesToRadians(positionData.rotation[0]))); animation_transform->addChild(subgraph); subgraph = animation_transform; } // attached any animation osg::AnimationPathCallback* animation = getAnimationPathCallback(positionData); if (animation) { OSG_INFO<<"Have animation path for image"<getBound().center(); osg::PositionAttitudeTransform* animation_transform = new osg::PositionAttitudeTransform; animation_transform->setDataVariance(osg::Object::DYNAMIC); animation_transform->setPivotPoint(pivot); animation->setPivotPoint(pivot); animation_transform->setUpdateCallback(animation); animation_transform->setReferenceFrame(positionData.absolute_path ? osg::Transform::ABSOLUTE_RF: osg::Transform::RELATIVE_RF); animation_transform->addChild(subgraph); subgraph = animation_transform; } if (positionData.hud) { HUDTransform* hudTransform = new HUDTransform(_hudSettings.get()); hudTransform->addChild(subgraph); subgraph = hudTransform; } addToCurrentLayer(subgraph); if (scriptData.hasScripts()) addScriptsToNode(scriptData, subgraph); } void SlideShowConstructor::addGraph(const std::string& contents, const PositionData& positionData, const ImageData& imageData, const ScriptData& scriptData) { static int s_count=0; if (contents.empty()) return; std::string tmpDirectory("/tmp/"); std::string filename = contents; std::string ext = osgDB::getFileExtension(contents); if (ext.empty()) { std::stringstream dotFileNameStream; dotFileNameStream << tmpDirectory<<"graph_"< model = osgDB::readRefNodeFile(filename, _options.get()); if (!model) return; dotFileName = tmpDirectory+osgDB::getStrippedName(filename)+std::string(".dot"); osg::ref_ptr opts = _options.valid() ? _options->cloneOptions() : (new osgDB::Options); if (!imageData.options.empty()) { opts->setOptionString(imageData.options); } opts->setObjectCacheHint(osgDB::Options::CACHE_NONE); osgDB::writeNodeFile(*model, dotFileName, opts.get()); } std::stringstream command; command<<"dot -Tsvg "< previousOptions = _options; // switch off cache so we make sure that we re-read the generated svg each time. _options = _options.valid() ? _options->cloneOptions() : (new osgDB::Options); _options->setObjectCacheHint(osgDB::Options::CACHE_NONE); addImage(tmpSvgFileName, positionData, imageData, scriptData); _options = previousOptions; ++s_count; } else OSG_NOTICE<<"Error: SlideShowConstructor::addGraph() system("<getAuthenticationMap()) osgDB::Registry::instance()->setAuthenticationMap(new osgDB::AuthenticationMap); osgDB::Registry::instance()->getAuthenticationMap()->addAuthenticationDetails(hostname, new osgDB::AuthenticationDetails("", password)); } addInteractiveImage(hostname+".vnc", positionData, imageData, scriptData); } void SlideShowConstructor::addBrowser(const std::string& url, const PositionData& positionData, const ImageData& imageData, const ScriptData& scriptData) { addInteractiveImage(url+".gecko", positionData, imageData, scriptData); } void SlideShowConstructor::addPDF(const std::string& filename, const PositionData& positionData, const ImageData& imageData, const ScriptData& scriptData) { addInteractiveImage(filename, positionData, imageData, scriptData); } class SetPageCallback: public LayerCallback { public: SetPageCallback(osgWidget::PdfImage* pdfImage, int pageNum): _pdfImage(pdfImage), _pageNum(pageNum) { } virtual void operator() (osg::Node*) const { OSG_INFO<<"PDF Page to be updated "<<_pageNum<getPageNum()!=_pageNum) { _pdfImage->page(_pageNum); } } osg::observer_ptr _pdfImage; int _pageNum; }; osg::ref_ptr SlideShowConstructor::addInteractiveImage(const std::string& filename, const PositionData& positionData, const ImageData& imageData, const ScriptData& scriptData) { osg::ref_ptr options = _options; if (!imageData.options.empty()) { options = _options->cloneOptions(); options->setOptionString(imageData.options); } osg::ref_ptr image = osgDB::readRefImageFile(filename, options.get()); OSG_INFO<<"addInteractiveImage("<s(); float t = image->t(); float sx = imageData.region_in_pixel_coords ? 1.0f : s; float sy = imageData.region_in_pixel_coords ? 1.0f : t; float x1 = imageData.region[0]*sx; float y1 = imageData.region[1]*sy; float x2 = imageData.region[2]*sx; float y2 = imageData.region[3]*sy; float aspectRatio = (y2-y1)/(x2-x1); float image_width = _slideWidth*positionData.scale.x(); float image_height = image_width*aspectRatio*positionData.scale.y()/positionData.scale.x(); float offset = 0.0f; osg::Vec3 pos = computePositionInModelCoords(positionData); osg::Vec3 image_local_pos = osg::Vec3(-image_width*0.5f+offset,-offset,-image_height*0.5f-offset); osg::Vec3 image_pos = positionData.autoRotate ? image_local_pos : (pos+image_local_pos); bool usedTextureRectangle = false; osg::Geometry* pictureQuad = createTexturedQuadGeometry(image_pos, positionData.rotate, image_width, image_height, image.get(), usedTextureRectangle); osg::ref_ptr handler = new osgViewer::InteractiveImageHandler(image.get()); pictureQuad->setEventCallback(handler.get()); pictureQuad->setCullCallback(handler.get()); osg::StateSet* pictureStateSet = pictureQuad->getOrCreateStateSet(); attachTexMat(pictureStateSet, imageData, s, t, usedTextureRectangle); pictureStateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF); osg::Node* subgraph = 0; if (positionData.autoRotate) { osg::Billboard* picture = new osg::Billboard; picture->setMode(osg::Billboard::POINT_ROT_EYE); picture->setNormal(osg::Vec3(0.0f,-1.0f,0.0f)); picture->setAxis(osg::Vec3(0.0f,0.0f,1.0f)); picture->addDrawable(pictureQuad,pos); subgraph = picture; } else { osg::Geode* picture = new osg::Geode; picture->addDrawable(pictureQuad); subgraph = picture; } // attach any meterial animation. if (positionData.requiresMaterialAnimation()) subgraph = attachMaterialAnimation(subgraph,positionData); // attached any rotation if (positionData.rotation[0]!=0.0) { osg::MatrixTransform* animation_transform = new osg::MatrixTransform; animation_transform->setDataVariance(osg::Object::DYNAMIC); animation_transform->setUpdateCallback( new osgUtil::TransformCallback(subgraph->getBound().center(), osg::Vec3(positionData.rotation[1],positionData.rotation[2],positionData.rotation[3]), osg::DegreesToRadians(positionData.rotation[0]))); animation_transform->addChild(subgraph); subgraph = animation_transform; } // attached any animation osg::AnimationPathCallback* animation = getAnimationPathCallback(positionData); if (animation) { OSG_INFO<<"Have animation path for image"<getBound().center(); osg::PositionAttitudeTransform* animation_transform = new osg::PositionAttitudeTransform; animation_transform->setDataVariance(osg::Object::DYNAMIC); animation_transform->setPivotPoint(pivot); animation->setPivotPoint(pivot); animation_transform->setUpdateCallback(animation); animation_transform->setReferenceFrame(positionData.absolute_path ? osg::Transform::ABSOLUTE_RF: osg::Transform::RELATIVE_RF); animation_transform->addChild(subgraph); subgraph = animation_transform; } if (positionData.hud) { HUDTransform* hudTransform = new HUDTransform(_hudSettings.get()); hudTransform->addChild(subgraph); subgraph = hudTransform; } addToCurrentLayer(subgraph); osgWidget::PdfImage* pdfImage = dynamic_cast(image.get()); if (pdfImage && imageData.page>=0) { getOrCreateLayerAttributes(_currentLayer.get())->addEnterCallback(new SetPageCallback(pdfImage, imageData.page)); OSG_INFO<<"Setting pdf page num "<setBackgroundColor(imageData.backgroundColor); pdfImage->page(imageData.page); if (imageData.backgroundColor.a()<1.0f) { SetToTransparentBin sttb; subgraph->accept(sttb); } } if (scriptData.hasScripts()) addScriptsToNode(scriptData, subgraph); return image; } std::string SlideShowConstructor::findFileAndRecordPath(const std::string& filename) { std::string foundFile = osgDB::findDataFile(filename, _options.get()); if (foundFile.empty()) return filename; OSG_INFO<<"foundFile "<filePathList.begin(),_filePathData->filePathList.end(),path); if (itr==_filePathData->filePathList.end()) { OSG_INFO<<"New path to record "<filePathList.push_front(path); } } return foundFile; } struct ClipRegionCallback : public osg::NodeCallback { public: ClipRegionCallback(const osg::Matrixd& originalMatrix, const std::string& str): _matrix(originalMatrix), _source(str) {} virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) { osg::MatrixTransform* transform = dynamic_cast(node); if (transform) { PropertyReader pr(nv->getNodePath(), _source); float xMin=0.0; float yMin=0.0; float zMin=0.0; float xMax=1.0; float yMax=1.0; float zMax=1.0; pr>>xMin>>yMin>>zMin>>xMax>>yMax>>zMax; if (pr.ok()) { OSG_NOTICE<<"ClipRegionCallback : xMin="< options = _options; if (!modelData.options.empty()) { options = _options->cloneOptions(); options->setOptionString(modelData.options); } osg::ref_ptr subgraph; if (filename=="sphere") { osg::Geode* geode = new osg::Geode; geode->addDrawable(new osg::ShapeDrawable(new osg::Sphere)); subgraph = geode; } else if (filename=="box") { osg::Geode* geode = new osg::Geode; geode->addDrawable(new osg::ShapeDrawable(new osg::Box)); subgraph = geode; } else { subgraph = osgDB::readRefNodeFile(filename, options.get()); if (subgraph) recordOptionsFilePath(options.get()); } if (!modelData.region.empty()) { osg::ref_ptr clipnode = new osg::ClipNode; clipnode->createClipBox(osg::BoundingBox(0.0,0.0,0.0,1.0,1.0,1.0),0); clipnode->setCullingActive(false); osg::ref_ptr transform = new osg::MatrixTransform; transform->addChild(clipnode.get()); osg::ref_ptr group = new osg::Group; group->addChild(subgraph.get()); group->addChild(transform.get()); //clipnode->setStateSetModes(*(group->getOrCreateStateSet()), osg::StateAttribute::ON); group->setStateSet(clipnode->getStateSet()); osg::ComputeBoundsVisitor cbbv(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN); subgraph->accept(cbbv); osg::BoundingBox bb = cbbv.getBoundingBox(); double width = bb.xMax()-bb.xMin(); double length = bb.yMax()-bb.yMin(); double height = bb.zMax()-bb.zMin(); osg::Matrixd matrix = osg::Matrixd::translate(-0.5,-0.5,-0.5)*osg::Matrixd::scale(width,length,height)*osg::Matrixd::translate(bb.center()); transform->setMatrix(matrix); if (containsPropertyReference(modelData.region)) { transform->addUpdateCallback(new ClipRegionCallback(matrix, modelData.region)); } else { double region[6]; std::istringstream sstream(modelData.region); sstream>>region[0]>>region[1]>>region[2]>>region[3]>>region[4]>>region[5]; osg::Matrix tm = osg::Matrix::scale(region[3]-region[0], region[4]-region[1], region[5]-region[2]) * osg::Matrix::translate(region[0],region[1],region[2]); transform->setMatrix( tm * matrix ); } subgraph = group; // osgDB::writeNodeFile(*subgraph, "output.osgt"); } if (subgraph.valid()) { addModel(subgraph.get(), positionData, modelData, scriptData); } else { OSG_NOTICE<<"Could not loaded model file : "<getBound(); float slide_scale = _slideHeight*(1.0f-positionData.position.z())*0.7f/bs.radius(); osg::MatrixTransform* transform = new osg::MatrixTransform; transform->setDataVariance(defaultMatrixDataVariance); transform->setMatrix(osg::Matrix::translate(-bs.center())* osg::Matrix::scale(positionData.scale.x()*slide_scale, positionData.scale.y()*slide_scale ,positionData.scale.z()*slide_scale)* osg::Matrix::rotate(osg::DegreesToRadians(positionData.rotate[0]),positionData.rotate[1],positionData.rotate[2],positionData.rotate[3])* osg::Matrix::translate(pos)); transform->setStateSet(createTransformStateSet()); transform->addChild(subgraph); subgraph = transform; } else { osg::Matrix matrix(osg::Matrix::scale(1.0f/positionData.scale.x(),1.0f/positionData.scale.y(),1.0f/positionData.scale.z())* osg::Matrix::rotate(osg::DegreesToRadians(positionData.rotate[0]),positionData.rotate[1],positionData.rotate[2],positionData.rotate[3])* osg::Matrix::translate(positionData.position)); osg::MatrixTransform* transform = new osg::MatrixTransform; transform->setDataVariance(defaultMatrixDataVariance); transform->setMatrix(osg::Matrix::inverse(matrix)); OSG_INFO<<"Position Matrix "<getMatrix()<addChild(subgraph); subgraph = transform; } float referenceSizeRatio = 0.707; float referenceSize = subgraph->getBound().radius() * referenceSizeRatio; // attached any rotation if (positionData.rotation[0]!=0.0) { osg::MatrixTransform* animation_transform = new osg::MatrixTransform; animation_transform->setDataVariance(osg::Object::DYNAMIC); animation_transform->setUpdateCallback( new osgUtil::TransformCallback(subgraph->getBound().center(), osg::Vec3(positionData.rotation[1],positionData.rotation[2],positionData.rotation[3]), osg::DegreesToRadians(positionData.rotation[0]))); animation_transform->addChild(subgraph); OSG_INFO<<"Rotation Matrix "<getMatrix()<getBound().center(); osg::AnimationPath* path = animation->getAnimationPath(); if (positionData.animation_name=="wheel" && (path->getTimeControlPointMap()).size()>=2) { OSG_INFO<<"**** Need to handle special wheel animation"<getTimeControlPointMap(); osg::AnimationPath::TimeControlPointMap::iterator curr_itr = controlPoints.begin(); osg::AnimationPath::TimeControlPointMap::iterator prev_itr=curr_itr; ++curr_itr; osg::AnimationPath::ControlPoint* prev_cp = &(prev_itr->second); osg::AnimationPath::ControlPoint* curr_cp = &(curr_itr->second); float totalLength = 0; float rotation_y_axis = 0; osg::Vec3 delta_position = curr_cp->getPosition() - prev_cp->getPosition(); float rotation_z_axis = atan2f(delta_position.y(),delta_position.x()); osg::Quat quat_y_axis,quat_z_axis,quat_combined; quat_y_axis.makeRotate(rotation_y_axis,0.0f,1.0f,0.0f); quat_z_axis.makeRotate(rotation_z_axis,0.0f,0.0f,1.0f); quat_combined = quat_y_axis*quat_z_axis; // set first rotation. prev_cp->setRotation(quat_combined); for(; curr_itr!=controlPoints.end(); ++curr_itr) { prev_cp = &(prev_itr->second); curr_cp = &(curr_itr->second); delta_position = curr_cp->getPosition() - prev_cp->getPosition(); totalLength += delta_position.length(); // rolling - rotation about the y axis. rotation_y_axis = totalLength/referenceSize; // direction - rotation about the z axis. rotation_z_axis = atan2f(delta_position.y(),delta_position.x()); OSG_INFO<<" rotation_y_axis="<setTextureUnit(1); specularHighlights->addChild(subgraph); subgraph = specularHighlights; } } // attach any meterial animation. if (positionData.requiresMaterialAnimation()) subgraph = attachMaterialAnimation(subgraph,positionData); subgraph = decorateSubgraphForPositionAndAnimation(subgraph, positionData); findImageStreamsAndAddCallbacks(subgraph); addToCurrentLayer(subgraph); if (scriptData.hasScripts()) addScriptsToNode(scriptData, subgraph); } class DraggerVolumeTileCallback : public osgManipulator::DraggerCallback { public: DraggerVolumeTileCallback(osgVolume::VolumeTile* volume, osgVolume::Locator* locator): _volume(volume), _locator(locator) {} virtual bool receive(const osgManipulator::MotionCommand& command); osg::observer_ptr _volume; osg::ref_ptr _locator; osg::Matrix _startMotionMatrix; osg::Matrix _localToWorld; osg::Matrix _worldToLocal; }; bool DraggerVolumeTileCallback::receive(const osgManipulator::MotionCommand& command) { if (!_locator) return false; switch (command.getStage()) { case osgManipulator::MotionCommand::START: { // Save the current matrix _startMotionMatrix = _locator->getTransform(); // Get the LocalToWorld and WorldToLocal matrix for this node. osg::NodePath nodePathToRoot; osgManipulator::computeNodePathToRoot(*_volume,nodePathToRoot); _localToWorld = _startMotionMatrix * osg::computeLocalToWorld(nodePathToRoot); _worldToLocal = osg::Matrix::inverse(_localToWorld); return true; } case osgManipulator::MotionCommand::MOVE: { // Transform the command's motion matrix into local motion matrix. osg::Matrix localMotionMatrix = _localToWorld * command.getWorldToLocal() * command.getMotionMatrix() * command.getLocalToWorld() * _worldToLocal; // Transform by the localMotionMatrix _locator->setTransform(localMotionMatrix * _startMotionMatrix); // OSG_NOTICE<<"New locator matrix "<<_locator->getTransform()<(node); osgVolume::Locator* locator = tile ? tile->getLocator() : 0; if (tile) { OSG_NOTICE<<"VolumeTileCallback : Have locator matrix "<getTransform()<(node); osgVolume::Locator* locator = tile ? tile->getLocator() : 0; if (locator) { PropertyReader pr(nv->getNodePath(), _source); float xMin=0.0; float yMin=0.0; float zMin=0.0; float xMax=1.0; float yMax=1.0; float zMax=1.0; pr>>xMin>>yMin>>zMin>>xMax>>yMax>>zMax; if (pr.ok()) { OSG_NOTICE<<"VolumeRegionCallback : xMin="<getNodePath(), _source); float value=0.0; pr>>value; if (pr.ok()) { OSG_NOTICE<<"ScalarPropertyCallback : value ["<<_source<<"]="<setValue(value); } else { OSG_NOTICE<<"Problem in reading, ScalarPropertyCallback : value="<(&node); if (tile) { OSG_NOTICE<<"Found Tile "<getLayer()->getProperty()->accept(*this); return; } osgUI::Widget* widget = dynamic_cast(&node); if (widget) { OSG_NOTICE<<"Found Widget "< > VolumeSettingsList; VolumeSettingsList _vsList; typedef std::vector< osg::ref_ptr > WidgetList; WidgetList _widgets; }; struct VolumeSettingsCallback : public osgGA::GUIEventHandler { VolumeSettingsCallback(): //_saveKey(19), // Ctril-S //_editKey(05) // Ctrl-E _saveKey('W'), _editKey('E') { } int _saveKey; int _editKey; bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& /*aa*/, osg::Object* object, osg::NodeVisitor* /*nv*/) { if (ea.getHandled()) return false; osg::Node* node = dynamic_cast(object); if (!node) { OSG_NOTICE<<"Warning: VolumeSettingsCallback assigned to a node other than VolumeTile, cannot operate edit/save."<accept(cvsv); for(CollectVolumeSettingsVisitor::VolumeSettingsList::iterator itr = cvsv._vsList.begin(); itr != cvsv._vsList.end(); ++itr) { osgVolume::VolumeSettings* vs = itr->get(); std::string filename = vs->getName(); if (!filename.empty()) { OSG_NOTICE<<"Save VolumeSettings "<accept(cvsv); for(CollectVolumeSettingsVisitor::WidgetList::iterator itr = cvsv._widgets.begin(); itr != cvsv._widgets.end(); ++itr) { osgUI::Widget* widget = itr->get(); OSG_NOTICE<<"Toggling visibility of Widget "<setVisible(!widget->getVisible()); } return true; } } return false; } }; void SlideShowConstructor::setUpVolumeScalarProperty(osgVolume::VolumeTile* tile, osgVolume::ScalarProperty* property, const std::string& source) { if (!source.empty()) { if (containsPropertyReference(source)) { tile->addUpdateCallback(new ScalarPropertyCallback( property, source)); } else { float value; std::istringstream sstream(source); sstream>>value; property->setValue(value); } } } void SlideShowConstructor::addVolume(const std::string& filename, const PositionData& in_positionData, const VolumeData& volumeData, const ScriptData& scriptData) { // osg::Object::DataVariance defaultMatrixDataVariance = osg::Object::DYNAMIC; // STATIC PositionData positionData(in_positionData); osg::ref_ptr options = _options; if (!volumeData.options.empty()) { options = _options->cloneOptions(); options->setOptionString(volumeData.options); } std::string foundFile = filename; osg::ref_ptr image; osg::ref_ptr volume; osg::ref_ptr tile; osg::ref_ptr layer; // check for wild cards if (filename.find('*')!=std::string::npos) { osgDB::DirectoryContents filenames = osgDB::expandWildcardsInFilename(filename); if (filenames.empty()) return; // make sure images are in alphabetical order. std::sort(filenames.begin(), filenames.end(), osgDB::FileNameComparator()); typedef std::vector< osg::ref_ptr > Images; Images images; for(osgDB::DirectoryContents::iterator itr = filenames.begin(); itr != filenames.end(); ++itr) { osg::ref_ptr loadedImage = osgDB::readRefImageFile(*itr, options.get()); if (loadedImage.valid()) { images.push_back(loadedImage.get()); } } image = osg::createImage3DWithAlpha(images); } else { osgDB::FileType fileType = osgDB::fileType(foundFile); if (fileType == osgDB::FILE_NOT_FOUND) { foundFile = findFileAndRecordPath(foundFile); fileType = osgDB::fileType(foundFile); } if (fileType == osgDB::DIRECTORY) { image = osgDB::readRefImageFile(foundFile+".dicom", options.get()); } else if (fileType == osgDB::REGULAR_FILE) { std::string ext = osgDB::getFileExtension(foundFile); if (ext=="osg" || ext=="ive" || ext=="osgx" || ext=="osgb" || ext=="osgt") { osg::ref_ptr obj = osgDB::readRefObjectFile(foundFile); image = dynamic_cast(obj.get()); volume = dynamic_cast(obj.get()); } else { image = osgDB::readRefImageFile( foundFile, options.get() ); } } else { // not found image, so fallback to plugins/callbacks to find the model. image = osgDB::readRefImageFile( filename, options.get() ); if (image) recordOptionsFilePath(options.get() ); } } if (!image && !volume) return; if (volumeData.colorSpaceOperation!=osg::NO_COLOR_SPACE_OPERATION) { OSG_NOTICE<<"Doing colour space conversion"< converted_image = osg::colorSpaceConversion(volumeData.colorSpaceOperation, image.get(), volumeData.colorModulate); if (converted_image!=image) { image->swap(*converted_image); } } if (positionData.scale.x()<0.0) { image->flipHorizontal(); positionData.scale.x() = fabs(positionData.scale.x()); OSG_INFO<<"addVolume(..) image->flipHorizontal();"<flipVertical(); positionData.scale.y() = fabs(positionData.scale.y()); OSG_INFO<<"addVolume(..) image->flipVertical();"<flipDepth(); positionData.scale.z() = fabs(positionData.scale.z()); OSG_INFO<<"addVolume(..) image->flipDepth();"<getNumChildren()>0) { tile = dynamic_cast(volume->getChild(0)); } } } else { volume = new osgVolume::Volume; } if (tile.valid()) { layer = dynamic_cast(tile->getLayer()); image = layer.valid() ? layer->getImage() : 0; } else { if (!image) return; tile = new osgVolume::VolumeTile; volume->addChild(tile.get()); } osg::ref_ptr vs = volumeData.volumeSettings; if (!layer) { if (!image) return; osg::ref_ptr details = dynamic_cast(image->getUserData()); osg::ref_ptr matrix = details ? details->getMatrix() : dynamic_cast(image->getUserData()); layer = new osgVolume::ImageLayer(image.get()); if (details) { layer->setTexelOffset(details->getTexelOffset()); layer->setTexelScale(details->getTexelScale()); } layer->rescaleToZeroToOneRange(); if (matrix.valid()) { layer->setLocator(new osgVolume::Locator(*matrix)); tile->setLocator(new osgVolume::Locator(*matrix)); } else { layer->setLocator(new osgVolume::Locator()); tile->setLocator(new osgVolume::Locator()); } if (!volumeData.region.empty()) { if (containsPropertyReference(volumeData.region)) { tile->addUpdateCallback(new VolumeRegionCallback((matrix.valid() ? *matrix : osg::Matrix::identity()), volumeData.region)); } else { float region[6]; std::istringstream sstream(volumeData.region); sstream>>region[0]>>region[1]>>region[2]>>region[3]>>region[4]>>region[5]; osg::Matrix tm = osg::Matrix::scale(region[3]-region[0], region[4]-region[1], region[5]-region[2]) * osg::Matrix::translate(region[0],region[1],region[2]); if (matrix.valid()) { tile->setLocator(new osgVolume::Locator(tm * (*matrix))); } else { tile->setLocator(new osgVolume::Locator(tm)); } } } tile->setLayer(layer.get()); osg::ref_ptr groupPropetry = new osgVolume::CompositeProperty; osg::ref_ptr sp = new osgVolume::SwitchProperty; sp->setActiveProperty(0); groupPropetry->addProperty(sp.get()); osg::ref_ptr ap = vs.valid() ? vs->getCutoffProperty() : new osgVolume::AlphaFuncProperty(0.1f); setUpVolumeScalarProperty(tile.get(), ap.get(), volumeData.cutoffValue); osg::ref_ptr tp = vs.valid() ? vs->getTransparencyProperty() : new osgVolume::TransparencyProperty(1.0f); setUpVolumeScalarProperty(tile.get(), tp.get(), volumeData.alphaValue); osg::ref_ptr sr = vs.valid() ? vs->getSampleRatioProperty() : new osgVolume::SampleRatioProperty(1.0); setUpVolumeScalarProperty(tile.get(), sr.get(), volumeData.sampleRatioValue); osg::ref_ptr srm = vs.valid() ? vs->getSampleRatioWhenMovingProperty() : 0; if (!volumeData.sampleRatioWhenMovingValue.empty()) { srm = new osgVolume::SampleRatioWhenMovingProperty(1.0); setUpVolumeScalarProperty(tile.get(), srm.get(), volumeData.sampleRatioWhenMovingValue); } // part of hull implementation. osg::ref_ptr etfp; if (!volumeData.exteriorTransparencyFactorValue.empty()) { etfp = new osgVolume::ExteriorTransparencyFactorProperty(0.0f); setUpVolumeScalarProperty(tile.get(), etfp.get(), volumeData.exteriorTransparencyFactorValue); } // deprecated, used by old RayTracedTechnique osg::ref_ptr sd = new osgVolume::SampleDensityProperty(0.005); setUpVolumeScalarProperty(tile.get(), sd.get(), volumeData.sampleDensityValue); osg::ref_ptr sdm; if (!volumeData.sampleDensityWhenMovingValue.empty()) { sdm = new osgVolume::SampleDensityWhenMovingProperty(0.005); setUpVolumeScalarProperty(tile.get(), sdm.get(), volumeData.sampleDensityWhenMovingValue); } osg::ref_ptr tfp = volumeData.transferFunction.valid() ? new osgVolume::TransferFunctionProperty(volumeData.transferFunction.get()) : 0; if (volumeData.volumeSettings.valid()) { groupPropetry->addProperty(volumeData.volumeSettings.get()); } else { if (ap.valid()) groupPropetry->addProperty(ap.get()); if (tp.valid()) groupPropetry->addProperty(tp.get()); if (sr.valid()) groupPropetry->addProperty(sr.get()); if (srm.valid()) groupPropetry->addProperty(srm.get()); } if (sd.valid()) groupPropetry->addProperty(sd.get()); if (sdm.valid()) groupPropetry->addProperty(sdm.get()); if (tfp.valid()) groupPropetry->addProperty(tfp.get()); if (etfp.valid()) groupPropetry->addProperty(etfp.get()); #if 1 { // Standard osgVolume::CompositeProperty* cp = new osgVolume::CompositeProperty; sp->addProperty(cp); } { // Light sp->addProperty(new osgVolume::LightingProperty); } { // Isosurface osgVolume::IsoSurfaceProperty* isp = vs.valid() ? vs->getIsoSurfaceProperty() : new osgVolume::IsoSurfaceProperty(0.1); setUpVolumeScalarProperty(tile.get(), isp, volumeData.alphaValue); sp->addProperty(isp); } { // MaximumIntensityProjection sp->addProperty(new osgVolume::MaximumIntensityProjectionProperty); } if (volumeData.volumeSettings.valid()) { sp->setActiveProperty(volumeData.volumeSettings->getShadingModel()); } else { switch(volumeData.shadingModel) { case(osgVolume::VolumeSettings::Standard): sp->setActiveProperty(0); break; case(osgVolume::VolumeSettings::Light): sp->setActiveProperty(1); break; case(osgVolume::VolumeSettings::Isosurface): sp->setActiveProperty(2); break; case(osgVolume::VolumeSettings::MaximumIntensityProjection): sp->setActiveProperty(3); break; } } #else { // Standard osgVolume::CompositeProperty* cp = new osgVolume::CompositeProperty; cp->addProperty(ap.get()); cp->addProperty(tp.get()); sp->addProperty(cp); } { // Light osgVolume::CompositeProperty* cp = new osgVolume::CompositeProperty; cp->addProperty(ap.get()); cp->addProperty(tp.get()); cp->addProperty(new osgVolume::LightingProperty); if (sd.valid()) cp->addProperty(sd.get()); if (sdm.valid()) cp->addProperty(sdm.get()); if (sr.valid()) cp->addProperty(sr.get()); if (srm.valid()) cp->addProperty(srm.get()); if (tfp.valid()) cp->addProperty(tfp.get()); if (etfp.valid()) cp->addProperty(etfp.get()); sp->addProperty(cp); } { // Isosurface osgVolume::CompositeProperty* cp = new osgVolume::CompositeProperty; cp->addProperty(tp.get()); osgVolume::IsoSurfaceProperty* isp = new osgVolume::IsoSurfaceProperty(0.1); setUpVolumeScalarProperty(tile.get(), isp, volumeData.alphaValue); cp->addProperty(isp); if (sd.valid()) cp->addProperty(sd.get()); if (sdm.valid()) cp->addProperty(sdm.get()); if (sr.valid()) cp->addProperty(sr.get()); if (srm.valid()) cp->addProperty(srm.get()); if (tfp.valid()) cp->addProperty(tfp.get()); if (etfp.valid()) cp->addProperty(etfp.get()); sp->addProperty(cp); } { // MaximumIntensityProjection osgVolume::CompositeProperty* cp = new osgVolume::CompositeProperty; cp->addProperty(ap.get()); cp->addProperty(tp.get()); cp->addProperty(new osgVolume::MaximumIntensityProjectionProperty); if (sd.valid()) cp->addProperty(sd.get()); if (sdm.valid()) cp->addProperty(sdm.get()); if (sr.valid()) cp->addProperty(sr.get()); if (srm.valid()) cp->addProperty(srm.get()); if (tfp.valid()) cp->addProperty(tfp.get()); if (etfp.valid()) cp->addProperty(etfp.get()); sp->addProperty(cp); } switch(volumeData.shadingModel) { case(osgVolume::VolumeSettings::Standard): sp->setActiveProperty(0); break; case(osgVolume::VolumeSettings::Light): sp->setActiveProperty(1); break; case(osgVolume::VolumeSettings::Isosurface): sp->setActiveProperty(2); break; case(osgVolume::VolumeSettings::MaximumIntensityProjection): sp->setActiveProperty(3); break; } #endif #if 1 layer->addProperty(groupPropetry.get()); #else layer->addProperty(sp.get()); #endif switch(volumeData.technique) { case(osgVolume::VolumeSettings::FixedFunction): tile->setVolumeTechnique(new osgVolume::FixedFunctionTechnique); break; case(osgVolume::VolumeSettings::RayTraced): tile->setVolumeTechnique(new osgVolume::RayTracedTechnique); break; case(osgVolume::VolumeSettings::MultiPass): tile->setVolumeTechnique(new osgVolume::MultipassTechnique); break; } tile->addEventCallback(new osgVolume::PropertyAdjustmentCallback()); } if (dynamic_cast(tile->getVolumeTechnique())!=0) { if (dynamic_cast(_root.get())==0) { osg::ref_ptr volumeScene = new osgVolume::VolumeScene; volumeScene->addChild(_root.get()); _root = volumeScene.get(); } } if (!volumeData.hull.empty()) { osg::ref_ptr hull = osgDB::readRefNodeFile(volumeData.hull, _options.get()); if (hull.valid()) { hull = decorateSubgraphForPositionAndAnimation(hull.get(), volumeData.hullPositionData); tile->addChild(hull.get()); } } osg::ref_ptr model = volume.get(); osg::ref_ptr group = dynamic_cast(model.get()); if (volumeData.useTabbedDragger || volumeData.useTrackballDragger) { if (!group) { group = new osg::Group; group->addChild(volume.get()); model = group.get(); } osg::ref_ptr dragger; if (volumeData.useTabbedDragger) { if (volumeData.useTrackballDragger) dragger = new osgManipulator::TabBoxTrackballDragger; else dragger = new osgManipulator::TabBoxDragger; } else dragger = new osgManipulator::TrackballDragger(); dragger->setupDefaultGeometry(); dragger->setHandleEvents(true); dragger->setActivationModKeyMask(osgGA::GUIEventAdapter::MODKEY_SHIFT); dragger->addDraggerCallback(new DraggerVolumeTileCallback(tile.get(), tile->getLocator())); dragger->setMatrix(osg::Matrix::translate(0.5,0.5,0.5)*tile->getLocator()->getTransform()); group->addChild(dragger.get()); } #if 1 osg::ref_ptr widget = vs.valid() ? osgDB::readRefFile("ui/VolumeSettings.lua") : 0; if (widget) { OSG_NOTICE<<"Adding widget"<setVisible(false); vs->setName("VolumeSettings"); widget->getOrCreateUserDataContainer()->addUserObject(vs.get()); osg::Vec3 pos = convertSlideToModel(osg::Vec3(0.0f,0.0f,0.0f)); const osg::BoundingBox& bb = widget->getExtents(); float slide_scale = 0.5f*_slideWidth/(bb.xMax()-bb.xMin()); osg::MatrixTransform* transform = new osg::MatrixTransform; transform->setDataVariance(osg::Object::DYNAMIC); transform->setMatrix(osg::Matrix::rotate(osg::inDegrees(90.0f),osg::Vec3(1.0f,0.0f,0.0f)) * osg::Matrix::scale(slide_scale,slide_scale,slide_scale)*osg::Matrix::translate(pos)); transform->addChild(widget); transform->addEventCallback(new VolumeSettingsCallback()); #if 0 HUDTransform* hudTransform = new HUDTransform(_hudSettings.get()); hudTransform->addChild(transform); addToCurrentLayer(hudTransform); #else addToCurrentLayer(transform); #endif } #endif ModelData modelData; addModel(model.get(), positionData, modelData, scriptData); } bool SlideShowConstructor::attachTexMat(osg::StateSet* stateset, const ImageData& imageData, float s, float t, bool textureRectangle) { float xScale = textureRectangle ? s : 1.0f; float yScale = textureRectangle ? t : 1.0f; float sx = (textureRectangle ? s : 1.0f) / (imageData.region_in_pixel_coords ? s : 1.0f); float sy = (textureRectangle ? t : 1.0f) / (imageData.region_in_pixel_coords ? t : 1.0f); float x1 = imageData.region[0]*sx; float y1 = imageData.region[1]*sy; float x2 = imageData.region[2]*sx; float y2 = imageData.region[3]*sy; if (x1!=0.0f || y1!=0.0f || x2!=xScale || y2 != yScale || imageData.texcoord_rotate != 0.0f) { osg::TexMat* texmat = new osg::TexMat; texmat->setMatrix(osg::Matrix::translate(-0.5f*xScale,-0.5f*yScale,0.0f)* osg::Matrix::rotate(osg::DegreesToRadians(imageData.texcoord_rotate),0.0f,0.0f,1.0f)* osg::Matrix::translate(0.5f*xScale,0.5f*yScale,0.0f)* osg::Matrix::scale((x2-x1)/xScale,(y2-y1)/yScale,1.0f)* osg::Matrix::translate(x1, y1, 0.0f)); stateset->setTextureAttribute(0,texmat); return true; } return false; } osg::Node* SlideShowConstructor::attachMaterialAnimation(osg::Node* model, const PositionData& positionData) { osg::ref_ptr animationMaterial = 0; if (!positionData.animation_material_filename.empty()) { #if 0 std::string absolute_animation_file_path = osgDB::findDataFile(positionData.animation_material_filename, _options.get()); if (!absolute_animation_file_path.empty()) { std::ifstream animation_filestream(absolute_animation_file_path.c_str()); if (!animation_filestream.eof()) { animationMaterial = new AnimationMaterial; animationMaterial->read(animation_filestream); } } #else animationMaterial = osgDB::readRefFile(positionData.animation_material_filename, _options.get()); #endif } else if (!positionData.fade.empty()) { std::istringstream iss(positionData.fade); animationMaterial = new AnimationMaterial; while (!iss.fail() && !iss.eof()) { float time=1.0f, alpha=1.0f; iss >> time >> alpha; if (!iss.fail()) { osg::Material* material = new osg::Material; material->setAmbient(osg::Material::FRONT_AND_BACK,osg::Vec4(1.0f,1.0f,1.0f,alpha)); material->setDiffuse(osg::Material::FRONT_AND_BACK,osg::Vec4(1.0f,1.0f,1.0f,alpha)); animationMaterial->insert(time,material); } } } if (animationMaterial) { animationMaterial->setLoopMode(positionData.animation_material_loop_mode); AnimationMaterialCallback* animationMaterialCallback = new AnimationMaterialCallback(animationMaterial.get()); animationMaterialCallback->setTimeOffset(positionData.animation_material_time_offset); animationMaterialCallback->setTimeMultiplier(positionData.animation_material_time_multiplier); osg::Group* decorator = new osg::Group; decorator->addChild(model); decorator->setUpdateCallback(animationMaterialCallback); if (animationMaterial->requiresBlending()) { SetToTransparentBin sttb; decorator->accept(sttb); } return decorator; } return model; } osg::AnimationPathCallback* SlideShowConstructor::getAnimationPathCallback(const PositionData& positionData) { if (!positionData.path.empty()) { // need to create an Options object with cache off to prevent sharing of animation paths osg::ref_ptr options = _options.valid() ? _options->cloneOptions() : new osgDB::Options; options->setObjectCacheHint(osgDB::Options::CACHE_NONE); osg::ref_ptr object = osgDB::readRefObjectFile(positionData.path, options.get()); osg::AnimationPath* animation = dynamic_cast(object.get()); if (animation) { if (positionData.frame==SlideShowConstructor::SLIDE) { osg::AnimationPath::TimeControlPointMap& controlPoints = animation->getTimeControlPointMap(); for(osg::AnimationPath::TimeControlPointMap::iterator itr=controlPoints.begin(); itr!=controlPoints.end(); ++itr) { osg::AnimationPath::ControlPoint& cp = itr->second; cp.setPosition(convertSlideToModel(cp.getPosition()+positionData.position)); } } animation->setLoopMode(positionData.path_loop_mode); osg::AnimationPathCallback* apc = new osg::AnimationPathCallback(animation); apc->setTimeOffset(positionData.path_time_offset); apc->setTimeMultiplier(positionData.path_time_multiplier); apc->setUseInverseMatrix(positionData.inverse_path); OSG_INFO<<"UseInverseMatrix "<getPluginStringData("filename"); std::string path = osgDB::getFilePath(filename_used); if (!path.empty() && _filePathData.valid()) { osgDB::FilePathList::iterator itr = std::find(_filePathData->filePathList.begin(),_filePathData->filePathList.end(),path); if (itr==_filePathData->filePathList.end()) { OSG_INFO<<"SlideShowConstructor::recordOptionsFilePath(..) - new path to record path="<