Example #1
0
//--------------------------------------------------------------------------
void PixelFormatTests::setupBoxes(PixelFormat srcFormat, PixelFormat dstFormat)
{
    unsigned int width = (mSize-4) / PixelUtil::getNumElemBytes(srcFormat);
    unsigned int width2 = (mSize-4) / PixelUtil::getNumElemBytes(dstFormat);
    if(width > width2)
        width = width2;

    mSrc = PixelBox(width, 1, 1, srcFormat, mRandomData);
    mDst1 = PixelBox(width, 1, 1, dstFormat, mTemp);
    mDst2 = PixelBox(width, 1, 1, dstFormat, mTemp2);
}
void 
WinMapControl::getCursorBox( PixelBox& box ) const
{
   box = PixelBox( MC2Point( 0, 0), 
                   MC2Point( m_width, m_height ) );

}
	//---------------------------------------------------------------------
	void TerrainLayerBlendMap::blit(const PixelBox &src, const Box &dstBox)
	{
		const PixelBox* srcBox = &src;

		if (srcBox->getWidth() != dstBox.getWidth() || srcBox->getHeight() != dstBox.getHeight())
		{
			// we need to rescale src to dst size first (also confvert format)
			void* tmpData = OGRE_MALLOC(dstBox.getWidth() * dstBox.getHeight(), MEMCATEGORY_GENERAL);
			srcBox = OGRE_NEW PixelBox(dstBox.getWidth(), dstBox.getHeight(), 1, PF_L8, tmpData);

			Image::scale(src, *srcBox);
		}

		// pixel conversion
		PixelBox dstMemBox(dstBox, PF_L8, mData);
		PixelUtil::bulkPixelConversion(*srcBox, dstMemBox);

		if (srcBox != &src)
		{
			// free temp
			OGRE_FREE(srcBox->data, MEMCATEGORY_GENERAL);
			OGRE_DELETE srcBox;
			srcBox = 0;
		}

		Rect dRect(dstBox.left, dstBox.top, dstBox.right, dstBox.bottom);
		dirtyRect(dRect);

	}
    PixelBox GL3PlusHardwarePixelBuffer::lockImpl( const Image::Box &lockBox, LockOptions options )
    {
        //Allocate memory for the entire image, as the buffer
        //maynot be freed and be reused in subsequent calls.
        allocateBuffer( PixelUtil::getMemorySize( mWidth, mHeight, mDepth, mFormat ) );

        mBuffer = PixelBox( lockBox.getWidth(), lockBox.getHeight(),
                            lockBox.getDepth(), mFormat, mBuffer.data );
        mCurrentLock = mBuffer;
        mCurrentLock.left    = lockBox.left;
        mCurrentLock.right  += lockBox.left;
        mCurrentLock.top     = lockBox.top;
        mCurrentLock.bottom += lockBox.top;

        if(options != HardwareBuffer::HBL_DISCARD)
        {
            // Download the old contents of the texture
            download( mCurrentLock );
        }
        mCurrentLockOptions = options;
        mLockedBox = lockBox;
        mCurrentLock = mBuffer;

        return mBuffer;
    }
void
StackedSet::updateItemPixelBox(const OverlayItemInternal* item,
                               const WFAPI::OverlayItemVisualSpec* visualSpec,
                               const WFAPI::WGS84Coordinate& coord)
{
   MC2Point screenPoint;

   WFAPI::wf_float64 x;
   WFAPI::wf_float64 y;
   m_projection.transformf(x,y, coord);
   screenPoint = MC2Point(static_cast<int>(x * SCALING_CONSTANT),
                          static_cast<int>(y * SCALING_CONSTANT));

   if(!visualSpec) {
      item->getPrecisionScaledPixelBox() = PixelBox(MC2Point(0, 0),
                                                    MC2Point(0, 0));
      return;
   }
   
   const WFAPI::ImageSpec* background = visualSpec->getBackgroundImage();

   if(!background) {
      item->getPrecisionScaledPixelBox() = PixelBox(MC2Point(0, 0),
                                                    MC2Point(0, 0));
      return;
   }
   
   WFAPI::ScreenPoint offsetPoint = visualSpec->getFocusPoint();
   
   // The pixel box needs to be scaled in order to gain sufficient
   // precision.
   offsetPoint.getX() *= SCALING_CONSTANT;
   offsetPoint.getY() *= SCALING_CONSTANT;
   unsigned int width = background->getWidth() * SCALING_CONSTANT;
   unsigned int height = background->getHeight() * SCALING_CONSTANT;

   // Create our offset box
   PixelBox box( MC2Point(-offsetPoint.getX(), -offsetPoint.getY()),
                 MC2Point(-offsetPoint.getX() + width,
                          -offsetPoint.getY() + height));

   //Offset the box to the correct position on the screen
   box.move(screenPoint);

   //Assign pixel box to item so that other items can check for overlap
   item->getPrecisionScaledPixelBox() = box;    
}
    void GL3PlusHardwarePixelBuffer::unlockImpl(void)
    {
        if (mCurrentLockOptions != HardwareBuffer::HBL_READ_ONLY)
        {
            // From buffer to card, only upload if was locked for writing.
            upload(mCurrentLock, mLockedBox);
        }
        freeBuffer();

        mBuffer = PixelBox( mWidth, mHeight, mDepth, mFormat, mBuffer.data );
    }
	//---------------------------------------------------------------------
	void D3D10RenderWindow::copyContentsToMemory(const PixelBox &dst, FrameBuffer buffer)
	{
		

		// get the backbuffer desc
		D3D10_TEXTURE2D_DESC BBDesc;
		mpBackBuffer->GetDesc( &BBDesc );

		// change the parameters of the texture so we can read it
		BBDesc.Usage = D3D10_USAGE_STAGING;
		BBDesc.CPUAccessFlags = D3D10_CPU_ACCESS_READ;
		BBDesc.BindFlags = 0;

		// create a temp buffer to copy to
		ID3D10Texture2D * pTempTexture2D;
		mDevice->CreateTexture2D(
			&BBDesc,
			0,
			&pTempTexture2D);

		// copy the back buffer
		mDevice->CopyResource(pTempTexture2D, mpBackBuffer);


		// map the copied texture
		D3D10_MAPPED_TEXTURE2D mappedTex2D;
		pTempTexture2D->Map(0,D3D10_MAP_READ, 0, &mappedTex2D);

		// copy the the texture to the dest
		PixelUtil::bulkPixelConversion(
			PixelBox(mWidth, mHeight, 1, PF_A8B8G8R8, mappedTex2D.pData), 
			dst);

		// unmap the temp buffer
		pTempTexture2D->Unmap(0);

		// Release the temp buffer
		pTempTexture2D->Release();
		pTempTexture2D = NULL;
	}
