From d7442e74564a082a1efebea8180e76355e5aa01a Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Mon, 18 Nov 2013 12:46:00 +0000 Subject: [PATCH] Added panning and zooming functionality to transfer function UI prototype code. --- examples/osgtransferfunction/CMakeLists.txt | 6 +- .../TransferFunctionWidget.cpp | 394 ++++++++++++++++++ .../TransferFunctionWidget.h | 73 ++++ examples/osgtransferfunction/Widget.cpp | 223 ++++++++++ examples/osgtransferfunction/Widget.h | 84 ++++ .../osgtransferfunction.cpp | 184 ++++---- 6 files changed, 859 insertions(+), 105 deletions(-) create mode 100644 examples/osgtransferfunction/TransferFunctionWidget.cpp create mode 100644 examples/osgtransferfunction/TransferFunctionWidget.h create mode 100644 examples/osgtransferfunction/Widget.cpp create mode 100644 examples/osgtransferfunction/Widget.h diff --git a/examples/osgtransferfunction/CMakeLists.txt b/examples/osgtransferfunction/CMakeLists.txt index e67a4a9ec..e5cbd4cc7 100644 --- a/examples/osgtransferfunction/CMakeLists.txt +++ b/examples/osgtransferfunction/CMakeLists.txt @@ -1,4 +1,8 @@ -SET(TARGET_SRC osgtransferfunction.cpp ) +SET(TARGET_SRC + Widget.cpp + TransferFunctionWidget.cpp + osgtransferfunction.cpp +) SET(TARGET_ADDED_LIBRARIES osgVolume osgManipulator) diff --git a/examples/osgtransferfunction/TransferFunctionWidget.cpp b/examples/osgtransferfunction/TransferFunctionWidget.cpp new file mode 100644 index 000000000..1643969a1 --- /dev/null +++ b/examples/osgtransferfunction/TransferFunctionWidget.cpp @@ -0,0 +1,394 @@ +/* -*-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(); +} diff --git a/examples/osgtransferfunction/TransferFunctionWidget.h b/examples/osgtransferfunction/TransferFunctionWidget.h new file mode 100644 index 000000000..ee0f93844 --- /dev/null +++ b/examples/osgtransferfunction/TransferFunctionWidget.h @@ -0,0 +1,73 @@ +/* -*-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. +*/ + +#ifndef OSGUI_TRANSFERFUNCTIONWIDGET +#define OSGUI_TRANSFERFUNCTIONWIDGET + +#include +#include + +#include "Widget.h" + +#define OSGUI_EXPORT + +namespace osgUI +{ + +class OSGUI_EXPORT TransferFunctionWidget : public osgUI::Widget +{ +public: + TransferFunctionWidget(osg::TransferFunction1D* tf=0); + TransferFunctionWidget(const TransferFunctionWidget& tfw, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY); + META_Node(osgUI, TransferFunctionWidget); + + void traverse(osg::NodeVisitor& nv); + + virtual bool handle(osgGA::EventVisitor* ev, osgGA::Event* event); + + void setTransferFunction(const osg::TransferFunction1D* tf); + osg::TransferFunction1D* getTransferFunction() { return _transferFunction.get(); } + const osg::TransferFunction1D* getTransferFunction() const { return _transferFunction.get(); } + + void resetVisibleRange(); + void setVisibleRange(float left, float right); + void translateVisibleRange(float delta); + void scaleVisibleRange(float center, float delta); + + virtual void createGraphics(); + +protected: + virtual ~TransferFunctionWidget() {} + + osg::ref_ptr _transferFunction; + + osg::ref_ptr _geode; + osg::ref_ptr _geometry; + osg::ref_ptr _vertices; + osg::ref_ptr _colours; + osg::ref_ptr _background_primitives; + osg::ref_ptr _historgram_primitives; + osg::ref_ptr _outline_primitives; + + float _min; + float _max; + float _left; + float _right; + + bool _startedDrag; + float _previousDragPosition; +}; + +} + +#endif diff --git a/examples/osgtransferfunction/Widget.cpp b/examples/osgtransferfunction/Widget.cpp new file mode 100644 index 000000000..b100468af --- /dev/null +++ b/examples/osgtransferfunction/Widget.cpp @@ -0,0 +1,223 @@ +/* -*-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 "Widget.h" + +#include +#include +#include +#include + +#include +#include + +using namespace osgUI; + +Widget::Widget(): + _focusBehaviour(FOCUS_FOLLOWS_POINTER), + _hasEventFocus(false), + _graphicsInitialized(false) + +{ + setNumChildrenRequiringEventTraversal(1); +} + +Widget::Widget(const Widget& widget, const osg::CopyOp& copyop): + osg::Group(), + _focusBehaviour(widget._focusBehaviour), + _hasEventFocus(false), + _graphicsInitialized(false) +{ + setNumChildrenRequiringEventTraversal(1); +} + +void Widget::setExtents(const osg::BoundingBox& bb) +{ + _extents = bb; +} + +void Widget::updateFocus(osg::NodeVisitor& nv) +{ + osgGA::EventVisitor* ev = dynamic_cast(&nv); + osgViewer::View* view = ev ? dynamic_cast(ev->getActionAdapter()) : 0; + if (ev && view) + { + osgGA::EventQueue::Events& events = ev->getEvents(); + for(osgGA::EventQueue::Events::iterator itr = events.begin(); + itr != events.end(); + ++itr) + { + osgGA::GUIEventAdapter* ea = (*itr)->asGUIEventAdapter(); + if (ea) + { + bool previousFocus = _hasEventFocus; + if (_focusBehaviour==CLICK_TO_FOCUS) + { + if (ea->getEventType()==osgGA::GUIEventAdapter::PUSH) + { + int numButtonsPressed = 0; + if (ea->getButtonMask()&osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON) ++numButtonsPressed; + if (ea->getButtonMask()&osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON) ++numButtonsPressed; + if (ea->getButtonMask()&osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON) ++numButtonsPressed; + + if (numButtonsPressed==1) + { + osgUtil::LineSegmentIntersector::Intersections intersections; + bool withinWidget = view->computeIntersections(*ea, nv.getNodePath(), intersections); + if (withinWidget) _hasEventFocus = true; + else _hasEventFocus = false; + } + } + } + else if (_focusBehaviour==FOCUS_FOLLOWS_POINTER) + { + bool checkWithinWidget = false; + if (!_hasEventFocus) + { + checkWithinWidget = (ea->getEventType()!=osgGA::GUIEventAdapter::FRAME) && ea->getButtonMask()==0; + } + else + { + // if mouse move or mouse release check to see if mouse still within widget to retain focus + if (ea->getEventType()==osgGA::GUIEventAdapter::MOVE) + { + checkWithinWidget = true; + } + else if (ea->getEventType()==osgGA::GUIEventAdapter::RELEASE) + { + // if no buttons pressed then check + if (ea->getButtonMask()==0) checkWithinWidget = true; + } + } + + if (checkWithinWidget) + { + osgUtil::LineSegmentIntersector::Intersections intersections; + bool withinWidget = view->computeIntersections(*ea, nv.getNodePath(), intersections); + + _hasEventFocus = withinWidget; + } + } + + if (previousFocus != _hasEventFocus) + { + if (_hasEventFocus) + { + enter(); +#if 0 + if (view->getCameraManipulator()) + { + view->getCameraManipulator()->finishAnimation(); + view->requestContinuousUpdate( false ); + } +#endif + } + else + { + leave(); + } + } + + } + } + } +} + +void Widget::setHasEventFocus(bool focus) +{ + if (_hasEventFocus == focus) return; + + _hasEventFocus = focus; + + if (_hasEventFocus) enter(); + else leave(); +} + +bool Widget::getHasEventFocus() const +{ + return _hasEventFocus; +} + +void Widget::enter() +{ + OSG_NOTICE<<"enter()"<(&nv); + osgViewer::View* view = ev ? dynamic_cast(ev->getActionAdapter()) : 0; + if (ev && view) + { + updateFocus(nv); + + if (getHasEventFocus()) + { + // signify that event has been taken by widget with focus + ev->setEventHandled(true); + + osgGA::EventQueue::Events& events = ev->getEvents(); + for(osgGA::EventQueue::Events::iterator itr = events.begin(); + itr != events.end(); + ++itr) + { + handle(ev, itr->get()); + + (*itr)->setHandled(true); + } + } + } + else + { + osg::Group::traverse(nv); + } +} + +bool Widget::handle(osgGA::EventVisitor* /*ev*/, osgGA::Event* /*event*/) +{ + return false; +} + +bool Widget::computePositionInLocalCoordinates(osgGA::EventVisitor* ev, osgGA::GUIEventAdapter* event, osg::Vec3& localPosition) const +{ + osgViewer::View* view = ev ? dynamic_cast(ev->getActionAdapter()) : 0; + osgUtil::LineSegmentIntersector::Intersections intersections; + if (view && view->computeIntersections(*event, ev->getNodePath(), intersections)) + { + localPosition = intersections.begin()->getLocalIntersectPoint(); + + return (_extents.contains(localPosition, 1e-6)); + } + else + { + return false; + } +} + + +void Widget::createGraphics() +{ + _graphicsInitialized = true; +} + +osg::BoundingSphere Widget::computeBound() const +{ + return osg::BoundingSphere(_extents); +} diff --git a/examples/osgtransferfunction/Widget.h b/examples/osgtransferfunction/Widget.h new file mode 100644 index 000000000..5c4024014 --- /dev/null +++ b/examples/osgtransferfunction/Widget.h @@ -0,0 +1,84 @@ +/* -*-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. +*/ + +#ifndef OSGUI_WIDGET +#define OSGUI_WIDGET + +#include +#include +#include +#include + +#define OSGUI_EXPORT + +namespace osgUI +{ + +class OSGUI_EXPORT Widget : public osg::Group +{ +public: + Widget(); + Widget(const Widget& tfw, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY); + META_Node(osgUI, Widget); + + virtual void traverse(osg::NodeVisitor& nv); + + virtual bool handle(osgGA::EventVisitor* ev, osgGA::Event* event); + + virtual bool computePositionInLocalCoordinates(osgGA::EventVisitor* ev, osgGA::GUIEventAdapter* event, osg::Vec3& localPosition) const; + + virtual void createGraphics(); + + virtual void setExtents(const osg::BoundingBox& bb); + const osg::BoundingBox& getExtents() const { return _extents; } + + enum FocusBehaviour + { + CLICK_TO_FOCUS, + FOCUS_FOLLOWS_POINTER, + EVENT_DRIVEN_FOCUS_DISABLED + }; + + void setFocusBehaviour(FocusBehaviour behaviour) { _focusBehaviour = behaviour; } + FocusBehaviour getFocusBehaviour() const { return _focusBehaviour; } + + /** update the focus according to events.*/ + virtual void updateFocus(osg::NodeVisitor& nv); + + /** set whether the widget has focus or not.*/ + virtual void setHasEventFocus(bool focus); + + /** get whether the widget has focus or not.*/ + virtual bool getHasEventFocus() const; + + virtual osg::BoundingSphere computeBound() const; + +protected: + virtual ~Widget() {} + + /** update any focus related graphics+state to the focused state.*/ + virtual void enter(); + + /** update any focus related graphics+state to the unfocused state.*/ + virtual void leave(); + + FocusBehaviour _focusBehaviour; + bool _hasEventFocus; + bool _graphicsInitialized; + + osg::BoundingBox _extents; +}; + +} + +#endif diff --git a/examples/osgtransferfunction/osgtransferfunction.cpp b/examples/osgtransferfunction/osgtransferfunction.cpp index a3e8216de..0770190d9 100644 --- a/examples/osgtransferfunction/osgtransferfunction.cpp +++ b/examples/osgtransferfunction/osgtransferfunction.cpp @@ -30,10 +30,15 @@ #include #include +#include +#include #include +#include +#include "TransferFunctionWidget.h" + class Histogram { public: @@ -248,104 +253,6 @@ osg::Node* Histogram::createGraphicalRepresentation() return transform.release(); } -osg::Node* createGraphicalRepresentation(osg::TransferFunction1D* tf) -{ - typedef osg::TransferFunction1D::ColorMap ColorMap; - ColorMap& colorMap = tf->getColorMap(); - if (colorMap.empty()) return 0; - - osg::ref_ptr transform = new osg::MatrixTransform; - - float xMin = colorMap.begin()->first; - float xMax = colorMap.rbegin()->first; - - 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/(xMax-xMin); - float yScale = 1.0f/yMax; - - { - osg::ref_ptr geode = new osg::Geode; - transform->addChild(geode.get()); - - osg::ref_ptr geometry = new osg::Geometry; - geode->addDrawable(geometry.get()); - geode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); - geode->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON); - - osg::ref_ptr vertices = new osg::Vec3Array; - geometry->setVertexArray(vertices.get()); - - osg::ref_ptr 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->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*xScale, 0.0f, depth)); - colours->push_back(color); - - vertices->push_back(osg::Vec3(x*xScale, y*yScale, depth)); - colours->push_back(color); - - vertices->push_back(osg::Vec3(x*xScale, y*yScale, depth)); - colours->push_back(background_color); - - vertices->push_back(osg::Vec3(x*xScale, yMax*yScale, depth)); - colours->push_back(background_color); - } - - osg::ref_ptr background_primitives = new osg::DrawElementsUShort(GL_TRIANGLE_STRIP); - osg::ref_ptr historgram_primitives = new osg::DrawElementsUShort(GL_TRIANGLE_STRIP); - osg::ref_ptr outline_primitives = new osg::DrawElementsUShort(GL_LINE_STRIP); - 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); - - } - - geometry->addPrimitiveSet(outline_primitives.get()); - geometry->addPrimitiveSet(historgram_primitives.get()); - geometry->addPrimitiveSet(background_primitives.get()); - } - - //transform->setMatrix(osg::Matrix::scale(xScale/(maxX-minY), yScale/(yMax), 1.0f)); - - transform->setMatrix(osg::Matrix::scale(2.0,1.0,1.0)*osg::Matrix::rotate(osg::DegreesToRadians(90.0), osg::Vec3d(1.0,0.0,0.0))); - - return transform.release(); -} - - osg::TransferFunction1D* readTransferFunctionFile(const std::string& filename, float colorScale=1.0f) { std::string foundFile = osgDB::findDataFile(filename); @@ -461,17 +368,72 @@ int main(int argc, char ** argv) osgViewer::Viewer viewer(arguments); + viewer.addEventHandler(new osgViewer::StatsHandler()); + osg::ref_ptr tf; std::string filename; if (arguments.read("--tf",filename)) { - tf = readTransferFunctionFile(filename); + tf = readTransferFunctionFile(filename, 1.0f); + } + if (arguments.read("--tf-255",filename)) + { + tf = readTransferFunctionFile(filename,1.0f/255.0f); } bool createHistorgram = arguments.read("--histogram"); - osg::ref_ptr model = osgDB::readNodeFiles(arguments); +#if 0 + for(int i=1; i image; + osg::ref_ptr volume; + osg::ref_ptr volumeTile; + std::string filename = arguments[i]; + osgDB::FileType fileType = osgDB::fileType(foundFile); + + if (fileType == osgDB::DIRECTORY) + { + osg::ref_ptr image = osgDB::readImageFile(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::readObjectFile(foundFile); + image = dynamic_cast(obj.get()); + volume = dynamic_cast(obj.get()); + volumeTile = dynamic_cast(obj.get()); + } + else + { + image = osgDB::readImageFile( foundFile ); + } + } + else + { + // not found image, so fallback to plugins/callbacks to find the model. + image = osgDB::readImageFile( filename); + } + + if (image.valid()) + { + volumeTile = new osgVolume::VolumeTile; + } + + } + OSG_NOTICE<<"Argument "< model = osgDB::readNodeFiles(arguments); +#endif typedef std::vector< osg::ref_ptr > Nodes; Nodes nodes; @@ -493,6 +455,9 @@ int main(int argc, char ** argv) osg::ref_ptr volume = new osgVolume::Volume; volume->addChild(model.get()); model = volume.get(); + +// volumeTile->setVolumeTechnique(new osgVolume::RayTracedTechnique); +// volumeTile->setVolumeTechnique(new osgVolume::FixedFunctionTechnique); } nodes.push_back(model.get()); @@ -500,7 +465,12 @@ int main(int argc, char ** argv) FindVolumeTiles fvt; model->accept(fvt); - if (!fvt._tiles.empty()) imageLayer = dynamic_cast(fvt._tiles[0]->getLayer()); + if (!fvt._tiles.empty()) + { + osgVolume::VolumeTile* tile = fvt._tiles[0].get(); + imageLayer = dynamic_cast(tile->getLayer()); + tile->addEventCallback(new osgVolume::PropertyAdjustmentCallback()); + } } @@ -549,7 +519,10 @@ int main(int argc, char ** argv) if (tf.valid()) { - nodes.push_back(createGraphicalRepresentation(tf.get())); + osg::ref_ptr transform = new osg::MatrixTransform; + transform->setMatrix(osg::Matrix::scale(2.0,1.0,1.0)*osg::Matrix::rotate(osg::DegreesToRadians(90.0), osg::Vec3d(1.0,0.0,0.0))); + transform->addChild(new osgUI::TransferFunctionWidget(tf.get())); + nodes.push_back(transform.get()); } if (nodes.empty()) @@ -558,7 +531,10 @@ int main(int argc, char ** argv) return 1; } - if (nodes.size()==1) viewer.setSceneData(nodes[0].get()); + if (nodes.size()==1) + { + viewer.setSceneData(nodes[0].get()); + } else { osg::Vec3d position(0.0,0.0,0.0); @@ -594,7 +570,7 @@ int main(int argc, char ** argv) viewer.setSceneData(group.get()); } - + OSG_NOTICE<<"Reading to run viewer"<