Image 17.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 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 OSG_IMAGE
#define OSG_IMAGE 1

#include <osg/BufferObject>
#include <osg/Vec2>
#include <osg/Vec3>
#include <osg/Vec4>
#include <osg/FrameStamp>
#include <osg/StateAttribute>

#include <string>
#include <vector>

#ifndef GL_VERSION_1_2
    // 1.2 definitions...
    #define GL_BGR                          0x80E0
    #define GL_BGRA                         0x80E1
    #define GL_UNSIGNED_BYTE_3_3_2          0x8032
    #define GL_UNSIGNED_BYTE_2_3_3_REV      0x8362
    #define GL_UNSIGNED_SHORT_5_6_5         0x8363
    #define GL_UNSIGNED_SHORT_5_6_5_REV     0x8364
    #define GL_UNSIGNED_SHORT_4_4_4_4       0x8033
    #define GL_UNSIGNED_SHORT_4_4_4_4_REV   0x8365
    #define GL_UNSIGNED_SHORT_5_5_5_1       0x8034
    #define GL_UNSIGNED_SHORT_1_5_5_5_REV   0x8366
    #define GL_UNSIGNED_INT_8_8_8_8         0x8035
    #define GL_UNSIGNED_INT_8_8_8_8_REV     0x8367
    #define GL_UNSIGNED_INT_10_10_10_2      0x8036
    #define GL_UNSIGNED_INT_2_10_10_10_REV  0x8368
#endif

#ifndef GL_COMPRESSED_ALPHA
    #define GL_COMPRESSED_ALPHA             0x84E9
    #define GL_COMPRESSED_LUMINANCE         0x84EA
    #define GL_COMPRESSED_LUMINANCE_ALPHA   0x84EB
    #define GL_COMPRESSED_INTENSITY         0x84EC
    #define GL_COMPRESSED_RGB               0x84ED
    #define GL_COMPRESSED_RGBA              0x84EE
#endif


#ifndef GL_ABGR_EXT
#define GL_ABGR_EXT                         0x8000
#endif

#if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE)
    #define GL_RED                  0x1903
    #define GL_GREEN                0x1904
    #define GL_BLUE                 0x1905
    #define GL_DEPTH_COMPONENT      0x1902
    #define GL_STENCIL_INDEX        0x1901
#endif

#if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE) || defined(OSG_GL3_AVAILABLE)
    #define GL_BITMAP               0x1A00
    #define GL_COLOR_INDEX          0x1900
    #define GL_INTENSITY12          0x804C
    #define GL_INTENSITY16          0x804D
    #define GL_INTENSITY4           0x804A
    #define GL_INTENSITY8           0x804B
    #define GL_LUMINANCE12          0x8041
    #define GL_LUMINANCE12_ALPHA4   0x8046
    #define GL_LUMINANCE12_ALPHA12  0x8047
    #define GL_LUMINANCE16          0x8042
    #define GL_LUMINANCE16_ALPHA16  0x8048
    #define GL_LUMINANCE4           0x803F
    #define GL_LUMINANCE4_ALPHA4    0x8043
    #define GL_LUMINANCE6_ALPHA2    0x8044
    #define GL_LUMINANCE8           0x8040
    #define GL_LUMINANCE8_ALPHA8    0x8045
    #define GL_RGBA8                0x8058
    #define GL_PACK_ROW_LENGTH      0x0D02
#endif

#ifndef GL_PACK_SKIP_IMAGES
    #define GL_PACK_SKIP_IMAGES     0x806B
    #define GL_PACK_IMAGE_HEIGHT    0x806C
    #define GL_UNPACK_SKIP_IMAGES   0x806D
    #define GL_UNPACK_IMAGE_HEIGHT  0x806E
#endif

namespace osg {

// forward declare
class NodeVisitor;

/** Image class for encapsulating the storage texture image data. */
class OSG_EXPORT Image : public BufferData
{

    public :

        Image();
        
        /** Copy constructor using CopyOp to manage deep vs shallow copy. */
        Image(const Image& image,const CopyOp& copyop=CopyOp::SHALLOW_COPY);