double TileBoundsCalculator::_evaluateSplitPoint(const PixelBox& pb, const Pixel& p)
{
  // This function has two goals:
  // * minimize the number of nodes intersected by a split
  // * minimize the difference between quadrant counts, or ignore the quadrant counts if all
  //   the quadrants are below _maxNodesPerBox
  //
  // Smaller scores are better.

  double llSum = _sumPixels(PixelBox(pb.minX, p.x, pb.minY, p.y));
  double ulSum = _sumPixels(PixelBox(pb.minX, p.x, p.y + 1, pb.maxY));
  double lrSum = _sumPixels(PixelBox(p.x + 1, pb.maxX, pb.minY, p.y));
  double urSum = _sumPixels(PixelBox(p.x + 1, pb.maxX, p.y + 1, pb.maxY));

  double total = llSum + ulSum + lrSum + urSum;
# ifdef DEBUG
    assert(fabs(total - _sumPixels(pb)) < 0.1);
# endif

  double avg = total / 4.0;

  double slop = fabs(llSum - avg) / avg;
  slop += fabs(ulSum - avg) / avg;
  slop += fabs(lrSum - avg) / avg;
  slop += fabs(urSum - avg) / avg;
  slop /= 4.0;

  double slopMultiplier;
  if (slop > _slop)
  {
    slopMultiplier = 2.0 + slop;
  }
  else
  {
    slopMultiplier = 1.0 + slop;
  }

  double intersects = 0.0;
  intersects += _sumPixels(PixelBox(p.x, p.x, pb.minY, pb.maxY));
  intersects += _sumPixels(PixelBox(pb.minX, pb.maxX, p.y, p.y));

  return intersects * slopMultiplier;
}
//---------------------------------------------------------------------
void D3D11RenderWindowBase::copyContentsToMemory(const PixelBox &dst, FrameBuffer buffer)
{
    if(mpBackBuffer == NULL)
        return;

    // get the backbuffer desc
    D3D11_TEXTURE2D_DESC BBDesc;
    mpBackBuffer->GetDesc( &BBDesc );

    ID3D11Texture2D *backbuffer = NULL;

    if(BBDesc.SampleDesc.Quality > 0)
    {
        D3D11_TEXTURE2D_DESC desc = BBDesc;
        desc.Usage = D3D11_USAGE_DEFAULT;
        desc.CPUAccessFlags = 0;
        desc.BindFlags = 0;
        desc.SampleDesc.Quality = 0;
        desc.SampleDesc.Count = 1;

        HRESULT hr = mDevice->CreateTexture2D(
                         &desc,
                         NULL,
                         &backbuffer);

        if (FAILED(hr) || mDevice.isError())
        {
            String errorDescription = mDevice.getErrorDescription(hr);
            OGRE_EXCEPT_EX(Exception::ERR_RENDERINGAPI_ERROR, hr,
                           "Error creating texture\nError Description:" + errorDescription,
                           "D3D11RenderWindow::copyContentsToMemory" );
        }

        mDevice.GetImmediateContext()->ResolveSubresource(backbuffer, D3D11CalcSubresource(0, 0, 1), mpBackBuffer, D3D11CalcSubresource(0, 0, 1), desc.Format);
    }


    // change the parameters of the texture so we can read it
    BBDesc.Usage = D3D11_USAGE_STAGING;
    BBDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
    BBDesc.BindFlags = 0;
    BBDesc.SampleDesc.Quality = 0;
    BBDesc.SampleDesc.Count = 1;

    // create a temp buffer to copy to
    ID3D11Texture2D * pTempTexture2D;
    HRESULT hr = mDevice->CreateTexture2D(
                     &BBDesc,
                     NULL,
                     &pTempTexture2D);

    if (FAILED(hr) || mDevice.isError())
    {
        String errorDescription = mDevice.getErrorDescription(hr);
        OGRE_EXCEPT_EX(Exception::ERR_RENDERINGAPI_ERROR, hr,
                       "Error creating texture\nError Description:" + errorDescription,
                       "D3D11RenderWindow::copyContentsToMemory" );
    }
    // copy the back buffer
    mDevice.GetImmediateContext()->CopyResource(pTempTexture2D, backbuffer != NULL ? backbuffer : mpBackBuffer);

    // map the copied texture
    D3D11_MAPPED_SUBRESOURCE mappedTex2D;
    mDevice.GetImmediateContext()->Map(pTempTexture2D, 0,D3D11_MAP_READ, 0, &mappedTex2D);

    // copy the the texture to the dest
    PixelUtil::bulkPixelConversion(
        PixelBox(mWidth, mHeight, 1, D3D11Mappings::_getPF(BBDesc.Format), mappedTex2D.pData),
        dst);

    // unmap the temp buffer
    mDevice.GetImmediateContext()->Unmap(pTempTexture2D, 0);

    // Release the temp buffer
    SAFE_RELEASE(pTempTexture2D);
    SAFE_RELEASE(backbuffer);
}
    void GLESTextureBuffer::buildMipmaps(const PixelBox &data)
    {
        int width;
        int height;
        int logW;
        int logH;
        int level;
        PixelBox scaled = data;
        scaled.data = data.data;
        scaled.left = data.left;
        scaled.right = data.right;
        scaled.top = data.top;
        scaled.bottom = data.bottom;
        scaled.front = data.front;
        scaled.back = data.back;

        width = data.getWidth();
        height = data.getHeight();

        logW = computeLog(width);
        logH = computeLog(height);
        level = (logW > logH ? logW : logH);

        for (int mip = 0; mip <= level; mip++)
        {
            GLenum glFormat = GLESPixelUtil::getGLOriginFormat(scaled.format);
            GLenum dataType = GLESPixelUtil::getGLOriginDataType(scaled.format);

            glTexImage2D(mFaceTarget,
                         mip,
                         glFormat,
                         width, height,
                         0,
                         glFormat,
                         dataType,
                         scaled.data);

            GL_CHECK_ERROR;

            if (mip != 0)
            {
                delete[] (uint8*) scaled.data;
                scaled.data = 0;
            }

            if (width > 1)
            {
                width = width / 2;
            }

            if (height > 1)
            {
                height = height / 2;
            }

            int sizeInBytes = PixelUtil::getMemorySize(width, height, 1,
                                                       data.format);
            scaled = PixelBox(width, height, 1, data.format);
            scaled.data = new uint8[sizeInBytes];
            Image::scale(data, scaled, Image::FILTER_LINEAR);
        }
    }
    //-----------------------------------------------------------------------------  
    // blitFromMemory doing hardware trilinear scaling
    void GLESTextureBuffer::blitFromMemory(const PixelBox &src_orig, const Image::Box &dstBox)
    {
        // Fall back to normal GLHardwarePixelBuffer::blitFromMemory in case 
        // - FBO is not supported
        // - Either source or target is luminance due doesn't looks like supported by hardware
        // - the source dimensions match the destination ones, in which case no scaling is needed
        if(!GL_OES_framebuffer_object ||
           PixelUtil::isLuminance(src_orig.format) ||
           PixelUtil::isLuminance(mFormat) ||
           (src_orig.getWidth() == dstBox.getWidth() &&
            src_orig.getHeight() == dstBox.getHeight() &&
            src_orig.getDepth() == dstBox.getDepth()))
        {
            GLESHardwarePixelBuffer::blitFromMemory(src_orig, dstBox);
            return;
        }
        if(!mBuffer.contains(dstBox))
            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Destination box out of range",
                        "GLESTextureBuffer::blitFromMemory");
        // For scoped deletion of conversion buffer
        MemoryDataStreamPtr buf;
        PixelBox src;
        
        // First, convert the srcbox to a OpenGL compatible pixel format
        if(GLESPixelUtil::getGLOriginFormat(src_orig.format) == 0)
        {
            // Convert to buffer internal format
            buf.bind(OGRE_NEW MemoryDataStream(PixelUtil::getMemorySize(src_orig.getWidth(), src_orig.getHeight(), src_orig.getDepth(),
                                                                   mFormat)));
            src = PixelBox(src_orig.getWidth(), src_orig.getHeight(), src_orig.getDepth(), mFormat, buf->getPtr());
            PixelUtil::bulkPixelConversion(src_orig, src);
        }
        else
        {
            // No conversion needed
            src = src_orig;
        }
        
        // Create temporary texture to store source data
        GLuint id;
        GLenum target = GL_TEXTURE_2D;
        GLsizei width = GLESPixelUtil::optionalPO2(src.getWidth());
        GLsizei height = GLESPixelUtil::optionalPO2(src.getHeight());
        GLenum format = GLESPixelUtil::getClosestGLInternalFormat(src.format);
        GLenum datatype = GLESPixelUtil::getGLOriginDataType(src.format);
        // Generate texture name
        glGenTextures(1, &id);
        GL_CHECK_ERROR;
        
        // Set texture type
        glBindTexture(target, id);
        GL_CHECK_ERROR;
        
        // Set automatic mipmap generation; nice for minimisation
        glTexParameteri(target, GL_GENERATE_MIPMAP, GL_TRUE );
        GL_CHECK_ERROR;

        // Allocate texture memory
        glTexImage2D(target, 0, format, width, height, 0, format, datatype, 0);
        GL_CHECK_ERROR;

        // GL texture buffer
        GLESTextureBuffer tex(BLANKSTRING, target, id, width, height, format, src.format,
                              0, 0, (Usage)(TU_AUTOMIPMAP|HBU_STATIC_WRITE_ONLY), false, false, 0);
        
        // Upload data to 0,0,0 in temporary texture
        Image::Box tempTarget(0, 0, 0, src.getWidth(), src.getHeight(), src.getDepth());
        tex.upload(src, tempTarget);
        
        // Blit
        blitFromTexture(&tex, tempTarget, dstBox);
        
        // Delete temp texture
        glDeleteTextures(1, &id);
        GL_CHECK_ERROR;
    }
    // TextureBuffer
    GLESTextureBuffer::GLESTextureBuffer(const String &baseName, GLenum target, GLuint id, 
                                         GLint width, GLint height, GLint internalFormat, GLenum format,
                                         GLint face, GLint level, Usage usage, bool crappyCard, 
                                         bool writeGamma, uint fsaa)
    : GLESHardwarePixelBuffer(0, 0, 0, PF_UNKNOWN, usage),
        mTarget(target), mTextureID(id), mFace(face), mLevel(level), mSoftwareMipmap(crappyCard)
    {
        GL_CHECK_ERROR;
        glBindTexture(mTarget, mTextureID);
        GL_CHECK_ERROR;

        // Get face identifier
        mFaceTarget = mTarget;

        // Calculate the width and height of the texture at this mip level
        mWidth = mLevel == 0 ? width : width / pow(2, level);
        mHeight = mLevel == 0 ? height : height / pow(2, level);
        if(mWidth < 1)
            mWidth = 1;
        if(mHeight < 1)
            mHeight = 1;
        
        // Only 2D is supported so depth is always 1
        mDepth = 1;

        mGLInternalFormat = internalFormat;
        mFormat = GLESPixelUtil::getClosestOGREFormat(internalFormat, format);

        mRowPitch = mWidth;
        mSlicePitch = mHeight*mWidth;
        mSizeInBytes = PixelUtil::getMemorySize(mWidth, mHeight, mDepth, mFormat);

        // Log a message
//        std::stringstream str;
//        str << "GLESHardwarePixelBuffer constructed for texture " << baseName
//            << " id " << mTextureID << " face " << mFace << " level " << mLevel << ": "
//            << "width=" << mWidth << " height="<< mHeight << " depth=" << mDepth
//            << "format=" << PixelUtil::getFormatName(mFormat);
//        LogManager::getSingleton().logMessage(LML_NORMAL, str.str());

        // Set up a pixel box
        mBuffer = PixelBox(mWidth, mHeight, mDepth, mFormat);
        
        if (mWidth==0 || mHeight==0 || mDepth==0)
            // We are invalid, do not allocate a buffer
            return;

        // Is this a render target?
        if (mUsage & TU_RENDERTARGET)
        {
            // Create render target for each slice
            mSliceTRT.reserve(mDepth);
            for(size_t zoffset=0; zoffset<mDepth; ++zoffset)
            {
                String name;
                name = "rtt/" + StringConverter::toString((size_t)this) + "/" + baseName;
                GLESSurfaceDesc surface;
                surface.buffer = this;
                surface.zoffset = zoffset;
                RenderTexture *trt = GLESRTTManager::getSingleton().createRenderTexture(name, surface, writeGamma, fsaa);
                mSliceTRT.push_back(trt);
                Root::getSingleton().getRenderSystem()->attachRenderTarget(*mSliceTRT[zoffset]);
            }
        }
    }
