| 1 | /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2009 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 | #ifndef OSGVOLUME_LAYER |
|---|
| 15 | #define OSGVOLUME_LAYER 1 |
|---|
| 16 | |
|---|
| 17 | #include <osg/Image> |
|---|
| 18 | #include <osg/TransferFunction> |
|---|
| 19 | |
|---|
| 20 | #include <osgVolume/Locator> |
|---|
| 21 | #include <osgVolume/Property> |
|---|
| 22 | |
|---|
| 23 | namespace osgVolume { |
|---|
| 24 | |
|---|
| 25 | /** Data strucutre for passing details about the loading imagery on to osgVolume for use when setting up dimensions etc.*/ |
|---|
| 26 | class OSGVOLUME_EXPORT ImageDetails : public osg::Object |
|---|
| 27 | { |
|---|
| 28 | public: |
|---|
| 29 | |
|---|
| 30 | ImageDetails(); |
|---|
| 31 | |
|---|
| 32 | /** Copy constructor using CopyOp to manage deep vs shallow copy.*/ |
|---|
| 33 | ImageDetails(const ImageDetails&,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY); |
|---|
| 34 | |
|---|
| 35 | META_Object(osgVolume, ImageDetails); |
|---|
| 36 | |
|---|
| 37 | void setTexelOffset(const osg::Vec4& offset) { _texelOffset = offset; } |
|---|
| 38 | const osg::Vec4& getTexelOffset() const { return _texelOffset; } |
|---|
| 39 | |
|---|
| 40 | void setTexelScale(const osg::Vec4& scale) { _texelScale = scale; } |
|---|
| 41 | const osg::Vec4& getTexelScale() const { return _texelScale; } |
|---|
| 42 | |
|---|
| 43 | void setMatrix(osg::RefMatrix* matrix) { _matrix = matrix; } |
|---|
| 44 | osg::RefMatrix* getMatrix() { return _matrix.get(); } |
|---|
| 45 | const osg::RefMatrix* getMatrix() const { return _matrix.get(); } |
|---|
| 46 | |
|---|
| 47 | protected: |
|---|
| 48 | |
|---|
| 49 | osg::Vec4 _texelOffset; |
|---|
| 50 | osg::Vec4 _texelScale; |
|---|
| 51 | osg::ref_ptr<osg::RefMatrix> _matrix; |
|---|
| 52 | |
|---|
| 53 | }; |
|---|
| 54 | |
|---|
| 55 | /** Base class for representing a single layer of volume data.*/ |
|---|
| 56 | class OSGVOLUME_EXPORT Layer : public osg::Object |
|---|
| 57 | { |
|---|
| 58 | public: |
|---|
| 59 | |
|---|
| 60 | Layer(); |
|---|
| 61 | |
|---|
| 62 | /** Copy constructor using CopyOp to manage deep vs shallow copy.*/ |
|---|
| 63 | Layer(const Layer&,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY); |
|---|
| 64 | |
|---|
| 65 | META_Object(osgVolume, Layer); |
|---|
| 66 | |
|---|
| 67 | /** Set the file name of the data associated with this layer. */ |
|---|
| 68 | virtual void setFileName(const std::string& filename) { _filename = filename; } |
|---|
| 69 | |
|---|
| 70 | /** Get the file name of the layer. */ |
|---|
| 71 | virtual const std::string& getFileName() const { return _filename; } |
|---|
| 72 | |
|---|
| 73 | void setLocator(Locator* locator) { _locator = locator; } |
|---|
| 74 | Locator* getLocator() { return _locator.get(); } |
|---|
| 75 | const Locator* getLocator() const { return _locator.get(); } |
|---|
| 76 | |
|---|
| 77 | void setDefaultValue(const osg::Vec4& value) { _defaultValue = value; } |
|---|
| 78 | const osg::Vec4& getDefaultValue() const { return _defaultValue; } |
|---|
| 79 | |
|---|
| 80 | /** Set the minification texture filter to use when do texture associated with this layer.*/ |
|---|
| 81 | void setMinFilter(osg::Texture::FilterMode filter) { _minFilter = filter; } |
|---|
| 82 | |
|---|
| 83 | /** Get the minification texture filter to use when do texture associated with this layer.*/ |
|---|
| 84 | osg::Texture::FilterMode getMinFilter() const { return _minFilter; } |
|---|
| 85 | |
|---|
| 86 | /** Set the magniification texture filter to use when do texture associated with this layer.*/ |
|---|
| 87 | void setMagFilter(osg::Texture::FilterMode filter) { _magFilter = filter; } |
|---|
| 88 | |
|---|
| 89 | /** Get the magnification texture filter to use when do texture associated with this layer.*/ |
|---|
| 90 | osg::Texture::FilterMode getMagFilter() const { return _magFilter; } |
|---|
| 91 | |
|---|
| 92 | /** Return image associated with layer if supported. */ |
|---|
| 93 | virtual osg::Image* getImage() { return 0; } |
|---|
| 94 | |
|---|
| 95 | /** Return const image associated with layer if supported. */ |
|---|
| 96 | virtual const osg::Image* getImage() const { return 0; } |
|---|
| 97 | |
|---|
| 98 | |
|---|
| 99 | /** Set the Property (or Properties via the CompositeProperty) that informs the VolumeTechnique how this layer should be rendered.*/ |
|---|
| 100 | void setProperty(Property* property) { _property = property; } |
|---|
| 101 | |
|---|
| 102 | /** Get the Property that informs the VolumeTechnique how this layer should be rendered.*/ |
|---|
| 103 | Property* getProperty() { return _property.get(); } |
|---|
| 104 | |
|---|
| 105 | /** Get the const Property that informs the VolumeTechnique how this layer should be rendered.*/ |
|---|
| 106 | const Property* getProperty() const { return _property.get(); } |
|---|
| 107 | |
|---|
| 108 | /** Add a property, automatically creating a CompositePorperty if one isn't already assigned.*/ |
|---|
| 109 | void addProperty(Property* property); |
|---|
| 110 | |
|---|
| 111 | |
|---|
| 112 | /** Specify whether ImageLayer requires update traversal. */ |
|---|
| 113 | virtual bool requiresUpdateTraversal() const { return false; } |
|---|
| 114 | |
|---|
| 115 | /** Call update on the Layer.*/ |
|---|
| 116 | virtual void update(osg::NodeVisitor& /*nv*/) {} |
|---|
| 117 | |
|---|
| 118 | /** increment the modified count."*/ |
|---|
| 119 | virtual void dirty() {}; |
|---|
| 120 | |
|---|
| 121 | /** Set the modified count value. */ |
|---|
| 122 | virtual void setModifiedCount(unsigned int /*value*/) {}; |
|---|
| 123 | |
|---|
| 124 | /** Get modified count value. */ |
|---|
| 125 | virtual unsigned int getModifiedCount() const { return 0; } |
|---|
| 126 | |
|---|
| 127 | virtual osg::BoundingSphere computeBound() const; |
|---|
| 128 | |
|---|
| 129 | protected: |
|---|
| 130 | |
|---|
| 131 | virtual ~Layer(); |
|---|
| 132 | |
|---|
| 133 | std::string _filename; |
|---|
| 134 | osg::ref_ptr<Locator> _locator; |
|---|
| 135 | osg::Vec4 _defaultValue; |
|---|
| 136 | osg::Texture::FilterMode _minFilter; |
|---|
| 137 | osg::Texture::FilterMode _magFilter; |
|---|
| 138 | |
|---|
| 139 | osg::ref_ptr<Property> _property; |
|---|
| 140 | |
|---|
| 141 | }; |
|---|
| 142 | |
|---|
| 143 | class OSGVOLUME_EXPORT ImageLayer : public Layer |
|---|
| 144 | { |
|---|
| 145 | public: |
|---|
| 146 | |
|---|
| 147 | ImageLayer(osg::Image* image=0); |
|---|
| 148 | |
|---|
| 149 | /** Copy constructor using CopyOp to manage deep vs shallow copy.*/ |
|---|
| 150 | ImageLayer(const ImageLayer& imageLayer,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY); |
|---|
| 151 | |
|---|
| 152 | META_Object(osgVolume, ImageLayer); |
|---|
| 153 | |
|---|
| 154 | void setFileName(const std::string& filename) { _filename = filename; if (_image.valid()) _image->setFileName(filename); } |
|---|
| 155 | virtual const std::string& getFileName() const { return _image.get() ? _image->getFileName() : _filename; } |
|---|
| 156 | |
|---|
| 157 | void setImage(osg::Image* image); |
|---|
| 158 | |
|---|
| 159 | /** Return image associated with layer. */ |
|---|
| 160 | virtual osg::Image* getImage() { return _image.get(); } |
|---|
| 161 | |
|---|
| 162 | /** Return const image associated with layer. */ |
|---|
| 163 | virtual const osg::Image* getImage() const { return _image.get(); } |
|---|
| 164 | |
|---|
| 165 | |
|---|
| 166 | void setTexelOffset(const osg::Vec4& offset) { _texelOffset = offset; } |
|---|
| 167 | const osg::Vec4& getTexelOffset() const { return _texelOffset; } |
|---|
| 168 | |
|---|
| 169 | void setTexelScale(const osg::Vec4& scale) { _texelScale = scale; } |
|---|
| 170 | const osg::Vec4& getTexelScale() const { return _texelScale; } |
|---|
| 171 | |
|---|
| 172 | |
|---|
| 173 | /** Compute the min and max pixel colors.*/ |
|---|
| 174 | bool computeMinMax(osg::Vec4& min, osg::Vec4& max); |
|---|
| 175 | |
|---|
| 176 | /** Apply color transformation to pixels using c' = offset + c * scale .*/ |
|---|
| 177 | void offsetAndScaleImage(const osg::Vec4& offset, const osg::Vec4& scale); |
|---|
| 178 | |
|---|
| 179 | /** Compute the min max range of the image, and then remap this to a 0 to 1 range.*/ |
|---|
| 180 | void rescaleToZeroToOneRange(); |
|---|
| 181 | |
|---|
| 182 | /** Compute the min color component of the image and then translate and pixels by this offset to make the new min component 0.*/ |
|---|
| 183 | void translateMinToZero(); |
|---|
| 184 | |
|---|
| 185 | virtual bool requiresUpdateTraversal() const; |
|---|
| 186 | |
|---|
| 187 | virtual void update(osg::NodeVisitor& /*nv*/); |
|---|
| 188 | |
|---|
| 189 | virtual void dirty(); |
|---|
| 190 | virtual void setModifiedCount(unsigned int value); |
|---|
| 191 | virtual unsigned int getModifiedCount() const; |
|---|
| 192 | |
|---|
| 193 | protected: |
|---|
| 194 | |
|---|
| 195 | virtual ~ImageLayer() {} |
|---|
| 196 | |
|---|
| 197 | osg::Vec4 _texelOffset; |
|---|
| 198 | osg::Vec4 _texelScale; |
|---|
| 199 | osg::ref_ptr<osg::Image> _image; |
|---|
| 200 | |
|---|
| 201 | }; |
|---|
| 202 | |
|---|
| 203 | class OSGVOLUME_EXPORT CompositeLayer : public Layer |
|---|
| 204 | { |
|---|
| 205 | public: |
|---|
| 206 | |
|---|
| 207 | CompositeLayer(); |
|---|
| 208 | |
|---|
| 209 | /** Copy constructor using CopyOp to manage deep vs shallow copy.*/ |
|---|
| 210 | CompositeLayer(const CompositeLayer& compositeLayer,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY); |
|---|
| 211 | |
|---|
| 212 | META_Object(osgVolume, CompositeLayer); |
|---|
| 213 | |
|---|
| 214 | void clear(); |
|---|
| 215 | |
|---|
| 216 | void setFileName(unsigned int i, const std::string& filename) { if (i>=_layers.size()) _layers.resize(i+1); _layers[i].filename = filename; if (_layers[i].layer.valid()) _layers[i].layer->setFileName(filename); } |
|---|
| 217 | const std::string& getFileName(unsigned int i) const { return _layers[i].layer.valid() ? _layers[i].layer->getFileName() : _layers[i].filename; } |
|---|
| 218 | |
|---|
| 219 | void setLayer(unsigned int i, Layer* layer) { if (i>=_layers.size()) _layers.resize(i+1); _layers[i].layer = layer; } |
|---|
| 220 | Layer* getLayer(unsigned int i) { return i<_layers.size() ? _layers[i].layer.get() : 0; } |
|---|
| 221 | const Layer* getLayer(unsigned int i) const { return i<_layers.size() ? _layers[i].layer.get() : 0; } |
|---|
| 222 | |
|---|
| 223 | void addLayer(Layer* layer) { _layers.push_back(NameLayer(layer->getFileName(),layer)); } |
|---|
| 224 | |
|---|
| 225 | void removeLayer(unsigned int i) { _layers.erase(_layers.begin()+i); } |
|---|
| 226 | |
|---|
| 227 | unsigned int getNumLayers() const { return _layers.size(); } |
|---|
| 228 | |
|---|
| 229 | bool requiresUpdateTraversal() const; |
|---|
| 230 | |
|---|
| 231 | virtual void update(osg::NodeVisitor& /*nv*/); |
|---|
| 232 | |
|---|
| 233 | protected: |
|---|
| 234 | |
|---|
| 235 | virtual ~CompositeLayer() {} |
|---|
| 236 | |
|---|
| 237 | struct NameLayer |
|---|
| 238 | { |
|---|
| 239 | NameLayer() {} |
|---|
| 240 | |
|---|
| 241 | NameLayer(const NameLayer& cnl): |
|---|
| 242 | filename(cnl.filename), |
|---|
| 243 | layer(cnl.layer) {} |
|---|
| 244 | |
|---|
| 245 | NameLayer(const std::string& fn, Layer* l): |
|---|
| 246 | filename(fn), |
|---|
| 247 | layer(l) {} |
|---|
| 248 | |
|---|
| 249 | NameLayer& operator = (const NameLayer& cnl) |
|---|
| 250 | { |
|---|
| 251 | if (&cnl==this) return *this; |
|---|
| 252 | |
|---|
| 253 | filename = cnl.filename; |
|---|
| 254 | layer = cnl.layer; |
|---|
| 255 | return *this; |
|---|
| 256 | } |
|---|
| 257 | |
|---|
| 258 | std::string filename; |
|---|
| 259 | osg::ref_ptr<Layer> layer; |
|---|
| 260 | }; |
|---|
| 261 | |
|---|
| 262 | typedef std::vector< NameLayer > Layers; |
|---|
| 263 | |
|---|
| 264 | Layers _layers; |
|---|
| 265 | }; |
|---|
| 266 | |
|---|
| 267 | /** Compute a 3d image that represent the normal map of the specified 3d image.*/ |
|---|
| 268 | extern OSGVOLUME_EXPORT osg::Image* createNormalMapTexture(osg::Image* image_3d); |
|---|
| 269 | |
|---|
| 270 | /** Create an image that has a transfer function applied specified Image.*/ |
|---|
| 271 | extern OSGVOLUME_EXPORT osg::Image* applyTransferFunction(osg::Image* image, osg::TransferFunction1D* transferFunction); |
|---|
| 272 | |
|---|
| 273 | } |
|---|
| 274 | |
|---|
| 275 | #endif |
|---|