        virtual Object* cloneType() const { return new Image(); }
        virtual Object* clone(const CopyOp& copyop) const { return new Image(*this,copyop); }
        virtual bool isSameKindAs(const Object* obj) const { return dynamic_cast<const Image*>(obj)!=0; }
        virtual const char* libraryName() const { return "osg"; }
        virtual const char* className() const { return "Image"; }

        virtual const GLvoid*   getDataPointer() const { return data(); }
        virtual unsigned int    getTotalDataSize() const { return getTotalSizeInBytesIncludingMipmaps(); }

        /** Return -1 if *this < *rhs, 0 if *this==*rhs, 1 if *this>*rhs. */
        virtual int compare(const Image& rhs) const;

        void setFileName(const std::string& fileName);
        inline const std::string& getFileName() const { return _fileName; }
        
        enum WriteHint {
            NO_PREFERENCE,
            STORE_INLINE,
            EXTERNAL_FILE
        };
        
        void setWriteHint(WriteHint writeHint) { _writeHint = writeHint; }
        WriteHint getWriteHint() const { return _writeHint; }
        
        enum AllocationMode {
            NO_DELETE,
            USE_NEW_DELETE,
            USE_MALLOC_FREE
        };
        
        /** Set the method used for deleting data once it goes out of scope. */
        void setAllocationMode(AllocationMode mode) { _allocationMode = mode; }

        /** Get the method used for deleting data once it goes out of scope. */
        AllocationMode getAllocationMode() const { return _allocationMode; }


        /** Allocate a pixel block of specified size and type. */
        virtual void allocateImage(int s,int t,int r,
                           GLenum pixelFormat,GLenum type,
                           int packing=1);
        
        
        /** Set the image dimensions, format and data. */
        virtual void setImage(int s,int t,int r,
                      GLint internalTextureformat,
                      GLenum pixelFormat,GLenum type,
                      unsigned char* data,
                      AllocationMode mode,
                      int packing=1);
            
        /** Read pixels from current frame buffer at specified position and size, using glReadPixels.
          * Create memory for storage if required, reuse existing pixel coords if possible.
        */
        virtual void readPixels(int x,int y,int width,int height,
                        GLenum pixelFormat,GLenum type);
            

        /** Read the contents of the current bound texture, handling compressed pixelFormats if present.
          * Create memory for storage if required, reuse existing pixel coords if possible.
        */
        virtual void readImageFromCurrentTexture(unsigned int contextID, bool copyMipMapsIfAvailable, GLenum type = GL_UNSIGNED_BYTE);


        /** Scale image to specified size. */
        void scaleImage(int s,int t,int r) { scaleImage(s,t,r, getDataType()); }

        /** Scale image to specified size and with specified data type. */
        virtual void scaleImage(int s,int t,int r, GLenum newDataType);

        /** Copy a source Image into a subpart of this Image at specified position.
          * Typically used to copy to an already allocated image, such as creating
          * a 3D image from a stack 2D images.
          * If this Image is empty then image data is created to
          * accomodate the source image in its offset position.
          * If source is NULL then no operation happens, this Image is left unchanged.
        */
        virtual void copySubImage(int s_offset, int t_offset, int r_offset, const osg::Image* source);


        enum Origin 
        {
            BOTTOM_LEFT,
            TOP_LEFT
        };
        
        /** Set the origin of the image.
          * The default value is BOTTOM_LEFT and is consistent with OpenGL.
          * TOP_LEFT is used for imagery that follows standard Imagery convention, such as movies,
          * and hasn't been flipped yet.  For such images one much flip the t axis of the tex coords.
          * to handle this origin position. */
        void setOrigin(Origin origin) { _origin = origin; }
        
        /** Get the origin of the image.*/
        Origin getOrigin() const { return _origin; }
        

        /** Width of image. */
        inline int s() const { return _s; }

        /** Height of image. */
        inline int t() const { return _t; }
        
        /** Depth of image. */
        inline int r() const { return _r; }
        
        void setInternalTextureFormat(GLint internalFormat);
        inline GLint getInternalTextureFormat() const { return _internalTextureFormat; }
        
        void setPixelFormat(GLenum pixelFormat);
        inline GLenum getPixelFormat() const { return _pixelFormat; }
        
        void setDataType(GLenum dataType);
        inline GLenum getDataType() const { return _dataType; }        
        
        void setPacking(unsigned int packing) { _packing = packing; }
        inline unsigned int getPacking() const { return _packing; }