Example #13
0
	//--------------------------------------------------------------------------
    void Texture::_loadImages( const ConstImagePtrList& images )
    {
		if(images.size() < 1)
			OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Cannot load empty vector of images",
			 "Texture::loadImages");
        
		// Set desired texture size and properties from images[0]
		mSrcWidth = mWidth = images[0]->getWidth();
		mSrcHeight = mHeight = images[0]->getHeight();
		mSrcDepth = mDepth = images[0]->getDepth();

        // Get source image format and adjust if required
        mSrcFormat = images[0]->getFormat();
        if (mTreatLuminanceAsAlpha && mSrcFormat == PF_L8)
        {
            mSrcFormat = PF_A8;
        }

        if (mDesiredFormat != PF_UNKNOWN)
        {
            // If have desired format, use it
            mFormat = mDesiredFormat;
        }
        else
        {
            // Get the format according with desired bit depth
            mFormat = PixelUtil::getFormatForBitDepths(mSrcFormat, mDesiredIntegerBitDepth, mDesiredFloatBitDepth);
        }

		// The custom mipmaps in the image have priority over everything
        size_t imageMips = images[0]->getNumMipmaps();

		if(imageMips > 0) {
			mNumMipmaps = mNumRequestedMipmaps = images[0]->getNumMipmaps();
			// Disable flag for auto mip generation
			mUsage &= ~TU_AUTOMIPMAP;
		}
		
        // Create the texture
        createInternalResources();
		// Check if we're loading one image with multiple faces
		// or a vector of images representing the faces
		size_t faces;
		bool multiImage; // Load from multiple images?
		if(images.size() > 1)
		{
			faces = images.size();
			multiImage = true;
		}
		else
		{
			faces = images[0]->getNumFaces();
			multiImage = false;
		}
		
		// Check wether number of faces in images exceeds number of faces
		// in this texture. If so, clamp it.
		if(faces > getNumFaces())
			faces = getNumFaces();
		
        if (TextureManager::getSingleton().getVerbose()) {
            // Say what we're doing
            StringUtil::StrStreamType str;
            str << "Texture: " << mName << ": Loading " << faces << " faces"
                << "(" << PixelUtil::getFormatName(images[0]->getFormat()) << "," <<
                images[0]->getWidth() << "x" << images[0]->getHeight() << "x" << images[0]->getDepth() <<
                ") with ";
            if (!(mMipmapsHardwareGenerated && mNumMipmaps == 0))
                str << mNumMipmaps;
            if(mUsage & TU_AUTOMIPMAP)
            {
                if (mMipmapsHardwareGenerated)
                    str << " hardware";

                str << " generated mipmaps";
            }
            else
            {
                str << " custom mipmaps";
            }
            if(multiImage)
                str << " from multiple Images.";
            else
                str << " from Image.";
            // Scoped
            {
                // Print data about first destination surface
                HardwarePixelBufferSharedPtr buf = getBuffer(0, 0); 
                str << " Internal format is " << PixelUtil::getFormatName(buf->getFormat()) << 
                "," << buf->getWidth() << "x" << buf->getHeight() << "x" << buf->getDepth() << ".";
            }
            LogManager::getSingleton().logMessage( 
                    LML_NORMAL, str.str());
        }
		
		// Main loading loop
        // imageMips == 0 if the image has no custom mipmaps, otherwise contains the number of custom mips
        for(size_t mip = 0; mip<=imageMips; ++mip)
        {
            for(size_t i = 0; i < faces; ++i)
            {
                PixelBox src;
                if(multiImage)
                {
                    // Load from multiple images
                    src = images[i]->getPixelBox(0, mip);
                }
                else
                {
                    // Load from faces of images[0]
                    src = images[0]->getPixelBox(i, mip);
                }
    
                // Sets to treated format in case is difference
                src.format = mSrcFormat;

                if(mGamma != 1.0f) {
                    // Apply gamma correction
                    // Do not overwrite original image but do gamma correction in temporary buffer
                    MemoryDataStreamPtr buf; // for scoped deletion of conversion buffer
                    buf.bind(OGRE_NEW MemoryDataStream(
                        PixelUtil::getMemorySize(
                            src.getWidth(), src.getHeight(), src.getDepth(), src.format)));
                    
                    PixelBox corrected = PixelBox(src.getWidth(), src.getHeight(), src.getDepth(), src.format, buf->getPtr());
                    PixelUtil::bulkPixelConversion(src, corrected);
                    
                    Image::applyGamma(static_cast<uint8*>(corrected.data), mGamma, corrected.getConsecutiveSize(), 
                        static_cast<uchar>(PixelUtil::getNumElemBits(src.format)));
    
                    // Destination: entire texture. blitFromMemory does the scaling to
                    // a power of two for us when needed
                    getBuffer(i, mip)->blitFromMemory(corrected);
                }
                else 
                {
                    // Destination: entire texture. blitFromMemory does the scaling to
                    // a power of two for us when needed
                    getBuffer(i, mip)->blitFromMemory(src);
                }
                
            }
        }
        // Update size (the final size, not including temp space)
        mSize = getNumFaces() * PixelUtil::getMemorySize(mWidth, mHeight, mDepth, mFormat);

    }
    //-----------------------------------------------------------------------------  
    // blitFromMemory doing hardware trilinear scaling
    void GLES2TextureBuffer::blitFromMemory(const PixelBox &src_orig, const Image::Box &dstBox)
    {
        // Fall back to normal GLHardwarePixelBuffer::blitFromMemory in case 
        // - FBO is not supported
        // - Either source or target is luminance due doesn't looks like supported by hardware
        // - the source dimensions match the destination ones, in which case no scaling is needed
        // TODO: Check that extension is NOT available
        if(PixelUtil::isLuminance(src_orig.format) ||
           PixelUtil::isLuminance(mFormat) ||
           (src_orig.getWidth() == dstBox.getWidth() &&
            src_orig.getHeight() == dstBox.getHeight() &&
            src_orig.getDepth() == dstBox.getDepth()))
        {
            GLES2HardwarePixelBuffer::blitFromMemory(src_orig, dstBox);
            return;
        }
        if(!mBuffer.contains(dstBox))
            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Destination box out of range",
                        "GLES2TextureBuffer::blitFromMemory");
        // For scoped deletion of conversion buffer
        MemoryDataStreamPtr buf;
        PixelBox src;
        
        // First, convert the srcbox to a OpenGL compatible pixel format
        if(GLES2PixelUtil::getGLOriginFormat(src_orig.format) == 0)
        {
            // Convert to buffer internal format
            buf.bind(OGRE_NEW MemoryDataStream(PixelUtil::getMemorySize(src_orig.getWidth(), src_orig.getHeight(),
                                                                        src_orig.getDepth(), mFormat)));
            src = PixelBox(src_orig.getWidth(), src_orig.getHeight(), src_orig.getDepth(), mFormat, buf->getPtr());
            PixelUtil::bulkPixelConversion(src_orig, src);
        }
        else
        {
            // No conversion needed
            src = src_orig;
        }
        
        // Create temporary texture to store source data
        GLuint id;
        GLenum target =
