/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2013 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #include "TransferFunctionWidget.h" #include #include #include #include #include #include #include #include #include #include #include using namespace osgUI; TransferFunctionWidget::TransferFunctionWidget(osg::TransferFunction1D* tf): _min(FLT_MAX), _max(-FLT_MAX), _left(FLT_MAX), _right(-FLT_MAX), _startedDrag(false), _previousDragPosition(0.0f) { setNumChildrenRequiringEventTraversal(1); setExtents(osg::BoundingBox(0.0,0.0,0.0,1.0,1.0,0.0)); setTransferFunction(tf); } TransferFunctionWidget::TransferFunctionWidget(const TransferFunctionWidget& tfw, const osg::CopyOp& copyop): Widget(tfw,copyop) { setExtents(tfw.getExtents()); setTransferFunction(tfw.getTransferFunction()); } void TransferFunctionWidget::setTransferFunction(const osg::TransferFunction1D* tf) { if (_transferFunction==tf) return; _transferFunction = const_cast(tf); if (_transferFunction.valid()) { osg::TransferFunction1D::ColorMap& colorMap = _transferFunction->getColorMap(); if (colorMap.empty()) { _min = FLT_MAX; _max = -FLT_MAX; } else { _min = colorMap.begin()->first; _max = colorMap.rbegin()->first; } } resetVisibleRange(); } void TransferFunctionWidget::resetVisibleRange() { setVisibleRange(_min, _max); } void TransferFunctionWidget::setVisibleRange(float left, float right) { if (left<_min) left = _min; if (right>_max) right = _max; _left = left; _right = right; // OSG_NOTICE<<"setVisibleRange("<<_left<<", "<<_right<<")"<_max) { new_left += (_max-new_right); new_right = _max; } } setVisibleRange(new_left, new_right); } void TransferFunctionWidget::scaleVisibleRange(float center, float delta) { float scale = powf(2.0, delta); setVisibleRange(center+(_left-center)*scale, center+(_right-center)*scale); } void TransferFunctionWidget::traverse(osg::NodeVisitor& nv) { Widget::traverse(nv); } bool TransferFunctionWidget::handle(osgGA::EventVisitor* ev, osgGA::Event* event) { osgGA::GUIEventAdapter* ea = event->asGUIEventAdapter(); if (!ea) return false; switch(ea->getEventType()) { case(osgGA::GUIEventAdapter::PUSH): // OSG_NOTICE<<"Pressed button "<getButton()<getButtonMask()==osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON) { osg::Vec3 position; if (computePositionInLocalCoordinates(ev, ea, position)) { _startedDrag = true; _previousDragPosition = position.x(); } } break; case(osgGA::GUIEventAdapter::RELEASE): // OSG_NOTICE<<"Released button "<getButton()<getScrollingMotion()) { case(osgGA::GUIEventAdapter::SCROLL_NONE): break; case(osgGA::GUIEventAdapter::SCROLL_LEFT): translation -= increment; break; case(osgGA::GUIEventAdapter::SCROLL_RIGHT): translation += increment; break; case(osgGA::GUIEventAdapter::SCROLL_UP): scale /= ratio; break; case(osgGA::GUIEventAdapter::SCROLL_DOWN): scale *= ratio; break; case(osgGA::GUIEventAdapter::SCROLL_2D): translation = increment*ea->getScrollingDeltaX(); scale = powf(ratio, increment*ea->getScrollingDeltaY()); break; } float center = _left+(_right-_left)*position.x(); // OSG_NOTICE<<"translation = "<getKey()<getKey()==osgGA::GUIEventAdapter::KEY_Left) translateVisibleRange(-delta); else if (ea->getKey()==osgGA::GUIEventAdapter::KEY_Right) translateVisibleRange(delta); else if (ea->getKey()==osgGA::GUIEventAdapter::KEY_Up) scaleVisibleRange((_left+_right)*0.5f, -delta); else if (ea->getKey()==osgGA::GUIEventAdapter::KEY_Down) scaleVisibleRange((_left+_right)*0.5f, delta); break; } case(osgGA::GUIEventAdapter::KEYUP): // OSG_NOTICE<<"Released key"<getKey()<getKey()==' ' ||ea->getKey()==osgGA::GUIEventAdapter::KEY_Home) resetVisibleRange(); break; default: break; } return false; } void TransferFunctionWidget::createGraphics() { // OSG_NOTICE<<"Create graphics"<getColorMap(); if (colorMap.empty()) return; float depth = 0.0f; float yMax = 0.0f; // find yMax for(ColorMap::iterator itr = colorMap.begin(); itr != colorMap.end(); ++itr) { float y = itr->second[3]; if (y>yMax) yMax = y; } float xScale = 1.0f/(_right-_left); float xOffset = -_left; float yScale = 1.0f/yMax; if (!_geode) { _geode = new osg::Geode; addChild(_geode.get()); } { if (!_geometry) { _geometry = new osg::Geometry; _geometry->setDataVariance(osg::Geometry::DYNAMIC); _geometry->setUseDisplayList(false); _geometry->setUseVertexBufferObjects(false); _geode->addDrawable(_geometry.get()); osg::ref_ptr stateset = _geometry->getOrCreateStateSet(); stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED); stateset->setMode(GL_BLEND, osg::StateAttribute::ON | osg::StateAttribute::PROTECTED); osg::ref_ptr alphaFunc = new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.0f); stateset->setAttributeAndModes(alphaFunc, osg::StateAttribute::ON | osg::StateAttribute::PROTECTED); osg::ref_ptr image = new osg::Image; image->allocateImage(1,1,1, GL_RGBA, GL_UNSIGNED_BYTE); unsigned char* data = image->data(); data[0] = 255; data[1] = 255; data[2] = 255; data[3] = 255; osg::ref_ptr texture = new osg::Texture2D; texture->setImage(image.get()); texture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::NEAREST); texture->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::NEAREST); texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::CLAMP_TO_BORDER); texture->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::CLAMP_TO_BORDER); texture->setBorderColor(osg::Vec4(1.0f,1.0f,0.0f,0.0f)); stateset->setTextureAttribute(0, texture.get()); osg::ref_ptr texgen = new osg::TexGen; texgen->setMode(osg::TexGen::OBJECT_LINEAR); texgen->setPlane(osg::TexGen::S, osg::Plane(1.0,0.0,0.0,0.0)); texgen->setPlane(osg::TexGen::T, osg::Plane(0.0,1.0,0.0,0.0)); stateset->setTextureAttribute(0, texgen.get()); stateset->setTextureMode(0, GL_TEXTURE_GEN_S, osg::StateAttribute::ON | osg::StateAttribute::PROTECTED); stateset->setTextureMode(0, GL_TEXTURE_GEN_T, osg::StateAttribute::ON | osg::StateAttribute::PROTECTED); stateset->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON | osg::StateAttribute::PROTECTED); } if (!_vertices) { _vertices = new osg::Vec3Array; _geometry->setVertexArray(_vertices.get()); } if (!_colours) { _colours = new osg::Vec4Array; _geometry->setColorArray(_colours.get(), osg::Array::BIND_PER_VERTEX); } osg::Vec4 background_color(1.0f, 1.0f, 1.0f, 0.1f); unsigned numColumnsRequired = colorMap.size(); _vertices->resize(0); _vertices->reserve(numColumnsRequired*3); for(ColorMap::iterator itr = colorMap.begin(); itr != colorMap.end(); ++itr) { float x = itr->first; osg::Vec4 color = itr->second; float y = itr->second[3]; color[3] = 1.0f; _vertices->push_back(osg::Vec3((x+xOffset)*xScale, 0.0f, depth)); _colours->push_back(color); _vertices->push_back(osg::Vec3((x+xOffset)*xScale, y*yScale, depth)); _colours->push_back(color); _vertices->push_back(osg::Vec3((x+xOffset)*xScale, y*yScale, depth)); _colours->push_back(background_color); _vertices->push_back(osg::Vec3((x+xOffset)*xScale, yMax*yScale, depth)); _colours->push_back(background_color); } if (!_background_primitives) { _background_primitives = new osg::DrawElementsUShort(GL_TRIANGLE_STRIP); _geometry->addPrimitiveSet(_background_primitives.get()); } if (!_historgram_primitives) { _historgram_primitives = new osg::DrawElementsUShort(GL_TRIANGLE_STRIP); _geometry->addPrimitiveSet(_historgram_primitives.get()); } if (!_outline_primitives) { _outline_primitives = new osg::DrawElementsUShort(GL_LINE_STRIP); _geometry->addPrimitiveSet(_outline_primitives.get()); } _background_primitives->resize(0); _historgram_primitives->resize(0); _outline_primitives->resize(0); for(unsigned int i=0; ipush_back(iv+3); _background_primitives->push_back(iv+2); _historgram_primitives->push_back(iv+1); _historgram_primitives->push_back(iv+0); _outline_primitives->push_back(iv+1); } } #if 0 static bool first = true; if (first) { osgDB::writeNodeFile(*_geode, "test.osgt"); first = false; } #endif _geometry->dirtyBound(); // make sure the general widget geometry/state is created and _graphicsInitialized reset to false Widget::createGraphics(); }