        /** return true of the pixel format is an OpenGL compressed pixel format.*/
        bool isCompressed() const;

        /** Set the pixel aspect ratio, defined as the pixel width divided by the pixel height.*/
        inline void setPixelAspectRatio(float pixelAspectRatio) { _pixelAspectRatio = pixelAspectRatio; }

        /** Get the pixel aspect ratio.*/
        inline float getPixelAspectRatio() const { return _pixelAspectRatio; }
        
        /** Return the number of bits required for each pixel. */
        inline unsigned int getPixelSizeInBits() const { return computePixelSizeInBits(_pixelFormat,_dataType); }

        /** Return the number of bytes each row of pixels occupies once it has been packed. */
        inline unsigned int getRowSizeInBytes() const { return computeRowWidthInBytes(_s,_pixelFormat,_dataType,_packing); }

        /** Return the number of bytes each image (_s*_t) of pixels occupies. */
        inline unsigned int getImageSizeInBytes() const { return getRowSizeInBytes()*_t; }
        
        /** Return the number of bytes the whole row/image/volume of pixels occupies. */
        inline unsigned int getTotalSizeInBytes() const { return getImageSizeInBytes()*_r; }

        /** Return the number of bytes the whole row/image/volume of pixels occupies, including all mip maps if included. */
        unsigned int getTotalSizeInBytesIncludingMipmaps() const;

        /** Return true if the Image represent a valid and usable imagery.*/
        bool valid() const { return _s!=0 && _t!=0 && _r!=0 && _data!=0 && _dataType!=0; }

        /** Raw image data. */
        inline unsigned char* data() { return _data; }
        
        /** Raw const image data. */
        inline const unsigned char* data() const { return _data; }


        inline unsigned char* data(int column, int row=0,int image=0)
        {
            if (!_data) return NULL;
            return _data+(column*getPixelSizeInBits())/8+row*getRowSizeInBytes()+image*getImageSizeInBytes();
        }
        
        inline const unsigned char* data(int column, int row=0,int image=0) const
        {
            if (!_data) return NULL;
            return _data+(column*getPixelSizeInBits())/8+row*getRowSizeInBytes()+image*getImageSizeInBytes();
        }

        /** Get the color value for specified texcoord.*/
        Vec4 getColor(unsigned int s,unsigned t=0,unsigned r=0) const;

        /** Get the color value for specified texcoord.*/
        Vec4 getColor(const Vec2& texcoord) const { return getColor(Vec3(texcoord.x(),texcoord.y(),0.0f)); }

        /** Get the color value for specified texcoord.*/
        Vec4 getColor(const Vec3& texcoord) const;


        /** Flip the image horizontally. */
        void flipHorizontal();
        
        /** Flip the image vertically. */
        void flipVertical();


        /** Ensure image dimensions are a power of two.
          * Mipmapped textures require the image dimensions to be
          * power of two and are within the maxiumum texture size for
          * the host machine.
        */
        void ensureValidSizeForTexturing(GLint maxTextureSize);

        static bool isPackedType(GLenum type);
        static GLenum computePixelFormat(GLenum pixelFormat);
        static GLenum computeFormatDataType(GLenum pixelFormat);
        static unsigned int computeNumComponents(GLenum pixelFormat);
        static unsigned int computePixelSizeInBits(GLenum pixelFormat,GLenum type);
        static unsigned int computeRowWidthInBytes(int width,GLenum pixelFormat,GLenum type,int packing);
        static int computeNearestPowerOfTwo(int s,float bias=0.5f);
        static int computeNumberOfMipmapLevels(int s,int t = 1, int r = 1);

        /** Precomputed mipmaps stuff. */
        typedef std::vector< unsigned int > MipmapDataType;

        inline bool isMipmap() const {return !_mipmapData.empty();};

        unsigned int getNumMipmapLevels() const
        {
            return static_cast<unsigned int>(_mipmapData.size())+1;
        };

        /** Send offsets into data. It is assumed that first mipmap offset (index 0) is 0.*/
        inline void setMipmapLevels(const MipmapDataType& mipmapDataVector) { _mipmapData = mipmapDataVector; }
        
        inline const MipmapDataType& getMipmapLevels() const { return _mipmapData; }