#if OGRE_NO_GLES3_SUPPORT == 0
        (src.getDepth() != 1) ? GL_TEXTURE_3D :
#endif
            GL_TEXTURE_2D;

        GLsizei width = GLES2PixelUtil::optionalPO2(src.getWidth());
        GLsizei height = GLES2PixelUtil::optionalPO2(src.getHeight());
        GLenum format = GLES2PixelUtil::getClosestGLInternalFormat(src.format);
        GLenum datatype = GLES2PixelUtil::getGLOriginDataType(src.format);

        // Generate texture name
        OGRE_CHECK_GL_ERROR(glGenTextures(1, &id));
        
        // Set texture type
        OGRE_CHECK_GL_ERROR(glBindTexture(target, id));

#if GL_APPLE_texture_max_level && OGRE_PLATFORM != OGRE_PLATFORM_NACL
        OGRE_CHECK_GL_ERROR(glTexParameteri(target, GL_TEXTURE_MAX_LEVEL_APPLE, 1000 ));
#elif OGRE_NO_GLES3_SUPPORT == 0
        OGRE_CHECK_GL_ERROR(glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, 1000 ));
#endif

        // Allocate texture memory
#if OGRE_NO_GLES3_SUPPORT == 0
        if(target == GL_TEXTURE_3D || target == GL_TEXTURE_2D_ARRAY)
            glTexImage3D(target, 0, src.format, src.getWidth(), src.getHeight(), src.getDepth(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
        else
#endif
            OGRE_CHECK_GL_ERROR(glTexImage2D(target, 0, format, width, height, 0, format, datatype, 0));

        // GL texture buffer
        GLES2TextureBuffer tex(StringUtil::BLANK, target, id, width, height, format, src.format,
                              0, 0, (Usage)(TU_AUTOMIPMAP|HBU_STATIC_WRITE_ONLY), false, false, 0);
        
        // Upload data to 0,0,0 in temporary texture
        Image::Box tempTarget(0, 0, 0, src.getWidth(), src.getHeight(), src.getDepth());
        tex.upload(src, tempTarget);
        
        // Blit
        blitFromTexture(&tex, tempTarget, dstBox);
        
        // Delete temp texture
        OGRE_CHECK_GL_ERROR(glDeleteTextures(1, &id));
    }
    void GLES2TextureBuffer::buildMipmaps(const PixelBox &data)
    {
        int width;
        int height;
        int logW;
        int logH;
        int level;
        PixelBox scaled = data;
        scaled.data = data.data;
        scaled.left = data.left;
        scaled.right = data.right;
        scaled.top = data.top;
        scaled.bottom = data.bottom;
        scaled.front = data.front;
        scaled.back = data.back;

        width = data.getWidth();
        height = data.getHeight();

        logW = computeLog(width);
        logH = computeLog(height);
        level = (logW > logH ? logW : logH);

        for (int mip = 0; mip <= level; mip++)
        {
            GLenum glFormat = GLES2PixelUtil::getGLOriginFormat(scaled.format);
            GLenum dataType = GLES2PixelUtil::getGLOriginDataType(scaled.format);
            GLenum internalFormat = glFormat;
#if OGRE_NO_GLES3_SUPPORT == 0
            // In GL ES 3, the internalformat and format parameters do not need to be identical
            internalFormat = GLES2PixelUtil::getClosestGLInternalFormat(scaled.format);
#endif
            switch(mTarget)
            {
                case GL_TEXTURE_2D:
                case GL_TEXTURE_CUBE_MAP:
                    OGRE_CHECK_GL_ERROR(glTexImage2D(mFaceTarget,
                                                     mip,
                                                     internalFormat,
                                                     width, height,
                                                     0,
                                                     glFormat,
                                                     dataType,
                                                     scaled.data));
                    break;
#if OGRE_NO_GLES3_SUPPORT == 0
                case GL_TEXTURE_3D:
                case GL_TEXTURE_2D_ARRAY:
                    OGRE_CHECK_GL_ERROR(glTexImage3D(mFaceTarget,
                                                     mip,
                                                     internalFormat,
                                                     width, height, depth,
                                                     0,
                                                     glFormat,
                                                     dataType,
                                                     scaled.data));
                    break;
#endif
            }

            if (mip != 0)
            {
                OGRE_DELETE[] (uint8*) scaled.data;
                scaled.data = 0;
            }

            if (width > 1)
            {
                width = width / 2;
            }

            if (height > 1)
            {
                height = height / 2;
            }

            int sizeInBytes = PixelUtil::getMemorySize(width, height, 1,
                                                       data.format);
            scaled = PixelBox(width, height, 1, data.format);
            scaled.data = new uint8[sizeInBytes];
            Image::scale(data, scaled, Image::FILTER_LINEAR);
        }
	//-----------------------------------------------------------------------------  
	void D3D10HardwarePixelBuffer::blitFromMemory(const PixelBox &src, const Image::Box &dstBox)
	{
		bool isDds = false;
		switch(mFormat)
		{
		case PF_DXT1:
		case PF_DXT2:
		case PF_DXT3:
		case PF_DXT4:
		case PF_DXT5:
			isDds = true;
			break;
		default:

			break;
		}

		if (isDds && (dstBox.getWidth() % 4 != 0 || dstBox.getHeight() % 4 != 0 ))
		{
			return;
		}


		// for scoped deletion of conversion buffer
		MemoryDataStreamPtr buf;
		PixelBox converted = src;

		D3D10_BOX dstBoxDx10 = OgreImageBoxToDx10Box(dstBox);

		// convert to pixelbuffer's native format if necessary
		if (src.format != mFormat)
		{
			buf.bind(new MemoryDataStream(
				PixelUtil::getMemorySize(src.getWidth(), src.getHeight(), src.getDepth(),
				mFormat)));
			converted = PixelBox(src.getWidth(), src.getHeight(), src.getDepth(), mFormat, buf->getPtr());
			PixelUtil::bulkPixelConversion(src, converted);
		}

		// In d3d10 the Row Pitch is defined as: "The size of one row of the source data" and not 
		// the same as the OGRE row pitch - meaning that we need to multiple the OGRE row pitch 
		// with the size in bytes of the element to get the d3d10 row pitch. 
		UINT d3dRowPitch = static_cast<UINT>(converted.rowPitch) * static_cast<UINT>(PixelUtil::getNumElemBytes(mFormat));


		switch(mParentTexture->getTextureType()) {
		case TEX_TYPE_1D:
			{

				mDevice->UpdateSubresource( 
					mParentTexture->GetTex1D(), 
					0,
					&dstBoxDx10,
					converted.data,
					0,
					0 );
				if (mDevice.isError())
				{
					String errorDescription = mDevice.getErrorDescription();
					OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 
						"D3D10 device cannot update 1d subresource\nError Description:" + errorDescription,
						"D3D10HardwarePixelBuffer::blitFromMemory");
				}
			}
			break;
		case TEX_TYPE_CUBE_MAP:
		case TEX_TYPE_2D:
			{
				mDevice->UpdateSubresource( 
					mParentTexture->GetTex2D(), 
					static_cast<UINT>(mSubresourceIndex),
					&dstBoxDx10,
					converted.data,
					d3dRowPitch,
					mFace );
				if (mDevice.isError())
				{
					String errorDescription = mDevice.getErrorDescription();
					OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 
						"D3D10 device cannot update 2d subresource\nError Description:" + errorDescription,
						"D3D10HardwarePixelBuffer::blitFromMemory");
				}
			}
			break;
		case TEX_TYPE_3D:
			{
				mDevice->UpdateSubresource( 
					mParentTexture->GetTex2D(), 
					static_cast<UINT>(mSubresourceIndex),
					&dstBoxDx10,
					converted.data,
					d3dRowPitch,
					static_cast<UINT>(converted.slicePitch)
					);
				if (mDevice.isError())
				{
					String errorDescription = mDevice.getErrorDescription();
					OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 
						"D3D10 device cannot update 3d subresource\nError Description:" + errorDescription,
						"D3D10HardwarePixelBuffer::blitFromMemory");
				}
			}
			break;
		}


		if (!isDds)
		{
			_genMipmaps();
		}

	}
