1 /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2013 Robert Osfield
2  *
3  * This library is open source and may be redistributed and/or modified under
4  * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5  * (at your option) any later version.  The full license is in LICENSE file
6  * included with this distribution, and on the openscenegraph.org website.
7  *
8  * This library is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * OpenSceneGraph Public License for more details.
12 */
13 
14 #include "TransferFunctionWidget.h"
15 
16 #include <osg/Geode>
17 #include <osg/Geometry>
18 #include <osg/TexGen>
19 #include <osg/AlphaFunc>
20 #include <osg/Texture2D>
21 #include <osg/MatrixTransform>
22 #include <osg/io_utils>
23 
24 #include <osgGA/EventVisitor>
25 #include <osgDB/ReadFile>
26 #include <osgDB/WriteFile>
27 #include <osgViewer/View>
28 
29 using namespace osgUI;
30 
TransferFunctionWidget(osg::TransferFunction1D * tf)31 TransferFunctionWidget::TransferFunctionWidget(osg::TransferFunction1D* tf):
32     _min(FLT_MAX),
33     _max(-FLT_MAX),
34     _left(FLT_MAX),
35     _right(-FLT_MAX),
36     _startedDrag(false),
37     _previousDragPosition(0.0f)
38 {
39     setNumChildrenRequiringEventTraversal(1);
40     setExtents(osg::BoundingBox(0.0,0.0,0.0,1.0,1.0,0.0));
41     setTransferFunction(tf);
42 }
43 
TransferFunctionWidget(const TransferFunctionWidget & tfw,const osg::CopyOp & copyop)44 TransferFunctionWidget::TransferFunctionWidget(const TransferFunctionWidget& tfw, const osg::CopyOp& copyop):
45     Widget(tfw,copyop)
46 {
47     setExtents(tfw.getExtents());
48     setTransferFunction(tfw.getTransferFunction());
49 }
50 
setTransferFunction(const osg::TransferFunction1D * tf)51 void TransferFunctionWidget::setTransferFunction(const osg::TransferFunction1D* tf)
52 {
53     if (_transferFunction==tf) return;
54 
55     _transferFunction = const_cast<osg::TransferFunction1D*>(tf);
56 
57     if (_transferFunction.valid())
58     {
59         osg::TransferFunction1D::ColorMap& colorMap = _transferFunction->getColorMap();
60         if (colorMap.empty())
61         {
62             _min = FLT_MAX;
63             _max = -FLT_MAX;
64         }
65         else
66         {
67             _min = colorMap.begin()->first;
68             _max = colorMap.rbegin()->first;
69         }
70     }
71 
72     resetVisibleRange();
73 }
74 
resetVisibleRange()75 void TransferFunctionWidget::resetVisibleRange()
76 {
77     setVisibleRange(_min, _max);
78 }
79 
setVisibleRange(float left,float right)80 void TransferFunctionWidget::setVisibleRange(float left, float right)
81 {
82     if (left<_min) left = _min;
83     if (right>_max) right = _max;
84 
85     _left = left;
86     _right = right;
87 //    OSG_NOTICE<<"setVisibleRange("<<_left<<", "<<_right<<")"<<std::endl;
88     createGraphics();
89 }
90 
translateVisibleRange(float delta)91 void TransferFunctionWidget::translateVisibleRange(float delta)
92 {
93     float new_left = _left+(_right-_left)*delta;
94     float new_right = _right+(_right-_left)*delta;
95     if (delta<0.0)
96     {
97         if (new_left<_min)
98         {
99             new_right += (_min-new_left);
100             new_left = _min;
101         }
102     }
103     else
104     {
105         if (new_right>_max)
106         {
107             new_left += (_max-new_right);
108             new_right = _max;
109         }
110     }
111 
112     setVisibleRange(new_left, new_right);
113 }
114 
scaleVisibleRange(float center,float delta)115 void TransferFunctionWidget::scaleVisibleRange(float center, float delta)
116 {
117     float scale = powf(2.0, delta);
118     setVisibleRange(center+(_left-center)*scale,
119                     center+(_right-center)*scale);
120 }
121 
122 
traverseImplementation(osg::NodeVisitor & nv)123 void TransferFunctionWidget::traverseImplementation(osg::NodeVisitor& nv)
124 {
125     Widget::traverseImplementation(nv);
126 }
127 
handleImplementation(osgGA::EventVisitor * ev,osgGA::Event * event)128 bool TransferFunctionWidget::handleImplementation(osgGA::EventVisitor* ev, osgGA::Event* event)
129 {
130     osgGA::GUIEventAdapter* ea = event->asGUIEventAdapter();
131     if (!ea) return false;
132 
133     switch(ea->getEventType())
134     {
135         case(osgGA::GUIEventAdapter::PUSH):
136             // OSG_NOTICE<<"Pressed button "<<ea->getButton()<<std::endl;
137             _startedDrag = false;
138             if (ea->getButtonMask()==osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON)
139             {
140                 osg::Vec3d position;
141                 if (computePositionInLocalCoordinates(ev, ea, position))
142                 {
143                     _startedDrag = true;
144                     _previousDragPosition = position.x();
145                 }
146             }
147             break;
148         case(osgGA::GUIEventAdapter::RELEASE):
149             // OSG_NOTICE<<"Released button "<<ea->getButton()<<std::endl;
150             _startedDrag = false;
151             break;
152         case(osgGA::GUIEventAdapter::DRAG):
153             // OSG_NOTICE<<"Dragged "<<std::endl;
154             if (_startedDrag)
155             {
156                 osg::Vec3d position;
157                 if (computePositionInLocalCoordinates(ev, ea, position))
158                 {
159                     float delta = -(position.x()-_previousDragPosition);
160 
161                     _previousDragPosition = position.x();
162 
163                     translateVisibleRange(delta);
164                 }
165             }
166             break;
167         case(osgGA::GUIEventAdapter::SCROLL):
168         {
169             osg::Vec3d position;
170             if (computePositionInLocalCoordinates(ev, ea, position))
171             {
172                 float translation = 0.0;
173                 float increment = 0.1;
174                 float scale = 1.0;
175                 float ratio = (1.0f+increment);
176                 switch(ea->getScrollingMotion())
177                 {
178                     case(osgGA::GUIEventAdapter::SCROLL_NONE):
179                         break;
180                     case(osgGA::GUIEventAdapter::SCROLL_LEFT):
181                         translation -= increment;
182                         break;
183                     case(osgGA::GUIEventAdapter::SCROLL_RIGHT):
184                         translation += increment;
185                         break;
186                     case(osgGA::GUIEventAdapter::SCROLL_UP):
187                         scale /= ratio;
188                         break;
189                     case(osgGA::GUIEventAdapter::SCROLL_DOWN):
190                         scale *= ratio;
191                         break;
192                     case(osgGA::GUIEventAdapter::SCROLL_2D):
193                         translation = increment*ea->getScrollingDeltaX();
194                         scale = powf(ratio, increment*ea->getScrollingDeltaY());
195                         break;
196                 }
197                 float center = _left+(_right-_left)*position.x();
198                 // OSG_NOTICE<<"translation = "<<translation<<", scale = "<<scale<<", x="<<position.x()<<", center="<<center<<std::endl;
199                 setVisibleRange(translation+center+(_left-center)*scale,
200                                 translation+center+(_right-center)*scale);
201 
202             }
203             break;
204         }
205         case(osgGA::GUIEventAdapter::KEYDOWN):
206         {
207             // OSG_NOTICE<<"Pressed key"<<ea->getKey()<<std::endl;
208             float delta = 0.02;
209             if (ea->getKey()==osgGA::GUIEventAdapter::KEY_Left) translateVisibleRange(-delta);
210             else if (ea->getKey()==osgGA::GUIEventAdapter::KEY_Right) translateVisibleRange(delta);
211             else if (ea->getKey()==osgGA::GUIEventAdapter::KEY_Up) scaleVisibleRange((_left+_right)*0.5f, -delta);
212             else if (ea->getKey()==osgGA::GUIEventAdapter::KEY_Down) scaleVisibleRange((_left+_right)*0.5f, delta);
213             break;
214         }
215         case(osgGA::GUIEventAdapter::KEYUP):
216             // OSG_NOTICE<<"Released key"<<ea->getKey()<<std::endl;
217             if (ea->getKey()==' ' ||ea->getKey()==osgGA::GUIEventAdapter::KEY_Home) resetVisibleRange();
218             break;
219         default:
220             break;
221     }
222     return false;
223 }
224 
createGraphicsImplementation()225 void TransferFunctionWidget::createGraphicsImplementation()
226 {
227 //    OSG_NOTICE<<"Create graphics"<<std::endl;
228 
229     typedef osg::TransferFunction1D::ColorMap ColorMap;
230     ColorMap& colorMap = _transferFunction->getColorMap();
231     if (colorMap.empty()) return;
232 
233     float depth = 0.0f;
234     float yMax = 0.0f;
235 
236     // find yMax
237     for(ColorMap::iterator itr = colorMap.begin();
238         itr != colorMap.end();
239         ++itr)
240     {
241         float y = itr->second[3];
242         if (y>yMax) yMax = y;
243     }
244 
245     float xScale = 1.0f/(_right-_left);
246     float xOffset = -_left;
247     float yScale = 1.0f/yMax;
248 
249     if (!_geode)
250     {
251         _geode = new osg::Geode;
252         addChild(_geode.get());
253     }
254 
255     {
256 
257         if (!_geometry)
258         {
259             _geometry = new osg::Geometry;
260             _geometry->setDataVariance(osg::Geometry::DYNAMIC);
261             _geometry->setUseDisplayList(false);
262             _geometry->setUseVertexBufferObjects(false);
263 
264             _geode->addDrawable(_geometry.get());
265 
266             osg::ref_ptr<osg::StateSet> stateset = _geometry->getOrCreateStateSet();
267 
268             stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED);
269             stateset->setMode(GL_BLEND, osg::StateAttribute::ON | osg::StateAttribute::PROTECTED);
270 
271             osg::ref_ptr<osg::AlphaFunc> alphaFunc = new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.0f);
272             stateset->setAttributeAndModes(alphaFunc.get(), osg::StateAttribute::ON | osg::StateAttribute::PROTECTED);
273 
274             osg::ref_ptr<osg::Image> image = new osg::Image;
275             image->allocateImage(1,1,1, GL_RGBA, GL_UNSIGNED_BYTE);
276             unsigned char* data = image->data();
277             data[0] = 255;
278             data[1] = 255;
279             data[2] = 255;
280             data[3] = 255;
281 
282             osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D;
283             texture->setImage(image.get());
284             texture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::NEAREST);
285             texture->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::NEAREST);
286             texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::CLAMP_TO_BORDER);
287             texture->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::CLAMP_TO_BORDER);
288             texture->setBorderColor(osg::Vec4(1.0f,1.0f,0.0f,0.0f));
289 
290             stateset->setTextureAttribute(0, texture.get());
291 
292             osg::ref_ptr<osg::TexGen> texgen = new osg::TexGen;
293             texgen->setMode(osg::TexGen::OBJECT_LINEAR);
294             texgen->setPlane(osg::TexGen::S, osg::Plane(1.0,0.0,0.0,0.0));
295             texgen->setPlane(osg::TexGen::T, osg::Plane(0.0,1.0,0.0,0.0));
296 
297             stateset->setTextureAttribute(0, texgen.get());
298             stateset->setTextureMode(0, GL_TEXTURE_GEN_S, osg::StateAttribute::ON | osg::StateAttribute::PROTECTED);
299             stateset->setTextureMode(0, GL_TEXTURE_GEN_T, osg::StateAttribute::ON | osg::StateAttribute::PROTECTED);
300             stateset->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON | osg::StateAttribute::PROTECTED);
301         }
302 
303 
304         if (!_vertices)
305         {
306             _vertices = new osg::Vec3Array;
307             _geometry->setVertexArray(_vertices.get());
308         }
309 
310         if (!_colours)
311         {
312             _colours = new osg::Vec4Array;
313             _geometry->setColorArray(_colours.get(), osg::Array::BIND_PER_VERTEX);
314         }
315 
316         osg::Vec4 background_color(1.0f, 1.0f, 1.0f, 0.1f);
317 
318         unsigned numColumnsRequired = colorMap.size();
319         _vertices->resize(0);
320         _vertices->reserve(numColumnsRequired*3);
321         for(ColorMap::iterator itr = colorMap.begin();
322             itr != colorMap.end();
323             ++itr)
324         {
325             float x = itr->first;
326             osg::Vec4 color = itr->second;
327 
328             float y = itr->second[3];
329             color[3] = 1.0f;
330 
331             _vertices->push_back(osg::Vec3((x+xOffset)*xScale, 0.0f, depth));
332             _colours->push_back(color);
333 
334             _vertices->push_back(osg::Vec3((x+xOffset)*xScale, y*yScale, depth));
335             _colours->push_back(color);
336 
337             _vertices->push_back(osg::Vec3((x+xOffset)*xScale, y*yScale, depth));
338             _colours->push_back(background_color);
339 
340             _vertices->push_back(osg::Vec3((x+xOffset)*xScale, yMax*yScale, depth));
341             _colours->push_back(background_color);
342         }
343 
344         if (!_background_primitives)
345         {
346             _background_primitives = new osg::DrawElementsUShort(GL_TRIANGLE_STRIP);
347             _geometry->addPrimitiveSet(_background_primitives.get());
348         }
349 
350         if (!_historgram_primitives)
351         {
352             _historgram_primitives = new osg::DrawElementsUShort(GL_TRIANGLE_STRIP);
353             _geometry->addPrimitiveSet(_historgram_primitives.get());
354         }
355 
356         if (!_outline_primitives)
357         {
358             _outline_primitives = new osg::DrawElementsUShort(GL_LINE_STRIP);
359             _geometry->addPrimitiveSet(_outline_primitives.get());
360         }
361 
362         _background_primitives->resize(0);
363         _historgram_primitives->resize(0);
364         _outline_primitives->resize(0);
365 
366         for(unsigned int i=0; i<numColumnsRequired; ++i)
367         {
368             int iv = i*4;
369 
370             _background_primitives->push_back(iv+3);
371             _background_primitives->push_back(iv+2);
372 
373             _historgram_primitives->push_back(iv+1);
374             _historgram_primitives->push_back(iv+0);
375 
376             _outline_primitives->push_back(iv+1);
377         }
378 
379     }
380 
381 #if 0
382     static bool first = true;
383     if (first)
384     {
385         osgDB::writeNodeFile(*_geode, "test.osgt");
386         first = false;
387     }
388 #endif
389 
390     _geometry->dirtyBound();
391 
392     // make sure the general widget geometry/state is created and _graphicsInitialized reset to false
393     Widget::createGraphicsImplementation();
394 }
395