//-------------------------------------------------------------------------- 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]); } } }
//-------------------------------------------------------------------------- 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; }
//----------------------------------------------------------------------- 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; } }
//----------------------------------------------------------------------- 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 }