//-----------------------------------------------------------------------------
void D3D11HardwarePixelBuffer::blitFromMemory(const PixelBox &src, const Image::Box &dstBox)
{
    bool isDds = false;
    switch(mFormat)
    {
    case PF_DXT1:
    case PF_DXT2:
    case PF_DXT3:
    case PF_DXT4:
    case PF_DXT5:
        isDds = true;
        break;
    default:

        break;
    }

    if (isDds && (dstBox.getWidth() % 4 != 0 || dstBox.getHeight() % 4 != 0 ))
    {
        return;
    }


    // for scoped deletion of conversion buffer
    MemoryDataStreamPtr buf;
    PixelBox converted = src;

    D3D11_BOX dstBoxDx11 = OgreImageBoxToDx11Box(dstBox);
    dstBoxDx11.front = 0;
    dstBoxDx11.back = converted.getDepth();

    // convert to pixelbuffer's native format if necessary
    if (src.format != mFormat)
    {
        buf.bind(new MemoryDataStream(
                     PixelUtil::getMemorySize(src.getWidth(), src.getHeight(), src.getDepth(),
                                              mFormat)));
        converted = PixelBox(src.getWidth(), src.getHeight(), src.getDepth(), mFormat, buf->getPtr());
        PixelUtil::bulkPixelConversion(src, converted);
    }

    if (mUsage & HBU_DYNAMIC)
    {
        size_t sizeinbytes;
        if (PixelUtil::isCompressed(converted.format))
        {
            // D3D wants the width of one row of cells in bytes
            if (converted.format == PF_DXT1)
            {
                // 64 bits (8 bytes) per 4x4 block
                sizeinbytes = std::max<size_t>(1, converted.getWidth() / 4) * std::max<size_t>(1, converted.getHeight() / 4) * 8;
            }
            else
            {
                // 128 bits (16 bytes) per 4x4 block
                sizeinbytes = std::max<size_t>(1, converted.getWidth() / 4) * std::max<size_t>(1, converted.getHeight() / 4) * 16;
            }
        }
        else
        {
            sizeinbytes = converted.getHeight() * converted.getWidth() * PixelUtil::getNumElemBytes(converted.format);
        }

        const Ogre::PixelBox &locked = lock(dstBox, HBL_DISCARD);

        memcpy(locked.data, converted.data, sizeinbytes);

        unlock();
    }
    else
    {
        size_t rowWidth;
        if (PixelUtil::isCompressed(converted.format))
        {
            // D3D wants the width of one row of cells in bytes
            if (converted.format == PF_DXT1)
            {
                // 64 bits (8 bytes) per 4x4 block
                rowWidth = (converted.rowPitch / 4) * 8;
            }
            else
            {
                // 128 bits (16 bytes) per 4x4 block
                rowWidth = (converted.rowPitch / 4) * 16;
            }
        }
        else
        {
            rowWidth = converted.rowPitch * PixelUtil::getNumElemBytes(converted.format);
        }

        switch(mParentTexture->getTextureType()) {
        case TEX_TYPE_1D:
        {
            D3D11RenderSystem* rsys = reinterpret_cast<D3D11RenderSystem*>(Root::getSingleton().getRenderSystem());
            if (rsys->_getFeatureLevel() >= D3D_FEATURE_LEVEL_10_0)
            {
                mDevice.GetImmediateContext()->UpdateSubresource(
                    mParentTexture->GetTex1D(),
                    0,
                    &dstBoxDx11,
                    converted.data,
                    rowWidth,
                    0 );
                if (mDevice.isError())
                {
                    String errorDescription = mDevice.getErrorDescription();
                    OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
                                "D3D11 device cannot update 1d subresource\nError Description:" + errorDescription,
                                "D3D11HardwarePixelBuffer::blitFromMemory");
                }
                break; // For Feature levels that do not support 1D textures, revert to creating a 2D texture.
            }
        }
        case TEX_TYPE_CUBE_MAP:
        case TEX_TYPE_2D:
        {
            mDevice.GetImmediateContext()->UpdateSubresource(
                mParentTexture->GetTex2D(),
                D3D11CalcSubresource(static_cast<UINT>(mSubresourceIndex), mFace, mParentTexture->getNumMipmaps()+1),
                &dstBoxDx11,
                converted.data,
                rowWidth,
                0 );
            if (mDevice.isError())
            {
                String errorDescription = mDevice.getErrorDescription();
                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
                            "D3D11 device cannot update 2d subresource\nError Description:" + errorDescription,
                            "D3D11HardwarePixelBuffer::blitFromMemory");
            }
        }
        break;
        case TEX_TYPE_2D_ARRAY:
        {
            mDevice.GetImmediateContext()->UpdateSubresource(
                mParentTexture->GetTex2D(),
                D3D11CalcSubresource(static_cast<UINT>(mSubresourceIndex), src.front, mParentTexture->getNumMipmaps()+1),
                &dstBoxDx11,
                converted.data,
                rowWidth,
                0 );
            if (mDevice.isError())
            {
                String errorDescription = mDevice.getErrorDescription();
                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
                            "D3D11 device cannot update 2d array subresource\nError Description:" + errorDescription,
                            "D3D11HardwarePixelBuffer::blitFromMemory");
            }
        }
        break;
        case TEX_TYPE_3D:
        {
            // copied from dx9
            size_t sliceWidth;
            if (PixelUtil::isCompressed(converted.format))
            {
                // D3D wants the width of one slice of cells in bytes
                if (converted.format == PF_DXT1)
                {
                    // 64 bits (8 bytes) per 4x4 block
                    sliceWidth = (converted.slicePitch / 16) * 8;
                }
                else
                {
                    // 128 bits (16 bytes) per 4x4 block
                    sliceWidth = (converted.slicePitch / 16) * 16;
                }

            }
            else
            {
                sliceWidth = converted.slicePitch * PixelUtil::getNumElemBytes(converted.format);
            }

            mDevice.GetImmediateContext()->UpdateSubresource(
                mParentTexture->GetTex3D(),
                static_cast<UINT>(mSubresourceIndex),
                &dstBoxDx11,
                converted.data,
                rowWidth,
                sliceWidth
            );
            if (mDevice.isError())
            {
                String errorDescription = mDevice.getErrorDescription();
                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
                            "D3D11 device cannot update 3d subresource\nError Description:" + errorDescription,
                            "D3D11HardwarePixelBuffer::blitFromMemory");
            }
        }
        break;
        }

        if (!isDds)
        {
            _genMipmaps();
        }
    }

}
OgreTextureHandler::OgreTextureHandler(Ogre::TexturePtr& texture, uint32 defaultColor) : _texture(texture), _data(NULL), _pb(PixelBox(0,0,0,Ogre::PixelFormat::PF_X8R8G8B8))
{
	/// Lock the buffer so we can write to it
	_texture->getBuffer()->lock(HardwareBuffer::HBL_NORMAL);
	_pb = _texture->getBuffer()->getCurrentLock();
		/// Update the contents of pb here
	/// Image data starts at pb.data and has format pb.format
	/// Here we assume data.format is PF_X8R8G8B8 so we can address pixels as uint32.
	_data = static_cast<uint32*>(_pb.data);
	
	_height = _pb.getHeight();
	_width = _pb.getWidth();
	_pitch = _pb.rowPitch; // Skip between rows of image
	drawRect(0, 0, _width, _height, defaultColor);
	_texture->getBuffer()->unlock();
}
vector< vector<Envelope> >  TileBoundsCalculator::calculateTiles()
{
  size_t width = 1;
  vector<PixelBox> boxes;
  boxes.resize(1);
  boxes[0] = PixelBox(0, _r1.cols - 1, 0, _r1.rows - 1);

  double nodeCount = _sumPixels(boxes[0]);
  LOG_INFO("w: " << _r1.cols << " h: " << _r1.rows);
  LOG_INFO("Total node count: " << nodeCount);

  while (!_isDone(boxes))
  {
    width *= 2;

    vector<PixelBox> nextLayer;
    nextLayer.resize(width * width);

    //LOG_INFO("width: " << width);
    for (size_t i = 0; i < boxes.size(); i++)
    {
      PixelBox& b = boxes[i];
      double splitX = _calculateSplitX(b);
      int tx = i % (width / 2);
      int ty = i / (width / 2);
      //LOG_INFO("  i: " << i << " tx: " << tx << " ty: " << ty);

      double splitYLeft = _calculateSplitY(PixelBox(b.minX, splitX, b.minY, b.maxY));
      nextLayer[(tx * 2 + 0) + (ty * 2 + 0) * width] = PixelBox(b.minX, splitX, b.minY,
        splitYLeft);
      nextLayer[(tx * 2 + 0) + (ty * 2 + 1) * width] = PixelBox(b.minX, splitX, splitYLeft + 1,
        b.maxY);

      double splitYRight = _calculateSplitY(PixelBox(splitX + 1, b.maxX, b.minY, b.maxY));
      nextLayer[(tx * 2 + 1) + (ty * 2 + 0) * width] = PixelBox(splitX + 1, b.maxX, b.minY,
        splitYRight);
      nextLayer[(tx * 2 + 1) + (ty * 2 + 1) * width] = PixelBox(splitX + 1, b.maxX, splitYRight + 1,
        b.maxY);
    }

    boxes = nextLayer;
  }

  vector< vector<Envelope> > result;

  long maxNodeCount = 0;
  result.resize(width);
  for (size_t tx = 0; tx < width; tx++)
  {
    result[tx].resize(width);
    for (size_t ty = 0; ty < width; ty++)
    {
      PixelBox& pb = boxes[tx + ty * width];
      maxNodeCount = std::max(maxNodeCount, _sumPixels(pb));
      if (pb.getWidth() < 3 || pb.getHeight() < 3)
      {
        throw HootException("PixelBox must be at least 3 pixels wide and tall.");
      }
      result[tx][ty] = _toEnvelope(pb);
    }
  }
  LOG_INFO("Max node count in one tile: " << maxNodeCount);
  _exportResult(boxes, "tmp/result.png");

  return result;
}
Example #20
0
    //-----------------------------------------------------------------------
    void Image::scale(const PixelBox &src, const PixelBox &scaled, Filter filter) 
    {
        assert(PixelUtil::isAccessible(src.format));
        assert(PixelUtil::isAccessible(scaled.format));
        MemoryDataStreamPtr buf; // For auto-delete
        PixelBox temp;
        switch (filter) 
        {
        default:
        case FILTER_NEAREST:
            if(src.format == scaled.format) 
            {
                // No intermediate buffer needed
                temp = scaled;
            }
            else
            {
                // Allocate temporary buffer of destination size in source format 
                temp = PixelBox(scaled.getWidth(), scaled.getHeight(), scaled.getDepth(), src.format);
                buf.bind(OGRE_NEW MemoryDataStream(temp.getConsecutiveSize()));
                temp.data = buf->getPtr();
            }
            // super-optimized: no conversion
            switch (PixelUtil::getNumElemBytes(src.format)) 
            {
            case 1: NearestResampler<1>::scale(src, temp); break;
            case 2: NearestResampler<2>::scale(src, temp); break;
            case 3: NearestResampler<3>::scale(src, temp); break;
            case 4: NearestResampler<4>::scale(src, temp); break;
            case 6: NearestResampler<6>::scale(src, temp); break;
            case 8: NearestResampler<8>::scale(src, temp); break;
            case 12: NearestResampler<12>::scale(src, temp); break;
            case 16: NearestResampler<16>::scale(src, temp); break;
            default:
                // never reached
                assert(false);
            }
            if(temp.data != scaled.data)
            {
                // Blit temp buffer
                PixelUtil::bulkPixelConversion(temp, scaled);
            }
            break;

        case FILTER_LINEAR:
        case FILTER_BILINEAR:
            switch (src.format) 
            {
            case PF_L8: case PF_A8: case PF_BYTE_LA:
            case PF_R8G8B8: case PF_B8G8R8:
            case PF_R8G8B8A8: case PF_B8G8R8A8:
            case PF_A8B8G8R8: case PF_A8R8G8B8:
            case PF_X8B8G8R8: case PF_X8R8G8B8:
                if(src.format == scaled.format) 
                {
                    // No intermediate buffer needed
                    temp = scaled;
                }
                else
                {
                    // Allocate temp buffer of destination size in source format 
                    temp = PixelBox(scaled.getWidth(), scaled.getHeight(), scaled.getDepth(), src.format);
                    buf.bind(OGRE_NEW MemoryDataStream(temp.getConsecutiveSize()));
                    temp.data = buf->getPtr();
                }
                // super-optimized: byte-oriented math, no conversion
                switch (PixelUtil::getNumElemBytes(src.format)) 
                {
                case 1: LinearResampler_Byte<1>::scale(src, temp); break;
                case 2: LinearResampler_Byte<2>::scale(src, temp); break;
                case 3: LinearResampler_Byte<3>::scale(src, temp); break;
                case 4: LinearResampler_Byte<4>::scale(src, temp); break;
                default:
                    // never reached
                    assert(false);
                }
                if(temp.data != scaled.data)
                {
                    // Blit temp buffer
                    PixelUtil::bulkPixelConversion(temp, scaled);
                }
                break;
            case PF_FLOAT32_RGB:
            case PF_FLOAT32_RGBA:
                if (scaled.format == PF_FLOAT32_RGB || scaled.format == PF_FLOAT32_RGBA)
                {
                    // float32 to float32, avoid unpack/repack overhead
                    LinearResampler_Float32::scale(src, scaled);
                    break;
                }
                // else, fall through
            default:
                // non-optimized: floating-point math, performs conversion but always works
                LinearResampler::scale(src, scaled);
            }
            break;
        }
    }
