1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
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.
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.
17#include <osg/BufferObject>
22#include <osg/FrameStamp>
23#include <osg/StateAttribute>
31 #define GL_BGRA 0x80E1
32 #define GL_UNSIGNED_BYTE_3_3_2 0x8032
33 #define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362
34 #define GL_UNSIGNED_SHORT_5_6_5 0x8363
35 #define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364
36 #define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
37 #define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365
38 #define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
39 #define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366
40 #define GL_UNSIGNED_INT_8_8_8_8 0x8035
41 #define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
42 #define GL_UNSIGNED_INT_10_10_10_2 0x8036
43 #define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368
46#ifndef GL_COMPRESSED_ALPHA
47 #define GL_COMPRESSED_ALPHA 0x84E9
48 #define GL_COMPRESSED_LUMINANCE 0x84EA
49 #define GL_COMPRESSED_LUMINANCE_ALPHA 0x84EB
50 #define GL_COMPRESSED_INTENSITY 0x84EC
51 #define GL_COMPRESSED_RGB 0x84ED
52 #define GL_COMPRESSED_RGBA 0x84EE
57#define GL_ABGR_EXT 0x8000
60#if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE)
62 #define GL_GREEN 0x1904
63 #define GL_BLUE 0x1905
64 #define GL_DEPTH_COMPONENT 0x1902
67#if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE) || defined(OSG_GLES3_AVAILABLE)
68 #define GL_STENCIL_INDEX 0x1901
71#if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE) || defined(OSG_GLES3_AVAILABLE) || defined(OSG_GL3_AVAILABLE)
72 #define GL_ALPHA4 0x803B
73 #define GL_ALPHA8 0x803C
74 #define GL_ALPHA12 0x803D
75 #define GL_ALPHA16 0x803E
76 #define GL_BITMAP 0x1A00
77 #define GL_COLOR_INDEX 0x1900
78 #define GL_INTENSITY12 0x804C
79 #define GL_INTENSITY16 0x804D
80 #define GL_INTENSITY 0x8049
81 #define GL_INTENSITY4 0x804A
82 #define GL_INTENSITY8 0x804B
83 #define GL_LUMINANCE12 0x8041
84 #define GL_LUMINANCE12_ALPHA4 0x8046
85 #define GL_LUMINANCE12_ALPHA12 0x8047
86 #define GL_LUMINANCE16 0x8042
87 #define GL_LUMINANCE16_ALPHA16 0x8048
88 #define GL_LUMINANCE4 0x803F
89 #define GL_LUMINANCE4_ALPHA4 0x8043
90 #define GL_LUMINANCE6_ALPHA2 0x8044
91 #define GL_LUMINANCE8 0x8040
92 #define GL_LUMINANCE8_ALPHA8 0x8045
93 #define GL_RGBA8 0x8058
94 #define GL_RGBA16 0x805B
95 #define GL_PACK_ROW_LENGTH 0x0D02
98#ifndef GL_PACK_SKIP_IMAGES
99 #define GL_PACK_SKIP_IMAGES 0x806B
100 #define GL_PACK_IMAGE_HEIGHT 0x806C
101 #define GL_UNPACK_SKIP_IMAGES 0x806D
102 #define GL_UNPACK_IMAGE_HEIGHT 0x806E
105#ifndef GL_OES_compressed_ETC1_RGB8_texture
106 #define GL_ETC1_RGB8_OES 0x8D64
109#ifndef GL_ARB_ES3_compatibility
110 #define GL_COMPRESSED_RGB8_ETC2 0x9274
111 #define GL_COMPRESSED_SRGB8_ETC2 0x9275
112 #define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276
113 #define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277
114 #define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278
115 #define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279
116 #define GL_COMPRESSED_R11_EAC 0x9270
117 #define GL_COMPRESSED_SIGNED_R11_EAC 0x9271
118 #define GL_COMPRESSED_RG11_EAC 0x9272
119 #define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273
122#ifndef GL_KHR_texture_compression_astc_hdr
123#define GL_KHR_texture_compression_astc_hdr 1
124#define GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93B0
125#define GL_COMPRESSED_RGBA_ASTC_5x4_KHR 0x93B1
126#define GL_COMPRESSED_RGBA_ASTC_5x5_KHR 0x93B2
127#define GL_COMPRESSED_RGBA_ASTC_6x5_KHR 0x93B3
128#define GL_COMPRESSED_RGBA_ASTC_6x6_KHR 0x93B4
129#define GL_COMPRESSED_RGBA_ASTC_8x5_KHR 0x93B5
130#define GL_COMPRESSED_RGBA_ASTC_8x6_KHR 0x93B6
131#define GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93B7
132#define GL_COMPRESSED_RGBA_ASTC_10x5_KHR 0x93B8
133#define GL_COMPRESSED_RGBA_ASTC_10x6_KHR 0x93B9
134#define GL_COMPRESSED_RGBA_ASTC_10x8_KHR 0x93BA
135#define GL_COMPRESSED_RGBA_ASTC_10x10_KHR 0x93BB
136#define GL_COMPRESSED_RGBA_ASTC_12x10_KHR 0x93BC
137#define GL_COMPRESSED_RGBA_ASTC_12x12_KHR 0x93BD
138#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR 0x93D0
139#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR 0x93D1
140#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR 0x93D2
141#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR 0x93D3
142#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR 0x93D4
143#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR 0x93D5
144#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR 0x93D6
145#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR 0x93D7
146#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR 0x93D8
147#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR 0x93D9
148#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR 0x93DA
149#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR 0x93DB
150#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR 0x93DC
151#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR 0x93DD
152#endif /* GL_KHR_texture_compression_astc_hdr */
154#ifndef GL_DEPTH_COMPONENT
155#define GL_DEPTH_COMPONENT 0x1902
158#ifndef GL_VERSION_1_4
159#define GL_DEPTH_COMPONENT16 0x81A5
160#define GL_DEPTH_COMPONENT24 0x81A6
161#define GL_DEPTH_COMPONENT32 0x81A7
164#ifndef GL_DEPTH_COMPONENT32F
165#define GL_DEPTH_COMPONENT32F 0x8CAC
168#ifndef GL_DEPTH_COMPONENT32F_NV
169#define GL_DEPTH_COMPONENT32F_NV 0x8DAB
177/** Image class for encapsulating the storage texture image data. */
178class OSG_EXPORT Image : public BufferData
185 /** Copy constructor using CopyOp to manage deep vs shallow copy. */
186 Image(const Image& image,const CopyOp& copyop=CopyOp::SHALLOW_COPY);
188 virtual Object* cloneType() const { return new Image(); }
189 virtual Object* clone(const CopyOp& copyop) const { return new Image(*this,copyop); }
190 virtual bool isSameKindAs(const Object* obj) const { return dynamic_cast<const Image*>(obj)!=0; }
191 virtual const char* libraryName() const { return "osg"; }
192 virtual const char* className() const { return "Image"; }
194 virtual osg::Image* asImage() { return this; }
195 virtual const osg::Image* asImage() const { return this; }
197 virtual const GLvoid* getDataPointer() const { return data(); }
198 virtual unsigned int getTotalDataSize() const { return getTotalSizeInBytesIncludingMipmaps(); }
200 /** Return -1 if *this < *rhs, 0 if *this==*rhs, 1 if *this>*rhs. */
201 virtual int compare(const Image& rhs) const;
203 void setFileName(const std::string& fileName);
204 inline const std::string& getFileName() const { return _fileName; }
212 void setWriteHint(WriteHint writeHint) { _writeHint = writeHint; }
213 WriteHint getWriteHint() const { return _writeHint; }
215 enum AllocationMode {
221 /** Set the method used for deleting data once it goes out of scope. */
222 void setAllocationMode(AllocationMode mode) { _allocationMode = mode; }
224 /** Get the method used for deleting data once it goes out of scope. */
225 AllocationMode getAllocationMode() const { return _allocationMode; }
228 /** Allocate a pixel block of specified size and type. */
229 virtual void allocateImage(int s,int t,int r,
230 GLenum pixelFormat,GLenum type,
234 /** Set the image dimensions, format and data. */
235 virtual void setImage(int s,int t,int r,
236 GLint internalTextureformat,
237 GLenum pixelFormat,GLenum type,
240 int packing=1, int rowLength=0);
242 /** Read pixels from current frame buffer at specified position and size, using glReadPixels.
243 * Create memory for storage if required, reuse existing pixel coords if possible.
245 virtual void readPixels(int x,int y,int width,int height,
246 GLenum pixelFormat, GLenum type, int packing=1);
249 /** Read the contents of the current bound texture, handling compressed pixelFormats if present.
250 * Create memory for storage if required, reuse existing pixel coords if possible.
252 virtual void readImageFromCurrentTexture(unsigned int contextID, bool copyMipMapsIfAvailable, GLenum type = GL_UNSIGNED_BYTE, unsigned int face = 0);
254 /** swap the data and settings between two image objects.*/
255 void swap(osg::Image& rhs);
257 /** Scale image to specified size. */
258 void scaleImage(int s,int t,int r) { scaleImage(s,t,r, getDataType()); }
260 /** Scale image to specified size and with specified data type. */
261 virtual void scaleImage(int s,int t,int r, GLenum newDataType);
263 /** Copy a source Image into a subpart of this Image at specified position.
264 * Typically used to copy to an already allocated image, such as creating
265 * a 3D image from a stack 2D images.
266 * If this Image is empty then image data is created to
267 * accommodate the source image in its offset position.
268 * If source is NULL then no operation happens, this Image is left unchanged.
270 virtual void copySubImage(int s_offset, int t_offset, int r_offset, const osg::Image* source);
279 /** Set the origin of the image.
280 * The default value is BOTTOM_LEFT and is consistent with OpenGL.
281 * TOP_LEFT is used for imagery that follows standard Imagery convention, such as movies,
282 * and hasn't been flipped yet. For such images one much flip the t axis of the tex coords.
283 * to handle this origin position. */
284 void setOrigin(Origin origin) { _origin = origin; }
286 /** Get the origin of the image.*/
287 Origin getOrigin() const { return _origin; }
290 /** Width of image. */
291 inline int s() const { return _s; }
293 /** Height of image. */
294 inline int t() const { return _t; }
296 /** Depth of image. */
297 inline int r() const { return _r; }
299 void setRowLength(int length);
300 inline int getRowLength() const { return _rowLength; }
302 void setInternalTextureFormat(GLint internalFormat);
303 inline GLint getInternalTextureFormat() const { return _internalTextureFormat; }
305 void setPixelFormat(GLenum pixelFormat);
306 inline GLenum getPixelFormat() const { return _pixelFormat; }
308 void setDataType(GLenum dataType);
309 inline GLenum getDataType() const { return _dataType; }
311 void setPacking(unsigned int packing) { _packing = packing; }
312 inline unsigned int getPacking() const { return _packing; }
314 /** Return true of the pixel format is an OpenGL compressed pixel format.*/
315 bool isCompressed() const;
317 /** Set the pixel aspect ratio, defined as the pixel width divided by the pixel height.*/
318 inline void setPixelAspectRatio(float pixelAspectRatio) { _pixelAspectRatio = pixelAspectRatio; }
320 /** Get the pixel aspect ratio.*/
321 inline float getPixelAspectRatio() const { return _pixelAspectRatio; }
323 /** Return the number of bits required for each pixel. */
324 inline unsigned int getPixelSizeInBits() const { return computePixelSizeInBits(_pixelFormat,_dataType); }
326 /** Return the number of bytes each row of pixels occupies once it has been packed. */
327 inline unsigned int getRowSizeInBytes() const { return computeRowWidthInBytes(_s,_pixelFormat,_dataType,_packing); }
329 /** Return the number of bytes between each successive row.
330 * Note, getRowSizeInBytes() will only equal getRowStepInBytes() when isDataContiguous() return true. */
331 inline unsigned int getRowStepInBytes() const { return computeRowWidthInBytes(_rowLength==0?_s:_rowLength,_pixelFormat,_dataType,_packing); }
333 /** Return the number of bytes each image (_s*_t) of pixels occupies. */
334 inline unsigned int getImageSizeInBytes() const { return getRowSizeInBytes()*_t; }
336 /** Return the number of bytes between each successive image.
337 * Note, getImageSizeInBytes() will only equal getImageStepInBytes() when isDataContiguous() return true. */
338 inline unsigned int getImageStepInBytes() const { return getRowStepInBytes()*_t; }
340 /** Return the number of bytes the whole row/image/volume of pixels occupies. */
341 inline unsigned int getTotalSizeInBytes() const { return getImageSizeInBytes()*_r; }
343 /** Return the number of bytes the whole row/image/volume of pixels occupies, including all mip maps if included. */
344 unsigned int getTotalSizeInBytesIncludingMipmaps() const;
346 /** Return true if the Image represent a valid and usable imagery.*/
347 bool valid() const { return _s!=0 && _t!=0 && _r!=0 && _data!=0 && _dataType!=0; }
350 * Note, data in successive rows may not be contiguous, isDataContiguous() return false then you should
351 * take care to access the data per row rather than treating the whole data as a single block. */
352 inline unsigned char* data() { return _data; }
354 /** Raw const image data.
355 * Note, data in successive rows may not be contiguous, isDataContiguous() return false then you should
356 * take care to access the data per row rather than treating the whole data as a single block. */
357 inline const unsigned char* data() const { return _data; }
359 inline unsigned char* data(unsigned int column, unsigned int row = 0, unsigned int image = 0)
361 if (!_data) return NULL;
362 return _data+(column*getPixelSizeInBits())/8+row*getRowStepInBytes()+image*getImageSizeInBytes();
365 inline const unsigned char* data(unsigned int column, unsigned int row = 0, unsigned int image = 0) const
367 if (!_data) return NULL;
368 return _data+(column*getPixelSizeInBits())/8+row*getRowStepInBytes()+image*getImageSizeInBytes();
371 /** return true if the data stored in the image is a contiguous block of data.*/
372 bool isDataContiguous() const { return _rowLength==0 || _rowLength==_s; }
374 /** Convenience class for assisting the copying of image data when the image data isn't contiguous.*/
375 class OSG_EXPORT DataIterator
378 DataIterator(const Image* image);
379 DataIterator(const DataIterator& ri);
382 /** advance iterator to next block of data.*/
385 /** is iterator valid.*/
386 bool valid() const { return _currentPtr!=0; }
388 /** data pointer of current block to copy.*/
389 const unsigned char* data() const { return _currentPtr; }
391 /** Size of current block to copy.*/
392 unsigned int size() const { return _currentSize; }
399 const osg::Image* _image;
402 unsigned int _mipmapNum;
403 const unsigned char* _currentPtr;
404 unsigned int _currentSize;
407 /** Get the color value for specified texcoord.*/
408 Vec4 getColor(unsigned int s,unsigned t=0,unsigned r=0) const;
410 /** Get the color value for specified texcoord.*/
411 Vec4 getColor(const Vec2& texcoord) const { return getColor(Vec3(texcoord.x(),texcoord.y(),0.0f)); }
413 /** Get the color value for specified texcoord.*/
414 Vec4 getColor(const Vec3& texcoord) const;
416 /** Set the color value for specified texcoord.*/
417 void setColor(const osg::Vec4& color, unsigned int s, unsigned int t=0, unsigned int r=0);
419 /** Set the color value for specified texcoord. Note texcoord is clamped to edge.*/
420 void setColor(const osg::Vec4& color, const osg::Vec2& texcoord ) { setColor(color, osg::Vec3(texcoord, 0.0f)); }
422 /** Set the color value for specified texcoord. Note texcoord is clamped to edge.*/
423 void setColor(const osg::Vec4& color, const osg::Vec3& texcoord );
425 /** Flip the image horizontally, around s dimension. */
426 void flipHorizontal();
428 /** Flip the image vertically, around t dimension. */
431 /** Flip the image around the r dimension. Only relevant for 3D textures. */
434 /** Ensure image dimensions are a power of two.
435 * Mipmapped textures require the image dimensions to be
436 * power of two and are within the maximum texture size for
439 void ensureValidSizeForTexturing(GLint maxTextureSize);
441 static bool isPackedType(GLenum type);
442 static GLenum computePixelFormat(GLenum pixelFormat);
443 static GLenum computeFormatDataType(GLenum pixelFormat);
445 /** return the dimensions of a block of compressed pixels */
446 static osg::Vec3i computeBlockFootprint(GLenum pixelFormat);
448 /** return the size in bytes of a block of compressed pixels */
449 static unsigned int computeBlockSize(GLenum pixelFormat, GLenum packing);
450 static unsigned int computeNumComponents(GLenum pixelFormat);
451 static unsigned int computePixelSizeInBits(GLenum pixelFormat,GLenum type);
452 static unsigned int computeRowWidthInBytes(int width,GLenum pixelFormat,GLenum type,int packing);
453 static unsigned int computeImageSizeInBytes(int width,int height, int depth, GLenum pixelFormat, GLenum type, int packing = 1, int slice_packing = 1, int image_packing = 1);
454 static int roudUpToMultiple(int s, int pack);
455 static int computeNearestPowerOfTwo(int s,float bias=0.5f);
456 static int computeNumberOfMipmapLevels(int s,int t = 1, int r = 1);
458 /** Precomputed mipmaps stuff. */
459 typedef std::vector< unsigned int > MipmapDataType;
461 inline bool isMipmap() const {return !_mipmapData.empty();};
463 unsigned int getNumMipmapLevels() const
465 return static_cast<unsigned int>(_mipmapData.size())+1;
468 /** Send offsets into data. It is assumed that first mipmap offset (index 0) is 0.*/
469 inline void setMipmapLevels(const MipmapDataType& mipmapDataVector) { _mipmapData = mipmapDataVector; }
471 inline const MipmapDataType& getMipmapLevels() const { return _mipmapData; }
473 inline unsigned int getMipmapOffset(unsigned int mipmapLevel) const
477 else if (mipmapLevel < getNumMipmapLevels())
478 return _mipmapData[mipmapLevel-1];
482 inline unsigned char* getMipmapData(unsigned int mipmapLevel)
484 return _data+getMipmapOffset(mipmapLevel);
487 inline const unsigned char* getMipmapData(unsigned int mipmapLevel) const
489 return _data+getMipmapOffset(mipmapLevel);
492 /** returns false for texture formats that do not support texture subloading */
493 bool supportsTextureSubloading() const;
495 /** Return true if this image is translucent - i.e. it has alpha values that are less 1.0 (when normalized). */
496 virtual bool isImageTranslucent() const;
498 /** Set the optional PixelBufferObject used to map the image memory efficiently to graphics memory. */
499 void setPixelBufferObject(PixelBufferObject* buffer) { setBufferObject(buffer); }
501 /** Get the PixelBufferObject.*/
502 PixelBufferObject* getPixelBufferObject() { return dynamic_cast<PixelBufferObject*>(getBufferObject()); }
504 /** Get the const PixelBufferObject.*/
505 const PixelBufferObject* getPixelBufferObject() const { return dynamic_cast<const PixelBufferObject*>(getBufferObject()); }
507 /** Return whether the update(NodeVisitor* nv) should be required on each frame to enable proper working of osg::Image.*/
508 virtual bool requiresUpdateCall() const { return false; }
510 /** update method for osg::Image subclasses that update themselves during the update traversal.*/
511 virtual void update(NodeVisitor* /*nv*/) {}
513 /** Convenience update callback class that can be attached to a StateAttribute (such as Textures) to ensure
514 * that the Image::update(NodeVisitor*) method is called during the update traversal. This callback
515 * is automatically attached when Image::requiresUpdateCall() is true (it's false by default.)
517 struct OSG_EXPORT UpdateCallback : public osg::StateAttributeCallback
519 virtual void operator () (osg::StateAttribute* attr, osg::NodeVisitor* nv);
522 /** Hint whether to enable or disable focus to images acting as front ends to interactive surfaces such as a vnc or browser window. Return true if handled. */
523 virtual bool sendFocusHint(bool /*focus*/) { return false; }
525 /** Send pointer events to images that are acting as front ends to interactive surfaces such as a vnc or browser window. Return true if handled. */
526 virtual bool sendPointerEvent(int /*x*/, int /*y*/, int /*buttonMask*/) { return false; }
528 /** Send key events to images that are acting as front ends to interactive surfaces such as a vnc or browser window. Return true if handled.*/
529 virtual bool sendKeyEvent(int /*key*/, bool /*keyDown*/) { return false; }
531 /** Pass frame information to the custom Image classes, to be called only when objects associated with imagery are not culled.*/
532 virtual void setFrameLastRendered(const osg::FrameStamp* /*frameStamp*/) {}
534 class DimensionsChangedCallback : public osg::Referenced {
536 DimensionsChangedCallback() : osg::Referenced() {}
537 virtual void operator()(osg::Image* image) = 0;
540 typedef std::vector< osg::ref_ptr<DimensionsChangedCallback> > DimensionsChangedCallbackVector;
542 void addDimensionsChangedCallback(DimensionsChangedCallback* cb);
543 void removeDimensionsChangedCallback(DimensionsChangedCallback* cb);
549 Image& operator = (const Image&) { return *this; }
551 void handleDimensionsChangedCallbacks()
553 for(DimensionsChangedCallbackVector::iterator i = _dimensionsChangedCallbacks.begin(); i != _dimensionsChangedCallbacks.end(); ++i)
555 (*i)->operator()(this);
559 std::string _fileName;
560 WriteHint _writeHint;
566 GLint _internalTextureFormat;
569 unsigned int _packing;
570 float _pixelAspectRatio;
572 AllocationMode _allocationMode;
573 unsigned char* _data;
575 void deallocateData();
577 void setData(unsigned char* data,AllocationMode allocationMode);
579 MipmapDataType _mipmapData;
581 DimensionsChangedCallbackVector _dimensionsChangedCallbacks;
586/** Convenience function to be used by image loaders to generate a valid geode
587 * to return for readNode().
588 * Use the image's s and t values to scale the dimensions of the image.
590extern OSG_EXPORT Geode* createGeodeForImage(Image* image);
592template<class T> Geode* createGeodeForImage(const ref_ptr<T>& image) { return createGeodeForImage(image.get()); }
595/** Convenience function to be used by image loaders to generate a valid geode
596 * to return for readNode().
597 * Use the specified s and t values to scale the dimensions of the image.
599extern OSG_EXPORT Geode* createGeodeForImage(Image* image, float s, float t);
601template<class T> Geode* createGeodeForImage(const ref_ptr<T>& image, float s, float t) { return createGeodeForImage(image.get(), s, t); }
605#endif // __SG_IMAGE_H