diff --git a/examples/osgphotoalbum/PhotoArchive.cpp b/examples/osgphotoalbum/PhotoArchive.cpp index 1cf750ee7..76db14477 100644 --- a/examples/osgphotoalbum/PhotoArchive.cpp +++ b/examples/osgphotoalbum/PhotoArchive.cpp @@ -222,6 +222,7 @@ void PhotoArchive::buildArchive(const std::string& filename, const FileNameList& osg::PixelStorageModes psm; psm.pack_alignment = image->getPacking(); + psm.pack_row_length = image->getRowLength(); psm.unpack_alignment = image->getPacking(); GLint status = osg::gluScaleImage(&psm, image->getPixelFormat(), @@ -289,6 +290,7 @@ void PhotoArchive::buildArchive(const std::string& filename, const FileNameList& osg::PixelStorageModes psm; psm.pack_alignment = image->getPacking(); + psm.pack_row_length = image->getRowLength(); psm.unpack_alignment = image->getPacking(); GLint status = osg::gluScaleImage(&psm, image->getPixelFormat(), diff --git a/examples/osgscreencapture/osgscreencapture.cpp b/examples/osgscreencapture/osgscreencapture.cpp index c899d7faf..9de19b634 100644 --- a/examples/osgscreencapture/osgscreencapture.cpp +++ b/examples/osgscreencapture/osgscreencapture.cpp @@ -384,6 +384,7 @@ void WindowCaptureCallback::ContextData::singlePBO(osg::GLBufferObject::Extensio if(src) { memcpy(image->data(), src, image->getTotalSizeInBytes()); + ext->glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB); } diff --git a/examples/osgtexture2D/osgtexture2D.cpp b/examples/osgtexture2D/osgtexture2D.cpp index b0329f01d..15cdc8ad2 100644 --- a/examples/osgtexture2D/osgtexture2D.cpp +++ b/examples/osgtexture2D/osgtexture2D.cpp @@ -536,8 +536,50 @@ public: _prevTime(0.0) { +#if 1 + osg::ref_ptr originalImage = osgDB::readImageFile("Images/dog_left_eye.jpg"); + + osg::ref_ptr subImage = new osg::Image; + subImage->setUserData(originalImage.get()); // attach the originalImage as user data to prevent it being deleted. + + // now assign the appropriate portion data from the originalImage + subImage->setImage(originalImage->s()/2, originalImage->t()/2, originalImage->r(), // half the width and height + originalImage->getInternalTextureFormat(), // same internal texture format + originalImage->getPixelFormat(),originalImage->getDataType(), // same pixel foramt and data type + originalImage->data(originalImage->s()/4,originalImage->t()/4), // offset teh start point to 1/4 into the image + osg::Image::NO_DELETE, // don't attempt to delete the image data, leave this to the originalImage + originalImage->getPacking(), // use the the same packing + originalImage->s()); // use the width of the original image as the row width + + + subImage->setPixelBufferObject(new osg::PixelBufferObject(subImage.get())); + +#if 0 + OSG_NOTICE<<"orignalImage iterator"<s()<<", "<t()<(itr.data()); d<(itr.data()+itr.size()); ++d) + { + *d = 255-*d; + } + } +#endif + + _imageList.push_back(subImage.get()); + +#else _imageList.push_back(osgDB::readImageFile("Images/dog_left_eye.jpg")); +#endif _textList.push_back("Subloaded Image 1 - dog_left_eye.jpg"); _imageList.push_back(osgDB::readImageFile("Images/dog_right_eye.jpg")); @@ -584,6 +626,7 @@ public: protected: + typedef std::vector< osg::ref_ptr > ImageList; typedef std::vector TextList; diff --git a/include/osg/Array b/include/osg/Array index 19d7396c0..47266df35 100644 --- a/include/osg/Array +++ b/include/osg/Array @@ -104,6 +104,10 @@ class OSG_EXPORT Array : public BufferData Type getType() const { return _arrayType; } GLint getDataSize() const { return _dataSize; } GLenum getDataType() const { return _dataType; } + + virtual osg::Array* asArray() { return this; } + virtual const osg::Array* asArray() const { return this; } + virtual const GLvoid* getDataPointer() const = 0; virtual unsigned int getTotalDataSize() const = 0; virtual unsigned int getNumElements() const = 0; diff --git a/include/osg/BufferObject b/include/osg/BufferObject index 00dc421dc..4b9d5f3c6 100644 --- a/include/osg/BufferObject +++ b/include/osg/BufferObject @@ -620,6 +620,15 @@ class OSG_EXPORT BufferData : public Object virtual const GLvoid* getDataPointer() const = 0; virtual unsigned int getTotalDataSize() const = 0; + virtual osg::Array* asArray() { return 0; } + virtual const osg::Array* asArray() const { return 0; } + + virtual osg::PrimitiveSet* asPrimitiveSet() { return 0; } + virtual const osg::PrimitiveSet* asPrimitiveSet() const { return 0; } + + virtual osg::Image* asImage() { return 0; } + virtual const osg::Image* asImage() const { return 0; } + void setBufferObject(BufferObject* bufferObject); BufferObject* getBufferObject() { return _bufferObject.get(); } const BufferObject* getBufferObject() const { return _bufferObject.get(); } diff --git a/include/osg/Image b/include/osg/Image index 95f9351b7..7c0083f80 100644 --- a/include/osg/Image +++ b/include/osg/Image @@ -114,6 +114,9 @@ class OSG_EXPORT Image : public BufferData virtual const char* libraryName() const { return "osg"; } virtual const char* className() const { return "Image"; } + virtual osg::Image* asImage() { return this; } + virtual const osg::Image* asImage() const { return this; } + virtual const GLvoid* getDataPointer() const { return data(); } virtual unsigned int getTotalDataSize() const { return getTotalSizeInBytesIncludingMipmaps(); } @@ -157,7 +160,7 @@ class OSG_EXPORT Image : public BufferData GLenum pixelFormat,GLenum type, unsigned char* data, AllocationMode mode, - int packing=1); + int packing=1, int rowLength=0); /** 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. @@ -213,6 +216,9 @@ class OSG_EXPORT Image : public BufferData /** Depth of image. */ inline int r() const { return _r; } + + void setRowLength(int length) { _rowLength = length; } + inline int getRowLength() const { return _rowLength; } void setInternalTextureFormat(GLint internalFormat); inline GLint getInternalTextureFormat() const { return _internalTextureFormat; } @@ -241,9 +247,17 @@ class OSG_EXPORT Image : public BufferData /** 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 between each successive row. + * Note, getRowSizeInBytes() will only equal getRowStepInBytes() when isDataContiguous() return true. */ + inline unsigned int getRowStepInBytes() const { return computeRowWidthInBytes(_rowLength==0?_s:_rowLength,_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 between each successive image. + * Note, getImageSizeInBytes() will only equal getImageStepInBytes() when isDataContiguous() return true. */ + inline unsigned int getImageStepInBytes() const { return getRowStepInBytes()*_t; } + /** Return the number of bytes the whole row/image/volume of pixels occupies. */ inline unsigned int getTotalSizeInBytes() const { return getImageSizeInBytes()*_r; } @@ -253,25 +267,64 @@ class OSG_EXPORT Image : public BufferData /** 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. */ + /** Raw image data. + * Note, data in successive rows may not be contiguous, isDataContiguous() return false then you should + * take care to access the data per row rather than treating the whole data as a single block. */ inline unsigned char* data() { return _data; } - /** Raw const image data. */ + /** Raw const image data. + * Note, data in successive rows may not be contiguous, isDataContiguous() return false then you should + * take care to access the data per row rather than treating the whole data as a single block. */ 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(); + return _data+(column*getPixelSizeInBits())/8+row*getRowStepInBytes()+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(); + return _data+(column*getPixelSizeInBits())/8+row*getRowStepInBytes()+image*getImageSizeInBytes(); } + /** return true if the data stored in the image is a contiguous block of data.*/ + bool isDataContiguous() const { return _rowLength==0 || _rowLength==_s; } + + /** Convenience class for assisting the copying of image data when the image data isn't contiguous.*/ + class OSG_EXPORT DataIterator + { + public: + DataIterator(const Image* image); + DataIterator(const DataIterator& ri); + ~DataIterator() {} + + /** advance iterator to next block of data.*/ + void operator ++ (); + + /** is iterator valid.*/ + bool valid() const { return _currentPtr!=0; } + + /** data pointer of current block to copy.*/ + const unsigned char* data() const { return _currentPtr; } + + /** Size of current block to copy.*/ + unsigned int size() const { return _currentSize; } + + protected: + + + void assign(); + + const osg::Image* _image; + int _rowNum; + int _imageNum; + unsigned int _mipmapNum; + const unsigned char* _currentPtr; + unsigned int _currentSize; + }; + /** Get the color value for specified texcoord.*/ Vec4 getColor(unsigned int s,unsigned t=0,unsigned r=0) const; @@ -301,9 +354,11 @@ class OSG_EXPORT Image : public BufferData static bool isPackedType(GLenum type); static GLenum computePixelFormat(GLenum pixelFormat); static GLenum computeFormatDataType(GLenum pixelFormat); + static unsigned int computeBlockSize(GLenum pixelFormat, GLenum packing); 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 unsigned int computeImageSizeInBytes(int width,int height, int depth, 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); @@ -341,12 +396,6 @@ class OSG_EXPORT Image : public BufferData 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; @@ -399,6 +448,7 @@ class OSG_EXPORT Image : public BufferData Origin _origin; int _s, _t, _r; + int _rowLength; GLint _internalTextureFormat; GLenum _pixelFormat; GLenum _dataType; diff --git a/include/osg/PrimitiveSet b/include/osg/PrimitiveSet index 294725ba1..3cd4a11c3 100644 --- a/include/osg/PrimitiveSet +++ b/include/osg/PrimitiveSet @@ -197,6 +197,10 @@ class OSG_EXPORT PrimitiveSet : public BufferData virtual const char* className() const { return "PrimitiveSet"; } Type getType() const { return _primitiveType; } + + virtual osg::PrimitiveSet* asPrimitiveSet() { return this; } + virtual const osg::PrimitiveSet* asPrimitiveSet() const { return this; } + virtual const GLvoid* getDataPointer() const { return 0; } virtual unsigned int getTotalDataSize() const { return 0; } virtual bool supportsBufferObject() const { return false; } diff --git a/src/osg/BufferObject.cpp b/src/osg/BufferObject.cpp index c51079c67..9d2389e94 100644 --- a/src/osg/BufferObject.cpp +++ b/src/osg/BufferObject.cpp @@ -204,7 +204,21 @@ void GLBufferObject::compileBuffer() // OSG_NOTICE<<"GLBufferObject::compileBuffer(..) downloading BufferEntry "<<&entry<getModifiedCount(); - _extensions->glBufferSubData(_profile._target, (GLintptrARB)entry.offset, (GLsizeiptrARB)entry.dataSize, entry.dataSource->getDataPointer()); + const osg::Image* image = entry.dataSource->asImage(); + if (image && !(image->isDataContiguous())) + { + unsigned int offset = entry.offset; + for(osg::Image::DataIterator img_itr(image); img_itr.valid(); ++img_itr) + { + //OSG_NOTICE<<"Copying to buffer object using DataIterator, offset="<isDataContiguous()) + { + _currentPtr = _image->data(); + _currentSize = _image->getTotalSizeInBytesIncludingMipmaps(); + + //OSG_NOTICE<<" _currentPtr="<<(void*)_currentPtr<isMipmap()) + { + //OSG_NOTICE<<"DataIterator::assign D"<=_image->getNumMipmapLevels()) + { + _currentPtr = 0; + _currentSize = 0; + return; + } + const unsigned char* ptr = _image->getMipmapData(_mipmapNum); + + int rowLength = _image->getRowLength()>>_mipmapNum; + if (rowLength==0) rowLength = 1; + + int imageHeight = _image->t()>>_mipmapNum; + if (imageHeight==0) imageHeight = 1; + + unsigned int rowWidthInBytes = Image::computeRowWidthInBytes(rowLength,_image->getPixelFormat(),_image->getDataType(),_image->getPacking()); + unsigned int imageSizeInBytes = rowWidthInBytes*imageHeight; + + _currentPtr = ptr + rowWidthInBytes*_rowNum + imageSizeInBytes*_imageNum; + _currentSize = rowWidthInBytes; + } + else + { + //OSG_NOTICE<<"DataIterator::assign E"<=_image->r() || _rowNum>=_image->t()) + { + _currentPtr = 0; + _currentSize = 0; + return; + } + + //OSG_NOTICE<<"DataIterator::assign F"<data(0, _rowNum, _imageNum); + _currentSize = _image->getRowSizeInBytes(); + return; + } +} + + Image::Image() :BufferData(), _fileName(""), _writeHint(NO_PREFERENCE), _origin(BOTTOM_LEFT), _s(0), _t(0), _r(0), + _rowLength(0), _internalTextureFormat(0), _pixelFormat(0), _dataType(0), @@ -71,6 +223,7 @@ Image::Image(const Image& image,const CopyOp& copyop): _writeHint(image._writeHint), _origin(image._origin), _s(image._s), _t(image._t), _r(image._r), + _rowLength(0), _internalTextureFormat(image._internalTextureFormat), _pixelFormat(image._pixelFormat), _dataType(image._dataType), @@ -84,7 +237,12 @@ Image::Image(const Image& image,const CopyOp& copyop): { int size = image.getTotalSizeInBytesIncludingMipmaps(); setData(new unsigned char [size],USE_NEW_DELETE); - memcpy(_data,image._data,size); + unsigned char* dest_ptr = _data; + for(DataIterator itr(&image); itr.valid(); ++itr) + { + memcpy(dest_ptr, itr.data(), itr.size()); + dest_ptr += itr.size(); + } } } @@ -510,6 +668,34 @@ unsigned int Image::computePixelSizeInBits(GLenum format,GLenum type) } +unsigned int Image::computeBlockSize(GLenum pixelFormat, GLenum packing) +{ + switch(pixelFormat) + { + case(GL_COMPRESSED_RGB_S3TC_DXT1_EXT): + case(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT): + return osg::maximum(8u,packing); // block size of 8 + case(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT): + case(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT): + case(GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG): + case(GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG): + case(GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG): + case(GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG): + case(GL_ETC1_RGB8_OES): + return osg::maximum(16u,packing); // block size of 16 + case(GL_COMPRESSED_SIGNED_RED_RGTC1_EXT): + case(GL_COMPRESSED_RED_RGTC1_EXT): + return osg::maximum(8u,packing); // block size of 8 + break; + case(GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT): + case(GL_COMPRESSED_RED_GREEN_RGTC2_EXT): + return osg::maximum(16u,packing); // block size of 16 + default: + break; + } + return packing; +} + unsigned int Image::computeRowWidthInBytes(int width,GLenum pixelFormat,GLenum type,int packing) { unsigned int pixelSize = computePixelSizeInBits(pixelFormat,type); @@ -519,6 +705,16 @@ unsigned int Image::computeRowWidthInBytes(int width,GLenum pixelFormat,GLenum t return (widthInBits/packingInBits + ((widthInBits%packingInBits)?1:0))*packing; } +unsigned int Image::computeImageSizeInBytes(int width,int height, int depth, GLenum pixelFormat,GLenum type,int packing) +{ + if (width==0 || height==0 || depth==0) return 0; + + return osg::maximum( + Image::computeRowWidthInBytes(width,pixelFormat,type,packing)*height*depth, + computeBlockSize(pixelFormat, packing) + ); +} + int Image::computeNearestPowerOfTwo(int s,float bias) { if ((s & (s-1))!=0) @@ -581,51 +777,21 @@ unsigned int Image::getTotalSizeInBytesIncludingMipmaps() const int s = _s; int t = _t; int r = _r; - - unsigned int maxValue = 0; - for(unsigned int i=0;i<_mipmapData.size() && _mipmapData[i];++i) + unsigned int totalSize = 0; + for(unsigned int i=0;i<_mipmapData.size()+1;++i) { + totalSize += computeImageSizeInBytes(s, t, r, _pixelFormat, _dataType, _packing); + s >>= 1; t >>= 1; r >>= 1; - maxValue = maximum(maxValue,_mipmapData[i]); - } - - if (s==0) s=1; - if (t==0) t=1; - if (r==0) r=1; - - unsigned int sizeOfLastMipMap = computeRowWidthInBytes(s,_pixelFormat,_dataType,_packing)* r*t; - switch(_pixelFormat) - { - case(GL_COMPRESSED_RGB_S3TC_DXT1_EXT): - case(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT): - sizeOfLastMipMap = maximum(sizeOfLastMipMap, 8u); // block size of 8 - break; - case(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT): - case(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT): - case(GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG): - case(GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG): - case(GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG): - case(GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG): - case(GL_ETC1_RGB8_OES): - sizeOfLastMipMap = maximum(sizeOfLastMipMap, 16u); // block size of 16 - break; - case(GL_COMPRESSED_SIGNED_RED_RGTC1_EXT): - case(GL_COMPRESSED_RED_RGTC1_EXT): - sizeOfLastMipMap = maximum(sizeOfLastMipMap, 8u); // block size of 8 - break; - case(GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT): - case(GL_COMPRESSED_RED_GREEN_RGTC2_EXT): - sizeOfLastMipMap = maximum(sizeOfLastMipMap, 16u); // block size of 8 - break; - default: break; + + if (s<1) s=1; + if (t<1) t=1; + if (r<1) r=1; } - // OSG_INFO<<"sizeOfLastMipMap="<glGetCompressedTexImage(textureMode, i, getMipmapData(i)); @@ -886,6 +1061,8 @@ void Image::readImageFromCurrentTexture(unsigned int contextID, bool copyMipMaps glGetTexLevelParameteriv(textureMode, 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat); glGetIntegerv(GL_UNPACK_ALIGNMENT, &packing); glPixelStorei(GL_PACK_ALIGNMENT, packing); + glGetIntegerv(GL_UNPACK_ROW_LENGTH, &rowLength); + glPixelStorei(GL_PACK_ROW_LENGTH, rowLength); unsigned int total_size = 0; GLint i; @@ -927,6 +1104,7 @@ void Image::readImageFromCurrentTexture(unsigned int contextID, bool copyMipMaps _mipmapData = mipMapData; _allocationMode=USE_NEW_DELETE; _packing = packing; + _rowLength = rowLength; for(i=0;igetPacking(); + psm.unpack_row_length = source->getRowLength(); GLint status = gluScaleImage(&psm, _pixelFormat, source->s(), @@ -1047,8 +1228,6 @@ void Image::copySubImage(int s_offset, int t_offset, int r_offset, const osg::Im _dataType, data_destination); - glPixelStorei(GL_PACK_ROW_LENGTH,0); - if (status!=0) { OSG_WARN << "Error Image::scaleImage() did not succeed : errorString = "<< gluErrorString((GLenum)status) << ". The rendering context may be invalid." << std::endl; @@ -1067,12 +1246,14 @@ void Image::flipHorizontal() if (_mipmapData.empty()) { - + unsigned int rowStepInBytes = getRowStepInBytes(); + unsigned int imageStepInBytes = getImageStepInBytes(); + for(int r=0;r<_r;++r) { for (int t=0; t<_t; ++t) { - unsigned char* rowData = _data+t*getRowSizeInBytes()+r*getImageSizeInBytes(); + unsigned char* rowData = _data + t*rowStepInBytes + r*imageStepInBytes; unsigned char* left = rowData ; unsigned char* right = rowData + ((_s-1)*getPixelSizeInBits())/8; @@ -1097,17 +1278,20 @@ void Image::flipHorizontal() dirty(); } -void flipImageVertical(unsigned char* top, unsigned char* bottom, unsigned int rowSize) +void flipImageVertical(unsigned char* top, unsigned char* bottom, unsigned int rowSize, unsigned int rowStep) { while(topsetMode(GL_LIGHTING,osg::StateAttribute::OFF); dstate->setTextureAttributeAndModes(0, texture,osg::StateAttribute::ON); - // set up the geoset. + // set up the geoset. unsigned int rowSize = computeRowWidthInBytes(s,_pixelFormat,_dataType,_packing); + Geometry* geom = new Geometry; geom->setStateSet(dstate); diff --git a/src/osg/Texture.cpp b/src/osg/Texture.cpp index dd7ffdc89..83affc2be 100644 --- a/src/osg/Texture.cpp +++ b/src/osg/Texture.cpp @@ -1842,6 +1842,7 @@ void Texture::applyTexImage2D_load(State& state, GLenum target, const Image* ima } glPixelStorei(GL_UNPACK_ALIGNMENT,image->getPacking()); + unsigned int rowLength = image->getRowLength(); bool useClientStorage = extensions->isClientStorageSupported() && getClientStorageHint(); if (useClientStorage) @@ -1891,6 +1892,7 @@ void Texture::applyTexImage2D_load(State& state, GLenum target, const Image* ima PixelStorageModes psm; psm.pack_alignment = image->getPacking(); + psm.pack_row_length = image->getRowLength(); psm.unpack_alignment = image->getPacking(); // rescale the image to the correct size. @@ -1899,6 +1901,7 @@ void Texture::applyTexImage2D_load(State& state, GLenum target, const Image* ima inwidth,inheight,image->getDataType(), dataPtr); + rowLength = 0; } bool mipmappingRequired = _min_filter != LINEAR && _min_filter != NEAREST; @@ -1910,6 +1913,7 @@ void Texture::applyTexImage2D_load(State& state, GLenum target, const Image* ima { state.bindPixelBufferObject(pbo); dataPtr = reinterpret_cast(pbo->getOffset(image->getBufferIndex())); + rowLength = 0; #ifdef DO_TIMING OSG_NOTICE<<"after PBO "<delta_m(start_tick,osg::Timer::instance()->tick())<<"ms"<getPixelFormat()); glPixelStorei(GL_UNPACK_ALIGNMENT,image->getPacking()); + unsigned int rowLength = image->getRowLength(); unsigned char* dataPtr = (unsigned char*)image->data(); @@ -2147,6 +2154,8 @@ void Texture::applyTexImage2D_subload(State& state, GLenum target, const Image* image->s(),image->t(),image->getDataType(),image->data(), inwidth,inheight,image->getDataType(), dataPtr); + + rowLength = 0; } @@ -2159,6 +2168,7 @@ void Texture::applyTexImage2D_subload(State& state, GLenum target, const Image* { state.bindPixelBufferObject(pbo); dataPtr = reinterpret_cast(pbo->getOffset(image->getBufferIndex())); + rowLength = 0; #ifdef DO_TIMING OSG_NOTICE<<"after PBO "<delta_m(start_tick,osg::Timer::instance()->tick())<<"ms"<getPacking()); + glPixelStorei(GL_UNPACK_ROW_LENGTH,image->getRowLength()); static MyCompressedTexImage1DArbProc glCompressedTexImage1D_ptr = convertPointerType(getGLExtensionFuncPtr("glCompressedTexImage1DARB")); diff --git a/src/osg/Texture2DArray.cpp b/src/osg/Texture2DArray.cpp index ec77b6009..ef345317d 100644 --- a/src/osg/Texture2DArray.cpp +++ b/src/osg/Texture2DArray.cpp @@ -455,6 +455,7 @@ void Texture2DArray::applyTexImage2DArray_subload(State& state, Image* image, GL } glPixelStorei(GL_UNPACK_ALIGNMENT,image->getPacking()); + glPixelStorei(GL_UNPACK_ROW_LENGTH,image->getRowLength()); bool useHardwareMipmapGeneration = !image->isMipmap() && _useHardwareMipMapGeneration && texExtensions->isGenerateMipMapSupported(); diff --git a/src/osg/Texture3D.cpp b/src/osg/Texture3D.cpp index 84e46cfa7..5e6121452 100644 --- a/src/osg/Texture3D.cpp +++ b/src/osg/Texture3D.cpp @@ -380,6 +380,7 @@ void Texture3D::applyTexImage3D(GLenum target, Image* image, State& state, GLsiz image->ensureValidSizeForTexturing(extensions->maxTexture3DSize()); glPixelStorei(GL_UNPACK_ALIGNMENT,image->getPacking()); + glPixelStorei(GL_UNPACK_ROW_LENGTH,image->getRowLength()); bool useHardwareMipMapGeneration = !image->isMipmap() && _useHardwareMipMapGeneration && texExtensions->isGenerateMipMapSupported(); diff --git a/src/osg/TextureRectangle.cpp b/src/osg/TextureRectangle.cpp index 5c7ed1065..5df5a88e0 100644 --- a/src/osg/TextureRectangle.cpp +++ b/src/osg/TextureRectangle.cpp @@ -312,6 +312,7 @@ void TextureRectangle::applyTexImage_load(GLenum target, Image* image, State& st computeInternalFormat(); glPixelStorei(GL_UNPACK_ALIGNMENT, image->getPacking()); + glPixelStorei(GL_UNPACK_ROW_LENGTH,image->getRowLength()); bool useClientStorage = extensions->isClientStorageSupported() && getClientStorageHint(); if (useClientStorage) @@ -392,6 +393,8 @@ void TextureRectangle::applyTexImage_subload(GLenum target, Image* image, State& computeInternalFormat(); glPixelStorei(GL_UNPACK_ALIGNMENT, image->getPacking()); + unsigned int rowLength = image->getRowLength(); + #ifdef DO_TIMING osg::Timer_t start_tick = osg::Timer::instance()->tick(); @@ -403,11 +406,13 @@ void TextureRectangle::applyTexImage_subload(GLenum target, Image* image, State& { state.bindPixelBufferObject(pbo); dataPtr = reinterpret_cast(pbo->getOffset(image->getBufferIndex())); + rowLength = 0; #ifdef DO_TIMING OSG_NOTICE<<"after PBO "<delta_m(start_tick,osg::Timer::instance()->tick())<<"ms"<isCompressedTexSubImage2DSupported()) { diff --git a/src/osgDB/OutputStream.cpp b/src/osgDB/OutputStream.cpp index f51f6e5f1..e72dada23 100644 --- a/src/osgDB/OutputStream.cpp +++ b/src/osgDB/OutputStream.cpp @@ -369,15 +369,33 @@ void OutputStream::writeImage( const osg::Image* img ) // _data unsigned int size = img->getTotalSizeInBytesIncludingMipmaps(); - writeSize(size); writeCharArray( (char*)img->data(), size ); + writeSize(size); + + for(osg::Image::DataIterator img_itr(img); img_itr.valid(); ++img_itr) + { + writeCharArray( (char*)img_itr.data(), img_itr.size() ); + } // _mipmapData - const osg::Image::MipmapDataType& levels = img->getMipmapLevels(); - writeSize(levels.size()); - for ( osg::Image::MipmapDataType::const_iterator itr=levels.begin(); - itr!=levels.end(); ++itr ) + unsigned int numMipmaps = img->getNumMipmapLevels()-1; + writeSize(numMipmaps); + int s = img->s(); + int t = img->t(); + int r = img->r(); + unsigned int offset = 0; + for (unsigned int i=0; igetPixelFormat(),img->getDataType(),img->getPacking()); + offset += size; + + *this << offset; + + s >>= 1; + t >>= 1; + r >>= 1; + if (s<1) s=1; + if (t<1) t=1; + if (r<1) r=1; } } break; diff --git a/src/osgPlugins/Inventor/ConvertFromInventor.cpp b/src/osgPlugins/Inventor/ConvertFromInventor.cpp index b98d0d12a..ec7ca7e53 100644 --- a/src/osgPlugins/Inventor/ConvertFromInventor.cpp +++ b/src/osgPlugins/Inventor/ConvertFromInventor.cpp @@ -1093,12 +1093,21 @@ static osgDB::ReaderWriter::Options* createOptions() static osg::Image* loadImage(const char *fileName, osgDB::ReaderWriter::Options *options) { - osg::Image *osgImage = osgDB::readImageFile(fileName, options); + osg::ref_ptr osgImage = osgDB::readImageFile(fileName, options); if (!osgImage) + { OSG_WARN << NOTIFY_HEADER << "Could not read texture file '" << fileName << "'."; + return 0; + } - return osgImage; + if (!osgImage->isDataContiguous()) + { + OSG_WARN << NOTIFY_HEADER << "Inventor cannot handle non contiguous image data found in texture file '" << fileName << "'."; + return 0; + } + + return osgImage.release(); } SbBool SoTexture2Osg::readInstance(SoInput *in, unsigned short flags) diff --git a/src/osgPlugins/Inventor/ReaderWriterIV.cpp b/src/osgPlugins/Inventor/ReaderWriterIV.cpp index a2cf4459d..301b5781b 100644 --- a/src/osgPlugins/Inventor/ReaderWriterIV.cpp +++ b/src/osgPlugins/Inventor/ReaderWriterIV.cpp @@ -142,7 +142,7 @@ ReaderWriterIV::readNodeFromSoInput(SoInput &input, if (fileName.length()) { OSG_NOTICE << "osgDB::ReaderWriterIV::readNode() " - << "File " << fileName.data() + << "File " << fileName << " loaded successfully." << std::endl; } else @@ -154,7 +154,7 @@ ReaderWriterIV::readNodeFromSoInput(SoInput &input, if (fileName.length()) { OSG_WARN << "osgDB::ReaderWriterIV::readNode() " - << "Failed to load file " << fileName.data() + << "Failed to load file " << fileName << "." << std::endl; } else diff --git a/src/osgPlugins/bmp/ReaderWriterBMP.cpp b/src/osgPlugins/bmp/ReaderWriterBMP.cpp index 934d57c12..b89ea3a77 100644 --- a/src/osgPlugins/bmp/ReaderWriterBMP.cpp +++ b/src/osgPlugins/bmp/ReaderWriterBMP.cpp @@ -527,7 +527,7 @@ static bool bmp_save(const osg::Image& img, std::ostream& fout) std::vector rowBuffer(bytesPerRowAlign); for (int y = 0; y < img.t(); ++y) { - const unsigned char* imgp = img.data() + img.s() * y * channelsPerPixel; + const unsigned char* imgp = img.data(0, y); for (int x = 0; x < img.s(); ++x) { // RGB -> BGR diff --git a/src/osgPlugins/dds/ReaderWriterDDS.cpp b/src/osgPlugins/dds/ReaderWriterDDS.cpp index 5a459eb20..30d00f746 100644 --- a/src/osgPlugins/dds/ReaderWriterDDS.cpp +++ b/src/osgPlugins/dds/ReaderWriterDDS.cpp @@ -878,8 +878,6 @@ bool WriteDDSFile(const osg::Image *img, std::ostream& fout) return false; } - int size = img->getTotalSizeInBytes(); - // set even more flags if( !img->isMipmap() ) { @@ -896,8 +894,6 @@ bool WriteDDSFile(const osg::Image *img, std::ostream& fout) ddsd.dwMipMapCount = img->getNumMipmapLevels(); - size = img->getTotalSizeInBytesIncludingMipmaps(); - OSG_INFO<<"writing out with mipmaps ddsd.dwMipMapCount"<(&ddsd), sizeof(ddsd)); /* write file header */ - fout.write(reinterpret_cast(img->data()), size ); + + for(osg::Image::DataIterator itr(img); itr.valid(); ++itr) + { + fout.write(reinterpret_cast(itr.data()), itr.size() ); + } // Check for correct saving if ( fout.fail() ) diff --git a/src/osgPlugins/exr/ReaderWriterEXR.cpp b/src/osgPlugins/exr/ReaderWriterEXR.cpp index eaf53e2dd..4e2f96018 100644 --- a/src/osgPlugins/exr/ReaderWriterEXR.cpp +++ b/src/osgPlugins/exr/ReaderWriterEXR.cpp @@ -276,9 +276,9 @@ protected: //If texture is half format if (dataType == GL_HALF_FLOAT_ARB) { - half* pOut = (half*) img.data(); for (long i = height-1; i >= 0; i--) { + half* pOut = (half*) img.data(0,i); for (long j = 0 ; j < width; j++) { outPixels[i][j].r = (*pOut); diff --git a/src/osgPlugins/hdr/hdrwriter.cpp b/src/osgPlugins/hdr/hdrwriter.cpp index 1644074c3..9c9a52a87 100644 --- a/src/osgPlugins/hdr/hdrwriter.cpp +++ b/src/osgPlugins/hdr/hdrwriter.cpp @@ -36,20 +36,16 @@ #include -bool HDRWriter::writeRLE(const osg::Image *img, std::ostream& fout) -{ - return writePixelsRLE(fout,(float*) img->data(), img->s(), img->t()); -} - bool HDRWriter::writeRAW(const osg::Image *img, std::ostream& fout) { - return writePixelsRAW(fout,(unsigned char*) img->data(), img->s() * img->t()); + bool result = true; + for(int row=0; result && rowt(); ++row) + { + result = writePixelsRAW(fout,(unsigned char*) img->data(0, row), img->s()); + } + return result; } - - - - /* number of floats per pixel */ #define RGBE_DATA_SIZE 3 @@ -86,21 +82,26 @@ bool HDRWriter::writeHeader(const osg::Image *img, std::ostream& fout) /* simple write routine that does not use run length encoding */ /* These routines can be made faster by allocating a larger buffer and fread-ing and fwrite-ing the data in larger chunks */ -bool HDRWriter::writePixelsNoRLE( std::ostream& fout, float* data, int numpixels) +bool HDRWriter::writeNoRLE( std::ostream& fout, const osg::Image* img) { unsigned char rgbe[4]; - while (numpixels-- > 0) + for(int row=0; rowt(); ++row) { - float2rgbe( + float* data = (float*)img->data(0,row); + for(int column=0; columns(); ++column) + { + float2rgbe( rgbe, data[R], data[G], data[B] ); - data += RGBE_DATA_SIZE; - fout.write(reinterpret_cast(rgbe), sizeof(rgbe)); //img->getTotalSizeInBytesIncludingMipmaps() + data += RGBE_DATA_SIZE; + fout.write(reinterpret_cast(rgbe), sizeof(rgbe)); + } } + return true; } @@ -183,23 +184,27 @@ bool HDRWriter::writeBytesRLE(std::ostream& fout, unsigned char *data, int numby #undef MINRUNLENGTH } -bool HDRWriter::writePixelsRLE( std::ostream& fout, float* data, int scanline_width, int num_scanlines ) - +bool HDRWriter::writeRLE( const osg::Image* img, std::ostream& fout) { + int scanline_width = img->s(); + int num_scanlines = img->t(); + unsigned char rgbe[4]; unsigned char *buffer; if ((scanline_width < MINELEN)||(scanline_width > MAXELEN)) // run length encoding is not allowed so write flat - return writePixelsNoRLE(fout,data,scanline_width*num_scanlines); + return writeNoRLE(fout,img); buffer = (unsigned char *)malloc(sizeof(unsigned char)*4*scanline_width); if (buffer == NULL) // no buffer space so write flat - return writePixelsNoRLE(fout,data,scanline_width*num_scanlines); + return writeNoRLE(fout,img); - while(num_scanlines-- > 0) + for(int row = 0; rowdata(0, row); + rgbe[0] = 2; rgbe[1] = 2; rgbe[2] = scanline_width >> 8; diff --git a/src/osgPlugins/hdr/hdrwriter.h b/src/osgPlugins/hdr/hdrwriter.h index 8374ba9c5..9aeda1b1a 100644 --- a/src/osgPlugins/hdr/hdrwriter.h +++ b/src/osgPlugins/hdr/hdrwriter.h @@ -39,13 +39,12 @@ public: protected: // can read or write pixels in chunks of any size including single pixels - static bool writePixelsNoRLE( std::ostream& fout, float* data, int numpixels); + static bool writeNoRLE( std::ostream& fout, const osg::Image* image); static bool writePixelsRAW( std::ostream& fout, unsigned char* data, int numpixels); // read or write run length encoded files // must be called to read or write whole scanlines static bool writeBytesRLE(std::ostream& fout, unsigned char *data, int numbytes); - static bool writePixelsRLE( std::ostream& fout, float* data, int scanline_width, int num_scanlines ); // inline conversions inline static void float2rgbe(unsigned char rgbe[4], float red, float green, float blue); diff --git a/src/osgPlugins/imageio/ReaderWriterImageIO.cpp b/src/osgPlugins/imageio/ReaderWriterImageIO.cpp index 26b1b5c8d..f1489bc2c 100644 --- a/src/osgPlugins/imageio/ReaderWriterImageIO.cpp +++ b/src/osgPlugins/imageio/ReaderWriterImageIO.cpp @@ -1199,6 +1199,11 @@ public: WriteResult writeImageStream(const osg::Image& osg_image, std::ostream& fout, const osgDB::ReaderWriter::Options* the_options) const { + if (!osg_image.isDataContiguous()) + { + return WriteResult::FILE_NOT_HANDLED; + } + WriteResult ret_val = WriteResult::ERROR_IN_WRITING_FILE; CGImageDestinationRef cg_dest_ref = CreateCGImageDestinationFromDataStream(fout, the_options); @@ -1235,6 +1240,12 @@ public: WriteResult writeImageFile(const osg::Image& osg_image, const std::string& full_file_name, const osgDB::ReaderWriter::Options* the_options) const { + if (!osg_image.isDataContiguous()) + { + return WriteResult::FILE_NOT_HANDLED; + } + + WriteResult ret_val = WriteResult::ERROR_IN_WRITING_FILE; WriteResult ret_val = WriteResult::ERROR_IN_WRITING_FILE; // Call ImageIO to load the image. CGImageDestinationRef cg_dest_ref = CreateCGImageDestinationFromFile(full_file_name.c_str(), the_options); @@ -1268,6 +1279,12 @@ public: std::string ext = osgDB::getFileExtension(file_name); if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED; + if (!osg_image.isDataContiguous()) + { + return WriteResult::FILE_NOT_HANDLED; + } + + WriteResult ret_val = WriteResult::ERROR_IN_WRITING_FILE; #if 1 // FIXME: Something may need to provide a proper writable location for the files. std::string full_file_name; diff --git a/src/osgPlugins/ive/Image.cpp b/src/osgPlugins/ive/Image.cpp index d716bd325..c09f096a2 100644 --- a/src/osgPlugins/ive/Image.cpp +++ b/src/osgPlugins/ive/Image.cpp @@ -72,7 +72,10 @@ void Image::write(DataOutputStream* out) unsigned int size = getTotalSizeInBytesIncludingMipmaps(); out->writeInt(size); // Write the data - out->writeCharArray((char*)data(), size); + for(osg::Image::DataIterator itr(this); itr.valid(); ++itr) + { + out->writeCharArray((char*)itr.data(), itr.size()); + } } } diff --git a/src/osgPlugins/jp2/ReaderWriterJP2.cpp b/src/osgPlugins/jp2/ReaderWriterJP2.cpp index 1fe658fa5..6078d8078 100644 --- a/src/osgPlugins/jp2/ReaderWriterJP2.cpp +++ b/src/osgPlugins/jp2/ReaderWriterJP2.cpp @@ -353,6 +353,12 @@ class ReaderWriterJP2 : public osgDB::ReaderWriter std::string ext = osgDB::getFileExtension(fileName); if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED; + if (!img.isDataContiguous()) + { + OSG_WARN<<"Warning: Writing of image data, that is non contiguous, is not supported by JPEG2000 plugin."<getPacking()); + glPixelStorei(GL_UNPACK_ROW_LENGTH, img->getRowLength()); x = place[i][0] + xi * img->s(); if( i == Center || i == UpperLeft || i == UpperRight || i == UpperCenter) y += yi * img->t(); diff --git a/src/osgPlugins/nvtt/NVTTImageProcessor.cpp b/src/osgPlugins/nvtt/NVTTImageProcessor.cpp index a98127220..0fe95a2c8 100644 --- a/src/osgPlugins/nvtt/NVTTImageProcessor.cpp +++ b/src/osgPlugins/nvtt/NVTTImageProcessor.cpp @@ -46,10 +46,10 @@ protected: }; // Convert RGBA to BGRA : nvtt only accepts BGRA pixel format - void convertRGBAToBGRA( std::vector& outputData, const unsigned char* inputData ); + void convertRGBAToBGRA( std::vector& outputData, const osg::Image& image ); // Convert RGB to BGRA : nvtt only accepts BGRA pixel format - void convertRGBToBGRA( std::vector& outputData, const unsigned char* inputData ); + void convertRGBToBGRA( std::vector& outputData, const osg::Image& image ); }; @@ -175,27 +175,38 @@ bool NVTTProcessor::OSGImageOutputHandler::writeData(const void * data, int size } // Convert RGBA to BGRA : nvtt only accepts BGRA pixel format -void NVTTProcessor::convertRGBAToBGRA( std::vector& outputData, const unsigned char* inputData ) +void NVTTProcessor::convertRGBAToBGRA( std::vector& outputData, const osg::Image& image ) { - for (unsigned n=0; n& outputData, const unsigned char* inputData ) +void NVTTProcessor::convertRGBToBGRA( std::vector& outputData, const osg::Image& image ) { - unsigned int numberOfPixels = outputData.size()/4; - for (unsigned n=0; n imageData( image.s() * image.t() * 4 ); if (image.getPixelFormat() == GL_RGB) { - convertRGBToBGRA( imageData, image.data() ); + convertRGBToBGRA( imageData, image ); } else { - convertRGBAToBGRA( imageData, image.data() ); + convertRGBAToBGRA( imageData, image ); } inputOptions.setMipmapData(&imageData[0],image.s(),image.t()); diff --git a/src/osgPlugins/pov/ReaderWriterPOV.cpp b/src/osgPlugins/pov/ReaderWriterPOV.cpp index 6873b255b..4ca9129fc 100644 --- a/src/osgPlugins/pov/ReaderWriterPOV.cpp +++ b/src/osgPlugins/pov/ReaderWriterPOV.cpp @@ -101,8 +101,7 @@ ReaderWriterPOV::writeNode( const Node& node, const string& fileName, string ext = osgDB::getLowerCaseFileExtension( fileName ); if( !acceptsExtension( ext ) ) return WriteResult::FILE_NOT_HANDLED; - notify( NOTICE ) << "ReaderWriterPOV::writeNode() Writing file " - << fileName.data() << endl; + notify( NOTICE ) << "ReaderWriterPOV::writeNode() Writing file " << fileName << endl; osgDB::ofstream fout( fileName.c_str(), ios::out | ios::trunc ); if( !fout ) diff --git a/src/osgPlugins/rgb/ReaderWriterRGB.cpp b/src/osgPlugins/rgb/ReaderWriterRGB.cpp index 7d23ebd64..1125d48de 100644 --- a/src/osgPlugins/rgb/ReaderWriterRGB.cpp +++ b/src/osgPlugins/rgb/ReaderWriterRGB.cpp @@ -660,11 +660,33 @@ class ReaderWriterRGB : public osgDB::ReaderWriter virtual WriteResult writeImage(const osg::Image& img,std::ostream& fout,const osgDB::ReaderWriter::Options*) const { + if (img.isCompressed()) + { + OSG_NOTICE<<"Warning: RGB plugin does not supporting writing compressed imagery."<_ready) - { - imageStream->allocateImage(width,height,1,pixelFormat,GL_UNSIGNED_BYTE,1); - imageStream->setInternalTextureFormat(GL_RGBA); - } - - osg::Timer_t start_tick = osg::Timer::instance()->tick(); - - memcpy(imageStream->data(),data,imageStream->getTotalSizeInBytes()); - - OSG_INFO<<"image memcpy size="<getTotalSizeInBytes()<<" time="<delta_m(start_tick,osg::Timer::instance()->tick())<<"ms"<dirty(); - #else - imageStream->setImage(width,height,1, + imageStream->setImage(width,height,1, GL_RGB, pixelFormat,GL_UNSIGNED_BYTE, (unsigned char *)data, osg::Image::NO_DELETE, 1); - #endif + imageStream->_ready = true; } diff --git a/src/osgText/Glyph.cpp b/src/osgText/Glyph.cpp index ab0b1b975..8732de49e 100644 --- a/src/osgText/Glyph.cpp +++ b/src/osgText/Glyph.cpp @@ -474,6 +474,7 @@ void Glyph::subload() const } glPixelStorei(GL_UNPACK_ALIGNMENT,getPacking()); + glPixelStorei(GL_UNPACK_ROW_LENGTH,getRowLength()); glTexSubImage2D(GL_TEXTURE_2D,0, _texturePosX,_texturePosY,