Example #21
0
	//-----------------------------------------------------------------------
	void Image::scale(const PixelBox &src, const PixelBox &scaled, Filter filter) 
	{
		assert(PixelUtil::isAccessible(src.format));
		assert(PixelUtil::isAccessible(scaled.format));
#ifdef NEWSCALING		
		MemoryDataStreamPtr buf; // For auto-delete
		PixelBox temp;
		switch (filter) {
		case FILTER_NEAREST:
			if(src.format == scaled.format) {
				// No intermediate buffer needed
				temp = scaled;
			}
			else
			{
				// Allocate temporary buffer of destination size in source format 
				temp = PixelBox(scaled.getWidth(), scaled.getHeight(), scaled.getDepth(), src.format);
				buf.bind(new MemoryDataStream(temp.getConsecutiveSize()));
				temp.data = buf->getPtr();
			}
			// super-optimized: no conversion
			switch (PixelUtil::getNumElemBytes(src.format)) {
			case 1: NearestResampler<1>::scale(src, temp); break;
			case 2: NearestResampler<2>::scale(src, temp); break;
			case 3: NearestResampler<3>::scale(src, temp); break;
			case 4: NearestResampler<4>::scale(src, temp); break;
			case 6: NearestResampler<6>::scale(src, temp); break;
			case 8: NearestResampler<8>::scale(src, temp); break;
			case 12: NearestResampler<12>::scale(src, temp); break;
			case 16: NearestResampler<16>::scale(src, temp); break;
			default:
				// never reached
				assert(false);
			}
			if(temp.data != scaled.data)
			{
				// Blit temp buffer
				PixelUtil::bulkPixelConversion(temp, scaled);
			}
			break;

		case FILTER_LINEAR:
		case FILTER_BILINEAR:
			switch (src.format) {
			case PF_L8: case PF_A8: case PF_BYTE_LA:
			case PF_R8G8B8: case PF_B8G8R8:
			case PF_R8G8B8A8: case PF_B8G8R8A8:
			case PF_A8B8G8R8: case PF_A8R8G8B8:
			case PF_X8B8G8R8: case PF_X8R8G8B8:
				if(src.format == scaled.format) {
					// No intermediate buffer needed
					temp = scaled;
				}
				else
				{
					// Allocate temp buffer of destination size in source format 
					temp = PixelBox(scaled.getWidth(), scaled.getHeight(), scaled.getDepth(), src.format);
					buf.bind(new MemoryDataStream(temp.getConsecutiveSize()));
					temp.data = buf->getPtr();
				}
				// super-optimized: byte-oriented math, no conversion
				switch (PixelUtil::getNumElemBytes(src.format)) {
				case 1: LinearResampler_Byte<1>::scale(src, temp); break;
				case 2: LinearResampler_Byte<2>::scale(src, temp); break;
				case 3: LinearResampler_Byte<3>::scale(src, temp); break;
				case 4: LinearResampler_Byte<4>::scale(src, temp); break;
				default:
					// never reached
					assert(false);
				}
				if(temp.data != scaled.data)
				{
					// Blit temp buffer
					PixelUtil::bulkPixelConversion(temp, scaled);
				}
				break;
			case PF_FLOAT32_RGB:
			case PF_FLOAT32_RGBA:
				if (scaled.format == PF_FLOAT32_RGB || scaled.format == PF_FLOAT32_RGBA)
				{
					// float32 to float32, avoid unpack/repack overhead
					LinearResampler_Float32::scale(src, scaled);
					break;
				}
				// else, fall through
			default:
				// non-optimized: floating-point math, performs conversion but always works
				LinearResampler::scale(src, scaled);
			}
			break;
		default:
			// fall back to old, slow, wildly incorrect DevIL code
#endif
#if OGRE_NO_DEVIL == 0
			ILuint ImageName;
			ilGenImages( 1, &ImageName );
			ilBindImage( ImageName );

			// Convert image from OGRE to current IL image
			ILUtil::fromOgre(src);

			// set filter
			iluImageParameter(ILU_FILTER, getILFilter(filter));

			// do the scaling
			if(!iluScale(scaled.getWidth(), scaled.getHeight(), scaled.getDepth())) {
				OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR,
					iluErrorString(ilGetError()),
					"Image::scale" ) ;
			}
			ILUtil::toOgre(scaled);

			ilDeleteImages(1, &ImageName);

			// return to default filter
			iluImageParameter(ILU_FILTER, ILU_NEAREST);
#else
			OGRE_EXCEPT( Exception::UNIMPLEMENTED_FEATURE,
				"Scaling algorithm not implemented without DevIL",
				"Image::scale" ) ;	
#endif
#ifdef NEWSCALING
		}
#endif
	}