        inline unsigned int getMipmapOffset(unsigned int mipmapLevel) const
        {
            if(mipmapLevel == 0)
                return 0;
            else if (mipmapLevel < getNumMipmapLevels())
               return _mipmapData[mipmapLevel-1];
            return 0;
        };
        
        inline unsigned char* getMipmapData(unsigned int mipmapLevel)
        {
           return _data+getMipmapOffset(mipmapLevel);
        }

        inline const unsigned char* getMipmapData(unsigned int mipmapLevel) const
        {
           return _data+getMipmapOffset(mipmapLevel);
        }

        /*inline const unsigned char* getMipmapData(unsigned int row, unsigned int column, unsigned int mipmapLevel) const
        {
           if (!_data) return NULL;
           return getMipmapData(mipmapLevel) + (column*getPixelSizeInBits())/8+row*getRowSizeInBytes();
        }*/

        /** Return true if this image is translucent - i.e. it has alpha values that are less 1.0 (when normalized). */
        virtual bool isImageTranslucent() const;

        /** Set the optional PixelBufferObject used to map the image memory efficiently to graphics memory. */ 
        void setPixelBufferObject(PixelBufferObject* buffer) { setBufferObject(buffer); }

        /** Get the PixelBufferObject.*/
        PixelBufferObject* getPixelBufferObject() { return dynamic_cast<PixelBufferObject*>(_bufferObject.get()); }

        /** Get the const PixelBufferObject.*/
        const PixelBufferObject* getPixelBufferObject() const { return dynamic_cast<const PixelBufferObject*>(_bufferObject.get()); }

        /** return whether the update(NodeVisitor* nv) should be required on each frame to enable proper working of osg::Image.*/
        virtual bool requiresUpdateCall() const { return false; }

        /** update method for osg::Image subclasses that update themselves during the update traversal.*/
        virtual void update(NodeVisitor* /*nv*/) {}

        /** convience update callback class that can be attached to StateAttribute (such as Textures) to ensure
          * that the Image::update(NodeVisitor*) method is called during the update traversal.  This callback
          * is automatically attached when Image::requiresUpdateCall() is true (it's false by default.)
          */
        struct OSG_EXPORT UpdateCallback : public osg::StateAttributeCallback
        {
            virtual void operator () (osg::StateAttribute* attr, osg::NodeVisitor* nv);
        };

        /** method for hinting 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. */
        virtual bool sendFocusHint(bool /*focus*/) { return false; }

        /** method for sending pointer events to images that are acting as front ends to interactive surfaces such as a vnc or browser window.  Return true if handled. */
        virtual bool sendPointerEvent(int /*x*/, int /*y*/, int /*buttonMask*/) { return false; }

        /** method for sending key events to images that are acting as front ends to interactive surfaces such as a vnc or browser window.  Return true if handled.*/
        virtual bool sendKeyEvent(int /*key*/, bool /*keyDown*/) { return false; }

        /** method for passing frame information to the custom Image classes, to be called only when objects associated with imagery are not culled.*/
        virtual void setFrameLastRendered(const osg::FrameStamp* /*frameStamp*/) {}

    protected :

        virtual ~Image();

        Image& operator = (const Image&) { return *this; }

        std::string _fileName;
        WriteHint   _writeHint;


        Origin _origin;

        int _s, _t, _r;
        GLint _internalTextureFormat;
        GLenum _pixelFormat;
        GLenum _dataType;
        unsigned int _packing;
        float _pixelAspectRatio;

        AllocationMode _allocationMode;
        unsigned char* _data;
        
        void deallocateData();
        
        void setData(unsigned char* data,AllocationMode allocationMode);

        MipmapDataType _mipmapData;
        
        ref_ptr<PixelBufferObject> _bufferObject;
};

class Geode;

/** Convenience function to be used by image loaders to generate a valid geode
  * to return for readNode().
  * Use the image's s and t values to scale the dimensions of the image.
*/
extern OSG_EXPORT Geode* createGeodeForImage(Image* image);
/** Convenience function to be used by image loaders to generate a valid geode
  * to return for readNode().
  * Use the specified s and t values to scale the dimensions of the image.
*/
extern OSG_EXPORT Geode* createGeodeForImage(Image* image,float s,float t);

}

#endif                                            // __SG_IMAGE_H